]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
49c0186917f0f61c6b40dacf0e4a3677fb37cdf9
[rails.git] / vendor / assets / iD / iD.js
1 (function () {
2 function actionAddEntity(way) {
3     return function(graph) {
4         return graph.replace(way);
5     };
6 }
7
8 var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
9
10
11
12
13
14 function createCommonjsModule(fn, module) {
15         return module = { exports: {} }, fn(module, module.exports), module.exports;
16 }
17
18 var lodash = createCommonjsModule(function (module, exports) {
19 /**
20  * @license
21  * Lodash <https://lodash.com/>
22  * Copyright JS Foundation and other contributors <https://js.foundation/>
23  * Released under MIT license <https://lodash.com/license>
24  * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
25  * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
26  */
27 (function() {
28
29   /** Used as a safe reference for `undefined` in pre-ES5 environments. */
30   var undefined;
31
32   /** Used as the semantic version number. */
33   var VERSION = '4.17.4';
34
35   /** Used as the size to enable large array optimizations. */
36   var LARGE_ARRAY_SIZE = 200;
37
38   /** Error message constants. */
39   var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
40       FUNC_ERROR_TEXT = 'Expected a function';
41
42   /** Used to stand-in for `undefined` hash values. */
43   var HASH_UNDEFINED = '__lodash_hash_undefined__';
44
45   /** Used as the maximum memoize cache size. */
46   var MAX_MEMOIZE_SIZE = 500;
47
48   /** Used as the internal argument placeholder. */
49   var PLACEHOLDER = '__lodash_placeholder__';
50
51   /** Used to compose bitmasks for cloning. */
52   var CLONE_DEEP_FLAG = 1,
53       CLONE_FLAT_FLAG = 2,
54       CLONE_SYMBOLS_FLAG = 4;
55
56   /** Used to compose bitmasks for value comparisons. */
57   var COMPARE_PARTIAL_FLAG = 1,
58       COMPARE_UNORDERED_FLAG = 2;
59
60   /** Used to compose bitmasks for function metadata. */
61   var WRAP_BIND_FLAG = 1,
62       WRAP_BIND_KEY_FLAG = 2,
63       WRAP_CURRY_BOUND_FLAG = 4,
64       WRAP_CURRY_FLAG = 8,
65       WRAP_CURRY_RIGHT_FLAG = 16,
66       WRAP_PARTIAL_FLAG = 32,
67       WRAP_PARTIAL_RIGHT_FLAG = 64,
68       WRAP_ARY_FLAG = 128,
69       WRAP_REARG_FLAG = 256,
70       WRAP_FLIP_FLAG = 512;
71
72   /** Used as default options for `_.truncate`. */
73   var DEFAULT_TRUNC_LENGTH = 30,
74       DEFAULT_TRUNC_OMISSION = '...';
75
76   /** Used to detect hot functions by number of calls within a span of milliseconds. */
77   var HOT_COUNT = 800,
78       HOT_SPAN = 16;
79
80   /** Used to indicate the type of lazy iteratees. */
81   var LAZY_FILTER_FLAG = 1,
82       LAZY_MAP_FLAG = 2,
83       LAZY_WHILE_FLAG = 3;
84
85   /** Used as references for various `Number` constants. */
86   var INFINITY = 1 / 0,
87       MAX_SAFE_INTEGER = 9007199254740991,
88       MAX_INTEGER = 1.7976931348623157e+308,
89       NAN = 0 / 0;
90
91   /** Used as references for the maximum length and index of an array. */
92   var MAX_ARRAY_LENGTH = 4294967295,
93       MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
94       HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
95
96   /** Used to associate wrap methods with their bit flags. */
97   var wrapFlags = [
98     ['ary', WRAP_ARY_FLAG],
99     ['bind', WRAP_BIND_FLAG],
100     ['bindKey', WRAP_BIND_KEY_FLAG],
101     ['curry', WRAP_CURRY_FLAG],
102     ['curryRight', WRAP_CURRY_RIGHT_FLAG],
103     ['flip', WRAP_FLIP_FLAG],
104     ['partial', WRAP_PARTIAL_FLAG],
105     ['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
106     ['rearg', WRAP_REARG_FLAG]
107   ];
108
109   /** `Object#toString` result references. */
110   var argsTag = '[object Arguments]',
111       arrayTag = '[object Array]',
112       asyncTag = '[object AsyncFunction]',
113       boolTag = '[object Boolean]',
114       dateTag = '[object Date]',
115       domExcTag = '[object DOMException]',
116       errorTag = '[object Error]',
117       funcTag = '[object Function]',
118       genTag = '[object GeneratorFunction]',
119       mapTag = '[object Map]',
120       numberTag = '[object Number]',
121       nullTag = '[object Null]',
122       objectTag = '[object Object]',
123       promiseTag = '[object Promise]',
124       proxyTag = '[object Proxy]',
125       regexpTag = '[object RegExp]',
126       setTag = '[object Set]',
127       stringTag = '[object String]',
128       symbolTag = '[object Symbol]',
129       undefinedTag = '[object Undefined]',
130       weakMapTag = '[object WeakMap]',
131       weakSetTag = '[object WeakSet]';
132
133   var arrayBufferTag = '[object ArrayBuffer]',
134       dataViewTag = '[object DataView]',
135       float32Tag = '[object Float32Array]',
136       float64Tag = '[object Float64Array]',
137       int8Tag = '[object Int8Array]',
138       int16Tag = '[object Int16Array]',
139       int32Tag = '[object Int32Array]',
140       uint8Tag = '[object Uint8Array]',
141       uint8ClampedTag = '[object Uint8ClampedArray]',
142       uint16Tag = '[object Uint16Array]',
143       uint32Tag = '[object Uint32Array]';
144
145   /** Used to match empty string literals in compiled template source. */
146   var reEmptyStringLeading = /\b__p \+= '';/g,
147       reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
148       reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
149
150   /** Used to match HTML entities and HTML characters. */
151   var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
152       reUnescapedHtml = /[&<>"']/g,
153       reHasEscapedHtml = RegExp(reEscapedHtml.source),
154       reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
155
156   /** Used to match template delimiters. */
157   var reEscape = /<%-([\s\S]+?)%>/g,
158       reEvaluate = /<%([\s\S]+?)%>/g,
159       reInterpolate = /<%=([\s\S]+?)%>/g;
160
161   /** Used to match property names within property paths. */
162   var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
163       reIsPlainProp = /^\w*$/,
164       reLeadingDot = /^\./,
165       rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
166
167   /**
168    * Used to match `RegExp`
169    * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
170    */
171   var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
172       reHasRegExpChar = RegExp(reRegExpChar.source);
173
174   /** Used to match leading and trailing whitespace. */
175   var reTrim = /^\s+|\s+$/g,
176       reTrimStart = /^\s+/,
177       reTrimEnd = /\s+$/;
178
179   /** Used to match wrap detail comments. */
180   var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
181       reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
182       reSplitDetails = /,? & /;
183
184   /** Used to match words composed of alphanumeric characters. */
185   var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
186
187   /** Used to match backslashes in property paths. */
188   var reEscapeChar = /\\(\\)?/g;
189
190   /**
191    * Used to match
192    * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
193    */
194   var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
195
196   /** Used to match `RegExp` flags from their coerced string values. */
197   var reFlags = /\w*$/;
198
199   /** Used to detect bad signed hexadecimal string values. */
200   var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
201
202   /** Used to detect binary string values. */
203   var reIsBinary = /^0b[01]+$/i;
204
205   /** Used to detect host constructors (Safari). */
206   var reIsHostCtor = /^\[object .+?Constructor\]$/;
207
208   /** Used to detect octal string values. */
209   var reIsOctal = /^0o[0-7]+$/i;
210
211   /** Used to detect unsigned integer values. */
212   var reIsUint = /^(?:0|[1-9]\d*)$/;
213
214   /** Used to match Latin Unicode letters (excluding mathematical operators). */
215   var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
216
217   /** Used to ensure capturing order of template delimiters. */
218   var reNoMatch = /($^)/;
219
220   /** Used to match unescaped characters in compiled string literals. */
221   var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
222
223   /** Used to compose unicode character classes. */
224   var rsAstralRange = '\\ud800-\\udfff',
225       rsComboMarksRange = '\\u0300-\\u036f',
226       reComboHalfMarksRange = '\\ufe20-\\ufe2f',
227       rsComboSymbolsRange = '\\u20d0-\\u20ff',
228       rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
229       rsDingbatRange = '\\u2700-\\u27bf',
230       rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
231       rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
232       rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
233       rsPunctuationRange = '\\u2000-\\u206f',
234       rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
235       rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
236       rsVarRange = '\\ufe0e\\ufe0f',
237       rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
238
239   /** Used to compose unicode capture groups. */
240   var rsApos = "['\u2019]",
241       rsAstral = '[' + rsAstralRange + ']',
242       rsBreak = '[' + rsBreakRange + ']',
243       rsCombo = '[' + rsComboRange + ']',
244       rsDigits = '\\d+',
245       rsDingbat = '[' + rsDingbatRange + ']',
246       rsLower = '[' + rsLowerRange + ']',
247       rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
248       rsFitz = '\\ud83c[\\udffb-\\udfff]',
249       rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
250       rsNonAstral = '[^' + rsAstralRange + ']',
251       rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
252       rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
253       rsUpper = '[' + rsUpperRange + ']',
254       rsZWJ = '\\u200d';
255
256   /** Used to compose unicode regexes. */
257   var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
258       rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
259       rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
260       rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
261       reOptMod = rsModifier + '?',
262       rsOptVar = '[' + rsVarRange + ']?',
263       rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
264       rsOrdLower = '\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)',
265       rsOrdUpper = '\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)',
266       rsSeq = rsOptVar + reOptMod + rsOptJoin,
267       rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
268       rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
269
270   /** Used to match apostrophes. */
271   var reApos = RegExp(rsApos, 'g');
272
273   /**
274    * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
275    * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
276    */
277   var reComboMark = RegExp(rsCombo, 'g');
278
279   /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
280   var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
281
282   /** Used to match complex or compound words. */
283   var reUnicodeWord = RegExp([
284     rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
285     rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
286     rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
287     rsUpper + '+' + rsOptContrUpper,
288     rsOrdUpper,
289     rsOrdLower,
290     rsDigits,
291     rsEmoji
292   ].join('|'), 'g');
293
294   /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
295   var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange  + rsComboRange + rsVarRange + ']');
296
297   /** Used to detect strings that need a more robust regexp to match words. */
298   var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
299
300   /** Used to assign default `context` object properties. */
301   var contextProps = [
302     'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
303     'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
304     'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array',
305     'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
306     '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
307   ];
308
309   /** Used to make template sourceURLs easier to identify. */
310   var templateCounter = -1;
311
312   /** Used to identify `toStringTag` values of typed arrays. */
313   var typedArrayTags = {};
314   typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
315   typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
316   typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
317   typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
318   typedArrayTags[uint32Tag] = true;
319   typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
320   typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
321   typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
322   typedArrayTags[errorTag] = typedArrayTags[funcTag] =
323   typedArrayTags[mapTag] = typedArrayTags[numberTag] =
324   typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
325   typedArrayTags[setTag] = typedArrayTags[stringTag] =
326   typedArrayTags[weakMapTag] = false;
327
328   /** Used to identify `toStringTag` values supported by `_.clone`. */
329   var cloneableTags = {};
330   cloneableTags[argsTag] = cloneableTags[arrayTag] =
331   cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
332   cloneableTags[boolTag] = cloneableTags[dateTag] =
333   cloneableTags[float32Tag] = cloneableTags[float64Tag] =
334   cloneableTags[int8Tag] = cloneableTags[int16Tag] =
335   cloneableTags[int32Tag] = cloneableTags[mapTag] =
336   cloneableTags[numberTag] = cloneableTags[objectTag] =
337   cloneableTags[regexpTag] = cloneableTags[setTag] =
338   cloneableTags[stringTag] = cloneableTags[symbolTag] =
339   cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
340   cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
341   cloneableTags[errorTag] = cloneableTags[funcTag] =
342   cloneableTags[weakMapTag] = false;
343
344   /** Used to map Latin Unicode letters to basic Latin letters. */
345   var deburredLetters = {
346     // Latin-1 Supplement block.
347     '\xc0': 'A',  '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
348     '\xe0': 'a',  '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
349     '\xc7': 'C',  '\xe7': 'c',
350     '\xd0': 'D',  '\xf0': 'd',
351     '\xc8': 'E',  '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
352     '\xe8': 'e',  '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
353     '\xcc': 'I',  '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
354     '\xec': 'i',  '\xed': 'i', '\xee': 'i', '\xef': 'i',
355     '\xd1': 'N',  '\xf1': 'n',
356     '\xd2': 'O',  '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
357     '\xf2': 'o',  '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
358     '\xd9': 'U',  '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
359     '\xf9': 'u',  '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
360     '\xdd': 'Y',  '\xfd': 'y', '\xff': 'y',
361     '\xc6': 'Ae', '\xe6': 'ae',
362     '\xde': 'Th', '\xfe': 'th',
363     '\xdf': 'ss',
364     // Latin Extended-A block.
365     '\u0100': 'A',  '\u0102': 'A', '\u0104': 'A',
366     '\u0101': 'a',  '\u0103': 'a', '\u0105': 'a',
367     '\u0106': 'C',  '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
368     '\u0107': 'c',  '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
369     '\u010e': 'D',  '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
370     '\u0112': 'E',  '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
371     '\u0113': 'e',  '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
372     '\u011c': 'G',  '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
373     '\u011d': 'g',  '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
374     '\u0124': 'H',  '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
375     '\u0128': 'I',  '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
376     '\u0129': 'i',  '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
377     '\u0134': 'J',  '\u0135': 'j',
378     '\u0136': 'K',  '\u0137': 'k', '\u0138': 'k',
379     '\u0139': 'L',  '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
380     '\u013a': 'l',  '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
381     '\u0143': 'N',  '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
382     '\u0144': 'n',  '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
383     '\u014c': 'O',  '\u014e': 'O', '\u0150': 'O',
384     '\u014d': 'o',  '\u014f': 'o', '\u0151': 'o',
385     '\u0154': 'R',  '\u0156': 'R', '\u0158': 'R',
386     '\u0155': 'r',  '\u0157': 'r', '\u0159': 'r',
387     '\u015a': 'S',  '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
388     '\u015b': 's',  '\u015d': 's', '\u015f': 's', '\u0161': 's',
389     '\u0162': 'T',  '\u0164': 'T', '\u0166': 'T',
390     '\u0163': 't',  '\u0165': 't', '\u0167': 't',
391     '\u0168': 'U',  '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
392     '\u0169': 'u',  '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
393     '\u0174': 'W',  '\u0175': 'w',
394     '\u0176': 'Y',  '\u0177': 'y', '\u0178': 'Y',
395     '\u0179': 'Z',  '\u017b': 'Z', '\u017d': 'Z',
396     '\u017a': 'z',  '\u017c': 'z', '\u017e': 'z',
397     '\u0132': 'IJ', '\u0133': 'ij',
398     '\u0152': 'Oe', '\u0153': 'oe',
399     '\u0149': "'n", '\u017f': 's'
400   };
401
402   /** Used to map characters to HTML entities. */
403   var htmlEscapes = {
404     '&': '&amp;',
405     '<': '&lt;',
406     '>': '&gt;',
407     '"': '&quot;',
408     "'": '&#39;'
409   };
410
411   /** Used to map HTML entities to characters. */
412   var htmlUnescapes = {
413     '&amp;': '&',
414     '&lt;': '<',
415     '&gt;': '>',
416     '&quot;': '"',
417     '&#39;': "'"
418   };
419
420   /** Used to escape characters for inclusion in compiled string literals. */
421   var stringEscapes = {
422     '\\': '\\',
423     "'": "'",
424     '\n': 'n',
425     '\r': 'r',
426     '\u2028': 'u2028',
427     '\u2029': 'u2029'
428   };
429
430   /** Built-in method references without a dependency on `root`. */
431   var freeParseFloat = parseFloat,
432       freeParseInt = parseInt;
433
434   /** Detect free variable `global` from Node.js. */
435   var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
436
437   /** Detect free variable `self`. */
438   var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
439
440   /** Used as a reference to the global object. */
441   var root = freeGlobal || freeSelf || Function('return this')();
442
443   /** Detect free variable `exports`. */
444   var freeExports = 'object' == 'object' && exports && !exports.nodeType && exports;
445
446   /** Detect free variable `module`. */
447   var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module;
448
449   /** Detect the popular CommonJS extension `module.exports`. */
450   var moduleExports = freeModule && freeModule.exports === freeExports;
451
452   /** Detect free variable `process` from Node.js. */
453   var freeProcess = moduleExports && freeGlobal.process;
454
455   /** Used to access faster Node.js helpers. */
456   var nodeUtil = (function() {
457     try {
458       return freeProcess && freeProcess.binding && freeProcess.binding('util');
459     } catch (e) {}
460   }());
461
462   /* Node.js helper references. */
463   var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
464       nodeIsDate = nodeUtil && nodeUtil.isDate,
465       nodeIsMap = nodeUtil && nodeUtil.isMap,
466       nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
467       nodeIsSet = nodeUtil && nodeUtil.isSet,
468       nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
469
470   /*--------------------------------------------------------------------------*/
471
472   /**
473    * Adds the key-value `pair` to `map`.
474    *
475    * @private
476    * @param {Object} map The map to modify.
477    * @param {Array} pair The key-value pair to add.
478    * @returns {Object} Returns `map`.
479    */
480   function addMapEntry(map, pair) {
481     // Don't return `map.set` because it's not chainable in IE 11.
482     map.set(pair[0], pair[1]);
483     return map;
484   }
485
486   /**
487    * Adds `value` to `set`.
488    *
489    * @private
490    * @param {Object} set The set to modify.
491    * @param {*} value The value to add.
492    * @returns {Object} Returns `set`.
493    */
494   function addSetEntry(set, value) {
495     // Don't return `set.add` because it's not chainable in IE 11.
496     set.add(value);
497     return set;
498   }
499
500   /**
501    * A faster alternative to `Function#apply`, this function invokes `func`
502    * with the `this` binding of `thisArg` and the arguments of `args`.
503    *
504    * @private
505    * @param {Function} func The function to invoke.
506    * @param {*} thisArg The `this` binding of `func`.
507    * @param {Array} args The arguments to invoke `func` with.
508    * @returns {*} Returns the result of `func`.
509    */
510   function apply(func, thisArg, args) {
511     switch (args.length) {
512       case 0: return func.call(thisArg);
513       case 1: return func.call(thisArg, args[0]);
514       case 2: return func.call(thisArg, args[0], args[1]);
515       case 3: return func.call(thisArg, args[0], args[1], args[2]);
516     }
517     return func.apply(thisArg, args);
518   }
519
520   /**
521    * A specialized version of `baseAggregator` for arrays.
522    *
523    * @private
524    * @param {Array} [array] The array to iterate over.
525    * @param {Function} setter The function to set `accumulator` values.
526    * @param {Function} iteratee The iteratee to transform keys.
527    * @param {Object} accumulator The initial aggregated object.
528    * @returns {Function} Returns `accumulator`.
529    */
530   function arrayAggregator(array, setter, iteratee, accumulator) {
531     var index = -1,
532         length = array == null ? 0 : array.length;
533
534     while (++index < length) {
535       var value = array[index];
536       setter(accumulator, value, iteratee(value), array);
537     }
538     return accumulator;
539   }
540
541   /**
542    * A specialized version of `_.forEach` for arrays without support for
543    * iteratee shorthands.
544    *
545    * @private
546    * @param {Array} [array] The array to iterate over.
547    * @param {Function} iteratee The function invoked per iteration.
548    * @returns {Array} Returns `array`.
549    */
550   function arrayEach(array, iteratee) {
551     var index = -1,
552         length = array == null ? 0 : array.length;
553
554     while (++index < length) {
555       if (iteratee(array[index], index, array) === false) {
556         break;
557       }
558     }
559     return array;
560   }
561
562   /**
563    * A specialized version of `_.forEachRight` for arrays without support for
564    * iteratee shorthands.
565    *
566    * @private
567    * @param {Array} [array] The array to iterate over.
568    * @param {Function} iteratee The function invoked per iteration.
569    * @returns {Array} Returns `array`.
570    */
571   function arrayEachRight(array, iteratee) {
572     var length = array == null ? 0 : array.length;
573
574     while (length--) {
575       if (iteratee(array[length], length, array) === false) {
576         break;
577       }
578     }
579     return array;
580   }
581
582   /**
583    * A specialized version of `_.every` for arrays without support for
584    * iteratee shorthands.
585    *
586    * @private
587    * @param {Array} [array] The array to iterate over.
588    * @param {Function} predicate The function invoked per iteration.
589    * @returns {boolean} Returns `true` if all elements pass the predicate check,
590    *  else `false`.
591    */
592   function arrayEvery(array, predicate) {
593     var index = -1,
594         length = array == null ? 0 : array.length;
595
596     while (++index < length) {
597       if (!predicate(array[index], index, array)) {
598         return false;
599       }
600     }
601     return true;
602   }
603
604   /**
605    * A specialized version of `_.filter` for arrays without support for
606    * iteratee shorthands.
607    *
608    * @private
609    * @param {Array} [array] The array to iterate over.
610    * @param {Function} predicate The function invoked per iteration.
611    * @returns {Array} Returns the new filtered array.
612    */
613   function arrayFilter(array, predicate) {
614     var index = -1,
615         length = array == null ? 0 : array.length,
616         resIndex = 0,
617         result = [];
618
619     while (++index < length) {
620       var value = array[index];
621       if (predicate(value, index, array)) {
622         result[resIndex++] = value;
623       }
624     }
625     return result;
626   }
627
628   /**
629    * A specialized version of `_.includes` for arrays without support for
630    * specifying an index to search from.
631    *
632    * @private
633    * @param {Array} [array] The array to inspect.
634    * @param {*} target The value to search for.
635    * @returns {boolean} Returns `true` if `target` is found, else `false`.
636    */
637   function arrayIncludes(array, value) {
638     var length = array == null ? 0 : array.length;
639     return !!length && baseIndexOf(array, value, 0) > -1;
640   }
641
642   /**
643    * This function is like `arrayIncludes` except that it accepts a comparator.
644    *
645    * @private
646    * @param {Array} [array] The array to inspect.
647    * @param {*} target The value to search for.
648    * @param {Function} comparator The comparator invoked per element.
649    * @returns {boolean} Returns `true` if `target` is found, else `false`.
650    */
651   function arrayIncludesWith(array, value, comparator) {
652     var index = -1,
653         length = array == null ? 0 : array.length;
654
655     while (++index < length) {
656       if (comparator(value, array[index])) {
657         return true;
658       }
659     }
660     return false;
661   }
662
663   /**
664    * A specialized version of `_.map` for arrays without support for iteratee
665    * shorthands.
666    *
667    * @private
668    * @param {Array} [array] The array to iterate over.
669    * @param {Function} iteratee The function invoked per iteration.
670    * @returns {Array} Returns the new mapped array.
671    */
672   function arrayMap(array, iteratee) {
673     var index = -1,
674         length = array == null ? 0 : array.length,
675         result = Array(length);
676
677     while (++index < length) {
678       result[index] = iteratee(array[index], index, array);
679     }
680     return result;
681   }
682
683   /**
684    * Appends the elements of `values` to `array`.
685    *
686    * @private
687    * @param {Array} array The array to modify.
688    * @param {Array} values The values to append.
689    * @returns {Array} Returns `array`.
690    */
691   function arrayPush(array, values) {
692     var index = -1,
693         length = values.length,
694         offset = array.length;
695
696     while (++index < length) {
697       array[offset + index] = values[index];
698     }
699     return array;
700   }
701
702   /**
703    * A specialized version of `_.reduce` for arrays without support for
704    * iteratee shorthands.
705    *
706    * @private
707    * @param {Array} [array] The array to iterate over.
708    * @param {Function} iteratee The function invoked per iteration.
709    * @param {*} [accumulator] The initial value.
710    * @param {boolean} [initAccum] Specify using the first element of `array` as
711    *  the initial value.
712    * @returns {*} Returns the accumulated value.
713    */
714   function arrayReduce(array, iteratee, accumulator, initAccum) {
715     var index = -1,
716         length = array == null ? 0 : array.length;
717
718     if (initAccum && length) {
719       accumulator = array[++index];
720     }
721     while (++index < length) {
722       accumulator = iteratee(accumulator, array[index], index, array);
723     }
724     return accumulator;
725   }
726
727   /**
728    * A specialized version of `_.reduceRight` for arrays without support for
729    * iteratee shorthands.
730    *
731    * @private
732    * @param {Array} [array] The array to iterate over.
733    * @param {Function} iteratee The function invoked per iteration.
734    * @param {*} [accumulator] The initial value.
735    * @param {boolean} [initAccum] Specify using the last element of `array` as
736    *  the initial value.
737    * @returns {*} Returns the accumulated value.
738    */
739   function arrayReduceRight(array, iteratee, accumulator, initAccum) {
740     var length = array == null ? 0 : array.length;
741     if (initAccum && length) {
742       accumulator = array[--length];
743     }
744     while (length--) {
745       accumulator = iteratee(accumulator, array[length], length, array);
746     }
747     return accumulator;
748   }
749
750   /**
751    * A specialized version of `_.some` for arrays without support for iteratee
752    * shorthands.
753    *
754    * @private
755    * @param {Array} [array] The array to iterate over.
756    * @param {Function} predicate The function invoked per iteration.
757    * @returns {boolean} Returns `true` if any element passes the predicate check,
758    *  else `false`.
759    */
760   function arraySome(array, predicate) {
761     var index = -1,
762         length = array == null ? 0 : array.length;
763
764     while (++index < length) {
765       if (predicate(array[index], index, array)) {
766         return true;
767       }
768     }
769     return false;
770   }
771
772   /**
773    * Gets the size of an ASCII `string`.
774    *
775    * @private
776    * @param {string} string The string inspect.
777    * @returns {number} Returns the string size.
778    */
779   var asciiSize = baseProperty('length');
780
781   /**
782    * Converts an ASCII `string` to an array.
783    *
784    * @private
785    * @param {string} string The string to convert.
786    * @returns {Array} Returns the converted array.
787    */
788   function asciiToArray(string) {
789     return string.split('');
790   }
791
792   /**
793    * Splits an ASCII `string` into an array of its words.
794    *
795    * @private
796    * @param {string} The string to inspect.
797    * @returns {Array} Returns the words of `string`.
798    */
799   function asciiWords(string) {
800     return string.match(reAsciiWord) || [];
801   }
802
803   /**
804    * The base implementation of methods like `_.findKey` and `_.findLastKey`,
805    * without support for iteratee shorthands, which iterates over `collection`
806    * using `eachFunc`.
807    *
808    * @private
809    * @param {Array|Object} collection The collection to inspect.
810    * @param {Function} predicate The function invoked per iteration.
811    * @param {Function} eachFunc The function to iterate over `collection`.
812    * @returns {*} Returns the found element or its key, else `undefined`.
813    */
814   function baseFindKey(collection, predicate, eachFunc) {
815     var result;
816     eachFunc(collection, function(value, key, collection) {
817       if (predicate(value, key, collection)) {
818         result = key;
819         return false;
820       }
821     });
822     return result;
823   }
824
825   /**
826    * The base implementation of `_.findIndex` and `_.findLastIndex` without
827    * support for iteratee shorthands.
828    *
829    * @private
830    * @param {Array} array The array to inspect.
831    * @param {Function} predicate The function invoked per iteration.
832    * @param {number} fromIndex The index to search from.
833    * @param {boolean} [fromRight] Specify iterating from right to left.
834    * @returns {number} Returns the index of the matched value, else `-1`.
835    */
836   function baseFindIndex(array, predicate, fromIndex, fromRight) {
837     var length = array.length,
838         index = fromIndex + (fromRight ? 1 : -1);
839
840     while ((fromRight ? index-- : ++index < length)) {
841       if (predicate(array[index], index, array)) {
842         return index;
843       }
844     }
845     return -1;
846   }
847
848   /**
849    * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
850    *
851    * @private
852    * @param {Array} array The array to inspect.
853    * @param {*} value The value to search for.
854    * @param {number} fromIndex The index to search from.
855    * @returns {number} Returns the index of the matched value, else `-1`.
856    */
857   function baseIndexOf(array, value, fromIndex) {
858     return value === value
859       ? strictIndexOf(array, value, fromIndex)
860       : baseFindIndex(array, baseIsNaN, fromIndex);
861   }
862
863   /**
864    * This function is like `baseIndexOf` except that it accepts a comparator.
865    *
866    * @private
867    * @param {Array} array The array to inspect.
868    * @param {*} value The value to search for.
869    * @param {number} fromIndex The index to search from.
870    * @param {Function} comparator The comparator invoked per element.
871    * @returns {number} Returns the index of the matched value, else `-1`.
872    */
873   function baseIndexOfWith(array, value, fromIndex, comparator) {
874     var index = fromIndex - 1,
875         length = array.length;
876
877     while (++index < length) {
878       if (comparator(array[index], value)) {
879         return index;
880       }
881     }
882     return -1;
883   }
884
885   /**
886    * The base implementation of `_.isNaN` without support for number objects.
887    *
888    * @private
889    * @param {*} value The value to check.
890    * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
891    */
892   function baseIsNaN(value) {
893     return value !== value;
894   }
895
896   /**
897    * The base implementation of `_.mean` and `_.meanBy` without support for
898    * iteratee shorthands.
899    *
900    * @private
901    * @param {Array} array The array to iterate over.
902    * @param {Function} iteratee The function invoked per iteration.
903    * @returns {number} Returns the mean.
904    */
905   function baseMean(array, iteratee) {
906     var length = array == null ? 0 : array.length;
907     return length ? (baseSum(array, iteratee) / length) : NAN;
908   }
909
910   /**
911    * The base implementation of `_.property` without support for deep paths.
912    *
913    * @private
914    * @param {string} key The key of the property to get.
915    * @returns {Function} Returns the new accessor function.
916    */
917   function baseProperty(key) {
918     return function(object) {
919       return object == null ? undefined : object[key];
920     };
921   }
922
923   /**
924    * The base implementation of `_.propertyOf` without support for deep paths.
925    *
926    * @private
927    * @param {Object} object The object to query.
928    * @returns {Function} Returns the new accessor function.
929    */
930   function basePropertyOf(object) {
931     return function(key) {
932       return object == null ? undefined : object[key];
933     };
934   }
935
936   /**
937    * The base implementation of `_.reduce` and `_.reduceRight`, without support
938    * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
939    *
940    * @private
941    * @param {Array|Object} collection The collection to iterate over.
942    * @param {Function} iteratee The function invoked per iteration.
943    * @param {*} accumulator The initial value.
944    * @param {boolean} initAccum Specify using the first or last element of
945    *  `collection` as the initial value.
946    * @param {Function} eachFunc The function to iterate over `collection`.
947    * @returns {*} Returns the accumulated value.
948    */
949   function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
950     eachFunc(collection, function(value, index, collection) {
951       accumulator = initAccum
952         ? (initAccum = false, value)
953         : iteratee(accumulator, value, index, collection);
954     });
955     return accumulator;
956   }
957
958   /**
959    * The base implementation of `_.sortBy` which uses `comparer` to define the
960    * sort order of `array` and replaces criteria objects with their corresponding
961    * values.
962    *
963    * @private
964    * @param {Array} array The array to sort.
965    * @param {Function} comparer The function to define sort order.
966    * @returns {Array} Returns `array`.
967    */
968   function baseSortBy(array, comparer) {
969     var length = array.length;
970
971     array.sort(comparer);
972     while (length--) {
973       array[length] = array[length].value;
974     }
975     return array;
976   }
977
978   /**
979    * The base implementation of `_.sum` and `_.sumBy` without support for
980    * iteratee shorthands.
981    *
982    * @private
983    * @param {Array} array The array to iterate over.
984    * @param {Function} iteratee The function invoked per iteration.
985    * @returns {number} Returns the sum.
986    */
987   function baseSum(array, iteratee) {
988     var result,
989         index = -1,
990         length = array.length;
991
992     while (++index < length) {
993       var current = iteratee(array[index]);
994       if (current !== undefined) {
995         result = result === undefined ? current : (result + current);
996       }
997     }
998     return result;
999   }
1000
1001   /**
1002    * The base implementation of `_.times` without support for iteratee shorthands
1003    * or max array length checks.
1004    *
1005    * @private
1006    * @param {number} n The number of times to invoke `iteratee`.
1007    * @param {Function} iteratee The function invoked per iteration.
1008    * @returns {Array} Returns the array of results.
1009    */
1010   function baseTimes(n, iteratee) {
1011     var index = -1,
1012         result = Array(n);
1013
1014     while (++index < n) {
1015       result[index] = iteratee(index);
1016     }
1017     return result;
1018   }
1019
1020   /**
1021    * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
1022    * of key-value pairs for `object` corresponding to the property names of `props`.
1023    *
1024    * @private
1025    * @param {Object} object The object to query.
1026    * @param {Array} props The property names to get values for.
1027    * @returns {Object} Returns the key-value pairs.
1028    */
1029   function baseToPairs(object, props) {
1030     return arrayMap(props, function(key) {
1031       return [key, object[key]];
1032     });
1033   }
1034
1035   /**
1036    * The base implementation of `_.unary` without support for storing metadata.
1037    *
1038    * @private
1039    * @param {Function} func The function to cap arguments for.
1040    * @returns {Function} Returns the new capped function.
1041    */
1042   function baseUnary(func) {
1043     return function(value) {
1044       return func(value);
1045     };
1046   }
1047
1048   /**
1049    * The base implementation of `_.values` and `_.valuesIn` which creates an
1050    * array of `object` property values corresponding to the property names
1051    * of `props`.
1052    *
1053    * @private
1054    * @param {Object} object The object to query.
1055    * @param {Array} props The property names to get values for.
1056    * @returns {Object} Returns the array of property values.
1057    */
1058   function baseValues(object, props) {
1059     return arrayMap(props, function(key) {
1060       return object[key];
1061     });
1062   }
1063
1064   /**
1065    * Checks if a `cache` value for `key` exists.
1066    *
1067    * @private
1068    * @param {Object} cache The cache to query.
1069    * @param {string} key The key of the entry to check.
1070    * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
1071    */
1072   function cacheHas(cache, key) {
1073     return cache.has(key);
1074   }
1075
1076   /**
1077    * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
1078    * that is not found in the character symbols.
1079    *
1080    * @private
1081    * @param {Array} strSymbols The string symbols to inspect.
1082    * @param {Array} chrSymbols The character symbols to find.
1083    * @returns {number} Returns the index of the first unmatched string symbol.
1084    */
1085   function charsStartIndex(strSymbols, chrSymbols) {
1086     var index = -1,
1087         length = strSymbols.length;
1088
1089     while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
1090     return index;
1091   }
1092
1093   /**
1094    * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
1095    * that is not found in the character symbols.
1096    *
1097    * @private
1098    * @param {Array} strSymbols The string symbols to inspect.
1099    * @param {Array} chrSymbols The character symbols to find.
1100    * @returns {number} Returns the index of the last unmatched string symbol.
1101    */
1102   function charsEndIndex(strSymbols, chrSymbols) {
1103     var index = strSymbols.length;
1104
1105     while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
1106     return index;
1107   }
1108
1109   /**
1110    * Gets the number of `placeholder` occurrences in `array`.
1111    *
1112    * @private
1113    * @param {Array} array The array to inspect.
1114    * @param {*} placeholder The placeholder to search for.
1115    * @returns {number} Returns the placeholder count.
1116    */
1117   function countHolders(array, placeholder) {
1118     var length = array.length,
1119         result = 0;
1120
1121     while (length--) {
1122       if (array[length] === placeholder) {
1123         ++result;
1124       }
1125     }
1126     return result;
1127   }
1128
1129   /**
1130    * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
1131    * letters to basic Latin letters.
1132    *
1133    * @private
1134    * @param {string} letter The matched letter to deburr.
1135    * @returns {string} Returns the deburred letter.
1136    */
1137   var deburrLetter = basePropertyOf(deburredLetters);
1138
1139   /**
1140    * Used by `_.escape` to convert characters to HTML entities.
1141    *
1142    * @private
1143    * @param {string} chr The matched character to escape.
1144    * @returns {string} Returns the escaped character.
1145    */
1146   var escapeHtmlChar = basePropertyOf(htmlEscapes);
1147
1148   /**
1149    * Used by `_.template` to escape characters for inclusion in compiled string literals.
1150    *
1151    * @private
1152    * @param {string} chr The matched character to escape.
1153    * @returns {string} Returns the escaped character.
1154    */
1155   function escapeStringChar(chr) {
1156     return '\\' + stringEscapes[chr];
1157   }
1158
1159   /**
1160    * Gets the value at `key` of `object`.
1161    *
1162    * @private
1163    * @param {Object} [object] The object to query.
1164    * @param {string} key The key of the property to get.
1165    * @returns {*} Returns the property value.
1166    */
1167   function getValue(object, key) {
1168     return object == null ? undefined : object[key];
1169   }
1170
1171   /**
1172    * Checks if `string` contains Unicode symbols.
1173    *
1174    * @private
1175    * @param {string} string The string to inspect.
1176    * @returns {boolean} Returns `true` if a symbol is found, else `false`.
1177    */
1178   function hasUnicode(string) {
1179     return reHasUnicode.test(string);
1180   }
1181
1182   /**
1183    * Checks if `string` contains a word composed of Unicode symbols.
1184    *
1185    * @private
1186    * @param {string} string The string to inspect.
1187    * @returns {boolean} Returns `true` if a word is found, else `false`.
1188    */
1189   function hasUnicodeWord(string) {
1190     return reHasUnicodeWord.test(string);
1191   }
1192
1193   /**
1194    * Converts `iterator` to an array.
1195    *
1196    * @private
1197    * @param {Object} iterator The iterator to convert.
1198    * @returns {Array} Returns the converted array.
1199    */
1200   function iteratorToArray(iterator) {
1201     var data,
1202         result = [];
1203
1204     while (!(data = iterator.next()).done) {
1205       result.push(data.value);
1206     }
1207     return result;
1208   }
1209
1210   /**
1211    * Converts `map` to its key-value pairs.
1212    *
1213    * @private
1214    * @param {Object} map The map to convert.
1215    * @returns {Array} Returns the key-value pairs.
1216    */
1217   function mapToArray(map) {
1218     var index = -1,
1219         result = Array(map.size);
1220
1221     map.forEach(function(value, key) {
1222       result[++index] = [key, value];
1223     });
1224     return result;
1225   }
1226
1227   /**
1228    * Creates a unary function that invokes `func` with its argument transformed.
1229    *
1230    * @private
1231    * @param {Function} func The function to wrap.
1232    * @param {Function} transform The argument transform.
1233    * @returns {Function} Returns the new function.
1234    */
1235   function overArg(func, transform) {
1236     return function(arg) {
1237       return func(transform(arg));
1238     };
1239   }
1240
1241   /**
1242    * Replaces all `placeholder` elements in `array` with an internal placeholder
1243    * and returns an array of their indexes.
1244    *
1245    * @private
1246    * @param {Array} array The array to modify.
1247    * @param {*} placeholder The placeholder to replace.
1248    * @returns {Array} Returns the new array of placeholder indexes.
1249    */
1250   function replaceHolders(array, placeholder) {
1251     var index = -1,
1252         length = array.length,
1253         resIndex = 0,
1254         result = [];
1255
1256     while (++index < length) {
1257       var value = array[index];
1258       if (value === placeholder || value === PLACEHOLDER) {
1259         array[index] = PLACEHOLDER;
1260         result[resIndex++] = index;
1261       }
1262     }
1263     return result;
1264   }
1265
1266   /**
1267    * Converts `set` to an array of its values.
1268    *
1269    * @private
1270    * @param {Object} set The set to convert.
1271    * @returns {Array} Returns the values.
1272    */
1273   function setToArray(set) {
1274     var index = -1,
1275         result = Array(set.size);
1276
1277     set.forEach(function(value) {
1278       result[++index] = value;
1279     });
1280     return result;
1281   }
1282
1283   /**
1284    * Converts `set` to its value-value pairs.
1285    *
1286    * @private
1287    * @param {Object} set The set to convert.
1288    * @returns {Array} Returns the value-value pairs.
1289    */
1290   function setToPairs(set) {
1291     var index = -1,
1292         result = Array(set.size);
1293
1294     set.forEach(function(value) {
1295       result[++index] = [value, value];
1296     });
1297     return result;
1298   }
1299
1300   /**
1301    * A specialized version of `_.indexOf` which performs strict equality
1302    * comparisons of values, i.e. `===`.
1303    *
1304    * @private
1305    * @param {Array} array The array to inspect.
1306    * @param {*} value The value to search for.
1307    * @param {number} fromIndex The index to search from.
1308    * @returns {number} Returns the index of the matched value, else `-1`.
1309    */
1310   function strictIndexOf(array, value, fromIndex) {
1311     var index = fromIndex - 1,
1312         length = array.length;
1313
1314     while (++index < length) {
1315       if (array[index] === value) {
1316         return index;
1317       }
1318     }
1319     return -1;
1320   }
1321
1322   /**
1323    * A specialized version of `_.lastIndexOf` which performs strict equality
1324    * comparisons of values, i.e. `===`.
1325    *
1326    * @private
1327    * @param {Array} array The array to inspect.
1328    * @param {*} value The value to search for.
1329    * @param {number} fromIndex The index to search from.
1330    * @returns {number} Returns the index of the matched value, else `-1`.
1331    */
1332   function strictLastIndexOf(array, value, fromIndex) {
1333     var index = fromIndex + 1;
1334     while (index--) {
1335       if (array[index] === value) {
1336         return index;
1337       }
1338     }
1339     return index;
1340   }
1341
1342   /**
1343    * Gets the number of symbols in `string`.
1344    *
1345    * @private
1346    * @param {string} string The string to inspect.
1347    * @returns {number} Returns the string size.
1348    */
1349   function stringSize(string) {
1350     return hasUnicode(string)
1351       ? unicodeSize(string)
1352       : asciiSize(string);
1353   }
1354
1355   /**
1356    * Converts `string` to an array.
1357    *
1358    * @private
1359    * @param {string} string The string to convert.
1360    * @returns {Array} Returns the converted array.
1361    */
1362   function stringToArray(string) {
1363     return hasUnicode(string)
1364       ? unicodeToArray(string)
1365       : asciiToArray(string);
1366   }
1367
1368   /**
1369    * Used by `_.unescape` to convert HTML entities to characters.
1370    *
1371    * @private
1372    * @param {string} chr The matched character to unescape.
1373    * @returns {string} Returns the unescaped character.
1374    */
1375   var unescapeHtmlChar = basePropertyOf(htmlUnescapes);
1376
1377   /**
1378    * Gets the size of a Unicode `string`.
1379    *
1380    * @private
1381    * @param {string} string The string inspect.
1382    * @returns {number} Returns the string size.
1383    */
1384   function unicodeSize(string) {
1385     var result = reUnicode.lastIndex = 0;
1386     while (reUnicode.test(string)) {
1387       ++result;
1388     }
1389     return result;
1390   }
1391
1392   /**
1393    * Converts a Unicode `string` to an array.
1394    *
1395    * @private
1396    * @param {string} string The string to convert.
1397    * @returns {Array} Returns the converted array.
1398    */
1399   function unicodeToArray(string) {
1400     return string.match(reUnicode) || [];
1401   }
1402
1403   /**
1404    * Splits a Unicode `string` into an array of its words.
1405    *
1406    * @private
1407    * @param {string} The string to inspect.
1408    * @returns {Array} Returns the words of `string`.
1409    */
1410   function unicodeWords(string) {
1411     return string.match(reUnicodeWord) || [];
1412   }
1413
1414   /*--------------------------------------------------------------------------*/
1415
1416   /**
1417    * Create a new pristine `lodash` function using the `context` object.
1418    *
1419    * @static
1420    * @memberOf _
1421    * @since 1.1.0
1422    * @category Util
1423    * @param {Object} [context=root] The context object.
1424    * @returns {Function} Returns a new `lodash` function.
1425    * @example
1426    *
1427    * _.mixin({ 'foo': _.constant('foo') });
1428    *
1429    * var lodash = _.runInContext();
1430    * lodash.mixin({ 'bar': lodash.constant('bar') });
1431    *
1432    * _.isFunction(_.foo);
1433    * // => true
1434    * _.isFunction(_.bar);
1435    * // => false
1436    *
1437    * lodash.isFunction(lodash.foo);
1438    * // => false
1439    * lodash.isFunction(lodash.bar);
1440    * // => true
1441    *
1442    * // Create a suped-up `defer` in Node.js.
1443    * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
1444    */
1445   var runInContext = (function runInContext(context) {
1446     context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));
1447
1448     /** Built-in constructor references. */
1449     var Array = context.Array,
1450         Date = context.Date,
1451         Error = context.Error,
1452         Function = context.Function,
1453         Math = context.Math,
1454         Object = context.Object,
1455         RegExp = context.RegExp,
1456         String = context.String,
1457         TypeError = context.TypeError;
1458
1459     /** Used for built-in method references. */
1460     var arrayProto = Array.prototype,
1461         funcProto = Function.prototype,
1462         objectProto = Object.prototype;
1463
1464     /** Used to detect overreaching core-js shims. */
1465     var coreJsData = context['__core-js_shared__'];
1466
1467     /** Used to resolve the decompiled source of functions. */
1468     var funcToString = funcProto.toString;
1469
1470     /** Used to check objects for own properties. */
1471     var hasOwnProperty = objectProto.hasOwnProperty;
1472
1473     /** Used to generate unique IDs. */
1474     var idCounter = 0;
1475
1476     /** Used to detect methods masquerading as native. */
1477     var maskSrcKey = (function() {
1478       var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
1479       return uid ? ('Symbol(src)_1.' + uid) : '';
1480     }());
1481
1482     /**
1483      * Used to resolve the
1484      * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
1485      * of values.
1486      */
1487     var nativeObjectToString = objectProto.toString;
1488
1489     /** Used to infer the `Object` constructor. */
1490     var objectCtorString = funcToString.call(Object);
1491
1492     /** Used to restore the original `_` reference in `_.noConflict`. */
1493     var oldDash = root._;
1494
1495     /** Used to detect if a method is native. */
1496     var reIsNative = RegExp('^' +
1497       funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
1498       .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
1499     );
1500
1501     /** Built-in value references. */
1502     var Buffer = moduleExports ? context.Buffer : undefined,
1503         Symbol = context.Symbol,
1504         Uint8Array = context.Uint8Array,
1505         allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
1506         getPrototype = overArg(Object.getPrototypeOf, Object),
1507         objectCreate = Object.create,
1508         propertyIsEnumerable = objectProto.propertyIsEnumerable,
1509         splice = arrayProto.splice,
1510         spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
1511         symIterator = Symbol ? Symbol.iterator : undefined,
1512         symToStringTag = Symbol ? Symbol.toStringTag : undefined;
1513
1514     var defineProperty = (function() {
1515       try {
1516         var func = getNative(Object, 'defineProperty');
1517         func({}, '', {});
1518         return func;
1519       } catch (e) {}
1520     }());
1521
1522     /** Mocked built-ins. */
1523     var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
1524         ctxNow = Date && Date.now !== root.Date.now && Date.now,
1525         ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;
1526
1527     /* Built-in method references for those with the same name as other `lodash` methods. */
1528     var nativeCeil = Math.ceil,
1529         nativeFloor = Math.floor,
1530         nativeGetSymbols = Object.getOwnPropertySymbols,
1531         nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
1532         nativeIsFinite = context.isFinite,
1533         nativeJoin = arrayProto.join,
1534         nativeKeys = overArg(Object.keys, Object),
1535         nativeMax = Math.max,
1536         nativeMin = Math.min,
1537         nativeNow = Date.now,
1538         nativeParseInt = context.parseInt,
1539         nativeRandom = Math.random,
1540         nativeReverse = arrayProto.reverse;
1541
1542     /* Built-in method references that are verified to be native. */
1543     var DataView = getNative(context, 'DataView'),
1544         Map = getNative(context, 'Map'),
1545         Promise = getNative(context, 'Promise'),
1546         Set = getNative(context, 'Set'),
1547         WeakMap = getNative(context, 'WeakMap'),
1548         nativeCreate = getNative(Object, 'create');
1549
1550     /** Used to store function metadata. */
1551     var metaMap = WeakMap && new WeakMap;
1552
1553     /** Used to lookup unminified function names. */
1554     var realNames = {};
1555
1556     /** Used to detect maps, sets, and weakmaps. */
1557     var dataViewCtorString = toSource(DataView),
1558         mapCtorString = toSource(Map),
1559         promiseCtorString = toSource(Promise),
1560         setCtorString = toSource(Set),
1561         weakMapCtorString = toSource(WeakMap);
1562
1563     /** Used to convert symbols to primitives and strings. */
1564     var symbolProto = Symbol ? Symbol.prototype : undefined,
1565         symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
1566         symbolToString = symbolProto ? symbolProto.toString : undefined;
1567
1568     /*------------------------------------------------------------------------*/
1569
1570     /**
1571      * Creates a `lodash` object which wraps `value` to enable implicit method
1572      * chain sequences. Methods that operate on and return arrays, collections,
1573      * and functions can be chained together. Methods that retrieve a single value
1574      * or may return a primitive value will automatically end the chain sequence
1575      * and return the unwrapped value. Otherwise, the value must be unwrapped
1576      * with `_#value`.
1577      *
1578      * Explicit chain sequences, which must be unwrapped with `_#value`, may be
1579      * enabled using `_.chain`.
1580      *
1581      * The execution of chained methods is lazy, that is, it's deferred until
1582      * `_#value` is implicitly or explicitly called.
1583      *
1584      * Lazy evaluation allows several methods to support shortcut fusion.
1585      * Shortcut fusion is an optimization to merge iteratee calls; this avoids
1586      * the creation of intermediate arrays and can greatly reduce the number of
1587      * iteratee executions. Sections of a chain sequence qualify for shortcut
1588      * fusion if the section is applied to an array and iteratees accept only
1589      * one argument. The heuristic for whether a section qualifies for shortcut
1590      * fusion is subject to change.
1591      *
1592      * Chaining is supported in custom builds as long as the `_#value` method is
1593      * directly or indirectly included in the build.
1594      *
1595      * In addition to lodash methods, wrappers have `Array` and `String` methods.
1596      *
1597      * The wrapper `Array` methods are:
1598      * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
1599      *
1600      * The wrapper `String` methods are:
1601      * `replace` and `split`
1602      *
1603      * The wrapper methods that support shortcut fusion are:
1604      * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
1605      * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
1606      * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
1607      *
1608      * The chainable wrapper methods are:
1609      * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
1610      * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
1611      * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
1612      * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
1613      * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
1614      * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
1615      * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
1616      * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
1617      * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
1618      * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
1619      * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
1620      * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
1621      * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
1622      * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
1623      * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
1624      * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
1625      * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
1626      * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
1627      * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
1628      * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
1629      * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
1630      * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
1631      * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
1632      * `zipObject`, `zipObjectDeep`, and `zipWith`
1633      *
1634      * The wrapper methods that are **not** chainable by default are:
1635      * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
1636      * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
1637      * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
1638      * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
1639      * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
1640      * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
1641      * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
1642      * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
1643      * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
1644      * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
1645      * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
1646      * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
1647      * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
1648      * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
1649      * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
1650      * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
1651      * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
1652      * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
1653      * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
1654      * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
1655      * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
1656      * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
1657      * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
1658      * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
1659      * `upperFirst`, `value`, and `words`
1660      *
1661      * @name _
1662      * @constructor
1663      * @category Seq
1664      * @param {*} value The value to wrap in a `lodash` instance.
1665      * @returns {Object} Returns the new `lodash` wrapper instance.
1666      * @example
1667      *
1668      * function square(n) {
1669      *   return n * n;
1670      * }
1671      *
1672      * var wrapped = _([1, 2, 3]);
1673      *
1674      * // Returns an unwrapped value.
1675      * wrapped.reduce(_.add);
1676      * // => 6
1677      *
1678      * // Returns a wrapped value.
1679      * var squares = wrapped.map(square);
1680      *
1681      * _.isArray(squares);
1682      * // => false
1683      *
1684      * _.isArray(squares.value());
1685      * // => true
1686      */
1687     function lodash(value) {
1688       if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
1689         if (value instanceof LodashWrapper) {
1690           return value;
1691         }
1692         if (hasOwnProperty.call(value, '__wrapped__')) {
1693           return wrapperClone(value);
1694         }
1695       }
1696       return new LodashWrapper(value);
1697     }
1698
1699     /**
1700      * The base implementation of `_.create` without support for assigning
1701      * properties to the created object.
1702      *
1703      * @private
1704      * @param {Object} proto The object to inherit from.
1705      * @returns {Object} Returns the new object.
1706      */
1707     var baseCreate = (function() {
1708       function object() {}
1709       return function(proto) {
1710         if (!isObject(proto)) {
1711           return {};
1712         }
1713         if (objectCreate) {
1714           return objectCreate(proto);
1715         }
1716         object.prototype = proto;
1717         var result = new object;
1718         object.prototype = undefined;
1719         return result;
1720       };
1721     }());
1722
1723     /**
1724      * The function whose prototype chain sequence wrappers inherit from.
1725      *
1726      * @private
1727      */
1728     function baseLodash() {
1729       // No operation performed.
1730     }
1731
1732     /**
1733      * The base constructor for creating `lodash` wrapper objects.
1734      *
1735      * @private
1736      * @param {*} value The value to wrap.
1737      * @param {boolean} [chainAll] Enable explicit method chain sequences.
1738      */
1739     function LodashWrapper(value, chainAll) {
1740       this.__wrapped__ = value;
1741       this.__actions__ = [];
1742       this.__chain__ = !!chainAll;
1743       this.__index__ = 0;
1744       this.__values__ = undefined;
1745     }
1746
1747     /**
1748      * By default, the template delimiters used by lodash are like those in
1749      * embedded Ruby (ERB) as well as ES2015 template strings. Change the
1750      * following template settings to use alternative delimiters.
1751      *
1752      * @static
1753      * @memberOf _
1754      * @type {Object}
1755      */
1756     lodash.templateSettings = {
1757
1758       /**
1759        * Used to detect `data` property values to be HTML-escaped.
1760        *
1761        * @memberOf _.templateSettings
1762        * @type {RegExp}
1763        */
1764       'escape': reEscape,
1765
1766       /**
1767        * Used to detect code to be evaluated.
1768        *
1769        * @memberOf _.templateSettings
1770        * @type {RegExp}
1771        */
1772       'evaluate': reEvaluate,
1773
1774       /**
1775        * Used to detect `data` property values to inject.
1776        *
1777        * @memberOf _.templateSettings
1778        * @type {RegExp}
1779        */
1780       'interpolate': reInterpolate,
1781
1782       /**
1783        * Used to reference the data object in the template text.
1784        *
1785        * @memberOf _.templateSettings
1786        * @type {string}
1787        */
1788       'variable': '',
1789
1790       /**
1791        * Used to import variables into the compiled template.
1792        *
1793        * @memberOf _.templateSettings
1794        * @type {Object}
1795        */
1796       'imports': {
1797
1798         /**
1799          * A reference to the `lodash` function.
1800          *
1801          * @memberOf _.templateSettings.imports
1802          * @type {Function}
1803          */
1804         '_': lodash
1805       }
1806     };
1807
1808     // Ensure wrappers are instances of `baseLodash`.
1809     lodash.prototype = baseLodash.prototype;
1810     lodash.prototype.constructor = lodash;
1811
1812     LodashWrapper.prototype = baseCreate(baseLodash.prototype);
1813     LodashWrapper.prototype.constructor = LodashWrapper;
1814
1815     /*------------------------------------------------------------------------*/
1816
1817     /**
1818      * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
1819      *
1820      * @private
1821      * @constructor
1822      * @param {*} value The value to wrap.
1823      */
1824     function LazyWrapper(value) {
1825       this.__wrapped__ = value;
1826       this.__actions__ = [];
1827       this.__dir__ = 1;
1828       this.__filtered__ = false;
1829       this.__iteratees__ = [];
1830       this.__takeCount__ = MAX_ARRAY_LENGTH;
1831       this.__views__ = [];
1832     }
1833
1834     /**
1835      * Creates a clone of the lazy wrapper object.
1836      *
1837      * @private
1838      * @name clone
1839      * @memberOf LazyWrapper
1840      * @returns {Object} Returns the cloned `LazyWrapper` object.
1841      */
1842     function lazyClone() {
1843       var result = new LazyWrapper(this.__wrapped__);
1844       result.__actions__ = copyArray(this.__actions__);
1845       result.__dir__ = this.__dir__;
1846       result.__filtered__ = this.__filtered__;
1847       result.__iteratees__ = copyArray(this.__iteratees__);
1848       result.__takeCount__ = this.__takeCount__;
1849       result.__views__ = copyArray(this.__views__);
1850       return result;
1851     }
1852
1853     /**
1854      * Reverses the direction of lazy iteration.
1855      *
1856      * @private
1857      * @name reverse
1858      * @memberOf LazyWrapper
1859      * @returns {Object} Returns the new reversed `LazyWrapper` object.
1860      */
1861     function lazyReverse() {
1862       if (this.__filtered__) {
1863         var result = new LazyWrapper(this);
1864         result.__dir__ = -1;
1865         result.__filtered__ = true;
1866       } else {
1867         result = this.clone();
1868         result.__dir__ *= -1;
1869       }
1870       return result;
1871     }
1872
1873     /**
1874      * Extracts the unwrapped value from its lazy wrapper.
1875      *
1876      * @private
1877      * @name value
1878      * @memberOf LazyWrapper
1879      * @returns {*} Returns the unwrapped value.
1880      */
1881     function lazyValue() {
1882       var array = this.__wrapped__.value(),
1883           dir = this.__dir__,
1884           isArr = isArray(array),
1885           isRight = dir < 0,
1886           arrLength = isArr ? array.length : 0,
1887           view = getView(0, arrLength, this.__views__),
1888           start = view.start,
1889           end = view.end,
1890           length = end - start,
1891           index = isRight ? end : (start - 1),
1892           iteratees = this.__iteratees__,
1893           iterLength = iteratees.length,
1894           resIndex = 0,
1895           takeCount = nativeMin(length, this.__takeCount__);
1896
1897       if (!isArr || (!isRight && arrLength == length && takeCount == length)) {
1898         return baseWrapperValue(array, this.__actions__);
1899       }
1900       var result = [];
1901
1902       outer:
1903       while (length-- && resIndex < takeCount) {
1904         index += dir;
1905
1906         var iterIndex = -1,
1907             value = array[index];
1908
1909         while (++iterIndex < iterLength) {
1910           var data = iteratees[iterIndex],
1911               iteratee = data.iteratee,
1912               type = data.type,
1913               computed = iteratee(value);
1914
1915           if (type == LAZY_MAP_FLAG) {
1916             value = computed;
1917           } else if (!computed) {
1918             if (type == LAZY_FILTER_FLAG) {
1919               continue outer;
1920             } else {
1921               break outer;
1922             }
1923           }
1924         }
1925         result[resIndex++] = value;
1926       }
1927       return result;
1928     }
1929
1930     // Ensure `LazyWrapper` is an instance of `baseLodash`.
1931     LazyWrapper.prototype = baseCreate(baseLodash.prototype);
1932     LazyWrapper.prototype.constructor = LazyWrapper;
1933
1934     /*------------------------------------------------------------------------*/
1935
1936     /**
1937      * Creates a hash object.
1938      *
1939      * @private
1940      * @constructor
1941      * @param {Array} [entries] The key-value pairs to cache.
1942      */
1943     function Hash(entries) {
1944       var index = -1,
1945           length = entries == null ? 0 : entries.length;
1946
1947       this.clear();
1948       while (++index < length) {
1949         var entry = entries[index];
1950         this.set(entry[0], entry[1]);
1951       }
1952     }
1953
1954     /**
1955      * Removes all key-value entries from the hash.
1956      *
1957      * @private
1958      * @name clear
1959      * @memberOf Hash
1960      */
1961     function hashClear() {
1962       this.__data__ = nativeCreate ? nativeCreate(null) : {};
1963       this.size = 0;
1964     }
1965
1966     /**
1967      * Removes `key` and its value from the hash.
1968      *
1969      * @private
1970      * @name delete
1971      * @memberOf Hash
1972      * @param {Object} hash The hash to modify.
1973      * @param {string} key The key of the value to remove.
1974      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
1975      */
1976     function hashDelete(key) {
1977       var result = this.has(key) && delete this.__data__[key];
1978       this.size -= result ? 1 : 0;
1979       return result;
1980     }
1981
1982     /**
1983      * Gets the hash value for `key`.
1984      *
1985      * @private
1986      * @name get
1987      * @memberOf Hash
1988      * @param {string} key The key of the value to get.
1989      * @returns {*} Returns the entry value.
1990      */
1991     function hashGet(key) {
1992       var data = this.__data__;
1993       if (nativeCreate) {
1994         var result = data[key];
1995         return result === HASH_UNDEFINED ? undefined : result;
1996       }
1997       return hasOwnProperty.call(data, key) ? data[key] : undefined;
1998     }
1999
2000     /**
2001      * Checks if a hash value for `key` exists.
2002      *
2003      * @private
2004      * @name has
2005      * @memberOf Hash
2006      * @param {string} key The key of the entry to check.
2007      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2008      */
2009     function hashHas(key) {
2010       var data = this.__data__;
2011       return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
2012     }
2013
2014     /**
2015      * Sets the hash `key` to `value`.
2016      *
2017      * @private
2018      * @name set
2019      * @memberOf Hash
2020      * @param {string} key The key of the value to set.
2021      * @param {*} value The value to set.
2022      * @returns {Object} Returns the hash instance.
2023      */
2024     function hashSet(key, value) {
2025       var data = this.__data__;
2026       this.size += this.has(key) ? 0 : 1;
2027       data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
2028       return this;
2029     }
2030
2031     // Add methods to `Hash`.
2032     Hash.prototype.clear = hashClear;
2033     Hash.prototype['delete'] = hashDelete;
2034     Hash.prototype.get = hashGet;
2035     Hash.prototype.has = hashHas;
2036     Hash.prototype.set = hashSet;
2037
2038     /*------------------------------------------------------------------------*/
2039
2040     /**
2041      * Creates an list cache object.
2042      *
2043      * @private
2044      * @constructor
2045      * @param {Array} [entries] The key-value pairs to cache.
2046      */
2047     function ListCache(entries) {
2048       var index = -1,
2049           length = entries == null ? 0 : entries.length;
2050
2051       this.clear();
2052       while (++index < length) {
2053         var entry = entries[index];
2054         this.set(entry[0], entry[1]);
2055       }
2056     }
2057
2058     /**
2059      * Removes all key-value entries from the list cache.
2060      *
2061      * @private
2062      * @name clear
2063      * @memberOf ListCache
2064      */
2065     function listCacheClear() {
2066       this.__data__ = [];
2067       this.size = 0;
2068     }
2069
2070     /**
2071      * Removes `key` and its value from the list cache.
2072      *
2073      * @private
2074      * @name delete
2075      * @memberOf ListCache
2076      * @param {string} key The key of the value to remove.
2077      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2078      */
2079     function listCacheDelete(key) {
2080       var data = this.__data__,
2081           index = assocIndexOf(data, key);
2082
2083       if (index < 0) {
2084         return false;
2085       }
2086       var lastIndex = data.length - 1;
2087       if (index == lastIndex) {
2088         data.pop();
2089       } else {
2090         splice.call(data, index, 1);
2091       }
2092       --this.size;
2093       return true;
2094     }
2095
2096     /**
2097      * Gets the list cache value for `key`.
2098      *
2099      * @private
2100      * @name get
2101      * @memberOf ListCache
2102      * @param {string} key The key of the value to get.
2103      * @returns {*} Returns the entry value.
2104      */
2105     function listCacheGet(key) {
2106       var data = this.__data__,
2107           index = assocIndexOf(data, key);
2108
2109       return index < 0 ? undefined : data[index][1];
2110     }
2111
2112     /**
2113      * Checks if a list cache value for `key` exists.
2114      *
2115      * @private
2116      * @name has
2117      * @memberOf ListCache
2118      * @param {string} key The key of the entry to check.
2119      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2120      */
2121     function listCacheHas(key) {
2122       return assocIndexOf(this.__data__, key) > -1;
2123     }
2124
2125     /**
2126      * Sets the list cache `key` to `value`.
2127      *
2128      * @private
2129      * @name set
2130      * @memberOf ListCache
2131      * @param {string} key The key of the value to set.
2132      * @param {*} value The value to set.
2133      * @returns {Object} Returns the list cache instance.
2134      */
2135     function listCacheSet(key, value) {
2136       var data = this.__data__,
2137           index = assocIndexOf(data, key);
2138
2139       if (index < 0) {
2140         ++this.size;
2141         data.push([key, value]);
2142       } else {
2143         data[index][1] = value;
2144       }
2145       return this;
2146     }
2147
2148     // Add methods to `ListCache`.
2149     ListCache.prototype.clear = listCacheClear;
2150     ListCache.prototype['delete'] = listCacheDelete;
2151     ListCache.prototype.get = listCacheGet;
2152     ListCache.prototype.has = listCacheHas;
2153     ListCache.prototype.set = listCacheSet;
2154
2155     /*------------------------------------------------------------------------*/
2156
2157     /**
2158      * Creates a map cache object to store key-value pairs.
2159      *
2160      * @private
2161      * @constructor
2162      * @param {Array} [entries] The key-value pairs to cache.
2163      */
2164     function MapCache(entries) {
2165       var index = -1,
2166           length = entries == null ? 0 : entries.length;
2167
2168       this.clear();
2169       while (++index < length) {
2170         var entry = entries[index];
2171         this.set(entry[0], entry[1]);
2172       }
2173     }
2174
2175     /**
2176      * Removes all key-value entries from the map.
2177      *
2178      * @private
2179      * @name clear
2180      * @memberOf MapCache
2181      */
2182     function mapCacheClear() {
2183       this.size = 0;
2184       this.__data__ = {
2185         'hash': new Hash,
2186         'map': new (Map || ListCache),
2187         'string': new Hash
2188       };
2189     }
2190
2191     /**
2192      * Removes `key` and its value from the map.
2193      *
2194      * @private
2195      * @name delete
2196      * @memberOf MapCache
2197      * @param {string} key The key of the value to remove.
2198      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2199      */
2200     function mapCacheDelete(key) {
2201       var result = getMapData(this, key)['delete'](key);
2202       this.size -= result ? 1 : 0;
2203       return result;
2204     }
2205
2206     /**
2207      * Gets the map value for `key`.
2208      *
2209      * @private
2210      * @name get
2211      * @memberOf MapCache
2212      * @param {string} key The key of the value to get.
2213      * @returns {*} Returns the entry value.
2214      */
2215     function mapCacheGet(key) {
2216       return getMapData(this, key).get(key);
2217     }
2218
2219     /**
2220      * Checks if a map value for `key` exists.
2221      *
2222      * @private
2223      * @name has
2224      * @memberOf MapCache
2225      * @param {string} key The key of the entry to check.
2226      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2227      */
2228     function mapCacheHas(key) {
2229       return getMapData(this, key).has(key);
2230     }
2231
2232     /**
2233      * Sets the map `key` to `value`.
2234      *
2235      * @private
2236      * @name set
2237      * @memberOf MapCache
2238      * @param {string} key The key of the value to set.
2239      * @param {*} value The value to set.
2240      * @returns {Object} Returns the map cache instance.
2241      */
2242     function mapCacheSet(key, value) {
2243       var data = getMapData(this, key),
2244           size = data.size;
2245
2246       data.set(key, value);
2247       this.size += data.size == size ? 0 : 1;
2248       return this;
2249     }
2250
2251     // Add methods to `MapCache`.
2252     MapCache.prototype.clear = mapCacheClear;
2253     MapCache.prototype['delete'] = mapCacheDelete;
2254     MapCache.prototype.get = mapCacheGet;
2255     MapCache.prototype.has = mapCacheHas;
2256     MapCache.prototype.set = mapCacheSet;
2257
2258     /*------------------------------------------------------------------------*/
2259
2260     /**
2261      *
2262      * Creates an array cache object to store unique values.
2263      *
2264      * @private
2265      * @constructor
2266      * @param {Array} [values] The values to cache.
2267      */
2268     function SetCache(values) {
2269       var index = -1,
2270           length = values == null ? 0 : values.length;
2271
2272       this.__data__ = new MapCache;
2273       while (++index < length) {
2274         this.add(values[index]);
2275       }
2276     }
2277
2278     /**
2279      * Adds `value` to the array cache.
2280      *
2281      * @private
2282      * @name add
2283      * @memberOf SetCache
2284      * @alias push
2285      * @param {*} value The value to cache.
2286      * @returns {Object} Returns the cache instance.
2287      */
2288     function setCacheAdd(value) {
2289       this.__data__.set(value, HASH_UNDEFINED);
2290       return this;
2291     }
2292
2293     /**
2294      * Checks if `value` is in the array cache.
2295      *
2296      * @private
2297      * @name has
2298      * @memberOf SetCache
2299      * @param {*} value The value to search for.
2300      * @returns {number} Returns `true` if `value` is found, else `false`.
2301      */
2302     function setCacheHas(value) {
2303       return this.__data__.has(value);
2304     }
2305
2306     // Add methods to `SetCache`.
2307     SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
2308     SetCache.prototype.has = setCacheHas;
2309
2310     /*------------------------------------------------------------------------*/
2311
2312     /**
2313      * Creates a stack cache object to store key-value pairs.
2314      *
2315      * @private
2316      * @constructor
2317      * @param {Array} [entries] The key-value pairs to cache.
2318      */
2319     function Stack(entries) {
2320       var data = this.__data__ = new ListCache(entries);
2321       this.size = data.size;
2322     }
2323
2324     /**
2325      * Removes all key-value entries from the stack.
2326      *
2327      * @private
2328      * @name clear
2329      * @memberOf Stack
2330      */
2331     function stackClear() {
2332       this.__data__ = new ListCache;
2333       this.size = 0;
2334     }
2335
2336     /**
2337      * Removes `key` and its value from the stack.
2338      *
2339      * @private
2340      * @name delete
2341      * @memberOf Stack
2342      * @param {string} key The key of the value to remove.
2343      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2344      */
2345     function stackDelete(key) {
2346       var data = this.__data__,
2347           result = data['delete'](key);
2348
2349       this.size = data.size;
2350       return result;
2351     }
2352
2353     /**
2354      * Gets the stack value for `key`.
2355      *
2356      * @private
2357      * @name get
2358      * @memberOf Stack
2359      * @param {string} key The key of the value to get.
2360      * @returns {*} Returns the entry value.
2361      */
2362     function stackGet(key) {
2363       return this.__data__.get(key);
2364     }
2365
2366     /**
2367      * Checks if a stack value for `key` exists.
2368      *
2369      * @private
2370      * @name has
2371      * @memberOf Stack
2372      * @param {string} key The key of the entry to check.
2373      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2374      */
2375     function stackHas(key) {
2376       return this.__data__.has(key);
2377     }
2378
2379     /**
2380      * Sets the stack `key` to `value`.
2381      *
2382      * @private
2383      * @name set
2384      * @memberOf Stack
2385      * @param {string} key The key of the value to set.
2386      * @param {*} value The value to set.
2387      * @returns {Object} Returns the stack cache instance.
2388      */
2389     function stackSet(key, value) {
2390       var data = this.__data__;
2391       if (data instanceof ListCache) {
2392         var pairs = data.__data__;
2393         if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
2394           pairs.push([key, value]);
2395           this.size = ++data.size;
2396           return this;
2397         }
2398         data = this.__data__ = new MapCache(pairs);
2399       }
2400       data.set(key, value);
2401       this.size = data.size;
2402       return this;
2403     }
2404
2405     // Add methods to `Stack`.
2406     Stack.prototype.clear = stackClear;
2407     Stack.prototype['delete'] = stackDelete;
2408     Stack.prototype.get = stackGet;
2409     Stack.prototype.has = stackHas;
2410     Stack.prototype.set = stackSet;
2411
2412     /*------------------------------------------------------------------------*/
2413
2414     /**
2415      * Creates an array of the enumerable property names of the array-like `value`.
2416      *
2417      * @private
2418      * @param {*} value The value to query.
2419      * @param {boolean} inherited Specify returning inherited property names.
2420      * @returns {Array} Returns the array of property names.
2421      */
2422     function arrayLikeKeys(value, inherited) {
2423       var isArr = isArray(value),
2424           isArg = !isArr && isArguments(value),
2425           isBuff = !isArr && !isArg && isBuffer(value),
2426           isType = !isArr && !isArg && !isBuff && isTypedArray(value),
2427           skipIndexes = isArr || isArg || isBuff || isType,
2428           result = skipIndexes ? baseTimes(value.length, String) : [],
2429           length = result.length;
2430
2431       for (var key in value) {
2432         if ((inherited || hasOwnProperty.call(value, key)) &&
2433             !(skipIndexes && (
2434                // Safari 9 has enumerable `arguments.length` in strict mode.
2435                key == 'length' ||
2436                // Node.js 0.10 has enumerable non-index properties on buffers.
2437                (isBuff && (key == 'offset' || key == 'parent')) ||
2438                // PhantomJS 2 has enumerable non-index properties on typed arrays.
2439                (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
2440                // Skip index properties.
2441                isIndex(key, length)
2442             ))) {
2443           result.push(key);
2444         }
2445       }
2446       return result;
2447     }
2448
2449     /**
2450      * A specialized version of `_.sample` for arrays.
2451      *
2452      * @private
2453      * @param {Array} array The array to sample.
2454      * @returns {*} Returns the random element.
2455      */
2456     function arraySample(array) {
2457       var length = array.length;
2458       return length ? array[baseRandom(0, length - 1)] : undefined;
2459     }
2460
2461     /**
2462      * A specialized version of `_.sampleSize` for arrays.
2463      *
2464      * @private
2465      * @param {Array} array The array to sample.
2466      * @param {number} n The number of elements to sample.
2467      * @returns {Array} Returns the random elements.
2468      */
2469     function arraySampleSize(array, n) {
2470       return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
2471     }
2472
2473     /**
2474      * A specialized version of `_.shuffle` for arrays.
2475      *
2476      * @private
2477      * @param {Array} array The array to shuffle.
2478      * @returns {Array} Returns the new shuffled array.
2479      */
2480     function arrayShuffle(array) {
2481       return shuffleSelf(copyArray(array));
2482     }
2483
2484     /**
2485      * This function is like `assignValue` except that it doesn't assign
2486      * `undefined` values.
2487      *
2488      * @private
2489      * @param {Object} object The object to modify.
2490      * @param {string} key The key of the property to assign.
2491      * @param {*} value The value to assign.
2492      */
2493     function assignMergeValue(object, key, value) {
2494       if ((value !== undefined && !eq(object[key], value)) ||
2495           (value === undefined && !(key in object))) {
2496         baseAssignValue(object, key, value);
2497       }
2498     }
2499
2500     /**
2501      * Assigns `value` to `key` of `object` if the existing value is not equivalent
2502      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
2503      * for equality comparisons.
2504      *
2505      * @private
2506      * @param {Object} object The object to modify.
2507      * @param {string} key The key of the property to assign.
2508      * @param {*} value The value to assign.
2509      */
2510     function assignValue(object, key, value) {
2511       var objValue = object[key];
2512       if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
2513           (value === undefined && !(key in object))) {
2514         baseAssignValue(object, key, value);
2515       }
2516     }
2517
2518     /**
2519      * Gets the index at which the `key` is found in `array` of key-value pairs.
2520      *
2521      * @private
2522      * @param {Array} array The array to inspect.
2523      * @param {*} key The key to search for.
2524      * @returns {number} Returns the index of the matched value, else `-1`.
2525      */
2526     function assocIndexOf(array, key) {
2527       var length = array.length;
2528       while (length--) {
2529         if (eq(array[length][0], key)) {
2530           return length;
2531         }
2532       }
2533       return -1;
2534     }
2535
2536     /**
2537      * Aggregates elements of `collection` on `accumulator` with keys transformed
2538      * by `iteratee` and values set by `setter`.
2539      *
2540      * @private
2541      * @param {Array|Object} collection The collection to iterate over.
2542      * @param {Function} setter The function to set `accumulator` values.
2543      * @param {Function} iteratee The iteratee to transform keys.
2544      * @param {Object} accumulator The initial aggregated object.
2545      * @returns {Function} Returns `accumulator`.
2546      */
2547     function baseAggregator(collection, setter, iteratee, accumulator) {
2548       baseEach(collection, function(value, key, collection) {
2549         setter(accumulator, value, iteratee(value), collection);
2550       });
2551       return accumulator;
2552     }
2553
2554     /**
2555      * The base implementation of `_.assign` without support for multiple sources
2556      * or `customizer` functions.
2557      *
2558      * @private
2559      * @param {Object} object The destination object.
2560      * @param {Object} source The source object.
2561      * @returns {Object} Returns `object`.
2562      */
2563     function baseAssign(object, source) {
2564       return object && copyObject(source, keys(source), object);
2565     }
2566
2567     /**
2568      * The base implementation of `_.assignIn` without support for multiple sources
2569      * or `customizer` functions.
2570      *
2571      * @private
2572      * @param {Object} object The destination object.
2573      * @param {Object} source The source object.
2574      * @returns {Object} Returns `object`.
2575      */
2576     function baseAssignIn(object, source) {
2577       return object && copyObject(source, keysIn(source), object);
2578     }
2579
2580     /**
2581      * The base implementation of `assignValue` and `assignMergeValue` without
2582      * value checks.
2583      *
2584      * @private
2585      * @param {Object} object The object to modify.
2586      * @param {string} key The key of the property to assign.
2587      * @param {*} value The value to assign.
2588      */
2589     function baseAssignValue(object, key, value) {
2590       if (key == '__proto__' && defineProperty) {
2591         defineProperty(object, key, {
2592           'configurable': true,
2593           'enumerable': true,
2594           'value': value,
2595           'writable': true
2596         });
2597       } else {
2598         object[key] = value;
2599       }
2600     }
2601
2602     /**
2603      * The base implementation of `_.at` without support for individual paths.
2604      *
2605      * @private
2606      * @param {Object} object The object to iterate over.
2607      * @param {string[]} paths The property paths to pick.
2608      * @returns {Array} Returns the picked elements.
2609      */
2610     function baseAt(object, paths) {
2611       var index = -1,
2612           length = paths.length,
2613           result = Array(length),
2614           skip = object == null;
2615
2616       while (++index < length) {
2617         result[index] = skip ? undefined : get(object, paths[index]);
2618       }
2619       return result;
2620     }
2621
2622     /**
2623      * The base implementation of `_.clamp` which doesn't coerce arguments.
2624      *
2625      * @private
2626      * @param {number} number The number to clamp.
2627      * @param {number} [lower] The lower bound.
2628      * @param {number} upper The upper bound.
2629      * @returns {number} Returns the clamped number.
2630      */
2631     function baseClamp(number, lower, upper) {
2632       if (number === number) {
2633         if (upper !== undefined) {
2634           number = number <= upper ? number : upper;
2635         }
2636         if (lower !== undefined) {
2637           number = number >= lower ? number : lower;
2638         }
2639       }
2640       return number;
2641     }
2642
2643     /**
2644      * The base implementation of `_.clone` and `_.cloneDeep` which tracks
2645      * traversed objects.
2646      *
2647      * @private
2648      * @param {*} value The value to clone.
2649      * @param {boolean} bitmask The bitmask flags.
2650      *  1 - Deep clone
2651      *  2 - Flatten inherited properties
2652      *  4 - Clone symbols
2653      * @param {Function} [customizer] The function to customize cloning.
2654      * @param {string} [key] The key of `value`.
2655      * @param {Object} [object] The parent object of `value`.
2656      * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
2657      * @returns {*} Returns the cloned value.
2658      */
2659     function baseClone(value, bitmask, customizer, key, object, stack) {
2660       var result,
2661           isDeep = bitmask & CLONE_DEEP_FLAG,
2662           isFlat = bitmask & CLONE_FLAT_FLAG,
2663           isFull = bitmask & CLONE_SYMBOLS_FLAG;
2664
2665       if (customizer) {
2666         result = object ? customizer(value, key, object, stack) : customizer(value);
2667       }
2668       if (result !== undefined) {
2669         return result;
2670       }
2671       if (!isObject(value)) {
2672         return value;
2673       }
2674       var isArr = isArray(value);
2675       if (isArr) {
2676         result = initCloneArray(value);
2677         if (!isDeep) {
2678           return copyArray(value, result);
2679         }
2680       } else {
2681         var tag = getTag(value),
2682             isFunc = tag == funcTag || tag == genTag;
2683
2684         if (isBuffer(value)) {
2685           return cloneBuffer(value, isDeep);
2686         }
2687         if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
2688           result = (isFlat || isFunc) ? {} : initCloneObject(value);
2689           if (!isDeep) {
2690             return isFlat
2691               ? copySymbolsIn(value, baseAssignIn(result, value))
2692               : copySymbols(value, baseAssign(result, value));
2693           }
2694         } else {
2695           if (!cloneableTags[tag]) {
2696             return object ? value : {};
2697           }
2698           result = initCloneByTag(value, tag, baseClone, isDeep);
2699         }
2700       }
2701       // Check for circular references and return its corresponding clone.
2702       stack || (stack = new Stack);
2703       var stacked = stack.get(value);
2704       if (stacked) {
2705         return stacked;
2706       }
2707       stack.set(value, result);
2708
2709       var keysFunc = isFull
2710         ? (isFlat ? getAllKeysIn : getAllKeys)
2711         : (isFlat ? keysIn : keys);
2712
2713       var props = isArr ? undefined : keysFunc(value);
2714       arrayEach(props || value, function(subValue, key) {
2715         if (props) {
2716           key = subValue;
2717           subValue = value[key];
2718         }
2719         // Recursively populate clone (susceptible to call stack limits).
2720         assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
2721       });
2722       return result;
2723     }
2724
2725     /**
2726      * The base implementation of `_.conforms` which doesn't clone `source`.
2727      *
2728      * @private
2729      * @param {Object} source The object of property predicates to conform to.
2730      * @returns {Function} Returns the new spec function.
2731      */
2732     function baseConforms(source) {
2733       var props = keys(source);
2734       return function(object) {
2735         return baseConformsTo(object, source, props);
2736       };
2737     }
2738
2739     /**
2740      * The base implementation of `_.conformsTo` which accepts `props` to check.
2741      *
2742      * @private
2743      * @param {Object} object The object to inspect.
2744      * @param {Object} source The object of property predicates to conform to.
2745      * @returns {boolean} Returns `true` if `object` conforms, else `false`.
2746      */
2747     function baseConformsTo(object, source, props) {
2748       var length = props.length;
2749       if (object == null) {
2750         return !length;
2751       }
2752       object = Object(object);
2753       while (length--) {
2754         var key = props[length],
2755             predicate = source[key],
2756             value = object[key];
2757
2758         if ((value === undefined && !(key in object)) || !predicate(value)) {
2759           return false;
2760         }
2761       }
2762       return true;
2763     }
2764
2765     /**
2766      * The base implementation of `_.delay` and `_.defer` which accepts `args`
2767      * to provide to `func`.
2768      *
2769      * @private
2770      * @param {Function} func The function to delay.
2771      * @param {number} wait The number of milliseconds to delay invocation.
2772      * @param {Array} args The arguments to provide to `func`.
2773      * @returns {number|Object} Returns the timer id or timeout object.
2774      */
2775     function baseDelay(func, wait, args) {
2776       if (typeof func != 'function') {
2777         throw new TypeError(FUNC_ERROR_TEXT);
2778       }
2779       return setTimeout(function() { func.apply(undefined, args); }, wait);
2780     }
2781
2782     /**
2783      * The base implementation of methods like `_.difference` without support
2784      * for excluding multiple arrays or iteratee shorthands.
2785      *
2786      * @private
2787      * @param {Array} array The array to inspect.
2788      * @param {Array} values The values to exclude.
2789      * @param {Function} [iteratee] The iteratee invoked per element.
2790      * @param {Function} [comparator] The comparator invoked per element.
2791      * @returns {Array} Returns the new array of filtered values.
2792      */
2793     function baseDifference(array, values, iteratee, comparator) {
2794       var index = -1,
2795           includes = arrayIncludes,
2796           isCommon = true,
2797           length = array.length,
2798           result = [],
2799           valuesLength = values.length;
2800
2801       if (!length) {
2802         return result;
2803       }
2804       if (iteratee) {
2805         values = arrayMap(values, baseUnary(iteratee));
2806       }
2807       if (comparator) {
2808         includes = arrayIncludesWith;
2809         isCommon = false;
2810       }
2811       else if (values.length >= LARGE_ARRAY_SIZE) {
2812         includes = cacheHas;
2813         isCommon = false;
2814         values = new SetCache(values);
2815       }
2816       outer:
2817       while (++index < length) {
2818         var value = array[index],
2819             computed = iteratee == null ? value : iteratee(value);
2820
2821         value = (comparator || value !== 0) ? value : 0;
2822         if (isCommon && computed === computed) {
2823           var valuesIndex = valuesLength;
2824           while (valuesIndex--) {
2825             if (values[valuesIndex] === computed) {
2826               continue outer;
2827             }
2828           }
2829           result.push(value);
2830         }
2831         else if (!includes(values, computed, comparator)) {
2832           result.push(value);
2833         }
2834       }
2835       return result;
2836     }
2837
2838     /**
2839      * The base implementation of `_.forEach` without support for iteratee shorthands.
2840      *
2841      * @private
2842      * @param {Array|Object} collection The collection to iterate over.
2843      * @param {Function} iteratee The function invoked per iteration.
2844      * @returns {Array|Object} Returns `collection`.
2845      */
2846     var baseEach = createBaseEach(baseForOwn);
2847
2848     /**
2849      * The base implementation of `_.forEachRight` without support for iteratee shorthands.
2850      *
2851      * @private
2852      * @param {Array|Object} collection The collection to iterate over.
2853      * @param {Function} iteratee The function invoked per iteration.
2854      * @returns {Array|Object} Returns `collection`.
2855      */
2856     var baseEachRight = createBaseEach(baseForOwnRight, true);
2857
2858     /**
2859      * The base implementation of `_.every` without support for iteratee shorthands.
2860      *
2861      * @private
2862      * @param {Array|Object} collection The collection to iterate over.
2863      * @param {Function} predicate The function invoked per iteration.
2864      * @returns {boolean} Returns `true` if all elements pass the predicate check,
2865      *  else `false`
2866      */
2867     function baseEvery(collection, predicate) {
2868       var result = true;
2869       baseEach(collection, function(value, index, collection) {
2870         result = !!predicate(value, index, collection);
2871         return result;
2872       });
2873       return result;
2874     }
2875
2876     /**
2877      * The base implementation of methods like `_.max` and `_.min` which accepts a
2878      * `comparator` to determine the extremum value.
2879      *
2880      * @private
2881      * @param {Array} array The array to iterate over.
2882      * @param {Function} iteratee The iteratee invoked per iteration.
2883      * @param {Function} comparator The comparator used to compare values.
2884      * @returns {*} Returns the extremum value.
2885      */
2886     function baseExtremum(array, iteratee, comparator) {
2887       var index = -1,
2888           length = array.length;
2889
2890       while (++index < length) {
2891         var value = array[index],
2892             current = iteratee(value);
2893
2894         if (current != null && (computed === undefined
2895               ? (current === current && !isSymbol(current))
2896               : comparator(current, computed)
2897             )) {
2898           var computed = current,
2899               result = value;
2900         }
2901       }
2902       return result;
2903     }
2904
2905     /**
2906      * The base implementation of `_.fill` without an iteratee call guard.
2907      *
2908      * @private
2909      * @param {Array} array The array to fill.
2910      * @param {*} value The value to fill `array` with.
2911      * @param {number} [start=0] The start position.
2912      * @param {number} [end=array.length] The end position.
2913      * @returns {Array} Returns `array`.
2914      */
2915     function baseFill(array, value, start, end) {
2916       var length = array.length;
2917
2918       start = toInteger(start);
2919       if (start < 0) {
2920         start = -start > length ? 0 : (length + start);
2921       }
2922       end = (end === undefined || end > length) ? length : toInteger(end);
2923       if (end < 0) {
2924         end += length;
2925       }
2926       end = start > end ? 0 : toLength(end);
2927       while (start < end) {
2928         array[start++] = value;
2929       }
2930       return array;
2931     }
2932
2933     /**
2934      * The base implementation of `_.filter` without support for iteratee shorthands.
2935      *
2936      * @private
2937      * @param {Array|Object} collection The collection to iterate over.
2938      * @param {Function} predicate The function invoked per iteration.
2939      * @returns {Array} Returns the new filtered array.
2940      */
2941     function baseFilter(collection, predicate) {
2942       var result = [];
2943       baseEach(collection, function(value, index, collection) {
2944         if (predicate(value, index, collection)) {
2945           result.push(value);
2946         }
2947       });
2948       return result;
2949     }
2950
2951     /**
2952      * The base implementation of `_.flatten` with support for restricting flattening.
2953      *
2954      * @private
2955      * @param {Array} array The array to flatten.
2956      * @param {number} depth The maximum recursion depth.
2957      * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
2958      * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
2959      * @param {Array} [result=[]] The initial result value.
2960      * @returns {Array} Returns the new flattened array.
2961      */
2962     function baseFlatten(array, depth, predicate, isStrict, result) {
2963       var index = -1,
2964           length = array.length;
2965
2966       predicate || (predicate = isFlattenable);
2967       result || (result = []);
2968
2969       while (++index < length) {
2970         var value = array[index];
2971         if (depth > 0 && predicate(value)) {
2972           if (depth > 1) {
2973             // Recursively flatten arrays (susceptible to call stack limits).
2974             baseFlatten(value, depth - 1, predicate, isStrict, result);
2975           } else {
2976             arrayPush(result, value);
2977           }
2978         } else if (!isStrict) {
2979           result[result.length] = value;
2980         }
2981       }
2982       return result;
2983     }
2984
2985     /**
2986      * The base implementation of `baseForOwn` which iterates over `object`
2987      * properties returned by `keysFunc` and invokes `iteratee` for each property.
2988      * Iteratee functions may exit iteration early by explicitly returning `false`.
2989      *
2990      * @private
2991      * @param {Object} object The object to iterate over.
2992      * @param {Function} iteratee The function invoked per iteration.
2993      * @param {Function} keysFunc The function to get the keys of `object`.
2994      * @returns {Object} Returns `object`.
2995      */
2996     var baseFor = createBaseFor();
2997
2998     /**
2999      * This function is like `baseFor` except that it iterates over properties
3000      * in the opposite order.
3001      *
3002      * @private
3003      * @param {Object} object The object to iterate over.
3004      * @param {Function} iteratee The function invoked per iteration.
3005      * @param {Function} keysFunc The function to get the keys of `object`.
3006      * @returns {Object} Returns `object`.
3007      */
3008     var baseForRight = createBaseFor(true);
3009
3010     /**
3011      * The base implementation of `_.forOwn` without support for iteratee shorthands.
3012      *
3013      * @private
3014      * @param {Object} object The object to iterate over.
3015      * @param {Function} iteratee The function invoked per iteration.
3016      * @returns {Object} Returns `object`.
3017      */
3018     function baseForOwn(object, iteratee) {
3019       return object && baseFor(object, iteratee, keys);
3020     }
3021
3022     /**
3023      * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
3024      *
3025      * @private
3026      * @param {Object} object The object to iterate over.
3027      * @param {Function} iteratee The function invoked per iteration.
3028      * @returns {Object} Returns `object`.
3029      */
3030     function baseForOwnRight(object, iteratee) {
3031       return object && baseForRight(object, iteratee, keys);
3032     }
3033
3034     /**
3035      * The base implementation of `_.functions` which creates an array of
3036      * `object` function property names filtered from `props`.
3037      *
3038      * @private
3039      * @param {Object} object The object to inspect.
3040      * @param {Array} props The property names to filter.
3041      * @returns {Array} Returns the function names.
3042      */
3043     function baseFunctions(object, props) {
3044       return arrayFilter(props, function(key) {
3045         return isFunction(object[key]);
3046       });
3047     }
3048
3049     /**
3050      * The base implementation of `_.get` without support for default values.
3051      *
3052      * @private
3053      * @param {Object} object The object to query.
3054      * @param {Array|string} path The path of the property to get.
3055      * @returns {*} Returns the resolved value.
3056      */
3057     function baseGet(object, path) {
3058       path = castPath(path, object);
3059
3060       var index = 0,
3061           length = path.length;
3062
3063       while (object != null && index < length) {
3064         object = object[toKey(path[index++])];
3065       }
3066       return (index && index == length) ? object : undefined;
3067     }
3068
3069     /**
3070      * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
3071      * `keysFunc` and `symbolsFunc` to get the enumerable property names and
3072      * symbols of `object`.
3073      *
3074      * @private
3075      * @param {Object} object The object to query.
3076      * @param {Function} keysFunc The function to get the keys of `object`.
3077      * @param {Function} symbolsFunc The function to get the symbols of `object`.
3078      * @returns {Array} Returns the array of property names and symbols.
3079      */
3080     function baseGetAllKeys(object, keysFunc, symbolsFunc) {
3081       var result = keysFunc(object);
3082       return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
3083     }
3084
3085     /**
3086      * The base implementation of `getTag` without fallbacks for buggy environments.
3087      *
3088      * @private
3089      * @param {*} value The value to query.
3090      * @returns {string} Returns the `toStringTag`.
3091      */
3092     function baseGetTag(value) {
3093       if (value == null) {
3094         return value === undefined ? undefinedTag : nullTag;
3095       }
3096       return (symToStringTag && symToStringTag in Object(value))
3097         ? getRawTag(value)
3098         : objectToString(value);
3099     }
3100
3101     /**
3102      * The base implementation of `_.gt` which doesn't coerce arguments.
3103      *
3104      * @private
3105      * @param {*} value The value to compare.
3106      * @param {*} other The other value to compare.
3107      * @returns {boolean} Returns `true` if `value` is greater than `other`,
3108      *  else `false`.
3109      */
3110     function baseGt(value, other) {
3111       return value > other;
3112     }
3113
3114     /**
3115      * The base implementation of `_.has` without support for deep paths.
3116      *
3117      * @private
3118      * @param {Object} [object] The object to query.
3119      * @param {Array|string} key The key to check.
3120      * @returns {boolean} Returns `true` if `key` exists, else `false`.
3121      */
3122     function baseHas(object, key) {
3123       return object != null && hasOwnProperty.call(object, key);
3124     }
3125
3126     /**
3127      * The base implementation of `_.hasIn` without support for deep paths.
3128      *
3129      * @private
3130      * @param {Object} [object] The object to query.
3131      * @param {Array|string} key The key to check.
3132      * @returns {boolean} Returns `true` if `key` exists, else `false`.
3133      */
3134     function baseHasIn(object, key) {
3135       return object != null && key in Object(object);
3136     }
3137
3138     /**
3139      * The base implementation of `_.inRange` which doesn't coerce arguments.
3140      *
3141      * @private
3142      * @param {number} number The number to check.
3143      * @param {number} start The start of the range.
3144      * @param {number} end The end of the range.
3145      * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
3146      */
3147     function baseInRange(number, start, end) {
3148       return number >= nativeMin(start, end) && number < nativeMax(start, end);
3149     }
3150
3151     /**
3152      * The base implementation of methods like `_.intersection`, without support
3153      * for iteratee shorthands, that accepts an array of arrays to inspect.
3154      *
3155      * @private
3156      * @param {Array} arrays The arrays to inspect.
3157      * @param {Function} [iteratee] The iteratee invoked per element.
3158      * @param {Function} [comparator] The comparator invoked per element.
3159      * @returns {Array} Returns the new array of shared values.
3160      */
3161     function baseIntersection(arrays, iteratee, comparator) {
3162       var includes = comparator ? arrayIncludesWith : arrayIncludes,
3163           length = arrays[0].length,
3164           othLength = arrays.length,
3165           othIndex = othLength,
3166           caches = Array(othLength),
3167           maxLength = Infinity,
3168           result = [];
3169
3170       while (othIndex--) {
3171         var array = arrays[othIndex];
3172         if (othIndex && iteratee) {
3173           array = arrayMap(array, baseUnary(iteratee));
3174         }
3175         maxLength = nativeMin(array.length, maxLength);
3176         caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
3177           ? new SetCache(othIndex && array)
3178           : undefined;
3179       }
3180       array = arrays[0];
3181
3182       var index = -1,
3183           seen = caches[0];
3184
3185       outer:
3186       while (++index < length && result.length < maxLength) {
3187         var value = array[index],
3188             computed = iteratee ? iteratee(value) : value;
3189
3190         value = (comparator || value !== 0) ? value : 0;
3191         if (!(seen
3192               ? cacheHas(seen, computed)
3193               : includes(result, computed, comparator)
3194             )) {
3195           othIndex = othLength;
3196           while (--othIndex) {
3197             var cache = caches[othIndex];
3198             if (!(cache
3199                   ? cacheHas(cache, computed)
3200                   : includes(arrays[othIndex], computed, comparator))
3201                 ) {
3202               continue outer;
3203             }
3204           }
3205           if (seen) {
3206             seen.push(computed);
3207           }
3208           result.push(value);
3209         }
3210       }
3211       return result;
3212     }
3213
3214     /**
3215      * The base implementation of `_.invert` and `_.invertBy` which inverts
3216      * `object` with values transformed by `iteratee` and set by `setter`.
3217      *
3218      * @private
3219      * @param {Object} object The object to iterate over.
3220      * @param {Function} setter The function to set `accumulator` values.
3221      * @param {Function} iteratee The iteratee to transform values.
3222      * @param {Object} accumulator The initial inverted object.
3223      * @returns {Function} Returns `accumulator`.
3224      */
3225     function baseInverter(object, setter, iteratee, accumulator) {
3226       baseForOwn(object, function(value, key, object) {
3227         setter(accumulator, iteratee(value), key, object);
3228       });
3229       return accumulator;
3230     }
3231
3232     /**
3233      * The base implementation of `_.invoke` without support for individual
3234      * method arguments.
3235      *
3236      * @private
3237      * @param {Object} object The object to query.
3238      * @param {Array|string} path The path of the method to invoke.
3239      * @param {Array} args The arguments to invoke the method with.
3240      * @returns {*} Returns the result of the invoked method.
3241      */
3242     function baseInvoke(object, path, args) {
3243       path = castPath(path, object);
3244       object = parent(object, path);
3245       var func = object == null ? object : object[toKey(last(path))];
3246       return func == null ? undefined : apply(func, object, args);
3247     }
3248
3249     /**
3250      * The base implementation of `_.isArguments`.
3251      *
3252      * @private
3253      * @param {*} value The value to check.
3254      * @returns {boolean} Returns `true` if `value` is an `arguments` object,
3255      */
3256     function baseIsArguments(value) {
3257       return isObjectLike(value) && baseGetTag(value) == argsTag;
3258     }
3259
3260     /**
3261      * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
3262      *
3263      * @private
3264      * @param {*} value The value to check.
3265      * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
3266      */
3267     function baseIsArrayBuffer(value) {
3268       return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
3269     }
3270
3271     /**
3272      * The base implementation of `_.isDate` without Node.js optimizations.
3273      *
3274      * @private
3275      * @param {*} value The value to check.
3276      * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
3277      */
3278     function baseIsDate(value) {
3279       return isObjectLike(value) && baseGetTag(value) == dateTag;
3280     }
3281
3282     /**
3283      * The base implementation of `_.isEqual` which supports partial comparisons
3284      * and tracks traversed objects.
3285      *
3286      * @private
3287      * @param {*} value The value to compare.
3288      * @param {*} other The other value to compare.
3289      * @param {boolean} bitmask The bitmask flags.
3290      *  1 - Unordered comparison
3291      *  2 - Partial comparison
3292      * @param {Function} [customizer] The function to customize comparisons.
3293      * @param {Object} [stack] Tracks traversed `value` and `other` objects.
3294      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
3295      */
3296     function baseIsEqual(value, other, bitmask, customizer, stack) {
3297       if (value === other) {
3298         return true;
3299       }
3300       if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
3301         return value !== value && other !== other;
3302       }
3303       return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
3304     }
3305
3306     /**
3307      * A specialized version of `baseIsEqual` for arrays and objects which performs
3308      * deep comparisons and tracks traversed objects enabling objects with circular
3309      * references to be compared.
3310      *
3311      * @private
3312      * @param {Object} object The object to compare.
3313      * @param {Object} other The other object to compare.
3314      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
3315      * @param {Function} customizer The function to customize comparisons.
3316      * @param {Function} equalFunc The function to determine equivalents of values.
3317      * @param {Object} [stack] Tracks traversed `object` and `other` objects.
3318      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
3319      */
3320     function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
3321       var objIsArr = isArray(object),
3322           othIsArr = isArray(other),
3323           objTag = objIsArr ? arrayTag : getTag(object),
3324           othTag = othIsArr ? arrayTag : getTag(other);
3325
3326       objTag = objTag == argsTag ? objectTag : objTag;
3327       othTag = othTag == argsTag ? objectTag : othTag;
3328
3329       var objIsObj = objTag == objectTag,
3330           othIsObj = othTag == objectTag,
3331           isSameTag = objTag == othTag;
3332
3333       if (isSameTag && isBuffer(object)) {
3334         if (!isBuffer(other)) {
3335           return false;
3336         }
3337         objIsArr = true;
3338         objIsObj = false;
3339       }
3340       if (isSameTag && !objIsObj) {
3341         stack || (stack = new Stack);
3342         return (objIsArr || isTypedArray(object))
3343           ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
3344           : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
3345       }
3346       if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
3347         var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
3348             othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
3349
3350         if (objIsWrapped || othIsWrapped) {
3351           var objUnwrapped = objIsWrapped ? object.value() : object,
3352               othUnwrapped = othIsWrapped ? other.value() : other;
3353
3354           stack || (stack = new Stack);
3355           return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
3356         }
3357       }
3358       if (!isSameTag) {
3359         return false;
3360       }
3361       stack || (stack = new Stack);
3362       return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
3363     }
3364
3365     /**
3366      * The base implementation of `_.isMap` without Node.js optimizations.
3367      *
3368      * @private
3369      * @param {*} value The value to check.
3370      * @returns {boolean} Returns `true` if `value` is a map, else `false`.
3371      */
3372     function baseIsMap(value) {
3373       return isObjectLike(value) && getTag(value) == mapTag;
3374     }
3375
3376     /**
3377      * The base implementation of `_.isMatch` without support for iteratee shorthands.
3378      *
3379      * @private
3380      * @param {Object} object The object to inspect.
3381      * @param {Object} source The object of property values to match.
3382      * @param {Array} matchData The property names, values, and compare flags to match.
3383      * @param {Function} [customizer] The function to customize comparisons.
3384      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
3385      */
3386     function baseIsMatch(object, source, matchData, customizer) {
3387       var index = matchData.length,
3388           length = index,
3389           noCustomizer = !customizer;
3390
3391       if (object == null) {
3392         return !length;
3393       }
3394       object = Object(object);
3395       while (index--) {
3396         var data = matchData[index];
3397         if ((noCustomizer && data[2])
3398               ? data[1] !== object[data[0]]
3399               : !(data[0] in object)
3400             ) {
3401           return false;
3402         }
3403       }
3404       while (++index < length) {
3405         data = matchData[index];
3406         var key = data[0],
3407             objValue = object[key],
3408             srcValue = data[1];
3409
3410         if (noCustomizer && data[2]) {
3411           if (objValue === undefined && !(key in object)) {
3412             return false;
3413           }
3414         } else {
3415           var stack = new Stack;
3416           if (customizer) {
3417             var result = customizer(objValue, srcValue, key, object, source, stack);
3418           }
3419           if (!(result === undefined
3420                 ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
3421                 : result
3422               )) {
3423             return false;
3424           }
3425         }
3426       }
3427       return true;
3428     }
3429
3430     /**
3431      * The base implementation of `_.isNative` without bad shim checks.
3432      *
3433      * @private
3434      * @param {*} value The value to check.
3435      * @returns {boolean} Returns `true` if `value` is a native function,
3436      *  else `false`.
3437      */
3438     function baseIsNative(value) {
3439       if (!isObject(value) || isMasked(value)) {
3440         return false;
3441       }
3442       var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
3443       return pattern.test(toSource(value));
3444     }
3445
3446     /**
3447      * The base implementation of `_.isRegExp` without Node.js optimizations.
3448      *
3449      * @private
3450      * @param {*} value The value to check.
3451      * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
3452      */
3453     function baseIsRegExp(value) {
3454       return isObjectLike(value) && baseGetTag(value) == regexpTag;
3455     }
3456
3457     /**
3458      * The base implementation of `_.isSet` without Node.js optimizations.
3459      *
3460      * @private
3461      * @param {*} value The value to check.
3462      * @returns {boolean} Returns `true` if `value` is a set, else `false`.
3463      */
3464     function baseIsSet(value) {
3465       return isObjectLike(value) && getTag(value) == setTag;
3466     }
3467
3468     /**
3469      * The base implementation of `_.isTypedArray` without Node.js optimizations.
3470      *
3471      * @private
3472      * @param {*} value The value to check.
3473      * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
3474      */
3475     function baseIsTypedArray(value) {
3476       return isObjectLike(value) &&
3477         isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
3478     }
3479
3480     /**
3481      * The base implementation of `_.iteratee`.
3482      *
3483      * @private
3484      * @param {*} [value=_.identity] The value to convert to an iteratee.
3485      * @returns {Function} Returns the iteratee.
3486      */
3487     function baseIteratee(value) {
3488       // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
3489       // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
3490       if (typeof value == 'function') {
3491         return value;
3492       }
3493       if (value == null) {
3494         return identity;
3495       }
3496       if (typeof value == 'object') {
3497         return isArray(value)
3498           ? baseMatchesProperty(value[0], value[1])
3499           : baseMatches(value);
3500       }
3501       return property(value);
3502     }
3503
3504     /**
3505      * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
3506      *
3507      * @private
3508      * @param {Object} object The object to query.
3509      * @returns {Array} Returns the array of property names.
3510      */
3511     function baseKeys(object) {
3512       if (!isPrototype(object)) {
3513         return nativeKeys(object);
3514       }
3515       var result = [];
3516       for (var key in Object(object)) {
3517         if (hasOwnProperty.call(object, key) && key != 'constructor') {
3518           result.push(key);
3519         }
3520       }
3521       return result;
3522     }
3523
3524     /**
3525      * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
3526      *
3527      * @private
3528      * @param {Object} object The object to query.
3529      * @returns {Array} Returns the array of property names.
3530      */
3531     function baseKeysIn(object) {
3532       if (!isObject(object)) {
3533         return nativeKeysIn(object);
3534       }
3535       var isProto = isPrototype(object),
3536           result = [];
3537
3538       for (var key in object) {
3539         if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
3540           result.push(key);
3541         }
3542       }
3543       return result;
3544     }
3545
3546     /**
3547      * The base implementation of `_.lt` which doesn't coerce arguments.
3548      *
3549      * @private
3550      * @param {*} value The value to compare.
3551      * @param {*} other The other value to compare.
3552      * @returns {boolean} Returns `true` if `value` is less than `other`,
3553      *  else `false`.
3554      */
3555     function baseLt(value, other) {
3556       return value < other;
3557     }
3558
3559     /**
3560      * The base implementation of `_.map` without support for iteratee shorthands.
3561      *
3562      * @private
3563      * @param {Array|Object} collection The collection to iterate over.
3564      * @param {Function} iteratee The function invoked per iteration.
3565      * @returns {Array} Returns the new mapped array.
3566      */
3567     function baseMap(collection, iteratee) {
3568       var index = -1,
3569           result = isArrayLike(collection) ? Array(collection.length) : [];
3570
3571       baseEach(collection, function(value, key, collection) {
3572         result[++index] = iteratee(value, key, collection);
3573       });
3574       return result;
3575     }
3576
3577     /**
3578      * The base implementation of `_.matches` which doesn't clone `source`.
3579      *
3580      * @private
3581      * @param {Object} source The object of property values to match.
3582      * @returns {Function} Returns the new spec function.
3583      */
3584     function baseMatches(source) {
3585       var matchData = getMatchData(source);
3586       if (matchData.length == 1 && matchData[0][2]) {
3587         return matchesStrictComparable(matchData[0][0], matchData[0][1]);
3588       }
3589       return function(object) {
3590         return object === source || baseIsMatch(object, source, matchData);
3591       };
3592     }
3593
3594     /**
3595      * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
3596      *
3597      * @private
3598      * @param {string} path The path of the property to get.
3599      * @param {*} srcValue The value to match.
3600      * @returns {Function} Returns the new spec function.
3601      */
3602     function baseMatchesProperty(path, srcValue) {
3603       if (isKey(path) && isStrictComparable(srcValue)) {
3604         return matchesStrictComparable(toKey(path), srcValue);
3605       }
3606       return function(object) {
3607         var objValue = get(object, path);
3608         return (objValue === undefined && objValue === srcValue)
3609           ? hasIn(object, path)
3610           : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
3611       };
3612     }
3613
3614     /**
3615      * The base implementation of `_.merge` without support for multiple sources.
3616      *
3617      * @private
3618      * @param {Object} object The destination object.
3619      * @param {Object} source The source object.
3620      * @param {number} srcIndex The index of `source`.
3621      * @param {Function} [customizer] The function to customize merged values.
3622      * @param {Object} [stack] Tracks traversed source values and their merged
3623      *  counterparts.
3624      */
3625     function baseMerge(object, source, srcIndex, customizer, stack) {
3626       if (object === source) {
3627         return;
3628       }
3629       baseFor(source, function(srcValue, key) {
3630         if (isObject(srcValue)) {
3631           stack || (stack = new Stack);
3632           baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
3633         }
3634         else {
3635           var newValue = customizer
3636             ? customizer(object[key], srcValue, (key + ''), object, source, stack)
3637             : undefined;
3638
3639           if (newValue === undefined) {
3640             newValue = srcValue;
3641           }
3642           assignMergeValue(object, key, newValue);
3643         }
3644       }, keysIn);
3645     }
3646
3647     /**
3648      * A specialized version of `baseMerge` for arrays and objects which performs
3649      * deep merges and tracks traversed objects enabling objects with circular
3650      * references to be merged.
3651      *
3652      * @private
3653      * @param {Object} object The destination object.
3654      * @param {Object} source The source object.
3655      * @param {string} key The key of the value to merge.
3656      * @param {number} srcIndex The index of `source`.
3657      * @param {Function} mergeFunc The function to merge values.
3658      * @param {Function} [customizer] The function to customize assigned values.
3659      * @param {Object} [stack] Tracks traversed source values and their merged
3660      *  counterparts.
3661      */
3662     function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
3663       var objValue = object[key],
3664           srcValue = source[key],
3665           stacked = stack.get(srcValue);
3666
3667       if (stacked) {
3668         assignMergeValue(object, key, stacked);
3669         return;
3670       }
3671       var newValue = customizer
3672         ? customizer(objValue, srcValue, (key + ''), object, source, stack)
3673         : undefined;
3674
3675       var isCommon = newValue === undefined;
3676
3677       if (isCommon) {
3678         var isArr = isArray(srcValue),
3679             isBuff = !isArr && isBuffer(srcValue),
3680             isTyped = !isArr && !isBuff && isTypedArray(srcValue);
3681
3682         newValue = srcValue;
3683         if (isArr || isBuff || isTyped) {
3684           if (isArray(objValue)) {
3685             newValue = objValue;
3686           }
3687           else if (isArrayLikeObject(objValue)) {
3688             newValue = copyArray(objValue);
3689           }
3690           else if (isBuff) {
3691             isCommon = false;
3692             newValue = cloneBuffer(srcValue, true);
3693           }
3694           else if (isTyped) {
3695             isCommon = false;
3696             newValue = cloneTypedArray(srcValue, true);
3697           }
3698           else {
3699             newValue = [];
3700           }
3701         }
3702         else if (isPlainObject(srcValue) || isArguments(srcValue)) {
3703           newValue = objValue;
3704           if (isArguments(objValue)) {
3705             newValue = toPlainObject(objValue);
3706           }
3707           else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
3708             newValue = initCloneObject(srcValue);
3709           }
3710         }
3711         else {
3712           isCommon = false;
3713         }
3714       }
3715       if (isCommon) {
3716         // Recursively merge objects and arrays (susceptible to call stack limits).
3717         stack.set(srcValue, newValue);
3718         mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
3719         stack['delete'](srcValue);
3720       }
3721       assignMergeValue(object, key, newValue);
3722     }
3723
3724     /**
3725      * The base implementation of `_.nth` which doesn't coerce arguments.
3726      *
3727      * @private
3728      * @param {Array} array The array to query.
3729      * @param {number} n The index of the element to return.
3730      * @returns {*} Returns the nth element of `array`.
3731      */
3732     function baseNth(array, n) {
3733       var length = array.length;
3734       if (!length) {
3735         return;
3736       }
3737       n += n < 0 ? length : 0;
3738       return isIndex(n, length) ? array[n] : undefined;
3739     }
3740
3741     /**
3742      * The base implementation of `_.orderBy` without param guards.
3743      *
3744      * @private
3745      * @param {Array|Object} collection The collection to iterate over.
3746      * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
3747      * @param {string[]} orders The sort orders of `iteratees`.
3748      * @returns {Array} Returns the new sorted array.
3749      */
3750     function baseOrderBy(collection, iteratees, orders) {
3751       var index = -1;
3752       iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee()));
3753
3754       var result = baseMap(collection, function(value, key, collection) {
3755         var criteria = arrayMap(iteratees, function(iteratee) {
3756           return iteratee(value);
3757         });
3758         return { 'criteria': criteria, 'index': ++index, 'value': value };
3759       });
3760
3761       return baseSortBy(result, function(object, other) {
3762         return compareMultiple(object, other, orders);
3763       });
3764     }
3765
3766     /**
3767      * The base implementation of `_.pick` without support for individual
3768      * property identifiers.
3769      *
3770      * @private
3771      * @param {Object} object The source object.
3772      * @param {string[]} paths The property paths to pick.
3773      * @returns {Object} Returns the new object.
3774      */
3775     function basePick(object, paths) {
3776       return basePickBy(object, paths, function(value, path) {
3777         return hasIn(object, path);
3778       });
3779     }
3780
3781     /**
3782      * The base implementation of  `_.pickBy` without support for iteratee shorthands.
3783      *
3784      * @private
3785      * @param {Object} object The source object.
3786      * @param {string[]} paths The property paths to pick.
3787      * @param {Function} predicate The function invoked per property.
3788      * @returns {Object} Returns the new object.
3789      */
3790     function basePickBy(object, paths, predicate) {
3791       var index = -1,
3792           length = paths.length,
3793           result = {};
3794
3795       while (++index < length) {
3796         var path = paths[index],
3797             value = baseGet(object, path);
3798
3799         if (predicate(value, path)) {
3800           baseSet(result, castPath(path, object), value);
3801         }
3802       }
3803       return result;
3804     }
3805
3806     /**
3807      * A specialized version of `baseProperty` which supports deep paths.
3808      *
3809      * @private
3810      * @param {Array|string} path The path of the property to get.
3811      * @returns {Function} Returns the new accessor function.
3812      */
3813     function basePropertyDeep(path) {
3814       return function(object) {
3815         return baseGet(object, path);
3816       };
3817     }
3818
3819     /**
3820      * The base implementation of `_.pullAllBy` without support for iteratee
3821      * shorthands.
3822      *
3823      * @private
3824      * @param {Array} array The array to modify.
3825      * @param {Array} values The values to remove.
3826      * @param {Function} [iteratee] The iteratee invoked per element.
3827      * @param {Function} [comparator] The comparator invoked per element.
3828      * @returns {Array} Returns `array`.
3829      */
3830     function basePullAll(array, values, iteratee, comparator) {
3831       var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
3832           index = -1,
3833           length = values.length,
3834           seen = array;
3835
3836       if (array === values) {
3837         values = copyArray(values);
3838       }
3839       if (iteratee) {
3840         seen = arrayMap(array, baseUnary(iteratee));
3841       }
3842       while (++index < length) {
3843         var fromIndex = 0,
3844             value = values[index],
3845             computed = iteratee ? iteratee(value) : value;
3846
3847         while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
3848           if (seen !== array) {
3849             splice.call(seen, fromIndex, 1);
3850           }
3851           splice.call(array, fromIndex, 1);
3852         }
3853       }
3854       return array;
3855     }
3856
3857     /**
3858      * The base implementation of `_.pullAt` without support for individual
3859      * indexes or capturing the removed elements.
3860      *
3861      * @private
3862      * @param {Array} array The array to modify.
3863      * @param {number[]} indexes The indexes of elements to remove.
3864      * @returns {Array} Returns `array`.
3865      */
3866     function basePullAt(array, indexes) {
3867       var length = array ? indexes.length : 0,
3868           lastIndex = length - 1;
3869
3870       while (length--) {
3871         var index = indexes[length];
3872         if (length == lastIndex || index !== previous) {
3873           var previous = index;
3874           if (isIndex(index)) {
3875             splice.call(array, index, 1);
3876           } else {
3877             baseUnset(array, index);
3878           }
3879         }
3880       }
3881       return array;
3882     }
3883
3884     /**
3885      * The base implementation of `_.random` without support for returning
3886      * floating-point numbers.
3887      *
3888      * @private
3889      * @param {number} lower The lower bound.
3890      * @param {number} upper The upper bound.
3891      * @returns {number} Returns the random number.
3892      */
3893     function baseRandom(lower, upper) {
3894       return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
3895     }
3896
3897     /**
3898      * The base implementation of `_.range` and `_.rangeRight` which doesn't
3899      * coerce arguments.
3900      *
3901      * @private
3902      * @param {number} start The start of the range.
3903      * @param {number} end The end of the range.
3904      * @param {number} step The value to increment or decrement by.
3905      * @param {boolean} [fromRight] Specify iterating from right to left.
3906      * @returns {Array} Returns the range of numbers.
3907      */
3908     function baseRange(start, end, step, fromRight) {
3909       var index = -1,
3910           length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
3911           result = Array(length);
3912
3913       while (length--) {
3914         result[fromRight ? length : ++index] = start;
3915         start += step;
3916       }
3917       return result;
3918     }
3919
3920     /**
3921      * The base implementation of `_.repeat` which doesn't coerce arguments.
3922      *
3923      * @private
3924      * @param {string} string The string to repeat.
3925      * @param {number} n The number of times to repeat the string.
3926      * @returns {string} Returns the repeated string.
3927      */
3928     function baseRepeat(string, n) {
3929       var result = '';
3930       if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
3931         return result;
3932       }
3933       // Leverage the exponentiation by squaring algorithm for a faster repeat.
3934       // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
3935       do {
3936         if (n % 2) {
3937           result += string;
3938         }
3939         n = nativeFloor(n / 2);
3940         if (n) {
3941           string += string;
3942         }
3943       } while (n);
3944
3945       return result;
3946     }
3947
3948     /**
3949      * The base implementation of `_.rest` which doesn't validate or coerce arguments.
3950      *
3951      * @private
3952      * @param {Function} func The function to apply a rest parameter to.
3953      * @param {number} [start=func.length-1] The start position of the rest parameter.
3954      * @returns {Function} Returns the new function.
3955      */
3956     function baseRest(func, start) {
3957       return setToString(overRest(func, start, identity), func + '');
3958     }
3959
3960     /**
3961      * The base implementation of `_.sample`.
3962      *
3963      * @private
3964      * @param {Array|Object} collection The collection to sample.
3965      * @returns {*} Returns the random element.
3966      */
3967     function baseSample(collection) {
3968       return arraySample(values(collection));
3969     }
3970
3971     /**
3972      * The base implementation of `_.sampleSize` without param guards.
3973      *
3974      * @private
3975      * @param {Array|Object} collection The collection to sample.
3976      * @param {number} n The number of elements to sample.
3977      * @returns {Array} Returns the random elements.
3978      */
3979     function baseSampleSize(collection, n) {
3980       var array = values(collection);
3981       return shuffleSelf(array, baseClamp(n, 0, array.length));
3982     }
3983
3984     /**
3985      * The base implementation of `_.set`.
3986      *
3987      * @private
3988      * @param {Object} object The object to modify.
3989      * @param {Array|string} path The path of the property to set.
3990      * @param {*} value The value to set.
3991      * @param {Function} [customizer] The function to customize path creation.
3992      * @returns {Object} Returns `object`.
3993      */
3994     function baseSet(object, path, value, customizer) {
3995       if (!isObject(object)) {
3996         return object;
3997       }
3998       path = castPath(path, object);
3999
4000       var index = -1,
4001           length = path.length,
4002           lastIndex = length - 1,
4003           nested = object;
4004
4005       while (nested != null && ++index < length) {
4006         var key = toKey(path[index]),
4007             newValue = value;
4008
4009         if (index != lastIndex) {
4010           var objValue = nested[key];
4011           newValue = customizer ? customizer(objValue, key, nested) : undefined;
4012           if (newValue === undefined) {
4013             newValue = isObject(objValue)
4014               ? objValue
4015               : (isIndex(path[index + 1]) ? [] : {});
4016           }
4017         }
4018         assignValue(nested, key, newValue);
4019         nested = nested[key];
4020       }
4021       return object;
4022     }
4023
4024     /**
4025      * The base implementation of `setData` without support for hot loop shorting.
4026      *
4027      * @private
4028      * @param {Function} func The function to associate metadata with.
4029      * @param {*} data The metadata.
4030      * @returns {Function} Returns `func`.
4031      */
4032     var baseSetData = !metaMap ? identity : function(func, data) {
4033       metaMap.set(func, data);
4034       return func;
4035     };
4036
4037     /**
4038      * The base implementation of `setToString` without support for hot loop shorting.
4039      *
4040      * @private
4041      * @param {Function} func The function to modify.
4042      * @param {Function} string The `toString` result.
4043      * @returns {Function} Returns `func`.
4044      */
4045     var baseSetToString = !defineProperty ? identity : function(func, string) {
4046       return defineProperty(func, 'toString', {
4047         'configurable': true,
4048         'enumerable': false,
4049         'value': constant(string),
4050         'writable': true
4051       });
4052     };
4053
4054     /**
4055      * The base implementation of `_.shuffle`.
4056      *
4057      * @private
4058      * @param {Array|Object} collection The collection to shuffle.
4059      * @returns {Array} Returns the new shuffled array.
4060      */
4061     function baseShuffle(collection) {
4062       return shuffleSelf(values(collection));
4063     }
4064
4065     /**
4066      * The base implementation of `_.slice` without an iteratee call guard.
4067      *
4068      * @private
4069      * @param {Array} array The array to slice.
4070      * @param {number} [start=0] The start position.
4071      * @param {number} [end=array.length] The end position.
4072      * @returns {Array} Returns the slice of `array`.
4073      */
4074     function baseSlice(array, start, end) {
4075       var index = -1,
4076           length = array.length;
4077
4078       if (start < 0) {
4079         start = -start > length ? 0 : (length + start);
4080       }
4081       end = end > length ? length : end;
4082       if (end < 0) {
4083         end += length;
4084       }
4085       length = start > end ? 0 : ((end - start) >>> 0);
4086       start >>>= 0;
4087
4088       var result = Array(length);
4089       while (++index < length) {
4090         result[index] = array[index + start];
4091       }
4092       return result;
4093     }
4094
4095     /**
4096      * The base implementation of `_.some` without support for iteratee shorthands.
4097      *
4098      * @private
4099      * @param {Array|Object} collection The collection to iterate over.
4100      * @param {Function} predicate The function invoked per iteration.
4101      * @returns {boolean} Returns `true` if any element passes the predicate check,
4102      *  else `false`.
4103      */
4104     function baseSome(collection, predicate) {
4105       var result;
4106
4107       baseEach(collection, function(value, index, collection) {
4108         result = predicate(value, index, collection);
4109         return !result;
4110       });
4111       return !!result;
4112     }
4113
4114     /**
4115      * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
4116      * performs a binary search of `array` to determine the index at which `value`
4117      * should be inserted into `array` in order to maintain its sort order.
4118      *
4119      * @private
4120      * @param {Array} array The sorted array to inspect.
4121      * @param {*} value The value to evaluate.
4122      * @param {boolean} [retHighest] Specify returning the highest qualified index.
4123      * @returns {number} Returns the index at which `value` should be inserted
4124      *  into `array`.
4125      */
4126     function baseSortedIndex(array, value, retHighest) {
4127       var low = 0,
4128           high = array == null ? low : array.length;
4129
4130       if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
4131         while (low < high) {
4132           var mid = (low + high) >>> 1,
4133               computed = array[mid];
4134
4135           if (computed !== null && !isSymbol(computed) &&
4136               (retHighest ? (computed <= value) : (computed < value))) {
4137             low = mid + 1;
4138           } else {
4139             high = mid;
4140           }
4141         }
4142         return high;
4143       }
4144       return baseSortedIndexBy(array, value, identity, retHighest);
4145     }
4146
4147     /**
4148      * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
4149      * which invokes `iteratee` for `value` and each element of `array` to compute
4150      * their sort ranking. The iteratee is invoked with one argument; (value).
4151      *
4152      * @private
4153      * @param {Array} array The sorted array to inspect.
4154      * @param {*} value The value to evaluate.
4155      * @param {Function} iteratee The iteratee invoked per element.
4156      * @param {boolean} [retHighest] Specify returning the highest qualified index.
4157      * @returns {number} Returns the index at which `value` should be inserted
4158      *  into `array`.
4159      */
4160     function baseSortedIndexBy(array, value, iteratee, retHighest) {
4161       value = iteratee(value);
4162
4163       var low = 0,
4164           high = array == null ? 0 : array.length,
4165           valIsNaN = value !== value,
4166           valIsNull = value === null,
4167           valIsSymbol = isSymbol(value),
4168           valIsUndefined = value === undefined;
4169
4170       while (low < high) {
4171         var mid = nativeFloor((low + high) / 2),
4172             computed = iteratee(array[mid]),
4173             othIsDefined = computed !== undefined,
4174             othIsNull = computed === null,
4175             othIsReflexive = computed === computed,
4176             othIsSymbol = isSymbol(computed);
4177
4178         if (valIsNaN) {
4179           var setLow = retHighest || othIsReflexive;
4180         } else if (valIsUndefined) {
4181           setLow = othIsReflexive && (retHighest || othIsDefined);
4182         } else if (valIsNull) {
4183           setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
4184         } else if (valIsSymbol) {
4185           setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
4186         } else if (othIsNull || othIsSymbol) {
4187           setLow = false;
4188         } else {
4189           setLow = retHighest ? (computed <= value) : (computed < value);
4190         }
4191         if (setLow) {
4192           low = mid + 1;
4193         } else {
4194           high = mid;
4195         }
4196       }
4197       return nativeMin(high, MAX_ARRAY_INDEX);
4198     }
4199
4200     /**
4201      * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
4202      * support for iteratee shorthands.
4203      *
4204      * @private
4205      * @param {Array} array The array to inspect.
4206      * @param {Function} [iteratee] The iteratee invoked per element.
4207      * @returns {Array} Returns the new duplicate free array.
4208      */
4209     function baseSortedUniq(array, iteratee) {
4210       var index = -1,
4211           length = array.length,
4212           resIndex = 0,
4213           result = [];
4214
4215       while (++index < length) {
4216         var value = array[index],
4217             computed = iteratee ? iteratee(value) : value;
4218
4219         if (!index || !eq(computed, seen)) {
4220           var seen = computed;
4221           result[resIndex++] = value === 0 ? 0 : value;
4222         }
4223       }
4224       return result;
4225     }
4226
4227     /**
4228      * The base implementation of `_.toNumber` which doesn't ensure correct
4229      * conversions of binary, hexadecimal, or octal string values.
4230      *
4231      * @private
4232      * @param {*} value The value to process.
4233      * @returns {number} Returns the number.
4234      */
4235     function baseToNumber(value) {
4236       if (typeof value == 'number') {
4237         return value;
4238       }
4239       if (isSymbol(value)) {
4240         return NAN;
4241       }
4242       return +value;
4243     }
4244
4245     /**
4246      * The base implementation of `_.toString` which doesn't convert nullish
4247      * values to empty strings.
4248      *
4249      * @private
4250      * @param {*} value The value to process.
4251      * @returns {string} Returns the string.
4252      */
4253     function baseToString(value) {
4254       // Exit early for strings to avoid a performance hit in some environments.
4255       if (typeof value == 'string') {
4256         return value;
4257       }
4258       if (isArray(value)) {
4259         // Recursively convert values (susceptible to call stack limits).
4260         return arrayMap(value, baseToString) + '';
4261       }
4262       if (isSymbol(value)) {
4263         return symbolToString ? symbolToString.call(value) : '';
4264       }
4265       var result = (value + '');
4266       return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
4267     }
4268
4269     /**
4270      * The base implementation of `_.uniqBy` without support for iteratee shorthands.
4271      *
4272      * @private
4273      * @param {Array} array The array to inspect.
4274      * @param {Function} [iteratee] The iteratee invoked per element.
4275      * @param {Function} [comparator] The comparator invoked per element.
4276      * @returns {Array} Returns the new duplicate free array.
4277      */
4278     function baseUniq(array, iteratee, comparator) {
4279       var index = -1,
4280           includes = arrayIncludes,
4281           length = array.length,
4282           isCommon = true,
4283           result = [],
4284           seen = result;
4285
4286       if (comparator) {
4287         isCommon = false;
4288         includes = arrayIncludesWith;
4289       }
4290       else if (length >= LARGE_ARRAY_SIZE) {
4291         var set = iteratee ? null : createSet(array);
4292         if (set) {
4293           return setToArray(set);
4294         }
4295         isCommon = false;
4296         includes = cacheHas;
4297         seen = new SetCache;
4298       }
4299       else {
4300         seen = iteratee ? [] : result;
4301       }
4302       outer:
4303       while (++index < length) {
4304         var value = array[index],
4305             computed = iteratee ? iteratee(value) : value;
4306
4307         value = (comparator || value !== 0) ? value : 0;
4308         if (isCommon && computed === computed) {
4309           var seenIndex = seen.length;
4310           while (seenIndex--) {
4311             if (seen[seenIndex] === computed) {
4312               continue outer;
4313             }
4314           }
4315           if (iteratee) {
4316             seen.push(computed);
4317           }
4318           result.push(value);
4319         }
4320         else if (!includes(seen, computed, comparator)) {
4321           if (seen !== result) {
4322             seen.push(computed);
4323           }
4324           result.push(value);
4325         }
4326       }
4327       return result;
4328     }
4329
4330     /**
4331      * The base implementation of `_.unset`.
4332      *
4333      * @private
4334      * @param {Object} object The object to modify.
4335      * @param {Array|string} path The property path to unset.
4336      * @returns {boolean} Returns `true` if the property is deleted, else `false`.
4337      */
4338     function baseUnset(object, path) {
4339       path = castPath(path, object);
4340       object = parent(object, path);
4341       return object == null || delete object[toKey(last(path))];
4342     }
4343
4344     /**
4345      * The base implementation of `_.update`.
4346      *
4347      * @private
4348      * @param {Object} object The object to modify.
4349      * @param {Array|string} path The path of the property to update.
4350      * @param {Function} updater The function to produce the updated value.
4351      * @param {Function} [customizer] The function to customize path creation.
4352      * @returns {Object} Returns `object`.
4353      */
4354     function baseUpdate(object, path, updater, customizer) {
4355       return baseSet(object, path, updater(baseGet(object, path)), customizer);
4356     }
4357
4358     /**
4359      * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
4360      * without support for iteratee shorthands.
4361      *
4362      * @private
4363      * @param {Array} array The array to query.
4364      * @param {Function} predicate The function invoked per iteration.
4365      * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
4366      * @param {boolean} [fromRight] Specify iterating from right to left.
4367      * @returns {Array} Returns the slice of `array`.
4368      */
4369     function baseWhile(array, predicate, isDrop, fromRight) {
4370       var length = array.length,
4371           index = fromRight ? length : -1;
4372
4373       while ((fromRight ? index-- : ++index < length) &&
4374         predicate(array[index], index, array)) {}
4375
4376       return isDrop
4377         ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
4378         : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
4379     }
4380
4381     /**
4382      * The base implementation of `wrapperValue` which returns the result of
4383      * performing a sequence of actions on the unwrapped `value`, where each
4384      * successive action is supplied the return value of the previous.
4385      *
4386      * @private
4387      * @param {*} value The unwrapped value.
4388      * @param {Array} actions Actions to perform to resolve the unwrapped value.
4389      * @returns {*} Returns the resolved value.
4390      */
4391     function baseWrapperValue(value, actions) {
4392       var result = value;
4393       if (result instanceof LazyWrapper) {
4394         result = result.value();
4395       }
4396       return arrayReduce(actions, function(result, action) {
4397         return action.func.apply(action.thisArg, arrayPush([result], action.args));
4398       }, result);
4399     }
4400
4401     /**
4402      * The base implementation of methods like `_.xor`, without support for
4403      * iteratee shorthands, that accepts an array of arrays to inspect.
4404      *
4405      * @private
4406      * @param {Array} arrays The arrays to inspect.
4407      * @param {Function} [iteratee] The iteratee invoked per element.
4408      * @param {Function} [comparator] The comparator invoked per element.
4409      * @returns {Array} Returns the new array of values.
4410      */
4411     function baseXor(arrays, iteratee, comparator) {
4412       var length = arrays.length;
4413       if (length < 2) {
4414         return length ? baseUniq(arrays[0]) : [];
4415       }
4416       var index = -1,
4417           result = Array(length);
4418
4419       while (++index < length) {
4420         var array = arrays[index],
4421             othIndex = -1;
4422
4423         while (++othIndex < length) {
4424           if (othIndex != index) {
4425             result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
4426           }
4427         }
4428       }
4429       return baseUniq(baseFlatten(result, 1), iteratee, comparator);
4430     }
4431
4432     /**
4433      * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
4434      *
4435      * @private
4436      * @param {Array} props The property identifiers.
4437      * @param {Array} values The property values.
4438      * @param {Function} assignFunc The function to assign values.
4439      * @returns {Object} Returns the new object.
4440      */
4441     function baseZipObject(props, values, assignFunc) {
4442       var index = -1,
4443           length = props.length,
4444           valsLength = values.length,
4445           result = {};
4446
4447       while (++index < length) {
4448         var value = index < valsLength ? values[index] : undefined;
4449         assignFunc(result, props[index], value);
4450       }
4451       return result;
4452     }
4453
4454     /**
4455      * Casts `value` to an empty array if it's not an array like object.
4456      *
4457      * @private
4458      * @param {*} value The value to inspect.
4459      * @returns {Array|Object} Returns the cast array-like object.
4460      */
4461     function castArrayLikeObject(value) {
4462       return isArrayLikeObject(value) ? value : [];
4463     }
4464
4465     /**
4466      * Casts `value` to `identity` if it's not a function.
4467      *
4468      * @private
4469      * @param {*} value The value to inspect.
4470      * @returns {Function} Returns cast function.
4471      */
4472     function castFunction(value) {
4473       return typeof value == 'function' ? value : identity;
4474     }
4475
4476     /**
4477      * Casts `value` to a path array if it's not one.
4478      *
4479      * @private
4480      * @param {*} value The value to inspect.
4481      * @param {Object} [object] The object to query keys on.
4482      * @returns {Array} Returns the cast property path array.
4483      */
4484     function castPath(value, object) {
4485       if (isArray(value)) {
4486         return value;
4487       }
4488       return isKey(value, object) ? [value] : stringToPath(toString(value));
4489     }
4490
4491     /**
4492      * A `baseRest` alias which can be replaced with `identity` by module
4493      * replacement plugins.
4494      *
4495      * @private
4496      * @type {Function}
4497      * @param {Function} func The function to apply a rest parameter to.
4498      * @returns {Function} Returns the new function.
4499      */
4500     var castRest = baseRest;
4501
4502     /**
4503      * Casts `array` to a slice if it's needed.
4504      *
4505      * @private
4506      * @param {Array} array The array to inspect.
4507      * @param {number} start The start position.
4508      * @param {number} [end=array.length] The end position.
4509      * @returns {Array} Returns the cast slice.
4510      */
4511     function castSlice(array, start, end) {
4512       var length = array.length;
4513       end = end === undefined ? length : end;
4514       return (!start && end >= length) ? array : baseSlice(array, start, end);
4515     }
4516
4517     /**
4518      * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
4519      *
4520      * @private
4521      * @param {number|Object} id The timer id or timeout object of the timer to clear.
4522      */
4523     var clearTimeout = ctxClearTimeout || function(id) {
4524       return root.clearTimeout(id);
4525     };
4526
4527     /**
4528      * Creates a clone of  `buffer`.
4529      *
4530      * @private
4531      * @param {Buffer} buffer The buffer to clone.
4532      * @param {boolean} [isDeep] Specify a deep clone.
4533      * @returns {Buffer} Returns the cloned buffer.
4534      */
4535     function cloneBuffer(buffer, isDeep) {
4536       if (isDeep) {
4537         return buffer.slice();
4538       }
4539       var length = buffer.length,
4540           result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
4541
4542       buffer.copy(result);
4543       return result;
4544     }
4545
4546     /**
4547      * Creates a clone of `arrayBuffer`.
4548      *
4549      * @private
4550      * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
4551      * @returns {ArrayBuffer} Returns the cloned array buffer.
4552      */
4553     function cloneArrayBuffer(arrayBuffer) {
4554       var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
4555       new Uint8Array(result).set(new Uint8Array(arrayBuffer));
4556       return result;
4557     }
4558
4559     /**
4560      * Creates a clone of `dataView`.
4561      *
4562      * @private
4563      * @param {Object} dataView The data view to clone.
4564      * @param {boolean} [isDeep] Specify a deep clone.
4565      * @returns {Object} Returns the cloned data view.
4566      */
4567     function cloneDataView(dataView, isDeep) {
4568       var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
4569       return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
4570     }
4571
4572     /**
4573      * Creates a clone of `map`.
4574      *
4575      * @private
4576      * @param {Object} map The map to clone.
4577      * @param {Function} cloneFunc The function to clone values.
4578      * @param {boolean} [isDeep] Specify a deep clone.
4579      * @returns {Object} Returns the cloned map.
4580      */
4581     function cloneMap(map, isDeep, cloneFunc) {
4582       var array = isDeep ? cloneFunc(mapToArray(map), CLONE_DEEP_FLAG) : mapToArray(map);
4583       return arrayReduce(array, addMapEntry, new map.constructor);
4584     }
4585
4586     /**
4587      * Creates a clone of `regexp`.
4588      *
4589      * @private
4590      * @param {Object} regexp The regexp to clone.
4591      * @returns {Object} Returns the cloned regexp.
4592      */
4593     function cloneRegExp(regexp) {
4594       var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
4595       result.lastIndex = regexp.lastIndex;
4596       return result;
4597     }
4598
4599     /**
4600      * Creates a clone of `set`.
4601      *
4602      * @private
4603      * @param {Object} set The set to clone.
4604      * @param {Function} cloneFunc The function to clone values.
4605      * @param {boolean} [isDeep] Specify a deep clone.
4606      * @returns {Object} Returns the cloned set.
4607      */
4608     function cloneSet(set, isDeep, cloneFunc) {
4609       var array = isDeep ? cloneFunc(setToArray(set), CLONE_DEEP_FLAG) : setToArray(set);
4610       return arrayReduce(array, addSetEntry, new set.constructor);
4611     }
4612
4613     /**
4614      * Creates a clone of the `symbol` object.
4615      *
4616      * @private
4617      * @param {Object} symbol The symbol object to clone.
4618      * @returns {Object} Returns the cloned symbol object.
4619      */
4620     function cloneSymbol(symbol) {
4621       return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
4622     }
4623
4624     /**
4625      * Creates a clone of `typedArray`.
4626      *
4627      * @private
4628      * @param {Object} typedArray The typed array to clone.
4629      * @param {boolean} [isDeep] Specify a deep clone.
4630      * @returns {Object} Returns the cloned typed array.
4631      */
4632     function cloneTypedArray(typedArray, isDeep) {
4633       var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
4634       return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
4635     }
4636
4637     /**
4638      * Compares values to sort them in ascending order.
4639      *
4640      * @private
4641      * @param {*} value The value to compare.
4642      * @param {*} other The other value to compare.
4643      * @returns {number} Returns the sort order indicator for `value`.
4644      */
4645     function compareAscending(value, other) {
4646       if (value !== other) {
4647         var valIsDefined = value !== undefined,
4648             valIsNull = value === null,
4649             valIsReflexive = value === value,
4650             valIsSymbol = isSymbol(value);
4651
4652         var othIsDefined = other !== undefined,
4653             othIsNull = other === null,
4654             othIsReflexive = other === other,
4655             othIsSymbol = isSymbol(other);
4656
4657         if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
4658             (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
4659             (valIsNull && othIsDefined && othIsReflexive) ||
4660             (!valIsDefined && othIsReflexive) ||
4661             !valIsReflexive) {
4662           return 1;
4663         }
4664         if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
4665             (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
4666             (othIsNull && valIsDefined && valIsReflexive) ||
4667             (!othIsDefined && valIsReflexive) ||
4668             !othIsReflexive) {
4669           return -1;
4670         }
4671       }
4672       return 0;
4673     }
4674
4675     /**
4676      * Used by `_.orderBy` to compare multiple properties of a value to another
4677      * and stable sort them.
4678      *
4679      * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
4680      * specify an order of "desc" for descending or "asc" for ascending sort order
4681      * of corresponding values.
4682      *
4683      * @private
4684      * @param {Object} object The object to compare.
4685      * @param {Object} other The other object to compare.
4686      * @param {boolean[]|string[]} orders The order to sort by for each property.
4687      * @returns {number} Returns the sort order indicator for `object`.
4688      */
4689     function compareMultiple(object, other, orders) {
4690       var index = -1,
4691           objCriteria = object.criteria,
4692           othCriteria = other.criteria,
4693           length = objCriteria.length,
4694           ordersLength = orders.length;
4695
4696       while (++index < length) {
4697         var result = compareAscending(objCriteria[index], othCriteria[index]);
4698         if (result) {
4699           if (index >= ordersLength) {
4700             return result;
4701           }
4702           var order = orders[index];
4703           return result * (order == 'desc' ? -1 : 1);
4704         }
4705       }
4706       // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
4707       // that causes it, under certain circumstances, to provide the same value for
4708       // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
4709       // for more details.
4710       //
4711       // This also ensures a stable sort in V8 and other engines.
4712       // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
4713       return object.index - other.index;
4714     }
4715
4716     /**
4717      * Creates an array that is the composition of partially applied arguments,
4718      * placeholders, and provided arguments into a single array of arguments.
4719      *
4720      * @private
4721      * @param {Array} args The provided arguments.
4722      * @param {Array} partials The arguments to prepend to those provided.
4723      * @param {Array} holders The `partials` placeholder indexes.
4724      * @params {boolean} [isCurried] Specify composing for a curried function.
4725      * @returns {Array} Returns the new array of composed arguments.
4726      */
4727     function composeArgs(args, partials, holders, isCurried) {
4728       var argsIndex = -1,
4729           argsLength = args.length,
4730           holdersLength = holders.length,
4731           leftIndex = -1,
4732           leftLength = partials.length,
4733           rangeLength = nativeMax(argsLength - holdersLength, 0),
4734           result = Array(leftLength + rangeLength),
4735           isUncurried = !isCurried;
4736
4737       while (++leftIndex < leftLength) {
4738         result[leftIndex] = partials[leftIndex];
4739       }
4740       while (++argsIndex < holdersLength) {
4741         if (isUncurried || argsIndex < argsLength) {
4742           result[holders[argsIndex]] = args[argsIndex];
4743         }
4744       }
4745       while (rangeLength--) {
4746         result[leftIndex++] = args[argsIndex++];
4747       }
4748       return result;
4749     }
4750
4751     /**
4752      * This function is like `composeArgs` except that the arguments composition
4753      * is tailored for `_.partialRight`.
4754      *
4755      * @private
4756      * @param {Array} args The provided arguments.
4757      * @param {Array} partials The arguments to append to those provided.
4758      * @param {Array} holders The `partials` placeholder indexes.
4759      * @params {boolean} [isCurried] Specify composing for a curried function.
4760      * @returns {Array} Returns the new array of composed arguments.
4761      */
4762     function composeArgsRight(args, partials, holders, isCurried) {
4763       var argsIndex = -1,
4764           argsLength = args.length,
4765           holdersIndex = -1,
4766           holdersLength = holders.length,
4767           rightIndex = -1,
4768           rightLength = partials.length,
4769           rangeLength = nativeMax(argsLength - holdersLength, 0),
4770           result = Array(rangeLength + rightLength),
4771           isUncurried = !isCurried;
4772
4773       while (++argsIndex < rangeLength) {
4774         result[argsIndex] = args[argsIndex];
4775       }
4776       var offset = argsIndex;
4777       while (++rightIndex < rightLength) {
4778         result[offset + rightIndex] = partials[rightIndex];
4779       }
4780       while (++holdersIndex < holdersLength) {
4781         if (isUncurried || argsIndex < argsLength) {
4782           result[offset + holders[holdersIndex]] = args[argsIndex++];
4783         }
4784       }
4785       return result;
4786     }
4787
4788     /**
4789      * Copies the values of `source` to `array`.
4790      *
4791      * @private
4792      * @param {Array} source The array to copy values from.
4793      * @param {Array} [array=[]] The array to copy values to.
4794      * @returns {Array} Returns `array`.
4795      */
4796     function copyArray(source, array) {
4797       var index = -1,
4798           length = source.length;
4799
4800       array || (array = Array(length));
4801       while (++index < length) {
4802         array[index] = source[index];
4803       }
4804       return array;
4805     }
4806
4807     /**
4808      * Copies properties of `source` to `object`.
4809      *
4810      * @private
4811      * @param {Object} source The object to copy properties from.
4812      * @param {Array} props The property identifiers to copy.
4813      * @param {Object} [object={}] The object to copy properties to.
4814      * @param {Function} [customizer] The function to customize copied values.
4815      * @returns {Object} Returns `object`.
4816      */
4817     function copyObject(source, props, object, customizer) {
4818       var isNew = !object;
4819       object || (object = {});
4820
4821       var index = -1,
4822           length = props.length;
4823
4824       while (++index < length) {
4825         var key = props[index];
4826
4827         var newValue = customizer
4828           ? customizer(object[key], source[key], key, object, source)
4829           : undefined;
4830
4831         if (newValue === undefined) {
4832           newValue = source[key];
4833         }
4834         if (isNew) {
4835           baseAssignValue(object, key, newValue);
4836         } else {
4837           assignValue(object, key, newValue);
4838         }
4839       }
4840       return object;
4841     }
4842
4843     /**
4844      * Copies own symbols of `source` to `object`.
4845      *
4846      * @private
4847      * @param {Object} source The object to copy symbols from.
4848      * @param {Object} [object={}] The object to copy symbols to.
4849      * @returns {Object} Returns `object`.
4850      */
4851     function copySymbols(source, object) {
4852       return copyObject(source, getSymbols(source), object);
4853     }
4854
4855     /**
4856      * Copies own and inherited symbols of `source` to `object`.
4857      *
4858      * @private
4859      * @param {Object} source The object to copy symbols from.
4860      * @param {Object} [object={}] The object to copy symbols to.
4861      * @returns {Object} Returns `object`.
4862      */
4863     function copySymbolsIn(source, object) {
4864       return copyObject(source, getSymbolsIn(source), object);
4865     }
4866
4867     /**
4868      * Creates a function like `_.groupBy`.
4869      *
4870      * @private
4871      * @param {Function} setter The function to set accumulator values.
4872      * @param {Function} [initializer] The accumulator object initializer.
4873      * @returns {Function} Returns the new aggregator function.
4874      */
4875     function createAggregator(setter, initializer) {
4876       return function(collection, iteratee) {
4877         var func = isArray(collection) ? arrayAggregator : baseAggregator,
4878             accumulator = initializer ? initializer() : {};
4879
4880         return func(collection, setter, getIteratee(iteratee, 2), accumulator);
4881       };
4882     }
4883
4884     /**
4885      * Creates a function like `_.assign`.
4886      *
4887      * @private
4888      * @param {Function} assigner The function to assign values.
4889      * @returns {Function} Returns the new assigner function.
4890      */
4891     function createAssigner(assigner) {
4892       return baseRest(function(object, sources) {
4893         var index = -1,
4894             length = sources.length,
4895             customizer = length > 1 ? sources[length - 1] : undefined,
4896             guard = length > 2 ? sources[2] : undefined;
4897
4898         customizer = (assigner.length > 3 && typeof customizer == 'function')
4899           ? (length--, customizer)
4900           : undefined;
4901
4902         if (guard && isIterateeCall(sources[0], sources[1], guard)) {
4903           customizer = length < 3 ? undefined : customizer;
4904           length = 1;
4905         }
4906         object = Object(object);
4907         while (++index < length) {
4908           var source = sources[index];
4909           if (source) {
4910             assigner(object, source, index, customizer);
4911           }
4912         }
4913         return object;
4914       });
4915     }
4916
4917     /**
4918      * Creates a `baseEach` or `baseEachRight` function.
4919      *
4920      * @private
4921      * @param {Function} eachFunc The function to iterate over a collection.
4922      * @param {boolean} [fromRight] Specify iterating from right to left.
4923      * @returns {Function} Returns the new base function.
4924      */
4925     function createBaseEach(eachFunc, fromRight) {
4926       return function(collection, iteratee) {
4927         if (collection == null) {
4928           return collection;
4929         }
4930         if (!isArrayLike(collection)) {
4931           return eachFunc(collection, iteratee);
4932         }
4933         var length = collection.length,
4934             index = fromRight ? length : -1,
4935             iterable = Object(collection);
4936
4937         while ((fromRight ? index-- : ++index < length)) {
4938           if (iteratee(iterable[index], index, iterable) === false) {
4939             break;
4940           }
4941         }
4942         return collection;
4943       };
4944     }
4945
4946     /**
4947      * Creates a base function for methods like `_.forIn` and `_.forOwn`.
4948      *
4949      * @private
4950      * @param {boolean} [fromRight] Specify iterating from right to left.
4951      * @returns {Function} Returns the new base function.
4952      */
4953     function createBaseFor(fromRight) {
4954       return function(object, iteratee, keysFunc) {
4955         var index = -1,
4956             iterable = Object(object),
4957             props = keysFunc(object),
4958             length = props.length;
4959
4960         while (length--) {
4961           var key = props[fromRight ? length : ++index];
4962           if (iteratee(iterable[key], key, iterable) === false) {
4963             break;
4964           }
4965         }
4966         return object;
4967       };
4968     }
4969
4970     /**
4971      * Creates a function that wraps `func` to invoke it with the optional `this`
4972      * binding of `thisArg`.
4973      *
4974      * @private
4975      * @param {Function} func The function to wrap.
4976      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
4977      * @param {*} [thisArg] The `this` binding of `func`.
4978      * @returns {Function} Returns the new wrapped function.
4979      */
4980     function createBind(func, bitmask, thisArg) {
4981       var isBind = bitmask & WRAP_BIND_FLAG,
4982           Ctor = createCtor(func);
4983
4984       function wrapper() {
4985         var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
4986         return fn.apply(isBind ? thisArg : this, arguments);
4987       }
4988       return wrapper;
4989     }
4990
4991     /**
4992      * Creates a function like `_.lowerFirst`.
4993      *
4994      * @private
4995      * @param {string} methodName The name of the `String` case method to use.
4996      * @returns {Function} Returns the new case function.
4997      */
4998     function createCaseFirst(methodName) {
4999       return function(string) {
5000         string = toString(string);
5001
5002         var strSymbols = hasUnicode(string)
5003           ? stringToArray(string)
5004           : undefined;
5005
5006         var chr = strSymbols
5007           ? strSymbols[0]
5008           : string.charAt(0);
5009
5010         var trailing = strSymbols
5011           ? castSlice(strSymbols, 1).join('')
5012           : string.slice(1);
5013
5014         return chr[methodName]() + trailing;
5015       };
5016     }
5017
5018     /**
5019      * Creates a function like `_.camelCase`.
5020      *
5021      * @private
5022      * @param {Function} callback The function to combine each word.
5023      * @returns {Function} Returns the new compounder function.
5024      */
5025     function createCompounder(callback) {
5026       return function(string) {
5027         return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
5028       };
5029     }
5030
5031     /**
5032      * Creates a function that produces an instance of `Ctor` regardless of
5033      * whether it was invoked as part of a `new` expression or by `call` or `apply`.
5034      *
5035      * @private
5036      * @param {Function} Ctor The constructor to wrap.
5037      * @returns {Function} Returns the new wrapped function.
5038      */
5039     function createCtor(Ctor) {
5040       return function() {
5041         // Use a `switch` statement to work with class constructors. See
5042         // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
5043         // for more details.
5044         var args = arguments;
5045         switch (args.length) {
5046           case 0: return new Ctor;
5047           case 1: return new Ctor(args[0]);
5048           case 2: return new Ctor(args[0], args[1]);
5049           case 3: return new Ctor(args[0], args[1], args[2]);
5050           case 4: return new Ctor(args[0], args[1], args[2], args[3]);
5051           case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
5052           case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
5053           case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
5054         }
5055         var thisBinding = baseCreate(Ctor.prototype),
5056             result = Ctor.apply(thisBinding, args);
5057
5058         // Mimic the constructor's `return` behavior.
5059         // See https://es5.github.io/#x13.2.2 for more details.
5060         return isObject(result) ? result : thisBinding;
5061       };
5062     }
5063
5064     /**
5065      * Creates a function that wraps `func` to enable currying.
5066      *
5067      * @private
5068      * @param {Function} func The function to wrap.
5069      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5070      * @param {number} arity The arity of `func`.
5071      * @returns {Function} Returns the new wrapped function.
5072      */
5073     function createCurry(func, bitmask, arity) {
5074       var Ctor = createCtor(func);
5075
5076       function wrapper() {
5077         var length = arguments.length,
5078             args = Array(length),
5079             index = length,
5080             placeholder = getHolder(wrapper);
5081
5082         while (index--) {
5083           args[index] = arguments[index];
5084         }
5085         var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
5086           ? []
5087           : replaceHolders(args, placeholder);
5088
5089         length -= holders.length;
5090         if (length < arity) {
5091           return createRecurry(
5092             func, bitmask, createHybrid, wrapper.placeholder, undefined,
5093             args, holders, undefined, undefined, arity - length);
5094         }
5095         var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
5096         return apply(fn, this, args);
5097       }
5098       return wrapper;
5099     }
5100
5101     /**
5102      * Creates a `_.find` or `_.findLast` function.
5103      *
5104      * @private
5105      * @param {Function} findIndexFunc The function to find the collection index.
5106      * @returns {Function} Returns the new find function.
5107      */
5108     function createFind(findIndexFunc) {
5109       return function(collection, predicate, fromIndex) {
5110         var iterable = Object(collection);
5111         if (!isArrayLike(collection)) {
5112           var iteratee = getIteratee(predicate, 3);
5113           collection = keys(collection);
5114           predicate = function(key) { return iteratee(iterable[key], key, iterable); };
5115         }
5116         var index = findIndexFunc(collection, predicate, fromIndex);
5117         return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
5118       };
5119     }
5120
5121     /**
5122      * Creates a `_.flow` or `_.flowRight` function.
5123      *
5124      * @private
5125      * @param {boolean} [fromRight] Specify iterating from right to left.
5126      * @returns {Function} Returns the new flow function.
5127      */
5128     function createFlow(fromRight) {
5129       return flatRest(function(funcs) {
5130         var length = funcs.length,
5131             index = length,
5132             prereq = LodashWrapper.prototype.thru;
5133
5134         if (fromRight) {
5135           funcs.reverse();
5136         }
5137         while (index--) {
5138           var func = funcs[index];
5139           if (typeof func != 'function') {
5140             throw new TypeError(FUNC_ERROR_TEXT);
5141           }
5142           if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
5143             var wrapper = new LodashWrapper([], true);
5144           }
5145         }
5146         index = wrapper ? index : length;
5147         while (++index < length) {
5148           func = funcs[index];
5149
5150           var funcName = getFuncName(func),
5151               data = funcName == 'wrapper' ? getData(func) : undefined;
5152
5153           if (data && isLaziable(data[0]) &&
5154                 data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
5155                 !data[4].length && data[9] == 1
5156               ) {
5157             wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
5158           } else {
5159             wrapper = (func.length == 1 && isLaziable(func))
5160               ? wrapper[funcName]()
5161               : wrapper.thru(func);
5162           }
5163         }
5164         return function() {
5165           var args = arguments,
5166               value = args[0];
5167
5168           if (wrapper && args.length == 1 && isArray(value)) {
5169             return wrapper.plant(value).value();
5170           }
5171           var index = 0,
5172               result = length ? funcs[index].apply(this, args) : value;
5173
5174           while (++index < length) {
5175             result = funcs[index].call(this, result);
5176           }
5177           return result;
5178         };
5179       });
5180     }
5181
5182     /**
5183      * Creates a function that wraps `func` to invoke it with optional `this`
5184      * binding of `thisArg`, partial application, and currying.
5185      *
5186      * @private
5187      * @param {Function|string} func The function or method name to wrap.
5188      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5189      * @param {*} [thisArg] The `this` binding of `func`.
5190      * @param {Array} [partials] The arguments to prepend to those provided to
5191      *  the new function.
5192      * @param {Array} [holders] The `partials` placeholder indexes.
5193      * @param {Array} [partialsRight] The arguments to append to those provided
5194      *  to the new function.
5195      * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
5196      * @param {Array} [argPos] The argument positions of the new function.
5197      * @param {number} [ary] The arity cap of `func`.
5198      * @param {number} [arity] The arity of `func`.
5199      * @returns {Function} Returns the new wrapped function.
5200      */
5201     function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
5202       var isAry = bitmask & WRAP_ARY_FLAG,
5203           isBind = bitmask & WRAP_BIND_FLAG,
5204           isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
5205           isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
5206           isFlip = bitmask & WRAP_FLIP_FLAG,
5207           Ctor = isBindKey ? undefined : createCtor(func);
5208
5209       function wrapper() {
5210         var length = arguments.length,
5211             args = Array(length),
5212             index = length;
5213
5214         while (index--) {
5215           args[index] = arguments[index];
5216         }
5217         if (isCurried) {
5218           var placeholder = getHolder(wrapper),
5219               holdersCount = countHolders(args, placeholder);
5220         }
5221         if (partials) {
5222           args = composeArgs(args, partials, holders, isCurried);
5223         }
5224         if (partialsRight) {
5225           args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
5226         }
5227         length -= holdersCount;
5228         if (isCurried && length < arity) {
5229           var newHolders = replaceHolders(args, placeholder);
5230           return createRecurry(
5231             func, bitmask, createHybrid, wrapper.placeholder, thisArg,
5232             args, newHolders, argPos, ary, arity - length
5233           );
5234         }
5235         var thisBinding = isBind ? thisArg : this,
5236             fn = isBindKey ? thisBinding[func] : func;
5237
5238         length = args.length;
5239         if (argPos) {
5240           args = reorder(args, argPos);
5241         } else if (isFlip && length > 1) {
5242           args.reverse();
5243         }
5244         if (isAry && ary < length) {
5245           args.length = ary;
5246         }
5247         if (this && this !== root && this instanceof wrapper) {
5248           fn = Ctor || createCtor(fn);
5249         }
5250         return fn.apply(thisBinding, args);
5251       }
5252       return wrapper;
5253     }
5254
5255     /**
5256      * Creates a function like `_.invertBy`.
5257      *
5258      * @private
5259      * @param {Function} setter The function to set accumulator values.
5260      * @param {Function} toIteratee The function to resolve iteratees.
5261      * @returns {Function} Returns the new inverter function.
5262      */
5263     function createInverter(setter, toIteratee) {
5264       return function(object, iteratee) {
5265         return baseInverter(object, setter, toIteratee(iteratee), {});
5266       };
5267     }
5268
5269     /**
5270      * Creates a function that performs a mathematical operation on two values.
5271      *
5272      * @private
5273      * @param {Function} operator The function to perform the operation.
5274      * @param {number} [defaultValue] The value used for `undefined` arguments.
5275      * @returns {Function} Returns the new mathematical operation function.
5276      */
5277     function createMathOperation(operator, defaultValue) {
5278       return function(value, other) {
5279         var result;
5280         if (value === undefined && other === undefined) {
5281           return defaultValue;
5282         }
5283         if (value !== undefined) {
5284           result = value;
5285         }
5286         if (other !== undefined) {
5287           if (result === undefined) {
5288             return other;
5289           }
5290           if (typeof value == 'string' || typeof other == 'string') {
5291             value = baseToString(value);
5292             other = baseToString(other);
5293           } else {
5294             value = baseToNumber(value);
5295             other = baseToNumber(other);
5296           }
5297           result = operator(value, other);
5298         }
5299         return result;
5300       };
5301     }
5302
5303     /**
5304      * Creates a function like `_.over`.
5305      *
5306      * @private
5307      * @param {Function} arrayFunc The function to iterate over iteratees.
5308      * @returns {Function} Returns the new over function.
5309      */
5310     function createOver(arrayFunc) {
5311       return flatRest(function(iteratees) {
5312         iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
5313         return baseRest(function(args) {
5314           var thisArg = this;
5315           return arrayFunc(iteratees, function(iteratee) {
5316             return apply(iteratee, thisArg, args);
5317           });
5318         });
5319       });
5320     }
5321
5322     /**
5323      * Creates the padding for `string` based on `length`. The `chars` string
5324      * is truncated if the number of characters exceeds `length`.
5325      *
5326      * @private
5327      * @param {number} length The padding length.
5328      * @param {string} [chars=' '] The string used as padding.
5329      * @returns {string} Returns the padding for `string`.
5330      */
5331     function createPadding(length, chars) {
5332       chars = chars === undefined ? ' ' : baseToString(chars);
5333
5334       var charsLength = chars.length;
5335       if (charsLength < 2) {
5336         return charsLength ? baseRepeat(chars, length) : chars;
5337       }
5338       var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
5339       return hasUnicode(chars)
5340         ? castSlice(stringToArray(result), 0, length).join('')
5341         : result.slice(0, length);
5342     }
5343
5344     /**
5345      * Creates a function that wraps `func` to invoke it with the `this` binding
5346      * of `thisArg` and `partials` prepended to the arguments it receives.
5347      *
5348      * @private
5349      * @param {Function} func The function to wrap.
5350      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5351      * @param {*} thisArg The `this` binding of `func`.
5352      * @param {Array} partials The arguments to prepend to those provided to
5353      *  the new function.
5354      * @returns {Function} Returns the new wrapped function.
5355      */
5356     function createPartial(func, bitmask, thisArg, partials) {
5357       var isBind = bitmask & WRAP_BIND_FLAG,
5358           Ctor = createCtor(func);
5359
5360       function wrapper() {
5361         var argsIndex = -1,
5362             argsLength = arguments.length,
5363             leftIndex = -1,
5364             leftLength = partials.length,
5365             args = Array(leftLength + argsLength),
5366             fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
5367
5368         while (++leftIndex < leftLength) {
5369           args[leftIndex] = partials[leftIndex];
5370         }
5371         while (argsLength--) {
5372           args[leftIndex++] = arguments[++argsIndex];
5373         }
5374         return apply(fn, isBind ? thisArg : this, args);
5375       }
5376       return wrapper;
5377     }
5378
5379     /**
5380      * Creates a `_.range` or `_.rangeRight` function.
5381      *
5382      * @private
5383      * @param {boolean} [fromRight] Specify iterating from right to left.
5384      * @returns {Function} Returns the new range function.
5385      */
5386     function createRange(fromRight) {
5387       return function(start, end, step) {
5388         if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
5389           end = step = undefined;
5390         }
5391         // Ensure the sign of `-0` is preserved.
5392         start = toFinite(start);
5393         if (end === undefined) {
5394           end = start;
5395           start = 0;
5396         } else {
5397           end = toFinite(end);
5398         }
5399         step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);
5400         return baseRange(start, end, step, fromRight);
5401       };
5402     }
5403
5404     /**
5405      * Creates a function that performs a relational operation on two values.
5406      *
5407      * @private
5408      * @param {Function} operator The function to perform the operation.
5409      * @returns {Function} Returns the new relational operation function.
5410      */
5411     function createRelationalOperation(operator) {
5412       return function(value, other) {
5413         if (!(typeof value == 'string' && typeof other == 'string')) {
5414           value = toNumber(value);
5415           other = toNumber(other);
5416         }
5417         return operator(value, other);
5418       };
5419     }
5420
5421     /**
5422      * Creates a function that wraps `func` to continue currying.
5423      *
5424      * @private
5425      * @param {Function} func The function to wrap.
5426      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5427      * @param {Function} wrapFunc The function to create the `func` wrapper.
5428      * @param {*} placeholder The placeholder value.
5429      * @param {*} [thisArg] The `this` binding of `func`.
5430      * @param {Array} [partials] The arguments to prepend to those provided to
5431      *  the new function.
5432      * @param {Array} [holders] The `partials` placeholder indexes.
5433      * @param {Array} [argPos] The argument positions of the new function.
5434      * @param {number} [ary] The arity cap of `func`.
5435      * @param {number} [arity] The arity of `func`.
5436      * @returns {Function} Returns the new wrapped function.
5437      */
5438     function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
5439       var isCurry = bitmask & WRAP_CURRY_FLAG,
5440           newHolders = isCurry ? holders : undefined,
5441           newHoldersRight = isCurry ? undefined : holders,
5442           newPartials = isCurry ? partials : undefined,
5443           newPartialsRight = isCurry ? undefined : partials;
5444
5445       bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG);
5446       bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);
5447
5448       if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
5449         bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
5450       }
5451       var newData = [
5452         func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
5453         newHoldersRight, argPos, ary, arity
5454       ];
5455
5456       var result = wrapFunc.apply(undefined, newData);
5457       if (isLaziable(func)) {
5458         setData(result, newData);
5459       }
5460       result.placeholder = placeholder;
5461       return setWrapToString(result, func, bitmask);
5462     }
5463
5464     /**
5465      * Creates a function like `_.round`.
5466      *
5467      * @private
5468      * @param {string} methodName The name of the `Math` method to use when rounding.
5469      * @returns {Function} Returns the new round function.
5470      */
5471     function createRound(methodName) {
5472       var func = Math[methodName];
5473       return function(number, precision) {
5474         number = toNumber(number);
5475         precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
5476         if (precision) {
5477           // Shift with exponential notation to avoid floating-point issues.
5478           // See [MDN](https://mdn.io/round#Examples) for more details.
5479           var pair = (toString(number) + 'e').split('e'),
5480               value = func(pair[0] + 'e' + (+pair[1] + precision));
5481
5482           pair = (toString(value) + 'e').split('e');
5483           return +(pair[0] + 'e' + (+pair[1] - precision));
5484         }
5485         return func(number);
5486       };
5487     }
5488
5489     /**
5490      * Creates a set object of `values`.
5491      *
5492      * @private
5493      * @param {Array} values The values to add to the set.
5494      * @returns {Object} Returns the new set.
5495      */
5496     var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
5497       return new Set(values);
5498     };
5499
5500     /**
5501      * Creates a `_.toPairs` or `_.toPairsIn` function.
5502      *
5503      * @private
5504      * @param {Function} keysFunc The function to get the keys of a given object.
5505      * @returns {Function} Returns the new pairs function.
5506      */
5507     function createToPairs(keysFunc) {
5508       return function(object) {
5509         var tag = getTag(object);
5510         if (tag == mapTag) {
5511           return mapToArray(object);
5512         }
5513         if (tag == setTag) {
5514           return setToPairs(object);
5515         }
5516         return baseToPairs(object, keysFunc(object));
5517       };
5518     }
5519
5520     /**
5521      * Creates a function that either curries or invokes `func` with optional
5522      * `this` binding and partially applied arguments.
5523      *
5524      * @private
5525      * @param {Function|string} func The function or method name to wrap.
5526      * @param {number} bitmask The bitmask flags.
5527      *    1 - `_.bind`
5528      *    2 - `_.bindKey`
5529      *    4 - `_.curry` or `_.curryRight` of a bound function
5530      *    8 - `_.curry`
5531      *   16 - `_.curryRight`
5532      *   32 - `_.partial`
5533      *   64 - `_.partialRight`
5534      *  128 - `_.rearg`
5535      *  256 - `_.ary`
5536      *  512 - `_.flip`
5537      * @param {*} [thisArg] The `this` binding of `func`.
5538      * @param {Array} [partials] The arguments to be partially applied.
5539      * @param {Array} [holders] The `partials` placeholder indexes.
5540      * @param {Array} [argPos] The argument positions of the new function.
5541      * @param {number} [ary] The arity cap of `func`.
5542      * @param {number} [arity] The arity of `func`.
5543      * @returns {Function} Returns the new wrapped function.
5544      */
5545     function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
5546       var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
5547       if (!isBindKey && typeof func != 'function') {
5548         throw new TypeError(FUNC_ERROR_TEXT);
5549       }
5550       var length = partials ? partials.length : 0;
5551       if (!length) {
5552         bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
5553         partials = holders = undefined;
5554       }
5555       ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
5556       arity = arity === undefined ? arity : toInteger(arity);
5557       length -= holders ? holders.length : 0;
5558
5559       if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
5560         var partialsRight = partials,
5561             holdersRight = holders;
5562
5563         partials = holders = undefined;
5564       }
5565       var data = isBindKey ? undefined : getData(func);
5566
5567       var newData = [
5568         func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
5569         argPos, ary, arity
5570       ];
5571
5572       if (data) {
5573         mergeData(newData, data);
5574       }
5575       func = newData[0];
5576       bitmask = newData[1];
5577       thisArg = newData[2];
5578       partials = newData[3];
5579       holders = newData[4];
5580       arity = newData[9] = newData[9] === undefined
5581         ? (isBindKey ? 0 : func.length)
5582         : nativeMax(newData[9] - length, 0);
5583
5584       if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
5585         bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
5586       }
5587       if (!bitmask || bitmask == WRAP_BIND_FLAG) {
5588         var result = createBind(func, bitmask, thisArg);
5589       } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) {
5590         result = createCurry(func, bitmask, arity);
5591       } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) {
5592         result = createPartial(func, bitmask, thisArg, partials);
5593       } else {
5594         result = createHybrid.apply(undefined, newData);
5595       }
5596       var setter = data ? baseSetData : setData;
5597       return setWrapToString(setter(result, newData), func, bitmask);
5598     }
5599
5600     /**
5601      * Used by `_.defaults` to customize its `_.assignIn` use to assign properties
5602      * of source objects to the destination object for all destination properties
5603      * that resolve to `undefined`.
5604      *
5605      * @private
5606      * @param {*} objValue The destination value.
5607      * @param {*} srcValue The source value.
5608      * @param {string} key The key of the property to assign.
5609      * @param {Object} object The parent object of `objValue`.
5610      * @returns {*} Returns the value to assign.
5611      */
5612     function customDefaultsAssignIn(objValue, srcValue, key, object) {
5613       if (objValue === undefined ||
5614           (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
5615         return srcValue;
5616       }
5617       return objValue;
5618     }
5619
5620     /**
5621      * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
5622      * objects into destination objects that are passed thru.
5623      *
5624      * @private
5625      * @param {*} objValue The destination value.
5626      * @param {*} srcValue The source value.
5627      * @param {string} key The key of the property to merge.
5628      * @param {Object} object The parent object of `objValue`.
5629      * @param {Object} source The parent object of `srcValue`.
5630      * @param {Object} [stack] Tracks traversed source values and their merged
5631      *  counterparts.
5632      * @returns {*} Returns the value to assign.
5633      */
5634     function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
5635       if (isObject(objValue) && isObject(srcValue)) {
5636         // Recursively merge objects and arrays (susceptible to call stack limits).
5637         stack.set(srcValue, objValue);
5638         baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
5639         stack['delete'](srcValue);
5640       }
5641       return objValue;
5642     }
5643
5644     /**
5645      * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
5646      * objects.
5647      *
5648      * @private
5649      * @param {*} value The value to inspect.
5650      * @param {string} key The key of the property to inspect.
5651      * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
5652      */
5653     function customOmitClone(value) {
5654       return isPlainObject(value) ? undefined : value;
5655     }
5656
5657     /**
5658      * A specialized version of `baseIsEqualDeep` for arrays with support for
5659      * partial deep comparisons.
5660      *
5661      * @private
5662      * @param {Array} array The array to compare.
5663      * @param {Array} other The other array to compare.
5664      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5665      * @param {Function} customizer The function to customize comparisons.
5666      * @param {Function} equalFunc The function to determine equivalents of values.
5667      * @param {Object} stack Tracks traversed `array` and `other` objects.
5668      * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
5669      */
5670     function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
5671       var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
5672           arrLength = array.length,
5673           othLength = other.length;
5674
5675       if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
5676         return false;
5677       }
5678       // Assume cyclic values are equal.
5679       var stacked = stack.get(array);
5680       if (stacked && stack.get(other)) {
5681         return stacked == other;
5682       }
5683       var index = -1,
5684           result = true,
5685           seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;
5686
5687       stack.set(array, other);
5688       stack.set(other, array);
5689
5690       // Ignore non-index properties.
5691       while (++index < arrLength) {
5692         var arrValue = array[index],
5693             othValue = other[index];
5694
5695         if (customizer) {
5696           var compared = isPartial
5697             ? customizer(othValue, arrValue, index, other, array, stack)
5698             : customizer(arrValue, othValue, index, array, other, stack);
5699         }
5700         if (compared !== undefined) {
5701           if (compared) {
5702             continue;
5703           }
5704           result = false;
5705           break;
5706         }
5707         // Recursively compare arrays (susceptible to call stack limits).
5708         if (seen) {
5709           if (!arraySome(other, function(othValue, othIndex) {
5710                 if (!cacheHas(seen, othIndex) &&
5711                     (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
5712                   return seen.push(othIndex);
5713                 }
5714               })) {
5715             result = false;
5716             break;
5717           }
5718         } else if (!(
5719               arrValue === othValue ||
5720                 equalFunc(arrValue, othValue, bitmask, customizer, stack)
5721             )) {
5722           result = false;
5723           break;
5724         }
5725       }
5726       stack['delete'](array);
5727       stack['delete'](other);
5728       return result;
5729     }
5730
5731     /**
5732      * A specialized version of `baseIsEqualDeep` for comparing objects of
5733      * the same `toStringTag`.
5734      *
5735      * **Note:** This function only supports comparing values with tags of
5736      * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
5737      *
5738      * @private
5739      * @param {Object} object The object to compare.
5740      * @param {Object} other The other object to compare.
5741      * @param {string} tag The `toStringTag` of the objects to compare.
5742      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5743      * @param {Function} customizer The function to customize comparisons.
5744      * @param {Function} equalFunc The function to determine equivalents of values.
5745      * @param {Object} stack Tracks traversed `object` and `other` objects.
5746      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
5747      */
5748     function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
5749       switch (tag) {
5750         case dataViewTag:
5751           if ((object.byteLength != other.byteLength) ||
5752               (object.byteOffset != other.byteOffset)) {
5753             return false;
5754           }
5755           object = object.buffer;
5756           other = other.buffer;
5757
5758         case arrayBufferTag:
5759           if ((object.byteLength != other.byteLength) ||
5760               !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
5761             return false;
5762           }
5763           return true;
5764
5765         case boolTag:
5766         case dateTag:
5767         case numberTag:
5768           // Coerce booleans to `1` or `0` and dates to milliseconds.
5769           // Invalid dates are coerced to `NaN`.
5770           return eq(+object, +other);
5771
5772         case errorTag:
5773           return object.name == other.name && object.message == other.message;
5774
5775         case regexpTag:
5776         case stringTag:
5777           // Coerce regexes to strings and treat strings, primitives and objects,
5778           // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
5779           // for more details.
5780           return object == (other + '');
5781
5782         case mapTag:
5783           var convert = mapToArray;
5784
5785         case setTag:
5786           var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
5787           convert || (convert = setToArray);
5788
5789           if (object.size != other.size && !isPartial) {
5790             return false;
5791           }
5792           // Assume cyclic values are equal.
5793           var stacked = stack.get(object);
5794           if (stacked) {
5795             return stacked == other;
5796           }
5797           bitmask |= COMPARE_UNORDERED_FLAG;
5798
5799           // Recursively compare objects (susceptible to call stack limits).
5800           stack.set(object, other);
5801           var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
5802           stack['delete'](object);
5803           return result;
5804
5805         case symbolTag:
5806           if (symbolValueOf) {
5807             return symbolValueOf.call(object) == symbolValueOf.call(other);
5808           }
5809       }
5810       return false;
5811     }
5812
5813     /**
5814      * A specialized version of `baseIsEqualDeep` for objects with support for
5815      * partial deep comparisons.
5816      *
5817      * @private
5818      * @param {Object} object The object to compare.
5819      * @param {Object} other The other object to compare.
5820      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5821      * @param {Function} customizer The function to customize comparisons.
5822      * @param {Function} equalFunc The function to determine equivalents of values.
5823      * @param {Object} stack Tracks traversed `object` and `other` objects.
5824      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
5825      */
5826     function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
5827       var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
5828           objProps = getAllKeys(object),
5829           objLength = objProps.length,
5830           othProps = getAllKeys(other),
5831           othLength = othProps.length;
5832
5833       if (objLength != othLength && !isPartial) {
5834         return false;
5835       }
5836       var index = objLength;
5837       while (index--) {
5838         var key = objProps[index];
5839         if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
5840           return false;
5841         }
5842       }
5843       // Assume cyclic values are equal.
5844       var stacked = stack.get(object);
5845       if (stacked && stack.get(other)) {
5846         return stacked == other;
5847       }
5848       var result = true;
5849       stack.set(object, other);
5850       stack.set(other, object);
5851
5852       var skipCtor = isPartial;
5853       while (++index < objLength) {
5854         key = objProps[index];
5855         var objValue = object[key],
5856             othValue = other[key];
5857
5858         if (customizer) {
5859           var compared = isPartial
5860             ? customizer(othValue, objValue, key, other, object, stack)
5861             : customizer(objValue, othValue, key, object, other, stack);
5862         }
5863         // Recursively compare objects (susceptible to call stack limits).
5864         if (!(compared === undefined
5865               ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))
5866               : compared
5867             )) {
5868           result = false;
5869           break;
5870         }
5871         skipCtor || (skipCtor = key == 'constructor');
5872       }
5873       if (result && !skipCtor) {
5874         var objCtor = object.constructor,
5875             othCtor = other.constructor;
5876
5877         // Non `Object` object instances with different constructors are not equal.
5878         if (objCtor != othCtor &&
5879             ('constructor' in object && 'constructor' in other) &&
5880             !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
5881               typeof othCtor == 'function' && othCtor instanceof othCtor)) {
5882           result = false;
5883         }
5884       }
5885       stack['delete'](object);
5886       stack['delete'](other);
5887       return result;
5888     }
5889
5890     /**
5891      * A specialized version of `baseRest` which flattens the rest array.
5892      *
5893      * @private
5894      * @param {Function} func The function to apply a rest parameter to.
5895      * @returns {Function} Returns the new function.
5896      */
5897     function flatRest(func) {
5898       return setToString(overRest(func, undefined, flatten), func + '');
5899     }
5900
5901     /**
5902      * Creates an array of own enumerable property names and symbols of `object`.
5903      *
5904      * @private
5905      * @param {Object} object The object to query.
5906      * @returns {Array} Returns the array of property names and symbols.
5907      */
5908     function getAllKeys(object) {
5909       return baseGetAllKeys(object, keys, getSymbols);
5910     }
5911
5912     /**
5913      * Creates an array of own and inherited enumerable property names and
5914      * symbols of `object`.
5915      *
5916      * @private
5917      * @param {Object} object The object to query.
5918      * @returns {Array} Returns the array of property names and symbols.
5919      */
5920     function getAllKeysIn(object) {
5921       return baseGetAllKeys(object, keysIn, getSymbolsIn);
5922     }
5923
5924     /**
5925      * Gets metadata for `func`.
5926      *
5927      * @private
5928      * @param {Function} func The function to query.
5929      * @returns {*} Returns the metadata for `func`.
5930      */
5931     var getData = !metaMap ? noop : function(func) {
5932       return metaMap.get(func);
5933     };
5934
5935     /**
5936      * Gets the name of `func`.
5937      *
5938      * @private
5939      * @param {Function} func The function to query.
5940      * @returns {string} Returns the function name.
5941      */
5942     function getFuncName(func) {
5943       var result = (func.name + ''),
5944           array = realNames[result],
5945           length = hasOwnProperty.call(realNames, result) ? array.length : 0;
5946
5947       while (length--) {
5948         var data = array[length],
5949             otherFunc = data.func;
5950         if (otherFunc == null || otherFunc == func) {
5951           return data.name;
5952         }
5953       }
5954       return result;
5955     }
5956
5957     /**
5958      * Gets the argument placeholder value for `func`.
5959      *
5960      * @private
5961      * @param {Function} func The function to inspect.
5962      * @returns {*} Returns the placeholder value.
5963      */
5964     function getHolder(func) {
5965       var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
5966       return object.placeholder;
5967     }
5968
5969     /**
5970      * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
5971      * this function returns the custom method, otherwise it returns `baseIteratee`.
5972      * If arguments are provided, the chosen function is invoked with them and
5973      * its result is returned.
5974      *
5975      * @private
5976      * @param {*} [value] The value to convert to an iteratee.
5977      * @param {number} [arity] The arity of the created iteratee.
5978      * @returns {Function} Returns the chosen function or its result.
5979      */
5980     function getIteratee() {
5981       var result = lodash.iteratee || iteratee;
5982       result = result === iteratee ? baseIteratee : result;
5983       return arguments.length ? result(arguments[0], arguments[1]) : result;
5984     }
5985
5986     /**
5987      * Gets the data for `map`.
5988      *
5989      * @private
5990      * @param {Object} map The map to query.
5991      * @param {string} key The reference key.
5992      * @returns {*} Returns the map data.
5993      */
5994     function getMapData(map, key) {
5995       var data = map.__data__;
5996       return isKeyable(key)
5997         ? data[typeof key == 'string' ? 'string' : 'hash']
5998         : data.map;
5999     }
6000
6001     /**
6002      * Gets the property names, values, and compare flags of `object`.
6003      *
6004      * @private
6005      * @param {Object} object The object to query.
6006      * @returns {Array} Returns the match data of `object`.
6007      */
6008     function getMatchData(object) {
6009       var result = keys(object),
6010           length = result.length;
6011
6012       while (length--) {
6013         var key = result[length],
6014             value = object[key];
6015
6016         result[length] = [key, value, isStrictComparable(value)];
6017       }
6018       return result;
6019     }
6020
6021     /**
6022      * Gets the native function at `key` of `object`.
6023      *
6024      * @private
6025      * @param {Object} object The object to query.
6026      * @param {string} key The key of the method to get.
6027      * @returns {*} Returns the function if it's native, else `undefined`.
6028      */
6029     function getNative(object, key) {
6030       var value = getValue(object, key);
6031       return baseIsNative(value) ? value : undefined;
6032     }
6033
6034     /**
6035      * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
6036      *
6037      * @private
6038      * @param {*} value The value to query.
6039      * @returns {string} Returns the raw `toStringTag`.
6040      */
6041     function getRawTag(value) {
6042       var isOwn = hasOwnProperty.call(value, symToStringTag),
6043           tag = value[symToStringTag];
6044
6045       try {
6046         value[symToStringTag] = undefined;
6047         var unmasked = true;
6048       } catch (e) {}
6049
6050       var result = nativeObjectToString.call(value);
6051       if (unmasked) {
6052         if (isOwn) {
6053           value[symToStringTag] = tag;
6054         } else {
6055           delete value[symToStringTag];
6056         }
6057       }
6058       return result;
6059     }
6060
6061     /**
6062      * Creates an array of the own enumerable symbols of `object`.
6063      *
6064      * @private
6065      * @param {Object} object The object to query.
6066      * @returns {Array} Returns the array of symbols.
6067      */
6068     var getSymbols = !nativeGetSymbols ? stubArray : function(object) {
6069       if (object == null) {
6070         return [];
6071       }
6072       object = Object(object);
6073       return arrayFilter(nativeGetSymbols(object), function(symbol) {
6074         return propertyIsEnumerable.call(object, symbol);
6075       });
6076     };
6077
6078     /**
6079      * Creates an array of the own and inherited enumerable symbols of `object`.
6080      *
6081      * @private
6082      * @param {Object} object The object to query.
6083      * @returns {Array} Returns the array of symbols.
6084      */
6085     var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {
6086       var result = [];
6087       while (object) {
6088         arrayPush(result, getSymbols(object));
6089         object = getPrototype(object);
6090       }
6091       return result;
6092     };
6093
6094     /**
6095      * Gets the `toStringTag` of `value`.
6096      *
6097      * @private
6098      * @param {*} value The value to query.
6099      * @returns {string} Returns the `toStringTag`.
6100      */
6101     var getTag = baseGetTag;
6102
6103     // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
6104     if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
6105         (Map && getTag(new Map) != mapTag) ||
6106         (Promise && getTag(Promise.resolve()) != promiseTag) ||
6107         (Set && getTag(new Set) != setTag) ||
6108         (WeakMap && getTag(new WeakMap) != weakMapTag)) {
6109       getTag = function(value) {
6110         var result = baseGetTag(value),
6111             Ctor = result == objectTag ? value.constructor : undefined,
6112             ctorString = Ctor ? toSource(Ctor) : '';
6113
6114         if (ctorString) {
6115           switch (ctorString) {
6116             case dataViewCtorString: return dataViewTag;
6117             case mapCtorString: return mapTag;
6118             case promiseCtorString: return promiseTag;
6119             case setCtorString: return setTag;
6120             case weakMapCtorString: return weakMapTag;
6121           }
6122         }
6123         return result;
6124       };
6125     }
6126
6127     /**
6128      * Gets the view, applying any `transforms` to the `start` and `end` positions.
6129      *
6130      * @private
6131      * @param {number} start The start of the view.
6132      * @param {number} end The end of the view.
6133      * @param {Array} transforms The transformations to apply to the view.
6134      * @returns {Object} Returns an object containing the `start` and `end`
6135      *  positions of the view.
6136      */
6137     function getView(start, end, transforms) {
6138       var index = -1,
6139           length = transforms.length;
6140
6141       while (++index < length) {
6142         var data = transforms[index],
6143             size = data.size;
6144
6145         switch (data.type) {
6146           case 'drop':      start += size; break;
6147           case 'dropRight': end -= size; break;
6148           case 'take':      end = nativeMin(end, start + size); break;
6149           case 'takeRight': start = nativeMax(start, end - size); break;
6150         }
6151       }
6152       return { 'start': start, 'end': end };
6153     }
6154
6155     /**
6156      * Extracts wrapper details from the `source` body comment.
6157      *
6158      * @private
6159      * @param {string} source The source to inspect.
6160      * @returns {Array} Returns the wrapper details.
6161      */
6162     function getWrapDetails(source) {
6163       var match = source.match(reWrapDetails);
6164       return match ? match[1].split(reSplitDetails) : [];
6165     }
6166
6167     /**
6168      * Checks if `path` exists on `object`.
6169      *
6170      * @private
6171      * @param {Object} object The object to query.
6172      * @param {Array|string} path The path to check.
6173      * @param {Function} hasFunc The function to check properties.
6174      * @returns {boolean} Returns `true` if `path` exists, else `false`.
6175      */
6176     function hasPath(object, path, hasFunc) {
6177       path = castPath(path, object);
6178
6179       var index = -1,
6180           length = path.length,
6181           result = false;
6182
6183       while (++index < length) {
6184         var key = toKey(path[index]);
6185         if (!(result = object != null && hasFunc(object, key))) {
6186           break;
6187         }
6188         object = object[key];
6189       }
6190       if (result || ++index != length) {
6191         return result;
6192       }
6193       length = object == null ? 0 : object.length;
6194       return !!length && isLength(length) && isIndex(key, length) &&
6195         (isArray(object) || isArguments(object));
6196     }
6197
6198     /**
6199      * Initializes an array clone.
6200      *
6201      * @private
6202      * @param {Array} array The array to clone.
6203      * @returns {Array} Returns the initialized clone.
6204      */
6205     function initCloneArray(array) {
6206       var length = array.length,
6207           result = array.constructor(length);
6208
6209       // Add properties assigned by `RegExp#exec`.
6210       if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
6211         result.index = array.index;
6212         result.input = array.input;
6213       }
6214       return result;
6215     }
6216
6217     /**
6218      * Initializes an object clone.
6219      *
6220      * @private
6221      * @param {Object} object The object to clone.
6222      * @returns {Object} Returns the initialized clone.
6223      */
6224     function initCloneObject(object) {
6225       return (typeof object.constructor == 'function' && !isPrototype(object))
6226         ? baseCreate(getPrototype(object))
6227         : {};
6228     }
6229
6230     /**
6231      * Initializes an object clone based on its `toStringTag`.
6232      *
6233      * **Note:** This function only supports cloning values with tags of
6234      * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
6235      *
6236      * @private
6237      * @param {Object} object The object to clone.
6238      * @param {string} tag The `toStringTag` of the object to clone.
6239      * @param {Function} cloneFunc The function to clone values.
6240      * @param {boolean} [isDeep] Specify a deep clone.
6241      * @returns {Object} Returns the initialized clone.
6242      */
6243     function initCloneByTag(object, tag, cloneFunc, isDeep) {
6244       var Ctor = object.constructor;
6245       switch (tag) {
6246         case arrayBufferTag:
6247           return cloneArrayBuffer(object);
6248
6249         case boolTag:
6250         case dateTag:
6251           return new Ctor(+object);
6252
6253         case dataViewTag:
6254           return cloneDataView(object, isDeep);
6255
6256         case float32Tag: case float64Tag:
6257         case int8Tag: case int16Tag: case int32Tag:
6258         case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
6259           return cloneTypedArray(object, isDeep);
6260
6261         case mapTag:
6262           return cloneMap(object, isDeep, cloneFunc);
6263
6264         case numberTag:
6265         case stringTag:
6266           return new Ctor(object);
6267
6268         case regexpTag:
6269           return cloneRegExp(object);
6270
6271         case setTag:
6272           return cloneSet(object, isDeep, cloneFunc);
6273
6274         case symbolTag:
6275           return cloneSymbol(object);
6276       }
6277     }
6278
6279     /**
6280      * Inserts wrapper `details` in a comment at the top of the `source` body.
6281      *
6282      * @private
6283      * @param {string} source The source to modify.
6284      * @returns {Array} details The details to insert.
6285      * @returns {string} Returns the modified source.
6286      */
6287     function insertWrapDetails(source, details) {
6288       var length = details.length;
6289       if (!length) {
6290         return source;
6291       }
6292       var lastIndex = length - 1;
6293       details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
6294       details = details.join(length > 2 ? ', ' : ' ');
6295       return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
6296     }
6297
6298     /**
6299      * Checks if `value` is a flattenable `arguments` object or array.
6300      *
6301      * @private
6302      * @param {*} value The value to check.
6303      * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
6304      */
6305     function isFlattenable(value) {
6306       return isArray(value) || isArguments(value) ||
6307         !!(spreadableSymbol && value && value[spreadableSymbol]);
6308     }
6309
6310     /**
6311      * Checks if `value` is a valid array-like index.
6312      *
6313      * @private
6314      * @param {*} value The value to check.
6315      * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
6316      * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
6317      */
6318     function isIndex(value, length) {
6319       length = length == null ? MAX_SAFE_INTEGER : length;
6320       return !!length &&
6321         (typeof value == 'number' || reIsUint.test(value)) &&
6322         (value > -1 && value % 1 == 0 && value < length);
6323     }
6324
6325     /**
6326      * Checks if the given arguments are from an iteratee call.
6327      *
6328      * @private
6329      * @param {*} value The potential iteratee value argument.
6330      * @param {*} index The potential iteratee index or key argument.
6331      * @param {*} object The potential iteratee object argument.
6332      * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
6333      *  else `false`.
6334      */
6335     function isIterateeCall(value, index, object) {
6336       if (!isObject(object)) {
6337         return false;
6338       }
6339       var type = typeof index;
6340       if (type == 'number'
6341             ? (isArrayLike(object) && isIndex(index, object.length))
6342             : (type == 'string' && index in object)
6343           ) {
6344         return eq(object[index], value);
6345       }
6346       return false;
6347     }
6348
6349     /**
6350      * Checks if `value` is a property name and not a property path.
6351      *
6352      * @private
6353      * @param {*} value The value to check.
6354      * @param {Object} [object] The object to query keys on.
6355      * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
6356      */
6357     function isKey(value, object) {
6358       if (isArray(value)) {
6359         return false;
6360       }
6361       var type = typeof value;
6362       if (type == 'number' || type == 'symbol' || type == 'boolean' ||
6363           value == null || isSymbol(value)) {
6364         return true;
6365       }
6366       return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
6367         (object != null && value in Object(object));
6368     }
6369
6370     /**
6371      * Checks if `value` is suitable for use as unique object key.
6372      *
6373      * @private
6374      * @param {*} value The value to check.
6375      * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
6376      */
6377     function isKeyable(value) {
6378       var type = typeof value;
6379       return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
6380         ? (value !== '__proto__')
6381         : (value === null);
6382     }
6383
6384     /**
6385      * Checks if `func` has a lazy counterpart.
6386      *
6387      * @private
6388      * @param {Function} func The function to check.
6389      * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
6390      *  else `false`.
6391      */
6392     function isLaziable(func) {
6393       var funcName = getFuncName(func),
6394           other = lodash[funcName];
6395
6396       if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
6397         return false;
6398       }
6399       if (func === other) {
6400         return true;
6401       }
6402       var data = getData(other);
6403       return !!data && func === data[0];
6404     }
6405
6406     /**
6407      * Checks if `func` has its source masked.
6408      *
6409      * @private
6410      * @param {Function} func The function to check.
6411      * @returns {boolean} Returns `true` if `func` is masked, else `false`.
6412      */
6413     function isMasked(func) {
6414       return !!maskSrcKey && (maskSrcKey in func);
6415     }
6416
6417     /**
6418      * Checks if `func` is capable of being masked.
6419      *
6420      * @private
6421      * @param {*} value The value to check.
6422      * @returns {boolean} Returns `true` if `func` is maskable, else `false`.
6423      */
6424     var isMaskable = coreJsData ? isFunction : stubFalse;
6425
6426     /**
6427      * Checks if `value` is likely a prototype object.
6428      *
6429      * @private
6430      * @param {*} value The value to check.
6431      * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
6432      */
6433     function isPrototype(value) {
6434       var Ctor = value && value.constructor,
6435           proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
6436
6437       return value === proto;
6438     }
6439
6440     /**
6441      * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
6442      *
6443      * @private
6444      * @param {*} value The value to check.
6445      * @returns {boolean} Returns `true` if `value` if suitable for strict
6446      *  equality comparisons, else `false`.
6447      */
6448     function isStrictComparable(value) {
6449       return value === value && !isObject(value);
6450     }
6451
6452     /**
6453      * A specialized version of `matchesProperty` for source values suitable
6454      * for strict equality comparisons, i.e. `===`.
6455      *
6456      * @private
6457      * @param {string} key The key of the property to get.
6458      * @param {*} srcValue The value to match.
6459      * @returns {Function} Returns the new spec function.
6460      */
6461     function matchesStrictComparable(key, srcValue) {
6462       return function(object) {
6463         if (object == null) {
6464           return false;
6465         }
6466         return object[key] === srcValue &&
6467           (srcValue !== undefined || (key in Object(object)));
6468       };
6469     }
6470
6471     /**
6472      * A specialized version of `_.memoize` which clears the memoized function's
6473      * cache when it exceeds `MAX_MEMOIZE_SIZE`.
6474      *
6475      * @private
6476      * @param {Function} func The function to have its output memoized.
6477      * @returns {Function} Returns the new memoized function.
6478      */
6479     function memoizeCapped(func) {
6480       var result = memoize(func, function(key) {
6481         if (cache.size === MAX_MEMOIZE_SIZE) {
6482           cache.clear();
6483         }
6484         return key;
6485       });
6486
6487       var cache = result.cache;
6488       return result;
6489     }
6490
6491     /**
6492      * Merges the function metadata of `source` into `data`.
6493      *
6494      * Merging metadata reduces the number of wrappers used to invoke a function.
6495      * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
6496      * may be applied regardless of execution order. Methods like `_.ary` and
6497      * `_.rearg` modify function arguments, making the order in which they are
6498      * executed important, preventing the merging of metadata. However, we make
6499      * an exception for a safe combined case where curried functions have `_.ary`
6500      * and or `_.rearg` applied.
6501      *
6502      * @private
6503      * @param {Array} data The destination metadata.
6504      * @param {Array} source The source metadata.
6505      * @returns {Array} Returns `data`.
6506      */
6507     function mergeData(data, source) {
6508       var bitmask = data[1],
6509           srcBitmask = source[1],
6510           newBitmask = bitmask | srcBitmask,
6511           isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG);
6512
6513       var isCombo =
6514         ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) ||
6515         ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) ||
6516         ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG));
6517
6518       // Exit early if metadata can't be merged.
6519       if (!(isCommon || isCombo)) {
6520         return data;
6521       }
6522       // Use source `thisArg` if available.
6523       if (srcBitmask & WRAP_BIND_FLAG) {
6524         data[2] = source[2];
6525         // Set when currying a bound function.
6526         newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG;
6527       }
6528       // Compose partial arguments.
6529       var value = source[3];
6530       if (value) {
6531         var partials = data[3];
6532         data[3] = partials ? composeArgs(partials, value, source[4]) : value;
6533         data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
6534       }
6535       // Compose partial right arguments.
6536       value = source[5];
6537       if (value) {
6538         partials = data[5];
6539         data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
6540         data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
6541       }
6542       // Use source `argPos` if available.
6543       value = source[7];
6544       if (value) {
6545         data[7] = value;
6546       }
6547       // Use source `ary` if it's smaller.
6548       if (srcBitmask & WRAP_ARY_FLAG) {
6549         data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
6550       }
6551       // Use source `arity` if one is not provided.
6552       if (data[9] == null) {
6553         data[9] = source[9];
6554       }
6555       // Use source `func` and merge bitmasks.
6556       data[0] = source[0];
6557       data[1] = newBitmask;
6558
6559       return data;
6560     }
6561
6562     /**
6563      * This function is like
6564      * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
6565      * except that it includes inherited enumerable properties.
6566      *
6567      * @private
6568      * @param {Object} object The object to query.
6569      * @returns {Array} Returns the array of property names.
6570      */
6571     function nativeKeysIn(object) {
6572       var result = [];
6573       if (object != null) {
6574         for (var key in Object(object)) {
6575           result.push(key);
6576         }
6577       }
6578       return result;
6579     }
6580
6581     /**
6582      * Converts `value` to a string using `Object.prototype.toString`.
6583      *
6584      * @private
6585      * @param {*} value The value to convert.
6586      * @returns {string} Returns the converted string.
6587      */
6588     function objectToString(value) {
6589       return nativeObjectToString.call(value);
6590     }
6591
6592     /**
6593      * A specialized version of `baseRest` which transforms the rest array.
6594      *
6595      * @private
6596      * @param {Function} func The function to apply a rest parameter to.
6597      * @param {number} [start=func.length-1] The start position of the rest parameter.
6598      * @param {Function} transform The rest array transform.
6599      * @returns {Function} Returns the new function.
6600      */
6601     function overRest(func, start, transform) {
6602       start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
6603       return function() {
6604         var args = arguments,
6605             index = -1,
6606             length = nativeMax(args.length - start, 0),
6607             array = Array(length);
6608
6609         while (++index < length) {
6610           array[index] = args[start + index];
6611         }
6612         index = -1;
6613         var otherArgs = Array(start + 1);
6614         while (++index < start) {
6615           otherArgs[index] = args[index];
6616         }
6617         otherArgs[start] = transform(array);
6618         return apply(func, this, otherArgs);
6619       };
6620     }
6621
6622     /**
6623      * Gets the parent value at `path` of `object`.
6624      *
6625      * @private
6626      * @param {Object} object The object to query.
6627      * @param {Array} path The path to get the parent value of.
6628      * @returns {*} Returns the parent value.
6629      */
6630     function parent(object, path) {
6631       return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
6632     }
6633
6634     /**
6635      * Reorder `array` according to the specified indexes where the element at
6636      * the first index is assigned as the first element, the element at
6637      * the second index is assigned as the second element, and so on.
6638      *
6639      * @private
6640      * @param {Array} array The array to reorder.
6641      * @param {Array} indexes The arranged array indexes.
6642      * @returns {Array} Returns `array`.
6643      */
6644     function reorder(array, indexes) {
6645       var arrLength = array.length,
6646           length = nativeMin(indexes.length, arrLength),
6647           oldArray = copyArray(array);
6648
6649       while (length--) {
6650         var index = indexes[length];
6651         array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
6652       }
6653       return array;
6654     }
6655
6656     /**
6657      * Sets metadata for `func`.
6658      *
6659      * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
6660      * period of time, it will trip its breaker and transition to an identity
6661      * function to avoid garbage collection pauses in V8. See
6662      * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
6663      * for more details.
6664      *
6665      * @private
6666      * @param {Function} func The function to associate metadata with.
6667      * @param {*} data The metadata.
6668      * @returns {Function} Returns `func`.
6669      */
6670     var setData = shortOut(baseSetData);
6671
6672     /**
6673      * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
6674      *
6675      * @private
6676      * @param {Function} func The function to delay.
6677      * @param {number} wait The number of milliseconds to delay invocation.
6678      * @returns {number|Object} Returns the timer id or timeout object.
6679      */
6680     var setTimeout = ctxSetTimeout || function(func, wait) {
6681       return root.setTimeout(func, wait);
6682     };
6683
6684     /**
6685      * Sets the `toString` method of `func` to return `string`.
6686      *
6687      * @private
6688      * @param {Function} func The function to modify.
6689      * @param {Function} string The `toString` result.
6690      * @returns {Function} Returns `func`.
6691      */
6692     var setToString = shortOut(baseSetToString);
6693
6694     /**
6695      * Sets the `toString` method of `wrapper` to mimic the source of `reference`
6696      * with wrapper details in a comment at the top of the source body.
6697      *
6698      * @private
6699      * @param {Function} wrapper The function to modify.
6700      * @param {Function} reference The reference function.
6701      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6702      * @returns {Function} Returns `wrapper`.
6703      */
6704     function setWrapToString(wrapper, reference, bitmask) {
6705       var source = (reference + '');
6706       return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask)));
6707     }
6708
6709     /**
6710      * Creates a function that'll short out and invoke `identity` instead
6711      * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
6712      * milliseconds.
6713      *
6714      * @private
6715      * @param {Function} func The function to restrict.
6716      * @returns {Function} Returns the new shortable function.
6717      */
6718     function shortOut(func) {
6719       var count = 0,
6720           lastCalled = 0;
6721
6722       return function() {
6723         var stamp = nativeNow(),
6724             remaining = HOT_SPAN - (stamp - lastCalled);
6725
6726         lastCalled = stamp;
6727         if (remaining > 0) {
6728           if (++count >= HOT_COUNT) {
6729             return arguments[0];
6730           }
6731         } else {
6732           count = 0;
6733         }
6734         return func.apply(undefined, arguments);
6735       };
6736     }
6737
6738     /**
6739      * A specialized version of `_.shuffle` which mutates and sets the size of `array`.
6740      *
6741      * @private
6742      * @param {Array} array The array to shuffle.
6743      * @param {number} [size=array.length] The size of `array`.
6744      * @returns {Array} Returns `array`.
6745      */
6746     function shuffleSelf(array, size) {
6747       var index = -1,
6748           length = array.length,
6749           lastIndex = length - 1;
6750
6751       size = size === undefined ? length : size;
6752       while (++index < size) {
6753         var rand = baseRandom(index, lastIndex),
6754             value = array[rand];
6755
6756         array[rand] = array[index];
6757         array[index] = value;
6758       }
6759       array.length = size;
6760       return array;
6761     }
6762
6763     /**
6764      * Converts `string` to a property path array.
6765      *
6766      * @private
6767      * @param {string} string The string to convert.
6768      * @returns {Array} Returns the property path array.
6769      */
6770     var stringToPath = memoizeCapped(function(string) {
6771       var result = [];
6772       if (reLeadingDot.test(string)) {
6773         result.push('');
6774       }
6775       string.replace(rePropName, function(match, number, quote, string) {
6776         result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
6777       });
6778       return result;
6779     });
6780
6781     /**
6782      * Converts `value` to a string key if it's not a string or symbol.
6783      *
6784      * @private
6785      * @param {*} value The value to inspect.
6786      * @returns {string|symbol} Returns the key.
6787      */
6788     function toKey(value) {
6789       if (typeof value == 'string' || isSymbol(value)) {
6790         return value;
6791       }
6792       var result = (value + '');
6793       return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
6794     }
6795
6796     /**
6797      * Converts `func` to its source code.
6798      *
6799      * @private
6800      * @param {Function} func The function to convert.
6801      * @returns {string} Returns the source code.
6802      */
6803     function toSource(func) {
6804       if (func != null) {
6805         try {
6806           return funcToString.call(func);
6807         } catch (e) {}
6808         try {
6809           return (func + '');
6810         } catch (e) {}
6811       }
6812       return '';
6813     }
6814
6815     /**
6816      * Updates wrapper `details` based on `bitmask` flags.
6817      *
6818      * @private
6819      * @returns {Array} details The details to modify.
6820      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6821      * @returns {Array} Returns `details`.
6822      */
6823     function updateWrapDetails(details, bitmask) {
6824       arrayEach(wrapFlags, function(pair) {
6825         var value = '_.' + pair[0];
6826         if ((bitmask & pair[1]) && !arrayIncludes(details, value)) {
6827           details.push(value);
6828         }
6829       });
6830       return details.sort();
6831     }
6832
6833     /**
6834      * Creates a clone of `wrapper`.
6835      *
6836      * @private
6837      * @param {Object} wrapper The wrapper to clone.
6838      * @returns {Object} Returns the cloned wrapper.
6839      */
6840     function wrapperClone(wrapper) {
6841       if (wrapper instanceof LazyWrapper) {
6842         return wrapper.clone();
6843       }
6844       var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
6845       result.__actions__ = copyArray(wrapper.__actions__);
6846       result.__index__  = wrapper.__index__;
6847       result.__values__ = wrapper.__values__;
6848       return result;
6849     }
6850
6851     /*------------------------------------------------------------------------*/
6852
6853     /**
6854      * Creates an array of elements split into groups the length of `size`.
6855      * If `array` can't be split evenly, the final chunk will be the remaining
6856      * elements.
6857      *
6858      * @static
6859      * @memberOf _
6860      * @since 3.0.0
6861      * @category Array
6862      * @param {Array} array The array to process.
6863      * @param {number} [size=1] The length of each chunk
6864      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
6865      * @returns {Array} Returns the new array of chunks.
6866      * @example
6867      *
6868      * _.chunk(['a', 'b', 'c', 'd'], 2);
6869      * // => [['a', 'b'], ['c', 'd']]
6870      *
6871      * _.chunk(['a', 'b', 'c', 'd'], 3);
6872      * // => [['a', 'b', 'c'], ['d']]
6873      */
6874     function chunk(array, size, guard) {
6875       if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
6876         size = 1;
6877       } else {
6878         size = nativeMax(toInteger(size), 0);
6879       }
6880       var length = array == null ? 0 : array.length;
6881       if (!length || size < 1) {
6882         return [];
6883       }
6884       var index = 0,
6885           resIndex = 0,
6886           result = Array(nativeCeil(length / size));
6887
6888       while (index < length) {
6889         result[resIndex++] = baseSlice(array, index, (index += size));
6890       }
6891       return result;
6892     }
6893
6894     /**
6895      * Creates an array with all falsey values removed. The values `false`, `null`,
6896      * `0`, `""`, `undefined`, and `NaN` are falsey.
6897      *
6898      * @static
6899      * @memberOf _
6900      * @since 0.1.0
6901      * @category Array
6902      * @param {Array} array The array to compact.
6903      * @returns {Array} Returns the new array of filtered values.
6904      * @example
6905      *
6906      * _.compact([0, 1, false, 2, '', 3]);
6907      * // => [1, 2, 3]
6908      */
6909     function compact(array) {
6910       var index = -1,
6911           length = array == null ? 0 : array.length,
6912           resIndex = 0,
6913           result = [];
6914
6915       while (++index < length) {
6916         var value = array[index];
6917         if (value) {
6918           result[resIndex++] = value;
6919         }
6920       }
6921       return result;
6922     }
6923
6924     /**
6925      * Creates a new array concatenating `array` with any additional arrays
6926      * and/or values.
6927      *
6928      * @static
6929      * @memberOf _
6930      * @since 4.0.0
6931      * @category Array
6932      * @param {Array} array The array to concatenate.
6933      * @param {...*} [values] The values to concatenate.
6934      * @returns {Array} Returns the new concatenated array.
6935      * @example
6936      *
6937      * var array = [1];
6938      * var other = _.concat(array, 2, [3], [[4]]);
6939      *
6940      * console.log(other);
6941      * // => [1, 2, 3, [4]]
6942      *
6943      * console.log(array);
6944      * // => [1]
6945      */
6946     function concat() {
6947       var length = arguments.length;
6948       if (!length) {
6949         return [];
6950       }
6951       var args = Array(length - 1),
6952           array = arguments[0],
6953           index = length;
6954
6955       while (index--) {
6956         args[index - 1] = arguments[index];
6957       }
6958       return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
6959     }
6960
6961     /**
6962      * Creates an array of `array` values not included in the other given arrays
6963      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
6964      * for equality comparisons. The order and references of result values are
6965      * determined by the first array.
6966      *
6967      * **Note:** Unlike `_.pullAll`, this method returns a new array.
6968      *
6969      * @static
6970      * @memberOf _
6971      * @since 0.1.0
6972      * @category Array
6973      * @param {Array} array The array to inspect.
6974      * @param {...Array} [values] The values to exclude.
6975      * @returns {Array} Returns the new array of filtered values.
6976      * @see _.without, _.xor
6977      * @example
6978      *
6979      * _.difference([2, 1], [2, 3]);
6980      * // => [1]
6981      */
6982     var difference = baseRest(function(array, values) {
6983       return isArrayLikeObject(array)
6984         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
6985         : [];
6986     });
6987
6988     /**
6989      * This method is like `_.difference` except that it accepts `iteratee` which
6990      * is invoked for each element of `array` and `values` to generate the criterion
6991      * by which they're compared. The order and references of result values are
6992      * determined by the first array. The iteratee is invoked with one argument:
6993      * (value).
6994      *
6995      * **Note:** Unlike `_.pullAllBy`, this method returns a new array.
6996      *
6997      * @static
6998      * @memberOf _
6999      * @since 4.0.0
7000      * @category Array
7001      * @param {Array} array The array to inspect.
7002      * @param {...Array} [values] The values to exclude.
7003      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7004      * @returns {Array} Returns the new array of filtered values.
7005      * @example
7006      *
7007      * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
7008      * // => [1.2]
7009      *
7010      * // The `_.property` iteratee shorthand.
7011      * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
7012      * // => [{ 'x': 2 }]
7013      */
7014     var differenceBy = baseRest(function(array, values) {
7015       var iteratee = last(values);
7016       if (isArrayLikeObject(iteratee)) {
7017         iteratee = undefined;
7018       }
7019       return isArrayLikeObject(array)
7020         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2))
7021         : [];
7022     });
7023
7024     /**
7025      * This method is like `_.difference` except that it accepts `comparator`
7026      * which is invoked to compare elements of `array` to `values`. The order and
7027      * references of result values are determined by the first array. The comparator
7028      * is invoked with two arguments: (arrVal, othVal).
7029      *
7030      * **Note:** Unlike `_.pullAllWith`, this method returns a new array.
7031      *
7032      * @static
7033      * @memberOf _
7034      * @since 4.0.0
7035      * @category Array
7036      * @param {Array} array The array to inspect.
7037      * @param {...Array} [values] The values to exclude.
7038      * @param {Function} [comparator] The comparator invoked per element.
7039      * @returns {Array} Returns the new array of filtered values.
7040      * @example
7041      *
7042      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
7043      *
7044      * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
7045      * // => [{ 'x': 2, 'y': 1 }]
7046      */
7047     var differenceWith = baseRest(function(array, values) {
7048       var comparator = last(values);
7049       if (isArrayLikeObject(comparator)) {
7050         comparator = undefined;
7051       }
7052       return isArrayLikeObject(array)
7053         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
7054         : [];
7055     });
7056
7057     /**
7058      * Creates a slice of `array` with `n` elements dropped from the beginning.
7059      *
7060      * @static
7061      * @memberOf _
7062      * @since 0.5.0
7063      * @category Array
7064      * @param {Array} array The array to query.
7065      * @param {number} [n=1] The number of elements to drop.
7066      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
7067      * @returns {Array} Returns the slice of `array`.
7068      * @example
7069      *
7070      * _.drop([1, 2, 3]);
7071      * // => [2, 3]
7072      *
7073      * _.drop([1, 2, 3], 2);
7074      * // => [3]
7075      *
7076      * _.drop([1, 2, 3], 5);
7077      * // => []
7078      *
7079      * _.drop([1, 2, 3], 0);
7080      * // => [1, 2, 3]
7081      */
7082     function drop(array, n, guard) {
7083       var length = array == null ? 0 : array.length;
7084       if (!length) {
7085         return [];
7086       }
7087       n = (guard || n === undefined) ? 1 : toInteger(n);
7088       return baseSlice(array, n < 0 ? 0 : n, length);
7089     }
7090
7091     /**
7092      * Creates a slice of `array` with `n` elements dropped from the end.
7093      *
7094      * @static
7095      * @memberOf _
7096      * @since 3.0.0
7097      * @category Array
7098      * @param {Array} array The array to query.
7099      * @param {number} [n=1] The number of elements to drop.
7100      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
7101      * @returns {Array} Returns the slice of `array`.
7102      * @example
7103      *
7104      * _.dropRight([1, 2, 3]);
7105      * // => [1, 2]
7106      *
7107      * _.dropRight([1, 2, 3], 2);
7108      * // => [1]
7109      *
7110      * _.dropRight([1, 2, 3], 5);
7111      * // => []
7112      *
7113      * _.dropRight([1, 2, 3], 0);
7114      * // => [1, 2, 3]
7115      */
7116     function dropRight(array, n, guard) {
7117       var length = array == null ? 0 : array.length;
7118       if (!length) {
7119         return [];
7120       }
7121       n = (guard || n === undefined) ? 1 : toInteger(n);
7122       n = length - n;
7123       return baseSlice(array, 0, n < 0 ? 0 : n);
7124     }
7125
7126     /**
7127      * Creates a slice of `array` excluding elements dropped from the end.
7128      * Elements are dropped until `predicate` returns falsey. The predicate is
7129      * invoked with three arguments: (value, index, array).
7130      *
7131      * @static
7132      * @memberOf _
7133      * @since 3.0.0
7134      * @category Array
7135      * @param {Array} array The array to query.
7136      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7137      * @returns {Array} Returns the slice of `array`.
7138      * @example
7139      *
7140      * var users = [
7141      *   { 'user': 'barney',  'active': true },
7142      *   { 'user': 'fred',    'active': false },
7143      *   { 'user': 'pebbles', 'active': false }
7144      * ];
7145      *
7146      * _.dropRightWhile(users, function(o) { return !o.active; });
7147      * // => objects for ['barney']
7148      *
7149      * // The `_.matches` iteratee shorthand.
7150      * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
7151      * // => objects for ['barney', 'fred']
7152      *
7153      * // The `_.matchesProperty` iteratee shorthand.
7154      * _.dropRightWhile(users, ['active', false]);
7155      * // => objects for ['barney']
7156      *
7157      * // The `_.property` iteratee shorthand.
7158      * _.dropRightWhile(users, 'active');
7159      * // => objects for ['barney', 'fred', 'pebbles']
7160      */
7161     function dropRightWhile(array, predicate) {
7162       return (array && array.length)
7163         ? baseWhile(array, getIteratee(predicate, 3), true, true)
7164         : [];
7165     }
7166
7167     /**
7168      * Creates a slice of `array` excluding elements dropped from the beginning.
7169      * Elements are dropped until `predicate` returns falsey. The predicate is
7170      * invoked with three arguments: (value, index, array).
7171      *
7172      * @static
7173      * @memberOf _
7174      * @since 3.0.0
7175      * @category Array
7176      * @param {Array} array The array to query.
7177      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7178      * @returns {Array} Returns the slice of `array`.
7179      * @example
7180      *
7181      * var users = [
7182      *   { 'user': 'barney',  'active': false },
7183      *   { 'user': 'fred',    'active': false },
7184      *   { 'user': 'pebbles', 'active': true }
7185      * ];
7186      *
7187      * _.dropWhile(users, function(o) { return !o.active; });
7188      * // => objects for ['pebbles']
7189      *
7190      * // The `_.matches` iteratee shorthand.
7191      * _.dropWhile(users, { 'user': 'barney', 'active': false });
7192      * // => objects for ['fred', 'pebbles']
7193      *
7194      * // The `_.matchesProperty` iteratee shorthand.
7195      * _.dropWhile(users, ['active', false]);
7196      * // => objects for ['pebbles']
7197      *
7198      * // The `_.property` iteratee shorthand.
7199      * _.dropWhile(users, 'active');
7200      * // => objects for ['barney', 'fred', 'pebbles']
7201      */
7202     function dropWhile(array, predicate) {
7203       return (array && array.length)
7204         ? baseWhile(array, getIteratee(predicate, 3), true)
7205         : [];
7206     }
7207
7208     /**
7209      * Fills elements of `array` with `value` from `start` up to, but not
7210      * including, `end`.
7211      *
7212      * **Note:** This method mutates `array`.
7213      *
7214      * @static
7215      * @memberOf _
7216      * @since 3.2.0
7217      * @category Array
7218      * @param {Array} array The array to fill.
7219      * @param {*} value The value to fill `array` with.
7220      * @param {number} [start=0] The start position.
7221      * @param {number} [end=array.length] The end position.
7222      * @returns {Array} Returns `array`.
7223      * @example
7224      *
7225      * var array = [1, 2, 3];
7226      *
7227      * _.fill(array, 'a');
7228      * console.log(array);
7229      * // => ['a', 'a', 'a']
7230      *
7231      * _.fill(Array(3), 2);
7232      * // => [2, 2, 2]
7233      *
7234      * _.fill([4, 6, 8, 10], '*', 1, 3);
7235      * // => [4, '*', '*', 10]
7236      */
7237     function fill(array, value, start, end) {
7238       var length = array == null ? 0 : array.length;
7239       if (!length) {
7240         return [];
7241       }
7242       if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
7243         start = 0;
7244         end = length;
7245       }
7246       return baseFill(array, value, start, end);
7247     }
7248
7249     /**
7250      * This method is like `_.find` except that it returns the index of the first
7251      * element `predicate` returns truthy for instead of the element itself.
7252      *
7253      * @static
7254      * @memberOf _
7255      * @since 1.1.0
7256      * @category Array
7257      * @param {Array} array The array to inspect.
7258      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7259      * @param {number} [fromIndex=0] The index to search from.
7260      * @returns {number} Returns the index of the found element, else `-1`.
7261      * @example
7262      *
7263      * var users = [
7264      *   { 'user': 'barney',  'active': false },
7265      *   { 'user': 'fred',    'active': false },
7266      *   { 'user': 'pebbles', 'active': true }
7267      * ];
7268      *
7269      * _.findIndex(users, function(o) { return o.user == 'barney'; });
7270      * // => 0
7271      *
7272      * // The `_.matches` iteratee shorthand.
7273      * _.findIndex(users, { 'user': 'fred', 'active': false });
7274      * // => 1
7275      *
7276      * // The `_.matchesProperty` iteratee shorthand.
7277      * _.findIndex(users, ['active', false]);
7278      * // => 0
7279      *
7280      * // The `_.property` iteratee shorthand.
7281      * _.findIndex(users, 'active');
7282      * // => 2
7283      */
7284     function findIndex(array, predicate, fromIndex) {
7285       var length = array == null ? 0 : array.length;
7286       if (!length) {
7287         return -1;
7288       }
7289       var index = fromIndex == null ? 0 : toInteger(fromIndex);
7290       if (index < 0) {
7291         index = nativeMax(length + index, 0);
7292       }
7293       return baseFindIndex(array, getIteratee(predicate, 3), index);
7294     }
7295
7296     /**
7297      * This method is like `_.findIndex` except that it iterates over elements
7298      * of `collection` from right to left.
7299      *
7300      * @static
7301      * @memberOf _
7302      * @since 2.0.0
7303      * @category Array
7304      * @param {Array} array The array to inspect.
7305      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7306      * @param {number} [fromIndex=array.length-1] The index to search from.
7307      * @returns {number} Returns the index of the found element, else `-1`.
7308      * @example
7309      *
7310      * var users = [
7311      *   { 'user': 'barney',  'active': true },
7312      *   { 'user': 'fred',    'active': false },
7313      *   { 'user': 'pebbles', 'active': false }
7314      * ];
7315      *
7316      * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
7317      * // => 2
7318      *
7319      * // The `_.matches` iteratee shorthand.
7320      * _.findLastIndex(users, { 'user': 'barney', 'active': true });
7321      * // => 0
7322      *
7323      * // The `_.matchesProperty` iteratee shorthand.
7324      * _.findLastIndex(users, ['active', false]);
7325      * // => 2
7326      *
7327      * // The `_.property` iteratee shorthand.
7328      * _.findLastIndex(users, 'active');
7329      * // => 0
7330      */
7331     function findLastIndex(array, predicate, fromIndex) {
7332       var length = array == null ? 0 : array.length;
7333       if (!length) {
7334         return -1;
7335       }
7336       var index = length - 1;
7337       if (fromIndex !== undefined) {
7338         index = toInteger(fromIndex);
7339         index = fromIndex < 0
7340           ? nativeMax(length + index, 0)
7341           : nativeMin(index, length - 1);
7342       }
7343       return baseFindIndex(array, getIteratee(predicate, 3), index, true);
7344     }
7345
7346     /**
7347      * Flattens `array` a single level deep.
7348      *
7349      * @static
7350      * @memberOf _
7351      * @since 0.1.0
7352      * @category Array
7353      * @param {Array} array The array to flatten.
7354      * @returns {Array} Returns the new flattened array.
7355      * @example
7356      *
7357      * _.flatten([1, [2, [3, [4]], 5]]);
7358      * // => [1, 2, [3, [4]], 5]
7359      */
7360     function flatten(array) {
7361       var length = array == null ? 0 : array.length;
7362       return length ? baseFlatten(array, 1) : [];
7363     }
7364
7365     /**
7366      * Recursively flattens `array`.
7367      *
7368      * @static
7369      * @memberOf _
7370      * @since 3.0.0
7371      * @category Array
7372      * @param {Array} array The array to flatten.
7373      * @returns {Array} Returns the new flattened array.
7374      * @example
7375      *
7376      * _.flattenDeep([1, [2, [3, [4]], 5]]);
7377      * // => [1, 2, 3, 4, 5]
7378      */
7379     function flattenDeep(array) {
7380       var length = array == null ? 0 : array.length;
7381       return length ? baseFlatten(array, INFINITY) : [];
7382     }
7383
7384     /**
7385      * Recursively flatten `array` up to `depth` times.
7386      *
7387      * @static
7388      * @memberOf _
7389      * @since 4.4.0
7390      * @category Array
7391      * @param {Array} array The array to flatten.
7392      * @param {number} [depth=1] The maximum recursion depth.
7393      * @returns {Array} Returns the new flattened array.
7394      * @example
7395      *
7396      * var array = [1, [2, [3, [4]], 5]];
7397      *
7398      * _.flattenDepth(array, 1);
7399      * // => [1, 2, [3, [4]], 5]
7400      *
7401      * _.flattenDepth(array, 2);
7402      * // => [1, 2, 3, [4], 5]
7403      */
7404     function flattenDepth(array, depth) {
7405       var length = array == null ? 0 : array.length;
7406       if (!length) {
7407         return [];
7408       }
7409       depth = depth === undefined ? 1 : toInteger(depth);
7410       return baseFlatten(array, depth);
7411     }
7412
7413     /**
7414      * The inverse of `_.toPairs`; this method returns an object composed
7415      * from key-value `pairs`.
7416      *
7417      * @static
7418      * @memberOf _
7419      * @since 4.0.0
7420      * @category Array
7421      * @param {Array} pairs The key-value pairs.
7422      * @returns {Object} Returns the new object.
7423      * @example
7424      *
7425      * _.fromPairs([['a', 1], ['b', 2]]);
7426      * // => { 'a': 1, 'b': 2 }
7427      */
7428     function fromPairs(pairs) {
7429       var index = -1,
7430           length = pairs == null ? 0 : pairs.length,
7431           result = {};
7432
7433       while (++index < length) {
7434         var pair = pairs[index];
7435         result[pair[0]] = pair[1];
7436       }
7437       return result;
7438     }
7439
7440     /**
7441      * Gets the first element of `array`.
7442      *
7443      * @static
7444      * @memberOf _
7445      * @since 0.1.0
7446      * @alias first
7447      * @category Array
7448      * @param {Array} array The array to query.
7449      * @returns {*} Returns the first element of `array`.
7450      * @example
7451      *
7452      * _.head([1, 2, 3]);
7453      * // => 1
7454      *
7455      * _.head([]);
7456      * // => undefined
7457      */
7458     function head(array) {
7459       return (array && array.length) ? array[0] : undefined;
7460     }
7461
7462     /**
7463      * Gets the index at which the first occurrence of `value` is found in `array`
7464      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7465      * for equality comparisons. If `fromIndex` is negative, it's used as the
7466      * offset from the end of `array`.
7467      *
7468      * @static
7469      * @memberOf _
7470      * @since 0.1.0
7471      * @category Array
7472      * @param {Array} array The array to inspect.
7473      * @param {*} value The value to search for.
7474      * @param {number} [fromIndex=0] The index to search from.
7475      * @returns {number} Returns the index of the matched value, else `-1`.
7476      * @example
7477      *
7478      * _.indexOf([1, 2, 1, 2], 2);
7479      * // => 1
7480      *
7481      * // Search from the `fromIndex`.
7482      * _.indexOf([1, 2, 1, 2], 2, 2);
7483      * // => 3
7484      */
7485     function indexOf(array, value, fromIndex) {
7486       var length = array == null ? 0 : array.length;
7487       if (!length) {
7488         return -1;
7489       }
7490       var index = fromIndex == null ? 0 : toInteger(fromIndex);
7491       if (index < 0) {
7492         index = nativeMax(length + index, 0);
7493       }
7494       return baseIndexOf(array, value, index);
7495     }
7496
7497     /**
7498      * Gets all but the last element of `array`.
7499      *
7500      * @static
7501      * @memberOf _
7502      * @since 0.1.0
7503      * @category Array
7504      * @param {Array} array The array to query.
7505      * @returns {Array} Returns the slice of `array`.
7506      * @example
7507      *
7508      * _.initial([1, 2, 3]);
7509      * // => [1, 2]
7510      */
7511     function initial(array) {
7512       var length = array == null ? 0 : array.length;
7513       return length ? baseSlice(array, 0, -1) : [];
7514     }
7515
7516     /**
7517      * Creates an array of unique values that are included in all given arrays
7518      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7519      * for equality comparisons. The order and references of result values are
7520      * determined by the first array.
7521      *
7522      * @static
7523      * @memberOf _
7524      * @since 0.1.0
7525      * @category Array
7526      * @param {...Array} [arrays] The arrays to inspect.
7527      * @returns {Array} Returns the new array of intersecting values.
7528      * @example
7529      *
7530      * _.intersection([2, 1], [2, 3]);
7531      * // => [2]
7532      */
7533     var intersection = baseRest(function(arrays) {
7534       var mapped = arrayMap(arrays, castArrayLikeObject);
7535       return (mapped.length && mapped[0] === arrays[0])
7536         ? baseIntersection(mapped)
7537         : [];
7538     });
7539
7540     /**
7541      * This method is like `_.intersection` except that it accepts `iteratee`
7542      * which is invoked for each element of each `arrays` to generate the criterion
7543      * by which they're compared. The order and references of result values are
7544      * determined by the first array. The iteratee is invoked with one argument:
7545      * (value).
7546      *
7547      * @static
7548      * @memberOf _
7549      * @since 4.0.0
7550      * @category Array
7551      * @param {...Array} [arrays] The arrays to inspect.
7552      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7553      * @returns {Array} Returns the new array of intersecting values.
7554      * @example
7555      *
7556      * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
7557      * // => [2.1]
7558      *
7559      * // The `_.property` iteratee shorthand.
7560      * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
7561      * // => [{ 'x': 1 }]
7562      */
7563     var intersectionBy = baseRest(function(arrays) {
7564       var iteratee = last(arrays),
7565           mapped = arrayMap(arrays, castArrayLikeObject);
7566
7567       if (iteratee === last(mapped)) {
7568         iteratee = undefined;
7569       } else {
7570         mapped.pop();
7571       }
7572       return (mapped.length && mapped[0] === arrays[0])
7573         ? baseIntersection(mapped, getIteratee(iteratee, 2))
7574         : [];
7575     });
7576
7577     /**
7578      * This method is like `_.intersection` except that it accepts `comparator`
7579      * which is invoked to compare elements of `arrays`. The order and references
7580      * of result values are determined by the first array. The comparator is
7581      * invoked with two arguments: (arrVal, othVal).
7582      *
7583      * @static
7584      * @memberOf _
7585      * @since 4.0.0
7586      * @category Array
7587      * @param {...Array} [arrays] The arrays to inspect.
7588      * @param {Function} [comparator] The comparator invoked per element.
7589      * @returns {Array} Returns the new array of intersecting values.
7590      * @example
7591      *
7592      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
7593      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
7594      *
7595      * _.intersectionWith(objects, others, _.isEqual);
7596      * // => [{ 'x': 1, 'y': 2 }]
7597      */
7598     var intersectionWith = baseRest(function(arrays) {
7599       var comparator = last(arrays),
7600           mapped = arrayMap(arrays, castArrayLikeObject);
7601
7602       comparator = typeof comparator == 'function' ? comparator : undefined;
7603       if (comparator) {
7604         mapped.pop();
7605       }
7606       return (mapped.length && mapped[0] === arrays[0])
7607         ? baseIntersection(mapped, undefined, comparator)
7608         : [];
7609     });
7610
7611     /**
7612      * Converts all elements in `array` into a string separated by `separator`.
7613      *
7614      * @static
7615      * @memberOf _
7616      * @since 4.0.0
7617      * @category Array
7618      * @param {Array} array The array to convert.
7619      * @param {string} [separator=','] The element separator.
7620      * @returns {string} Returns the joined string.
7621      * @example
7622      *
7623      * _.join(['a', 'b', 'c'], '~');
7624      * // => 'a~b~c'
7625      */
7626     function join(array, separator) {
7627       return array == null ? '' : nativeJoin.call(array, separator);
7628     }
7629
7630     /**
7631      * Gets the last element of `array`.
7632      *
7633      * @static
7634      * @memberOf _
7635      * @since 0.1.0
7636      * @category Array
7637      * @param {Array} array The array to query.
7638      * @returns {*} Returns the last element of `array`.
7639      * @example
7640      *
7641      * _.last([1, 2, 3]);
7642      * // => 3
7643      */
7644     function last(array) {
7645       var length = array == null ? 0 : array.length;
7646       return length ? array[length - 1] : undefined;
7647     }
7648
7649     /**
7650      * This method is like `_.indexOf` except that it iterates over elements of
7651      * `array` from right to left.
7652      *
7653      * @static
7654      * @memberOf _
7655      * @since 0.1.0
7656      * @category Array
7657      * @param {Array} array The array to inspect.
7658      * @param {*} value The value to search for.
7659      * @param {number} [fromIndex=array.length-1] The index to search from.
7660      * @returns {number} Returns the index of the matched value, else `-1`.
7661      * @example
7662      *
7663      * _.lastIndexOf([1, 2, 1, 2], 2);
7664      * // => 3
7665      *
7666      * // Search from the `fromIndex`.
7667      * _.lastIndexOf([1, 2, 1, 2], 2, 2);
7668      * // => 1
7669      */
7670     function lastIndexOf(array, value, fromIndex) {
7671       var length = array == null ? 0 : array.length;
7672       if (!length) {
7673         return -1;
7674       }
7675       var index = length;
7676       if (fromIndex !== undefined) {
7677         index = toInteger(fromIndex);
7678         index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
7679       }
7680       return value === value
7681         ? strictLastIndexOf(array, value, index)
7682         : baseFindIndex(array, baseIsNaN, index, true);
7683     }
7684
7685     /**
7686      * Gets the element at index `n` of `array`. If `n` is negative, the nth
7687      * element from the end is returned.
7688      *
7689      * @static
7690      * @memberOf _
7691      * @since 4.11.0
7692      * @category Array
7693      * @param {Array} array The array to query.
7694      * @param {number} [n=0] The index of the element to return.
7695      * @returns {*} Returns the nth element of `array`.
7696      * @example
7697      *
7698      * var array = ['a', 'b', 'c', 'd'];
7699      *
7700      * _.nth(array, 1);
7701      * // => 'b'
7702      *
7703      * _.nth(array, -2);
7704      * // => 'c';
7705      */
7706     function nth(array, n) {
7707       return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;
7708     }
7709
7710     /**
7711      * Removes all given values from `array` using
7712      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7713      * for equality comparisons.
7714      *
7715      * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
7716      * to remove elements from an array by predicate.
7717      *
7718      * @static
7719      * @memberOf _
7720      * @since 2.0.0
7721      * @category Array
7722      * @param {Array} array The array to modify.
7723      * @param {...*} [values] The values to remove.
7724      * @returns {Array} Returns `array`.
7725      * @example
7726      *
7727      * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
7728      *
7729      * _.pull(array, 'a', 'c');
7730      * console.log(array);
7731      * // => ['b', 'b']
7732      */
7733     var pull = baseRest(pullAll);
7734
7735     /**
7736      * This method is like `_.pull` except that it accepts an array of values to remove.
7737      *
7738      * **Note:** Unlike `_.difference`, this method mutates `array`.
7739      *
7740      * @static
7741      * @memberOf _
7742      * @since 4.0.0
7743      * @category Array
7744      * @param {Array} array The array to modify.
7745      * @param {Array} values The values to remove.
7746      * @returns {Array} Returns `array`.
7747      * @example
7748      *
7749      * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
7750      *
7751      * _.pullAll(array, ['a', 'c']);
7752      * console.log(array);
7753      * // => ['b', 'b']
7754      */
7755     function pullAll(array, values) {
7756       return (array && array.length && values && values.length)
7757         ? basePullAll(array, values)
7758         : array;
7759     }
7760
7761     /**
7762      * This method is like `_.pullAll` except that it accepts `iteratee` which is
7763      * invoked for each element of `array` and `values` to generate the criterion
7764      * by which they're compared. The iteratee is invoked with one argument: (value).
7765      *
7766      * **Note:** Unlike `_.differenceBy`, this method mutates `array`.
7767      *
7768      * @static
7769      * @memberOf _
7770      * @since 4.0.0
7771      * @category Array
7772      * @param {Array} array The array to modify.
7773      * @param {Array} values The values to remove.
7774      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7775      * @returns {Array} Returns `array`.
7776      * @example
7777      *
7778      * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
7779      *
7780      * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
7781      * console.log(array);
7782      * // => [{ 'x': 2 }]
7783      */
7784     function pullAllBy(array, values, iteratee) {
7785       return (array && array.length && values && values.length)
7786         ? basePullAll(array, values, getIteratee(iteratee, 2))
7787         : array;
7788     }
7789
7790     /**
7791      * This method is like `_.pullAll` except that it accepts `comparator` which
7792      * is invoked to compare elements of `array` to `values`. The comparator is
7793      * invoked with two arguments: (arrVal, othVal).
7794      *
7795      * **Note:** Unlike `_.differenceWith`, this method mutates `array`.
7796      *
7797      * @static
7798      * @memberOf _
7799      * @since 4.6.0
7800      * @category Array
7801      * @param {Array} array The array to modify.
7802      * @param {Array} values The values to remove.
7803      * @param {Function} [comparator] The comparator invoked per element.
7804      * @returns {Array} Returns `array`.
7805      * @example
7806      *
7807      * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
7808      *
7809      * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
7810      * console.log(array);
7811      * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
7812      */
7813     function pullAllWith(array, values, comparator) {
7814       return (array && array.length && values && values.length)
7815         ? basePullAll(array, values, undefined, comparator)
7816         : array;
7817     }
7818
7819     /**
7820      * Removes elements from `array` corresponding to `indexes` and returns an
7821      * array of removed elements.
7822      *
7823      * **Note:** Unlike `_.at`, this method mutates `array`.
7824      *
7825      * @static
7826      * @memberOf _
7827      * @since 3.0.0
7828      * @category Array
7829      * @param {Array} array The array to modify.
7830      * @param {...(number|number[])} [indexes] The indexes of elements to remove.
7831      * @returns {Array} Returns the new array of removed elements.
7832      * @example
7833      *
7834      * var array = ['a', 'b', 'c', 'd'];
7835      * var pulled = _.pullAt(array, [1, 3]);
7836      *
7837      * console.log(array);
7838      * // => ['a', 'c']
7839      *
7840      * console.log(pulled);
7841      * // => ['b', 'd']
7842      */
7843     var pullAt = flatRest(function(array, indexes) {
7844       var length = array == null ? 0 : array.length,
7845           result = baseAt(array, indexes);
7846
7847       basePullAt(array, arrayMap(indexes, function(index) {
7848         return isIndex(index, length) ? +index : index;
7849       }).sort(compareAscending));
7850
7851       return result;
7852     });
7853
7854     /**
7855      * Removes all elements from `array` that `predicate` returns truthy for
7856      * and returns an array of the removed elements. The predicate is invoked
7857      * with three arguments: (value, index, array).
7858      *
7859      * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
7860      * to pull elements from an array by value.
7861      *
7862      * @static
7863      * @memberOf _
7864      * @since 2.0.0
7865      * @category Array
7866      * @param {Array} array The array to modify.
7867      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7868      * @returns {Array} Returns the new array of removed elements.
7869      * @example
7870      *
7871      * var array = [1, 2, 3, 4];
7872      * var evens = _.remove(array, function(n) {
7873      *   return n % 2 == 0;
7874      * });
7875      *
7876      * console.log(array);
7877      * // => [1, 3]
7878      *
7879      * console.log(evens);
7880      * // => [2, 4]
7881      */
7882     function remove(array, predicate) {
7883       var result = [];
7884       if (!(array && array.length)) {
7885         return result;
7886       }
7887       var index = -1,
7888           indexes = [],
7889           length = array.length;
7890
7891       predicate = getIteratee(predicate, 3);
7892       while (++index < length) {
7893         var value = array[index];
7894         if (predicate(value, index, array)) {
7895           result.push(value);
7896           indexes.push(index);
7897         }
7898       }
7899       basePullAt(array, indexes);
7900       return result;
7901     }
7902
7903     /**
7904      * Reverses `array` so that the first element becomes the last, the second
7905      * element becomes the second to last, and so on.
7906      *
7907      * **Note:** This method mutates `array` and is based on
7908      * [`Array#reverse`](https://mdn.io/Array/reverse).
7909      *
7910      * @static
7911      * @memberOf _
7912      * @since 4.0.0
7913      * @category Array
7914      * @param {Array} array The array to modify.
7915      * @returns {Array} Returns `array`.
7916      * @example
7917      *
7918      * var array = [1, 2, 3];
7919      *
7920      * _.reverse(array);
7921      * // => [3, 2, 1]
7922      *
7923      * console.log(array);
7924      * // => [3, 2, 1]
7925      */
7926     function reverse(array) {
7927       return array == null ? array : nativeReverse.call(array);
7928     }
7929
7930     /**
7931      * Creates a slice of `array` from `start` up to, but not including, `end`.
7932      *
7933      * **Note:** This method is used instead of
7934      * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
7935      * returned.
7936      *
7937      * @static
7938      * @memberOf _
7939      * @since 3.0.0
7940      * @category Array
7941      * @param {Array} array The array to slice.
7942      * @param {number} [start=0] The start position.
7943      * @param {number} [end=array.length] The end position.
7944      * @returns {Array} Returns the slice of `array`.
7945      */
7946     function slice(array, start, end) {
7947       var length = array == null ? 0 : array.length;
7948       if (!length) {
7949         return [];
7950       }
7951       if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
7952         start = 0;
7953         end = length;
7954       }
7955       else {
7956         start = start == null ? 0 : toInteger(start);
7957         end = end === undefined ? length : toInteger(end);
7958       }
7959       return baseSlice(array, start, end);
7960     }
7961
7962     /**
7963      * Uses a binary search to determine the lowest index at which `value`
7964      * should be inserted into `array` in order to maintain its sort order.
7965      *
7966      * @static
7967      * @memberOf _
7968      * @since 0.1.0
7969      * @category Array
7970      * @param {Array} array The sorted array to inspect.
7971      * @param {*} value The value to evaluate.
7972      * @returns {number} Returns the index at which `value` should be inserted
7973      *  into `array`.
7974      * @example
7975      *
7976      * _.sortedIndex([30, 50], 40);
7977      * // => 1
7978      */
7979     function sortedIndex(array, value) {
7980       return baseSortedIndex(array, value);
7981     }
7982
7983     /**
7984      * This method is like `_.sortedIndex` except that it accepts `iteratee`
7985      * which is invoked for `value` and each element of `array` to compute their
7986      * sort ranking. The iteratee is invoked with one argument: (value).
7987      *
7988      * @static
7989      * @memberOf _
7990      * @since 4.0.0
7991      * @category Array
7992      * @param {Array} array The sorted array to inspect.
7993      * @param {*} value The value to evaluate.
7994      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7995      * @returns {number} Returns the index at which `value` should be inserted
7996      *  into `array`.
7997      * @example
7998      *
7999      * var objects = [{ 'x': 4 }, { 'x': 5 }];
8000      *
8001      * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
8002      * // => 0
8003      *
8004      * // The `_.property` iteratee shorthand.
8005      * _.sortedIndexBy(objects, { 'x': 4 }, 'x');
8006      * // => 0
8007      */
8008     function sortedIndexBy(array, value, iteratee) {
8009       return baseSortedIndexBy(array, value, getIteratee(iteratee, 2));
8010     }
8011
8012     /**
8013      * This method is like `_.indexOf` except that it performs a binary
8014      * search on a sorted `array`.
8015      *
8016      * @static
8017      * @memberOf _
8018      * @since 4.0.0
8019      * @category Array
8020      * @param {Array} array The array to inspect.
8021      * @param {*} value The value to search for.
8022      * @returns {number} Returns the index of the matched value, else `-1`.
8023      * @example
8024      *
8025      * _.sortedIndexOf([4, 5, 5, 5, 6], 5);
8026      * // => 1
8027      */
8028     function sortedIndexOf(array, value) {
8029       var length = array == null ? 0 : array.length;
8030       if (length) {
8031         var index = baseSortedIndex(array, value);
8032         if (index < length && eq(array[index], value)) {
8033           return index;
8034         }
8035       }
8036       return -1;
8037     }
8038
8039     /**
8040      * This method is like `_.sortedIndex` except that it returns the highest
8041      * index at which `value` should be inserted into `array` in order to
8042      * maintain its sort order.
8043      *
8044      * @static
8045      * @memberOf _
8046      * @since 3.0.0
8047      * @category Array
8048      * @param {Array} array The sorted array to inspect.
8049      * @param {*} value The value to evaluate.
8050      * @returns {number} Returns the index at which `value` should be inserted
8051      *  into `array`.
8052      * @example
8053      *
8054      * _.sortedLastIndex([4, 5, 5, 5, 6], 5);
8055      * // => 4
8056      */
8057     function sortedLastIndex(array, value) {
8058       return baseSortedIndex(array, value, true);
8059     }
8060
8061     /**
8062      * This method is like `_.sortedLastIndex` except that it accepts `iteratee`
8063      * which is invoked for `value` and each element of `array` to compute their
8064      * sort ranking. The iteratee is invoked with one argument: (value).
8065      *
8066      * @static
8067      * @memberOf _
8068      * @since 4.0.0
8069      * @category Array
8070      * @param {Array} array The sorted array to inspect.
8071      * @param {*} value The value to evaluate.
8072      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8073      * @returns {number} Returns the index at which `value` should be inserted
8074      *  into `array`.
8075      * @example
8076      *
8077      * var objects = [{ 'x': 4 }, { 'x': 5 }];
8078      *
8079      * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
8080      * // => 1
8081      *
8082      * // The `_.property` iteratee shorthand.
8083      * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
8084      * // => 1
8085      */
8086     function sortedLastIndexBy(array, value, iteratee) {
8087       return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true);
8088     }
8089
8090     /**
8091      * This method is like `_.lastIndexOf` except that it performs a binary
8092      * search on a sorted `array`.
8093      *
8094      * @static
8095      * @memberOf _
8096      * @since 4.0.0
8097      * @category Array
8098      * @param {Array} array The array to inspect.
8099      * @param {*} value The value to search for.
8100      * @returns {number} Returns the index of the matched value, else `-1`.
8101      * @example
8102      *
8103      * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
8104      * // => 3
8105      */
8106     function sortedLastIndexOf(array, value) {
8107       var length = array == null ? 0 : array.length;
8108       if (length) {
8109         var index = baseSortedIndex(array, value, true) - 1;
8110         if (eq(array[index], value)) {
8111           return index;
8112         }
8113       }
8114       return -1;
8115     }
8116
8117     /**
8118      * This method is like `_.uniq` except that it's designed and optimized
8119      * for sorted arrays.
8120      *
8121      * @static
8122      * @memberOf _
8123      * @since 4.0.0
8124      * @category Array
8125      * @param {Array} array The array to inspect.
8126      * @returns {Array} Returns the new duplicate free array.
8127      * @example
8128      *
8129      * _.sortedUniq([1, 1, 2]);
8130      * // => [1, 2]
8131      */
8132     function sortedUniq(array) {
8133       return (array && array.length)
8134         ? baseSortedUniq(array)
8135         : [];
8136     }
8137
8138     /**
8139      * This method is like `_.uniqBy` except that it's designed and optimized
8140      * for sorted arrays.
8141      *
8142      * @static
8143      * @memberOf _
8144      * @since 4.0.0
8145      * @category Array
8146      * @param {Array} array The array to inspect.
8147      * @param {Function} [iteratee] The iteratee invoked per element.
8148      * @returns {Array} Returns the new duplicate free array.
8149      * @example
8150      *
8151      * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
8152      * // => [1.1, 2.3]
8153      */
8154     function sortedUniqBy(array, iteratee) {
8155       return (array && array.length)
8156         ? baseSortedUniq(array, getIteratee(iteratee, 2))
8157         : [];
8158     }
8159
8160     /**
8161      * Gets all but the first element of `array`.
8162      *
8163      * @static
8164      * @memberOf _
8165      * @since 4.0.0
8166      * @category Array
8167      * @param {Array} array The array to query.
8168      * @returns {Array} Returns the slice of `array`.
8169      * @example
8170      *
8171      * _.tail([1, 2, 3]);
8172      * // => [2, 3]
8173      */
8174     function tail(array) {
8175       var length = array == null ? 0 : array.length;
8176       return length ? baseSlice(array, 1, length) : [];
8177     }
8178
8179     /**
8180      * Creates a slice of `array` with `n` elements taken from the beginning.
8181      *
8182      * @static
8183      * @memberOf _
8184      * @since 0.1.0
8185      * @category Array
8186      * @param {Array} array The array to query.
8187      * @param {number} [n=1] The number of elements to take.
8188      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8189      * @returns {Array} Returns the slice of `array`.
8190      * @example
8191      *
8192      * _.take([1, 2, 3]);
8193      * // => [1]
8194      *
8195      * _.take([1, 2, 3], 2);
8196      * // => [1, 2]
8197      *
8198      * _.take([1, 2, 3], 5);
8199      * // => [1, 2, 3]
8200      *
8201      * _.take([1, 2, 3], 0);
8202      * // => []
8203      */
8204     function take(array, n, guard) {
8205       if (!(array && array.length)) {
8206         return [];
8207       }
8208       n = (guard || n === undefined) ? 1 : toInteger(n);
8209       return baseSlice(array, 0, n < 0 ? 0 : n);
8210     }
8211
8212     /**
8213      * Creates a slice of `array` with `n` elements taken from the end.
8214      *
8215      * @static
8216      * @memberOf _
8217      * @since 3.0.0
8218      * @category Array
8219      * @param {Array} array The array to query.
8220      * @param {number} [n=1] The number of elements to take.
8221      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8222      * @returns {Array} Returns the slice of `array`.
8223      * @example
8224      *
8225      * _.takeRight([1, 2, 3]);
8226      * // => [3]
8227      *
8228      * _.takeRight([1, 2, 3], 2);
8229      * // => [2, 3]
8230      *
8231      * _.takeRight([1, 2, 3], 5);
8232      * // => [1, 2, 3]
8233      *
8234      * _.takeRight([1, 2, 3], 0);
8235      * // => []
8236      */
8237     function takeRight(array, n, guard) {
8238       var length = array == null ? 0 : array.length;
8239       if (!length) {
8240         return [];
8241       }
8242       n = (guard || n === undefined) ? 1 : toInteger(n);
8243       n = length - n;
8244       return baseSlice(array, n < 0 ? 0 : n, length);
8245     }
8246
8247     /**
8248      * Creates a slice of `array` with elements taken from the end. Elements are
8249      * taken until `predicate` returns falsey. The predicate is invoked with
8250      * three arguments: (value, index, array).
8251      *
8252      * @static
8253      * @memberOf _
8254      * @since 3.0.0
8255      * @category Array
8256      * @param {Array} array The array to query.
8257      * @param {Function} [predicate=_.identity] The function invoked per iteration.
8258      * @returns {Array} Returns the slice of `array`.
8259      * @example
8260      *
8261      * var users = [
8262      *   { 'user': 'barney',  'active': true },
8263      *   { 'user': 'fred',    'active': false },
8264      *   { 'user': 'pebbles', 'active': false }
8265      * ];
8266      *
8267      * _.takeRightWhile(users, function(o) { return !o.active; });
8268      * // => objects for ['fred', 'pebbles']
8269      *
8270      * // The `_.matches` iteratee shorthand.
8271      * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
8272      * // => objects for ['pebbles']
8273      *
8274      * // The `_.matchesProperty` iteratee shorthand.
8275      * _.takeRightWhile(users, ['active', false]);
8276      * // => objects for ['fred', 'pebbles']
8277      *
8278      * // The `_.property` iteratee shorthand.
8279      * _.takeRightWhile(users, 'active');
8280      * // => []
8281      */
8282     function takeRightWhile(array, predicate) {
8283       return (array && array.length)
8284         ? baseWhile(array, getIteratee(predicate, 3), false, true)
8285         : [];
8286     }
8287
8288     /**
8289      * Creates a slice of `array` with elements taken from the beginning. Elements
8290      * are taken until `predicate` returns falsey. The predicate is invoked with
8291      * three arguments: (value, index, array).
8292      *
8293      * @static
8294      * @memberOf _
8295      * @since 3.0.0
8296      * @category Array
8297      * @param {Array} array The array to query.
8298      * @param {Function} [predicate=_.identity] The function invoked per iteration.
8299      * @returns {Array} Returns the slice of `array`.
8300      * @example
8301      *
8302      * var users = [
8303      *   { 'user': 'barney',  'active': false },
8304      *   { 'user': 'fred',    'active': false },
8305      *   { 'user': 'pebbles', 'active': true }
8306      * ];
8307      *
8308      * _.takeWhile(users, function(o) { return !o.active; });
8309      * // => objects for ['barney', 'fred']
8310      *
8311      * // The `_.matches` iteratee shorthand.
8312      * _.takeWhile(users, { 'user': 'barney', 'active': false });
8313      * // => objects for ['barney']
8314      *
8315      * // The `_.matchesProperty` iteratee shorthand.
8316      * _.takeWhile(users, ['active', false]);
8317      * // => objects for ['barney', 'fred']
8318      *
8319      * // The `_.property` iteratee shorthand.
8320      * _.takeWhile(users, 'active');
8321      * // => []
8322      */
8323     function takeWhile(array, predicate) {
8324       return (array && array.length)
8325         ? baseWhile(array, getIteratee(predicate, 3))
8326         : [];
8327     }
8328
8329     /**
8330      * Creates an array of unique values, in order, from all given arrays using
8331      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8332      * for equality comparisons.
8333      *
8334      * @static
8335      * @memberOf _
8336      * @since 0.1.0
8337      * @category Array
8338      * @param {...Array} [arrays] The arrays to inspect.
8339      * @returns {Array} Returns the new array of combined values.
8340      * @example
8341      *
8342      * _.union([2], [1, 2]);
8343      * // => [2, 1]
8344      */
8345     var union = baseRest(function(arrays) {
8346       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
8347     });
8348
8349     /**
8350      * This method is like `_.union` except that it accepts `iteratee` which is
8351      * invoked for each element of each `arrays` to generate the criterion by
8352      * which uniqueness is computed. Result values are chosen from the first
8353      * array in which the value occurs. The iteratee is invoked with one argument:
8354      * (value).
8355      *
8356      * @static
8357      * @memberOf _
8358      * @since 4.0.0
8359      * @category Array
8360      * @param {...Array} [arrays] The arrays to inspect.
8361      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8362      * @returns {Array} Returns the new array of combined values.
8363      * @example
8364      *
8365      * _.unionBy([2.1], [1.2, 2.3], Math.floor);
8366      * // => [2.1, 1.2]
8367      *
8368      * // The `_.property` iteratee shorthand.
8369      * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
8370      * // => [{ 'x': 1 }, { 'x': 2 }]
8371      */
8372     var unionBy = baseRest(function(arrays) {
8373       var iteratee = last(arrays);
8374       if (isArrayLikeObject(iteratee)) {
8375         iteratee = undefined;
8376       }
8377       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2));
8378     });
8379
8380     /**
8381      * This method is like `_.union` except that it accepts `comparator` which
8382      * is invoked to compare elements of `arrays`. Result values are chosen from
8383      * the first array in which the value occurs. The comparator is invoked
8384      * with two arguments: (arrVal, othVal).
8385      *
8386      * @static
8387      * @memberOf _
8388      * @since 4.0.0
8389      * @category Array
8390      * @param {...Array} [arrays] The arrays to inspect.
8391      * @param {Function} [comparator] The comparator invoked per element.
8392      * @returns {Array} Returns the new array of combined values.
8393      * @example
8394      *
8395      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
8396      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
8397      *
8398      * _.unionWith(objects, others, _.isEqual);
8399      * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
8400      */
8401     var unionWith = baseRest(function(arrays) {
8402       var comparator = last(arrays);
8403       comparator = typeof comparator == 'function' ? comparator : undefined;
8404       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
8405     });
8406
8407     /**
8408      * Creates a duplicate-free version of an array, using
8409      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8410      * for equality comparisons, in which only the first occurrence of each element
8411      * is kept. The order of result values is determined by the order they occur
8412      * in the array.
8413      *
8414      * @static
8415      * @memberOf _
8416      * @since 0.1.0
8417      * @category Array
8418      * @param {Array} array The array to inspect.
8419      * @returns {Array} Returns the new duplicate free array.
8420      * @example
8421      *
8422      * _.uniq([2, 1, 2]);
8423      * // => [2, 1]
8424      */
8425     function uniq(array) {
8426       return (array && array.length) ? baseUniq(array) : [];
8427     }
8428
8429     /**
8430      * This method is like `_.uniq` except that it accepts `iteratee` which is
8431      * invoked for each element in `array` to generate the criterion by which
8432      * uniqueness is computed. The order of result values is determined by the
8433      * order they occur in the array. The iteratee is invoked with one argument:
8434      * (value).
8435      *
8436      * @static
8437      * @memberOf _
8438      * @since 4.0.0
8439      * @category Array
8440      * @param {Array} array The array to inspect.
8441      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8442      * @returns {Array} Returns the new duplicate free array.
8443      * @example
8444      *
8445      * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
8446      * // => [2.1, 1.2]
8447      *
8448      * // The `_.property` iteratee shorthand.
8449      * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
8450      * // => [{ 'x': 1 }, { 'x': 2 }]
8451      */
8452     function uniqBy(array, iteratee) {
8453       return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : [];
8454     }
8455
8456     /**
8457      * This method is like `_.uniq` except that it accepts `comparator` which
8458      * is invoked to compare elements of `array`. The order of result values is
8459      * determined by the order they occur in the array.The comparator is invoked
8460      * with two arguments: (arrVal, othVal).
8461      *
8462      * @static
8463      * @memberOf _
8464      * @since 4.0.0
8465      * @category Array
8466      * @param {Array} array The array to inspect.
8467      * @param {Function} [comparator] The comparator invoked per element.
8468      * @returns {Array} Returns the new duplicate free array.
8469      * @example
8470      *
8471      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
8472      *
8473      * _.uniqWith(objects, _.isEqual);
8474      * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
8475      */
8476     function uniqWith(array, comparator) {
8477       comparator = typeof comparator == 'function' ? comparator : undefined;
8478       return (array && array.length) ? baseUniq(array, undefined, comparator) : [];
8479     }
8480
8481     /**
8482      * This method is like `_.zip` except that it accepts an array of grouped
8483      * elements and creates an array regrouping the elements to their pre-zip
8484      * configuration.
8485      *
8486      * @static
8487      * @memberOf _
8488      * @since 1.2.0
8489      * @category Array
8490      * @param {Array} array The array of grouped elements to process.
8491      * @returns {Array} Returns the new array of regrouped elements.
8492      * @example
8493      *
8494      * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
8495      * // => [['a', 1, true], ['b', 2, false]]
8496      *
8497      * _.unzip(zipped);
8498      * // => [['a', 'b'], [1, 2], [true, false]]
8499      */
8500     function unzip(array) {
8501       if (!(array && array.length)) {
8502         return [];
8503       }
8504       var length = 0;
8505       array = arrayFilter(array, function(group) {
8506         if (isArrayLikeObject(group)) {
8507           length = nativeMax(group.length, length);
8508           return true;
8509         }
8510       });
8511       return baseTimes(length, function(index) {
8512         return arrayMap(array, baseProperty(index));
8513       });
8514     }
8515
8516     /**
8517      * This method is like `_.unzip` except that it accepts `iteratee` to specify
8518      * how regrouped values should be combined. The iteratee is invoked with the
8519      * elements of each group: (...group).
8520      *
8521      * @static
8522      * @memberOf _
8523      * @since 3.8.0
8524      * @category Array
8525      * @param {Array} array The array of grouped elements to process.
8526      * @param {Function} [iteratee=_.identity] The function to combine
8527      *  regrouped values.
8528      * @returns {Array} Returns the new array of regrouped elements.
8529      * @example
8530      *
8531      * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
8532      * // => [[1, 10, 100], [2, 20, 200]]
8533      *
8534      * _.unzipWith(zipped, _.add);
8535      * // => [3, 30, 300]
8536      */
8537     function unzipWith(array, iteratee) {
8538       if (!(array && array.length)) {
8539         return [];
8540       }
8541       var result = unzip(array);
8542       if (iteratee == null) {
8543         return result;
8544       }
8545       return arrayMap(result, function(group) {
8546         return apply(iteratee, undefined, group);
8547       });
8548     }
8549
8550     /**
8551      * Creates an array excluding all given values using
8552      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8553      * for equality comparisons.
8554      *
8555      * **Note:** Unlike `_.pull`, this method returns a new array.
8556      *
8557      * @static
8558      * @memberOf _
8559      * @since 0.1.0
8560      * @category Array
8561      * @param {Array} array The array to inspect.
8562      * @param {...*} [values] The values to exclude.
8563      * @returns {Array} Returns the new array of filtered values.
8564      * @see _.difference, _.xor
8565      * @example
8566      *
8567      * _.without([2, 1, 2, 3], 1, 2);
8568      * // => [3]
8569      */
8570     var without = baseRest(function(array, values) {
8571       return isArrayLikeObject(array)
8572         ? baseDifference(array, values)
8573         : [];
8574     });
8575
8576     /**
8577      * Creates an array of unique values that is the
8578      * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
8579      * of the given arrays. The order of result values is determined by the order
8580      * they occur in the arrays.
8581      *
8582      * @static
8583      * @memberOf _
8584      * @since 2.4.0
8585      * @category Array
8586      * @param {...Array} [arrays] The arrays to inspect.
8587      * @returns {Array} Returns the new array of filtered values.
8588      * @see _.difference, _.without
8589      * @example
8590      *
8591      * _.xor([2, 1], [2, 3]);
8592      * // => [1, 3]
8593      */
8594     var xor = baseRest(function(arrays) {
8595       return baseXor(arrayFilter(arrays, isArrayLikeObject));
8596     });
8597
8598     /**
8599      * This method is like `_.xor` except that it accepts `iteratee` which is
8600      * invoked for each element of each `arrays` to generate the criterion by
8601      * which by which they're compared. The order of result values is determined
8602      * by the order they occur in the arrays. The iteratee is invoked with one
8603      * argument: (value).
8604      *
8605      * @static
8606      * @memberOf _
8607      * @since 4.0.0
8608      * @category Array
8609      * @param {...Array} [arrays] The arrays to inspect.
8610      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8611      * @returns {Array} Returns the new array of filtered values.
8612      * @example
8613      *
8614      * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
8615      * // => [1.2, 3.4]
8616      *
8617      * // The `_.property` iteratee shorthand.
8618      * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
8619      * // => [{ 'x': 2 }]
8620      */
8621     var xorBy = baseRest(function(arrays) {
8622       var iteratee = last(arrays);
8623       if (isArrayLikeObject(iteratee)) {
8624         iteratee = undefined;
8625       }
8626       return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2));
8627     });
8628
8629     /**
8630      * This method is like `_.xor` except that it accepts `comparator` which is
8631      * invoked to compare elements of `arrays`. The order of result values is
8632      * determined by the order they occur in the arrays. The comparator is invoked
8633      * with two arguments: (arrVal, othVal).
8634      *
8635      * @static
8636      * @memberOf _
8637      * @since 4.0.0
8638      * @category Array
8639      * @param {...Array} [arrays] The arrays to inspect.
8640      * @param {Function} [comparator] The comparator invoked per element.
8641      * @returns {Array} Returns the new array of filtered values.
8642      * @example
8643      *
8644      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
8645      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
8646      *
8647      * _.xorWith(objects, others, _.isEqual);
8648      * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
8649      */
8650     var xorWith = baseRest(function(arrays) {
8651       var comparator = last(arrays);
8652       comparator = typeof comparator == 'function' ? comparator : undefined;
8653       return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
8654     });
8655
8656     /**
8657      * Creates an array of grouped elements, the first of which contains the
8658      * first elements of the given arrays, the second of which contains the
8659      * second elements of the given arrays, and so on.
8660      *
8661      * @static
8662      * @memberOf _
8663      * @since 0.1.0
8664      * @category Array
8665      * @param {...Array} [arrays] The arrays to process.
8666      * @returns {Array} Returns the new array of grouped elements.
8667      * @example
8668      *
8669      * _.zip(['a', 'b'], [1, 2], [true, false]);
8670      * // => [['a', 1, true], ['b', 2, false]]
8671      */
8672     var zip = baseRest(unzip);
8673
8674     /**
8675      * This method is like `_.fromPairs` except that it accepts two arrays,
8676      * one of property identifiers and one of corresponding values.
8677      *
8678      * @static
8679      * @memberOf _
8680      * @since 0.4.0
8681      * @category Array
8682      * @param {Array} [props=[]] The property identifiers.
8683      * @param {Array} [values=[]] The property values.
8684      * @returns {Object} Returns the new object.
8685      * @example
8686      *
8687      * _.zipObject(['a', 'b'], [1, 2]);
8688      * // => { 'a': 1, 'b': 2 }
8689      */
8690     function zipObject(props, values) {
8691       return baseZipObject(props || [], values || [], assignValue);
8692     }
8693
8694     /**
8695      * This method is like `_.zipObject` except that it supports property paths.
8696      *
8697      * @static
8698      * @memberOf _
8699      * @since 4.1.0
8700      * @category Array
8701      * @param {Array} [props=[]] The property identifiers.
8702      * @param {Array} [values=[]] The property values.
8703      * @returns {Object} Returns the new object.
8704      * @example
8705      *
8706      * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
8707      * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
8708      */
8709     function zipObjectDeep(props, values) {
8710       return baseZipObject(props || [], values || [], baseSet);
8711     }
8712
8713     /**
8714      * This method is like `_.zip` except that it accepts `iteratee` to specify
8715      * how grouped values should be combined. The iteratee is invoked with the
8716      * elements of each group: (...group).
8717      *
8718      * @static
8719      * @memberOf _
8720      * @since 3.8.0
8721      * @category Array
8722      * @param {...Array} [arrays] The arrays to process.
8723      * @param {Function} [iteratee=_.identity] The function to combine
8724      *  grouped values.
8725      * @returns {Array} Returns the new array of grouped elements.
8726      * @example
8727      *
8728      * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
8729      *   return a + b + c;
8730      * });
8731      * // => [111, 222]
8732      */
8733     var zipWith = baseRest(function(arrays) {
8734       var length = arrays.length,
8735           iteratee = length > 1 ? arrays[length - 1] : undefined;
8736
8737       iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
8738       return unzipWith(arrays, iteratee);
8739     });
8740
8741     /*------------------------------------------------------------------------*/
8742
8743     /**
8744      * Creates a `lodash` wrapper instance that wraps `value` with explicit method
8745      * chain sequences enabled. The result of such sequences must be unwrapped
8746      * with `_#value`.
8747      *
8748      * @static
8749      * @memberOf _
8750      * @since 1.3.0
8751      * @category Seq
8752      * @param {*} value The value to wrap.
8753      * @returns {Object} Returns the new `lodash` wrapper instance.
8754      * @example
8755      *
8756      * var users = [
8757      *   { 'user': 'barney',  'age': 36 },
8758      *   { 'user': 'fred',    'age': 40 },
8759      *   { 'user': 'pebbles', 'age': 1 }
8760      * ];
8761      *
8762      * var youngest = _
8763      *   .chain(users)
8764      *   .sortBy('age')
8765      *   .map(function(o) {
8766      *     return o.user + ' is ' + o.age;
8767      *   })
8768      *   .head()
8769      *   .value();
8770      * // => 'pebbles is 1'
8771      */
8772     function chain(value) {
8773       var result = lodash(value);
8774       result.__chain__ = true;
8775       return result;
8776     }
8777
8778     /**
8779      * This method invokes `interceptor` and returns `value`. The interceptor
8780      * is invoked with one argument; (value). The purpose of this method is to
8781      * "tap into" a method chain sequence in order to modify intermediate results.
8782      *
8783      * @static
8784      * @memberOf _
8785      * @since 0.1.0
8786      * @category Seq
8787      * @param {*} value The value to provide to `interceptor`.
8788      * @param {Function} interceptor The function to invoke.
8789      * @returns {*} Returns `value`.
8790      * @example
8791      *
8792      * _([1, 2, 3])
8793      *  .tap(function(array) {
8794      *    // Mutate input array.
8795      *    array.pop();
8796      *  })
8797      *  .reverse()
8798      *  .value();
8799      * // => [2, 1]
8800      */
8801     function tap(value, interceptor) {
8802       interceptor(value);
8803       return value;
8804     }
8805
8806     /**
8807      * This method is like `_.tap` except that it returns the result of `interceptor`.
8808      * The purpose of this method is to "pass thru" values replacing intermediate
8809      * results in a method chain sequence.
8810      *
8811      * @static
8812      * @memberOf _
8813      * @since 3.0.0
8814      * @category Seq
8815      * @param {*} value The value to provide to `interceptor`.
8816      * @param {Function} interceptor The function to invoke.
8817      * @returns {*} Returns the result of `interceptor`.
8818      * @example
8819      *
8820      * _('  abc  ')
8821      *  .chain()
8822      *  .trim()
8823      *  .thru(function(value) {
8824      *    return [value];
8825      *  })
8826      *  .value();
8827      * // => ['abc']
8828      */
8829     function thru(value, interceptor) {
8830       return interceptor(value);
8831     }
8832
8833     /**
8834      * This method is the wrapper version of `_.at`.
8835      *
8836      * @name at
8837      * @memberOf _
8838      * @since 1.0.0
8839      * @category Seq
8840      * @param {...(string|string[])} [paths] The property paths to pick.
8841      * @returns {Object} Returns the new `lodash` wrapper instance.
8842      * @example
8843      *
8844      * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
8845      *
8846      * _(object).at(['a[0].b.c', 'a[1]']).value();
8847      * // => [3, 4]
8848      */
8849     var wrapperAt = flatRest(function(paths) {
8850       var length = paths.length,
8851           start = length ? paths[0] : 0,
8852           value = this.__wrapped__,
8853           interceptor = function(object) { return baseAt(object, paths); };
8854
8855       if (length > 1 || this.__actions__.length ||
8856           !(value instanceof LazyWrapper) || !isIndex(start)) {
8857         return this.thru(interceptor);
8858       }
8859       value = value.slice(start, +start + (length ? 1 : 0));
8860       value.__actions__.push({
8861         'func': thru,
8862         'args': [interceptor],
8863         'thisArg': undefined
8864       });
8865       return new LodashWrapper(value, this.__chain__).thru(function(array) {
8866         if (length && !array.length) {
8867           array.push(undefined);
8868         }
8869         return array;
8870       });
8871     });
8872
8873     /**
8874      * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
8875      *
8876      * @name chain
8877      * @memberOf _
8878      * @since 0.1.0
8879      * @category Seq
8880      * @returns {Object} Returns the new `lodash` wrapper instance.
8881      * @example
8882      *
8883      * var users = [
8884      *   { 'user': 'barney', 'age': 36 },
8885      *   { 'user': 'fred',   'age': 40 }
8886      * ];
8887      *
8888      * // A sequence without explicit chaining.
8889      * _(users).head();
8890      * // => { 'user': 'barney', 'age': 36 }
8891      *
8892      * // A sequence with explicit chaining.
8893      * _(users)
8894      *   .chain()
8895      *   .head()
8896      *   .pick('user')
8897      *   .value();
8898      * // => { 'user': 'barney' }
8899      */
8900     function wrapperChain() {
8901       return chain(this);
8902     }
8903
8904     /**
8905      * Executes the chain sequence and returns the wrapped result.
8906      *
8907      * @name commit
8908      * @memberOf _
8909      * @since 3.2.0
8910      * @category Seq
8911      * @returns {Object} Returns the new `lodash` wrapper instance.
8912      * @example
8913      *
8914      * var array = [1, 2];
8915      * var wrapped = _(array).push(3);
8916      *
8917      * console.log(array);
8918      * // => [1, 2]
8919      *
8920      * wrapped = wrapped.commit();
8921      * console.log(array);
8922      * // => [1, 2, 3]
8923      *
8924      * wrapped.last();
8925      * // => 3
8926      *
8927      * console.log(array);
8928      * // => [1, 2, 3]
8929      */
8930     function wrapperCommit() {
8931       return new LodashWrapper(this.value(), this.__chain__);
8932     }
8933
8934     /**
8935      * Gets the next value on a wrapped object following the
8936      * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
8937      *
8938      * @name next
8939      * @memberOf _
8940      * @since 4.0.0
8941      * @category Seq
8942      * @returns {Object} Returns the next iterator value.
8943      * @example
8944      *
8945      * var wrapped = _([1, 2]);
8946      *
8947      * wrapped.next();
8948      * // => { 'done': false, 'value': 1 }
8949      *
8950      * wrapped.next();
8951      * // => { 'done': false, 'value': 2 }
8952      *
8953      * wrapped.next();
8954      * // => { 'done': true, 'value': undefined }
8955      */
8956     function wrapperNext() {
8957       if (this.__values__ === undefined) {
8958         this.__values__ = toArray(this.value());
8959       }
8960       var done = this.__index__ >= this.__values__.length,
8961           value = done ? undefined : this.__values__[this.__index__++];
8962
8963       return { 'done': done, 'value': value };
8964     }
8965
8966     /**
8967      * Enables the wrapper to be iterable.
8968      *
8969      * @name Symbol.iterator
8970      * @memberOf _
8971      * @since 4.0.0
8972      * @category Seq
8973      * @returns {Object} Returns the wrapper object.
8974      * @example
8975      *
8976      * var wrapped = _([1, 2]);
8977      *
8978      * wrapped[Symbol.iterator]() === wrapped;
8979      * // => true
8980      *
8981      * Array.from(wrapped);
8982      * // => [1, 2]
8983      */
8984     function wrapperToIterator() {
8985       return this;
8986     }
8987
8988     /**
8989      * Creates a clone of the chain sequence planting `value` as the wrapped value.
8990      *
8991      * @name plant
8992      * @memberOf _
8993      * @since 3.2.0
8994      * @category Seq
8995      * @param {*} value The value to plant.
8996      * @returns {Object} Returns the new `lodash` wrapper instance.
8997      * @example
8998      *
8999      * function square(n) {
9000      *   return n * n;
9001      * }
9002      *
9003      * var wrapped = _([1, 2]).map(square);
9004      * var other = wrapped.plant([3, 4]);
9005      *
9006      * other.value();
9007      * // => [9, 16]
9008      *
9009      * wrapped.value();
9010      * // => [1, 4]
9011      */
9012     function wrapperPlant(value) {
9013       var result,
9014           parent = this;
9015
9016       while (parent instanceof baseLodash) {
9017         var clone = wrapperClone(parent);
9018         clone.__index__ = 0;
9019         clone.__values__ = undefined;
9020         if (result) {
9021           previous.__wrapped__ = clone;
9022         } else {
9023           result = clone;
9024         }
9025         var previous = clone;
9026         parent = parent.__wrapped__;
9027       }
9028       previous.__wrapped__ = value;
9029       return result;
9030     }
9031
9032     /**
9033      * This method is the wrapper version of `_.reverse`.
9034      *
9035      * **Note:** This method mutates the wrapped array.
9036      *
9037      * @name reverse
9038      * @memberOf _
9039      * @since 0.1.0
9040      * @category Seq
9041      * @returns {Object} Returns the new `lodash` wrapper instance.
9042      * @example
9043      *
9044      * var array = [1, 2, 3];
9045      *
9046      * _(array).reverse().value()
9047      * // => [3, 2, 1]
9048      *
9049      * console.log(array);
9050      * // => [3, 2, 1]
9051      */
9052     function wrapperReverse() {
9053       var value = this.__wrapped__;
9054       if (value instanceof LazyWrapper) {
9055         var wrapped = value;
9056         if (this.__actions__.length) {
9057           wrapped = new LazyWrapper(this);
9058         }
9059         wrapped = wrapped.reverse();
9060         wrapped.__actions__.push({
9061           'func': thru,
9062           'args': [reverse],
9063           'thisArg': undefined
9064         });
9065         return new LodashWrapper(wrapped, this.__chain__);
9066       }
9067       return this.thru(reverse);
9068     }
9069
9070     /**
9071      * Executes the chain sequence to resolve the unwrapped value.
9072      *
9073      * @name value
9074      * @memberOf _
9075      * @since 0.1.0
9076      * @alias toJSON, valueOf
9077      * @category Seq
9078      * @returns {*} Returns the resolved unwrapped value.
9079      * @example
9080      *
9081      * _([1, 2, 3]).value();
9082      * // => [1, 2, 3]
9083      */
9084     function wrapperValue() {
9085       return baseWrapperValue(this.__wrapped__, this.__actions__);
9086     }
9087
9088     /*------------------------------------------------------------------------*/
9089
9090     /**
9091      * Creates an object composed of keys generated from the results of running
9092      * each element of `collection` thru `iteratee`. The corresponding value of
9093      * each key is the number of times the key was returned by `iteratee`. The
9094      * iteratee is invoked with one argument: (value).
9095      *
9096      * @static
9097      * @memberOf _
9098      * @since 0.5.0
9099      * @category Collection
9100      * @param {Array|Object} collection The collection to iterate over.
9101      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9102      * @returns {Object} Returns the composed aggregate object.
9103      * @example
9104      *
9105      * _.countBy([6.1, 4.2, 6.3], Math.floor);
9106      * // => { '4': 1, '6': 2 }
9107      *
9108      * // The `_.property` iteratee shorthand.
9109      * _.countBy(['one', 'two', 'three'], 'length');
9110      * // => { '3': 2, '5': 1 }
9111      */
9112     var countBy = createAggregator(function(result, value, key) {
9113       if (hasOwnProperty.call(result, key)) {
9114         ++result[key];
9115       } else {
9116         baseAssignValue(result, key, 1);
9117       }
9118     });
9119
9120     /**
9121      * Checks if `predicate` returns truthy for **all** elements of `collection`.
9122      * Iteration is stopped once `predicate` returns falsey. The predicate is
9123      * invoked with three arguments: (value, index|key, collection).
9124      *
9125      * **Note:** This method returns `true` for
9126      * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
9127      * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
9128      * elements of empty collections.
9129      *
9130      * @static
9131      * @memberOf _
9132      * @since 0.1.0
9133      * @category Collection
9134      * @param {Array|Object} collection The collection to iterate over.
9135      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9136      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9137      * @returns {boolean} Returns `true` if all elements pass the predicate check,
9138      *  else `false`.
9139      * @example
9140      *
9141      * _.every([true, 1, null, 'yes'], Boolean);
9142      * // => false
9143      *
9144      * var users = [
9145      *   { 'user': 'barney', 'age': 36, 'active': false },
9146      *   { 'user': 'fred',   'age': 40, 'active': false }
9147      * ];
9148      *
9149      * // The `_.matches` iteratee shorthand.
9150      * _.every(users, { 'user': 'barney', 'active': false });
9151      * // => false
9152      *
9153      * // The `_.matchesProperty` iteratee shorthand.
9154      * _.every(users, ['active', false]);
9155      * // => true
9156      *
9157      * // The `_.property` iteratee shorthand.
9158      * _.every(users, 'active');
9159      * // => false
9160      */
9161     function every(collection, predicate, guard) {
9162       var func = isArray(collection) ? arrayEvery : baseEvery;
9163       if (guard && isIterateeCall(collection, predicate, guard)) {
9164         predicate = undefined;
9165       }
9166       return func(collection, getIteratee(predicate, 3));
9167     }
9168
9169     /**
9170      * Iterates over elements of `collection`, returning an array of all elements
9171      * `predicate` returns truthy for. The predicate is invoked with three
9172      * arguments: (value, index|key, collection).
9173      *
9174      * **Note:** Unlike `_.remove`, this method returns a new array.
9175      *
9176      * @static
9177      * @memberOf _
9178      * @since 0.1.0
9179      * @category Collection
9180      * @param {Array|Object} collection The collection to iterate over.
9181      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9182      * @returns {Array} Returns the new filtered array.
9183      * @see _.reject
9184      * @example
9185      *
9186      * var users = [
9187      *   { 'user': 'barney', 'age': 36, 'active': true },
9188      *   { 'user': 'fred',   'age': 40, 'active': false }
9189      * ];
9190      *
9191      * _.filter(users, function(o) { return !o.active; });
9192      * // => objects for ['fred']
9193      *
9194      * // The `_.matches` iteratee shorthand.
9195      * _.filter(users, { 'age': 36, 'active': true });
9196      * // => objects for ['barney']
9197      *
9198      * // The `_.matchesProperty` iteratee shorthand.
9199      * _.filter(users, ['active', false]);
9200      * // => objects for ['fred']
9201      *
9202      * // The `_.property` iteratee shorthand.
9203      * _.filter(users, 'active');
9204      * // => objects for ['barney']
9205      */
9206     function filter(collection, predicate) {
9207       var func = isArray(collection) ? arrayFilter : baseFilter;
9208       return func(collection, getIteratee(predicate, 3));
9209     }
9210
9211     /**
9212      * Iterates over elements of `collection`, returning the first element
9213      * `predicate` returns truthy for. The predicate is invoked with three
9214      * arguments: (value, index|key, collection).
9215      *
9216      * @static
9217      * @memberOf _
9218      * @since 0.1.0
9219      * @category Collection
9220      * @param {Array|Object} collection The collection to inspect.
9221      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9222      * @param {number} [fromIndex=0] The index to search from.
9223      * @returns {*} Returns the matched element, else `undefined`.
9224      * @example
9225      *
9226      * var users = [
9227      *   { 'user': 'barney',  'age': 36, 'active': true },
9228      *   { 'user': 'fred',    'age': 40, 'active': false },
9229      *   { 'user': 'pebbles', 'age': 1,  'active': true }
9230      * ];
9231      *
9232      * _.find(users, function(o) { return o.age < 40; });
9233      * // => object for 'barney'
9234      *
9235      * // The `_.matches` iteratee shorthand.
9236      * _.find(users, { 'age': 1, 'active': true });
9237      * // => object for 'pebbles'
9238      *
9239      * // The `_.matchesProperty` iteratee shorthand.
9240      * _.find(users, ['active', false]);
9241      * // => object for 'fred'
9242      *
9243      * // The `_.property` iteratee shorthand.
9244      * _.find(users, 'active');
9245      * // => object for 'barney'
9246      */
9247     var find = createFind(findIndex);
9248
9249     /**
9250      * This method is like `_.find` except that it iterates over elements of
9251      * `collection` from right to left.
9252      *
9253      * @static
9254      * @memberOf _
9255      * @since 2.0.0
9256      * @category Collection
9257      * @param {Array|Object} collection The collection to inspect.
9258      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9259      * @param {number} [fromIndex=collection.length-1] The index to search from.
9260      * @returns {*} Returns the matched element, else `undefined`.
9261      * @example
9262      *
9263      * _.findLast([1, 2, 3, 4], function(n) {
9264      *   return n % 2 == 1;
9265      * });
9266      * // => 3
9267      */
9268     var findLast = createFind(findLastIndex);
9269
9270     /**
9271      * Creates a flattened array of values by running each element in `collection`
9272      * thru `iteratee` and flattening the mapped results. The iteratee is invoked
9273      * with three arguments: (value, index|key, collection).
9274      *
9275      * @static
9276      * @memberOf _
9277      * @since 4.0.0
9278      * @category Collection
9279      * @param {Array|Object} collection The collection to iterate over.
9280      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9281      * @returns {Array} Returns the new flattened array.
9282      * @example
9283      *
9284      * function duplicate(n) {
9285      *   return [n, n];
9286      * }
9287      *
9288      * _.flatMap([1, 2], duplicate);
9289      * // => [1, 1, 2, 2]
9290      */
9291     function flatMap(collection, iteratee) {
9292       return baseFlatten(map(collection, iteratee), 1);
9293     }
9294
9295     /**
9296      * This method is like `_.flatMap` except that it recursively flattens the
9297      * mapped results.
9298      *
9299      * @static
9300      * @memberOf _
9301      * @since 4.7.0
9302      * @category Collection
9303      * @param {Array|Object} collection The collection to iterate over.
9304      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9305      * @returns {Array} Returns the new flattened array.
9306      * @example
9307      *
9308      * function duplicate(n) {
9309      *   return [[[n, n]]];
9310      * }
9311      *
9312      * _.flatMapDeep([1, 2], duplicate);
9313      * // => [1, 1, 2, 2]
9314      */
9315     function flatMapDeep(collection, iteratee) {
9316       return baseFlatten(map(collection, iteratee), INFINITY);
9317     }
9318
9319     /**
9320      * This method is like `_.flatMap` except that it recursively flattens the
9321      * mapped results up to `depth` times.
9322      *
9323      * @static
9324      * @memberOf _
9325      * @since 4.7.0
9326      * @category Collection
9327      * @param {Array|Object} collection The collection to iterate over.
9328      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9329      * @param {number} [depth=1] The maximum recursion depth.
9330      * @returns {Array} Returns the new flattened array.
9331      * @example
9332      *
9333      * function duplicate(n) {
9334      *   return [[[n, n]]];
9335      * }
9336      *
9337      * _.flatMapDepth([1, 2], duplicate, 2);
9338      * // => [[1, 1], [2, 2]]
9339      */
9340     function flatMapDepth(collection, iteratee, depth) {
9341       depth = depth === undefined ? 1 : toInteger(depth);
9342       return baseFlatten(map(collection, iteratee), depth);
9343     }
9344
9345     /**
9346      * Iterates over elements of `collection` and invokes `iteratee` for each element.
9347      * The iteratee is invoked with three arguments: (value, index|key, collection).
9348      * Iteratee functions may exit iteration early by explicitly returning `false`.
9349      *
9350      * **Note:** As with other "Collections" methods, objects with a "length"
9351      * property are iterated like arrays. To avoid this behavior use `_.forIn`
9352      * or `_.forOwn` for object iteration.
9353      *
9354      * @static
9355      * @memberOf _
9356      * @since 0.1.0
9357      * @alias each
9358      * @category Collection
9359      * @param {Array|Object} collection The collection to iterate over.
9360      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9361      * @returns {Array|Object} Returns `collection`.
9362      * @see _.forEachRight
9363      * @example
9364      *
9365      * _.forEach([1, 2], function(value) {
9366      *   console.log(value);
9367      * });
9368      * // => Logs `1` then `2`.
9369      *
9370      * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
9371      *   console.log(key);
9372      * });
9373      * // => Logs 'a' then 'b' (iteration order is not guaranteed).
9374      */
9375     function forEach(collection, iteratee) {
9376       var func = isArray(collection) ? arrayEach : baseEach;
9377       return func(collection, getIteratee(iteratee, 3));
9378     }
9379
9380     /**
9381      * This method is like `_.forEach` except that it iterates over elements of
9382      * `collection` from right to left.
9383      *
9384      * @static
9385      * @memberOf _
9386      * @since 2.0.0
9387      * @alias eachRight
9388      * @category Collection
9389      * @param {Array|Object} collection The collection to iterate over.
9390      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9391      * @returns {Array|Object} Returns `collection`.
9392      * @see _.forEach
9393      * @example
9394      *
9395      * _.forEachRight([1, 2], function(value) {
9396      *   console.log(value);
9397      * });
9398      * // => Logs `2` then `1`.
9399      */
9400     function forEachRight(collection, iteratee) {
9401       var func = isArray(collection) ? arrayEachRight : baseEachRight;
9402       return func(collection, getIteratee(iteratee, 3));
9403     }
9404
9405     /**
9406      * Creates an object composed of keys generated from the results of running
9407      * each element of `collection` thru `iteratee`. The order of grouped values
9408      * is determined by the order they occur in `collection`. The corresponding
9409      * value of each key is an array of elements responsible for generating the
9410      * key. The iteratee is invoked with one argument: (value).
9411      *
9412      * @static
9413      * @memberOf _
9414      * @since 0.1.0
9415      * @category Collection
9416      * @param {Array|Object} collection The collection to iterate over.
9417      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9418      * @returns {Object} Returns the composed aggregate object.
9419      * @example
9420      *
9421      * _.groupBy([6.1, 4.2, 6.3], Math.floor);
9422      * // => { '4': [4.2], '6': [6.1, 6.3] }
9423      *
9424      * // The `_.property` iteratee shorthand.
9425      * _.groupBy(['one', 'two', 'three'], 'length');
9426      * // => { '3': ['one', 'two'], '5': ['three'] }
9427      */
9428     var groupBy = createAggregator(function(result, value, key) {
9429       if (hasOwnProperty.call(result, key)) {
9430         result[key].push(value);
9431       } else {
9432         baseAssignValue(result, key, [value]);
9433       }
9434     });
9435
9436     /**
9437      * Checks if `value` is in `collection`. If `collection` is a string, it's
9438      * checked for a substring of `value`, otherwise
9439      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
9440      * is used for equality comparisons. If `fromIndex` is negative, it's used as
9441      * the offset from the end of `collection`.
9442      *
9443      * @static
9444      * @memberOf _
9445      * @since 0.1.0
9446      * @category Collection
9447      * @param {Array|Object|string} collection The collection to inspect.
9448      * @param {*} value The value to search for.
9449      * @param {number} [fromIndex=0] The index to search from.
9450      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
9451      * @returns {boolean} Returns `true` if `value` is found, else `false`.
9452      * @example
9453      *
9454      * _.includes([1, 2, 3], 1);
9455      * // => true
9456      *
9457      * _.includes([1, 2, 3], 1, 2);
9458      * // => false
9459      *
9460      * _.includes({ 'a': 1, 'b': 2 }, 1);
9461      * // => true
9462      *
9463      * _.includes('abcd', 'bc');
9464      * // => true
9465      */
9466     function includes(collection, value, fromIndex, guard) {
9467       collection = isArrayLike(collection) ? collection : values(collection);
9468       fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;
9469
9470       var length = collection.length;
9471       if (fromIndex < 0) {
9472         fromIndex = nativeMax(length + fromIndex, 0);
9473       }
9474       return isString(collection)
9475         ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
9476         : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
9477     }
9478
9479     /**
9480      * Invokes the method at `path` of each element in `collection`, returning
9481      * an array of the results of each invoked method. Any additional arguments
9482      * are provided to each invoked method. If `path` is a function, it's invoked
9483      * for, and `this` bound to, each element in `collection`.
9484      *
9485      * @static
9486      * @memberOf _
9487      * @since 4.0.0
9488      * @category Collection
9489      * @param {Array|Object} collection The collection to iterate over.
9490      * @param {Array|Function|string} path The path of the method to invoke or
9491      *  the function invoked per iteration.
9492      * @param {...*} [args] The arguments to invoke each method with.
9493      * @returns {Array} Returns the array of results.
9494      * @example
9495      *
9496      * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
9497      * // => [[1, 5, 7], [1, 2, 3]]
9498      *
9499      * _.invokeMap([123, 456], String.prototype.split, '');
9500      * // => [['1', '2', '3'], ['4', '5', '6']]
9501      */
9502     var invokeMap = baseRest(function(collection, path, args) {
9503       var index = -1,
9504           isFunc = typeof path == 'function',
9505           result = isArrayLike(collection) ? Array(collection.length) : [];
9506
9507       baseEach(collection, function(value) {
9508         result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
9509       });
9510       return result;
9511     });
9512
9513     /**
9514      * Creates an object composed of keys generated from the results of running
9515      * each element of `collection` thru `iteratee`. The corresponding value of
9516      * each key is the last element responsible for generating the key. The
9517      * iteratee is invoked with one argument: (value).
9518      *
9519      * @static
9520      * @memberOf _
9521      * @since 4.0.0
9522      * @category Collection
9523      * @param {Array|Object} collection The collection to iterate over.
9524      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9525      * @returns {Object} Returns the composed aggregate object.
9526      * @example
9527      *
9528      * var array = [
9529      *   { 'dir': 'left', 'code': 97 },
9530      *   { 'dir': 'right', 'code': 100 }
9531      * ];
9532      *
9533      * _.keyBy(array, function(o) {
9534      *   return String.fromCharCode(o.code);
9535      * });
9536      * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
9537      *
9538      * _.keyBy(array, 'dir');
9539      * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
9540      */
9541     var keyBy = createAggregator(function(result, value, key) {
9542       baseAssignValue(result, key, value);
9543     });
9544
9545     /**
9546      * Creates an array of values by running each element in `collection` thru
9547      * `iteratee`. The iteratee is invoked with three arguments:
9548      * (value, index|key, collection).
9549      *
9550      * Many lodash methods are guarded to work as iteratees for methods like
9551      * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
9552      *
9553      * The guarded methods are:
9554      * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
9555      * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
9556      * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
9557      * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
9558      *
9559      * @static
9560      * @memberOf _
9561      * @since 0.1.0
9562      * @category Collection
9563      * @param {Array|Object} collection The collection to iterate over.
9564      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9565      * @returns {Array} Returns the new mapped array.
9566      * @example
9567      *
9568      * function square(n) {
9569      *   return n * n;
9570      * }
9571      *
9572      * _.map([4, 8], square);
9573      * // => [16, 64]
9574      *
9575      * _.map({ 'a': 4, 'b': 8 }, square);
9576      * // => [16, 64] (iteration order is not guaranteed)
9577      *
9578      * var users = [
9579      *   { 'user': 'barney' },
9580      *   { 'user': 'fred' }
9581      * ];
9582      *
9583      * // The `_.property` iteratee shorthand.
9584      * _.map(users, 'user');
9585      * // => ['barney', 'fred']
9586      */
9587     function map(collection, iteratee) {
9588       var func = isArray(collection) ? arrayMap : baseMap;
9589       return func(collection, getIteratee(iteratee, 3));
9590     }
9591
9592     /**
9593      * This method is like `_.sortBy` except that it allows specifying the sort
9594      * orders of the iteratees to sort by. If `orders` is unspecified, all values
9595      * are sorted in ascending order. Otherwise, specify an order of "desc" for
9596      * descending or "asc" for ascending sort order of corresponding values.
9597      *
9598      * @static
9599      * @memberOf _
9600      * @since 4.0.0
9601      * @category Collection
9602      * @param {Array|Object} collection The collection to iterate over.
9603      * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
9604      *  The iteratees to sort by.
9605      * @param {string[]} [orders] The sort orders of `iteratees`.
9606      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
9607      * @returns {Array} Returns the new sorted array.
9608      * @example
9609      *
9610      * var users = [
9611      *   { 'user': 'fred',   'age': 48 },
9612      *   { 'user': 'barney', 'age': 34 },
9613      *   { 'user': 'fred',   'age': 40 },
9614      *   { 'user': 'barney', 'age': 36 }
9615      * ];
9616      *
9617      * // Sort by `user` in ascending order and by `age` in descending order.
9618      * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
9619      * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
9620      */
9621     function orderBy(collection, iteratees, orders, guard) {
9622       if (collection == null) {
9623         return [];
9624       }
9625       if (!isArray(iteratees)) {
9626         iteratees = iteratees == null ? [] : [iteratees];
9627       }
9628       orders = guard ? undefined : orders;
9629       if (!isArray(orders)) {
9630         orders = orders == null ? [] : [orders];
9631       }
9632       return baseOrderBy(collection, iteratees, orders);
9633     }
9634
9635     /**
9636      * Creates an array of elements split into two groups, the first of which
9637      * contains elements `predicate` returns truthy for, the second of which
9638      * contains elements `predicate` returns falsey for. The predicate is
9639      * invoked with one argument: (value).
9640      *
9641      * @static
9642      * @memberOf _
9643      * @since 3.0.0
9644      * @category Collection
9645      * @param {Array|Object} collection The collection to iterate over.
9646      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9647      * @returns {Array} Returns the array of grouped elements.
9648      * @example
9649      *
9650      * var users = [
9651      *   { 'user': 'barney',  'age': 36, 'active': false },
9652      *   { 'user': 'fred',    'age': 40, 'active': true },
9653      *   { 'user': 'pebbles', 'age': 1,  'active': false }
9654      * ];
9655      *
9656      * _.partition(users, function(o) { return o.active; });
9657      * // => objects for [['fred'], ['barney', 'pebbles']]
9658      *
9659      * // The `_.matches` iteratee shorthand.
9660      * _.partition(users, { 'age': 1, 'active': false });
9661      * // => objects for [['pebbles'], ['barney', 'fred']]
9662      *
9663      * // The `_.matchesProperty` iteratee shorthand.
9664      * _.partition(users, ['active', false]);
9665      * // => objects for [['barney', 'pebbles'], ['fred']]
9666      *
9667      * // The `_.property` iteratee shorthand.
9668      * _.partition(users, 'active');
9669      * // => objects for [['fred'], ['barney', 'pebbles']]
9670      */
9671     var partition = createAggregator(function(result, value, key) {
9672       result[key ? 0 : 1].push(value);
9673     }, function() { return [[], []]; });
9674
9675     /**
9676      * Reduces `collection` to a value which is the accumulated result of running
9677      * each element in `collection` thru `iteratee`, where each successive
9678      * invocation is supplied the return value of the previous. If `accumulator`
9679      * is not given, the first element of `collection` is used as the initial
9680      * value. The iteratee is invoked with four arguments:
9681      * (accumulator, value, index|key, collection).
9682      *
9683      * Many lodash methods are guarded to work as iteratees for methods like
9684      * `_.reduce`, `_.reduceRight`, and `_.transform`.
9685      *
9686      * The guarded methods are:
9687      * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
9688      * and `sortBy`
9689      *
9690      * @static
9691      * @memberOf _
9692      * @since 0.1.0
9693      * @category Collection
9694      * @param {Array|Object} collection The collection to iterate over.
9695      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9696      * @param {*} [accumulator] The initial value.
9697      * @returns {*} Returns the accumulated value.
9698      * @see _.reduceRight
9699      * @example
9700      *
9701      * _.reduce([1, 2], function(sum, n) {
9702      *   return sum + n;
9703      * }, 0);
9704      * // => 3
9705      *
9706      * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
9707      *   (result[value] || (result[value] = [])).push(key);
9708      *   return result;
9709      * }, {});
9710      * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
9711      */
9712     function reduce(collection, iteratee, accumulator) {
9713       var func = isArray(collection) ? arrayReduce : baseReduce,
9714           initAccum = arguments.length < 3;
9715
9716       return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
9717     }
9718
9719     /**
9720      * This method is like `_.reduce` except that it iterates over elements of
9721      * `collection` from right to left.
9722      *
9723      * @static
9724      * @memberOf _
9725      * @since 0.1.0
9726      * @category Collection
9727      * @param {Array|Object} collection The collection to iterate over.
9728      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9729      * @param {*} [accumulator] The initial value.
9730      * @returns {*} Returns the accumulated value.
9731      * @see _.reduce
9732      * @example
9733      *
9734      * var array = [[0, 1], [2, 3], [4, 5]];
9735      *
9736      * _.reduceRight(array, function(flattened, other) {
9737      *   return flattened.concat(other);
9738      * }, []);
9739      * // => [4, 5, 2, 3, 0, 1]
9740      */
9741     function reduceRight(collection, iteratee, accumulator) {
9742       var func = isArray(collection) ? arrayReduceRight : baseReduce,
9743           initAccum = arguments.length < 3;
9744
9745       return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
9746     }
9747
9748     /**
9749      * The opposite of `_.filter`; this method returns the elements of `collection`
9750      * that `predicate` does **not** return truthy for.
9751      *
9752      * @static
9753      * @memberOf _
9754      * @since 0.1.0
9755      * @category Collection
9756      * @param {Array|Object} collection The collection to iterate over.
9757      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9758      * @returns {Array} Returns the new filtered array.
9759      * @see _.filter
9760      * @example
9761      *
9762      * var users = [
9763      *   { 'user': 'barney', 'age': 36, 'active': false },
9764      *   { 'user': 'fred',   'age': 40, 'active': true }
9765      * ];
9766      *
9767      * _.reject(users, function(o) { return !o.active; });
9768      * // => objects for ['fred']
9769      *
9770      * // The `_.matches` iteratee shorthand.
9771      * _.reject(users, { 'age': 40, 'active': true });
9772      * // => objects for ['barney']
9773      *
9774      * // The `_.matchesProperty` iteratee shorthand.
9775      * _.reject(users, ['active', false]);
9776      * // => objects for ['fred']
9777      *
9778      * // The `_.property` iteratee shorthand.
9779      * _.reject(users, 'active');
9780      * // => objects for ['barney']
9781      */
9782     function reject(collection, predicate) {
9783       var func = isArray(collection) ? arrayFilter : baseFilter;
9784       return func(collection, negate(getIteratee(predicate, 3)));
9785     }
9786
9787     /**
9788      * Gets a random element from `collection`.
9789      *
9790      * @static
9791      * @memberOf _
9792      * @since 2.0.0
9793      * @category Collection
9794      * @param {Array|Object} collection The collection to sample.
9795      * @returns {*} Returns the random element.
9796      * @example
9797      *
9798      * _.sample([1, 2, 3, 4]);
9799      * // => 2
9800      */
9801     function sample(collection) {
9802       var func = isArray(collection) ? arraySample : baseSample;
9803       return func(collection);
9804     }
9805
9806     /**
9807      * Gets `n` random elements at unique keys from `collection` up to the
9808      * size of `collection`.
9809      *
9810      * @static
9811      * @memberOf _
9812      * @since 4.0.0
9813      * @category Collection
9814      * @param {Array|Object} collection The collection to sample.
9815      * @param {number} [n=1] The number of elements to sample.
9816      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9817      * @returns {Array} Returns the random elements.
9818      * @example
9819      *
9820      * _.sampleSize([1, 2, 3], 2);
9821      * // => [3, 1]
9822      *
9823      * _.sampleSize([1, 2, 3], 4);
9824      * // => [2, 3, 1]
9825      */
9826     function sampleSize(collection, n, guard) {
9827       if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {
9828         n = 1;
9829       } else {
9830         n = toInteger(n);
9831       }
9832       var func = isArray(collection) ? arraySampleSize : baseSampleSize;
9833       return func(collection, n);
9834     }
9835
9836     /**
9837      * Creates an array of shuffled values, using a version of the
9838      * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
9839      *
9840      * @static
9841      * @memberOf _
9842      * @since 0.1.0
9843      * @category Collection
9844      * @param {Array|Object} collection The collection to shuffle.
9845      * @returns {Array} Returns the new shuffled array.
9846      * @example
9847      *
9848      * _.shuffle([1, 2, 3, 4]);
9849      * // => [4, 1, 3, 2]
9850      */
9851     function shuffle(collection) {
9852       var func = isArray(collection) ? arrayShuffle : baseShuffle;
9853       return func(collection);
9854     }
9855
9856     /**
9857      * Gets the size of `collection` by returning its length for array-like
9858      * values or the number of own enumerable string keyed properties for objects.
9859      *
9860      * @static
9861      * @memberOf _
9862      * @since 0.1.0
9863      * @category Collection
9864      * @param {Array|Object|string} collection The collection to inspect.
9865      * @returns {number} Returns the collection size.
9866      * @example
9867      *
9868      * _.size([1, 2, 3]);
9869      * // => 3
9870      *
9871      * _.size({ 'a': 1, 'b': 2 });
9872      * // => 2
9873      *
9874      * _.size('pebbles');
9875      * // => 7
9876      */
9877     function size(collection) {
9878       if (collection == null) {
9879         return 0;
9880       }
9881       if (isArrayLike(collection)) {
9882         return isString(collection) ? stringSize(collection) : collection.length;
9883       }
9884       var tag = getTag(collection);
9885       if (tag == mapTag || tag == setTag) {
9886         return collection.size;
9887       }
9888       return baseKeys(collection).length;
9889     }
9890
9891     /**
9892      * Checks if `predicate` returns truthy for **any** element of `collection`.
9893      * Iteration is stopped once `predicate` returns truthy. The predicate is
9894      * invoked with three arguments: (value, index|key, collection).
9895      *
9896      * @static
9897      * @memberOf _
9898      * @since 0.1.0
9899      * @category Collection
9900      * @param {Array|Object} collection The collection to iterate over.
9901      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9902      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9903      * @returns {boolean} Returns `true` if any element passes the predicate check,
9904      *  else `false`.
9905      * @example
9906      *
9907      * _.some([null, 0, 'yes', false], Boolean);
9908      * // => true
9909      *
9910      * var users = [
9911      *   { 'user': 'barney', 'active': true },
9912      *   { 'user': 'fred',   'active': false }
9913      * ];
9914      *
9915      * // The `_.matches` iteratee shorthand.
9916      * _.some(users, { 'user': 'barney', 'active': false });
9917      * // => false
9918      *
9919      * // The `_.matchesProperty` iteratee shorthand.
9920      * _.some(users, ['active', false]);
9921      * // => true
9922      *
9923      * // The `_.property` iteratee shorthand.
9924      * _.some(users, 'active');
9925      * // => true
9926      */
9927     function some(collection, predicate, guard) {
9928       var func = isArray(collection) ? arraySome : baseSome;
9929       if (guard && isIterateeCall(collection, predicate, guard)) {
9930         predicate = undefined;
9931       }
9932       return func(collection, getIteratee(predicate, 3));
9933     }
9934
9935     /**
9936      * Creates an array of elements, sorted in ascending order by the results of
9937      * running each element in a collection thru each iteratee. This method
9938      * performs a stable sort, that is, it preserves the original sort order of
9939      * equal elements. The iteratees are invoked with one argument: (value).
9940      *
9941      * @static
9942      * @memberOf _
9943      * @since 0.1.0
9944      * @category Collection
9945      * @param {Array|Object} collection The collection to iterate over.
9946      * @param {...(Function|Function[])} [iteratees=[_.identity]]
9947      *  The iteratees to sort by.
9948      * @returns {Array} Returns the new sorted array.
9949      * @example
9950      *
9951      * var users = [
9952      *   { 'user': 'fred',   'age': 48 },
9953      *   { 'user': 'barney', 'age': 36 },
9954      *   { 'user': 'fred',   'age': 40 },
9955      *   { 'user': 'barney', 'age': 34 }
9956      * ];
9957      *
9958      * _.sortBy(users, [function(o) { return o.user; }]);
9959      * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
9960      *
9961      * _.sortBy(users, ['user', 'age']);
9962      * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
9963      */
9964     var sortBy = baseRest(function(collection, iteratees) {
9965       if (collection == null) {
9966         return [];
9967       }
9968       var length = iteratees.length;
9969       if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
9970         iteratees = [];
9971       } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
9972         iteratees = [iteratees[0]];
9973       }
9974       return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
9975     });
9976
9977     /*------------------------------------------------------------------------*/
9978
9979     /**
9980      * Gets the timestamp of the number of milliseconds that have elapsed since
9981      * the Unix epoch (1 January 1970 00:00:00 UTC).
9982      *
9983      * @static
9984      * @memberOf _
9985      * @since 2.4.0
9986      * @category Date
9987      * @returns {number} Returns the timestamp.
9988      * @example
9989      *
9990      * _.defer(function(stamp) {
9991      *   console.log(_.now() - stamp);
9992      * }, _.now());
9993      * // => Logs the number of milliseconds it took for the deferred invocation.
9994      */
9995     var now = ctxNow || function() {
9996       return root.Date.now();
9997     };
9998
9999     /*------------------------------------------------------------------------*/
10000
10001     /**
10002      * The opposite of `_.before`; this method creates a function that invokes
10003      * `func` once it's called `n` or more times.
10004      *
10005      * @static
10006      * @memberOf _
10007      * @since 0.1.0
10008      * @category Function
10009      * @param {number} n The number of calls before `func` is invoked.
10010      * @param {Function} func The function to restrict.
10011      * @returns {Function} Returns the new restricted function.
10012      * @example
10013      *
10014      * var saves = ['profile', 'settings'];
10015      *
10016      * var done = _.after(saves.length, function() {
10017      *   console.log('done saving!');
10018      * });
10019      *
10020      * _.forEach(saves, function(type) {
10021      *   asyncSave({ 'type': type, 'complete': done });
10022      * });
10023      * // => Logs 'done saving!' after the two async saves have completed.
10024      */
10025     function after(n, func) {
10026       if (typeof func != 'function') {
10027         throw new TypeError(FUNC_ERROR_TEXT);
10028       }
10029       n = toInteger(n);
10030       return function() {
10031         if (--n < 1) {
10032           return func.apply(this, arguments);
10033         }
10034       };
10035     }
10036
10037     /**
10038      * Creates a function that invokes `func`, with up to `n` arguments,
10039      * ignoring any additional arguments.
10040      *
10041      * @static
10042      * @memberOf _
10043      * @since 3.0.0
10044      * @category Function
10045      * @param {Function} func The function to cap arguments for.
10046      * @param {number} [n=func.length] The arity cap.
10047      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10048      * @returns {Function} Returns the new capped function.
10049      * @example
10050      *
10051      * _.map(['6', '8', '10'], _.ary(parseInt, 1));
10052      * // => [6, 8, 10]
10053      */
10054     function ary(func, n, guard) {
10055       n = guard ? undefined : n;
10056       n = (func && n == null) ? func.length : n;
10057       return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n);
10058     }
10059
10060     /**
10061      * Creates a function that invokes `func`, with the `this` binding and arguments
10062      * of the created function, while it's called less than `n` times. Subsequent
10063      * calls to the created function return the result of the last `func` invocation.
10064      *
10065      * @static
10066      * @memberOf _
10067      * @since 3.0.0
10068      * @category Function
10069      * @param {number} n The number of calls at which `func` is no longer invoked.
10070      * @param {Function} func The function to restrict.
10071      * @returns {Function} Returns the new restricted function.
10072      * @example
10073      *
10074      * jQuery(element).on('click', _.before(5, addContactToList));
10075      * // => Allows adding up to 4 contacts to the list.
10076      */
10077     function before(n, func) {
10078       var result;
10079       if (typeof func != 'function') {
10080         throw new TypeError(FUNC_ERROR_TEXT);
10081       }
10082       n = toInteger(n);
10083       return function() {
10084         if (--n > 0) {
10085           result = func.apply(this, arguments);
10086         }
10087         if (n <= 1) {
10088           func = undefined;
10089         }
10090         return result;
10091       };
10092     }
10093
10094     /**
10095      * Creates a function that invokes `func` with the `this` binding of `thisArg`
10096      * and `partials` prepended to the arguments it receives.
10097      *
10098      * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
10099      * may be used as a placeholder for partially applied arguments.
10100      *
10101      * **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
10102      * property of bound functions.
10103      *
10104      * @static
10105      * @memberOf _
10106      * @since 0.1.0
10107      * @category Function
10108      * @param {Function} func The function to bind.
10109      * @param {*} thisArg The `this` binding of `func`.
10110      * @param {...*} [partials] The arguments to be partially applied.
10111      * @returns {Function} Returns the new bound function.
10112      * @example
10113      *
10114      * function greet(greeting, punctuation) {
10115      *   return greeting + ' ' + this.user + punctuation;
10116      * }
10117      *
10118      * var object = { 'user': 'fred' };
10119      *
10120      * var bound = _.bind(greet, object, 'hi');
10121      * bound('!');
10122      * // => 'hi fred!'
10123      *
10124      * // Bound with placeholders.
10125      * var bound = _.bind(greet, object, _, '!');
10126      * bound('hi');
10127      * // => 'hi fred!'
10128      */
10129     var bind = baseRest(function(func, thisArg, partials) {
10130       var bitmask = WRAP_BIND_FLAG;
10131       if (partials.length) {
10132         var holders = replaceHolders(partials, getHolder(bind));
10133         bitmask |= WRAP_PARTIAL_FLAG;
10134       }
10135       return createWrap(func, bitmask, thisArg, partials, holders);
10136     });
10137
10138     /**
10139      * Creates a function that invokes the method at `object[key]` with `partials`
10140      * prepended to the arguments it receives.
10141      *
10142      * This method differs from `_.bind` by allowing bound functions to reference
10143      * methods that may be redefined or don't yet exist. See
10144      * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
10145      * for more details.
10146      *
10147      * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
10148      * builds, may be used as a placeholder for partially applied arguments.
10149      *
10150      * @static
10151      * @memberOf _
10152      * @since 0.10.0
10153      * @category Function
10154      * @param {Object} object The object to invoke the method on.
10155      * @param {string} key The key of the method.
10156      * @param {...*} [partials] The arguments to be partially applied.
10157      * @returns {Function} Returns the new bound function.
10158      * @example
10159      *
10160      * var object = {
10161      *   'user': 'fred',
10162      *   'greet': function(greeting, punctuation) {
10163      *     return greeting + ' ' + this.user + punctuation;
10164      *   }
10165      * };
10166      *
10167      * var bound = _.bindKey(object, 'greet', 'hi');
10168      * bound('!');
10169      * // => 'hi fred!'
10170      *
10171      * object.greet = function(greeting, punctuation) {
10172      *   return greeting + 'ya ' + this.user + punctuation;
10173      * };
10174      *
10175      * bound('!');
10176      * // => 'hiya fred!'
10177      *
10178      * // Bound with placeholders.
10179      * var bound = _.bindKey(object, 'greet', _, '!');
10180      * bound('hi');
10181      * // => 'hiya fred!'
10182      */
10183     var bindKey = baseRest(function(object, key, partials) {
10184       var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG;
10185       if (partials.length) {
10186         var holders = replaceHolders(partials, getHolder(bindKey));
10187         bitmask |= WRAP_PARTIAL_FLAG;
10188       }
10189       return createWrap(key, bitmask, object, partials, holders);
10190     });
10191
10192     /**
10193      * Creates a function that accepts arguments of `func` and either invokes
10194      * `func` returning its result, if at least `arity` number of arguments have
10195      * been provided, or returns a function that accepts the remaining `func`
10196      * arguments, and so on. The arity of `func` may be specified if `func.length`
10197      * is not sufficient.
10198      *
10199      * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
10200      * may be used as a placeholder for provided arguments.
10201      *
10202      * **Note:** This method doesn't set the "length" property of curried functions.
10203      *
10204      * @static
10205      * @memberOf _
10206      * @since 2.0.0
10207      * @category Function
10208      * @param {Function} func The function to curry.
10209      * @param {number} [arity=func.length] The arity of `func`.
10210      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10211      * @returns {Function} Returns the new curried function.
10212      * @example
10213      *
10214      * var abc = function(a, b, c) {
10215      *   return [a, b, c];
10216      * };
10217      *
10218      * var curried = _.curry(abc);
10219      *
10220      * curried(1)(2)(3);
10221      * // => [1, 2, 3]
10222      *
10223      * curried(1, 2)(3);
10224      * // => [1, 2, 3]
10225      *
10226      * curried(1, 2, 3);
10227      * // => [1, 2, 3]
10228      *
10229      * // Curried with placeholders.
10230      * curried(1)(_, 3)(2);
10231      * // => [1, 2, 3]
10232      */
10233     function curry(func, arity, guard) {
10234       arity = guard ? undefined : arity;
10235       var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
10236       result.placeholder = curry.placeholder;
10237       return result;
10238     }
10239
10240     /**
10241      * This method is like `_.curry` except that arguments are applied to `func`
10242      * in the manner of `_.partialRight` instead of `_.partial`.
10243      *
10244      * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
10245      * builds, may be used as a placeholder for provided arguments.
10246      *
10247      * **Note:** This method doesn't set the "length" property of curried functions.
10248      *
10249      * @static
10250      * @memberOf _
10251      * @since 3.0.0
10252      * @category Function
10253      * @param {Function} func The function to curry.
10254      * @param {number} [arity=func.length] The arity of `func`.
10255      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10256      * @returns {Function} Returns the new curried function.
10257      * @example
10258      *
10259      * var abc = function(a, b, c) {
10260      *   return [a, b, c];
10261      * };
10262      *
10263      * var curried = _.curryRight(abc);
10264      *
10265      * curried(3)(2)(1);
10266      * // => [1, 2, 3]
10267      *
10268      * curried(2, 3)(1);
10269      * // => [1, 2, 3]
10270      *
10271      * curried(1, 2, 3);
10272      * // => [1, 2, 3]
10273      *
10274      * // Curried with placeholders.
10275      * curried(3)(1, _)(2);
10276      * // => [1, 2, 3]
10277      */
10278     function curryRight(func, arity, guard) {
10279       arity = guard ? undefined : arity;
10280       var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
10281       result.placeholder = curryRight.placeholder;
10282       return result;
10283     }
10284
10285     /**
10286      * Creates a debounced function that delays invoking `func` until after `wait`
10287      * milliseconds have elapsed since the last time the debounced function was
10288      * invoked. The debounced function comes with a `cancel` method to cancel
10289      * delayed `func` invocations and a `flush` method to immediately invoke them.
10290      * Provide `options` to indicate whether `func` should be invoked on the
10291      * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
10292      * with the last arguments provided to the debounced function. Subsequent
10293      * calls to the debounced function return the result of the last `func`
10294      * invocation.
10295      *
10296      * **Note:** If `leading` and `trailing` options are `true`, `func` is
10297      * invoked on the trailing edge of the timeout only if the debounced function
10298      * is invoked more than once during the `wait` timeout.
10299      *
10300      * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
10301      * until to the next tick, similar to `setTimeout` with a timeout of `0`.
10302      *
10303      * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
10304      * for details over the differences between `_.debounce` and `_.throttle`.
10305      *
10306      * @static
10307      * @memberOf _
10308      * @since 0.1.0
10309      * @category Function
10310      * @param {Function} func The function to debounce.
10311      * @param {number} [wait=0] The number of milliseconds to delay.
10312      * @param {Object} [options={}] The options object.
10313      * @param {boolean} [options.leading=false]
10314      *  Specify invoking on the leading edge of the timeout.
10315      * @param {number} [options.maxWait]
10316      *  The maximum time `func` is allowed to be delayed before it's invoked.
10317      * @param {boolean} [options.trailing=true]
10318      *  Specify invoking on the trailing edge of the timeout.
10319      * @returns {Function} Returns the new debounced function.
10320      * @example
10321      *
10322      * // Avoid costly calculations while the window size is in flux.
10323      * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
10324      *
10325      * // Invoke `sendMail` when clicked, debouncing subsequent calls.
10326      * jQuery(element).on('click', _.debounce(sendMail, 300, {
10327      *   'leading': true,
10328      *   'trailing': false
10329      * }));
10330      *
10331      * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
10332      * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
10333      * var source = new EventSource('/stream');
10334      * jQuery(source).on('message', debounced);
10335      *
10336      * // Cancel the trailing debounced invocation.
10337      * jQuery(window).on('popstate', debounced.cancel);
10338      */
10339     function debounce(func, wait, options) {
10340       var lastArgs,
10341           lastThis,
10342           maxWait,
10343           result,
10344           timerId,
10345           lastCallTime,
10346           lastInvokeTime = 0,
10347           leading = false,
10348           maxing = false,
10349           trailing = true;
10350
10351       if (typeof func != 'function') {
10352         throw new TypeError(FUNC_ERROR_TEXT);
10353       }
10354       wait = toNumber(wait) || 0;
10355       if (isObject(options)) {
10356         leading = !!options.leading;
10357         maxing = 'maxWait' in options;
10358         maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
10359         trailing = 'trailing' in options ? !!options.trailing : trailing;
10360       }
10361
10362       function invokeFunc(time) {
10363         var args = lastArgs,
10364             thisArg = lastThis;
10365
10366         lastArgs = lastThis = undefined;
10367         lastInvokeTime = time;
10368         result = func.apply(thisArg, args);
10369         return result;
10370       }
10371
10372       function leadingEdge(time) {
10373         // Reset any `maxWait` timer.
10374         lastInvokeTime = time;
10375         // Start the timer for the trailing edge.
10376         timerId = setTimeout(timerExpired, wait);
10377         // Invoke the leading edge.
10378         return leading ? invokeFunc(time) : result;
10379       }
10380
10381       function remainingWait(time) {
10382         var timeSinceLastCall = time - lastCallTime,
10383             timeSinceLastInvoke = time - lastInvokeTime,
10384             result = wait - timeSinceLastCall;
10385
10386         return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
10387       }
10388
10389       function shouldInvoke(time) {
10390         var timeSinceLastCall = time - lastCallTime,
10391             timeSinceLastInvoke = time - lastInvokeTime;
10392
10393         // Either this is the first call, activity has stopped and we're at the
10394         // trailing edge, the system time has gone backwards and we're treating
10395         // it as the trailing edge, or we've hit the `maxWait` limit.
10396         return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
10397           (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
10398       }
10399
10400       function timerExpired() {
10401         var time = now();
10402         if (shouldInvoke(time)) {
10403           return trailingEdge(time);
10404         }
10405         // Restart the timer.
10406         timerId = setTimeout(timerExpired, remainingWait(time));
10407       }
10408
10409       function trailingEdge(time) {
10410         timerId = undefined;
10411
10412         // Only invoke if we have `lastArgs` which means `func` has been
10413         // debounced at least once.
10414         if (trailing && lastArgs) {
10415           return invokeFunc(time);
10416         }
10417         lastArgs = lastThis = undefined;
10418         return result;
10419       }
10420
10421       function cancel() {
10422         if (timerId !== undefined) {
10423           clearTimeout(timerId);
10424         }
10425         lastInvokeTime = 0;
10426         lastArgs = lastCallTime = lastThis = timerId = undefined;
10427       }
10428
10429       function flush() {
10430         return timerId === undefined ? result : trailingEdge(now());
10431       }
10432
10433       function debounced() {
10434         var time = now(),
10435             isInvoking = shouldInvoke(time);
10436
10437         lastArgs = arguments;
10438         lastThis = this;
10439         lastCallTime = time;
10440
10441         if (isInvoking) {
10442           if (timerId === undefined) {
10443             return leadingEdge(lastCallTime);
10444           }
10445           if (maxing) {
10446             // Handle invocations in a tight loop.
10447             timerId = setTimeout(timerExpired, wait);
10448             return invokeFunc(lastCallTime);
10449           }
10450         }
10451         if (timerId === undefined) {
10452           timerId = setTimeout(timerExpired, wait);
10453         }
10454         return result;
10455       }
10456       debounced.cancel = cancel;
10457       debounced.flush = flush;
10458       return debounced;
10459     }
10460
10461     /**
10462      * Defers invoking the `func` until the current call stack has cleared. Any
10463      * additional arguments are provided to `func` when it's invoked.
10464      *
10465      * @static
10466      * @memberOf _
10467      * @since 0.1.0
10468      * @category Function
10469      * @param {Function} func The function to defer.
10470      * @param {...*} [args] The arguments to invoke `func` with.
10471      * @returns {number} Returns the timer id.
10472      * @example
10473      *
10474      * _.defer(function(text) {
10475      *   console.log(text);
10476      * }, 'deferred');
10477      * // => Logs 'deferred' after one millisecond.
10478      */
10479     var defer = baseRest(function(func, args) {
10480       return baseDelay(func, 1, args);
10481     });
10482
10483     /**
10484      * Invokes `func` after `wait` milliseconds. Any additional arguments are
10485      * provided to `func` when it's invoked.
10486      *
10487      * @static
10488      * @memberOf _
10489      * @since 0.1.0
10490      * @category Function
10491      * @param {Function} func The function to delay.
10492      * @param {number} wait The number of milliseconds to delay invocation.
10493      * @param {...*} [args] The arguments to invoke `func` with.
10494      * @returns {number} Returns the timer id.
10495      * @example
10496      *
10497      * _.delay(function(text) {
10498      *   console.log(text);
10499      * }, 1000, 'later');
10500      * // => Logs 'later' after one second.
10501      */
10502     var delay = baseRest(function(func, wait, args) {
10503       return baseDelay(func, toNumber(wait) || 0, args);
10504     });
10505
10506     /**
10507      * Creates a function that invokes `func` with arguments reversed.
10508      *
10509      * @static
10510      * @memberOf _
10511      * @since 4.0.0
10512      * @category Function
10513      * @param {Function} func The function to flip arguments for.
10514      * @returns {Function} Returns the new flipped function.
10515      * @example
10516      *
10517      * var flipped = _.flip(function() {
10518      *   return _.toArray(arguments);
10519      * });
10520      *
10521      * flipped('a', 'b', 'c', 'd');
10522      * // => ['d', 'c', 'b', 'a']
10523      */
10524     function flip(func) {
10525       return createWrap(func, WRAP_FLIP_FLAG);
10526     }
10527
10528     /**
10529      * Creates a function that memoizes the result of `func`. If `resolver` is
10530      * provided, it determines the cache key for storing the result based on the
10531      * arguments provided to the memoized function. By default, the first argument
10532      * provided to the memoized function is used as the map cache key. The `func`
10533      * is invoked with the `this` binding of the memoized function.
10534      *
10535      * **Note:** The cache is exposed as the `cache` property on the memoized
10536      * function. Its creation may be customized by replacing the `_.memoize.Cache`
10537      * constructor with one whose instances implement the
10538      * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
10539      * method interface of `clear`, `delete`, `get`, `has`, and `set`.
10540      *
10541      * @static
10542      * @memberOf _
10543      * @since 0.1.0
10544      * @category Function
10545      * @param {Function} func The function to have its output memoized.
10546      * @param {Function} [resolver] The function to resolve the cache key.
10547      * @returns {Function} Returns the new memoized function.
10548      * @example
10549      *
10550      * var object = { 'a': 1, 'b': 2 };
10551      * var other = { 'c': 3, 'd': 4 };
10552      *
10553      * var values = _.memoize(_.values);
10554      * values(object);
10555      * // => [1, 2]
10556      *
10557      * values(other);
10558      * // => [3, 4]
10559      *
10560      * object.a = 2;
10561      * values(object);
10562      * // => [1, 2]
10563      *
10564      * // Modify the result cache.
10565      * values.cache.set(object, ['a', 'b']);
10566      * values(object);
10567      * // => ['a', 'b']
10568      *
10569      * // Replace `_.memoize.Cache`.
10570      * _.memoize.Cache = WeakMap;
10571      */
10572     function memoize(func, resolver) {
10573       if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
10574         throw new TypeError(FUNC_ERROR_TEXT);
10575       }
10576       var memoized = function() {
10577         var args = arguments,
10578             key = resolver ? resolver.apply(this, args) : args[0],
10579             cache = memoized.cache;
10580
10581         if (cache.has(key)) {
10582           return cache.get(key);
10583         }
10584         var result = func.apply(this, args);
10585         memoized.cache = cache.set(key, result) || cache;
10586         return result;
10587       };
10588       memoized.cache = new (memoize.Cache || MapCache);
10589       return memoized;
10590     }
10591
10592     // Expose `MapCache`.
10593     memoize.Cache = MapCache;
10594
10595     /**
10596      * Creates a function that negates the result of the predicate `func`. The
10597      * `func` predicate is invoked with the `this` binding and arguments of the
10598      * created function.
10599      *
10600      * @static
10601      * @memberOf _
10602      * @since 3.0.0
10603      * @category Function
10604      * @param {Function} predicate The predicate to negate.
10605      * @returns {Function} Returns the new negated function.
10606      * @example
10607      *
10608      * function isEven(n) {
10609      *   return n % 2 == 0;
10610      * }
10611      *
10612      * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
10613      * // => [1, 3, 5]
10614      */
10615     function negate(predicate) {
10616       if (typeof predicate != 'function') {
10617         throw new TypeError(FUNC_ERROR_TEXT);
10618       }
10619       return function() {
10620         var args = arguments;
10621         switch (args.length) {
10622           case 0: return !predicate.call(this);
10623           case 1: return !predicate.call(this, args[0]);
10624           case 2: return !predicate.call(this, args[0], args[1]);
10625           case 3: return !predicate.call(this, args[0], args[1], args[2]);
10626         }
10627         return !predicate.apply(this, args);
10628       };
10629     }
10630
10631     /**
10632      * Creates a function that is restricted to invoking `func` once. Repeat calls
10633      * to the function return the value of the first invocation. The `func` is
10634      * invoked with the `this` binding and arguments of the created function.
10635      *
10636      * @static
10637      * @memberOf _
10638      * @since 0.1.0
10639      * @category Function
10640      * @param {Function} func The function to restrict.
10641      * @returns {Function} Returns the new restricted function.
10642      * @example
10643      *
10644      * var initialize = _.once(createApplication);
10645      * initialize();
10646      * initialize();
10647      * // => `createApplication` is invoked once
10648      */
10649     function once(func) {
10650       return before(2, func);
10651     }
10652
10653     /**
10654      * Creates a function that invokes `func` with its arguments transformed.
10655      *
10656      * @static
10657      * @since 4.0.0
10658      * @memberOf _
10659      * @category Function
10660      * @param {Function} func The function to wrap.
10661      * @param {...(Function|Function[])} [transforms=[_.identity]]
10662      *  The argument transforms.
10663      * @returns {Function} Returns the new function.
10664      * @example
10665      *
10666      * function doubled(n) {
10667      *   return n * 2;
10668      * }
10669      *
10670      * function square(n) {
10671      *   return n * n;
10672      * }
10673      *
10674      * var func = _.overArgs(function(x, y) {
10675      *   return [x, y];
10676      * }, [square, doubled]);
10677      *
10678      * func(9, 3);
10679      * // => [81, 6]
10680      *
10681      * func(10, 5);
10682      * // => [100, 10]
10683      */
10684     var overArgs = castRest(function(func, transforms) {
10685       transforms = (transforms.length == 1 && isArray(transforms[0]))
10686         ? arrayMap(transforms[0], baseUnary(getIteratee()))
10687         : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee()));
10688
10689       var funcsLength = transforms.length;
10690       return baseRest(function(args) {
10691         var index = -1,
10692             length = nativeMin(args.length, funcsLength);
10693
10694         while (++index < length) {
10695           args[index] = transforms[index].call(this, args[index]);
10696         }
10697         return apply(func, this, args);
10698       });
10699     });
10700
10701     /**
10702      * Creates a function that invokes `func` with `partials` prepended to the
10703      * arguments it receives. This method is like `_.bind` except it does **not**
10704      * alter the `this` binding.
10705      *
10706      * The `_.partial.placeholder` value, which defaults to `_` in monolithic
10707      * builds, may be used as a placeholder for partially applied arguments.
10708      *
10709      * **Note:** This method doesn't set the "length" property of partially
10710      * applied functions.
10711      *
10712      * @static
10713      * @memberOf _
10714      * @since 0.2.0
10715      * @category Function
10716      * @param {Function} func The function to partially apply arguments to.
10717      * @param {...*} [partials] The arguments to be partially applied.
10718      * @returns {Function} Returns the new partially applied function.
10719      * @example
10720      *
10721      * function greet(greeting, name) {
10722      *   return greeting + ' ' + name;
10723      * }
10724      *
10725      * var sayHelloTo = _.partial(greet, 'hello');
10726      * sayHelloTo('fred');
10727      * // => 'hello fred'
10728      *
10729      * // Partially applied with placeholders.
10730      * var greetFred = _.partial(greet, _, 'fred');
10731      * greetFred('hi');
10732      * // => 'hi fred'
10733      */
10734     var partial = baseRest(function(func, partials) {
10735       var holders = replaceHolders(partials, getHolder(partial));
10736       return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders);
10737     });
10738
10739     /**
10740      * This method is like `_.partial` except that partially applied arguments
10741      * are appended to the arguments it receives.
10742      *
10743      * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
10744      * builds, may be used as a placeholder for partially applied arguments.
10745      *
10746      * **Note:** This method doesn't set the "length" property of partially
10747      * applied functions.
10748      *
10749      * @static
10750      * @memberOf _
10751      * @since 1.0.0
10752      * @category Function
10753      * @param {Function} func The function to partially apply arguments to.
10754      * @param {...*} [partials] The arguments to be partially applied.
10755      * @returns {Function} Returns the new partially applied function.
10756      * @example
10757      *
10758      * function greet(greeting, name) {
10759      *   return greeting + ' ' + name;
10760      * }
10761      *
10762      * var greetFred = _.partialRight(greet, 'fred');
10763      * greetFred('hi');
10764      * // => 'hi fred'
10765      *
10766      * // Partially applied with placeholders.
10767      * var sayHelloTo = _.partialRight(greet, 'hello', _);
10768      * sayHelloTo('fred');
10769      * // => 'hello fred'
10770      */
10771     var partialRight = baseRest(function(func, partials) {
10772       var holders = replaceHolders(partials, getHolder(partialRight));
10773       return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders);
10774     });
10775
10776     /**
10777      * Creates a function that invokes `func` with arguments arranged according
10778      * to the specified `indexes` where the argument value at the first index is
10779      * provided as the first argument, the argument value at the second index is
10780      * provided as the second argument, and so on.
10781      *
10782      * @static
10783      * @memberOf _
10784      * @since 3.0.0
10785      * @category Function
10786      * @param {Function} func The function to rearrange arguments for.
10787      * @param {...(number|number[])} indexes The arranged argument indexes.
10788      * @returns {Function} Returns the new function.
10789      * @example
10790      *
10791      * var rearged = _.rearg(function(a, b, c) {
10792      *   return [a, b, c];
10793      * }, [2, 0, 1]);
10794      *
10795      * rearged('b', 'c', 'a')
10796      * // => ['a', 'b', 'c']
10797      */
10798     var rearg = flatRest(function(func, indexes) {
10799       return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes);
10800     });
10801
10802     /**
10803      * Creates a function that invokes `func` with the `this` binding of the
10804      * created function and arguments from `start` and beyond provided as
10805      * an array.
10806      *
10807      * **Note:** This method is based on the
10808      * [rest parameter](https://mdn.io/rest_parameters).
10809      *
10810      * @static
10811      * @memberOf _
10812      * @since 4.0.0
10813      * @category Function
10814      * @param {Function} func The function to apply a rest parameter to.
10815      * @param {number} [start=func.length-1] The start position of the rest parameter.
10816      * @returns {Function} Returns the new function.
10817      * @example
10818      *
10819      * var say = _.rest(function(what, names) {
10820      *   return what + ' ' + _.initial(names).join(', ') +
10821      *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
10822      * });
10823      *
10824      * say('hello', 'fred', 'barney', 'pebbles');
10825      * // => 'hello fred, barney, & pebbles'
10826      */
10827     function rest(func, start) {
10828       if (typeof func != 'function') {
10829         throw new TypeError(FUNC_ERROR_TEXT);
10830       }
10831       start = start === undefined ? start : toInteger(start);
10832       return baseRest(func, start);
10833     }
10834
10835     /**
10836      * Creates a function that invokes `func` with the `this` binding of the
10837      * create function and an array of arguments much like
10838      * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
10839      *
10840      * **Note:** This method is based on the
10841      * [spread operator](https://mdn.io/spread_operator).
10842      *
10843      * @static
10844      * @memberOf _
10845      * @since 3.2.0
10846      * @category Function
10847      * @param {Function} func The function to spread arguments over.
10848      * @param {number} [start=0] The start position of the spread.
10849      * @returns {Function} Returns the new function.
10850      * @example
10851      *
10852      * var say = _.spread(function(who, what) {
10853      *   return who + ' says ' + what;
10854      * });
10855      *
10856      * say(['fred', 'hello']);
10857      * // => 'fred says hello'
10858      *
10859      * var numbers = Promise.all([
10860      *   Promise.resolve(40),
10861      *   Promise.resolve(36)
10862      * ]);
10863      *
10864      * numbers.then(_.spread(function(x, y) {
10865      *   return x + y;
10866      * }));
10867      * // => a Promise of 76
10868      */
10869     function spread(func, start) {
10870       if (typeof func != 'function') {
10871         throw new TypeError(FUNC_ERROR_TEXT);
10872       }
10873       start = start == null ? 0 : nativeMax(toInteger(start), 0);
10874       return baseRest(function(args) {
10875         var array = args[start],
10876             otherArgs = castSlice(args, 0, start);
10877
10878         if (array) {
10879           arrayPush(otherArgs, array);
10880         }
10881         return apply(func, this, otherArgs);
10882       });
10883     }
10884
10885     /**
10886      * Creates a throttled function that only invokes `func` at most once per
10887      * every `wait` milliseconds. The throttled function comes with a `cancel`
10888      * method to cancel delayed `func` invocations and a `flush` method to
10889      * immediately invoke them. Provide `options` to indicate whether `func`
10890      * should be invoked on the leading and/or trailing edge of the `wait`
10891      * timeout. The `func` is invoked with the last arguments provided to the
10892      * throttled function. Subsequent calls to the throttled function return the
10893      * result of the last `func` invocation.
10894      *
10895      * **Note:** If `leading` and `trailing` options are `true`, `func` is
10896      * invoked on the trailing edge of the timeout only if the throttled function
10897      * is invoked more than once during the `wait` timeout.
10898      *
10899      * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
10900      * until to the next tick, similar to `setTimeout` with a timeout of `0`.
10901      *
10902      * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
10903      * for details over the differences between `_.throttle` and `_.debounce`.
10904      *
10905      * @static
10906      * @memberOf _
10907      * @since 0.1.0
10908      * @category Function
10909      * @param {Function} func The function to throttle.
10910      * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
10911      * @param {Object} [options={}] The options object.
10912      * @param {boolean} [options.leading=true]
10913      *  Specify invoking on the leading edge of the timeout.
10914      * @param {boolean} [options.trailing=true]
10915      *  Specify invoking on the trailing edge of the timeout.
10916      * @returns {Function} Returns the new throttled function.
10917      * @example
10918      *
10919      * // Avoid excessively updating the position while scrolling.
10920      * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
10921      *
10922      * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
10923      * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
10924      * jQuery(element).on('click', throttled);
10925      *
10926      * // Cancel the trailing throttled invocation.
10927      * jQuery(window).on('popstate', throttled.cancel);
10928      */
10929     function throttle(func, wait, options) {
10930       var leading = true,
10931           trailing = true;
10932
10933       if (typeof func != 'function') {
10934         throw new TypeError(FUNC_ERROR_TEXT);
10935       }
10936       if (isObject(options)) {
10937         leading = 'leading' in options ? !!options.leading : leading;
10938         trailing = 'trailing' in options ? !!options.trailing : trailing;
10939       }
10940       return debounce(func, wait, {
10941         'leading': leading,
10942         'maxWait': wait,
10943         'trailing': trailing
10944       });
10945     }
10946
10947     /**
10948      * Creates a function that accepts up to one argument, ignoring any
10949      * additional arguments.
10950      *
10951      * @static
10952      * @memberOf _
10953      * @since 4.0.0
10954      * @category Function
10955      * @param {Function} func The function to cap arguments for.
10956      * @returns {Function} Returns the new capped function.
10957      * @example
10958      *
10959      * _.map(['6', '8', '10'], _.unary(parseInt));
10960      * // => [6, 8, 10]
10961      */
10962     function unary(func) {
10963       return ary(func, 1);
10964     }
10965
10966     /**
10967      * Creates a function that provides `value` to `wrapper` as its first
10968      * argument. Any additional arguments provided to the function are appended
10969      * to those provided to the `wrapper`. The wrapper is invoked with the `this`
10970      * binding of the created function.
10971      *
10972      * @static
10973      * @memberOf _
10974      * @since 0.1.0
10975      * @category Function
10976      * @param {*} value The value to wrap.
10977      * @param {Function} [wrapper=identity] The wrapper function.
10978      * @returns {Function} Returns the new function.
10979      * @example
10980      *
10981      * var p = _.wrap(_.escape, function(func, text) {
10982      *   return '<p>' + func(text) + '</p>';
10983      * });
10984      *
10985      * p('fred, barney, & pebbles');
10986      * // => '<p>fred, barney, &amp; pebbles</p>'
10987      */
10988     function wrap(value, wrapper) {
10989       return partial(castFunction(wrapper), value);
10990     }
10991
10992     /*------------------------------------------------------------------------*/
10993
10994     /**
10995      * Casts `value` as an array if it's not one.
10996      *
10997      * @static
10998      * @memberOf _
10999      * @since 4.4.0
11000      * @category Lang
11001      * @param {*} value The value to inspect.
11002      * @returns {Array} Returns the cast array.
11003      * @example
11004      *
11005      * _.castArray(1);
11006      * // => [1]
11007      *
11008      * _.castArray({ 'a': 1 });
11009      * // => [{ 'a': 1 }]
11010      *
11011      * _.castArray('abc');
11012      * // => ['abc']
11013      *
11014      * _.castArray(null);
11015      * // => [null]
11016      *
11017      * _.castArray(undefined);
11018      * // => [undefined]
11019      *
11020      * _.castArray();
11021      * // => []
11022      *
11023      * var array = [1, 2, 3];
11024      * console.log(_.castArray(array) === array);
11025      * // => true
11026      */
11027     function castArray() {
11028       if (!arguments.length) {
11029         return [];
11030       }
11031       var value = arguments[0];
11032       return isArray(value) ? value : [value];
11033     }
11034
11035     /**
11036      * Creates a shallow clone of `value`.
11037      *
11038      * **Note:** This method is loosely based on the
11039      * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
11040      * and supports cloning arrays, array buffers, booleans, date objects, maps,
11041      * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
11042      * arrays. The own enumerable properties of `arguments` objects are cloned
11043      * as plain objects. An empty object is returned for uncloneable values such
11044      * as error objects, functions, DOM nodes, and WeakMaps.
11045      *
11046      * @static
11047      * @memberOf _
11048      * @since 0.1.0
11049      * @category Lang
11050      * @param {*} value The value to clone.
11051      * @returns {*} Returns the cloned value.
11052      * @see _.cloneDeep
11053      * @example
11054      *
11055      * var objects = [{ 'a': 1 }, { 'b': 2 }];
11056      *
11057      * var shallow = _.clone(objects);
11058      * console.log(shallow[0] === objects[0]);
11059      * // => true
11060      */
11061     function clone(value) {
11062       return baseClone(value, CLONE_SYMBOLS_FLAG);
11063     }
11064
11065     /**
11066      * This method is like `_.clone` except that it accepts `customizer` which
11067      * is invoked to produce the cloned value. If `customizer` returns `undefined`,
11068      * cloning is handled by the method instead. The `customizer` is invoked with
11069      * up to four arguments; (value [, index|key, object, stack]).
11070      *
11071      * @static
11072      * @memberOf _
11073      * @since 4.0.0
11074      * @category Lang
11075      * @param {*} value The value to clone.
11076      * @param {Function} [customizer] The function to customize cloning.
11077      * @returns {*} Returns the cloned value.
11078      * @see _.cloneDeepWith
11079      * @example
11080      *
11081      * function customizer(value) {
11082      *   if (_.isElement(value)) {
11083      *     return value.cloneNode(false);
11084      *   }
11085      * }
11086      *
11087      * var el = _.cloneWith(document.body, customizer);
11088      *
11089      * console.log(el === document.body);
11090      * // => false
11091      * console.log(el.nodeName);
11092      * // => 'BODY'
11093      * console.log(el.childNodes.length);
11094      * // => 0
11095      */
11096     function cloneWith(value, customizer) {
11097       customizer = typeof customizer == 'function' ? customizer : undefined;
11098       return baseClone(value, CLONE_SYMBOLS_FLAG, customizer);
11099     }
11100
11101     /**
11102      * This method is like `_.clone` except that it recursively clones `value`.
11103      *
11104      * @static
11105      * @memberOf _
11106      * @since 1.0.0
11107      * @category Lang
11108      * @param {*} value The value to recursively clone.
11109      * @returns {*} Returns the deep cloned value.
11110      * @see _.clone
11111      * @example
11112      *
11113      * var objects = [{ 'a': 1 }, { 'b': 2 }];
11114      *
11115      * var deep = _.cloneDeep(objects);
11116      * console.log(deep[0] === objects[0]);
11117      * // => false
11118      */
11119     function cloneDeep(value) {
11120       return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
11121     }
11122
11123     /**
11124      * This method is like `_.cloneWith` except that it recursively clones `value`.
11125      *
11126      * @static
11127      * @memberOf _
11128      * @since 4.0.0
11129      * @category Lang
11130      * @param {*} value The value to recursively clone.
11131      * @param {Function} [customizer] The function to customize cloning.
11132      * @returns {*} Returns the deep cloned value.
11133      * @see _.cloneWith
11134      * @example
11135      *
11136      * function customizer(value) {
11137      *   if (_.isElement(value)) {
11138      *     return value.cloneNode(true);
11139      *   }
11140      * }
11141      *
11142      * var el = _.cloneDeepWith(document.body, customizer);
11143      *
11144      * console.log(el === document.body);
11145      * // => false
11146      * console.log(el.nodeName);
11147      * // => 'BODY'
11148      * console.log(el.childNodes.length);
11149      * // => 20
11150      */
11151     function cloneDeepWith(value, customizer) {
11152       customizer = typeof customizer == 'function' ? customizer : undefined;
11153       return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);
11154     }
11155
11156     /**
11157      * Checks if `object` conforms to `source` by invoking the predicate
11158      * properties of `source` with the corresponding property values of `object`.
11159      *
11160      * **Note:** This method is equivalent to `_.conforms` when `source` is
11161      * partially applied.
11162      *
11163      * @static
11164      * @memberOf _
11165      * @since 4.14.0
11166      * @category Lang
11167      * @param {Object} object The object to inspect.
11168      * @param {Object} source The object of property predicates to conform to.
11169      * @returns {boolean} Returns `true` if `object` conforms, else `false`.
11170      * @example
11171      *
11172      * var object = { 'a': 1, 'b': 2 };
11173      *
11174      * _.conformsTo(object, { 'b': function(n) { return n > 1; } });
11175      * // => true
11176      *
11177      * _.conformsTo(object, { 'b': function(n) { return n > 2; } });
11178      * // => false
11179      */
11180     function conformsTo(object, source) {
11181       return source == null || baseConformsTo(object, source, keys(source));
11182     }
11183
11184     /**
11185      * Performs a
11186      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
11187      * comparison between two values to determine if they are equivalent.
11188      *
11189      * @static
11190      * @memberOf _
11191      * @since 4.0.0
11192      * @category Lang
11193      * @param {*} value The value to compare.
11194      * @param {*} other The other value to compare.
11195      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11196      * @example
11197      *
11198      * var object = { 'a': 1 };
11199      * var other = { 'a': 1 };
11200      *
11201      * _.eq(object, object);
11202      * // => true
11203      *
11204      * _.eq(object, other);
11205      * // => false
11206      *
11207      * _.eq('a', 'a');
11208      * // => true
11209      *
11210      * _.eq('a', Object('a'));
11211      * // => false
11212      *
11213      * _.eq(NaN, NaN);
11214      * // => true
11215      */
11216     function eq(value, other) {
11217       return value === other || (value !== value && other !== other);
11218     }
11219
11220     /**
11221      * Checks if `value` is greater than `other`.
11222      *
11223      * @static
11224      * @memberOf _
11225      * @since 3.9.0
11226      * @category Lang
11227      * @param {*} value The value to compare.
11228      * @param {*} other The other value to compare.
11229      * @returns {boolean} Returns `true` if `value` is greater than `other`,
11230      *  else `false`.
11231      * @see _.lt
11232      * @example
11233      *
11234      * _.gt(3, 1);
11235      * // => true
11236      *
11237      * _.gt(3, 3);
11238      * // => false
11239      *
11240      * _.gt(1, 3);
11241      * // => false
11242      */
11243     var gt = createRelationalOperation(baseGt);
11244
11245     /**
11246      * Checks if `value` is greater than or equal to `other`.
11247      *
11248      * @static
11249      * @memberOf _
11250      * @since 3.9.0
11251      * @category Lang
11252      * @param {*} value The value to compare.
11253      * @param {*} other The other value to compare.
11254      * @returns {boolean} Returns `true` if `value` is greater than or equal to
11255      *  `other`, else `false`.
11256      * @see _.lte
11257      * @example
11258      *
11259      * _.gte(3, 1);
11260      * // => true
11261      *
11262      * _.gte(3, 3);
11263      * // => true
11264      *
11265      * _.gte(1, 3);
11266      * // => false
11267      */
11268     var gte = createRelationalOperation(function(value, other) {
11269       return value >= other;
11270     });
11271
11272     /**
11273      * Checks if `value` is likely an `arguments` object.
11274      *
11275      * @static
11276      * @memberOf _
11277      * @since 0.1.0
11278      * @category Lang
11279      * @param {*} value The value to check.
11280      * @returns {boolean} Returns `true` if `value` is an `arguments` object,
11281      *  else `false`.
11282      * @example
11283      *
11284      * _.isArguments(function() { return arguments; }());
11285      * // => true
11286      *
11287      * _.isArguments([1, 2, 3]);
11288      * // => false
11289      */
11290     var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
11291       return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
11292         !propertyIsEnumerable.call(value, 'callee');
11293     };
11294
11295     /**
11296      * Checks if `value` is classified as an `Array` object.
11297      *
11298      * @static
11299      * @memberOf _
11300      * @since 0.1.0
11301      * @category Lang
11302      * @param {*} value The value to check.
11303      * @returns {boolean} Returns `true` if `value` is an array, else `false`.
11304      * @example
11305      *
11306      * _.isArray([1, 2, 3]);
11307      * // => true
11308      *
11309      * _.isArray(document.body.children);
11310      * // => false
11311      *
11312      * _.isArray('abc');
11313      * // => false
11314      *
11315      * _.isArray(_.noop);
11316      * // => false
11317      */
11318     var isArray = Array.isArray;
11319
11320     /**
11321      * Checks if `value` is classified as an `ArrayBuffer` object.
11322      *
11323      * @static
11324      * @memberOf _
11325      * @since 4.3.0
11326      * @category Lang
11327      * @param {*} value The value to check.
11328      * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
11329      * @example
11330      *
11331      * _.isArrayBuffer(new ArrayBuffer(2));
11332      * // => true
11333      *
11334      * _.isArrayBuffer(new Array(2));
11335      * // => false
11336      */
11337     var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;
11338
11339     /**
11340      * Checks if `value` is array-like. A value is considered array-like if it's
11341      * not a function and has a `value.length` that's an integer greater than or
11342      * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
11343      *
11344      * @static
11345      * @memberOf _
11346      * @since 4.0.0
11347      * @category Lang
11348      * @param {*} value The value to check.
11349      * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
11350      * @example
11351      *
11352      * _.isArrayLike([1, 2, 3]);
11353      * // => true
11354      *
11355      * _.isArrayLike(document.body.children);
11356      * // => true
11357      *
11358      * _.isArrayLike('abc');
11359      * // => true
11360      *
11361      * _.isArrayLike(_.noop);
11362      * // => false
11363      */
11364     function isArrayLike(value) {
11365       return value != null && isLength(value.length) && !isFunction(value);
11366     }
11367
11368     /**
11369      * This method is like `_.isArrayLike` except that it also checks if `value`
11370      * is an object.
11371      *
11372      * @static
11373      * @memberOf _
11374      * @since 4.0.0
11375      * @category Lang
11376      * @param {*} value The value to check.
11377      * @returns {boolean} Returns `true` if `value` is an array-like object,
11378      *  else `false`.
11379      * @example
11380      *
11381      * _.isArrayLikeObject([1, 2, 3]);
11382      * // => true
11383      *
11384      * _.isArrayLikeObject(document.body.children);
11385      * // => true
11386      *
11387      * _.isArrayLikeObject('abc');
11388      * // => false
11389      *
11390      * _.isArrayLikeObject(_.noop);
11391      * // => false
11392      */
11393     function isArrayLikeObject(value) {
11394       return isObjectLike(value) && isArrayLike(value);
11395     }
11396
11397     /**
11398      * Checks if `value` is classified as a boolean primitive or object.
11399      *
11400      * @static
11401      * @memberOf _
11402      * @since 0.1.0
11403      * @category Lang
11404      * @param {*} value The value to check.
11405      * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
11406      * @example
11407      *
11408      * _.isBoolean(false);
11409      * // => true
11410      *
11411      * _.isBoolean(null);
11412      * // => false
11413      */
11414     function isBoolean(value) {
11415       return value === true || value === false ||
11416         (isObjectLike(value) && baseGetTag(value) == boolTag);
11417     }
11418
11419     /**
11420      * Checks if `value` is a buffer.
11421      *
11422      * @static
11423      * @memberOf _
11424      * @since 4.3.0
11425      * @category Lang
11426      * @param {*} value The value to check.
11427      * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
11428      * @example
11429      *
11430      * _.isBuffer(new Buffer(2));
11431      * // => true
11432      *
11433      * _.isBuffer(new Uint8Array(2));
11434      * // => false
11435      */
11436     var isBuffer = nativeIsBuffer || stubFalse;
11437
11438     /**
11439      * Checks if `value` is classified as a `Date` object.
11440      *
11441      * @static
11442      * @memberOf _
11443      * @since 0.1.0
11444      * @category Lang
11445      * @param {*} value The value to check.
11446      * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
11447      * @example
11448      *
11449      * _.isDate(new Date);
11450      * // => true
11451      *
11452      * _.isDate('Mon April 23 2012');
11453      * // => false
11454      */
11455     var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
11456
11457     /**
11458      * Checks if `value` is likely a DOM element.
11459      *
11460      * @static
11461      * @memberOf _
11462      * @since 0.1.0
11463      * @category Lang
11464      * @param {*} value The value to check.
11465      * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
11466      * @example
11467      *
11468      * _.isElement(document.body);
11469      * // => true
11470      *
11471      * _.isElement('<body>');
11472      * // => false
11473      */
11474     function isElement(value) {
11475       return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
11476     }
11477
11478     /**
11479      * Checks if `value` is an empty object, collection, map, or set.
11480      *
11481      * Objects are considered empty if they have no own enumerable string keyed
11482      * properties.
11483      *
11484      * Array-like values such as `arguments` objects, arrays, buffers, strings, or
11485      * jQuery-like collections are considered empty if they have a `length` of `0`.
11486      * Similarly, maps and sets are considered empty if they have a `size` of `0`.
11487      *
11488      * @static
11489      * @memberOf _
11490      * @since 0.1.0
11491      * @category Lang
11492      * @param {*} value The value to check.
11493      * @returns {boolean} Returns `true` if `value` is empty, else `false`.
11494      * @example
11495      *
11496      * _.isEmpty(null);
11497      * // => true
11498      *
11499      * _.isEmpty(true);
11500      * // => true
11501      *
11502      * _.isEmpty(1);
11503      * // => true
11504      *
11505      * _.isEmpty([1, 2, 3]);
11506      * // => false
11507      *
11508      * _.isEmpty({ 'a': 1 });
11509      * // => false
11510      */
11511     function isEmpty(value) {
11512       if (value == null) {
11513         return true;
11514       }
11515       if (isArrayLike(value) &&
11516           (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||
11517             isBuffer(value) || isTypedArray(value) || isArguments(value))) {
11518         return !value.length;
11519       }
11520       var tag = getTag(value);
11521       if (tag == mapTag || tag == setTag) {
11522         return !value.size;
11523       }
11524       if (isPrototype(value)) {
11525         return !baseKeys(value).length;
11526       }
11527       for (var key in value) {
11528         if (hasOwnProperty.call(value, key)) {
11529           return false;
11530         }
11531       }
11532       return true;
11533     }
11534
11535     /**
11536      * Performs a deep comparison between two values to determine if they are
11537      * equivalent.
11538      *
11539      * **Note:** This method supports comparing arrays, array buffers, booleans,
11540      * date objects, error objects, maps, numbers, `Object` objects, regexes,
11541      * sets, strings, symbols, and typed arrays. `Object` objects are compared
11542      * by their own, not inherited, enumerable properties. Functions and DOM
11543      * nodes are compared by strict equality, i.e. `===`.
11544      *
11545      * @static
11546      * @memberOf _
11547      * @since 0.1.0
11548      * @category Lang
11549      * @param {*} value The value to compare.
11550      * @param {*} other The other value to compare.
11551      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11552      * @example
11553      *
11554      * var object = { 'a': 1 };
11555      * var other = { 'a': 1 };
11556      *
11557      * _.isEqual(object, other);
11558      * // => true
11559      *
11560      * object === other;
11561      * // => false
11562      */
11563     function isEqual(value, other) {
11564       return baseIsEqual(value, other);
11565     }
11566
11567     /**
11568      * This method is like `_.isEqual` except that it accepts `customizer` which
11569      * is invoked to compare values. If `customizer` returns `undefined`, comparisons
11570      * are handled by the method instead. The `customizer` is invoked with up to
11571      * six arguments: (objValue, othValue [, index|key, object, other, stack]).
11572      *
11573      * @static
11574      * @memberOf _
11575      * @since 4.0.0
11576      * @category Lang
11577      * @param {*} value The value to compare.
11578      * @param {*} other The other value to compare.
11579      * @param {Function} [customizer] The function to customize comparisons.
11580      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11581      * @example
11582      *
11583      * function isGreeting(value) {
11584      *   return /^h(?:i|ello)$/.test(value);
11585      * }
11586      *
11587      * function customizer(objValue, othValue) {
11588      *   if (isGreeting(objValue) && isGreeting(othValue)) {
11589      *     return true;
11590      *   }
11591      * }
11592      *
11593      * var array = ['hello', 'goodbye'];
11594      * var other = ['hi', 'goodbye'];
11595      *
11596      * _.isEqualWith(array, other, customizer);
11597      * // => true
11598      */
11599     function isEqualWith(value, other, customizer) {
11600       customizer = typeof customizer == 'function' ? customizer : undefined;
11601       var result = customizer ? customizer(value, other) : undefined;
11602       return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;
11603     }
11604
11605     /**
11606      * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
11607      * `SyntaxError`, `TypeError`, or `URIError` object.
11608      *
11609      * @static
11610      * @memberOf _
11611      * @since 3.0.0
11612      * @category Lang
11613      * @param {*} value The value to check.
11614      * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
11615      * @example
11616      *
11617      * _.isError(new Error);
11618      * // => true
11619      *
11620      * _.isError(Error);
11621      * // => false
11622      */
11623     function isError(value) {
11624       if (!isObjectLike(value)) {
11625         return false;
11626       }
11627       var tag = baseGetTag(value);
11628       return tag == errorTag || tag == domExcTag ||
11629         (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value));
11630     }
11631
11632     /**
11633      * Checks if `value` is a finite primitive number.
11634      *
11635      * **Note:** This method is based on
11636      * [`Number.isFinite`](https://mdn.io/Number/isFinite).
11637      *
11638      * @static
11639      * @memberOf _
11640      * @since 0.1.0
11641      * @category Lang
11642      * @param {*} value The value to check.
11643      * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
11644      * @example
11645      *
11646      * _.isFinite(3);
11647      * // => true
11648      *
11649      * _.isFinite(Number.MIN_VALUE);
11650      * // => true
11651      *
11652      * _.isFinite(Infinity);
11653      * // => false
11654      *
11655      * _.isFinite('3');
11656      * // => false
11657      */
11658     function isFinite(value) {
11659       return typeof value == 'number' && nativeIsFinite(value);
11660     }
11661
11662     /**
11663      * Checks if `value` is classified as a `Function` object.
11664      *
11665      * @static
11666      * @memberOf _
11667      * @since 0.1.0
11668      * @category Lang
11669      * @param {*} value The value to check.
11670      * @returns {boolean} Returns `true` if `value` is a function, else `false`.
11671      * @example
11672      *
11673      * _.isFunction(_);
11674      * // => true
11675      *
11676      * _.isFunction(/abc/);
11677      * // => false
11678      */
11679     function isFunction(value) {
11680       if (!isObject(value)) {
11681         return false;
11682       }
11683       // The use of `Object#toString` avoids issues with the `typeof` operator
11684       // in Safari 9 which returns 'object' for typed arrays and other constructors.
11685       var tag = baseGetTag(value);
11686       return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
11687     }
11688
11689     /**
11690      * Checks if `value` is an integer.
11691      *
11692      * **Note:** This method is based on
11693      * [`Number.isInteger`](https://mdn.io/Number/isInteger).
11694      *
11695      * @static
11696      * @memberOf _
11697      * @since 4.0.0
11698      * @category Lang
11699      * @param {*} value The value to check.
11700      * @returns {boolean} Returns `true` if `value` is an integer, else `false`.
11701      * @example
11702      *
11703      * _.isInteger(3);
11704      * // => true
11705      *
11706      * _.isInteger(Number.MIN_VALUE);
11707      * // => false
11708      *
11709      * _.isInteger(Infinity);
11710      * // => false
11711      *
11712      * _.isInteger('3');
11713      * // => false
11714      */
11715     function isInteger(value) {
11716       return typeof value == 'number' && value == toInteger(value);
11717     }
11718
11719     /**
11720      * Checks if `value` is a valid array-like length.
11721      *
11722      * **Note:** This method is loosely based on
11723      * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
11724      *
11725      * @static
11726      * @memberOf _
11727      * @since 4.0.0
11728      * @category Lang
11729      * @param {*} value The value to check.
11730      * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
11731      * @example
11732      *
11733      * _.isLength(3);
11734      * // => true
11735      *
11736      * _.isLength(Number.MIN_VALUE);
11737      * // => false
11738      *
11739      * _.isLength(Infinity);
11740      * // => false
11741      *
11742      * _.isLength('3');
11743      * // => false
11744      */
11745     function isLength(value) {
11746       return typeof value == 'number' &&
11747         value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
11748     }
11749
11750     /**
11751      * Checks if `value` is the
11752      * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
11753      * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
11754      *
11755      * @static
11756      * @memberOf _
11757      * @since 0.1.0
11758      * @category Lang
11759      * @param {*} value The value to check.
11760      * @returns {boolean} Returns `true` if `value` is an object, else `false`.
11761      * @example
11762      *
11763      * _.isObject({});
11764      * // => true
11765      *
11766      * _.isObject([1, 2, 3]);
11767      * // => true
11768      *
11769      * _.isObject(_.noop);
11770      * // => true
11771      *
11772      * _.isObject(null);
11773      * // => false
11774      */
11775     function isObject(value) {
11776       var type = typeof value;
11777       return value != null && (type == 'object' || type == 'function');
11778     }
11779
11780     /**
11781      * Checks if `value` is object-like. A value is object-like if it's not `null`
11782      * and has a `typeof` result of "object".
11783      *
11784      * @static
11785      * @memberOf _
11786      * @since 4.0.0
11787      * @category Lang
11788      * @param {*} value The value to check.
11789      * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
11790      * @example
11791      *
11792      * _.isObjectLike({});
11793      * // => true
11794      *
11795      * _.isObjectLike([1, 2, 3]);
11796      * // => true
11797      *
11798      * _.isObjectLike(_.noop);
11799      * // => false
11800      *
11801      * _.isObjectLike(null);
11802      * // => false
11803      */
11804     function isObjectLike(value) {
11805       return value != null && typeof value == 'object';
11806     }
11807
11808     /**
11809      * Checks if `value` is classified as a `Map` object.
11810      *
11811      * @static
11812      * @memberOf _
11813      * @since 4.3.0
11814      * @category Lang
11815      * @param {*} value The value to check.
11816      * @returns {boolean} Returns `true` if `value` is a map, else `false`.
11817      * @example
11818      *
11819      * _.isMap(new Map);
11820      * // => true
11821      *
11822      * _.isMap(new WeakMap);
11823      * // => false
11824      */
11825     var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;
11826
11827     /**
11828      * Performs a partial deep comparison between `object` and `source` to
11829      * determine if `object` contains equivalent property values.
11830      *
11831      * **Note:** This method is equivalent to `_.matches` when `source` is
11832      * partially applied.
11833      *
11834      * Partial comparisons will match empty array and empty object `source`
11835      * values against any array or object value, respectively. See `_.isEqual`
11836      * for a list of supported value comparisons.
11837      *
11838      * @static
11839      * @memberOf _
11840      * @since 3.0.0
11841      * @category Lang
11842      * @param {Object} object The object to inspect.
11843      * @param {Object} source The object of property values to match.
11844      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
11845      * @example
11846      *
11847      * var object = { 'a': 1, 'b': 2 };
11848      *
11849      * _.isMatch(object, { 'b': 2 });
11850      * // => true
11851      *
11852      * _.isMatch(object, { 'b': 1 });
11853      * // => false
11854      */
11855     function isMatch(object, source) {
11856       return object === source || baseIsMatch(object, source, getMatchData(source));
11857     }
11858
11859     /**
11860      * This method is like `_.isMatch` except that it accepts `customizer` which
11861      * is invoked to compare values. If `customizer` returns `undefined`, comparisons
11862      * are handled by the method instead. The `customizer` is invoked with five
11863      * arguments: (objValue, srcValue, index|key, object, source).
11864      *
11865      * @static
11866      * @memberOf _
11867      * @since 4.0.0
11868      * @category Lang
11869      * @param {Object} object The object to inspect.
11870      * @param {Object} source The object of property values to match.
11871      * @param {Function} [customizer] The function to customize comparisons.
11872      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
11873      * @example
11874      *
11875      * function isGreeting(value) {
11876      *   return /^h(?:i|ello)$/.test(value);
11877      * }
11878      *
11879      * function customizer(objValue, srcValue) {
11880      *   if (isGreeting(objValue) && isGreeting(srcValue)) {
11881      *     return true;
11882      *   }
11883      * }
11884      *
11885      * var object = { 'greeting': 'hello' };
11886      * var source = { 'greeting': 'hi' };
11887      *
11888      * _.isMatchWith(object, source, customizer);
11889      * // => true
11890      */
11891     function isMatchWith(object, source, customizer) {
11892       customizer = typeof customizer == 'function' ? customizer : undefined;
11893       return baseIsMatch(object, source, getMatchData(source), customizer);
11894     }
11895
11896     /**
11897      * Checks if `value` is `NaN`.
11898      *
11899      * **Note:** This method is based on
11900      * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
11901      * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
11902      * `undefined` and other non-number values.
11903      *
11904      * @static
11905      * @memberOf _
11906      * @since 0.1.0
11907      * @category Lang
11908      * @param {*} value The value to check.
11909      * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
11910      * @example
11911      *
11912      * _.isNaN(NaN);
11913      * // => true
11914      *
11915      * _.isNaN(new Number(NaN));
11916      * // => true
11917      *
11918      * isNaN(undefined);
11919      * // => true
11920      *
11921      * _.isNaN(undefined);
11922      * // => false
11923      */
11924     function isNaN(value) {
11925       // An `NaN` primitive is the only value that is not equal to itself.
11926       // Perform the `toStringTag` check first to avoid errors with some
11927       // ActiveX objects in IE.
11928       return isNumber(value) && value != +value;
11929     }
11930
11931     /**
11932      * Checks if `value` is a pristine native function.
11933      *
11934      * **Note:** This method can't reliably detect native functions in the presence
11935      * of the core-js package because core-js circumvents this kind of detection.
11936      * Despite multiple requests, the core-js maintainer has made it clear: any
11937      * attempt to fix the detection will be obstructed. As a result, we're left
11938      * with little choice but to throw an error. Unfortunately, this also affects
11939      * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),
11940      * which rely on core-js.
11941      *
11942      * @static
11943      * @memberOf _
11944      * @since 3.0.0
11945      * @category Lang
11946      * @param {*} value The value to check.
11947      * @returns {boolean} Returns `true` if `value` is a native function,
11948      *  else `false`.
11949      * @example
11950      *
11951      * _.isNative(Array.prototype.push);
11952      * // => true
11953      *
11954      * _.isNative(_);
11955      * // => false
11956      */
11957     function isNative(value) {
11958       if (isMaskable(value)) {
11959         throw new Error(CORE_ERROR_TEXT);
11960       }
11961       return baseIsNative(value);
11962     }
11963
11964     /**
11965      * Checks if `value` is `null`.
11966      *
11967      * @static
11968      * @memberOf _
11969      * @since 0.1.0
11970      * @category Lang
11971      * @param {*} value The value to check.
11972      * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
11973      * @example
11974      *
11975      * _.isNull(null);
11976      * // => true
11977      *
11978      * _.isNull(void 0);
11979      * // => false
11980      */
11981     function isNull(value) {
11982       return value === null;
11983     }
11984
11985     /**
11986      * Checks if `value` is `null` or `undefined`.
11987      *
11988      * @static
11989      * @memberOf _
11990      * @since 4.0.0
11991      * @category Lang
11992      * @param {*} value The value to check.
11993      * @returns {boolean} Returns `true` if `value` is nullish, else `false`.
11994      * @example
11995      *
11996      * _.isNil(null);
11997      * // => true
11998      *
11999      * _.isNil(void 0);
12000      * // => true
12001      *
12002      * _.isNil(NaN);
12003      * // => false
12004      */
12005     function isNil(value) {
12006       return value == null;
12007     }
12008
12009     /**
12010      * Checks if `value` is classified as a `Number` primitive or object.
12011      *
12012      * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
12013      * classified as numbers, use the `_.isFinite` method.
12014      *
12015      * @static
12016      * @memberOf _
12017      * @since 0.1.0
12018      * @category Lang
12019      * @param {*} value The value to check.
12020      * @returns {boolean} Returns `true` if `value` is a number, else `false`.
12021      * @example
12022      *
12023      * _.isNumber(3);
12024      * // => true
12025      *
12026      * _.isNumber(Number.MIN_VALUE);
12027      * // => true
12028      *
12029      * _.isNumber(Infinity);
12030      * // => true
12031      *
12032      * _.isNumber('3');
12033      * // => false
12034      */
12035     function isNumber(value) {
12036       return typeof value == 'number' ||
12037         (isObjectLike(value) && baseGetTag(value) == numberTag);
12038     }
12039
12040     /**
12041      * Checks if `value` is a plain object, that is, an object created by the
12042      * `Object` constructor or one with a `[[Prototype]]` of `null`.
12043      *
12044      * @static
12045      * @memberOf _
12046      * @since 0.8.0
12047      * @category Lang
12048      * @param {*} value The value to check.
12049      * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
12050      * @example
12051      *
12052      * function Foo() {
12053      *   this.a = 1;
12054      * }
12055      *
12056      * _.isPlainObject(new Foo);
12057      * // => false
12058      *
12059      * _.isPlainObject([1, 2, 3]);
12060      * // => false
12061      *
12062      * _.isPlainObject({ 'x': 0, 'y': 0 });
12063      * // => true
12064      *
12065      * _.isPlainObject(Object.create(null));
12066      * // => true
12067      */
12068     function isPlainObject(value) {
12069       if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
12070         return false;
12071       }
12072       var proto = getPrototype(value);
12073       if (proto === null) {
12074         return true;
12075       }
12076       var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
12077       return typeof Ctor == 'function' && Ctor instanceof Ctor &&
12078         funcToString.call(Ctor) == objectCtorString;
12079     }
12080
12081     /**
12082      * Checks if `value` is classified as a `RegExp` object.
12083      *
12084      * @static
12085      * @memberOf _
12086      * @since 0.1.0
12087      * @category Lang
12088      * @param {*} value The value to check.
12089      * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
12090      * @example
12091      *
12092      * _.isRegExp(/abc/);
12093      * // => true
12094      *
12095      * _.isRegExp('/abc/');
12096      * // => false
12097      */
12098     var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;
12099
12100     /**
12101      * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
12102      * double precision number which isn't the result of a rounded unsafe integer.
12103      *
12104      * **Note:** This method is based on
12105      * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
12106      *
12107      * @static
12108      * @memberOf _
12109      * @since 4.0.0
12110      * @category Lang
12111      * @param {*} value The value to check.
12112      * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.
12113      * @example
12114      *
12115      * _.isSafeInteger(3);
12116      * // => true
12117      *
12118      * _.isSafeInteger(Number.MIN_VALUE);
12119      * // => false
12120      *
12121      * _.isSafeInteger(Infinity);
12122      * // => false
12123      *
12124      * _.isSafeInteger('3');
12125      * // => false
12126      */
12127     function isSafeInteger(value) {
12128       return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
12129     }
12130
12131     /**
12132      * Checks if `value` is classified as a `Set` object.
12133      *
12134      * @static
12135      * @memberOf _
12136      * @since 4.3.0
12137      * @category Lang
12138      * @param {*} value The value to check.
12139      * @returns {boolean} Returns `true` if `value` is a set, else `false`.
12140      * @example
12141      *
12142      * _.isSet(new Set);
12143      * // => true
12144      *
12145      * _.isSet(new WeakSet);
12146      * // => false
12147      */
12148     var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;
12149
12150     /**
12151      * Checks if `value` is classified as a `String` primitive or object.
12152      *
12153      * @static
12154      * @since 0.1.0
12155      * @memberOf _
12156      * @category Lang
12157      * @param {*} value The value to check.
12158      * @returns {boolean} Returns `true` if `value` is a string, else `false`.
12159      * @example
12160      *
12161      * _.isString('abc');
12162      * // => true
12163      *
12164      * _.isString(1);
12165      * // => false
12166      */
12167     function isString(value) {
12168       return typeof value == 'string' ||
12169         (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);
12170     }
12171
12172     /**
12173      * Checks if `value` is classified as a `Symbol` primitive or object.
12174      *
12175      * @static
12176      * @memberOf _
12177      * @since 4.0.0
12178      * @category Lang
12179      * @param {*} value The value to check.
12180      * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
12181      * @example
12182      *
12183      * _.isSymbol(Symbol.iterator);
12184      * // => true
12185      *
12186      * _.isSymbol('abc');
12187      * // => false
12188      */
12189     function isSymbol(value) {
12190       return typeof value == 'symbol' ||
12191         (isObjectLike(value) && baseGetTag(value) == symbolTag);
12192     }
12193
12194     /**
12195      * Checks if `value` is classified as a typed array.
12196      *
12197      * @static
12198      * @memberOf _
12199      * @since 3.0.0
12200      * @category Lang
12201      * @param {*} value The value to check.
12202      * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
12203      * @example
12204      *
12205      * _.isTypedArray(new Uint8Array);
12206      * // => true
12207      *
12208      * _.isTypedArray([]);
12209      * // => false
12210      */
12211     var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
12212
12213     /**
12214      * Checks if `value` is `undefined`.
12215      *
12216      * @static
12217      * @since 0.1.0
12218      * @memberOf _
12219      * @category Lang
12220      * @param {*} value The value to check.
12221      * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
12222      * @example
12223      *
12224      * _.isUndefined(void 0);
12225      * // => true
12226      *
12227      * _.isUndefined(null);
12228      * // => false
12229      */
12230     function isUndefined(value) {
12231       return value === undefined;
12232     }
12233
12234     /**
12235      * Checks if `value` is classified as a `WeakMap` object.
12236      *
12237      * @static
12238      * @memberOf _
12239      * @since 4.3.0
12240      * @category Lang
12241      * @param {*} value The value to check.
12242      * @returns {boolean} Returns `true` if `value` is a weak map, else `false`.
12243      * @example
12244      *
12245      * _.isWeakMap(new WeakMap);
12246      * // => true
12247      *
12248      * _.isWeakMap(new Map);
12249      * // => false
12250      */
12251     function isWeakMap(value) {
12252       return isObjectLike(value) && getTag(value) == weakMapTag;
12253     }
12254
12255     /**
12256      * Checks if `value` is classified as a `WeakSet` object.
12257      *
12258      * @static
12259      * @memberOf _
12260      * @since 4.3.0
12261      * @category Lang
12262      * @param {*} value The value to check.
12263      * @returns {boolean} Returns `true` if `value` is a weak set, else `false`.
12264      * @example
12265      *
12266      * _.isWeakSet(new WeakSet);
12267      * // => true
12268      *
12269      * _.isWeakSet(new Set);
12270      * // => false
12271      */
12272     function isWeakSet(value) {
12273       return isObjectLike(value) && baseGetTag(value) == weakSetTag;
12274     }
12275
12276     /**
12277      * Checks if `value` is less than `other`.
12278      *
12279      * @static
12280      * @memberOf _
12281      * @since 3.9.0
12282      * @category Lang
12283      * @param {*} value The value to compare.
12284      * @param {*} other The other value to compare.
12285      * @returns {boolean} Returns `true` if `value` is less than `other`,
12286      *  else `false`.
12287      * @see _.gt
12288      * @example
12289      *
12290      * _.lt(1, 3);
12291      * // => true
12292      *
12293      * _.lt(3, 3);
12294      * // => false
12295      *
12296      * _.lt(3, 1);
12297      * // => false
12298      */
12299     var lt = createRelationalOperation(baseLt);
12300
12301     /**
12302      * Checks if `value` is less than or equal to `other`.
12303      *
12304      * @static
12305      * @memberOf _
12306      * @since 3.9.0
12307      * @category Lang
12308      * @param {*} value The value to compare.
12309      * @param {*} other The other value to compare.
12310      * @returns {boolean} Returns `true` if `value` is less than or equal to
12311      *  `other`, else `false`.
12312      * @see _.gte
12313      * @example
12314      *
12315      * _.lte(1, 3);
12316      * // => true
12317      *
12318      * _.lte(3, 3);
12319      * // => true
12320      *
12321      * _.lte(3, 1);
12322      * // => false
12323      */
12324     var lte = createRelationalOperation(function(value, other) {
12325       return value <= other;
12326     });
12327
12328     /**
12329      * Converts `value` to an array.
12330      *
12331      * @static
12332      * @since 0.1.0
12333      * @memberOf _
12334      * @category Lang
12335      * @param {*} value The value to convert.
12336      * @returns {Array} Returns the converted array.
12337      * @example
12338      *
12339      * _.toArray({ 'a': 1, 'b': 2 });
12340      * // => [1, 2]
12341      *
12342      * _.toArray('abc');
12343      * // => ['a', 'b', 'c']
12344      *
12345      * _.toArray(1);
12346      * // => []
12347      *
12348      * _.toArray(null);
12349      * // => []
12350      */
12351     function toArray(value) {
12352       if (!value) {
12353         return [];
12354       }
12355       if (isArrayLike(value)) {
12356         return isString(value) ? stringToArray(value) : copyArray(value);
12357       }
12358       if (symIterator && value[symIterator]) {
12359         return iteratorToArray(value[symIterator]());
12360       }
12361       var tag = getTag(value),
12362           func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);
12363
12364       return func(value);
12365     }
12366
12367     /**
12368      * Converts `value` to a finite number.
12369      *
12370      * @static
12371      * @memberOf _
12372      * @since 4.12.0
12373      * @category Lang
12374      * @param {*} value The value to convert.
12375      * @returns {number} Returns the converted number.
12376      * @example
12377      *
12378      * _.toFinite(3.2);
12379      * // => 3.2
12380      *
12381      * _.toFinite(Number.MIN_VALUE);
12382      * // => 5e-324
12383      *
12384      * _.toFinite(Infinity);
12385      * // => 1.7976931348623157e+308
12386      *
12387      * _.toFinite('3.2');
12388      * // => 3.2
12389      */
12390     function toFinite(value) {
12391       if (!value) {
12392         return value === 0 ? value : 0;
12393       }
12394       value = toNumber(value);
12395       if (value === INFINITY || value === -INFINITY) {
12396         var sign = (value < 0 ? -1 : 1);
12397         return sign * MAX_INTEGER;
12398       }
12399       return value === value ? value : 0;
12400     }
12401
12402     /**
12403      * Converts `value` to an integer.
12404      *
12405      * **Note:** This method is loosely based on
12406      * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
12407      *
12408      * @static
12409      * @memberOf _
12410      * @since 4.0.0
12411      * @category Lang
12412      * @param {*} value The value to convert.
12413      * @returns {number} Returns the converted integer.
12414      * @example
12415      *
12416      * _.toInteger(3.2);
12417      * // => 3
12418      *
12419      * _.toInteger(Number.MIN_VALUE);
12420      * // => 0
12421      *
12422      * _.toInteger(Infinity);
12423      * // => 1.7976931348623157e+308
12424      *
12425      * _.toInteger('3.2');
12426      * // => 3
12427      */
12428     function toInteger(value) {
12429       var result = toFinite(value),
12430           remainder = result % 1;
12431
12432       return result === result ? (remainder ? result - remainder : result) : 0;
12433     }
12434
12435     /**
12436      * Converts `value` to an integer suitable for use as the length of an
12437      * array-like object.
12438      *
12439      * **Note:** This method is based on
12440      * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
12441      *
12442      * @static
12443      * @memberOf _
12444      * @since 4.0.0
12445      * @category Lang
12446      * @param {*} value The value to convert.
12447      * @returns {number} Returns the converted integer.
12448      * @example
12449      *
12450      * _.toLength(3.2);
12451      * // => 3
12452      *
12453      * _.toLength(Number.MIN_VALUE);
12454      * // => 0
12455      *
12456      * _.toLength(Infinity);
12457      * // => 4294967295
12458      *
12459      * _.toLength('3.2');
12460      * // => 3
12461      */
12462     function toLength(value) {
12463       return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
12464     }
12465
12466     /**
12467      * Converts `value` to a number.
12468      *
12469      * @static
12470      * @memberOf _
12471      * @since 4.0.0
12472      * @category Lang
12473      * @param {*} value The value to process.
12474      * @returns {number} Returns the number.
12475      * @example
12476      *
12477      * _.toNumber(3.2);
12478      * // => 3.2
12479      *
12480      * _.toNumber(Number.MIN_VALUE);
12481      * // => 5e-324
12482      *
12483      * _.toNumber(Infinity);
12484      * // => Infinity
12485      *
12486      * _.toNumber('3.2');
12487      * // => 3.2
12488      */
12489     function toNumber(value) {
12490       if (typeof value == 'number') {
12491         return value;
12492       }
12493       if (isSymbol(value)) {
12494         return NAN;
12495       }
12496       if (isObject(value)) {
12497         var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
12498         value = isObject(other) ? (other + '') : other;
12499       }
12500       if (typeof value != 'string') {
12501         return value === 0 ? value : +value;
12502       }
12503       value = value.replace(reTrim, '');
12504       var isBinary = reIsBinary.test(value);
12505       return (isBinary || reIsOctal.test(value))
12506         ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
12507         : (reIsBadHex.test(value) ? NAN : +value);
12508     }
12509
12510     /**
12511      * Converts `value` to a plain object flattening inherited enumerable string
12512      * keyed properties of `value` to own properties of the plain object.
12513      *
12514      * @static
12515      * @memberOf _
12516      * @since 3.0.0
12517      * @category Lang
12518      * @param {*} value The value to convert.
12519      * @returns {Object} Returns the converted plain object.
12520      * @example
12521      *
12522      * function Foo() {
12523      *   this.b = 2;
12524      * }
12525      *
12526      * Foo.prototype.c = 3;
12527      *
12528      * _.assign({ 'a': 1 }, new Foo);
12529      * // => { 'a': 1, 'b': 2 }
12530      *
12531      * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
12532      * // => { 'a': 1, 'b': 2, 'c': 3 }
12533      */
12534     function toPlainObject(value) {
12535       return copyObject(value, keysIn(value));
12536     }
12537
12538     /**
12539      * Converts `value` to a safe integer. A safe integer can be compared and
12540      * represented correctly.
12541      *
12542      * @static
12543      * @memberOf _
12544      * @since 4.0.0
12545      * @category Lang
12546      * @param {*} value The value to convert.
12547      * @returns {number} Returns the converted integer.
12548      * @example
12549      *
12550      * _.toSafeInteger(3.2);
12551      * // => 3
12552      *
12553      * _.toSafeInteger(Number.MIN_VALUE);
12554      * // => 0
12555      *
12556      * _.toSafeInteger(Infinity);
12557      * // => 9007199254740991
12558      *
12559      * _.toSafeInteger('3.2');
12560      * // => 3
12561      */
12562     function toSafeInteger(value) {
12563       return value
12564         ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER)
12565         : (value === 0 ? value : 0);
12566     }
12567
12568     /**
12569      * Converts `value` to a string. An empty string is returned for `null`
12570      * and `undefined` values. The sign of `-0` is preserved.
12571      *
12572      * @static
12573      * @memberOf _
12574      * @since 4.0.0
12575      * @category Lang
12576      * @param {*} value The value to convert.
12577      * @returns {string} Returns the converted string.
12578      * @example
12579      *
12580      * _.toString(null);
12581      * // => ''
12582      *
12583      * _.toString(-0);
12584      * // => '-0'
12585      *
12586      * _.toString([1, 2, 3]);
12587      * // => '1,2,3'
12588      */
12589     function toString(value) {
12590       return value == null ? '' : baseToString(value);
12591     }
12592
12593     /*------------------------------------------------------------------------*/
12594
12595     /**
12596      * Assigns own enumerable string keyed properties of source objects to the
12597      * destination object. Source objects are applied from left to right.
12598      * Subsequent sources overwrite property assignments of previous sources.
12599      *
12600      * **Note:** This method mutates `object` and is loosely based on
12601      * [`Object.assign`](https://mdn.io/Object/assign).
12602      *
12603      * @static
12604      * @memberOf _
12605      * @since 0.10.0
12606      * @category Object
12607      * @param {Object} object The destination object.
12608      * @param {...Object} [sources] The source objects.
12609      * @returns {Object} Returns `object`.
12610      * @see _.assignIn
12611      * @example
12612      *
12613      * function Foo() {
12614      *   this.a = 1;
12615      * }
12616      *
12617      * function Bar() {
12618      *   this.c = 3;
12619      * }
12620      *
12621      * Foo.prototype.b = 2;
12622      * Bar.prototype.d = 4;
12623      *
12624      * _.assign({ 'a': 0 }, new Foo, new Bar);
12625      * // => { 'a': 1, 'c': 3 }
12626      */
12627     var assign = createAssigner(function(object, source) {
12628       if (isPrototype(source) || isArrayLike(source)) {
12629         copyObject(source, keys(source), object);
12630         return;
12631       }
12632       for (var key in source) {
12633         if (hasOwnProperty.call(source, key)) {
12634           assignValue(object, key, source[key]);
12635         }
12636       }
12637     });
12638
12639     /**
12640      * This method is like `_.assign` except that it iterates over own and
12641      * inherited source properties.
12642      *
12643      * **Note:** This method mutates `object`.
12644      *
12645      * @static
12646      * @memberOf _
12647      * @since 4.0.0
12648      * @alias extend
12649      * @category Object
12650      * @param {Object} object The destination object.
12651      * @param {...Object} [sources] The source objects.
12652      * @returns {Object} Returns `object`.
12653      * @see _.assign
12654      * @example
12655      *
12656      * function Foo() {
12657      *   this.a = 1;
12658      * }
12659      *
12660      * function Bar() {
12661      *   this.c = 3;
12662      * }
12663      *
12664      * Foo.prototype.b = 2;
12665      * Bar.prototype.d = 4;
12666      *
12667      * _.assignIn({ 'a': 0 }, new Foo, new Bar);
12668      * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }
12669      */
12670     var assignIn = createAssigner(function(object, source) {
12671       copyObject(source, keysIn(source), object);
12672     });
12673
12674     /**
12675      * This method is like `_.assignIn` except that it accepts `customizer`
12676      * which is invoked to produce the assigned values. If `customizer` returns
12677      * `undefined`, assignment is handled by the method instead. The `customizer`
12678      * is invoked with five arguments: (objValue, srcValue, key, object, source).
12679      *
12680      * **Note:** This method mutates `object`.
12681      *
12682      * @static
12683      * @memberOf _
12684      * @since 4.0.0
12685      * @alias extendWith
12686      * @category Object
12687      * @param {Object} object The destination object.
12688      * @param {...Object} sources The source objects.
12689      * @param {Function} [customizer] The function to customize assigned values.
12690      * @returns {Object} Returns `object`.
12691      * @see _.assignWith
12692      * @example
12693      *
12694      * function customizer(objValue, srcValue) {
12695      *   return _.isUndefined(objValue) ? srcValue : objValue;
12696      * }
12697      *
12698      * var defaults = _.partialRight(_.assignInWith, customizer);
12699      *
12700      * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12701      * // => { 'a': 1, 'b': 2 }
12702      */
12703     var assignInWith = createAssigner(function(object, source, srcIndex, customizer) {
12704       copyObject(source, keysIn(source), object, customizer);
12705     });
12706
12707     /**
12708      * This method is like `_.assign` except that it accepts `customizer`
12709      * which is invoked to produce the assigned values. If `customizer` returns
12710      * `undefined`, assignment is handled by the method instead. The `customizer`
12711      * is invoked with five arguments: (objValue, srcValue, key, object, source).
12712      *
12713      * **Note:** This method mutates `object`.
12714      *
12715      * @static
12716      * @memberOf _
12717      * @since 4.0.0
12718      * @category Object
12719      * @param {Object} object The destination object.
12720      * @param {...Object} sources The source objects.
12721      * @param {Function} [customizer] The function to customize assigned values.
12722      * @returns {Object} Returns `object`.
12723      * @see _.assignInWith
12724      * @example
12725      *
12726      * function customizer(objValue, srcValue) {
12727      *   return _.isUndefined(objValue) ? srcValue : objValue;
12728      * }
12729      *
12730      * var defaults = _.partialRight(_.assignWith, customizer);
12731      *
12732      * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12733      * // => { 'a': 1, 'b': 2 }
12734      */
12735     var assignWith = createAssigner(function(object, source, srcIndex, customizer) {
12736       copyObject(source, keys(source), object, customizer);
12737     });
12738
12739     /**
12740      * Creates an array of values corresponding to `paths` of `object`.
12741      *
12742      * @static
12743      * @memberOf _
12744      * @since 1.0.0
12745      * @category Object
12746      * @param {Object} object The object to iterate over.
12747      * @param {...(string|string[])} [paths] The property paths to pick.
12748      * @returns {Array} Returns the picked values.
12749      * @example
12750      *
12751      * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
12752      *
12753      * _.at(object, ['a[0].b.c', 'a[1]']);
12754      * // => [3, 4]
12755      */
12756     var at = flatRest(baseAt);
12757
12758     /**
12759      * Creates an object that inherits from the `prototype` object. If a
12760      * `properties` object is given, its own enumerable string keyed properties
12761      * are assigned to the created object.
12762      *
12763      * @static
12764      * @memberOf _
12765      * @since 2.3.0
12766      * @category Object
12767      * @param {Object} prototype The object to inherit from.
12768      * @param {Object} [properties] The properties to assign to the object.
12769      * @returns {Object} Returns the new object.
12770      * @example
12771      *
12772      * function Shape() {
12773      *   this.x = 0;
12774      *   this.y = 0;
12775      * }
12776      *
12777      * function Circle() {
12778      *   Shape.call(this);
12779      * }
12780      *
12781      * Circle.prototype = _.create(Shape.prototype, {
12782      *   'constructor': Circle
12783      * });
12784      *
12785      * var circle = new Circle;
12786      * circle instanceof Circle;
12787      * // => true
12788      *
12789      * circle instanceof Shape;
12790      * // => true
12791      */
12792     function create(prototype, properties) {
12793       var result = baseCreate(prototype);
12794       return properties == null ? result : baseAssign(result, properties);
12795     }
12796
12797     /**
12798      * Assigns own and inherited enumerable string keyed properties of source
12799      * objects to the destination object for all destination properties that
12800      * resolve to `undefined`. Source objects are applied from left to right.
12801      * Once a property is set, additional values of the same property are ignored.
12802      *
12803      * **Note:** This method mutates `object`.
12804      *
12805      * @static
12806      * @since 0.1.0
12807      * @memberOf _
12808      * @category Object
12809      * @param {Object} object The destination object.
12810      * @param {...Object} [sources] The source objects.
12811      * @returns {Object} Returns `object`.
12812      * @see _.defaultsDeep
12813      * @example
12814      *
12815      * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12816      * // => { 'a': 1, 'b': 2 }
12817      */
12818     var defaults = baseRest(function(args) {
12819       args.push(undefined, customDefaultsAssignIn);
12820       return apply(assignInWith, undefined, args);
12821     });
12822
12823     /**
12824      * This method is like `_.defaults` except that it recursively assigns
12825      * default properties.
12826      *
12827      * **Note:** This method mutates `object`.
12828      *
12829      * @static
12830      * @memberOf _
12831      * @since 3.10.0
12832      * @category Object
12833      * @param {Object} object The destination object.
12834      * @param {...Object} [sources] The source objects.
12835      * @returns {Object} Returns `object`.
12836      * @see _.defaults
12837      * @example
12838      *
12839      * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
12840      * // => { 'a': { 'b': 2, 'c': 3 } }
12841      */
12842     var defaultsDeep = baseRest(function(args) {
12843       args.push(undefined, customDefaultsMerge);
12844       return apply(mergeWith, undefined, args);
12845     });
12846
12847     /**
12848      * This method is like `_.find` except that it returns the key of the first
12849      * element `predicate` returns truthy for instead of the element itself.
12850      *
12851      * @static
12852      * @memberOf _
12853      * @since 1.1.0
12854      * @category Object
12855      * @param {Object} object The object to inspect.
12856      * @param {Function} [predicate=_.identity] The function invoked per iteration.
12857      * @returns {string|undefined} Returns the key of the matched element,
12858      *  else `undefined`.
12859      * @example
12860      *
12861      * var users = {
12862      *   'barney':  { 'age': 36, 'active': true },
12863      *   'fred':    { 'age': 40, 'active': false },
12864      *   'pebbles': { 'age': 1,  'active': true }
12865      * };
12866      *
12867      * _.findKey(users, function(o) { return o.age < 40; });
12868      * // => 'barney' (iteration order is not guaranteed)
12869      *
12870      * // The `_.matches` iteratee shorthand.
12871      * _.findKey(users, { 'age': 1, 'active': true });
12872      * // => 'pebbles'
12873      *
12874      * // The `_.matchesProperty` iteratee shorthand.
12875      * _.findKey(users, ['active', false]);
12876      * // => 'fred'
12877      *
12878      * // The `_.property` iteratee shorthand.
12879      * _.findKey(users, 'active');
12880      * // => 'barney'
12881      */
12882     function findKey(object, predicate) {
12883       return baseFindKey(object, getIteratee(predicate, 3), baseForOwn);
12884     }
12885
12886     /**
12887      * This method is like `_.findKey` except that it iterates over elements of
12888      * a collection in the opposite order.
12889      *
12890      * @static
12891      * @memberOf _
12892      * @since 2.0.0
12893      * @category Object
12894      * @param {Object} object The object to inspect.
12895      * @param {Function} [predicate=_.identity] The function invoked per iteration.
12896      * @returns {string|undefined} Returns the key of the matched element,
12897      *  else `undefined`.
12898      * @example
12899      *
12900      * var users = {
12901      *   'barney':  { 'age': 36, 'active': true },
12902      *   'fred':    { 'age': 40, 'active': false },
12903      *   'pebbles': { 'age': 1,  'active': true }
12904      * };
12905      *
12906      * _.findLastKey(users, function(o) { return o.age < 40; });
12907      * // => returns 'pebbles' assuming `_.findKey` returns 'barney'
12908      *
12909      * // The `_.matches` iteratee shorthand.
12910      * _.findLastKey(users, { 'age': 36, 'active': true });
12911      * // => 'barney'
12912      *
12913      * // The `_.matchesProperty` iteratee shorthand.
12914      * _.findLastKey(users, ['active', false]);
12915      * // => 'fred'
12916      *
12917      * // The `_.property` iteratee shorthand.
12918      * _.findLastKey(users, 'active');
12919      * // => 'pebbles'
12920      */
12921     function findLastKey(object, predicate) {
12922       return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight);
12923     }
12924
12925     /**
12926      * Iterates over own and inherited enumerable string keyed properties of an
12927      * object and invokes `iteratee` for each property. The iteratee is invoked
12928      * with three arguments: (value, key, object). Iteratee functions may exit
12929      * iteration early by explicitly returning `false`.
12930      *
12931      * @static
12932      * @memberOf _
12933      * @since 0.3.0
12934      * @category Object
12935      * @param {Object} object The object to iterate over.
12936      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12937      * @returns {Object} Returns `object`.
12938      * @see _.forInRight
12939      * @example
12940      *
12941      * function Foo() {
12942      *   this.a = 1;
12943      *   this.b = 2;
12944      * }
12945      *
12946      * Foo.prototype.c = 3;
12947      *
12948      * _.forIn(new Foo, function(value, key) {
12949      *   console.log(key);
12950      * });
12951      * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
12952      */
12953     function forIn(object, iteratee) {
12954       return object == null
12955         ? object
12956         : baseFor(object, getIteratee(iteratee, 3), keysIn);
12957     }
12958
12959     /**
12960      * This method is like `_.forIn` except that it iterates over properties of
12961      * `object` in the opposite order.
12962      *
12963      * @static
12964      * @memberOf _
12965      * @since 2.0.0
12966      * @category Object
12967      * @param {Object} object The object to iterate over.
12968      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12969      * @returns {Object} Returns `object`.
12970      * @see _.forIn
12971      * @example
12972      *
12973      * function Foo() {
12974      *   this.a = 1;
12975      *   this.b = 2;
12976      * }
12977      *
12978      * Foo.prototype.c = 3;
12979      *
12980      * _.forInRight(new Foo, function(value, key) {
12981      *   console.log(key);
12982      * });
12983      * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
12984      */
12985     function forInRight(object, iteratee) {
12986       return object == null
12987         ? object
12988         : baseForRight(object, getIteratee(iteratee, 3), keysIn);
12989     }
12990
12991     /**
12992      * Iterates over own enumerable string keyed properties of an object and
12993      * invokes `iteratee` for each property. The iteratee is invoked with three
12994      * arguments: (value, key, object). Iteratee functions may exit iteration
12995      * early by explicitly returning `false`.
12996      *
12997      * @static
12998      * @memberOf _
12999      * @since 0.3.0
13000      * @category Object
13001      * @param {Object} object The object to iterate over.
13002      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13003      * @returns {Object} Returns `object`.
13004      * @see _.forOwnRight
13005      * @example
13006      *
13007      * function Foo() {
13008      *   this.a = 1;
13009      *   this.b = 2;
13010      * }
13011      *
13012      * Foo.prototype.c = 3;
13013      *
13014      * _.forOwn(new Foo, function(value, key) {
13015      *   console.log(key);
13016      * });
13017      * // => Logs 'a' then 'b' (iteration order is not guaranteed).
13018      */
13019     function forOwn(object, iteratee) {
13020       return object && baseForOwn(object, getIteratee(iteratee, 3));
13021     }
13022
13023     /**
13024      * This method is like `_.forOwn` except that it iterates over properties of
13025      * `object` in the opposite order.
13026      *
13027      * @static
13028      * @memberOf _
13029      * @since 2.0.0
13030      * @category Object
13031      * @param {Object} object The object to iterate over.
13032      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13033      * @returns {Object} Returns `object`.
13034      * @see _.forOwn
13035      * @example
13036      *
13037      * function Foo() {
13038      *   this.a = 1;
13039      *   this.b = 2;
13040      * }
13041      *
13042      * Foo.prototype.c = 3;
13043      *
13044      * _.forOwnRight(new Foo, function(value, key) {
13045      *   console.log(key);
13046      * });
13047      * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
13048      */
13049     function forOwnRight(object, iteratee) {
13050       return object && baseForOwnRight(object, getIteratee(iteratee, 3));
13051     }
13052
13053     /**
13054      * Creates an array of function property names from own enumerable properties
13055      * of `object`.
13056      *
13057      * @static
13058      * @since 0.1.0
13059      * @memberOf _
13060      * @category Object
13061      * @param {Object} object The object to inspect.
13062      * @returns {Array} Returns the function names.
13063      * @see _.functionsIn
13064      * @example
13065      *
13066      * function Foo() {
13067      *   this.a = _.constant('a');
13068      *   this.b = _.constant('b');
13069      * }
13070      *
13071      * Foo.prototype.c = _.constant('c');
13072      *
13073      * _.functions(new Foo);
13074      * // => ['a', 'b']
13075      */
13076     function functions(object) {
13077       return object == null ? [] : baseFunctions(object, keys(object));
13078     }
13079
13080     /**
13081      * Creates an array of function property names from own and inherited
13082      * enumerable properties of `object`.
13083      *
13084      * @static
13085      * @memberOf _
13086      * @since 4.0.0
13087      * @category Object
13088      * @param {Object} object The object to inspect.
13089      * @returns {Array} Returns the function names.
13090      * @see _.functions
13091      * @example
13092      *
13093      * function Foo() {
13094      *   this.a = _.constant('a');
13095      *   this.b = _.constant('b');
13096      * }
13097      *
13098      * Foo.prototype.c = _.constant('c');
13099      *
13100      * _.functionsIn(new Foo);
13101      * // => ['a', 'b', 'c']
13102      */
13103     function functionsIn(object) {
13104       return object == null ? [] : baseFunctions(object, keysIn(object));
13105     }
13106
13107     /**
13108      * Gets the value at `path` of `object`. If the resolved value is
13109      * `undefined`, the `defaultValue` is returned in its place.
13110      *
13111      * @static
13112      * @memberOf _
13113      * @since 3.7.0
13114      * @category Object
13115      * @param {Object} object The object to query.
13116      * @param {Array|string} path The path of the property to get.
13117      * @param {*} [defaultValue] The value returned for `undefined` resolved values.
13118      * @returns {*} Returns the resolved value.
13119      * @example
13120      *
13121      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13122      *
13123      * _.get(object, 'a[0].b.c');
13124      * // => 3
13125      *
13126      * _.get(object, ['a', '0', 'b', 'c']);
13127      * // => 3
13128      *
13129      * _.get(object, 'a.b.c', 'default');
13130      * // => 'default'
13131      */
13132     function get(object, path, defaultValue) {
13133       var result = object == null ? undefined : baseGet(object, path);
13134       return result === undefined ? defaultValue : result;
13135     }
13136
13137     /**
13138      * Checks if `path` is a direct property of `object`.
13139      *
13140      * @static
13141      * @since 0.1.0
13142      * @memberOf _
13143      * @category Object
13144      * @param {Object} object The object to query.
13145      * @param {Array|string} path The path to check.
13146      * @returns {boolean} Returns `true` if `path` exists, else `false`.
13147      * @example
13148      *
13149      * var object = { 'a': { 'b': 2 } };
13150      * var other = _.create({ 'a': _.create({ 'b': 2 }) });
13151      *
13152      * _.has(object, 'a');
13153      * // => true
13154      *
13155      * _.has(object, 'a.b');
13156      * // => true
13157      *
13158      * _.has(object, ['a', 'b']);
13159      * // => true
13160      *
13161      * _.has(other, 'a');
13162      * // => false
13163      */
13164     function has(object, path) {
13165       return object != null && hasPath(object, path, baseHas);
13166     }
13167
13168     /**
13169      * Checks if `path` is a direct or inherited property of `object`.
13170      *
13171      * @static
13172      * @memberOf _
13173      * @since 4.0.0
13174      * @category Object
13175      * @param {Object} object The object to query.
13176      * @param {Array|string} path The path to check.
13177      * @returns {boolean} Returns `true` if `path` exists, else `false`.
13178      * @example
13179      *
13180      * var object = _.create({ 'a': _.create({ 'b': 2 }) });
13181      *
13182      * _.hasIn(object, 'a');
13183      * // => true
13184      *
13185      * _.hasIn(object, 'a.b');
13186      * // => true
13187      *
13188      * _.hasIn(object, ['a', 'b']);
13189      * // => true
13190      *
13191      * _.hasIn(object, 'b');
13192      * // => false
13193      */
13194     function hasIn(object, path) {
13195       return object != null && hasPath(object, path, baseHasIn);
13196     }
13197
13198     /**
13199      * Creates an object composed of the inverted keys and values of `object`.
13200      * If `object` contains duplicate values, subsequent values overwrite
13201      * property assignments of previous values.
13202      *
13203      * @static
13204      * @memberOf _
13205      * @since 0.7.0
13206      * @category Object
13207      * @param {Object} object The object to invert.
13208      * @returns {Object} Returns the new inverted object.
13209      * @example
13210      *
13211      * var object = { 'a': 1, 'b': 2, 'c': 1 };
13212      *
13213      * _.invert(object);
13214      * // => { '1': 'c', '2': 'b' }
13215      */
13216     var invert = createInverter(function(result, value, key) {
13217       result[value] = key;
13218     }, constant(identity));
13219
13220     /**
13221      * This method is like `_.invert` except that the inverted object is generated
13222      * from the results of running each element of `object` thru `iteratee`. The
13223      * corresponding inverted value of each inverted key is an array of keys
13224      * responsible for generating the inverted value. The iteratee is invoked
13225      * with one argument: (value).
13226      *
13227      * @static
13228      * @memberOf _
13229      * @since 4.1.0
13230      * @category Object
13231      * @param {Object} object The object to invert.
13232      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
13233      * @returns {Object} Returns the new inverted object.
13234      * @example
13235      *
13236      * var object = { 'a': 1, 'b': 2, 'c': 1 };
13237      *
13238      * _.invertBy(object);
13239      * // => { '1': ['a', 'c'], '2': ['b'] }
13240      *
13241      * _.invertBy(object, function(value) {
13242      *   return 'group' + value;
13243      * });
13244      * // => { 'group1': ['a', 'c'], 'group2': ['b'] }
13245      */
13246     var invertBy = createInverter(function(result, value, key) {
13247       if (hasOwnProperty.call(result, value)) {
13248         result[value].push(key);
13249       } else {
13250         result[value] = [key];
13251       }
13252     }, getIteratee);
13253
13254     /**
13255      * Invokes the method at `path` of `object`.
13256      *
13257      * @static
13258      * @memberOf _
13259      * @since 4.0.0
13260      * @category Object
13261      * @param {Object} object The object to query.
13262      * @param {Array|string} path The path of the method to invoke.
13263      * @param {...*} [args] The arguments to invoke the method with.
13264      * @returns {*} Returns the result of the invoked method.
13265      * @example
13266      *
13267      * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
13268      *
13269      * _.invoke(object, 'a[0].b.c.slice', 1, 3);
13270      * // => [2, 3]
13271      */
13272     var invoke = baseRest(baseInvoke);
13273
13274     /**
13275      * Creates an array of the own enumerable property names of `object`.
13276      *
13277      * **Note:** Non-object values are coerced to objects. See the
13278      * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
13279      * for more details.
13280      *
13281      * @static
13282      * @since 0.1.0
13283      * @memberOf _
13284      * @category Object
13285      * @param {Object} object The object to query.
13286      * @returns {Array} Returns the array of property names.
13287      * @example
13288      *
13289      * function Foo() {
13290      *   this.a = 1;
13291      *   this.b = 2;
13292      * }
13293      *
13294      * Foo.prototype.c = 3;
13295      *
13296      * _.keys(new Foo);
13297      * // => ['a', 'b'] (iteration order is not guaranteed)
13298      *
13299      * _.keys('hi');
13300      * // => ['0', '1']
13301      */
13302     function keys(object) {
13303       return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
13304     }
13305
13306     /**
13307      * Creates an array of the own and inherited enumerable property names of `object`.
13308      *
13309      * **Note:** Non-object values are coerced to objects.
13310      *
13311      * @static
13312      * @memberOf _
13313      * @since 3.0.0
13314      * @category Object
13315      * @param {Object} object The object to query.
13316      * @returns {Array} Returns the array of property names.
13317      * @example
13318      *
13319      * function Foo() {
13320      *   this.a = 1;
13321      *   this.b = 2;
13322      * }
13323      *
13324      * Foo.prototype.c = 3;
13325      *
13326      * _.keysIn(new Foo);
13327      * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
13328      */
13329     function keysIn(object) {
13330       return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
13331     }
13332
13333     /**
13334      * The opposite of `_.mapValues`; this method creates an object with the
13335      * same values as `object` and keys generated by running each own enumerable
13336      * string keyed property of `object` thru `iteratee`. The iteratee is invoked
13337      * with three arguments: (value, key, object).
13338      *
13339      * @static
13340      * @memberOf _
13341      * @since 3.8.0
13342      * @category Object
13343      * @param {Object} object The object to iterate over.
13344      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13345      * @returns {Object} Returns the new mapped object.
13346      * @see _.mapValues
13347      * @example
13348      *
13349      * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
13350      *   return key + value;
13351      * });
13352      * // => { 'a1': 1, 'b2': 2 }
13353      */
13354     function mapKeys(object, iteratee) {
13355       var result = {};
13356       iteratee = getIteratee(iteratee, 3);
13357
13358       baseForOwn(object, function(value, key, object) {
13359         baseAssignValue(result, iteratee(value, key, object), value);
13360       });
13361       return result;
13362     }
13363
13364     /**
13365      * Creates an object with the same keys as `object` and values generated
13366      * by running each own enumerable string keyed property of `object` thru
13367      * `iteratee`. The iteratee is invoked with three arguments:
13368      * (value, key, object).
13369      *
13370      * @static
13371      * @memberOf _
13372      * @since 2.4.0
13373      * @category Object
13374      * @param {Object} object The object to iterate over.
13375      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13376      * @returns {Object} Returns the new mapped object.
13377      * @see _.mapKeys
13378      * @example
13379      *
13380      * var users = {
13381      *   'fred':    { 'user': 'fred',    'age': 40 },
13382      *   'pebbles': { 'user': 'pebbles', 'age': 1 }
13383      * };
13384      *
13385      * _.mapValues(users, function(o) { return o.age; });
13386      * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
13387      *
13388      * // The `_.property` iteratee shorthand.
13389      * _.mapValues(users, 'age');
13390      * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
13391      */
13392     function mapValues(object, iteratee) {
13393       var result = {};
13394       iteratee = getIteratee(iteratee, 3);
13395
13396       baseForOwn(object, function(value, key, object) {
13397         baseAssignValue(result, key, iteratee(value, key, object));
13398       });
13399       return result;
13400     }
13401
13402     /**
13403      * This method is like `_.assign` except that it recursively merges own and
13404      * inherited enumerable string keyed properties of source objects into the
13405      * destination object. Source properties that resolve to `undefined` are
13406      * skipped if a destination value exists. Array and plain object properties
13407      * are merged recursively. Other objects and value types are overridden by
13408      * assignment. Source objects are applied from left to right. Subsequent
13409      * sources overwrite property assignments of previous sources.
13410      *
13411      * **Note:** This method mutates `object`.
13412      *
13413      * @static
13414      * @memberOf _
13415      * @since 0.5.0
13416      * @category Object
13417      * @param {Object} object The destination object.
13418      * @param {...Object} [sources] The source objects.
13419      * @returns {Object} Returns `object`.
13420      * @example
13421      *
13422      * var object = {
13423      *   'a': [{ 'b': 2 }, { 'd': 4 }]
13424      * };
13425      *
13426      * var other = {
13427      *   'a': [{ 'c': 3 }, { 'e': 5 }]
13428      * };
13429      *
13430      * _.merge(object, other);
13431      * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
13432      */
13433     var merge = createAssigner(function(object, source, srcIndex) {
13434       baseMerge(object, source, srcIndex);
13435     });
13436
13437     /**
13438      * This method is like `_.merge` except that it accepts `customizer` which
13439      * is invoked to produce the merged values of the destination and source
13440      * properties. If `customizer` returns `undefined`, merging is handled by the
13441      * method instead. The `customizer` is invoked with six arguments:
13442      * (objValue, srcValue, key, object, source, stack).
13443      *
13444      * **Note:** This method mutates `object`.
13445      *
13446      * @static
13447      * @memberOf _
13448      * @since 4.0.0
13449      * @category Object
13450      * @param {Object} object The destination object.
13451      * @param {...Object} sources The source objects.
13452      * @param {Function} customizer The function to customize assigned values.
13453      * @returns {Object} Returns `object`.
13454      * @example
13455      *
13456      * function customizer(objValue, srcValue) {
13457      *   if (_.isArray(objValue)) {
13458      *     return objValue.concat(srcValue);
13459      *   }
13460      * }
13461      *
13462      * var object = { 'a': [1], 'b': [2] };
13463      * var other = { 'a': [3], 'b': [4] };
13464      *
13465      * _.mergeWith(object, other, customizer);
13466      * // => { 'a': [1, 3], 'b': [2, 4] }
13467      */
13468     var mergeWith = createAssigner(function(object, source, srcIndex, customizer) {
13469       baseMerge(object, source, srcIndex, customizer);
13470     });
13471
13472     /**
13473      * The opposite of `_.pick`; this method creates an object composed of the
13474      * own and inherited enumerable property paths of `object` that are not omitted.
13475      *
13476      * **Note:** This method is considerably slower than `_.pick`.
13477      *
13478      * @static
13479      * @since 0.1.0
13480      * @memberOf _
13481      * @category Object
13482      * @param {Object} object The source object.
13483      * @param {...(string|string[])} [paths] The property paths to omit.
13484      * @returns {Object} Returns the new object.
13485      * @example
13486      *
13487      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13488      *
13489      * _.omit(object, ['a', 'c']);
13490      * // => { 'b': '2' }
13491      */
13492     var omit = flatRest(function(object, paths) {
13493       var result = {};
13494       if (object == null) {
13495         return result;
13496       }
13497       var isDeep = false;
13498       paths = arrayMap(paths, function(path) {
13499         path = castPath(path, object);
13500         isDeep || (isDeep = path.length > 1);
13501         return path;
13502       });
13503       copyObject(object, getAllKeysIn(object), result);
13504       if (isDeep) {
13505         result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);
13506       }
13507       var length = paths.length;
13508       while (length--) {
13509         baseUnset(result, paths[length]);
13510       }
13511       return result;
13512     });
13513
13514     /**
13515      * The opposite of `_.pickBy`; this method creates an object composed of
13516      * the own and inherited enumerable string keyed properties of `object` that
13517      * `predicate` doesn't return truthy for. The predicate is invoked with two
13518      * arguments: (value, key).
13519      *
13520      * @static
13521      * @memberOf _
13522      * @since 4.0.0
13523      * @category Object
13524      * @param {Object} object The source object.
13525      * @param {Function} [predicate=_.identity] The function invoked per property.
13526      * @returns {Object} Returns the new object.
13527      * @example
13528      *
13529      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13530      *
13531      * _.omitBy(object, _.isNumber);
13532      * // => { 'b': '2' }
13533      */
13534     function omitBy(object, predicate) {
13535       return pickBy(object, negate(getIteratee(predicate)));
13536     }
13537
13538     /**
13539      * Creates an object composed of the picked `object` properties.
13540      *
13541      * @static
13542      * @since 0.1.0
13543      * @memberOf _
13544      * @category Object
13545      * @param {Object} object The source object.
13546      * @param {...(string|string[])} [paths] The property paths to pick.
13547      * @returns {Object} Returns the new object.
13548      * @example
13549      *
13550      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13551      *
13552      * _.pick(object, ['a', 'c']);
13553      * // => { 'a': 1, 'c': 3 }
13554      */
13555     var pick = flatRest(function(object, paths) {
13556       return object == null ? {} : basePick(object, paths);
13557     });
13558
13559     /**
13560      * Creates an object composed of the `object` properties `predicate` returns
13561      * truthy for. The predicate is invoked with two arguments: (value, key).
13562      *
13563      * @static
13564      * @memberOf _
13565      * @since 4.0.0
13566      * @category Object
13567      * @param {Object} object The source object.
13568      * @param {Function} [predicate=_.identity] The function invoked per property.
13569      * @returns {Object} Returns the new object.
13570      * @example
13571      *
13572      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13573      *
13574      * _.pickBy(object, _.isNumber);
13575      * // => { 'a': 1, 'c': 3 }
13576      */
13577     function pickBy(object, predicate) {
13578       if (object == null) {
13579         return {};
13580       }
13581       var props = arrayMap(getAllKeysIn(object), function(prop) {
13582         return [prop];
13583       });
13584       predicate = getIteratee(predicate);
13585       return basePickBy(object, props, function(value, path) {
13586         return predicate(value, path[0]);
13587       });
13588     }
13589
13590     /**
13591      * This method is like `_.get` except that if the resolved value is a
13592      * function it's invoked with the `this` binding of its parent object and
13593      * its result is returned.
13594      *
13595      * @static
13596      * @since 0.1.0
13597      * @memberOf _
13598      * @category Object
13599      * @param {Object} object The object to query.
13600      * @param {Array|string} path The path of the property to resolve.
13601      * @param {*} [defaultValue] The value returned for `undefined` resolved values.
13602      * @returns {*} Returns the resolved value.
13603      * @example
13604      *
13605      * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
13606      *
13607      * _.result(object, 'a[0].b.c1');
13608      * // => 3
13609      *
13610      * _.result(object, 'a[0].b.c2');
13611      * // => 4
13612      *
13613      * _.result(object, 'a[0].b.c3', 'default');
13614      * // => 'default'
13615      *
13616      * _.result(object, 'a[0].b.c3', _.constant('default'));
13617      * // => 'default'
13618      */
13619     function result(object, path, defaultValue) {
13620       path = castPath(path, object);
13621
13622       var index = -1,
13623           length = path.length;
13624
13625       // Ensure the loop is entered when path is empty.
13626       if (!length) {
13627         length = 1;
13628         object = undefined;
13629       }
13630       while (++index < length) {
13631         var value = object == null ? undefined : object[toKey(path[index])];
13632         if (value === undefined) {
13633           index = length;
13634           value = defaultValue;
13635         }
13636         object = isFunction(value) ? value.call(object) : value;
13637       }
13638       return object;
13639     }
13640
13641     /**
13642      * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
13643      * it's created. Arrays are created for missing index properties while objects
13644      * are created for all other missing properties. Use `_.setWith` to customize
13645      * `path` creation.
13646      *
13647      * **Note:** This method mutates `object`.
13648      *
13649      * @static
13650      * @memberOf _
13651      * @since 3.7.0
13652      * @category Object
13653      * @param {Object} object The object to modify.
13654      * @param {Array|string} path The path of the property to set.
13655      * @param {*} value The value to set.
13656      * @returns {Object} Returns `object`.
13657      * @example
13658      *
13659      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13660      *
13661      * _.set(object, 'a[0].b.c', 4);
13662      * console.log(object.a[0].b.c);
13663      * // => 4
13664      *
13665      * _.set(object, ['x', '0', 'y', 'z'], 5);
13666      * console.log(object.x[0].y.z);
13667      * // => 5
13668      */
13669     function set(object, path, value) {
13670       return object == null ? object : baseSet(object, path, value);
13671     }
13672
13673     /**
13674      * This method is like `_.set` except that it accepts `customizer` which is
13675      * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
13676      * path creation is handled by the method instead. The `customizer` is invoked
13677      * with three arguments: (nsValue, key, nsObject).
13678      *
13679      * **Note:** This method mutates `object`.
13680      *
13681      * @static
13682      * @memberOf _
13683      * @since 4.0.0
13684      * @category Object
13685      * @param {Object} object The object to modify.
13686      * @param {Array|string} path The path of the property to set.
13687      * @param {*} value The value to set.
13688      * @param {Function} [customizer] The function to customize assigned values.
13689      * @returns {Object} Returns `object`.
13690      * @example
13691      *
13692      * var object = {};
13693      *
13694      * _.setWith(object, '[0][1]', 'a', Object);
13695      * // => { '0': { '1': 'a' } }
13696      */
13697     function setWith(object, path, value, customizer) {
13698       customizer = typeof customizer == 'function' ? customizer : undefined;
13699       return object == null ? object : baseSet(object, path, value, customizer);
13700     }
13701
13702     /**
13703      * Creates an array of own enumerable string keyed-value pairs for `object`
13704      * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
13705      * entries are returned.
13706      *
13707      * @static
13708      * @memberOf _
13709      * @since 4.0.0
13710      * @alias entries
13711      * @category Object
13712      * @param {Object} object The object to query.
13713      * @returns {Array} Returns the key-value pairs.
13714      * @example
13715      *
13716      * function Foo() {
13717      *   this.a = 1;
13718      *   this.b = 2;
13719      * }
13720      *
13721      * Foo.prototype.c = 3;
13722      *
13723      * _.toPairs(new Foo);
13724      * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
13725      */
13726     var toPairs = createToPairs(keys);
13727
13728     /**
13729      * Creates an array of own and inherited enumerable string keyed-value pairs
13730      * for `object` which can be consumed by `_.fromPairs`. If `object` is a map
13731      * or set, its entries are returned.
13732      *
13733      * @static
13734      * @memberOf _
13735      * @since 4.0.0
13736      * @alias entriesIn
13737      * @category Object
13738      * @param {Object} object The object to query.
13739      * @returns {Array} Returns the key-value pairs.
13740      * @example
13741      *
13742      * function Foo() {
13743      *   this.a = 1;
13744      *   this.b = 2;
13745      * }
13746      *
13747      * Foo.prototype.c = 3;
13748      *
13749      * _.toPairsIn(new Foo);
13750      * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
13751      */
13752     var toPairsIn = createToPairs(keysIn);
13753
13754     /**
13755      * An alternative to `_.reduce`; this method transforms `object` to a new
13756      * `accumulator` object which is the result of running each of its own
13757      * enumerable string keyed properties thru `iteratee`, with each invocation
13758      * potentially mutating the `accumulator` object. If `accumulator` is not
13759      * provided, a new object with the same `[[Prototype]]` will be used. The
13760      * iteratee is invoked with four arguments: (accumulator, value, key, object).
13761      * Iteratee functions may exit iteration early by explicitly returning `false`.
13762      *
13763      * @static
13764      * @memberOf _
13765      * @since 1.3.0
13766      * @category Object
13767      * @param {Object} object The object to iterate over.
13768      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13769      * @param {*} [accumulator] The custom accumulator value.
13770      * @returns {*} Returns the accumulated value.
13771      * @example
13772      *
13773      * _.transform([2, 3, 4], function(result, n) {
13774      *   result.push(n *= n);
13775      *   return n % 2 == 0;
13776      * }, []);
13777      * // => [4, 9]
13778      *
13779      * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
13780      *   (result[value] || (result[value] = [])).push(key);
13781      * }, {});
13782      * // => { '1': ['a', 'c'], '2': ['b'] }
13783      */
13784     function transform(object, iteratee, accumulator) {
13785       var isArr = isArray(object),
13786           isArrLike = isArr || isBuffer(object) || isTypedArray(object);
13787
13788       iteratee = getIteratee(iteratee, 4);
13789       if (accumulator == null) {
13790         var Ctor = object && object.constructor;
13791         if (isArrLike) {
13792           accumulator = isArr ? new Ctor : [];
13793         }
13794         else if (isObject(object)) {
13795           accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
13796         }
13797         else {
13798           accumulator = {};
13799         }
13800       }
13801       (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) {
13802         return iteratee(accumulator, value, index, object);
13803       });
13804       return accumulator;
13805     }
13806
13807     /**
13808      * Removes the property at `path` of `object`.
13809      *
13810      * **Note:** This method mutates `object`.
13811      *
13812      * @static
13813      * @memberOf _
13814      * @since 4.0.0
13815      * @category Object
13816      * @param {Object} object The object to modify.
13817      * @param {Array|string} path The path of the property to unset.
13818      * @returns {boolean} Returns `true` if the property is deleted, else `false`.
13819      * @example
13820      *
13821      * var object = { 'a': [{ 'b': { 'c': 7 } }] };
13822      * _.unset(object, 'a[0].b.c');
13823      * // => true
13824      *
13825      * console.log(object);
13826      * // => { 'a': [{ 'b': {} }] };
13827      *
13828      * _.unset(object, ['a', '0', 'b', 'c']);
13829      * // => true
13830      *
13831      * console.log(object);
13832      * // => { 'a': [{ 'b': {} }] };
13833      */
13834     function unset(object, path) {
13835       return object == null ? true : baseUnset(object, path);
13836     }
13837
13838     /**
13839      * This method is like `_.set` except that accepts `updater` to produce the
13840      * value to set. Use `_.updateWith` to customize `path` creation. The `updater`
13841      * is invoked with one argument: (value).
13842      *
13843      * **Note:** This method mutates `object`.
13844      *
13845      * @static
13846      * @memberOf _
13847      * @since 4.6.0
13848      * @category Object
13849      * @param {Object} object The object to modify.
13850      * @param {Array|string} path The path of the property to set.
13851      * @param {Function} updater The function to produce the updated value.
13852      * @returns {Object} Returns `object`.
13853      * @example
13854      *
13855      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13856      *
13857      * _.update(object, 'a[0].b.c', function(n) { return n * n; });
13858      * console.log(object.a[0].b.c);
13859      * // => 9
13860      *
13861      * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
13862      * console.log(object.x[0].y.z);
13863      * // => 0
13864      */
13865     function update(object, path, updater) {
13866       return object == null ? object : baseUpdate(object, path, castFunction(updater));
13867     }
13868
13869     /**
13870      * This method is like `_.update` except that it accepts `customizer` which is
13871      * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
13872      * path creation is handled by the method instead. The `customizer` is invoked
13873      * with three arguments: (nsValue, key, nsObject).
13874      *
13875      * **Note:** This method mutates `object`.
13876      *
13877      * @static
13878      * @memberOf _
13879      * @since 4.6.0
13880      * @category Object
13881      * @param {Object} object The object to modify.
13882      * @param {Array|string} path The path of the property to set.
13883      * @param {Function} updater The function to produce the updated value.
13884      * @param {Function} [customizer] The function to customize assigned values.
13885      * @returns {Object} Returns `object`.
13886      * @example
13887      *
13888      * var object = {};
13889      *
13890      * _.updateWith(object, '[0][1]', _.constant('a'), Object);
13891      * // => { '0': { '1': 'a' } }
13892      */
13893     function updateWith(object, path, updater, customizer) {
13894       customizer = typeof customizer == 'function' ? customizer : undefined;
13895       return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
13896     }
13897
13898     /**
13899      * Creates an array of the own enumerable string keyed property values of `object`.
13900      *
13901      * **Note:** Non-object values are coerced to objects.
13902      *
13903      * @static
13904      * @since 0.1.0
13905      * @memberOf _
13906      * @category Object
13907      * @param {Object} object The object to query.
13908      * @returns {Array} Returns the array of property values.
13909      * @example
13910      *
13911      * function Foo() {
13912      *   this.a = 1;
13913      *   this.b = 2;
13914      * }
13915      *
13916      * Foo.prototype.c = 3;
13917      *
13918      * _.values(new Foo);
13919      * // => [1, 2] (iteration order is not guaranteed)
13920      *
13921      * _.values('hi');
13922      * // => ['h', 'i']
13923      */
13924     function values(object) {
13925       return object == null ? [] : baseValues(object, keys(object));
13926     }
13927
13928     /**
13929      * Creates an array of the own and inherited enumerable string keyed property
13930      * values of `object`.
13931      *
13932      * **Note:** Non-object values are coerced to objects.
13933      *
13934      * @static
13935      * @memberOf _
13936      * @since 3.0.0
13937      * @category Object
13938      * @param {Object} object The object to query.
13939      * @returns {Array} Returns the array of property values.
13940      * @example
13941      *
13942      * function Foo() {
13943      *   this.a = 1;
13944      *   this.b = 2;
13945      * }
13946      *
13947      * Foo.prototype.c = 3;
13948      *
13949      * _.valuesIn(new Foo);
13950      * // => [1, 2, 3] (iteration order is not guaranteed)
13951      */
13952     function valuesIn(object) {
13953       return object == null ? [] : baseValues(object, keysIn(object));
13954     }
13955
13956     /*------------------------------------------------------------------------*/
13957
13958     /**
13959      * Clamps `number` within the inclusive `lower` and `upper` bounds.
13960      *
13961      * @static
13962      * @memberOf _
13963      * @since 4.0.0
13964      * @category Number
13965      * @param {number} number The number to clamp.
13966      * @param {number} [lower] The lower bound.
13967      * @param {number} upper The upper bound.
13968      * @returns {number} Returns the clamped number.
13969      * @example
13970      *
13971      * _.clamp(-10, -5, 5);
13972      * // => -5
13973      *
13974      * _.clamp(10, -5, 5);
13975      * // => 5
13976      */
13977     function clamp(number, lower, upper) {
13978       if (upper === undefined) {
13979         upper = lower;
13980         lower = undefined;
13981       }
13982       if (upper !== undefined) {
13983         upper = toNumber(upper);
13984         upper = upper === upper ? upper : 0;
13985       }
13986       if (lower !== undefined) {
13987         lower = toNumber(lower);
13988         lower = lower === lower ? lower : 0;
13989       }
13990       return baseClamp(toNumber(number), lower, upper);
13991     }
13992
13993     /**
13994      * Checks if `n` is between `start` and up to, but not including, `end`. If
13995      * `end` is not specified, it's set to `start` with `start` then set to `0`.
13996      * If `start` is greater than `end` the params are swapped to support
13997      * negative ranges.
13998      *
13999      * @static
14000      * @memberOf _
14001      * @since 3.3.0
14002      * @category Number
14003      * @param {number} number The number to check.
14004      * @param {number} [start=0] The start of the range.
14005      * @param {number} end The end of the range.
14006      * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
14007      * @see _.range, _.rangeRight
14008      * @example
14009      *
14010      * _.inRange(3, 2, 4);
14011      * // => true
14012      *
14013      * _.inRange(4, 8);
14014      * // => true
14015      *
14016      * _.inRange(4, 2);
14017      * // => false
14018      *
14019      * _.inRange(2, 2);
14020      * // => false
14021      *
14022      * _.inRange(1.2, 2);
14023      * // => true
14024      *
14025      * _.inRange(5.2, 4);
14026      * // => false
14027      *
14028      * _.inRange(-3, -2, -6);
14029      * // => true
14030      */
14031     function inRange(number, start, end) {
14032       start = toFinite(start);
14033       if (end === undefined) {
14034         end = start;
14035         start = 0;
14036       } else {
14037         end = toFinite(end);
14038       }
14039       number = toNumber(number);
14040       return baseInRange(number, start, end);
14041     }
14042
14043     /**
14044      * Produces a random number between the inclusive `lower` and `upper` bounds.
14045      * If only one argument is provided a number between `0` and the given number
14046      * is returned. If `floating` is `true`, or either `lower` or `upper` are
14047      * floats, a floating-point number is returned instead of an integer.
14048      *
14049      * **Note:** JavaScript follows the IEEE-754 standard for resolving
14050      * floating-point values which can produce unexpected results.
14051      *
14052      * @static
14053      * @memberOf _
14054      * @since 0.7.0
14055      * @category Number
14056      * @param {number} [lower=0] The lower bound.
14057      * @param {number} [upper=1] The upper bound.
14058      * @param {boolean} [floating] Specify returning a floating-point number.
14059      * @returns {number} Returns the random number.
14060      * @example
14061      *
14062      * _.random(0, 5);
14063      * // => an integer between 0 and 5
14064      *
14065      * _.random(5);
14066      * // => also an integer between 0 and 5
14067      *
14068      * _.random(5, true);
14069      * // => a floating-point number between 0 and 5
14070      *
14071      * _.random(1.2, 5.2);
14072      * // => a floating-point number between 1.2 and 5.2
14073      */
14074     function random(lower, upper, floating) {
14075       if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {
14076         upper = floating = undefined;
14077       }
14078       if (floating === undefined) {
14079         if (typeof upper == 'boolean') {
14080           floating = upper;
14081           upper = undefined;
14082         }
14083         else if (typeof lower == 'boolean') {
14084           floating = lower;
14085           lower = undefined;
14086         }
14087       }
14088       if (lower === undefined && upper === undefined) {
14089         lower = 0;
14090         upper = 1;
14091       }
14092       else {
14093         lower = toFinite(lower);
14094         if (upper === undefined) {
14095           upper = lower;
14096           lower = 0;
14097         } else {
14098           upper = toFinite(upper);
14099         }
14100       }
14101       if (lower > upper) {
14102         var temp = lower;
14103         lower = upper;
14104         upper = temp;
14105       }
14106       if (floating || lower % 1 || upper % 1) {
14107         var rand = nativeRandom();
14108         return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper);
14109       }
14110       return baseRandom(lower, upper);
14111     }
14112
14113     /*------------------------------------------------------------------------*/
14114
14115     /**
14116      * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
14117      *
14118      * @static
14119      * @memberOf _
14120      * @since 3.0.0
14121      * @category String
14122      * @param {string} [string=''] The string to convert.
14123      * @returns {string} Returns the camel cased string.
14124      * @example
14125      *
14126      * _.camelCase('Foo Bar');
14127      * // => 'fooBar'
14128      *
14129      * _.camelCase('--foo-bar--');
14130      * // => 'fooBar'
14131      *
14132      * _.camelCase('__FOO_BAR__');
14133      * // => 'fooBar'
14134      */
14135     var camelCase = createCompounder(function(result, word, index) {
14136       word = word.toLowerCase();
14137       return result + (index ? capitalize(word) : word);
14138     });
14139
14140     /**
14141      * Converts the first character of `string` to upper case and the remaining
14142      * to lower case.
14143      *
14144      * @static
14145      * @memberOf _
14146      * @since 3.0.0
14147      * @category String
14148      * @param {string} [string=''] The string to capitalize.
14149      * @returns {string} Returns the capitalized string.
14150      * @example
14151      *
14152      * _.capitalize('FRED');
14153      * // => 'Fred'
14154      */
14155     function capitalize(string) {
14156       return upperFirst(toString(string).toLowerCase());
14157     }
14158
14159     /**
14160      * Deburrs `string` by converting
14161      * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
14162      * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
14163      * letters to basic Latin letters and removing
14164      * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
14165      *
14166      * @static
14167      * @memberOf _
14168      * @since 3.0.0
14169      * @category String
14170      * @param {string} [string=''] The string to deburr.
14171      * @returns {string} Returns the deburred string.
14172      * @example
14173      *
14174      * _.deburr('déjà vu');
14175      * // => 'deja vu'
14176      */
14177     function deburr(string) {
14178       string = toString(string);
14179       return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
14180     }
14181
14182     /**
14183      * Checks if `string` ends with the given target string.
14184      *
14185      * @static
14186      * @memberOf _
14187      * @since 3.0.0
14188      * @category String
14189      * @param {string} [string=''] The string to inspect.
14190      * @param {string} [target] The string to search for.
14191      * @param {number} [position=string.length] The position to search up to.
14192      * @returns {boolean} Returns `true` if `string` ends with `target`,
14193      *  else `false`.
14194      * @example
14195      *
14196      * _.endsWith('abc', 'c');
14197      * // => true
14198      *
14199      * _.endsWith('abc', 'b');
14200      * // => false
14201      *
14202      * _.endsWith('abc', 'b', 2);
14203      * // => true
14204      */
14205     function endsWith(string, target, position) {
14206       string = toString(string);
14207       target = baseToString(target);
14208
14209       var length = string.length;
14210       position = position === undefined
14211         ? length
14212         : baseClamp(toInteger(position), 0, length);
14213
14214       var end = position;
14215       position -= target.length;
14216       return position >= 0 && string.slice(position, end) == target;
14217     }
14218
14219     /**
14220      * Converts the characters "&", "<", ">", '"', and "'" in `string` to their
14221      * corresponding HTML entities.
14222      *
14223      * **Note:** No other characters are escaped. To escape additional
14224      * characters use a third-party library like [_he_](https://mths.be/he).
14225      *
14226      * Though the ">" character is escaped for symmetry, characters like
14227      * ">" and "/" don't need escaping in HTML and have no special meaning
14228      * unless they're part of a tag or unquoted attribute value. See
14229      * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
14230      * (under "semi-related fun fact") for more details.
14231      *
14232      * When working with HTML you should always
14233      * [quote attribute values](http://wonko.com/post/html-escaping) to reduce
14234      * XSS vectors.
14235      *
14236      * @static
14237      * @since 0.1.0
14238      * @memberOf _
14239      * @category String
14240      * @param {string} [string=''] The string to escape.
14241      * @returns {string} Returns the escaped string.
14242      * @example
14243      *
14244      * _.escape('fred, barney, & pebbles');
14245      * // => 'fred, barney, &amp; pebbles'
14246      */
14247     function escape(string) {
14248       string = toString(string);
14249       return (string && reHasUnescapedHtml.test(string))
14250         ? string.replace(reUnescapedHtml, escapeHtmlChar)
14251         : string;
14252     }
14253
14254     /**
14255      * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
14256      * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
14257      *
14258      * @static
14259      * @memberOf _
14260      * @since 3.0.0
14261      * @category String
14262      * @param {string} [string=''] The string to escape.
14263      * @returns {string} Returns the escaped string.
14264      * @example
14265      *
14266      * _.escapeRegExp('[lodash](https://lodash.com/)');
14267      * // => '\[lodash\]\(https://lodash\.com/\)'
14268      */
14269     function escapeRegExp(string) {
14270       string = toString(string);
14271       return (string && reHasRegExpChar.test(string))
14272         ? string.replace(reRegExpChar, '\\$&')
14273         : string;
14274     }
14275
14276     /**
14277      * Converts `string` to
14278      * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
14279      *
14280      * @static
14281      * @memberOf _
14282      * @since 3.0.0
14283      * @category String
14284      * @param {string} [string=''] The string to convert.
14285      * @returns {string} Returns the kebab cased string.
14286      * @example
14287      *
14288      * _.kebabCase('Foo Bar');
14289      * // => 'foo-bar'
14290      *
14291      * _.kebabCase('fooBar');
14292      * // => 'foo-bar'
14293      *
14294      * _.kebabCase('__FOO_BAR__');
14295      * // => 'foo-bar'
14296      */
14297     var kebabCase = createCompounder(function(result, word, index) {
14298       return result + (index ? '-' : '') + word.toLowerCase();
14299     });
14300
14301     /**
14302      * Converts `string`, as space separated words, to lower case.
14303      *
14304      * @static
14305      * @memberOf _
14306      * @since 4.0.0
14307      * @category String
14308      * @param {string} [string=''] The string to convert.
14309      * @returns {string} Returns the lower cased string.
14310      * @example
14311      *
14312      * _.lowerCase('--Foo-Bar--');
14313      * // => 'foo bar'
14314      *
14315      * _.lowerCase('fooBar');
14316      * // => 'foo bar'
14317      *
14318      * _.lowerCase('__FOO_BAR__');
14319      * // => 'foo bar'
14320      */
14321     var lowerCase = createCompounder(function(result, word, index) {
14322       return result + (index ? ' ' : '') + word.toLowerCase();
14323     });
14324
14325     /**
14326      * Converts the first character of `string` to lower case.
14327      *
14328      * @static
14329      * @memberOf _
14330      * @since 4.0.0
14331      * @category String
14332      * @param {string} [string=''] The string to convert.
14333      * @returns {string} Returns the converted string.
14334      * @example
14335      *
14336      * _.lowerFirst('Fred');
14337      * // => 'fred'
14338      *
14339      * _.lowerFirst('FRED');
14340      * // => 'fRED'
14341      */
14342     var lowerFirst = createCaseFirst('toLowerCase');
14343
14344     /**
14345      * Pads `string` on the left and right sides if it's shorter than `length`.
14346      * Padding characters are truncated if they can't be evenly divided by `length`.
14347      *
14348      * @static
14349      * @memberOf _
14350      * @since 3.0.0
14351      * @category String
14352      * @param {string} [string=''] The string to pad.
14353      * @param {number} [length=0] The padding length.
14354      * @param {string} [chars=' '] The string used as padding.
14355      * @returns {string} Returns the padded string.
14356      * @example
14357      *
14358      * _.pad('abc', 8);
14359      * // => '  abc   '
14360      *
14361      * _.pad('abc', 8, '_-');
14362      * // => '_-abc_-_'
14363      *
14364      * _.pad('abc', 3);
14365      * // => 'abc'
14366      */
14367     function pad(string, length, chars) {
14368       string = toString(string);
14369       length = toInteger(length);
14370
14371       var strLength = length ? stringSize(string) : 0;
14372       if (!length || strLength >= length) {
14373         return string;
14374       }
14375       var mid = (length - strLength) / 2;
14376       return (
14377         createPadding(nativeFloor(mid), chars) +
14378         string +
14379         createPadding(nativeCeil(mid), chars)
14380       );
14381     }
14382
14383     /**
14384      * Pads `string` on the right side if it's shorter than `length`. Padding
14385      * characters are truncated if they exceed `length`.
14386      *
14387      * @static
14388      * @memberOf _
14389      * @since 4.0.0
14390      * @category String
14391      * @param {string} [string=''] The string to pad.
14392      * @param {number} [length=0] The padding length.
14393      * @param {string} [chars=' '] The string used as padding.
14394      * @returns {string} Returns the padded string.
14395      * @example
14396      *
14397      * _.padEnd('abc', 6);
14398      * // => 'abc   '
14399      *
14400      * _.padEnd('abc', 6, '_-');
14401      * // => 'abc_-_'
14402      *
14403      * _.padEnd('abc', 3);
14404      * // => 'abc'
14405      */
14406     function padEnd(string, length, chars) {
14407       string = toString(string);
14408       length = toInteger(length);
14409
14410       var strLength = length ? stringSize(string) : 0;
14411       return (length && strLength < length)
14412         ? (string + createPadding(length - strLength, chars))
14413         : string;
14414     }
14415
14416     /**
14417      * Pads `string` on the left side if it's shorter than `length`. Padding
14418      * characters are truncated if they exceed `length`.
14419      *
14420      * @static
14421      * @memberOf _
14422      * @since 4.0.0
14423      * @category String
14424      * @param {string} [string=''] The string to pad.
14425      * @param {number} [length=0] The padding length.
14426      * @param {string} [chars=' '] The string used as padding.
14427      * @returns {string} Returns the padded string.
14428      * @example
14429      *
14430      * _.padStart('abc', 6);
14431      * // => '   abc'
14432      *
14433      * _.padStart('abc', 6, '_-');
14434      * // => '_-_abc'
14435      *
14436      * _.padStart('abc', 3);
14437      * // => 'abc'
14438      */
14439     function padStart(string, length, chars) {
14440       string = toString(string);
14441       length = toInteger(length);
14442
14443       var strLength = length ? stringSize(string) : 0;
14444       return (length && strLength < length)
14445         ? (createPadding(length - strLength, chars) + string)
14446         : string;
14447     }
14448
14449     /**
14450      * Converts `string` to an integer of the specified radix. If `radix` is
14451      * `undefined` or `0`, a `radix` of `10` is used unless `value` is a
14452      * hexadecimal, in which case a `radix` of `16` is used.
14453      *
14454      * **Note:** This method aligns with the
14455      * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
14456      *
14457      * @static
14458      * @memberOf _
14459      * @since 1.1.0
14460      * @category String
14461      * @param {string} string The string to convert.
14462      * @param {number} [radix=10] The radix to interpret `value` by.
14463      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14464      * @returns {number} Returns the converted integer.
14465      * @example
14466      *
14467      * _.parseInt('08');
14468      * // => 8
14469      *
14470      * _.map(['6', '08', '10'], _.parseInt);
14471      * // => [6, 8, 10]
14472      */
14473     function parseInt(string, radix, guard) {
14474       if (guard || radix == null) {
14475         radix = 0;
14476       } else if (radix) {
14477         radix = +radix;
14478       }
14479       return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0);
14480     }
14481
14482     /**
14483      * Repeats the given string `n` times.
14484      *
14485      * @static
14486      * @memberOf _
14487      * @since 3.0.0
14488      * @category String
14489      * @param {string} [string=''] The string to repeat.
14490      * @param {number} [n=1] The number of times to repeat the string.
14491      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14492      * @returns {string} Returns the repeated string.
14493      * @example
14494      *
14495      * _.repeat('*', 3);
14496      * // => '***'
14497      *
14498      * _.repeat('abc', 2);
14499      * // => 'abcabc'
14500      *
14501      * _.repeat('abc', 0);
14502      * // => ''
14503      */
14504     function repeat(string, n, guard) {
14505       if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) {
14506         n = 1;
14507       } else {
14508         n = toInteger(n);
14509       }
14510       return baseRepeat(toString(string), n);
14511     }
14512
14513     /**
14514      * Replaces matches for `pattern` in `string` with `replacement`.
14515      *
14516      * **Note:** This method is based on
14517      * [`String#replace`](https://mdn.io/String/replace).
14518      *
14519      * @static
14520      * @memberOf _
14521      * @since 4.0.0
14522      * @category String
14523      * @param {string} [string=''] The string to modify.
14524      * @param {RegExp|string} pattern The pattern to replace.
14525      * @param {Function|string} replacement The match replacement.
14526      * @returns {string} Returns the modified string.
14527      * @example
14528      *
14529      * _.replace('Hi Fred', 'Fred', 'Barney');
14530      * // => 'Hi Barney'
14531      */
14532     function replace() {
14533       var args = arguments,
14534           string = toString(args[0]);
14535
14536       return args.length < 3 ? string : string.replace(args[1], args[2]);
14537     }
14538
14539     /**
14540      * Converts `string` to
14541      * [snake case](https://en.wikipedia.org/wiki/Snake_case).
14542      *
14543      * @static
14544      * @memberOf _
14545      * @since 3.0.0
14546      * @category String
14547      * @param {string} [string=''] The string to convert.
14548      * @returns {string} Returns the snake cased string.
14549      * @example
14550      *
14551      * _.snakeCase('Foo Bar');
14552      * // => 'foo_bar'
14553      *
14554      * _.snakeCase('fooBar');
14555      * // => 'foo_bar'
14556      *
14557      * _.snakeCase('--FOO-BAR--');
14558      * // => 'foo_bar'
14559      */
14560     var snakeCase = createCompounder(function(result, word, index) {
14561       return result + (index ? '_' : '') + word.toLowerCase();
14562     });
14563
14564     /**
14565      * Splits `string` by `separator`.
14566      *
14567      * **Note:** This method is based on
14568      * [`String#split`](https://mdn.io/String/split).
14569      *
14570      * @static
14571      * @memberOf _
14572      * @since 4.0.0
14573      * @category String
14574      * @param {string} [string=''] The string to split.
14575      * @param {RegExp|string} separator The separator pattern to split by.
14576      * @param {number} [limit] The length to truncate results to.
14577      * @returns {Array} Returns the string segments.
14578      * @example
14579      *
14580      * _.split('a-b-c', '-', 2);
14581      * // => ['a', 'b']
14582      */
14583     function split(string, separator, limit) {
14584       if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {
14585         separator = limit = undefined;
14586       }
14587       limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;
14588       if (!limit) {
14589         return [];
14590       }
14591       string = toString(string);
14592       if (string && (
14593             typeof separator == 'string' ||
14594             (separator != null && !isRegExp(separator))
14595           )) {
14596         separator = baseToString(separator);
14597         if (!separator && hasUnicode(string)) {
14598           return castSlice(stringToArray(string), 0, limit);
14599         }
14600       }
14601       return string.split(separator, limit);
14602     }
14603
14604     /**
14605      * Converts `string` to
14606      * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
14607      *
14608      * @static
14609      * @memberOf _
14610      * @since 3.1.0
14611      * @category String
14612      * @param {string} [string=''] The string to convert.
14613      * @returns {string} Returns the start cased string.
14614      * @example
14615      *
14616      * _.startCase('--foo-bar--');
14617      * // => 'Foo Bar'
14618      *
14619      * _.startCase('fooBar');
14620      * // => 'Foo Bar'
14621      *
14622      * _.startCase('__FOO_BAR__');
14623      * // => 'FOO BAR'
14624      */
14625     var startCase = createCompounder(function(result, word, index) {
14626       return result + (index ? ' ' : '') + upperFirst(word);
14627     });
14628
14629     /**
14630      * Checks if `string` starts with the given target string.
14631      *
14632      * @static
14633      * @memberOf _
14634      * @since 3.0.0
14635      * @category String
14636      * @param {string} [string=''] The string to inspect.
14637      * @param {string} [target] The string to search for.
14638      * @param {number} [position=0] The position to search from.
14639      * @returns {boolean} Returns `true` if `string` starts with `target`,
14640      *  else `false`.
14641      * @example
14642      *
14643      * _.startsWith('abc', 'a');
14644      * // => true
14645      *
14646      * _.startsWith('abc', 'b');
14647      * // => false
14648      *
14649      * _.startsWith('abc', 'b', 1);
14650      * // => true
14651      */
14652     function startsWith(string, target, position) {
14653       string = toString(string);
14654       position = position == null
14655         ? 0
14656         : baseClamp(toInteger(position), 0, string.length);
14657
14658       target = baseToString(target);
14659       return string.slice(position, position + target.length) == target;
14660     }
14661
14662     /**
14663      * Creates a compiled template function that can interpolate data properties
14664      * in "interpolate" delimiters, HTML-escape interpolated data properties in
14665      * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
14666      * properties may be accessed as free variables in the template. If a setting
14667      * object is given, it takes precedence over `_.templateSettings` values.
14668      *
14669      * **Note:** In the development build `_.template` utilizes
14670      * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
14671      * for easier debugging.
14672      *
14673      * For more information on precompiling templates see
14674      * [lodash's custom builds documentation](https://lodash.com/custom-builds).
14675      *
14676      * For more information on Chrome extension sandboxes see
14677      * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
14678      *
14679      * @static
14680      * @since 0.1.0
14681      * @memberOf _
14682      * @category String
14683      * @param {string} [string=''] The template string.
14684      * @param {Object} [options={}] The options object.
14685      * @param {RegExp} [options.escape=_.templateSettings.escape]
14686      *  The HTML "escape" delimiter.
14687      * @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
14688      *  The "evaluate" delimiter.
14689      * @param {Object} [options.imports=_.templateSettings.imports]
14690      *  An object to import into the template as free variables.
14691      * @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
14692      *  The "interpolate" delimiter.
14693      * @param {string} [options.sourceURL='lodash.templateSources[n]']
14694      *  The sourceURL of the compiled template.
14695      * @param {string} [options.variable='obj']
14696      *  The data object variable name.
14697      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14698      * @returns {Function} Returns the compiled template function.
14699      * @example
14700      *
14701      * // Use the "interpolate" delimiter to create a compiled template.
14702      * var compiled = _.template('hello <%= user %>!');
14703      * compiled({ 'user': 'fred' });
14704      * // => 'hello fred!'
14705      *
14706      * // Use the HTML "escape" delimiter to escape data property values.
14707      * var compiled = _.template('<b><%- value %></b>');
14708      * compiled({ 'value': '<script>' });
14709      * // => '<b>&lt;script&gt;</b>'
14710      *
14711      * // Use the "evaluate" delimiter to execute JavaScript and generate HTML.
14712      * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
14713      * compiled({ 'users': ['fred', 'barney'] });
14714      * // => '<li>fred</li><li>barney</li>'
14715      *
14716      * // Use the internal `print` function in "evaluate" delimiters.
14717      * var compiled = _.template('<% print("hello " + user); %>!');
14718      * compiled({ 'user': 'barney' });
14719      * // => 'hello barney!'
14720      *
14721      * // Use the ES template literal delimiter as an "interpolate" delimiter.
14722      * // Disable support by replacing the "interpolate" delimiter.
14723      * var compiled = _.template('hello ${ user }!');
14724      * compiled({ 'user': 'pebbles' });
14725      * // => 'hello pebbles!'
14726      *
14727      * // Use backslashes to treat delimiters as plain text.
14728      * var compiled = _.template('<%= "\\<%- value %\\>" %>');
14729      * compiled({ 'value': 'ignored' });
14730      * // => '<%- value %>'
14731      *
14732      * // Use the `imports` option to import `jQuery` as `jq`.
14733      * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
14734      * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
14735      * compiled({ 'users': ['fred', 'barney'] });
14736      * // => '<li>fred</li><li>barney</li>'
14737      *
14738      * // Use the `sourceURL` option to specify a custom sourceURL for the template.
14739      * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
14740      * compiled(data);
14741      * // => Find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector.
14742      *
14743      * // Use the `variable` option to ensure a with-statement isn't used in the compiled template.
14744      * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
14745      * compiled.source;
14746      * // => function(data) {
14747      * //   var __t, __p = '';
14748      * //   __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
14749      * //   return __p;
14750      * // }
14751      *
14752      * // Use custom template delimiters.
14753      * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
14754      * var compiled = _.template('hello {{ user }}!');
14755      * compiled({ 'user': 'mustache' });
14756      * // => 'hello mustache!'
14757      *
14758      * // Use the `source` property to inline compiled templates for meaningful
14759      * // line numbers in error messages and stack traces.
14760      * fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\
14761      *   var JST = {\
14762      *     "main": ' + _.template(mainText).source + '\
14763      *   };\
14764      * ');
14765      */
14766     function template(string, options, guard) {
14767       // Based on John Resig's `tmpl` implementation
14768       // (http://ejohn.org/blog/javascript-micro-templating/)
14769       // and Laura Doktorova's doT.js (https://github.com/olado/doT).
14770       var settings = lodash.templateSettings;
14771
14772       if (guard && isIterateeCall(string, options, guard)) {
14773         options = undefined;
14774       }
14775       string = toString(string);
14776       options = assignInWith({}, options, settings, customDefaultsAssignIn);
14777
14778       var imports = assignInWith({}, options.imports, settings.imports, customDefaultsAssignIn),
14779           importsKeys = keys(imports),
14780           importsValues = baseValues(imports, importsKeys);
14781
14782       var isEscaping,
14783           isEvaluating,
14784           index = 0,
14785           interpolate = options.interpolate || reNoMatch,
14786           source = "__p += '";
14787
14788       // Compile the regexp to match each delimiter.
14789       var reDelimiters = RegExp(
14790         (options.escape || reNoMatch).source + '|' +
14791         interpolate.source + '|' +
14792         (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
14793         (options.evaluate || reNoMatch).source + '|$'
14794       , 'g');
14795
14796       // Use a sourceURL for easier debugging.
14797       var sourceURL = '//# sourceURL=' +
14798         ('sourceURL' in options
14799           ? options.sourceURL
14800           : ('lodash.templateSources[' + (++templateCounter) + ']')
14801         ) + '\n';
14802
14803       string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
14804         interpolateValue || (interpolateValue = esTemplateValue);
14805
14806         // Escape characters that can't be included in string literals.
14807         source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
14808
14809         // Replace delimiters with snippets.
14810         if (escapeValue) {
14811           isEscaping = true;
14812           source += "' +\n__e(" + escapeValue + ") +\n'";
14813         }
14814         if (evaluateValue) {
14815           isEvaluating = true;
14816           source += "';\n" + evaluateValue + ";\n__p += '";
14817         }
14818         if (interpolateValue) {
14819           source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
14820         }
14821         index = offset + match.length;
14822
14823         // The JS engine embedded in Adobe products needs `match` returned in
14824         // order to produce the correct `offset` value.
14825         return match;
14826       });
14827
14828       source += "';\n";
14829
14830       // If `variable` is not specified wrap a with-statement around the generated
14831       // code to add the data object to the top of the scope chain.
14832       var variable = options.variable;
14833       if (!variable) {
14834         source = 'with (obj) {\n' + source + '\n}\n';
14835       }
14836       // Cleanup code by stripping empty strings.
14837       source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
14838         .replace(reEmptyStringMiddle, '$1')
14839         .replace(reEmptyStringTrailing, '$1;');
14840
14841       // Frame code as the function body.
14842       source = 'function(' + (variable || 'obj') + ') {\n' +
14843         (variable
14844           ? ''
14845           : 'obj || (obj = {});\n'
14846         ) +
14847         "var __t, __p = ''" +
14848         (isEscaping
14849            ? ', __e = _.escape'
14850            : ''
14851         ) +
14852         (isEvaluating
14853           ? ', __j = Array.prototype.join;\n' +
14854             "function print() { __p += __j.call(arguments, '') }\n"
14855           : ';\n'
14856         ) +
14857         source +
14858         'return __p\n}';
14859
14860       var result = attempt(function() {
14861         return Function(importsKeys, sourceURL + 'return ' + source)
14862           .apply(undefined, importsValues);
14863       });
14864
14865       // Provide the compiled function's source by its `toString` method or
14866       // the `source` property as a convenience for inlining compiled templates.
14867       result.source = source;
14868       if (isError(result)) {
14869         throw result;
14870       }
14871       return result;
14872     }
14873
14874     /**
14875      * Converts `string`, as a whole, to lower case just like
14876      * [String#toLowerCase](https://mdn.io/toLowerCase).
14877      *
14878      * @static
14879      * @memberOf _
14880      * @since 4.0.0
14881      * @category String
14882      * @param {string} [string=''] The string to convert.
14883      * @returns {string} Returns the lower cased string.
14884      * @example
14885      *
14886      * _.toLower('--Foo-Bar--');
14887      * // => '--foo-bar--'
14888      *
14889      * _.toLower('fooBar');
14890      * // => 'foobar'
14891      *
14892      * _.toLower('__FOO_BAR__');
14893      * // => '__foo_bar__'
14894      */
14895     function toLower(value) {
14896       return toString(value).toLowerCase();
14897     }
14898
14899     /**
14900      * Converts `string`, as a whole, to upper case just like
14901      * [String#toUpperCase](https://mdn.io/toUpperCase).
14902      *
14903      * @static
14904      * @memberOf _
14905      * @since 4.0.0
14906      * @category String
14907      * @param {string} [string=''] The string to convert.
14908      * @returns {string} Returns the upper cased string.
14909      * @example
14910      *
14911      * _.toUpper('--foo-bar--');
14912      * // => '--FOO-BAR--'
14913      *
14914      * _.toUpper('fooBar');
14915      * // => 'FOOBAR'
14916      *
14917      * _.toUpper('__foo_bar__');
14918      * // => '__FOO_BAR__'
14919      */
14920     function toUpper(value) {
14921       return toString(value).toUpperCase();
14922     }
14923
14924     /**
14925      * Removes leading and trailing whitespace or specified characters from `string`.
14926      *
14927      * @static
14928      * @memberOf _
14929      * @since 3.0.0
14930      * @category String
14931      * @param {string} [string=''] The string to trim.
14932      * @param {string} [chars=whitespace] The characters to trim.
14933      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14934      * @returns {string} Returns the trimmed string.
14935      * @example
14936      *
14937      * _.trim('  abc  ');
14938      * // => 'abc'
14939      *
14940      * _.trim('-_-abc-_-', '_-');
14941      * // => 'abc'
14942      *
14943      * _.map(['  foo  ', '  bar  '], _.trim);
14944      * // => ['foo', 'bar']
14945      */
14946     function trim(string, chars, guard) {
14947       string = toString(string);
14948       if (string && (guard || chars === undefined)) {
14949         return string.replace(reTrim, '');
14950       }
14951       if (!string || !(chars = baseToString(chars))) {
14952         return string;
14953       }
14954       var strSymbols = stringToArray(string),
14955           chrSymbols = stringToArray(chars),
14956           start = charsStartIndex(strSymbols, chrSymbols),
14957           end = charsEndIndex(strSymbols, chrSymbols) + 1;
14958
14959       return castSlice(strSymbols, start, end).join('');
14960     }
14961
14962     /**
14963      * Removes trailing whitespace or specified characters from `string`.
14964      *
14965      * @static
14966      * @memberOf _
14967      * @since 4.0.0
14968      * @category String
14969      * @param {string} [string=''] The string to trim.
14970      * @param {string} [chars=whitespace] The characters to trim.
14971      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14972      * @returns {string} Returns the trimmed string.
14973      * @example
14974      *
14975      * _.trimEnd('  abc  ');
14976      * // => '  abc'
14977      *
14978      * _.trimEnd('-_-abc-_-', '_-');
14979      * // => '-_-abc'
14980      */
14981     function trimEnd(string, chars, guard) {
14982       string = toString(string);
14983       if (string && (guard || chars === undefined)) {
14984         return string.replace(reTrimEnd, '');
14985       }
14986       if (!string || !(chars = baseToString(chars))) {
14987         return string;
14988       }
14989       var strSymbols = stringToArray(string),
14990           end = charsEndIndex(strSymbols, stringToArray(chars)) + 1;
14991
14992       return castSlice(strSymbols, 0, end).join('');
14993     }
14994
14995     /**
14996      * Removes leading whitespace or specified characters from `string`.
14997      *
14998      * @static
14999      * @memberOf _
15000      * @since 4.0.0
15001      * @category String
15002      * @param {string} [string=''] The string to trim.
15003      * @param {string} [chars=whitespace] The characters to trim.
15004      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
15005      * @returns {string} Returns the trimmed string.
15006      * @example
15007      *
15008      * _.trimStart('  abc  ');
15009      * // => 'abc  '
15010      *
15011      * _.trimStart('-_-abc-_-', '_-');
15012      * // => 'abc-_-'
15013      */
15014     function trimStart(string, chars, guard) {
15015       string = toString(string);
15016       if (string && (guard || chars === undefined)) {
15017         return string.replace(reTrimStart, '');
15018       }
15019       if (!string || !(chars = baseToString(chars))) {
15020         return string;
15021       }
15022       var strSymbols = stringToArray(string),
15023           start = charsStartIndex(strSymbols, stringToArray(chars));
15024
15025       return castSlice(strSymbols, start).join('');
15026     }
15027
15028     /**
15029      * Truncates `string` if it's longer than the given maximum string length.
15030      * The last characters of the truncated string are replaced with the omission
15031      * string which defaults to "...".
15032      *
15033      * @static
15034      * @memberOf _
15035      * @since 4.0.0
15036      * @category String
15037      * @param {string} [string=''] The string to truncate.
15038      * @param {Object} [options={}] The options object.
15039      * @param {number} [options.length=30] The maximum string length.
15040      * @param {string} [options.omission='...'] The string to indicate text is omitted.
15041      * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
15042      * @returns {string} Returns the truncated string.
15043      * @example
15044      *
15045      * _.truncate('hi-diddly-ho there, neighborino');
15046      * // => 'hi-diddly-ho there, neighbo...'
15047      *
15048      * _.truncate('hi-diddly-ho there, neighborino', {
15049      *   'length': 24,
15050      *   'separator': ' '
15051      * });
15052      * // => 'hi-diddly-ho there,...'
15053      *
15054      * _.truncate('hi-diddly-ho there, neighborino', {
15055      *   'length': 24,
15056      *   'separator': /,? +/
15057      * });
15058      * // => 'hi-diddly-ho there...'
15059      *
15060      * _.truncate('hi-diddly-ho there, neighborino', {
15061      *   'omission': ' [...]'
15062      * });
15063      * // => 'hi-diddly-ho there, neig [...]'
15064      */
15065     function truncate(string, options) {
15066       var length = DEFAULT_TRUNC_LENGTH,
15067           omission = DEFAULT_TRUNC_OMISSION;
15068
15069       if (isObject(options)) {
15070         var separator = 'separator' in options ? options.separator : separator;
15071         length = 'length' in options ? toInteger(options.length) : length;
15072         omission = 'omission' in options ? baseToString(options.omission) : omission;
15073       }
15074       string = toString(string);
15075
15076       var strLength = string.length;
15077       if (hasUnicode(string)) {
15078         var strSymbols = stringToArray(string);
15079         strLength = strSymbols.length;
15080       }
15081       if (length >= strLength) {
15082         return string;
15083       }
15084       var end = length - stringSize(omission);
15085       if (end < 1) {
15086         return omission;
15087       }
15088       var result = strSymbols
15089         ? castSlice(strSymbols, 0, end).join('')
15090         : string.slice(0, end);
15091
15092       if (separator === undefined) {
15093         return result + omission;
15094       }
15095       if (strSymbols) {
15096         end += (result.length - end);
15097       }
15098       if (isRegExp(separator)) {
15099         if (string.slice(end).search(separator)) {
15100           var match,
15101               substring = result;
15102
15103           if (!separator.global) {
15104             separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g');
15105           }
15106           separator.lastIndex = 0;
15107           while ((match = separator.exec(substring))) {
15108             var newEnd = match.index;
15109           }
15110           result = result.slice(0, newEnd === undefined ? end : newEnd);
15111         }
15112       } else if (string.indexOf(baseToString(separator), end) != end) {
15113         var index = result.lastIndexOf(separator);
15114         if (index > -1) {
15115           result = result.slice(0, index);
15116         }
15117       }
15118       return result + omission;
15119     }
15120
15121     /**
15122      * The inverse of `_.escape`; this method converts the HTML entities
15123      * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to
15124      * their corresponding characters.
15125      *
15126      * **Note:** No other HTML entities are unescaped. To unescape additional
15127      * HTML entities use a third-party library like [_he_](https://mths.be/he).
15128      *
15129      * @static
15130      * @memberOf _
15131      * @since 0.6.0
15132      * @category String
15133      * @param {string} [string=''] The string to unescape.
15134      * @returns {string} Returns the unescaped string.
15135      * @example
15136      *
15137      * _.unescape('fred, barney, &amp; pebbles');
15138      * // => 'fred, barney, & pebbles'
15139      */
15140     function unescape(string) {
15141       string = toString(string);
15142       return (string && reHasEscapedHtml.test(string))
15143         ? string.replace(reEscapedHtml, unescapeHtmlChar)
15144         : string;
15145     }
15146
15147     /**
15148      * Converts `string`, as space separated words, to upper case.
15149      *
15150      * @static
15151      * @memberOf _
15152      * @since 4.0.0
15153      * @category String
15154      * @param {string} [string=''] The string to convert.
15155      * @returns {string} Returns the upper cased string.
15156      * @example
15157      *
15158      * _.upperCase('--foo-bar');
15159      * // => 'FOO BAR'
15160      *
15161      * _.upperCase('fooBar');
15162      * // => 'FOO BAR'
15163      *
15164      * _.upperCase('__foo_bar__');
15165      * // => 'FOO BAR'
15166      */
15167     var upperCase = createCompounder(function(result, word, index) {
15168       return result + (index ? ' ' : '') + word.toUpperCase();
15169     });
15170
15171     /**
15172      * Converts the first character of `string` to upper case.
15173      *
15174      * @static
15175      * @memberOf _
15176      * @since 4.0.0
15177      * @category String
15178      * @param {string} [string=''] The string to convert.
15179      * @returns {string} Returns the converted string.
15180      * @example
15181      *
15182      * _.upperFirst('fred');
15183      * // => 'Fred'
15184      *
15185      * _.upperFirst('FRED');
15186      * // => 'FRED'
15187      */
15188     var upperFirst = createCaseFirst('toUpperCase');
15189
15190     /**
15191      * Splits `string` into an array of its words.
15192      *
15193      * @static
15194      * @memberOf _
15195      * @since 3.0.0
15196      * @category String
15197      * @param {string} [string=''] The string to inspect.
15198      * @param {RegExp|string} [pattern] The pattern to match words.
15199      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
15200      * @returns {Array} Returns the words of `string`.
15201      * @example
15202      *
15203      * _.words('fred, barney, & pebbles');
15204      * // => ['fred', 'barney', 'pebbles']
15205      *
15206      * _.words('fred, barney, & pebbles', /[^, ]+/g);
15207      * // => ['fred', 'barney', '&', 'pebbles']
15208      */
15209     function words(string, pattern, guard) {
15210       string = toString(string);
15211       pattern = guard ? undefined : pattern;
15212
15213       if (pattern === undefined) {
15214         return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
15215       }
15216       return string.match(pattern) || [];
15217     }
15218
15219     /*------------------------------------------------------------------------*/
15220
15221     /**
15222      * Attempts to invoke `func`, returning either the result or the caught error
15223      * object. Any additional arguments are provided to `func` when it's invoked.
15224      *
15225      * @static
15226      * @memberOf _
15227      * @since 3.0.0
15228      * @category Util
15229      * @param {Function} func The function to attempt.
15230      * @param {...*} [args] The arguments to invoke `func` with.
15231      * @returns {*} Returns the `func` result or error object.
15232      * @example
15233      *
15234      * // Avoid throwing errors for invalid selectors.
15235      * var elements = _.attempt(function(selector) {
15236      *   return document.querySelectorAll(selector);
15237      * }, '>_>');
15238      *
15239      * if (_.isError(elements)) {
15240      *   elements = [];
15241      * }
15242      */
15243     var attempt = baseRest(function(func, args) {
15244       try {
15245         return apply(func, undefined, args);
15246       } catch (e) {
15247         return isError(e) ? e : new Error(e);
15248       }
15249     });
15250
15251     /**
15252      * Binds methods of an object to the object itself, overwriting the existing
15253      * method.
15254      *
15255      * **Note:** This method doesn't set the "length" property of bound functions.
15256      *
15257      * @static
15258      * @since 0.1.0
15259      * @memberOf _
15260      * @category Util
15261      * @param {Object} object The object to bind and assign the bound methods to.
15262      * @param {...(string|string[])} methodNames The object method names to bind.
15263      * @returns {Object} Returns `object`.
15264      * @example
15265      *
15266      * var view = {
15267      *   'label': 'docs',
15268      *   'click': function() {
15269      *     console.log('clicked ' + this.label);
15270      *   }
15271      * };
15272      *
15273      * _.bindAll(view, ['click']);
15274      * jQuery(element).on('click', view.click);
15275      * // => Logs 'clicked docs' when clicked.
15276      */
15277     var bindAll = flatRest(function(object, methodNames) {
15278       arrayEach(methodNames, function(key) {
15279         key = toKey(key);
15280         baseAssignValue(object, key, bind(object[key], object));
15281       });
15282       return object;
15283     });
15284
15285     /**
15286      * Creates a function that iterates over `pairs` and invokes the corresponding
15287      * function of the first predicate to return truthy. The predicate-function
15288      * pairs are invoked with the `this` binding and arguments of the created
15289      * function.
15290      *
15291      * @static
15292      * @memberOf _
15293      * @since 4.0.0
15294      * @category Util
15295      * @param {Array} pairs The predicate-function pairs.
15296      * @returns {Function} Returns the new composite function.
15297      * @example
15298      *
15299      * var func = _.cond([
15300      *   [_.matches({ 'a': 1 }),           _.constant('matches A')],
15301      *   [_.conforms({ 'b': _.isNumber }), _.constant('matches B')],
15302      *   [_.stubTrue,                      _.constant('no match')]
15303      * ]);
15304      *
15305      * func({ 'a': 1, 'b': 2 });
15306      * // => 'matches A'
15307      *
15308      * func({ 'a': 0, 'b': 1 });
15309      * // => 'matches B'
15310      *
15311      * func({ 'a': '1', 'b': '2' });
15312      * // => 'no match'
15313      */
15314     function cond(pairs) {
15315       var length = pairs == null ? 0 : pairs.length,
15316           toIteratee = getIteratee();
15317
15318       pairs = !length ? [] : arrayMap(pairs, function(pair) {
15319         if (typeof pair[1] != 'function') {
15320           throw new TypeError(FUNC_ERROR_TEXT);
15321         }
15322         return [toIteratee(pair[0]), pair[1]];
15323       });
15324
15325       return baseRest(function(args) {
15326         var index = -1;
15327         while (++index < length) {
15328           var pair = pairs[index];
15329           if (apply(pair[0], this, args)) {
15330             return apply(pair[1], this, args);
15331           }
15332         }
15333       });
15334     }
15335
15336     /**
15337      * Creates a function that invokes the predicate properties of `source` with
15338      * the corresponding property values of a given object, returning `true` if
15339      * all predicates return truthy, else `false`.
15340      *
15341      * **Note:** The created function is equivalent to `_.conformsTo` with
15342      * `source` partially applied.
15343      *
15344      * @static
15345      * @memberOf _
15346      * @since 4.0.0
15347      * @category Util
15348      * @param {Object} source The object of property predicates to conform to.
15349      * @returns {Function} Returns the new spec function.
15350      * @example
15351      *
15352      * var objects = [
15353      *   { 'a': 2, 'b': 1 },
15354      *   { 'a': 1, 'b': 2 }
15355      * ];
15356      *
15357      * _.filter(objects, _.conforms({ 'b': function(n) { return n > 1; } }));
15358      * // => [{ 'a': 1, 'b': 2 }]
15359      */
15360     function conforms(source) {
15361       return baseConforms(baseClone(source, CLONE_DEEP_FLAG));
15362     }
15363
15364     /**
15365      * Creates a function that returns `value`.
15366      *
15367      * @static
15368      * @memberOf _
15369      * @since 2.4.0
15370      * @category Util
15371      * @param {*} value The value to return from the new function.
15372      * @returns {Function} Returns the new constant function.
15373      * @example
15374      *
15375      * var objects = _.times(2, _.constant({ 'a': 1 }));
15376      *
15377      * console.log(objects);
15378      * // => [{ 'a': 1 }, { 'a': 1 }]
15379      *
15380      * console.log(objects[0] === objects[1]);
15381      * // => true
15382      */
15383     function constant(value) {
15384       return function() {
15385         return value;
15386       };
15387     }
15388
15389     /**
15390      * Checks `value` to determine whether a default value should be returned in
15391      * its place. The `defaultValue` is returned if `value` is `NaN`, `null`,
15392      * or `undefined`.
15393      *
15394      * @static
15395      * @memberOf _
15396      * @since 4.14.0
15397      * @category Util
15398      * @param {*} value The value to check.
15399      * @param {*} defaultValue The default value.
15400      * @returns {*} Returns the resolved value.
15401      * @example
15402      *
15403      * _.defaultTo(1, 10);
15404      * // => 1
15405      *
15406      * _.defaultTo(undefined, 10);
15407      * // => 10
15408      */
15409     function defaultTo(value, defaultValue) {
15410       return (value == null || value !== value) ? defaultValue : value;
15411     }
15412
15413     /**
15414      * Creates a function that returns the result of invoking the given functions
15415      * with the `this` binding of the created function, where each successive
15416      * invocation is supplied the return value of the previous.
15417      *
15418      * @static
15419      * @memberOf _
15420      * @since 3.0.0
15421      * @category Util
15422      * @param {...(Function|Function[])} [funcs] The functions to invoke.
15423      * @returns {Function} Returns the new composite function.
15424      * @see _.flowRight
15425      * @example
15426      *
15427      * function square(n) {
15428      *   return n * n;
15429      * }
15430      *
15431      * var addSquare = _.flow([_.add, square]);
15432      * addSquare(1, 2);
15433      * // => 9
15434      */
15435     var flow = createFlow();
15436
15437     /**
15438      * This method is like `_.flow` except that it creates a function that
15439      * invokes the given functions from right to left.
15440      *
15441      * @static
15442      * @since 3.0.0
15443      * @memberOf _
15444      * @category Util
15445      * @param {...(Function|Function[])} [funcs] The functions to invoke.
15446      * @returns {Function} Returns the new composite function.
15447      * @see _.flow
15448      * @example
15449      *
15450      * function square(n) {
15451      *   return n * n;
15452      * }
15453      *
15454      * var addSquare = _.flowRight([square, _.add]);
15455      * addSquare(1, 2);
15456      * // => 9
15457      */
15458     var flowRight = createFlow(true);
15459
15460     /**
15461      * This method returns the first argument it receives.
15462      *
15463      * @static
15464      * @since 0.1.0
15465      * @memberOf _
15466      * @category Util
15467      * @param {*} value Any value.
15468      * @returns {*} Returns `value`.
15469      * @example
15470      *
15471      * var object = { 'a': 1 };
15472      *
15473      * console.log(_.identity(object) === object);
15474      * // => true
15475      */
15476     function identity(value) {
15477       return value;
15478     }
15479
15480     /**
15481      * Creates a function that invokes `func` with the arguments of the created
15482      * function. If `func` is a property name, the created function returns the
15483      * property value for a given element. If `func` is an array or object, the
15484      * created function returns `true` for elements that contain the equivalent
15485      * source properties, otherwise it returns `false`.
15486      *
15487      * @static
15488      * @since 4.0.0
15489      * @memberOf _
15490      * @category Util
15491      * @param {*} [func=_.identity] The value to convert to a callback.
15492      * @returns {Function} Returns the callback.
15493      * @example
15494      *
15495      * var users = [
15496      *   { 'user': 'barney', 'age': 36, 'active': true },
15497      *   { 'user': 'fred',   'age': 40, 'active': false }
15498      * ];
15499      *
15500      * // The `_.matches` iteratee shorthand.
15501      * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
15502      * // => [{ 'user': 'barney', 'age': 36, 'active': true }]
15503      *
15504      * // The `_.matchesProperty` iteratee shorthand.
15505      * _.filter(users, _.iteratee(['user', 'fred']));
15506      * // => [{ 'user': 'fred', 'age': 40 }]
15507      *
15508      * // The `_.property` iteratee shorthand.
15509      * _.map(users, _.iteratee('user'));
15510      * // => ['barney', 'fred']
15511      *
15512      * // Create custom iteratee shorthands.
15513      * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
15514      *   return !_.isRegExp(func) ? iteratee(func) : function(string) {
15515      *     return func.test(string);
15516      *   };
15517      * });
15518      *
15519      * _.filter(['abc', 'def'], /ef/);
15520      * // => ['def']
15521      */
15522     function iteratee(func) {
15523       return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG));
15524     }
15525
15526     /**
15527      * Creates a function that performs a partial deep comparison between a given
15528      * object and `source`, returning `true` if the given object has equivalent
15529      * property values, else `false`.
15530      *
15531      * **Note:** The created function is equivalent to `_.isMatch` with `source`
15532      * partially applied.
15533      *
15534      * Partial comparisons will match empty array and empty object `source`
15535      * values against any array or object value, respectively. See `_.isEqual`
15536      * for a list of supported value comparisons.
15537      *
15538      * @static
15539      * @memberOf _
15540      * @since 3.0.0
15541      * @category Util
15542      * @param {Object} source The object of property values to match.
15543      * @returns {Function} Returns the new spec function.
15544      * @example
15545      *
15546      * var objects = [
15547      *   { 'a': 1, 'b': 2, 'c': 3 },
15548      *   { 'a': 4, 'b': 5, 'c': 6 }
15549      * ];
15550      *
15551      * _.filter(objects, _.matches({ 'a': 4, 'c': 6 }));
15552      * // => [{ 'a': 4, 'b': 5, 'c': 6 }]
15553      */
15554     function matches(source) {
15555       return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
15556     }
15557
15558     /**
15559      * Creates a function that performs a partial deep comparison between the
15560      * value at `path` of a given object to `srcValue`, returning `true` if the
15561      * object value is equivalent, else `false`.
15562      *
15563      * **Note:** Partial comparisons will match empty array and empty object
15564      * `srcValue` values against any array or object value, respectively. See
15565      * `_.isEqual` for a list of supported value comparisons.
15566      *
15567      * @static
15568      * @memberOf _
15569      * @since 3.2.0
15570      * @category Util
15571      * @param {Array|string} path The path of the property to get.
15572      * @param {*} srcValue The value to match.
15573      * @returns {Function} Returns the new spec function.
15574      * @example
15575      *
15576      * var objects = [
15577      *   { 'a': 1, 'b': 2, 'c': 3 },
15578      *   { 'a': 4, 'b': 5, 'c': 6 }
15579      * ];
15580      *
15581      * _.find(objects, _.matchesProperty('a', 4));
15582      * // => { 'a': 4, 'b': 5, 'c': 6 }
15583      */
15584     function matchesProperty(path, srcValue) {
15585       return baseMatchesProperty(path, baseClone(srcValue, CLONE_DEEP_FLAG));
15586     }
15587
15588     /**
15589      * Creates a function that invokes the method at `path` of a given object.
15590      * Any additional arguments are provided to the invoked method.
15591      *
15592      * @static
15593      * @memberOf _
15594      * @since 3.7.0
15595      * @category Util
15596      * @param {Array|string} path The path of the method to invoke.
15597      * @param {...*} [args] The arguments to invoke the method with.
15598      * @returns {Function} Returns the new invoker function.
15599      * @example
15600      *
15601      * var objects = [
15602      *   { 'a': { 'b': _.constant(2) } },
15603      *   { 'a': { 'b': _.constant(1) } }
15604      * ];
15605      *
15606      * _.map(objects, _.method('a.b'));
15607      * // => [2, 1]
15608      *
15609      * _.map(objects, _.method(['a', 'b']));
15610      * // => [2, 1]
15611      */
15612     var method = baseRest(function(path, args) {
15613       return function(object) {
15614         return baseInvoke(object, path, args);
15615       };
15616     });
15617
15618     /**
15619      * The opposite of `_.method`; this method creates a function that invokes
15620      * the method at a given path of `object`. Any additional arguments are
15621      * provided to the invoked method.
15622      *
15623      * @static
15624      * @memberOf _
15625      * @since 3.7.0
15626      * @category Util
15627      * @param {Object} object The object to query.
15628      * @param {...*} [args] The arguments to invoke the method with.
15629      * @returns {Function} Returns the new invoker function.
15630      * @example
15631      *
15632      * var array = _.times(3, _.constant),
15633      *     object = { 'a': array, 'b': array, 'c': array };
15634      *
15635      * _.map(['a[2]', 'c[0]'], _.methodOf(object));
15636      * // => [2, 0]
15637      *
15638      * _.map([['a', '2'], ['c', '0']], _.methodOf(object));
15639      * // => [2, 0]
15640      */
15641     var methodOf = baseRest(function(object, args) {
15642       return function(path) {
15643         return baseInvoke(object, path, args);
15644       };
15645     });
15646
15647     /**
15648      * Adds all own enumerable string keyed function properties of a source
15649      * object to the destination object. If `object` is a function, then methods
15650      * are added to its prototype as well.
15651      *
15652      * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
15653      * avoid conflicts caused by modifying the original.
15654      *
15655      * @static
15656      * @since 0.1.0
15657      * @memberOf _
15658      * @category Util
15659      * @param {Function|Object} [object=lodash] The destination object.
15660      * @param {Object} source The object of functions to add.
15661      * @param {Object} [options={}] The options object.
15662      * @param {boolean} [options.chain=true] Specify whether mixins are chainable.
15663      * @returns {Function|Object} Returns `object`.
15664      * @example
15665      *
15666      * function vowels(string) {
15667      *   return _.filter(string, function(v) {
15668      *     return /[aeiou]/i.test(v);
15669      *   });
15670      * }
15671      *
15672      * _.mixin({ 'vowels': vowels });
15673      * _.vowels('fred');
15674      * // => ['e']
15675      *
15676      * _('fred').vowels().value();
15677      * // => ['e']
15678      *
15679      * _.mixin({ 'vowels': vowels }, { 'chain': false });
15680      * _('fred').vowels();
15681      * // => ['e']
15682      */
15683     function mixin(object, source, options) {
15684       var props = keys(source),
15685           methodNames = baseFunctions(source, props);
15686
15687       if (options == null &&
15688           !(isObject(source) && (methodNames.length || !props.length))) {
15689         options = source;
15690         source = object;
15691         object = this;
15692         methodNames = baseFunctions(source, keys(source));
15693       }
15694       var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
15695           isFunc = isFunction(object);
15696
15697       arrayEach(methodNames, function(methodName) {
15698         var func = source[methodName];
15699         object[methodName] = func;
15700         if (isFunc) {
15701           object.prototype[methodName] = function() {
15702             var chainAll = this.__chain__;
15703             if (chain || chainAll) {
15704               var result = object(this.__wrapped__),
15705                   actions = result.__actions__ = copyArray(this.__actions__);
15706
15707               actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
15708               result.__chain__ = chainAll;
15709               return result;
15710             }
15711             return func.apply(object, arrayPush([this.value()], arguments));
15712           };
15713         }
15714       });
15715
15716       return object;
15717     }
15718
15719     /**
15720      * Reverts the `_` variable to its previous value and returns a reference to
15721      * the `lodash` function.
15722      *
15723      * @static
15724      * @since 0.1.0
15725      * @memberOf _
15726      * @category Util
15727      * @returns {Function} Returns the `lodash` function.
15728      * @example
15729      *
15730      * var lodash = _.noConflict();
15731      */
15732     function noConflict() {
15733       if (root._ === this) {
15734         root._ = oldDash;
15735       }
15736       return this;
15737     }
15738
15739     /**
15740      * This method returns `undefined`.
15741      *
15742      * @static
15743      * @memberOf _
15744      * @since 2.3.0
15745      * @category Util
15746      * @example
15747      *
15748      * _.times(2, _.noop);
15749      * // => [undefined, undefined]
15750      */
15751     function noop() {
15752       // No operation performed.
15753     }
15754
15755     /**
15756      * Creates a function that gets the argument at index `n`. If `n` is negative,
15757      * the nth argument from the end is returned.
15758      *
15759      * @static
15760      * @memberOf _
15761      * @since 4.0.0
15762      * @category Util
15763      * @param {number} [n=0] The index of the argument to return.
15764      * @returns {Function} Returns the new pass-thru function.
15765      * @example
15766      *
15767      * var func = _.nthArg(1);
15768      * func('a', 'b', 'c', 'd');
15769      * // => 'b'
15770      *
15771      * var func = _.nthArg(-2);
15772      * func('a', 'b', 'c', 'd');
15773      * // => 'c'
15774      */
15775     function nthArg(n) {
15776       n = toInteger(n);
15777       return baseRest(function(args) {
15778         return baseNth(args, n);
15779       });
15780     }
15781
15782     /**
15783      * Creates a function that invokes `iteratees` with the arguments it receives
15784      * and returns their results.
15785      *
15786      * @static
15787      * @memberOf _
15788      * @since 4.0.0
15789      * @category Util
15790      * @param {...(Function|Function[])} [iteratees=[_.identity]]
15791      *  The iteratees to invoke.
15792      * @returns {Function} Returns the new function.
15793      * @example
15794      *
15795      * var func = _.over([Math.max, Math.min]);
15796      *
15797      * func(1, 2, 3, 4);
15798      * // => [4, 1]
15799      */
15800     var over = createOver(arrayMap);
15801
15802     /**
15803      * Creates a function that checks if **all** of the `predicates` return
15804      * truthy when invoked with the arguments it receives.
15805      *
15806      * @static
15807      * @memberOf _
15808      * @since 4.0.0
15809      * @category Util
15810      * @param {...(Function|Function[])} [predicates=[_.identity]]
15811      *  The predicates to check.
15812      * @returns {Function} Returns the new function.
15813      * @example
15814      *
15815      * var func = _.overEvery([Boolean, isFinite]);
15816      *
15817      * func('1');
15818      * // => true
15819      *
15820      * func(null);
15821      * // => false
15822      *
15823      * func(NaN);
15824      * // => false
15825      */
15826     var overEvery = createOver(arrayEvery);
15827
15828     /**
15829      * Creates a function that checks if **any** of the `predicates` return
15830      * truthy when invoked with the arguments it receives.
15831      *
15832      * @static
15833      * @memberOf _
15834      * @since 4.0.0
15835      * @category Util
15836      * @param {...(Function|Function[])} [predicates=[_.identity]]
15837      *  The predicates to check.
15838      * @returns {Function} Returns the new function.
15839      * @example
15840      *
15841      * var func = _.overSome([Boolean, isFinite]);
15842      *
15843      * func('1');
15844      * // => true
15845      *
15846      * func(null);
15847      * // => true
15848      *
15849      * func(NaN);
15850      * // => false
15851      */
15852     var overSome = createOver(arraySome);
15853
15854     /**
15855      * Creates a function that returns the value at `path` of a given object.
15856      *
15857      * @static
15858      * @memberOf _
15859      * @since 2.4.0
15860      * @category Util
15861      * @param {Array|string} path The path of the property to get.
15862      * @returns {Function} Returns the new accessor function.
15863      * @example
15864      *
15865      * var objects = [
15866      *   { 'a': { 'b': 2 } },
15867      *   { 'a': { 'b': 1 } }
15868      * ];
15869      *
15870      * _.map(objects, _.property('a.b'));
15871      * // => [2, 1]
15872      *
15873      * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
15874      * // => [1, 2]
15875      */
15876     function property(path) {
15877       return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
15878     }
15879
15880     /**
15881      * The opposite of `_.property`; this method creates a function that returns
15882      * the value at a given path of `object`.
15883      *
15884      * @static
15885      * @memberOf _
15886      * @since 3.0.0
15887      * @category Util
15888      * @param {Object} object The object to query.
15889      * @returns {Function} Returns the new accessor function.
15890      * @example
15891      *
15892      * var array = [0, 1, 2],
15893      *     object = { 'a': array, 'b': array, 'c': array };
15894      *
15895      * _.map(['a[2]', 'c[0]'], _.propertyOf(object));
15896      * // => [2, 0]
15897      *
15898      * _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
15899      * // => [2, 0]
15900      */
15901     function propertyOf(object) {
15902       return function(path) {
15903         return object == null ? undefined : baseGet(object, path);
15904       };
15905     }
15906
15907     /**
15908      * Creates an array of numbers (positive and/or negative) progressing from
15909      * `start` up to, but not including, `end`. A step of `-1` is used if a negative
15910      * `start` is specified without an `end` or `step`. If `end` is not specified,
15911      * it's set to `start` with `start` then set to `0`.
15912      *
15913      * **Note:** JavaScript follows the IEEE-754 standard for resolving
15914      * floating-point values which can produce unexpected results.
15915      *
15916      * @static
15917      * @since 0.1.0
15918      * @memberOf _
15919      * @category Util
15920      * @param {number} [start=0] The start of the range.
15921      * @param {number} end The end of the range.
15922      * @param {number} [step=1] The value to increment or decrement by.
15923      * @returns {Array} Returns the range of numbers.
15924      * @see _.inRange, _.rangeRight
15925      * @example
15926      *
15927      * _.range(4);
15928      * // => [0, 1, 2, 3]
15929      *
15930      * _.range(-4);
15931      * // => [0, -1, -2, -3]
15932      *
15933      * _.range(1, 5);
15934      * // => [1, 2, 3, 4]
15935      *
15936      * _.range(0, 20, 5);
15937      * // => [0, 5, 10, 15]
15938      *
15939      * _.range(0, -4, -1);
15940      * // => [0, -1, -2, -3]
15941      *
15942      * _.range(1, 4, 0);
15943      * // => [1, 1, 1]
15944      *
15945      * _.range(0);
15946      * // => []
15947      */
15948     var range = createRange();
15949
15950     /**
15951      * This method is like `_.range` except that it populates values in
15952      * descending order.
15953      *
15954      * @static
15955      * @memberOf _
15956      * @since 4.0.0
15957      * @category Util
15958      * @param {number} [start=0] The start of the range.
15959      * @param {number} end The end of the range.
15960      * @param {number} [step=1] The value to increment or decrement by.
15961      * @returns {Array} Returns the range of numbers.
15962      * @see _.inRange, _.range
15963      * @example
15964      *
15965      * _.rangeRight(4);
15966      * // => [3, 2, 1, 0]
15967      *
15968      * _.rangeRight(-4);
15969      * // => [-3, -2, -1, 0]
15970      *
15971      * _.rangeRight(1, 5);
15972      * // => [4, 3, 2, 1]
15973      *
15974      * _.rangeRight(0, 20, 5);
15975      * // => [15, 10, 5, 0]
15976      *
15977      * _.rangeRight(0, -4, -1);
15978      * // => [-3, -2, -1, 0]
15979      *
15980      * _.rangeRight(1, 4, 0);
15981      * // => [1, 1, 1]
15982      *
15983      * _.rangeRight(0);
15984      * // => []
15985      */
15986     var rangeRight = createRange(true);
15987
15988     /**
15989      * This method returns a new empty array.
15990      *
15991      * @static
15992      * @memberOf _
15993      * @since 4.13.0
15994      * @category Util
15995      * @returns {Array} Returns the new empty array.
15996      * @example
15997      *
15998      * var arrays = _.times(2, _.stubArray);
15999      *
16000      * console.log(arrays);
16001      * // => [[], []]
16002      *
16003      * console.log(arrays[0] === arrays[1]);
16004      * // => false
16005      */
16006     function stubArray() {
16007       return [];
16008     }
16009
16010     /**
16011      * This method returns `false`.
16012      *
16013      * @static
16014      * @memberOf _
16015      * @since 4.13.0
16016      * @category Util
16017      * @returns {boolean} Returns `false`.
16018      * @example
16019      *
16020      * _.times(2, _.stubFalse);
16021      * // => [false, false]
16022      */
16023     function stubFalse() {
16024       return false;
16025     }
16026
16027     /**
16028      * This method returns a new empty object.
16029      *
16030      * @static
16031      * @memberOf _
16032      * @since 4.13.0
16033      * @category Util
16034      * @returns {Object} Returns the new empty object.
16035      * @example
16036      *
16037      * var objects = _.times(2, _.stubObject);
16038      *
16039      * console.log(objects);
16040      * // => [{}, {}]
16041      *
16042      * console.log(objects[0] === objects[1]);
16043      * // => false
16044      */
16045     function stubObject() {
16046       return {};
16047     }
16048
16049     /**
16050      * This method returns an empty string.
16051      *
16052      * @static
16053      * @memberOf _
16054      * @since 4.13.0
16055      * @category Util
16056      * @returns {string} Returns the empty string.
16057      * @example
16058      *
16059      * _.times(2, _.stubString);
16060      * // => ['', '']
16061      */
16062     function stubString() {
16063       return '';
16064     }
16065
16066     /**
16067      * This method returns `true`.
16068      *
16069      * @static
16070      * @memberOf _
16071      * @since 4.13.0
16072      * @category Util
16073      * @returns {boolean} Returns `true`.
16074      * @example
16075      *
16076      * _.times(2, _.stubTrue);
16077      * // => [true, true]
16078      */
16079     function stubTrue() {
16080       return true;
16081     }
16082
16083     /**
16084      * Invokes the iteratee `n` times, returning an array of the results of
16085      * each invocation. The iteratee is invoked with one argument; (index).
16086      *
16087      * @static
16088      * @since 0.1.0
16089      * @memberOf _
16090      * @category Util
16091      * @param {number} n The number of times to invoke `iteratee`.
16092      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
16093      * @returns {Array} Returns the array of results.
16094      * @example
16095      *
16096      * _.times(3, String);
16097      * // => ['0', '1', '2']
16098      *
16099      *  _.times(4, _.constant(0));
16100      * // => [0, 0, 0, 0]
16101      */
16102     function times(n, iteratee) {
16103       n = toInteger(n);
16104       if (n < 1 || n > MAX_SAFE_INTEGER) {
16105         return [];
16106       }
16107       var index = MAX_ARRAY_LENGTH,
16108           length = nativeMin(n, MAX_ARRAY_LENGTH);
16109
16110       iteratee = getIteratee(iteratee);
16111       n -= MAX_ARRAY_LENGTH;
16112
16113       var result = baseTimes(length, iteratee);
16114       while (++index < n) {
16115         iteratee(index);
16116       }
16117       return result;
16118     }
16119
16120     /**
16121      * Converts `value` to a property path array.
16122      *
16123      * @static
16124      * @memberOf _
16125      * @since 4.0.0
16126      * @category Util
16127      * @param {*} value The value to convert.
16128      * @returns {Array} Returns the new property path array.
16129      * @example
16130      *
16131      * _.toPath('a.b.c');
16132      * // => ['a', 'b', 'c']
16133      *
16134      * _.toPath('a[0].b.c');
16135      * // => ['a', '0', 'b', 'c']
16136      */
16137     function toPath(value) {
16138       if (isArray(value)) {
16139         return arrayMap(value, toKey);
16140       }
16141       return isSymbol(value) ? [value] : copyArray(stringToPath(toString(value)));
16142     }
16143
16144     /**
16145      * Generates a unique ID. If `prefix` is given, the ID is appended to it.
16146      *
16147      * @static
16148      * @since 0.1.0
16149      * @memberOf _
16150      * @category Util
16151      * @param {string} [prefix=''] The value to prefix the ID with.
16152      * @returns {string} Returns the unique ID.
16153      * @example
16154      *
16155      * _.uniqueId('contact_');
16156      * // => 'contact_104'
16157      *
16158      * _.uniqueId();
16159      * // => '105'
16160      */
16161     function uniqueId(prefix) {
16162       var id = ++idCounter;
16163       return toString(prefix) + id;
16164     }
16165
16166     /*------------------------------------------------------------------------*/
16167
16168     /**
16169      * Adds two numbers.
16170      *
16171      * @static
16172      * @memberOf _
16173      * @since 3.4.0
16174      * @category Math
16175      * @param {number} augend The first number in an addition.
16176      * @param {number} addend The second number in an addition.
16177      * @returns {number} Returns the total.
16178      * @example
16179      *
16180      * _.add(6, 4);
16181      * // => 10
16182      */
16183     var add = createMathOperation(function(augend, addend) {
16184       return augend + addend;
16185     }, 0);
16186
16187     /**
16188      * Computes `number` rounded up to `precision`.
16189      *
16190      * @static
16191      * @memberOf _
16192      * @since 3.10.0
16193      * @category Math
16194      * @param {number} number The number to round up.
16195      * @param {number} [precision=0] The precision to round up to.
16196      * @returns {number} Returns the rounded up number.
16197      * @example
16198      *
16199      * _.ceil(4.006);
16200      * // => 5
16201      *
16202      * _.ceil(6.004, 2);
16203      * // => 6.01
16204      *
16205      * _.ceil(6040, -2);
16206      * // => 6100
16207      */
16208     var ceil = createRound('ceil');
16209
16210     /**
16211      * Divide two numbers.
16212      *
16213      * @static
16214      * @memberOf _
16215      * @since 4.7.0
16216      * @category Math
16217      * @param {number} dividend The first number in a division.
16218      * @param {number} divisor The second number in a division.
16219      * @returns {number} Returns the quotient.
16220      * @example
16221      *
16222      * _.divide(6, 4);
16223      * // => 1.5
16224      */
16225     var divide = createMathOperation(function(dividend, divisor) {
16226       return dividend / divisor;
16227     }, 1);
16228
16229     /**
16230      * Computes `number` rounded down to `precision`.
16231      *
16232      * @static
16233      * @memberOf _
16234      * @since 3.10.0
16235      * @category Math
16236      * @param {number} number The number to round down.
16237      * @param {number} [precision=0] The precision to round down to.
16238      * @returns {number} Returns the rounded down number.
16239      * @example
16240      *
16241      * _.floor(4.006);
16242      * // => 4
16243      *
16244      * _.floor(0.046, 2);
16245      * // => 0.04
16246      *
16247      * _.floor(4060, -2);
16248      * // => 4000
16249      */
16250     var floor = createRound('floor');
16251
16252     /**
16253      * Computes the maximum value of `array`. If `array` is empty or falsey,
16254      * `undefined` is returned.
16255      *
16256      * @static
16257      * @since 0.1.0
16258      * @memberOf _
16259      * @category Math
16260      * @param {Array} array The array to iterate over.
16261      * @returns {*} Returns the maximum value.
16262      * @example
16263      *
16264      * _.max([4, 2, 8, 6]);
16265      * // => 8
16266      *
16267      * _.max([]);
16268      * // => undefined
16269      */
16270     function max(array) {
16271       return (array && array.length)
16272         ? baseExtremum(array, identity, baseGt)
16273         : undefined;
16274     }
16275
16276     /**
16277      * This method is like `_.max` except that it accepts `iteratee` which is
16278      * invoked for each element in `array` to generate the criterion by which
16279      * the value is ranked. The iteratee is invoked with one argument: (value).
16280      *
16281      * @static
16282      * @memberOf _
16283      * @since 4.0.0
16284      * @category Math
16285      * @param {Array} array The array to iterate over.
16286      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16287      * @returns {*} Returns the maximum value.
16288      * @example
16289      *
16290      * var objects = [{ 'n': 1 }, { 'n': 2 }];
16291      *
16292      * _.maxBy(objects, function(o) { return o.n; });
16293      * // => { 'n': 2 }
16294      *
16295      * // The `_.property` iteratee shorthand.
16296      * _.maxBy(objects, 'n');
16297      * // => { 'n': 2 }
16298      */
16299     function maxBy(array, iteratee) {
16300       return (array && array.length)
16301         ? baseExtremum(array, getIteratee(iteratee, 2), baseGt)
16302         : undefined;
16303     }
16304
16305     /**
16306      * Computes the mean of the values in `array`.
16307      *
16308      * @static
16309      * @memberOf _
16310      * @since 4.0.0
16311      * @category Math
16312      * @param {Array} array The array to iterate over.
16313      * @returns {number} Returns the mean.
16314      * @example
16315      *
16316      * _.mean([4, 2, 8, 6]);
16317      * // => 5
16318      */
16319     function mean(array) {
16320       return baseMean(array, identity);
16321     }
16322
16323     /**
16324      * This method is like `_.mean` except that it accepts `iteratee` which is
16325      * invoked for each element in `array` to generate the value to be averaged.
16326      * The iteratee is invoked with one argument: (value).
16327      *
16328      * @static
16329      * @memberOf _
16330      * @since 4.7.0
16331      * @category Math
16332      * @param {Array} array The array to iterate over.
16333      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16334      * @returns {number} Returns the mean.
16335      * @example
16336      *
16337      * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
16338      *
16339      * _.meanBy(objects, function(o) { return o.n; });
16340      * // => 5
16341      *
16342      * // The `_.property` iteratee shorthand.
16343      * _.meanBy(objects, 'n');
16344      * // => 5
16345      */
16346     function meanBy(array, iteratee) {
16347       return baseMean(array, getIteratee(iteratee, 2));
16348     }
16349
16350     /**
16351      * Computes the minimum value of `array`. If `array` is empty or falsey,
16352      * `undefined` is returned.
16353      *
16354      * @static
16355      * @since 0.1.0
16356      * @memberOf _
16357      * @category Math
16358      * @param {Array} array The array to iterate over.
16359      * @returns {*} Returns the minimum value.
16360      * @example
16361      *
16362      * _.min([4, 2, 8, 6]);
16363      * // => 2
16364      *
16365      * _.min([]);
16366      * // => undefined
16367      */
16368     function min(array) {
16369       return (array && array.length)
16370         ? baseExtremum(array, identity, baseLt)
16371         : undefined;
16372     }
16373
16374     /**
16375      * This method is like `_.min` except that it accepts `iteratee` which is
16376      * invoked for each element in `array` to generate the criterion by which
16377      * the value is ranked. The iteratee is invoked with one argument: (value).
16378      *
16379      * @static
16380      * @memberOf _
16381      * @since 4.0.0
16382      * @category Math
16383      * @param {Array} array The array to iterate over.
16384      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16385      * @returns {*} Returns the minimum value.
16386      * @example
16387      *
16388      * var objects = [{ 'n': 1 }, { 'n': 2 }];
16389      *
16390      * _.minBy(objects, function(o) { return o.n; });
16391      * // => { 'n': 1 }
16392      *
16393      * // The `_.property` iteratee shorthand.
16394      * _.minBy(objects, 'n');
16395      * // => { 'n': 1 }
16396      */
16397     function minBy(array, iteratee) {
16398       return (array && array.length)
16399         ? baseExtremum(array, getIteratee(iteratee, 2), baseLt)
16400         : undefined;
16401     }
16402
16403     /**
16404      * Multiply two numbers.
16405      *
16406      * @static
16407      * @memberOf _
16408      * @since 4.7.0
16409      * @category Math
16410      * @param {number} multiplier The first number in a multiplication.
16411      * @param {number} multiplicand The second number in a multiplication.
16412      * @returns {number} Returns the product.
16413      * @example
16414      *
16415      * _.multiply(6, 4);
16416      * // => 24
16417      */
16418     var multiply = createMathOperation(function(multiplier, multiplicand) {
16419       return multiplier * multiplicand;
16420     }, 1);
16421
16422     /**
16423      * Computes `number` rounded to `precision`.
16424      *
16425      * @static
16426      * @memberOf _
16427      * @since 3.10.0
16428      * @category Math
16429      * @param {number} number The number to round.
16430      * @param {number} [precision=0] The precision to round to.
16431      * @returns {number} Returns the rounded number.
16432      * @example
16433      *
16434      * _.round(4.006);
16435      * // => 4
16436      *
16437      * _.round(4.006, 2);
16438      * // => 4.01
16439      *
16440      * _.round(4060, -2);
16441      * // => 4100
16442      */
16443     var round = createRound('round');
16444
16445     /**
16446      * Subtract two numbers.
16447      *
16448      * @static
16449      * @memberOf _
16450      * @since 4.0.0
16451      * @category Math
16452      * @param {number} minuend The first number in a subtraction.
16453      * @param {number} subtrahend The second number in a subtraction.
16454      * @returns {number} Returns the difference.
16455      * @example
16456      *
16457      * _.subtract(6, 4);
16458      * // => 2
16459      */
16460     var subtract = createMathOperation(function(minuend, subtrahend) {
16461       return minuend - subtrahend;
16462     }, 0);
16463
16464     /**
16465      * Computes the sum of the values in `array`.
16466      *
16467      * @static
16468      * @memberOf _
16469      * @since 3.4.0
16470      * @category Math
16471      * @param {Array} array The array to iterate over.
16472      * @returns {number} Returns the sum.
16473      * @example
16474      *
16475      * _.sum([4, 2, 8, 6]);
16476      * // => 20
16477      */
16478     function sum(array) {
16479       return (array && array.length)
16480         ? baseSum(array, identity)
16481         : 0;
16482     }
16483
16484     /**
16485      * This method is like `_.sum` except that it accepts `iteratee` which is
16486      * invoked for each element in `array` to generate the value to be summed.
16487      * The iteratee is invoked with one argument: (value).
16488      *
16489      * @static
16490      * @memberOf _
16491      * @since 4.0.0
16492      * @category Math
16493      * @param {Array} array The array to iterate over.
16494      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16495      * @returns {number} Returns the sum.
16496      * @example
16497      *
16498      * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
16499      *
16500      * _.sumBy(objects, function(o) { return o.n; });
16501      * // => 20
16502      *
16503      * // The `_.property` iteratee shorthand.
16504      * _.sumBy(objects, 'n');
16505      * // => 20
16506      */
16507     function sumBy(array, iteratee) {
16508       return (array && array.length)
16509         ? baseSum(array, getIteratee(iteratee, 2))
16510         : 0;
16511     }
16512
16513     /*------------------------------------------------------------------------*/
16514
16515     // Add methods that return wrapped values in chain sequences.
16516     lodash.after = after;
16517     lodash.ary = ary;
16518     lodash.assign = assign;
16519     lodash.assignIn = assignIn;
16520     lodash.assignInWith = assignInWith;
16521     lodash.assignWith = assignWith;
16522     lodash.at = at;
16523     lodash.before = before;
16524     lodash.bind = bind;
16525     lodash.bindAll = bindAll;
16526     lodash.bindKey = bindKey;
16527     lodash.castArray = castArray;
16528     lodash.chain = chain;
16529     lodash.chunk = chunk;
16530     lodash.compact = compact;
16531     lodash.concat = concat;
16532     lodash.cond = cond;
16533     lodash.conforms = conforms;
16534     lodash.constant = constant;
16535     lodash.countBy = countBy;
16536     lodash.create = create;
16537     lodash.curry = curry;
16538     lodash.curryRight = curryRight;
16539     lodash.debounce = debounce;
16540     lodash.defaults = defaults;
16541     lodash.defaultsDeep = defaultsDeep;
16542     lodash.defer = defer;
16543     lodash.delay = delay;
16544     lodash.difference = difference;
16545     lodash.differenceBy = differenceBy;
16546     lodash.differenceWith = differenceWith;
16547     lodash.drop = drop;
16548     lodash.dropRight = dropRight;
16549     lodash.dropRightWhile = dropRightWhile;
16550     lodash.dropWhile = dropWhile;
16551     lodash.fill = fill;
16552     lodash.filter = filter;
16553     lodash.flatMap = flatMap;
16554     lodash.flatMapDeep = flatMapDeep;
16555     lodash.flatMapDepth = flatMapDepth;
16556     lodash.flatten = flatten;
16557     lodash.flattenDeep = flattenDeep;
16558     lodash.flattenDepth = flattenDepth;
16559     lodash.flip = flip;
16560     lodash.flow = flow;
16561     lodash.flowRight = flowRight;
16562     lodash.fromPairs = fromPairs;
16563     lodash.functions = functions;
16564     lodash.functionsIn = functionsIn;
16565     lodash.groupBy = groupBy;
16566     lodash.initial = initial;
16567     lodash.intersection = intersection;
16568     lodash.intersectionBy = intersectionBy;
16569     lodash.intersectionWith = intersectionWith;
16570     lodash.invert = invert;
16571     lodash.invertBy = invertBy;
16572     lodash.invokeMap = invokeMap;
16573     lodash.iteratee = iteratee;
16574     lodash.keyBy = keyBy;
16575     lodash.keys = keys;
16576     lodash.keysIn = keysIn;
16577     lodash.map = map;
16578     lodash.mapKeys = mapKeys;
16579     lodash.mapValues = mapValues;
16580     lodash.matches = matches;
16581     lodash.matchesProperty = matchesProperty;
16582     lodash.memoize = memoize;
16583     lodash.merge = merge;
16584     lodash.mergeWith = mergeWith;
16585     lodash.method = method;
16586     lodash.methodOf = methodOf;
16587     lodash.mixin = mixin;
16588     lodash.negate = negate;
16589     lodash.nthArg = nthArg;
16590     lodash.omit = omit;
16591     lodash.omitBy = omitBy;
16592     lodash.once = once;
16593     lodash.orderBy = orderBy;
16594     lodash.over = over;
16595     lodash.overArgs = overArgs;
16596     lodash.overEvery = overEvery;
16597     lodash.overSome = overSome;
16598     lodash.partial = partial;
16599     lodash.partialRight = partialRight;
16600     lodash.partition = partition;
16601     lodash.pick = pick;
16602     lodash.pickBy = pickBy;
16603     lodash.property = property;
16604     lodash.propertyOf = propertyOf;
16605     lodash.pull = pull;
16606     lodash.pullAll = pullAll;
16607     lodash.pullAllBy = pullAllBy;
16608     lodash.pullAllWith = pullAllWith;
16609     lodash.pullAt = pullAt;
16610     lodash.range = range;
16611     lodash.rangeRight = rangeRight;
16612     lodash.rearg = rearg;
16613     lodash.reject = reject;
16614     lodash.remove = remove;
16615     lodash.rest = rest;
16616     lodash.reverse = reverse;
16617     lodash.sampleSize = sampleSize;
16618     lodash.set = set;
16619     lodash.setWith = setWith;
16620     lodash.shuffle = shuffle;
16621     lodash.slice = slice;
16622     lodash.sortBy = sortBy;
16623     lodash.sortedUniq = sortedUniq;
16624     lodash.sortedUniqBy = sortedUniqBy;
16625     lodash.split = split;
16626     lodash.spread = spread;
16627     lodash.tail = tail;
16628     lodash.take = take;
16629     lodash.takeRight = takeRight;
16630     lodash.takeRightWhile = takeRightWhile;
16631     lodash.takeWhile = takeWhile;
16632     lodash.tap = tap;
16633     lodash.throttle = throttle;
16634     lodash.thru = thru;
16635     lodash.toArray = toArray;
16636     lodash.toPairs = toPairs;
16637     lodash.toPairsIn = toPairsIn;
16638     lodash.toPath = toPath;
16639     lodash.toPlainObject = toPlainObject;
16640     lodash.transform = transform;
16641     lodash.unary = unary;
16642     lodash.union = union;
16643     lodash.unionBy = unionBy;
16644     lodash.unionWith = unionWith;
16645     lodash.uniq = uniq;
16646     lodash.uniqBy = uniqBy;
16647     lodash.uniqWith = uniqWith;
16648     lodash.unset = unset;
16649     lodash.unzip = unzip;
16650     lodash.unzipWith = unzipWith;
16651     lodash.update = update;
16652     lodash.updateWith = updateWith;
16653     lodash.values = values;
16654     lodash.valuesIn = valuesIn;
16655     lodash.without = without;
16656     lodash.words = words;
16657     lodash.wrap = wrap;
16658     lodash.xor = xor;
16659     lodash.xorBy = xorBy;
16660     lodash.xorWith = xorWith;
16661     lodash.zip = zip;
16662     lodash.zipObject = zipObject;
16663     lodash.zipObjectDeep = zipObjectDeep;
16664     lodash.zipWith = zipWith;
16665
16666     // Add aliases.
16667     lodash.entries = toPairs;
16668     lodash.entriesIn = toPairsIn;
16669     lodash.extend = assignIn;
16670     lodash.extendWith = assignInWith;
16671
16672     // Add methods to `lodash.prototype`.
16673     mixin(lodash, lodash);
16674
16675     /*------------------------------------------------------------------------*/
16676
16677     // Add methods that return unwrapped values in chain sequences.
16678     lodash.add = add;
16679     lodash.attempt = attempt;
16680     lodash.camelCase = camelCase;
16681     lodash.capitalize = capitalize;
16682     lodash.ceil = ceil;
16683     lodash.clamp = clamp;
16684     lodash.clone = clone;
16685     lodash.cloneDeep = cloneDeep;
16686     lodash.cloneDeepWith = cloneDeepWith;
16687     lodash.cloneWith = cloneWith;
16688     lodash.conformsTo = conformsTo;
16689     lodash.deburr = deburr;
16690     lodash.defaultTo = defaultTo;
16691     lodash.divide = divide;
16692     lodash.endsWith = endsWith;
16693     lodash.eq = eq;
16694     lodash.escape = escape;
16695     lodash.escapeRegExp = escapeRegExp;
16696     lodash.every = every;
16697     lodash.find = find;
16698     lodash.findIndex = findIndex;
16699     lodash.findKey = findKey;
16700     lodash.findLast = findLast;
16701     lodash.findLastIndex = findLastIndex;
16702     lodash.findLastKey = findLastKey;
16703     lodash.floor = floor;
16704     lodash.forEach = forEach;
16705     lodash.forEachRight = forEachRight;
16706     lodash.forIn = forIn;
16707     lodash.forInRight = forInRight;
16708     lodash.forOwn = forOwn;
16709     lodash.forOwnRight = forOwnRight;
16710     lodash.get = get;
16711     lodash.gt = gt;
16712     lodash.gte = gte;
16713     lodash.has = has;
16714     lodash.hasIn = hasIn;
16715     lodash.head = head;
16716     lodash.identity = identity;
16717     lodash.includes = includes;
16718     lodash.indexOf = indexOf;
16719     lodash.inRange = inRange;
16720     lodash.invoke = invoke;
16721     lodash.isArguments = isArguments;
16722     lodash.isArray = isArray;
16723     lodash.isArrayBuffer = isArrayBuffer;
16724     lodash.isArrayLike = isArrayLike;
16725     lodash.isArrayLikeObject = isArrayLikeObject;
16726     lodash.isBoolean = isBoolean;
16727     lodash.isBuffer = isBuffer;
16728     lodash.isDate = isDate;
16729     lodash.isElement = isElement;
16730     lodash.isEmpty = isEmpty;
16731     lodash.isEqual = isEqual;
16732     lodash.isEqualWith = isEqualWith;
16733     lodash.isError = isError;
16734     lodash.isFinite = isFinite;
16735     lodash.isFunction = isFunction;
16736     lodash.isInteger = isInteger;
16737     lodash.isLength = isLength;
16738     lodash.isMap = isMap;
16739     lodash.isMatch = isMatch;
16740     lodash.isMatchWith = isMatchWith;
16741     lodash.isNaN = isNaN;
16742     lodash.isNative = isNative;
16743     lodash.isNil = isNil;
16744     lodash.isNull = isNull;
16745     lodash.isNumber = isNumber;
16746     lodash.isObject = isObject;
16747     lodash.isObjectLike = isObjectLike;
16748     lodash.isPlainObject = isPlainObject;
16749     lodash.isRegExp = isRegExp;
16750     lodash.isSafeInteger = isSafeInteger;
16751     lodash.isSet = isSet;
16752     lodash.isString = isString;
16753     lodash.isSymbol = isSymbol;
16754     lodash.isTypedArray = isTypedArray;
16755     lodash.isUndefined = isUndefined;
16756     lodash.isWeakMap = isWeakMap;
16757     lodash.isWeakSet = isWeakSet;
16758     lodash.join = join;
16759     lodash.kebabCase = kebabCase;
16760     lodash.last = last;
16761     lodash.lastIndexOf = lastIndexOf;
16762     lodash.lowerCase = lowerCase;
16763     lodash.lowerFirst = lowerFirst;
16764     lodash.lt = lt;
16765     lodash.lte = lte;
16766     lodash.max = max;
16767     lodash.maxBy = maxBy;
16768     lodash.mean = mean;
16769     lodash.meanBy = meanBy;
16770     lodash.min = min;
16771     lodash.minBy = minBy;
16772     lodash.stubArray = stubArray;
16773     lodash.stubFalse = stubFalse;
16774     lodash.stubObject = stubObject;
16775     lodash.stubString = stubString;
16776     lodash.stubTrue = stubTrue;
16777     lodash.multiply = multiply;
16778     lodash.nth = nth;
16779     lodash.noConflict = noConflict;
16780     lodash.noop = noop;
16781     lodash.now = now;
16782     lodash.pad = pad;
16783     lodash.padEnd = padEnd;
16784     lodash.padStart = padStart;
16785     lodash.parseInt = parseInt;
16786     lodash.random = random;
16787     lodash.reduce = reduce;
16788     lodash.reduceRight = reduceRight;
16789     lodash.repeat = repeat;
16790     lodash.replace = replace;
16791     lodash.result = result;
16792     lodash.round = round;
16793     lodash.runInContext = runInContext;
16794     lodash.sample = sample;
16795     lodash.size = size;
16796     lodash.snakeCase = snakeCase;
16797     lodash.some = some;
16798     lodash.sortedIndex = sortedIndex;
16799     lodash.sortedIndexBy = sortedIndexBy;
16800     lodash.sortedIndexOf = sortedIndexOf;
16801     lodash.sortedLastIndex = sortedLastIndex;
16802     lodash.sortedLastIndexBy = sortedLastIndexBy;
16803     lodash.sortedLastIndexOf = sortedLastIndexOf;
16804     lodash.startCase = startCase;
16805     lodash.startsWith = startsWith;
16806     lodash.subtract = subtract;
16807     lodash.sum = sum;
16808     lodash.sumBy = sumBy;
16809     lodash.template = template;
16810     lodash.times = times;
16811     lodash.toFinite = toFinite;
16812     lodash.toInteger = toInteger;
16813     lodash.toLength = toLength;
16814     lodash.toLower = toLower;
16815     lodash.toNumber = toNumber;
16816     lodash.toSafeInteger = toSafeInteger;
16817     lodash.toString = toString;
16818     lodash.toUpper = toUpper;
16819     lodash.trim = trim;
16820     lodash.trimEnd = trimEnd;
16821     lodash.trimStart = trimStart;
16822     lodash.truncate = truncate;
16823     lodash.unescape = unescape;
16824     lodash.uniqueId = uniqueId;
16825     lodash.upperCase = upperCase;
16826     lodash.upperFirst = upperFirst;
16827
16828     // Add aliases.
16829     lodash.each = forEach;
16830     lodash.eachRight = forEachRight;
16831     lodash.first = head;
16832
16833     mixin(lodash, (function() {
16834       var source = {};
16835       baseForOwn(lodash, function(func, methodName) {
16836         if (!hasOwnProperty.call(lodash.prototype, methodName)) {
16837           source[methodName] = func;
16838         }
16839       });
16840       return source;
16841     }()), { 'chain': false });
16842
16843     /*------------------------------------------------------------------------*/
16844
16845     /**
16846      * The semantic version number.
16847      *
16848      * @static
16849      * @memberOf _
16850      * @type {string}
16851      */
16852     lodash.VERSION = VERSION;
16853
16854     // Assign default placeholders.
16855     arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
16856       lodash[methodName].placeholder = lodash;
16857     });
16858
16859     // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
16860     arrayEach(['drop', 'take'], function(methodName, index) {
16861       LazyWrapper.prototype[methodName] = function(n) {
16862         n = n === undefined ? 1 : nativeMax(toInteger(n), 0);
16863
16864         var result = (this.__filtered__ && !index)
16865           ? new LazyWrapper(this)
16866           : this.clone();
16867
16868         if (result.__filtered__) {
16869           result.__takeCount__ = nativeMin(n, result.__takeCount__);
16870         } else {
16871           result.__views__.push({
16872             'size': nativeMin(n, MAX_ARRAY_LENGTH),
16873             'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
16874           });
16875         }
16876         return result;
16877       };
16878
16879       LazyWrapper.prototype[methodName + 'Right'] = function(n) {
16880         return this.reverse()[methodName](n).reverse();
16881       };
16882     });
16883
16884     // Add `LazyWrapper` methods that accept an `iteratee` value.
16885     arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
16886       var type = index + 1,
16887           isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;
16888
16889       LazyWrapper.prototype[methodName] = function(iteratee) {
16890         var result = this.clone();
16891         result.__iteratees__.push({
16892           'iteratee': getIteratee(iteratee, 3),
16893           'type': type
16894         });
16895         result.__filtered__ = result.__filtered__ || isFilter;
16896         return result;
16897       };
16898     });
16899
16900     // Add `LazyWrapper` methods for `_.head` and `_.last`.
16901     arrayEach(['head', 'last'], function(methodName, index) {
16902       var takeName = 'take' + (index ? 'Right' : '');
16903
16904       LazyWrapper.prototype[methodName] = function() {
16905         return this[takeName](1).value()[0];
16906       };
16907     });
16908
16909     // Add `LazyWrapper` methods for `_.initial` and `_.tail`.
16910     arrayEach(['initial', 'tail'], function(methodName, index) {
16911       var dropName = 'drop' + (index ? '' : 'Right');
16912
16913       LazyWrapper.prototype[methodName] = function() {
16914         return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
16915       };
16916     });
16917
16918     LazyWrapper.prototype.compact = function() {
16919       return this.filter(identity);
16920     };
16921
16922     LazyWrapper.prototype.find = function(predicate) {
16923       return this.filter(predicate).head();
16924     };
16925
16926     LazyWrapper.prototype.findLast = function(predicate) {
16927       return this.reverse().find(predicate);
16928     };
16929
16930     LazyWrapper.prototype.invokeMap = baseRest(function(path, args) {
16931       if (typeof path == 'function') {
16932         return new LazyWrapper(this);
16933       }
16934       return this.map(function(value) {
16935         return baseInvoke(value, path, args);
16936       });
16937     });
16938
16939     LazyWrapper.prototype.reject = function(predicate) {
16940       return this.filter(negate(getIteratee(predicate)));
16941     };
16942
16943     LazyWrapper.prototype.slice = function(start, end) {
16944       start = toInteger(start);
16945
16946       var result = this;
16947       if (result.__filtered__ && (start > 0 || end < 0)) {
16948         return new LazyWrapper(result);
16949       }
16950       if (start < 0) {
16951         result = result.takeRight(-start);
16952       } else if (start) {
16953         result = result.drop(start);
16954       }
16955       if (end !== undefined) {
16956         end = toInteger(end);
16957         result = end < 0 ? result.dropRight(-end) : result.take(end - start);
16958       }
16959       return result;
16960     };
16961
16962     LazyWrapper.prototype.takeRightWhile = function(predicate) {
16963       return this.reverse().takeWhile(predicate).reverse();
16964     };
16965
16966     LazyWrapper.prototype.toArray = function() {
16967       return this.take(MAX_ARRAY_LENGTH);
16968     };
16969
16970     // Add `LazyWrapper` methods to `lodash.prototype`.
16971     baseForOwn(LazyWrapper.prototype, function(func, methodName) {
16972       var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
16973           isTaker = /^(?:head|last)$/.test(methodName),
16974           lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
16975           retUnwrapped = isTaker || /^find/.test(methodName);
16976
16977       if (!lodashFunc) {
16978         return;
16979       }
16980       lodash.prototype[methodName] = function() {
16981         var value = this.__wrapped__,
16982             args = isTaker ? [1] : arguments,
16983             isLazy = value instanceof LazyWrapper,
16984             iteratee = args[0],
16985             useLazy = isLazy || isArray(value);
16986
16987         var interceptor = function(value) {
16988           var result = lodashFunc.apply(lodash, arrayPush([value], args));
16989           return (isTaker && chainAll) ? result[0] : result;
16990         };
16991
16992         if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
16993           // Avoid lazy use if the iteratee has a "length" value other than `1`.
16994           isLazy = useLazy = false;
16995         }
16996         var chainAll = this.__chain__,
16997             isHybrid = !!this.__actions__.length,
16998             isUnwrapped = retUnwrapped && !chainAll,
16999             onlyLazy = isLazy && !isHybrid;
17000
17001         if (!retUnwrapped && useLazy) {
17002           value = onlyLazy ? value : new LazyWrapper(this);
17003           var result = func.apply(value, args);
17004           result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
17005           return new LodashWrapper(result, chainAll);
17006         }
17007         if (isUnwrapped && onlyLazy) {
17008           return func.apply(this, args);
17009         }
17010         result = this.thru(interceptor);
17011         return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
17012       };
17013     });
17014
17015     // Add `Array` methods to `lodash.prototype`.
17016     arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
17017       var func = arrayProto[methodName],
17018           chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
17019           retUnwrapped = /^(?:pop|shift)$/.test(methodName);
17020
17021       lodash.prototype[methodName] = function() {
17022         var args = arguments;
17023         if (retUnwrapped && !this.__chain__) {
17024           var value = this.value();
17025           return func.apply(isArray(value) ? value : [], args);
17026         }
17027         return this[chainName](function(value) {
17028           return func.apply(isArray(value) ? value : [], args);
17029         });
17030       };
17031     });
17032
17033     // Map minified method names to their real names.
17034     baseForOwn(LazyWrapper.prototype, function(func, methodName) {
17035       var lodashFunc = lodash[methodName];
17036       if (lodashFunc) {
17037         var key = (lodashFunc.name + ''),
17038             names = realNames[key] || (realNames[key] = []);
17039
17040         names.push({ 'name': methodName, 'func': lodashFunc });
17041       }
17042     });
17043
17044     realNames[createHybrid(undefined, WRAP_BIND_KEY_FLAG).name] = [{
17045       'name': 'wrapper',
17046       'func': undefined
17047     }];
17048
17049     // Add methods to `LazyWrapper`.
17050     LazyWrapper.prototype.clone = lazyClone;
17051     LazyWrapper.prototype.reverse = lazyReverse;
17052     LazyWrapper.prototype.value = lazyValue;
17053
17054     // Add chain sequence methods to the `lodash` wrapper.
17055     lodash.prototype.at = wrapperAt;
17056     lodash.prototype.chain = wrapperChain;
17057     lodash.prototype.commit = wrapperCommit;
17058     lodash.prototype.next = wrapperNext;
17059     lodash.prototype.plant = wrapperPlant;
17060     lodash.prototype.reverse = wrapperReverse;
17061     lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
17062
17063     // Add lazy aliases.
17064     lodash.prototype.first = lodash.prototype.head;
17065
17066     if (symIterator) {
17067       lodash.prototype[symIterator] = wrapperToIterator;
17068     }
17069     return lodash;
17070   });
17071
17072   /*--------------------------------------------------------------------------*/
17073
17074   // Export lodash.
17075   var _ = runInContext();
17076
17077   // Some AMD build optimizers, like r.js, check for condition patterns like:
17078   if (typeof undefined == 'function' && typeof undefined.amd == 'object' && undefined.amd) {
17079     // Expose Lodash on the global object to prevent errors when Lodash is
17080     // loaded by a script tag in the presence of an AMD loader.
17081     // See http://requirejs.org/docs/errors.html#mismatch for more details.
17082     // Use `_.noConflict` to remove Lodash from the global object.
17083     root._ = _;
17084
17085     // Define as an anonymous module so, through path mapping, it can be
17086     // referenced as the "underscore" module.
17087     undefined(function() {
17088       return _;
17089     });
17090   }
17091   // Check for `exports` after `define` in case a build optimizer adds it.
17092   else if (freeModule) {
17093     // Export for Node.js.
17094     (freeModule.exports = _)._ = _;
17095     // Export for CommonJS support.
17096     freeExports._ = _;
17097   }
17098   else {
17099     // Export to the global object.
17100     root._ = _;
17101   }
17102 }.call(commonjsGlobal));
17103 });
17104
17105
17106
17107 var lodash$1 = Object.freeze({
17108         default: lodash,
17109         __moduleExports: lodash
17110 });
17111
17112 function osmIsInterestingTag(key) {
17113     return key !== 'attribution' &&
17114         key !== 'created_by' &&
17115         key !== 'source' &&
17116         key !== 'odbl' &&
17117         key.indexOf('tiger:') !== 0;
17118
17119 }
17120
17121
17122 var osmOneWayTags = {
17123     'aerialway': {
17124         'chair_lift': true,
17125         'mixed_lift': true,
17126         't-bar': true,
17127         'j-bar': true,
17128         'platter': true,
17129         'rope_tow': true,
17130         'magic_carpet': true,
17131         'yes': true
17132     },
17133     'highway': {
17134         'motorway': true,
17135         'motorway_link': true
17136     },
17137     'junction': {
17138         'roundabout': true
17139     },
17140     'man_made': {
17141         'piste:halfpipe': true
17142     },
17143     'piste:type': {
17144         'downhill': true,
17145         'sled': true,
17146         'yes': true
17147     },
17148     'waterway': {
17149         'canal': true,
17150         'ditch': true,
17151         'drain': true,
17152         'river': true,
17153         'stream': true
17154     }
17155 };
17156
17157
17158 var osmPavedTags = {
17159     'surface': {
17160         'paved': true,
17161         'asphalt': true,
17162         'concrete': true
17163     },
17164     'tracktype': {
17165         'grade1': true
17166     }
17167 };
17168
17169 var dataWikipedia = [
17170     [
17171         "Abkhazian",
17172         "Аҧсшәа",
17173         "ab"
17174     ],
17175     [
17176         "Achinese",
17177         "Acèh",
17178         "ace"
17179     ],
17180     [
17181         "Adyghe",
17182         "адыгабзэ",
17183         "ady"
17184     ],
17185     [
17186         "Afrikaans",
17187         "Afrikaans",
17188         "af"
17189     ],
17190     [
17191         "Akan",
17192         "Akan",
17193         "ak"
17194     ],
17195     [
17196         "Alemannisch",
17197         "Alemannisch",
17198         "als"
17199     ],
17200     [
17201         "Amharic",
17202         "አማርኛ",
17203         "am"
17204     ],
17205     [
17206         "Aragonese",
17207         "aragonés",
17208         "an"
17209     ],
17210     [
17211         "Old English",
17212         "Ænglisc",
17213         "ang"
17214     ],
17215     [
17216         "Arabic",
17217         "العربية",
17218         "ar"
17219     ],
17220     [
17221         "Aramaic",
17222         "ܐܪܡܝܐ",
17223         "arc"
17224     ],
17225     [
17226         "Egyptian Arabic",
17227         "مصرى",
17228         "arz"
17229     ],
17230     [
17231         "Assamese",
17232         "অসমীয়া",
17233         "as"
17234     ],
17235     [
17236         "Asturian",
17237         "asturianu",
17238         "ast"
17239     ],
17240     [
17241         "Avaric",
17242         "авар",
17243         "av"
17244     ],
17245     [
17246         "Aymara",
17247         "Aymar aru",
17248         "ay"
17249     ],
17250     [
17251         "Azerbaijani",
17252         "azərbaycanca",
17253         "az"
17254     ],
17255     [
17256         "تۆرکجه",
17257         "تۆرکجه",
17258         "azb"
17259     ],
17260     [
17261         "Bashkir",
17262         "башҡортса",
17263         "ba"
17264     ],
17265     [
17266         "Bavarian",
17267         "Boarisch",
17268         "bar"
17269     ],
17270     [
17271         "Samogitian",
17272         "žemaitėška",
17273         "bat-smg"
17274     ],
17275     [
17276         "Bikol Central",
17277         "Bikol Central",
17278         "bcl"
17279     ],
17280     [
17281         "Belarusian",
17282         "беларуская",
17283         "be"
17284     ],
17285     [
17286         "беларуская (тарашкевіца)‎",
17287         "беларуская (тарашкевіца)‎",
17288         "be-x-old"
17289     ],
17290     [
17291         "Bulgarian",
17292         "български",
17293         "bg"
17294     ],
17295     [
17296         "भोजपुरी",
17297         "भोजपुरी",
17298         "bh"
17299     ],
17300     [
17301         "Bislama",
17302         "Bislama",
17303         "bi"
17304     ],
17305     [
17306         "Banjar",
17307         "Bahasa Banjar",
17308         "bjn"
17309     ],
17310     [
17311         "Bambara",
17312         "bamanankan",
17313         "bm"
17314     ],
17315     [
17316         "Bangla",
17317         "বাংলা",
17318         "bn"
17319     ],
17320     [
17321         "Tibetan",
17322         "བོད་ཡིག",
17323         "bo"
17324     ],
17325     [
17326         "Bishnupriya",
17327         "বিষ্ণুপ্রিয়া মণিপুরী",
17328         "bpy"
17329     ],
17330     [
17331         "Breton",
17332         "brezhoneg",
17333         "br"
17334     ],
17335     [
17336         "Bosnian",
17337         "bosanski",
17338         "bs"
17339     ],
17340     [
17341         "Buginese",
17342         "ᨅᨔ ᨕᨘᨁᨗ",
17343         "bug"
17344     ],
17345     [
17346         "буряад",
17347         "буряад",
17348         "bxr"
17349     ],
17350     [
17351         "Catalan",
17352         "català",
17353         "ca"
17354     ],
17355     [
17356         "Chavacano de Zamboanga",
17357         "Chavacano de Zamboanga",
17358         "cbk-zam"
17359     ],
17360     [
17361         "Min Dong Chinese",
17362         "Mìng-dĕ̤ng-ngṳ̄",
17363         "cdo"
17364     ],
17365     [
17366         "Chechen",
17367         "нохчийн",
17368         "ce"
17369     ],
17370     [
17371         "Cebuano",
17372         "Cebuano",
17373         "ceb"
17374     ],
17375     [
17376         "Chamorro",
17377         "Chamoru",
17378         "ch"
17379     ],
17380     [
17381         "Cherokee",
17382         "ᏣᎳᎩ",
17383         "chr"
17384     ],
17385     [
17386         "Cheyenne",
17387         "Tsetsêhestâhese",
17388         "chy"
17389     ],
17390     [
17391         "Central Kurdish",
17392         "کوردیی ناوەندی",
17393         "ckb"
17394     ],
17395     [
17396         "Corsican",
17397         "corsu",
17398         "co"
17399     ],
17400     [
17401         "Cree",
17402         "Nēhiyawēwin / ᓀᐦᐃᔭᐍᐏᐣ",
17403         "cr"
17404     ],
17405     [
17406         "Crimean Turkish",
17407         "qırımtatarca",
17408         "crh"
17409     ],
17410     [
17411         "Czech",
17412         "čeština",
17413         "cs"
17414     ],
17415     [
17416         "Kashubian",
17417         "kaszëbsczi",
17418         "csb"
17419     ],
17420     [
17421         "Church Slavic",
17422         "словѣньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ",
17423         "cu"
17424     ],
17425     [
17426         "Chuvash",
17427         "Чӑвашла",
17428         "cv"
17429     ],
17430     [
17431         "Welsh",
17432         "Cymraeg",
17433         "cy"
17434     ],
17435     [
17436         "Danish",
17437         "dansk",
17438         "da"
17439     ],
17440     [
17441         "German",
17442         "Deutsch",
17443         "de"
17444     ],
17445     [
17446         "Zazaki",
17447         "Zazaki",
17448         "diq"
17449     ],
17450     [
17451         "Lower Sorbian",
17452         "dolnoserbski",
17453         "dsb"
17454     ],
17455     [
17456         "Divehi",
17457         "ދިވެހިބަސް",
17458         "dv"
17459     ],
17460     [
17461         "Dzongkha",
17462         "ཇོང་ཁ",
17463         "dz"
17464     ],
17465     [
17466         "Ewe",
17467         "eʋegbe",
17468         "ee"
17469     ],
17470     [
17471         "Greek",
17472         "Ελληνικά",
17473         "el"
17474     ],
17475     [
17476         "Emiliano-Romagnolo",
17477         "emiliàn e rumagnòl",
17478         "eml"
17479     ],
17480     [
17481         "English",
17482         "English",
17483         "en"
17484     ],
17485     [
17486         "Esperanto",
17487         "Esperanto",
17488         "eo"
17489     ],
17490     [
17491         "Spanish",
17492         "español",
17493         "es"
17494     ],
17495     [
17496         "Estonian",
17497         "eesti",
17498         "et"
17499     ],
17500     [
17501         "Basque",
17502         "euskara",
17503         "eu"
17504     ],
17505     [
17506         "Extremaduran",
17507         "estremeñu",
17508         "ext"
17509     ],
17510     [
17511         "Persian",
17512         "فارسی",
17513         "fa"
17514     ],
17515     [
17516         "Fulah",
17517         "Fulfulde",
17518         "ff"
17519     ],
17520     [
17521         "Finnish",
17522         "suomi",
17523         "fi"
17524     ],
17525     [
17526         "Võro",
17527         "Võro",
17528         "fiu-vro"
17529     ],
17530     [
17531         "Fijian",
17532         "Na Vosa Vakaviti",
17533         "fj"
17534     ],
17535     [
17536         "Faroese",
17537         "føroyskt",
17538         "fo"
17539     ],
17540     [
17541         "French",
17542         "français",
17543         "fr"
17544     ],
17545     [
17546         "Arpitan",
17547         "arpetan",
17548         "frp"
17549     ],
17550     [
17551         "Northern Frisian",
17552         "Nordfriisk",
17553         "frr"
17554     ],
17555     [
17556         "Friulian",
17557         "furlan",
17558         "fur"
17559     ],
17560     [
17561         "Western Frisian",
17562         "Frysk",
17563         "fy"
17564     ],
17565     [
17566         "Irish",
17567         "Gaeilge",
17568         "ga"
17569     ],
17570     [
17571         "Gagauz",
17572         "Gagauz",
17573         "gag"
17574     ],
17575     [
17576         "Gan Chinese",
17577         "贛語",
17578         "gan"
17579     ],
17580     [
17581         "Scottish Gaelic",
17582         "Gàidhlig",
17583         "gd"
17584     ],
17585     [
17586         "Galician",
17587         "galego",
17588         "gl"
17589     ],
17590     [
17591         "Gilaki",
17592         "گیلکی",
17593         "glk"
17594     ],
17595     [
17596         "Guarani",
17597         "Avañe'ẽ",
17598         "gn"
17599     ],
17600     [
17601         "Goan Konkani",
17602         "गोंयची कोंकणी / Gõychi Konknni",
17603         "gom"
17604     ],
17605     [
17606         "Gothic",
17607         "𐌲𐌿𐍄𐌹𐍃𐌺",
17608         "got"
17609     ],
17610     [
17611         "Gujarati",
17612         "ગુજરાતી",
17613         "gu"
17614     ],
17615     [
17616         "Manx",
17617         "Gaelg",
17618         "gv"
17619     ],
17620     [
17621         "Hausa",
17622         "Hausa",
17623         "ha"
17624     ],
17625     [
17626         "Hakka Chinese",
17627         "客家語/Hak-kâ-ngî",
17628         "hak"
17629     ],
17630     [
17631         "Hawaiian",
17632         "Hawaiʻi",
17633         "haw"
17634     ],
17635     [
17636         "Hebrew",
17637         "עברית",
17638         "he"
17639     ],
17640     [
17641         "Hindi",
17642         "हिन्दी",
17643         "hi"
17644     ],
17645     [
17646         "Fiji Hindi",
17647         "Fiji Hindi",
17648         "hif"
17649     ],
17650     [
17651         "Croatian",
17652         "hrvatski",
17653         "hr"
17654     ],
17655     [
17656         "Upper Sorbian",
17657         "hornjoserbsce",
17658         "hsb"
17659     ],
17660     [
17661         "Haitian Creole",
17662         "Kreyòl ayisyen",
17663         "ht"
17664     ],
17665     [
17666         "Hungarian",
17667         "magyar",
17668         "hu"
17669     ],
17670     [
17671         "Armenian",
17672         "Հայերեն",
17673         "hy"
17674     ],
17675     [
17676         "Interlingua",
17677         "interlingua",
17678         "ia"
17679     ],
17680     [
17681         "Indonesian",
17682         "Bahasa Indonesia",
17683         "id"
17684     ],
17685     [
17686         "Interlingue",
17687         "Interlingue",
17688         "ie"
17689     ],
17690     [
17691         "Igbo",
17692         "Igbo",
17693         "ig"
17694     ],
17695     [
17696         "Inupiaq",
17697         "Iñupiak",
17698         "ik"
17699     ],
17700     [
17701         "Iloko",
17702         "Ilokano",
17703         "ilo"
17704     ],
17705     [
17706         "Ido",
17707         "Ido",
17708         "io"
17709     ],
17710     [
17711         "Icelandic",
17712         "íslenska",
17713         "is"
17714     ],
17715     [
17716         "Italian",
17717         "italiano",
17718         "it"
17719     ],
17720     [
17721         "Inuktitut",
17722         "ᐃᓄᒃᑎᑐᑦ/inuktitut",
17723         "iu"
17724     ],
17725     [
17726         "Japanese",
17727         "日本語",
17728         "ja"
17729     ],
17730     [
17731         "Jamaican Creole English",
17732         "Patois",
17733         "jam"
17734     ],
17735     [
17736         "Lojban",
17737         "la .lojban.",
17738         "jbo"
17739     ],
17740     [
17741         "Javanese",
17742         "Basa Jawa",
17743         "jv"
17744     ],
17745     [
17746         "Georgian",
17747         "ქართული",
17748         "ka"
17749     ],
17750     [
17751         "Kara-Kalpak",
17752         "Qaraqalpaqsha",
17753         "kaa"
17754     ],
17755     [
17756         "Kabyle",
17757         "Taqbaylit",
17758         "kab"
17759     ],
17760     [
17761         "Kabardian",
17762         "Адыгэбзэ",
17763         "kbd"
17764     ],
17765     [
17766         "Kongo",
17767         "Kongo",
17768         "kg"
17769     ],
17770     [
17771         "Kikuyu",
17772         "Gĩkũyũ",
17773         "ki"
17774     ],
17775     [
17776         "Kazakh",
17777         "қазақша",
17778         "kk"
17779     ],
17780     [
17781         "Kalaallisut",
17782         "kalaallisut",
17783         "kl"
17784     ],
17785     [
17786         "Khmer",
17787         "ភាសាខ្មែរ",
17788         "km"
17789     ],
17790     [
17791         "Kannada",
17792         "ಕನ್ನಡ",
17793         "kn"
17794     ],
17795     [
17796         "Korean",
17797         "한국어",
17798         "ko"
17799     ],
17800     [
17801         "Komi-Permyak",
17802         "Перем Коми",
17803         "koi"
17804     ],
17805     [
17806         "Karachay-Balkar",
17807         "къарачай-малкъар",
17808         "krc"
17809     ],
17810     [
17811         "Kashmiri",
17812         "कॉशुर / کٲشُر",
17813         "ks"
17814     ],
17815     [
17816         "Colognian",
17817         "Ripoarisch",
17818         "ksh"
17819     ],
17820     [
17821         "Kurdish",
17822         "Kurdî",
17823         "ku"
17824     ],
17825     [
17826         "Komi",
17827         "коми",
17828         "kv"
17829     ],
17830     [
17831         "Cornish",
17832         "kernowek",
17833         "kw"
17834     ],
17835     [
17836         "Kyrgyz",
17837         "Кыргызча",
17838         "ky"
17839     ],
17840     [
17841         "Latin",
17842         "Latina",
17843         "la"
17844     ],
17845     [
17846         "Ladino",
17847         "Ladino",
17848         "lad"
17849     ],
17850     [
17851         "Luxembourgish",
17852         "Lëtzebuergesch",
17853         "lb"
17854     ],
17855     [
17856         "лакку",
17857         "лакку",
17858         "lbe"
17859     ],
17860     [
17861         "Lezghian",
17862         "лезги",
17863         "lez"
17864     ],
17865     [
17866         "Ganda",
17867         "Luganda",
17868         "lg"
17869     ],
17870     [
17871         "Limburgish",
17872         "Limburgs",
17873         "li"
17874     ],
17875     [
17876         "Ligurian",
17877         "Ligure",
17878         "lij"
17879     ],
17880     [
17881         "Lombard",
17882         "lumbaart",
17883         "lmo"
17884     ],
17885     [
17886         "Lingala",
17887         "lingála",
17888         "ln"
17889     ],
17890     [
17891         "Lao",
17892         "ລາວ",
17893         "lo"
17894     ],
17895     [
17896         "Northern Luri",
17897         "لۊری شومالی",
17898         "lrc"
17899     ],
17900     [
17901         "Lithuanian",
17902         "lietuvių",
17903         "lt"
17904     ],
17905     [
17906         "Latgalian",
17907         "latgaļu",
17908         "ltg"
17909     ],
17910     [
17911         "Latvian",
17912         "latviešu",
17913         "lv"
17914     ],
17915     [
17916         "Maithili",
17917         "मैथिली",
17918         "mai"
17919     ],
17920     [
17921         "Basa Banyumasan",
17922         "Basa Banyumasan",
17923         "map-bms"
17924     ],
17925     [
17926         "Moksha",
17927         "мокшень",
17928         "mdf"
17929     ],
17930     [
17931         "Malagasy",
17932         "Malagasy",
17933         "mg"
17934     ],
17935     [
17936         "Eastern Mari",
17937         "олык марий",
17938         "mhr"
17939     ],
17940     [
17941         "Maori",
17942         "Māori",
17943         "mi"
17944     ],
17945     [
17946         "Minangkabau",
17947         "Baso Minangkabau",
17948         "min"
17949     ],
17950     [
17951         "Macedonian",
17952         "македонски",
17953         "mk"
17954     ],
17955     [
17956         "Malayalam",
17957         "മലയാളം",
17958         "ml"
17959     ],
17960     [
17961         "Mongolian",
17962         "монгол",
17963         "mn"
17964     ],
17965     [
17966         "Marathi",
17967         "मराठी",
17968         "mr"
17969     ],
17970     [
17971         "Western Mari",
17972         "кырык мары",
17973         "mrj"
17974     ],
17975     [
17976         "Malay",
17977         "Bahasa Melayu",
17978         "ms"
17979     ],
17980     [
17981         "Maltese",
17982         "Malti",
17983         "mt"
17984     ],
17985     [
17986         "Mirandese",
17987         "Mirandés",
17988         "mwl"
17989     ],
17990     [
17991         "Burmese",
17992         "မြန်မာဘာသာ",
17993         "my"
17994     ],
17995     [
17996         "Erzya",
17997         "эрзянь",
17998         "myv"
17999     ],
18000     [
18001         "Mazanderani",
18002         "مازِرونی",
18003         "mzn"
18004     ],
18005     [
18006         "Nauru",
18007         "Dorerin Naoero",
18008         "na"
18009     ],
18010     [
18011         "Nāhuatl",
18012         "Nāhuatl",
18013         "nah"
18014     ],
18015     [
18016         "Neapolitan",
18017         "Napulitano",
18018         "nap"
18019     ],
18020     [
18021         "Low German",
18022         "Plattdüütsch",
18023         "nds"
18024     ],
18025     [
18026         "Low Saxon",
18027         "Nedersaksies",
18028         "nds-nl"
18029     ],
18030     [
18031         "Nepali",
18032         "नेपाली",
18033         "ne"
18034     ],
18035     [
18036         "Newari",
18037         "नेपाल भाषा",
18038         "new"
18039     ],
18040     [
18041         "Dutch",
18042         "Nederlands",
18043         "nl"
18044     ],
18045     [
18046         "Norwegian Nynorsk",
18047         "norsk nynorsk",
18048         "nn"
18049     ],
18050     [
18051         "Norwegian",
18052         "norsk bokmål",
18053         "no"
18054     ],
18055     [
18056         "Novial",
18057         "Novial",
18058         "nov"
18059     ],
18060     [
18061         "Nouormand",
18062         "Nouormand",
18063         "nrm"
18064     ],
18065     [
18066         "Northern Sotho",
18067         "Sesotho sa Leboa",
18068         "nso"
18069     ],
18070     [
18071         "Navajo",
18072         "Diné bizaad",
18073         "nv"
18074     ],
18075     [
18076         "Nyanja",
18077         "Chi-Chewa",
18078         "ny"
18079     ],
18080     [
18081         "Occitan",
18082         "occitan",
18083         "oc"
18084     ],
18085     [
18086         "Livvi-Karelian",
18087         "Livvinkarjala",
18088         "olo"
18089     ],
18090     [
18091         "Oromo",
18092         "Oromoo",
18093         "om"
18094     ],
18095     [
18096         "Odia",
18097         "ଓଡ଼ିଆ",
18098         "or"
18099     ],
18100     [
18101         "Ossetic",
18102         "Ирон",
18103         "os"
18104     ],
18105     [
18106         "Punjabi",
18107         "ਪੰਜਾਬੀ",
18108         "pa"
18109     ],
18110     [
18111         "Pangasinan",
18112         "Pangasinan",
18113         "pag"
18114     ],
18115     [
18116         "Pampanga",
18117         "Kapampangan",
18118         "pam"
18119     ],
18120     [
18121         "Papiamento",
18122         "Papiamentu",
18123         "pap"
18124     ],
18125     [
18126         "Picard",
18127         "Picard",
18128         "pcd"
18129     ],
18130     [
18131         "Pennsylvania German",
18132         "Deitsch",
18133         "pdc"
18134     ],
18135     [
18136         "Palatine German",
18137         "Pälzisch",
18138         "pfl"
18139     ],
18140     [
18141         "Pali",
18142         "पालि",
18143         "pi"
18144     ],
18145     [
18146         "Norfuk / Pitkern",
18147         "Norfuk / Pitkern",
18148         "pih"
18149     ],
18150     [
18151         "Polish",
18152         "polski",
18153         "pl"
18154     ],
18155     [
18156         "Piedmontese",
18157         "Piemontèis",
18158         "pms"
18159     ],
18160     [
18161         "Western Punjabi",
18162         "پنجابی",
18163         "pnb"
18164     ],
18165     [
18166         "Pontic",
18167         "Ποντιακά",
18168         "pnt"
18169     ],
18170     [
18171         "Pashto",
18172         "پښتو",
18173         "ps"
18174     ],
18175     [
18176         "Portuguese",
18177         "português",
18178         "pt"
18179     ],
18180     [
18181         "Quechua",
18182         "Runa Simi",
18183         "qu"
18184     ],
18185     [
18186         "Romansh",
18187         "rumantsch",
18188         "rm"
18189     ],
18190     [
18191         "Romani",
18192         "Romani",
18193         "rmy"
18194     ],
18195     [
18196         "Rundi",
18197         "Kirundi",
18198         "rn"
18199     ],
18200     [
18201         "Romanian",
18202         "română",
18203         "ro"
18204     ],
18205     [
18206         "Aromanian",
18207         "armãneashti",
18208         "roa-rup"
18209     ],
18210     [
18211         "tarandíne",
18212         "tarandíne",
18213         "roa-tara"
18214     ],
18215     [
18216         "Russian",
18217         "русский",
18218         "ru"
18219     ],
18220     [
18221         "Rusyn",
18222         "русиньскый",
18223         "rue"
18224     ],
18225     [
18226         "Kinyarwanda",
18227         "Kinyarwanda",
18228         "rw"
18229     ],
18230     [
18231         "Sanskrit",
18232         "संस्कृतम्",
18233         "sa"
18234     ],
18235     [
18236         "Sakha",
18237         "саха тыла",
18238         "sah"
18239     ],
18240     [
18241         "Sardinian",
18242         "sardu",
18243         "sc"
18244     ],
18245     [
18246         "Sicilian",
18247         "sicilianu",
18248         "scn"
18249     ],
18250     [
18251         "Scots",
18252         "Scots",
18253         "sco"
18254     ],
18255     [
18256         "Sindhi",
18257         "سنڌي",
18258         "sd"
18259     ],
18260     [
18261         "Northern Sami",
18262         "sámegiella",
18263         "se"
18264     ],
18265     [
18266         "Sango",
18267         "Sängö",
18268         "sg"
18269     ],
18270     [
18271         "Serbo-Croatian",
18272         "srpskohrvatski / српскохрватски",
18273         "sh"
18274     ],
18275     [
18276         "Sinhala",
18277         "සිංහල",
18278         "si"
18279     ],
18280     [
18281         "Simple English",
18282         "Simple English",
18283         "simple"
18284     ],
18285     [
18286         "Slovak",
18287         "slovenčina",
18288         "sk"
18289     ],
18290     [
18291         "Slovenian",
18292         "slovenščina",
18293         "sl"
18294     ],
18295     [
18296         "Samoan",
18297         "Gagana Samoa",
18298         "sm"
18299     ],
18300     [
18301         "Shona",
18302         "chiShona",
18303         "sn"
18304     ],
18305     [
18306         "Somali",
18307         "Soomaaliga",
18308         "so"
18309     ],
18310     [
18311         "Albanian",
18312         "shqip",
18313         "sq"
18314     ],
18315     [
18316         "Serbian",
18317         "српски / srpski",
18318         "sr"
18319     ],
18320     [
18321         "Sranan Tongo",
18322         "Sranantongo",
18323         "srn"
18324     ],
18325     [
18326         "Swati",
18327         "SiSwati",
18328         "ss"
18329     ],
18330     [
18331         "Southern Sotho",
18332         "Sesotho",
18333         "st"
18334     ],
18335     [
18336         "Saterland Frisian",
18337         "Seeltersk",
18338         "stq"
18339     ],
18340     [
18341         "Sundanese",
18342         "Basa Sunda",
18343         "su"
18344     ],
18345     [
18346         "Swedish",
18347         "svenska",
18348         "sv"
18349     ],
18350     [
18351         "Swahili",
18352         "Kiswahili",
18353         "sw"
18354     ],
18355     [
18356         "Silesian",
18357         "ślůnski",
18358         "szl"
18359     ],
18360     [
18361         "Tamil",
18362         "தமிழ்",
18363         "ta"
18364     ],
18365     [
18366         "Tulu",
18367         "ತುಳು",
18368         "tcy"
18369     ],
18370     [
18371         "Telugu",
18372         "తెలుగు",
18373         "te"
18374     ],
18375     [
18376         "Tetum",
18377         "tetun",
18378         "tet"
18379     ],
18380     [
18381         "Tajik",
18382         "тоҷикӣ",
18383         "tg"
18384     ],
18385     [
18386         "Thai",
18387         "ไทย",
18388         "th"
18389     ],
18390     [
18391         "Tigrinya",
18392         "ትግርኛ",
18393         "ti"
18394     ],
18395     [
18396         "Turkmen",
18397         "Türkmençe",
18398         "tk"
18399     ],
18400     [
18401         "Tagalog",
18402         "Tagalog",
18403         "tl"
18404     ],
18405     [
18406         "Tswana",
18407         "Setswana",
18408         "tn"
18409     ],
18410     [
18411         "Tongan",
18412         "lea faka-Tonga",
18413         "to"
18414     ],
18415     [
18416         "Tok Pisin",
18417         "Tok Pisin",
18418         "tpi"
18419     ],
18420     [
18421         "Turkish",
18422         "Türkçe",
18423         "tr"
18424     ],
18425     [
18426         "Tsonga",
18427         "Xitsonga",
18428         "ts"
18429     ],
18430     [
18431         "Tatar",
18432         "татарча/tatarça",
18433         "tt"
18434     ],
18435     [
18436         "Tumbuka",
18437         "chiTumbuka",
18438         "tum"
18439     ],
18440     [
18441         "Twi",
18442         "Twi",
18443         "tw"
18444     ],
18445     [
18446         "Tahitian",
18447         "reo tahiti",
18448         "ty"
18449     ],
18450     [
18451         "Tuvinian",
18452         "тыва дыл",
18453         "tyv"
18454     ],
18455     [
18456         "Udmurt",
18457         "удмурт",
18458         "udm"
18459     ],
18460     [
18461         "Uyghur",
18462         "ئۇيغۇرچە / Uyghurche",
18463         "ug"
18464     ],
18465     [
18466         "Ukrainian",
18467         "українська",
18468         "uk"
18469     ],
18470     [
18471         "Urdu",
18472         "اردو",
18473         "ur"
18474     ],
18475     [
18476         "Uzbek",
18477         "oʻzbekcha/ўзбекча",
18478         "uz"
18479     ],
18480     [
18481         "Venda",
18482         "Tshivenda",
18483         "ve"
18484     ],
18485     [
18486         "Venetian",
18487         "vèneto",
18488         "vec"
18489     ],
18490     [
18491         "Veps",
18492         "vepsän kel’",
18493         "vep"
18494     ],
18495     [
18496         "Vietnamese",
18497         "Tiếng Việt",
18498         "vi"
18499     ],
18500     [
18501         "West Flemish",
18502         "West-Vlams",
18503         "vls"
18504     ],
18505     [
18506         "Volapük",
18507         "Volapük",
18508         "vo"
18509     ],
18510     [
18511         "Walloon",
18512         "walon",
18513         "wa"
18514     ],
18515     [
18516         "Waray",
18517         "Winaray",
18518         "war"
18519     ],
18520     [
18521         "Wolof",
18522         "Wolof",
18523         "wo"
18524     ],
18525     [
18526         "Wu Chinese",
18527         "吴语",
18528         "wuu"
18529     ],
18530     [
18531         "Kalmyk",
18532         "хальмг",
18533         "xal"
18534     ],
18535     [
18536         "Xhosa",
18537         "isiXhosa",
18538         "xh"
18539     ],
18540     [
18541         "Mingrelian",
18542         "მარგალური",
18543         "xmf"
18544     ],
18545     [
18546         "Yiddish",
18547         "ייִדיש",
18548         "yi"
18549     ],
18550     [
18551         "Yoruba",
18552         "Yorùbá",
18553         "yo"
18554     ],
18555     [
18556         "Zhuang",
18557         "Vahcuengh",
18558         "za"
18559     ],
18560     [
18561         "Zeelandic",
18562         "Zeêuws",
18563         "zea"
18564     ],
18565     [
18566         "Chinese",
18567         "中文",
18568         "zh"
18569     ],
18570     [
18571         "Classical Chinese",
18572         "文言",
18573         "zh-classical"
18574     ],
18575     [
18576         "Chinese (Min Nan)",
18577         "Bân-lâm-gú",
18578         "zh-min-nan"
18579     ],
18580     [
18581         "Cantonese",
18582         "粵語",
18583         "zh-yue"
18584     ],
18585     [
18586         "Zulu",
18587         "isiZulu",
18588         "zu"
18589     ]
18590 ];
18591
18592 var amenity = {"fuel":{"76":{"count":314},"Neste":{"count":189},"BP":{"count":2511},"Shell":{"count":8380},"Agip":{"count":2651},"Migrol":{"count":65},"Avia":{"count":897},"Texaco":{"count":680},"Total":{"count":2607},"Statoil":{"count":596},"Esso":{"count":3652},"Jet":{"count":441},"Avanti":{"count":90},"Sainsbury's":{"count":58},"OMV":{"count":701},"Aral":{"count":1339},"Tesco":{"count":197},"JET":{"count":180},"Morrisons":{"count":111},"United":{"count":91},"Canadian Tire":{"count":66},"Mobil":{"count":613},"Caltex":{"count":1001},"Sunoco":{"count":355},"Q8":{"count":1161},"ABC":{"count":79},"ARAL":{"count":375},"CEPSA":{"count":1018},"BFT":{"count":89},"Petron":{"count":878},"Intermarché":{"count":434},"Total Access":{"count":51},"Super U":{"count":124},"Auchan":{"count":53},"Elf":{"count":129},"Carrefour":{"count":205},"Station Service E. Leclerc":{"count":530},"Shell Express":{"count":131},"Hess":{"count":127},"Flying V":{"count":129},"bft":{"count":168},"Gulf":{"count":199},"PTT":{"count":191},"St1":{"count":100},"Teboil":{"count":115},"HEM":{"count":212},"GALP":{"count":626},"OK":{"count":163},"ÖMV":{"count":101},"Tinq":{"count":215},"OKQ8":{"count":186},"Repsol":{"count":424},"Westfalen":{"count":96},"Esso Express":{"count":98},"Raiffeisenbank":{"count":117},"Tamoil":{"count":866},"Engen":{"count":241},"Sasol":{"count":59},"Topaz":{"count":78},"LPG":{"count":174},"Coop":{"count":62},"Orlen":{"count":598},"Oilibya":{"count":68},"Tango":{"count":122},"Star":{"count":319},"Петрол":{"count":84},"Cepsa":{"count":96},"OIL!":{"count":63},"Ultramar":{"count":125},"Irving":{"count":87},"Lukoil":{"count":701},"Petro-Canada":{"count":489},"7-Eleven":{"count":488},"Agrola":{"count":69},"Husky":{"count":126},"Slovnaft":{"count":219},"Sheetz":{"count":134},"Mol":{"count":61},"Petronas":{"count":159},"Газпромнефть":{"count":748},"Лукойл":{"count":1477},"Elan":{"count":112},"Роснефть":{"count":638},"Turmöl":{"count":57},"Neste A24":{"count":55},"Marathon":{"count":189},"Valero":{"count":366},"Eni":{"count":236},"Chevron":{"count":954},"ТНК":{"count":520},"REPSOL":{"count":1603},"MOL":{"count":228},"Bliska":{"count":150},"Api":{"count":302},"Arco":{"count":179},"Pemex":{"count":423},"Exxon":{"count":506},"Coles Express":{"count":115},"Petrom":{"count":259},"PETRONOR":{"count":207},"Rompetrol":{"count":174},"Lotos":{"count":178},"ОМВ":{"count":60},"BR":{"count":129},"Copec":{"count":505},"Petrobras":{"count":270},"Liberty":{"count":55},"IP":{"count":871},"Erg":{"count":596},"Eneos":{"count":97},"Citgo":{"count":279},"Metano":{"count":208},"Сургутнефтегаз":{"count":61},"EKO":{"count":59},"Eko":{"count":58},"Indipend.":{"count":172},"IES":{"count":63},"TotalErg":{"count":89},"Cenex":{"count":115},"ПТК":{"count":82},"HP":{"count":79},"Phillips 66":{"count":216},"CARREFOUR":{"count":74},"ERG":{"count":76},"Speedway":{"count":148},"Benzina":{"count":96},"Татнефть":{"count":264},"Terpel":{"count":259},"WOG":{"count":189},"Seaoil":{"count":54},"АЗС":{"count":1077},"Kwik Trip":{"count":108},"Wawa":{"count":89},"Pertamina":{"count":186},"COSMO":{"count":64},"Z":{"count":76},"Indian Oil":{"count":183},"АГЗС":{"count":494},"INA":{"count":121},"JOMO":{"count":62},"Holiday":{"count":97},"YPF":{"count":70},"IDEMITSU":{"count":87},"ENEOS":{"count":736},"Bharat Petroleum":{"count":64},"CAMPSA":{"count":615},"Casey's General Store":{"count":190},"Башнефть":{"count":60},"Kangaroo":{"count":60},"コスモ石油 (COSMO)":{"count":136},"MEROIL":{"count":77},"1-2-3":{"count":71},"出光":{"count":228,"tags":{"name:en":"IDEMITSU"}},"НК Альянс":{"count":88},"Sinclair":{"count":100},"Conoco":{"count":189},"SPBU":{"count":54},"Макпетрол":{"count":109},"Circle K":{"count":166},"Posto Ipiranga":{"count":70},"Posto Shell":{"count":54},"Phoenix":{"count":144},"Ipiranga":{"count":119},"OKKO":{"count":85},"ОККО":{"count":119},"บางจาก":{"count":60},"QuikTrip":{"count":105},"Stewart's":{"count":63},"Posto BR":{"count":68},"ป ต ท":{"count":152},"ปตท":{"count":88},"ANP":{"count":80},"Kum & Go":{"count":80},"Petrolimex":{"count":55},"Sokimex":{"count":66},"Tela":{"count":154},"Posto":{"count":71},"H-E-B":{"count":182},"Укрнафта":{"count":58},"Татнефтепродукт":{"count":54},"Afriquia":{"count":88},"Murphy USA":{"count":67},"昭和シェル (Showa-shell)":{"count":94},"エネオス":{"count":53},"CNG":{"count":94}},"pub":{"Kings Arms":{"count":67},"The Ship":{"count":89},"The White Horse":{"count":204},"The White Hart":{"count":226},"Royal Oak":{"count":150},"The Red Lion":{"count":233},"The Kings Arms":{"count":58},"The Star":{"count":73},"The Anchor":{"count":64},"The Cross Keys":{"count":55},"The Wheatsheaf":{"count":117},"The Crown Inn":{"count":67},"The Kings Head":{"count":53},"The Castle":{"count":62},"The Railway":{"count":102},"The White Lion":{"count":118},"The Bell":{"count":121},"The Bull":{"count":68},"The Plough":{"count":179},"The George":{"count":110},"The Royal Oak":{"count":209},"The Fox":{"count":74},"Prince of Wales":{"count":77},"The Rising Sun":{"count":71},"The Prince of Wales":{"count":51},"The Crown":{"count":244},"The Chequers":{"count":66},"The Swan":{"count":152},"Rose and Crown":{"count":79},"The Victoria":{"count":67},"New Inn":{"count":90},"Royal Hotel":{"count":57},"Red Lion":{"count":207},"Cross Keys":{"count":61},"The Greyhound":{"count":96},"The Black Horse":{"count":94},"The New Inn":{"count":105},"Kings Head":{"count":59},"The Albion":{"count":51},"The Angel":{"count":52},"The Queens Head":{"count":52},"The Ship Inn":{"count":83},"Rose & Crown":{"count":51},"Queens Head":{"count":52},"Irish Pub":{"count":76}},"fast_food":{"Quick":{"count":484},"McDonald's":{"count":12376,"tags":{"cuisine":"burger"}},"Subway":{"count":5576,"tags":{"cuisine":"sandwich"}},"Burger King":{"count":3734,"tags":{"cuisine":"burger"}},"Ali Baba":{"count":61},"Hungry Jacks":{"count":173,"tags":{"cuisine":"burger"}},"Red Rooster":{"count":148},"KFC":{"count":3198,"tags":{"cuisine":"chicken"}},"Domino's Pizza":{"count":985,"tags":{"cuisine":"pizza"}},"Chowking":{"count":142},"Jollibee":{"count":396},"Hesburger":{"count":102},"肯德基":{"count":86},"Wendy's":{"count":1621,"tags":{"cuisine":"burger"}},"Tim Hortons":{"count":323},"Steers":{"count":151},"Hardee's":{"count":268,"tags":{"cuisine":"burger"}},"Arby's":{"count":782},"A&W":{"count":283},"Dairy Queen":{"count":791},"Hallo Pizza":{"count":76},"Fish & Chips":{"count":93},"Harvey's":{"count":90},"麥當勞":{"count":65},"Pizza Pizza":{"count":215},"Kotipizza":{"count":74},"Jack in the Box":{"count":546,"tags":{"cuisine":"burger"}},"Istanbul":{"count":56},"Kochlöffel":{"count":68},"Döner":{"count":228},"Telepizza":{"count":201},"Sibylla":{"count":61},"Carl's Jr.":{"count":298,"tags":{"cuisine":"burger"}},"Quiznos":{"count":266,"tags":{"cuisine":"sandwich"}},"Wimpy":{"count":141},"Sonic":{"count":566,"tags":{"cuisine":"burger"}},"Taco Bell":{"count":1423,"tags":{"cuisine":"mexican"}},"Pizza Nova":{"count":63},"Papa John's":{"count":304,"tags":{"cuisine":"pizza"}},"Nordsee":{"count":159},"Mr. Sub":{"count":103},"Макдоналдс":{"count":324,"tags":{"name:en":"McDonald's"}},"Asia Imbiss":{"count":111},"Chipotle":{"count":290,"tags":{"cuisine":"mexican"}},"マクドナルド":{"count":692,"tags":{"name:en":"McDonald's","cuisine":"burger"}},"In-N-Out Burger":{"count":65},"Jimmy John's":{"count":141},"Jamba Juice":{"count":68},"Робин Сдобин":{"count":82},"Baskin Robbins":{"count":74},"ケンタッキーフライドチキン":{"count":164,"tags":{"name:en":"KFC","cuisine":"chicken"}},"吉野家":{"count":191},"Taco Time":{"count":88},"松屋":{"count":281,"tags":{"name:en":"Matsuya"}},"Little Caesars":{"count":81},"El Pollo Loco":{"count":63},"Del Taco":{"count":141},"White Castle":{"count":80},"Boston Market":{"count":66},"Chick-fil-A":{"count":257,"tags":{"cuisine":"chicken"}},"Panda Express":{"count":238,"tags":{"cuisine":"chinese"}},"Whataburger":{"count":364},"Taco John's":{"count":78},"Теремок":{"count":68},"Culver's":{"count":425},"Five Guys":{"count":141},"Church's Chicken":{"count":95},"Popeye's":{"count":167,"tags":{"cuisine":"chicken"}},"Long John Silver's":{"count":93},"Pollo Campero":{"count":62},"Zaxby's":{"count":51},"すき家":{"count":276,"tags":{"name:en":"SUKIYA"}},"モスバーガー":{"count":257,"tags":{"name:en":"MOS BURGER"}},"Русский Аппетит":{"count":69},"なか卯":{"count":63}},"restaurant":{"Pizza Hut":{"count":1180,"tags":{"cuisine":"pizza"}},"Little Chef":{"count":64},"Adler":{"count":158},"Zur Krone":{"count":90},"Deutsches Haus":{"count":90},"Krone":{"count":171},"Akropolis":{"count":152},"Schützenhaus":{"count":124},"Kreuz":{"count":74},"Waldschänke":{"count":55},"La Piazza":{"count":69},"Lamm":{"count":66},"Zur Sonne":{"count":73},"Zur Linde":{"count":204},"Poseidon":{"count":110},"Shanghai":{"count":82},"Red Lobster":{"count":235},"Zum Löwen":{"count":84},"Swiss Chalet":{"count":107},"Olympia":{"count":74},"Wagamama":{"count":64},"Frankie & Benny's":{"count":66},"Hooters":{"count":103},"Sternen":{"count":78},"Hirschen":{"count":79},"Denny's":{"count":450},"Athen":{"count":68},"Sonne":{"count":126},"Hirsch":{"count":79},"Ratskeller":{"count":150},"La Cantina":{"count":56},"Gasthaus Krone":{"count":56},"El Greco":{"count":86},"Gasthof zur Post":{"count":79},"Nando's":{"count":246},"Löwen":{"count":112},"La Pataterie":{"count":51},"Bella Napoli":{"count":53},"Pizza Express":{"count":262},"Mandarin":{"count":65},"Hong Kong":{"count":83},"Zizzi":{"count":68},"Cracker Barrel":{"count":183},"Rhodos":{"count":81},"Lindenhof":{"count":79},"Milano":{"count":54},"Dolce Vita":{"count":77},"Kirchenwirt":{"count":81},"Kantine":{"count":52},"Ochsen":{"count":95},"Spur":{"count":62},"Mykonos":{"count":59},"Lotus":{"count":66},"Applebee's":{"count":531},"Flunch":{"count":72},"Zur Post":{"count":116},"China Town":{"count":76},"La Dolce Vita":{"count":73},"Waffle House":{"count":207},"Delphi":{"count":88},"Linde":{"count":103},"Outback Steakhouse":{"count":218},"Dionysos":{"count":69},"Kelsey's":{"count":57},"Boston Pizza":{"count":165},"Bella Italia":{"count":132},"Sizzler":{"count":53},"Grüner Baum":{"count":116},"Taj Mahal":{"count":104},"Rössli":{"count":68},"Wimpy":{"count":51},"Traube":{"count":65},"Adria":{"count":52},"Red Robin":{"count":185},"Roma":{"count":61},"San Marco":{"count":67},"Hellas":{"count":55},"La Perla":{"count":67},"Vips":{"count":53},"Panera Bread":{"count":218},"Da Vinci":{"count":54},"Hippopotamus":{"count":96},"Prezzo":{"count":75},"Courtepaille":{"count":106},"Hard Rock Cafe":{"count":70},"Panorama":{"count":61},"デニーズ":{"count":82},"Sportheim":{"count":65},"餃子の王将":{"count":57},"Bären":{"count":60},"Alte Post":{"count":60},"Pizzeria Roma":{"count":51},"China Garden":{"count":66},"Vapiano":{"count":82},"Mamma Mia":{"count":64},"Schwarzer Adler":{"count":57},"IHOP":{"count":317},"Chili's":{"count":328},"Asia":{"count":51},"Olive Garden":{"count":279},"TGI Friday's":{"count":159},"Friendly's":{"count":78},"Buffalo Grill":{"count":202},"Texas Roadhouse":{"count":110},"ガスト":{"count":230,"tags":{"name:en":"Gusto"}},"Sakura":{"count":75},"Mensa":{"count":99},"The Keg":{"count":53},"サイゼリヤ":{"count":93},"La Strada":{"count":52},"Village Inn":{"count":92},"Buffalo Wild Wings":{"count":176},"Peking":{"count":59},"Boston Market":{"count":61},"Round Table Pizza":{"count":53},"Jimmy John's":{"count":69},"California Pizza Kitchen":{"count":61},"Якитория":{"count":77},"Golden Corral":{"count":101},"Perkins":{"count":105},"Ruby Tuesday":{"count":162},"Shari's":{"count":65},"Bob Evans":{"count":129},"바다횟집 (Bada Fish Restaurant)":{"count":55},"Mang Inasal":{"count":84},"Евразия":{"count":102},"ジョナサン":{"count":59},"Longhorn Steakhouse":{"count":66}},"bank":{"Chase":{"count":721},"Commonwealth Bank":{"count":232},"Citibank":{"count":277},"HSBC":{"count":1102},"Barclays":{"count":965},"Westpac":{"count":208},"NAB":{"count":131},"ANZ":{"count":218},"Lloyds Bank":{"count":547},"Landbank":{"count":81},"Sparkasse":{"count":4555},"UCPB":{"count":92},"PNB":{"count":244},"Metrobank":{"count":269},"BDO":{"count":290},"Volksbank":{"count":2591},"BPI":{"count":415},"Postbank":{"count":443},"NatWest":{"count":628},"Raiffeisenbank":{"count":2119},"Yorkshire Bank":{"count":63},"ABSA":{"count":95},"Standard Bank":{"count":109},"FNB":{"count":97},"Deutsche Bank":{"count":855},"SEB":{"count":133},"Commerzbank":{"count":806},"Targobank":{"count":166},"ABN AMRO":{"count":130},"Handelsbanken":{"count":184},"Swedbank":{"count":223},"Kreissparkasse":{"count":600},"UniCredit Bank":{"count":408},"Monte dei Paschi di Siena":{"count":132},"Caja Rural":{"count":99},"Dresdner Bank":{"count":66},"Sparda-Bank":{"count":320},"VÚB":{"count":107},"Slovenská sporiteľňa":{"count":134},"Bank of Montreal":{"count":118},"KBC":{"count":203},"Royal Bank of Scotland":{"count":111},"TSB":{"count":80},"US Bank":{"count":256},"HypoVereinsbank":{"count":561},"Bank Austria":{"count":176},"ING":{"count":496},"Erste Bank":{"count":180},"CIBC":{"count":326},"Scotiabank":{"count":413},"Caisse d'Épargne":{"count":882},"Santander":{"count":1323},"Bank of Scotland":{"count":89},"TD Canada Trust":{"count":450},"BMO":{"count":169},"Danske Bank":{"count":131},"OTP":{"count":192},"Crédit Agricole":{"count":1239},"LCL":{"count":553},"VR-Bank":{"count":430},"ČSOB":{"count":160},"Česká spořitelna":{"count":212},"BNP":{"count":112},"Royal Bank":{"count":65},"Nationwide":{"count":209},"Halifax":{"count":225},"BAWAG PSK":{"count":102},"National Bank":{"count":84},"Nedbank":{"count":80},"First National Bank":{"count":85},"Nordea":{"count":319},"Rabobank":{"count":609},"Sparkasse KölnBonn":{"count":69},"Tatra banka":{"count":67},"Berliner Sparkasse":{"count":62},"Berliner Volksbank":{"count":77},"Wells Fargo":{"count":874},"Credit Suisse":{"count":71},"Société Générale":{"count":634},"Osuuspankki":{"count":75},"Sparkasse Aachen":{"count":56},"Hamburger Sparkasse":{"count":156},"Cassa di Risparmio del Veneto":{"count":68},"BNP Paribas":{"count":617},"Banque Populaire":{"count":433},"BNP Paribas Fortis":{"count":209},"Banco Popular":{"count":291},"Bancaja":{"count":55},"Banesto":{"count":208},"La Caixa":{"count":583},"Santander Consumer Bank":{"count":88},"BRD":{"count":191},"BCR":{"count":143},"Banca Transilvania":{"count":141},"BW-Bank":{"count":97},"Komerční banka":{"count":132},"Banco Pastor":{"count":64},"Stadtsparkasse":{"count":86},"Ulster Bank":{"count":86},"Sberbank":{"count":58},"CIC":{"count":427},"Bancpost":{"count":56},"Caja Madrid":{"count":115},"Maybank":{"count":94},"中国银行":{"count":85},"Unicredit Banca":{"count":243},"Crédit Mutuel":{"count":690},"BBVA":{"count":647},"Intesa San Paolo":{"count":69},"TD Bank":{"count":206},"Belfius":{"count":231},"Bank of America":{"count":924},"RBC":{"count":230},"Alpha Bank":{"count":123},"Сбербанк":{"count":4794},"Россельхозбанк":{"count":201},"Crédit du Nord":{"count":96},"BancoEstado":{"count":80},"Millennium Bank":{"count":414},"State Bank of India":{"count":151},"Беларусбанк":{"count":242},"ING Bank Śląski":{"count":67},"Caixa Geral de Depósitos":{"count":129},"Kreissparkasse Köln":{"count":65},"Banco BCI":{"count":51},"Banco de Chile":{"count":98},"ВТБ24":{"count":326},"UBS":{"count":134},"PKO BP":{"count":265},"Chinabank":{"count":55},"PSBank":{"count":59},"Union Bank":{"count":124},"China Bank":{"count":66},"RCBC":{"count":122},"Unicaja":{"count":83},"BBK":{"count":79},"Ibercaja":{"count":69},"RBS":{"count":143},"Commercial Bank of Ceylon PLC":{"count":79},"Bank of Ireland":{"count":109},"BNL":{"count":87},"Banco Santander":{"count":138},"Banco Itaú":{"count":111},"AIB":{"count":72},"BZ WBK":{"count":77},"Banco do Brasil":{"count":557},"Caixa Econômica Federal":{"count":184},"Fifth Third Bank":{"count":84},"Banca Popolare di Vicenza":{"count":81},"Wachovia":{"count":58},"OLB":{"count":53},"みずほ銀行":{"count":78},"BES":{"count":72},"ICICI Bank":{"count":91},"HDFC Bank":{"count":91},"La Banque Postale":{"count":67},"Pekao SA":{"count":56},"Oberbank":{"count":90},"Bradesco":{"count":295},"Oldenburgische Landesbank":{"count":56},"Bendigo Bank":{"count":93},"Argenta":{"count":86},"AXA":{"count":68},"Axis Bank":{"count":61},"Banco Nación":{"count":67},"GE Money Bank":{"count":72},"Альфа-Банк":{"count":185},"Белагропромбанк":{"count":70},"Caja Círculo":{"count":65},"Banco Galicia":{"count":51},"Eurobank":{"count":97},"Banca Intesa":{"count":62},"Canara Bank":{"count":92},"Cajamar":{"count":77},"Banamex":{"count":149},"Crédit Mutuel de Bretagne":{"count":335},"Davivienda":{"count":83},"Bank Spółdzielczy":{"count":159},"Credit Agricole":{"count":157},"Bankinter":{"count":59},"Banque Nationale":{"count":63},"Bank of the West":{"count":96},"Key Bank":{"count":155},"Western Union":{"count":88},"Citizens Bank":{"count":115},"ПриватБанк":{"count":513},"Security Bank":{"count":78},"Millenium":{"count":60},"Bankia":{"count":149},"三菱東京UFJ銀行":{"count":159},"Caixa":{"count":117},"Banco de Costa Rica":{"count":63},"SunTrust Bank":{"count":73},"Itaú":{"count":338},"PBZ":{"count":52},"中国工商银行":{"count":51},"Bancolombia":{"count":89},"Райффайзен Банк Аваль":{"count":64},"Bancomer":{"count":115},"Banorte":{"count":80},"Alior Bank":{"count":81},"BOC":{"count":51},"Банк Москвы":{"count":118},"ВТБ":{"count":59},"Getin Bank":{"count":55},"Caja Duero":{"count":57},"Regions Bank":{"count":62},"Росбанк":{"count":177},"Banco Estado":{"count":72},"BCI":{"count":68},"SunTrust":{"count":68},"PNC Bank":{"count":254},"신한은행":{"count":217,"tags":{"name:en":"Sinhan Bank"}},"우리은행":{"count":291,"tags":{"name:en":"Uri Bank"}},"국민은행":{"count":165,"tags":{"name:en":"Gungmin Bank"}},"중소기업은행":{"count":52,"tags":{"name:en":"Industrial Bank of Korea"}},"광주은행":{"count":51,"tags":{"name:en":"Gwangju Bank"}},"Газпромбанк":{"count":100},"M&T Bank":{"count":92},"Caja de Burgos":{"count":51},"Santander Totta":{"count":69},"УкрСиббанк":{"count":192},"Ощадбанк":{"count":364},"Уралсиб":{"count":85},"りそな銀行":{"count":225,"tags":{"name:en":"Mizuho Bank"}},"Ecobank":{"count":66},"Cajero Automatico Bancared":{"count":145},"Промсвязьбанк":{"count":93},"三井住友銀行":{"count":129},"Banco Provincia":{"count":67},"BB&T":{"count":147},"Возрождение":{"count":59},"Capital One":{"count":59},"横浜銀行":{"count":51},"Bank Mandiri":{"count":62},"Banco de la Nación":{"count":92},"Banco G&T Continental":{"count":62},"Peoples Bank":{"count":60},"工商银行":{"count":51},"Совкомбанк":{"count":55},"Provincial":{"count":56},"Banco de Desarrollo Banrural":{"count":73},"Banco Bradesco":{"count":65},"Bicentenario":{"count":182},"ლიბერთი ბანკი":{"count":54,"tags":{"name:en":"Liberty Bank"}},"Banesco":{"count":108},"Mercantil":{"count":75},"Bank BRI":{"count":53},"Del Tesoro":{"count":91},"하나은행":{"count":77},"CityCommerce Bank":{"count":71},"De Venezuela":{"count":117}},"car_rental":{"Europcar":{"count":291},"Budget":{"count":92},"Sixt":{"count":161},"Avis":{"count":282},"Hertz":{"count":293},"Enterprise":{"count":199},"stadtmobil CarSharing-Station":{"count":148}},"pharmacy":{"Rowlands Pharmacy":{"count":71},"Boots":{"count":840},"Marien-Apotheke":{"count":314},"Mercury Drug":{"count":426},"Löwen-Apotheke":{"count":356},"Superdrug":{"count":117},"Sonnen-Apotheke":{"count":311},"Rathaus-Apotheke":{"count":132},"Engel-Apotheke":{"count":123},"Hirsch-Apotheke":{"count":83},"Stern-Apotheke":{"count":67},"Lloyds Pharmacy":{"count":295},"Rosen-Apotheke":{"count":208},"Stadt-Apotheke":{"count":302},"Markt-Apotheke":{"count":164},"Аптека":{"count":1989},"Pharmasave":{"count":64},"Brunnen-Apotheke":{"count":53},"Shoppers Drug Mart":{"count":430},"Apotheke am Markt":{"count":60},"Alte Apotheke":{"count":88},"Neue Apotheke":{"count":109},"Gintarinė vaistinė":{"count":101},"Rats-Apotheke":{"count":84},"Adler Apotheke":{"count":313},"Pharmacie Centrale":{"count":64},"Walgreens":{"count":1619},"Rite Aid":{"count":745},"Apotheke":{"count":165},"Linden-Apotheke":{"count":211},"Bahnhof-Apotheke":{"count":66},"Burg-Apotheke":{"count":55},"Jean Coutu":{"count":62},"Pharmaprix":{"count":60},"Farmacias Ahumada":{"count":104},"Farmacia Comunale":{"count":113},"Farmacias Cruz Verde":{"count":86},"Cruz Verde":{"count":99},"Hubertus Apotheke":{"count":52},"CVS":{"count":1560},"Farmacias SalcoBrand":{"count":133},"Фармация":{"count":120},"Bären-Apotheke":{"count":74},"Clicks":{"count":113},"セイジョー":{"count":53},"マツモトキヨシ":{"count":115},"Dr. Max":{"count":51},"Вита":{"count":106},"Радуга":{"count":70},"サンドラッグ":{"count":61},"Apteka":{"count":366},"Первая помощь":{"count":74},"Ригла":{"count":113},"Имплозия":{"count":63},"Kinney Drugs":{"count":68},"Классика":{"count":67},"Ljekarna":{"count":53},"SalcoBrand":{"count":88},"Аптека 36,6":{"count":224},"Фармакор":{"count":75},"スギ薬局":{"count":84},"Аптечный пункт":{"count":148},"Невис":{"count":60},"トモズ (Tomod's)":{"count":83},"Eurovaistinė":{"count":65},"Farmacity":{"count":68},"аптека":{"count":96},"The Generics Pharmacy":{"count":95},"Farmatodo":{"count":123},"Duane Reade":{"count":61},"H-E-B":{"count":262},"Фармленд":{"count":82},"ドラッグてらしま (Drug Terashima)":{"count":96},"Арніка":{"count":125},"ავერსი (Aversi)":{"count":62},"Farmahorro":{"count":58}},"cafe":{"Starbucks":{"count":4238,"tags":{"cuisine":"coffee_shop"}},"Cafeteria":{"count":115},"Costa":{"count":618},"Caffè Nero":{"count":169},"Кафе":{"count":226},"Café Central":{"count":61},"Second Cup":{"count":193},"Dunkin Donuts":{"count":428,"tags":{"cuisine":"donut"}},"Espresso House":{"count":53},"Segafredo":{"count":69},"Coffee Time":{"count":94},"Cafe Coffee Day":{"count":120},"Eiscafe Venezia":{"count":180},"スターバックス":{"count":251,"tags":{"name:en":"Starbucks"}},"Шоколадница":{"count":145},"Pret A Manger":{"count":119},"Столовая":{"count":391},"Jamba Juice":{"count":53},"ドトール":{"count":164,"tags":{"name:en":"DOUTOR"}},"Tchibo":{"count":100},"Кофе Хауз":{"count":104},"Caribou Coffee":{"count":100},"Уют":{"count":51},"Шашлычная":{"count":58},"คาเฟ่ อเมซอน":{"count":62},"Traveler's Coffee":{"count":60},"カフェ・ド・クリエ":{"count":67,"tags":{"name:en":"Cafe de CRIE"}},"Cafe Amazon":{"count":65}}};
18593 var shop = {"supermarket":{"Budgens":{"count":88},"Morrisons":{"count":411},"Interspar":{"count":142},"Merkur":{"count":107},"Sainsbury's":{"count":547},"Lidl":{"count":7130},"Edeka":{"count":2293},"Coles":{"count":400},"Iceland":{"count":315},"Coop":{"count":2100},"Tesco":{"count":1297},"Woolworths":{"count":541},"Zielpunkt":{"count":239},"Nahkauf":{"count":170},"Billa":{"count":1432},"Kaufland":{"count":1004},"Plus":{"count":120},"ALDI":{"count":5172},"Checkers":{"count":128},"Tesco Metro":{"count":137},"NP":{"count":153},"Penny":{"count":1759},"Norma":{"count":1068},"Asda":{"count":225},"Netto":{"count":4379},"Rewe":{"count":2645},"Aldi Süd":{"count":594},"Real":{"count":246},"Tesco Express":{"count":406},"King Soopers":{"count":72},"Kiwi":{"count":167},"Pick n Pay":{"count":241},"ICA":{"count":192},"Tengelmann":{"count":188},"Carrefour":{"count":1640},"Waitrose":{"count":258},"Spar":{"count":2386},"Hofer":{"count":442},"M-Preis":{"count":76},"tegut":{"count":210},"Sainsbury's Local":{"count":118},"E-Center":{"count":66},"Aldi Nord":{"count":210},"nahkauf":{"count":84},"Meijer":{"count":76},"Safeway":{"count":410},"Costco":{"count":152},"Albert":{"count":185},"Jumbo":{"count":194},"Shoprite":{"count":244},"MPreis":{"count":54},"Penny Market":{"count":429},"Tesco Extra":{"count":123},"Albert Heijn":{"count":476},"IGA":{"count":363},"Super U":{"count":488},"Metro":{"count":260},"Neukauf":{"count":77},"Migros":{"count":459},"Marktkauf":{"count":121},"Delikatesy Centrum":{"count":59},"C1000":{"count":307},"Hoogvliet":{"count":53},"Food Basics":{"count":75},"Casino":{"count":264},"Penny Markt":{"count":466},"Giant":{"count":191},"COOP Jednota":{"count":73},"Rema 1000":{"count":368},"Kaufpark":{"count":96},"ALDI SÜD":{"count":113},"Simply Market":{"count":330},"Konzum":{"count":230},"Carrefour Express":{"count":353},"Eurospar":{"count":270},"Mercator":{"count":125},"Famila":{"count":130},"Hemköp":{"count":82},"real,-":{"count":81},"Markant":{"count":88},"Volg":{"count":135},"Leader Price":{"count":267},"Treff 3000":{"count":94},"SuperBrugsen":{"count":67},"Kaiser's":{"count":256},"K+K":{"count":106},"Unimarkt":{"count":86},"Carrefour City":{"count":126},"Sobeys":{"count":122},"S-Market":{"count":109},"Combi":{"count":55},"Denner":{"count":276},"Konsum":{"count":133},"Franprix":{"count":312},"Monoprix":{"count":198},"Diska":{"count":69},"PENNY":{"count":79},"Dia":{"count":835},"Giant Eagle":{"count":85},"NORMA":{"count":115},"AD Delhaize":{"count":63},"Auchan":{"count":152},"Mercadona":{"count":769},"Consum":{"count":130},"Carrefour Market":{"count":80},"Whole Foods":{"count":210,"tags":{"shop":"supermarket"}},"Pam":{"count":56},"sky":{"count":105},"Despar":{"count":146},"Eroski":{"count":208},"Costcutter":{"count":63},"Maxi":{"count":108},"Colruyt":{"count":180},"The Co-operative":{"count":64},"Intermarché":{"count":1210},"Delhaize":{"count":207},"CBA":{"count":176},"Shopi":{"count":53},"Walmart":{"count":644},"Kroger":{"count":317},"Albertsons":{"count":242},"Trader Joe's":{"count":235},"Feneberg":{"count":58},"denn's Biomarkt":{"count":52},"dm":{"count":114},"Kvickly":{"count":55},"Makro":{"count":140},"Dico":{"count":53},"Nah & Frisch":{"count":73},"Champion":{"count":59},"ICA Supermarket":{"count":51},"Fakta":{"count":235},"Магнит":{"count":1760},"Caprabo":{"count":103},"Famiglia Cooperativa":{"count":64},"Народная 7Я семьЯ":{"count":154},"Esselunga":{"count":85},"Maxima":{"count":102},"Petit Casino":{"count":111},"Wasgau":{"count":60},"Pingo Doce":{"count":253},"Match":{"count":140},"Profi":{"count":60},"Lider":{"count":65},"Unimarc":{"count":177},"The Co-operative Food":{"count":190},"Santa Isabel":{"count":128},"Седьмой континент":{"count":79},"HIT":{"count":59},"Rimi":{"count":106},"Conad":{"count":304},"Фуршет":{"count":76},"Willys":{"count":56},"Farmfoods":{"count":64},"U Express":{"count":51},"Фора":{"count":52},"Dunnes Stores":{"count":73},"Сільпо":{"count":125},"マルエツ":{"count":59},"Piggly Wiggly":{"count":57},"Crai":{"count":54},"El Árbol":{"count":73},"Centre Commercial E. Leclerc":{"count":549},"Foodland":{"count":100},"Super Brugsen":{"count":67},"Дикси":{"count":683},"Пятёрочка":{"count":1344},"Publix":{"count":339},"Føtex":{"count":66},"coop":{"count":73},"Fressnapf":{"count":69},"Coop Konsum":{"count":79},"Carrefour Contact":{"count":83},"No Frills":{"count":105},"Plodine":{"count":52},"ADEG":{"count":68},"Minipreço":{"count":111},"Biedronka":{"count":1335},"Eurospin":{"count":155},"Семья":{"count":62},"Gadis":{"count":53},"Евроопт":{"count":68},"Centra":{"count":51},"Квартал":{"count":82},"New World":{"count":69},"Countdown":{"count":95},"Reliance Fresh":{"count":61},"Stokrotka":{"count":98},"Coop Jednota":{"count":74},"Fred Meyer":{"count":64},"Irma":{"count":58},"Continente":{"count":75},"Price Chopper":{"count":99},"Game":{"count":52},"Soriana":{"count":93},"Alimerka":{"count":64},"Piotr i Paweł":{"count":53},"Перекресток":{"count":312},"Maxima X":{"count":117},"Карусель":{"count":55},"ALDI Nord":{"count":51},"Condis":{"count":67},"Sam's Club":{"count":138},"Копейка":{"count":87},"Géant Casino":{"count":54},"ASDA":{"count":180},"Intermarche":{"count":115},"Stop & Shop":{"count":66},"Food Lion":{"count":216},"Harris Teeter":{"count":92},"Foodworks":{"count":62},"Polo Market":{"count":86},"Лента":{"count":51},"西友 (SEIYU)":{"count":58},"H-E-B":{"count":293},"Атак":{"count":53},"Полушка":{"count":139},"Extra":{"count":82},"Lewiatan":{"count":94},"Sigma":{"count":51},"АТБ":{"count":322},"Społem":{"count":55},"Bodega Aurrera":{"count":82},"Tesco Lotus":{"count":77},"Мария-Ра":{"count":108},"Магнолия":{"count":72},"Магазин":{"count":120},"Монетка":{"count":174},"Hy-Vee":{"count":75},"Walmart Supercenter":{"count":133},"Hannaford":{"count":57},"Wegmans":{"count":83},"業務スーパー":{"count":61},"Norfa XL":{"count":55},"ヨークマート (YorkMart)":{"count":64},"Leclerc Drive":{"count":76}},"electronics":{"Media Markt":{"count":285},"Maplin":{"count":65},"Best Buy":{"count":345},"Future Shop":{"count":73},"Saturn":{"count":134},"Currys":{"count":80},"Radio Shack":{"count":269},"Euronics":{"count":115},"Expert":{"count":123},"Эльдорадо":{"count":184},"Darty":{"count":74},"М.Видео":{"count":89},"ヤマダ電機":{"count":51}},"convenience":{"Shell":{"count":255},"Spar":{"count":1119},"McColl's":{"count":100},"Tesco Express":{"count":426},"Sainsbury's Local":{"count":104},"Aral":{"count":56},"One Stop":{"count":146},"The Co-operative Food":{"count":115},"Londis":{"count":352},"7-Eleven":{"count":4440},"CBA":{"count":135},"Coop":{"count":678},"Sale":{"count":80},"Statoil":{"count":69},"Sheetz":{"count":54},"Konzum":{"count":173},"Siwa":{"count":216},"Mercator":{"count":57},"Esso":{"count":67},"COOP Jednota":{"count":181},"Mac's":{"count":152},"Alepa":{"count":62},"Hasty Market":{"count":54},"K-Market":{"count":54},"Costcutter":{"count":292},"Valintatalo":{"count":62},"Casino":{"count":90},"Franprix":{"count":61},"Circle K":{"count":289},"セブンイレブン":{"count":3011,"tags":{"name:en":"7-Eleven"}},"ローソン":{"count":1596,"tags":{"name:en":"LAWSON"}},"BP":{"count":163},"Tesco":{"count":55},"Petit Casino":{"count":233},"Volg":{"count":116},"Mace":{"count":115},"Mini Market":{"count":272},"Nisa Local":{"count":77},"Dorfladen":{"count":75},"Продукты":{"count":4285},"Mini Stop":{"count":228},"LAWSON":{"count":419},"デイリーヤマザキ":{"count":141},"Biedronka":{"count":83},"Надежда":{"count":56},"Mobil":{"count":66},"Nisa":{"count":51},"Premier":{"count":129},"ABC":{"count":152},"ミニストップ":{"count":316,"tags":{"name:en":"MINISTOP"}},"サンクス":{"count":560,"tags":{"name:en":"sunkus"}},"スリーエフ":{"count":88},"8 à Huit":{"count":61},"Tchibo":{"count":56},"Żabka":{"count":546},"Almacen":{"count":229},"Vival":{"count":194},"FamilyMart":{"count":529},"ファミリーマート":{"count":1608,"tags":{"name:en":"FamilyMart"}},"Carrefour City":{"count":57},"Sunkus":{"count":62},"Casey's General Store":{"count":95},"セブンイレブン(Seven-Eleven)":{"count":65},"Jednota":{"count":58},"Магазин":{"count":915},"Гастроном":{"count":152},"Centra":{"count":111},"Магнит":{"count":701},"サークルK":{"count":538,"tags":{"name:en":"Circle K"}},"Wawa":{"count":135},"Proxi":{"count":123},"Универсам":{"count":78},"Перекресток":{"count":51},"Groszek":{"count":65},"Select":{"count":62},"Večerka":{"count":51},"Potraviny":{"count":249},"Смак":{"count":78},"Эконом":{"count":55},"Березка":{"count":77},"Społem":{"count":93},"Carrefour Express":{"count":84},"Cumberland Farms":{"count":63},"Chevron":{"count":59},"Coop Jednota":{"count":66},"Tesco Lotus Express":{"count":67},"Kiosk":{"count":55},"Sklep spożywczy":{"count":130},"24 часа":{"count":58},"Минимаркет":{"count":102},"Oxxo":{"count":669},"Пятёрочка":{"count":398},"abc":{"count":74},"7/11":{"count":51},"Stewart's":{"count":255},"Продукти":{"count":171},"ローソンストア100 (LAWSON STORE 100)":{"count":85},"Дикси":{"count":119},"Радуга":{"count":86},"ローソンストア100":{"count":76},"เซเว่นอีเลฟเว่น":{"count":185},"Delikatesy Centrum":{"count":53},"Citgo":{"count":62},"Фортуна":{"count":51},"Kum & Go":{"count":59},"Мария-Ра":{"count":76},"Picard":{"count":57},"Four Square":{"count":52},"Визит":{"count":57},"Авоська":{"count":55},"Dollar General":{"count":127},"Studenac":{"count":76},"Central Convenience Store":{"count":55},"Монетка":{"count":62},"продукты":{"count":114},"Теремок":{"count":56},"Kwik Trip":{"count":69},"Кулинария":{"count":55},"全家":{"count":90},"Мечта":{"count":54},"Epicerie":{"count":102},"Кировский":{"count":67},"Food Mart":{"count":117},"Delikatesy":{"count":81},"ポプラ":{"count":54},"Lewiatan":{"count":135},"Продуктовый магазин":{"count":149},"Продуктовый":{"count":84},"セイコーマート (Seicomart)":{"count":72},"Виктория":{"count":70},"Весна":{"count":57},"Mini Market Non-Stop":{"count":60},"QuikTrip":{"count":75},"Копеечка":{"count":51},"Royal Farms":{"count":51},"Alfamart":{"count":103},"Indomaret":{"count":141},"магазин":{"count":171},"全家便利商店":{"count":156},"Boutique":{"count":59},"მარკეტი (Market)":{"count":144},"Stores":{"count":61}},"chemist":{"dm":{"count":939},"Müller":{"count":212},"Schlecker":{"count":187},"Etos":{"count":467},"Bipa":{"count":289},"Rossmann":{"count":1669},"DM Drogeriemarkt":{"count":55},"Ihr Platz":{"count":73},"Douglas":{"count":62},"Kruidvat":{"count":123}},"car_repair":{"Peugeot":{"count":83},"Kwik Fit":{"count":128},"ATU":{"count":261},"Midas":{"count":202},"Feu Vert":{"count":113},"Norauto":{"count":152},"Speedy":{"count":115},"Автозапчасти":{"count":212},"Renault":{"count":171},"Pit Stop":{"count":58},"Jiffy Lube":{"count":198},"Шиномонтаж":{"count":1157},"СТО":{"count":395},"O'Reilly Auto Parts":{"count":81},"Carglass":{"count":112},"шиномонтаж":{"count":62},"Citroen":{"count":51},"Euromaster":{"count":87},"Firestone":{"count":88},"Автосервис":{"count":361},"Advance Auto Parts":{"count":52},"Roady":{"count":56}},"furniture":{"IKEA":{"count":169},"Jysk":{"count":109},"Roller":{"count":78},"Dänisches Bettenlager":{"count":309},"Conforama":{"count":99},"Matratzen Concord":{"count":52},"Мебель":{"count":210},"But":{"count":63}},"doityourself":{"Hornbach":{"count":123},"B&Q":{"count":225},"Hubo":{"count":77},"Mr Bricolage":{"count":88},"Gamma":{"count":111},"OBI":{"count":422},"Lowes":{"count":1152},"Wickes":{"count":123},"Hagebau":{"count":59},"Max Bahr":{"count":79},"Castorama":{"count":153},"Rona":{"count":61},"Home Depot":{"count":865},"Toom Baumarkt":{"count":71},"Homebase":{"count":225},"Baumax":{"count":95},"Lagerhaus":{"count":79},"Bauhaus":{"count":186},"Canadian Tire":{"count":97},"Leroy Merlin":{"count":209},"Hellweg":{"count":58},"Brico":{"count":98},"Bricomarché":{"count":235},"Toom":{"count":67},"Hagebaumarkt":{"count":107},"Praktiker":{"count":122},"Menards":{"count":70},"Weldom":{"count":73},"Bunnings Warehouse":{"count":91},"Ace Hardware":{"count":147},"Home Hardware":{"count":72},"Хозтовары":{"count":86},"Стройматериалы":{"count":197},"Bricorama":{"count":60},"Point P":{"count":59}},"stationery":{"Staples":{"count":299},"McPaper":{"count":83},"Office Depot":{"count":98},"Канцтовары":{"count":63}},"car":{"Skoda":{"count":97},"BMW":{"count":149},"Citroen":{"count":277},"Renault":{"count":382},"Mercedes-Benz":{"count":235},"Volvo":{"count":96},"Ford":{"count":239},"Volkswagen":{"count":217},"Mazda":{"count":105},"Mitsubishi":{"count":73},"Fiat":{"count":93},"Автозапчасти":{"count":277},"Opel":{"count":165},"Audi":{"count":121},"Toyota":{"count":271},"Nissan":{"count":189},"Suzuki":{"count":75},"Honda":{"count":157},"Peugeot":{"count":308},"Шиномонтаж":{"count":259},"Hyundai":{"count":166},"Subaru":{"count":58},"Chevrolet":{"count":86},"Автомагазин":{"count":72}},"clothes":{"Matalan":{"count":90},"KiK":{"count":1219},"H&M":{"count":658},"Urban Outfitters":{"count":63},"Vögele":{"count":132},"Zeeman":{"count":121},"Takko":{"count":515},"Adler":{"count":55},"C&A":{"count":506},"Zara":{"count":217},"Vero Moda":{"count":95},"NKD":{"count":486},"Ernsting's family":{"count":312},"Winners":{"count":65},"River Island":{"count":59},"Next":{"count":176},"Gap":{"count":81},"Adidas":{"count":92},"Woolworths":{"count":117},"Mr Price":{"count":88},"Jet":{"count":61},"Pep":{"count":134},"Edgars":{"count":110},"Ackermans":{"count":91},"Truworths":{"count":65},"Ross":{"count":93},"Burton":{"count":51},"Dorothy Perkins":{"count":53},"Deichmann":{"count":61},"Lindex":{"count":73},"s.Oliver":{"count":56},"Cecil":{"count":51},"Dress Barn":{"count":52},"Old Navy":{"count":174},"Jack & Jones":{"count":52},"Pimkie":{"count":73},"Esprit":{"count":231},"Primark":{"count":92},"Bonita":{"count":155},"Mexx":{"count":67},"Gerry Weber":{"count":71},"Tally Weijl":{"count":70},"Mango":{"count":133},"TK Maxx":{"count":84},"Benetton":{"count":101},"Ulla Popken":{"count":61},"AWG":{"count":66},"Tommy Hilfiger":{"count":75},"New Yorker":{"count":180},"Orsay":{"count":73},"Jeans Fritz":{"count":51},"Charles Vögele":{"count":69},"New Look":{"count":126},"Lacoste":{"count":78},"Etam":{"count":53},"Kiabi":{"count":148},"Jack Wolfskin":{"count":60},"American Apparel":{"count":57},"Men's Wearhouse":{"count":54},"Intimissimi":{"count":52},"United Colors of Benetton":{"count":96},"Jules":{"count":63},"Second Hand":{"count":53},"AOKI":{"count":57},"Calzedonia":{"count":68},"洋服の青山":{"count":100},"Levi's":{"count":63},"Celio":{"count":74},"TJ Maxx":{"count":57},"Promod":{"count":82},"Street One":{"count":72},"ユニクロ":{"count":59},"Banana Republic":{"count":57},"Одежда":{"count":75},"Marshalls":{"count":56},"La Halle":{"count":62},"Peacocks":{"count":89},"しまむら":{"count":60}},"books":{"Bruna":{"count":58},"Waterstones":{"count":90},"Libro":{"count":57},"Barnes & Noble":{"count":267},"Weltbild":{"count":74},"Thalia":{"count":121},"Книги":{"count":112}},"department_store":{"Debenhams":{"count":67},"Canadian Tire":{"count":75},"Karstadt":{"count":64},"Walmart":{"count":517},"Kmart":{"count":143},"Target":{"count":574},"Galeria Kaufhof":{"count":61},"Marks & Spencer":{"count":66},"Big W":{"count":57},"Woolworth":{"count":78},"Универмаг":{"count":72},"Sears":{"count":235},"Walmart Supercenter":{"count":101},"Kohl's":{"count":153},"Macy's":{"count":147},"Sam's Club":{"count":54},"JCPenney":{"count":66}},"alcohol":{"Alko":{"count":145},"The Beer Store":{"count":150},"Systembolaget":{"count":210},"LCBO":{"count":239},"Ароматный мир":{"count":62},"Bargain Booze":{"count":62},"Nicolas":{"count":119},"BWS":{"count":70},"Botilleria":{"count":77},"SAQ":{"count":72},"Gall & Gall":{"count":512},"Живое пиво":{"count":70}},"bakery":{"Kamps":{"count":252},"Banette":{"count":52},"Bäckerei Schmidt":{"count":57},"Anker":{"count":73},"Hofpfisterei":{"count":111},"Greggs":{"count":276},"Oebel":{"count":57},"Boulangerie":{"count":266},"Stadtbäckerei":{"count":57},"Steinecke":{"count":145},"Ihle":{"count":76},"Goldilocks":{"count":59},"Dat Backhus":{"count":67},"K&U":{"count":61},"Der Beck":{"count":96},"Thürmann":{"count":54},"Backwerk":{"count":95},"Schäfer's":{"count":51},"Panaderia":{"count":168},"Goeken backen":{"count":51},"Stadtbäckerei Junge":{"count":51},"Boulangerie Patisserie":{"count":119},"Paul":{"count":81},"Хлеб":{"count":89},"Пекарня":{"count":52},"Кулиничи":{"count":51}},"sports":{"Sports Direct":{"count":57},"Decathlon":{"count":309},"Intersport":{"count":283},"Sports Authority":{"count":75},"Спортмастер":{"count":87},"Sport 2000":{"count":90},"Dick's Sporting Goods":{"count":77}},"variety_store":{"Tedi":{"count":157},"Dollarama":{"count":103},"Family Dollar":{"count":61},"Dollar Tree":{"count":110},"Dollar General":{"count":80}},"pet":{"Fressnapf":{"count":318},"PetSmart":{"count":177},"Das Futterhaus":{"count":69},"Pets at Home":{"count":62},"Petco":{"count":101},"Зоомагазин":{"count":100}},"shoes":{"Deichmann":{"count":622},"Reno":{"count":183},"Ecco":{"count":55},"Clarks":{"count":109},"La Halle aux Chaussures":{"count":69},"Brantano":{"count":71},"Geox":{"count":51},"Salamander":{"count":51},"Обувь":{"count":100},"Payless Shoe Source":{"count":67},"Famous Footwear":{"count":59},"Quick Schuh":{"count":72},"Shoe Zone":{"count":55},"Foot Locker":{"count":82},"Bata":{"count":101},"ЦентрОбувь":{"count":51}},"toys":{"La Grande Récré":{"count":56},"Toys R Us":{"count":151,"tags":{"shop":"toys"}},"Intertoys":{"count":57},"Детский мир":{"count":86},"Игрушки":{"count":58}},"travel_agency":{"Flight Centre":{"count":92},"Thomas Cook":{"count":119}},"jewelry":{"Bijou Brigitte":{"count":57},"Christ":{"count":57},"Swarovski":{"count":74}},"optician":{"Fielmann":{"count":232},"Apollo Optik":{"count":150},"Vision Express":{"count":58},"Оптика":{"count":182},"Optic 2000":{"count":98},"Alain Afflelou":{"count":73},"Specsavers":{"count":124},"Krys":{"count":77},"Atol":{"count":55}},"video":{"Blockbuster":{"count":184},"World of Video":{"count":64}},"mobile_phone":{"Билайн":{"count":128},"ソフトバンクショップ (SoftBank shop)":{"count":255},"Vodafone":{"count":355},"O2":{"count":208},"Carphone Warehouse":{"count":127},"Orange":{"count":246},"Verizon Wireless":{"count":125},"Sprint":{"count":109},"T-Mobile":{"count":175},"МТС":{"count":352},"Евросеть":{"count":506},"Bell":{"count":190},"The Phone House":{"count":83},"SFR":{"count":71},"Связной":{"count":439},"Мегафон":{"count":251},"AT&T":{"count":124},"ドコモショップ (docomo shop)":{"count":114},"au":{"count":65},"Movistar":{"count":77},"Bitė":{"count":72}},"hifi":{},"computer":{"PC World":{"count":55},"DNS":{"count":128}},"hairdresser":{"Klier":{"count":119},"Supercuts":{"count":106},"Hairkiller":{"count":51},"Great Clips":{"count":182},"Парикмахерская":{"count":510},"Стиль":{"count":51},"Franck Provost":{"count":70},"Салон красоты":{"count":70}},"hardware":{"1000 мелочей":{"count":61},"Хозтовары":{"count":151},"Стройматериалы":{"count":54}},"motorcycle":{"Yamaha":{"count":67},"Honda":{"count":69}}};
18594 var dataSuggestions = {
18595         amenity: amenity,
18596         shop: shop
18597 };
18598
18599 var dataAddressFormats = [{"format":[["housenumber","street"],["city","postcode"]]},{"countryCodes":["gb"],"format":[["housename"],["housenumber","street"],["city","postcode"]]},{"countryCodes":["ie"],"format":[["housename"],["housenumber","street"],["city"],["postcode"]]},{"countryCodes":["ad","at","ba","be","ch","cz","de","dk","es","fi","gr","hr","is","it","li","nl","no","pl","pt","se","si","sk","sm","va"],"format":[["street","housenumber"],["postcode","city"]]},{"countryCodes":["fr","lu","mo"],"format":[["housenumber","street"],["postcode","city"]]},{"countryCodes":["br"],"format":[["street"],["housenumber","suburb"],["city","postcode"]]},{"countryCodes":["vn"],"format":[["housenumber","street"],["subdistrict"],["district"],["city"],["province","postcode"]]},{"countryCodes":["us"],"format":[["housenumber","street"],["city","state","postcode"]]},{"countryCodes":["ca"],"format":[["housenumber","street"],["city","province","postcode"]]},{"countryCodes":["tw"],"format":[["postcode","city","district"],["place","street"],["housenumber","floor"]]},{"countryCodes":["jp"],"format":[["postcode","province","county"],["city","suburb"],["quarter","neighbourhood"],["block_number","housenumber"]],"dropdowns":["postcode","province","county","city","suburb","quarter","neighbourhood","block_number"],"widths":{"postcode":0.3,"province":0.35,"county":0.35,"city":0.65,"suburb":0.35,"quarter":0.5,"neighbourhood":0.5,"block_number":0.5,"housenumber":0.5}},{"countryCodes":["tr"],"format":[["neighbourhood"],["street","housenumber"],["postcode","district","city"]]},{"countryCodes":["ua"],"format":[["housenumber","postcode"],["street"]]},{"countryCodes":["cn"],"format":[["postcode","province"],["city"],["district"],["street","housenumber"]]}];
18600
18601 var dataDeprecated = [{"old":{"amenity":"firepit"},"replace":{"leisure":"firepit"}},{"old":{"barrier":"wire_fence"},"replace":{"barrier":"fence","fence_type":"chain"}},{"old":{"barrier":"wood_fence"},"replace":{"barrier":"fence","fence_type":"wood"}},{"old":{"highway":"ford"},"replace":{"ford":"yes"}},{"old":{"highway":"stile"},"replace":{"barrier":"stile"}},{"old":{"highway":"incline"},"replace":{"highway":"road","incline":"up"}},{"old":{"highway":"incline_steep"},"replace":{"highway":"road","incline":"up"}},{"old":{"highway":"unsurfaced"},"replace":{"highway":"road","incline":"unpaved"}},{"old":{"landuse":"wood"},"replace":{"landuse":"forest","natural":"wood"}},{"old":{"natural":"marsh"},"replace":{"natural":"wetland","wetland":"marsh"}},{"old":{"power_source":"*"},"replace":{"generator:source":"$1"}},{"old":{"power_rating":"*"},"replace":{"generator:output":"$1"}},{"old":{"shop":"organic"},"replace":{"shop":"supermarket","organic":"only"}}];
18602
18603 var dataDiscarded = ["created_by","odbl","odbl:note","tiger:upload_uuid","tiger:tlid","tiger:source","tiger:separated","geobase:datasetName","geobase:uuid","sub_sea:type","KSJ2:ADS","KSJ2:ARE","KSJ2:AdminArea","KSJ2:COP_label","KSJ2:DFD","KSJ2:INT","KSJ2:INT_label","KSJ2:LOC","KSJ2:LPN","KSJ2:OPC","KSJ2:PubFacAdmin","KSJ2:RAC","KSJ2:RAC_label","KSJ2:RIC","KSJ2:RIN","KSJ2:WSC","KSJ2:coordinate","KSJ2:curve_id","KSJ2:curve_type","KSJ2:filename","KSJ2:lake_id","KSJ2:lat","KSJ2:long","KSJ2:river_id","yh:LINE_NAME","yh:LINE_NUM","yh:STRUCTURE","yh:TOTYUMONO","yh:TYPE","yh:WIDTH","yh:WIDTH_RANK","SK53_bulk:load"];
18604
18605 var dataLocales = {"af":{"rtl":false},"ar":{"rtl":true},"ar-AA":{"rtl":true},"ast":{"rtl":false},"bg":{"rtl":false},"bg-BG":{"rtl":false},"bn":{"rtl":false},"bs":{"rtl":false},"ca":{"rtl":false},"cs":{"rtl":false},"da":{"rtl":false},"de":{"rtl":false},"el":{"rtl":false},"en-GB":{"rtl":false},"eo":{"rtl":false},"es":{"rtl":false},"et":{"rtl":false},"fa":{"rtl":true},"fi":{"rtl":false},"fr":{"rtl":false},"gan":{"rtl":false},"gl":{"rtl":false},"gu":{"rtl":false},"he":{"rtl":true},"hi":{"rtl":false},"hr":{"rtl":false},"hu":{"rtl":false},"hy":{"rtl":false},"ia":{"rtl":false},"id":{"rtl":false},"is":{"rtl":false},"it":{"rtl":false},"ja":{"rtl":false},"jv":{"rtl":false},"km":{"rtl":false},"kn":{"rtl":false},"ko":{"rtl":false},"ku":{"rtl":true},"lij":{"rtl":false},"lt":{"rtl":false},"lv":{"rtl":false},"mg":{"rtl":false},"mk":{"rtl":false},"ml":{"rtl":false},"mn":{"rtl":false},"ms":{"rtl":false},"ne":{"rtl":false},"nl":{"rtl":false},"nn":{"rtl":false},"no":{"rtl":false},"nv":{"rtl":false},"pl":{"rtl":false},"pt":{"rtl":false},"pt-BR":{"rtl":false},"rm":{"rtl":false},"ro":{"rtl":false},"ru":{"rtl":false},"sc":{"rtl":false},"si":{"rtl":false},"sk":{"rtl":false},"sl":{"rtl":false},"sq":{"rtl":false},"sr":{"rtl":false},"sv":{"rtl":false},"ta":{"rtl":false},"te":{"rtl":false},"th":{"rtl":false},"tl":{"rtl":false},"tr":{"rtl":false},"uk":{"rtl":false},"ur":{"rtl":true},"vi":{"rtl":false},"yue":{"rtl":false},"zh":{"rtl":false},"zh-CN":{"rtl":false},"zh-HK":{"rtl":false},"zh-TW":{"rtl":false}};
18606
18607 var dataPhoneFormats = {"us":"+1-202-555-1234","ca":"+1-226-555-1234","bs":"+1-242-555-1234","bb":"+1-246-555-1234","ai":"+1-264-555-1234","ag":"+1-268-555-1234","vg":"+1-284-555-1234","vi":"+1-340-555-1234","ky":"+1-345-555-1234","bm":"+1-441-555-1234","gd":"+1-473-555-1234","tc":"+1-649-555-1234","ms":"+1-664-555-1234","mp":"+1-670-555-1234","gu":"+1-671-555-1234","as":"+1-684-555-1234","sx":"+1-721-555-1234","lc":"+1-758-555-1234","dm":"+1-767-555-1234","vc":"+1-784-555-1234","pr":"+1-787-555-1234","do":"+1-809-555-1234","tt":"+1-868-555-1234","kn":"+1-869-555-1234","jm":"+1-876-555-1234","za":"+27 11 907 1111","nl":"+31 42 123 4567","fr":"+33 1 23 45 67 89","es":"+34 989 12 34 56","pt":"+351 211 123456","ie":"+353 20 912 3456","fi":"+358 40 123 4567","hu":"+36 1 123 45 67","hr":"+385 01 123 4567","si":"+386 31 123 4567","it":"+39 01 123 456","va":"+39 01 123 456","gb":"+44 1632 961234","gg":"+44 1632 961234","im":"+44 1632 961234","je":"+44 1632 961234","se":"+46 31 123 4567","no":"+47 22 12 34 56","sj":"+47 22 12 34 56","pl":"+48 42 123 4567","de":"+49 89 1234567","br":"+55 11 0982 1098","ru":"+7 495 1234567","kz":"+7 495 1234567","vn":"+84 1 234 5678","hk":"+852 1234 5678","cn":"+86 10 12345678","tw":"+886 1 2345 6789","tr":"+90 312 123 4567","ua":"+380 44 123 4567"};
18608
18609 var dataShortcuts = [{"tab":"browsing","text":"shortcuts.browsing.title","columns":[{"rows":[{"section":"navigation","text":"shortcuts.browsing.navigation.title"},{"shortcuts":["↓","↑","←","→"],"text":"shortcuts.browsing.navigation.pan","separator":","},{"modifiers":["⌘"],"shortcuts":["↓","↑","←","→"],"text":"shortcuts.browsing.navigation.pan_more","separator":","},{"shortcuts":["+","-"],"text":"shortcuts.browsing.navigation.zoom","separator":","},{"modifiers":["⌘"],"shortcuts":["+","-"],"text":"shortcuts.browsing.navigation.zoom_more","separator":","},{"section":"help","text":"shortcuts.browsing.help.title"},{"shortcuts":["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":["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"}},"club":{"label":"Type"},"collection_times":{"label":"Collection Times"},"communication_multi":{"label":"Communication Types"},"construction":{"label":"Type"},"contact/webcam":{"label":"Webcam URL","placeholder":"http://example.com/"},"content":{"label":"Contents"},"country":{"label":"Country"},"covered":{"label":"Covered"},"craft":{"label":"Type"},"crop":{"label":"Crops"},"crossing":{"label":"Type"},"cuisine":{"label":"Cuisines"},"currency_multi":{"label":"Currency Types"},"cycle_network":{"label":"Network"},"cycleway":{"label":"Bike Lanes","placeholder":"none","types":{"cycleway:left":"Left side","cycleway:right":"Right side"},"options":{"none":{"title":"None","description":"No bike lane"},"lane":{"title":"Standard bike lane","description":"A bike lane separated from auto traffic by a painted line"},"shared_lane":{"title":"Shared bike lane","description":"A bike lane with no separation from auto traffic"},"track":{"title":"Bike track","description":"A bike lane separated from traffic by a physical barrier"},"share_busway":{"title":"Bike lane shared with bus","description":"A bike lane shared with a bus lane"},"opposite_lane":{"title":"Opposite bike lane","description":"A bike lane that travels in the opposite direction of traffic"},"opposite":{"title":"Contraflow bike lane","description":"A bike lane that travels in both directions on a one-way street"}}},"date":{"label":"Date"},"delivery":{"label":"Delivery"},"denomination":{"label":"Denomination"},"denotation":{"label":"Denotation"},"description":{"label":"Description"},"diaper":{"label":"Diaper Changing Available"},"display":{"label":"Display"},"dock":{"label":"Type"},"drive_through":{"label":"Drive-Through"},"electrified":{"label":"Electrification","placeholder":"Contact Line, Electrified Rail...","options":{"contact_line":"Contact Line","rail":"Electrified Rail","yes":"Yes (unspecified)","no":"No"}},"elevation":{"label":"Elevation"},"email":{"label":"Email","placeholder":"example@example.com"},"emergency":{"label":"Emergency"},"entrance":{"label":"Type"},"except":{"label":"Exceptions"},"fax":{"label":"Fax","placeholder":"+31 42 123 4567"},"fee":{"label":"Fee"},"fence_type":{"label":"Type"},"fire_hydrant/position":{"label":"Position","options":{"lane":"Lane","parking_lot":"Parking Lot","sidewalk":"Sidewalk","green":"Green"}},"fire_hydrant/type":{"label":"Type","options":{"pillar":"Pillar/Aboveground","underground":"Underground","wall":"Wall","pond":"Pond"}},"fixme":{"label":"Fix Me"},"fuel_multi":{"label":"Fuel Types"},"fuel":{"label":"Fuel"},"gauge":{"label":"Gauge"},"gender":{"label":"Gender","placeholder":"Unknown","options":{"male":"Male","female":"Female","unisex":"Unisex"}},"generator/method":{"label":"Method"},"generator/source":{"label":"Source"},"generator/type":{"label":"Type"},"golf_hole":{"label":"Reference","placeholder":"Hole number (1-18)"},"grape_variety":{"label":"Grape Varieties"},"handicap":{"label":"Handicap","placeholder":"1-18"},"handrail":{"label":"Handrail"},"height":{"label":"Height (Meters)"},"highway":{"label":"Type"},"historic":{"label":"Type"},"historic/civilization":{"label":"Historic Civilization"},"hoops":{"label":"Hoops","placeholder":"1, 2, 4..."},"iata":{"label":"IATA"},"icao":{"label":"ICAO"},"incline_steps":{"label":"Incline","options":{"up":"Up","down":"Down"}},"incline":{"label":"Incline"},"indoor":{"label":"Indoor"},"information":{"label":"Type"},"inscription":{"label":"Inscription"},"internet_access":{"label":"Internet Access","options":{"yes":"Yes","no":"No","wlan":"Wifi","wired":"Wired","terminal":"Terminal"}},"internet_access/fee":{"label":"Internet Access Fee"},"internet_access/ssid":{"label":"SSID (Network Name)"},"kerb":{"label":"Curb"},"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"},"population":{"label":"Population"},"power_supply":{"label":"Power Supply"},"power":{"label":"Type"},"produce":{"label":"Produce"},"product":{"label":"Products"},"railway":{"label":"Type"},"recycling_accepts":{"label":"Accepts"},"recycling_type":{"label":"Recycling Type","options":{"container":"Container","centre":"Recycling Center"}},"ref":{"label":"Reference"},"relation":{"label":"Type"},"religion":{"label":"Religion"},"restriction":{"label":"Type"},"restrictions":{"label":"Turn Restrictions"},"rooms":{"label":"Rooms"},"route_master":{"label":"Type"},"route":{"label":"Type"},"sac_scale":{"label":"Hiking Difficulty","placeholder":"Mountain Hiking, Alpine Hiking...","options":{"hiking":"T1: Hiking","mountain_hiking":"T2: Mountain Hiking","demanding_mountain_hiking":"T3: Demanding Mountain Hiking","alpine_hiking":"T4: Alpine Hiking","demanding_alpine_hiking":"T5: Demanding Alpine Hiking","difficult_alpine_hiking":"T6: Difficult Alpine Hiking"}},"sanitary_dump_station":{"label":"Toilet Disposal"},"seasonal":{"label":"Seasonal"},"second_hand":{"label":"Sells Used","placeholder":"Yes, No, Only","options":{"yes":"Yes","no":"No","only":"Only"}},"service_rail":{"label":"Service Type","options":{"spur":"Spur","yard":"Yard","siding":"Siding","crossover":"Crossover"}},"service_times":{"label":"Service Times"},"service":{"label":"Type"},"service/bicycle":{"label":"Services"},"service/vehicle":{"label":"Services"},"shelter_type":{"label":"Type"},"shelter":{"label":"Shelter"},"shop":{"label":"Type"},"site":{"label":"Type"},"smoking":{"label":"Smoking","placeholder":"No, Separated, Yes...","options":{"no":"No smoking anywhere","separated":"In smoking areas, not physically isolated","isolated":"In smoking areas, physically isolated","outside":"Allowed outside","yes":"Allowed everywhere","dedicated":"Dedicated to smokers (e.g. smokers' club)"}},"smoothness":{"label":"Smoothness","placeholder":"Thin Rollers, Wheels, Off-Road...","options":{"excellent":"Thin Rollers: rollerblade, skateboard","good":"Thin Wheels: racing bike","intermediate":"Wheels: city bike, wheelchair, scooter","bad":"Robust Wheels: trekking bike, car, rickshaw","very_bad":"High Clearance: light duty off-road vehicle","horrible":"Off-Road: heavy duty off-road vehicle","very_horrible":"Specialized off-road: tractor, ATV","impassable":"Impassable / No wheeled vehicle"}},"social_facility_for":{"label":"People Served"},"social_facility":{"label":"Type"},"source":{"label":"Source"},"sport_ice":{"label":"Sports"},"sport_racing_motor":{"label":"Sports"},"sport_racing_nonmotor":{"label":"Sports"},"sport":{"label":"Sports"},"stars":{"label":"Stars"},"start_date":{"label":"Start Date"},"step_count":{"label":"Number of Steps"},"stop":{"label":"Stop Type","options":{"all":"All Ways","minor":"Minor Road"}},"structure":{"label":"Structure","placeholder":"Unknown","options":{"bridge":"Bridge","tunnel":"Tunnel","embankment":"Embankment","cutting":"Cutting","ford":"Ford"}},"studio":{"label":"Type"},"substation":{"label":"Type"},"supervised":{"label":"Supervised"},"support":{"label":"Support"},"surface":{"label":"Surface"},"surveillance":{"label":"Surveillance Kind"},"surveillance/type":{"label":"Surveillance Type","options":{"camera":"Camera","guard":"Guard","ALPR":"Automatic License Plate Reader"}},"surveillance/zone":{"label":"Surveillance Zone"},"tactile_paving":{"label":"Tactile Paving"},"takeaway":{"label":"Takeaway","placeholder":"Yes, No, Takeaway Only...","options":{"yes":"Yes","no":"No","only":"Takeaway Only"}},"toilets/disposal":{"label":"Disposal","options":{"flush":"Flush","pitlatrine":"Pit/Latrine","chemical":"Chemical","bucket":"Bucket"}},"toll":{"label":"Toll"},"tomb":{"label":"Type"},"tourism":{"label":"Type"},"tower/construction":{"label":"Construction","placeholder":"Guyed, Lattice, Concealed, ..."},"tower/type":{"label":"Type"},"tracktype":{"label":"Track Type","placeholder":"Solid, Mostly Solid, Soft...","options":{"grade1":"Solid: paved or heavily compacted hardcore surface","grade2":"Mostly Solid: gravel/rock with some soft material mixed in","grade3":"Even mixture of hard and soft materials","grade4":"Mostly Soft: soil/sand/grass with some hard material mixed in","grade5":"Soft: soil/sand/grass"}},"traffic_calming":{"label":"Type"},"traffic_signals":{"label":"Type"},"trail_visibility":{"label":"Trail Visibility","placeholder":"Excellent, Good, Bad...","options":{"excellent":"Excellent: unambiguous path or markers everywhere","good":"Good: markers visible, sometimes require searching","intermediate":"Intermediate: few markers, path mostly visible","bad":"Bad: no markers, path sometimes invisible/pathless","horrible":"Horrible: often pathless, some orientation skills required","no":"No: pathless, excellent orientation skills required"}},"trees":{"label":"Trees"},"tunnel":{"label":"Tunnel"},"vending":{"label":"Type of Goods"},"visibility":{"label":"Visibility","options":{"house":"Up to 5m (16ft)","street":"5 to 20m (16 to 65ft)","area":"Over 20m (65ft)"}},"wall":{"label":"Type"},"water_point":{"label":"Water Point"},"water":{"label":"Type"},"waterway":{"label":"Type"},"website":{"label":"Website","placeholder":"http://example.com/"},"wetland":{"label":"Type"},"wheelchair":{"label":"Wheelchair Access"},"width":{"label":"Width (Meters)"},"wikipedia":{"label":"Wikipedia"}},"presets":{"aerialway":{"name":"Aerialway","terms":"ski lift,funifor,funitel"},"aeroway":{"name":"Aeroway","terms":""},"amenity":{"name":"Amenity","terms":""},"highway":{"name":"Highway","terms":""},"place":{"name":"Place","terms":""},"power":{"name":"Power","terms":""},"railway":{"name":"Railway","terms":""},"roundabout":{"name":"Roundabout","terms":""},"waterway":{"name":"Waterway","terms":""},"address":{"name":"Address","terms":""},"advertising/billboard":{"name":"Billboard","terms":""},"aerialway/cable_car":{"name":"Cable Car","terms":"tramway,ropeway"},"aerialway/chair_lift":{"name":"Chair Lift","terms":""},"aerialway/drag_lift":{"name":"Drag Lift","terms":""},"aerialway/gondola":{"name":"Gondola","terms":""},"aerialway/goods":{"name":"Goods Aerialway","terms":""},"aerialway/magic_carpet":{"name":"Magic Carpet Lift","terms":""},"aerialway/mixed_lift":{"name":"Mixed Lift","terms":""},"aerialway/platter":{"name":"Platter Lift","terms":"button lift,poma lift"},"aerialway/pylon":{"name":"Aerialway Pylon","terms":""},"aerialway/rope_tow":{"name":"Rope Tow Lift","terms":"handle tow,bugel lift"},"aerialway/station":{"name":"Aerialway Station","terms":""},"aerialway/t-bar":{"name":"T-bar Lift","terms":""},"aeroway/aerodrome":{"name":"Airport","terms":"airplane,airport,aerodrome"},"aeroway/apron":{"name":"Apron","terms":"ramp"},"aeroway/gate":{"name":"Airport Gate","terms":""},"aeroway/hangar":{"name":"Hangar","terms":""},"aeroway/helipad":{"name":"Helipad","terms":"helicopter,helipad,heliport"},"aeroway/runway":{"name":"Runway","terms":"landing strip"},"aeroway/taxiway":{"name":"Taxiway","terms":""},"aeroway/terminal":{"name":"Airport Terminal","terms":"airport,aerodrome"},"amenity/coworking_space":{"name":"Coworking Space","terms":""},"amenity/nursing_home":{"name":"Nursing Home","terms":""},"amenity/register_office":{"name":"Register Office","terms":""},"amenity/swimming_pool":{"name":"Swimming Pool","terms":""},"amenity/animal_boarding":{"name":"Animal Boarding Facility","terms":"boarding,cat,dog,horse,kitten,pet boarding,pet care,pet hotel,puppy,reptile"},"amenity/animal_breeding":{"name":"Animal Breeding Facility","terms":"breeding,bull,cat,cow,dog,horse,husbandry,kitten,livestock,pet breeding,puppy,reptile"},"amenity/animal_shelter":{"name":"Animal Shelter","terms":"adoption,aspca,cat,dog,horse,kitten,pet care,pet rescue,puppy,raptor,reptile,rescue,spca"},"amenity/arts_centre":{"name":"Arts Center","terms":""},"amenity/atm":{"name":"ATM","terms":"money,cash,machine"},"amenity/bank":{"name":"Bank","terms":"credit union,check,deposit,fund,investment,repository,reserve,safe,savings,stock,treasury,trust,vault"},"amenity/bar":{"name":"Bar","terms":"dive,beer,bier,booze"},"amenity/bbq":{"name":"Barbecue/Grill","terms":"bbq,grill"},"amenity/bench":{"name":"Bench","terms":"seat"},"amenity/bicycle_parking":{"name":"Bicycle Parking","terms":"bike"},"amenity/bicycle_rental":{"name":"Bicycle Rental","terms":"bike"},"amenity/bicycle_repair_station":{"name":"Bicycle Repair Tool Stand","terms":"bike,repair,chain,pump"},"amenity/biergarten":{"name":"Beer Garden","terms":"beer,bier,booze"},"amenity/boat_rental":{"name":"Boat Rental","terms":""},"amenity/bureau_de_change":{"name":"Currency Exchange","terms":"bureau de change,money changer"},"amenity/bus_station":{"name":"Bus Station","terms":""},"amenity/cafe":{"name":"Cafe","terms":"bistro,coffee,tea"},"amenity/car_rental":{"name":"Car Rental","terms":""},"amenity/car_sharing":{"name":"Car Sharing","terms":""},"amenity/car_wash":{"name":"Car Wash","terms":""},"amenity/casino":{"name":"Casino","terms":"gambling,roulette,craps,poker,blackjack"},"amenity/charging_station":{"name":"Charging Station","terms":"EV,Electric Vehicle,Supercharger"},"amenity/childcare":{"name":"Nursery/Childcare","terms":"daycare,orphanage,playgroup"},"amenity/cinema":{"name":"Cinema","terms":"drive-in,film,flick,movie,theater,picture,show,screen"},"amenity/clinic":{"name":"Clinic","terms":"medical,urgentcare"},"amenity/clock":{"name":"Clock","terms":""},"amenity/college":{"name":"College Grounds","terms":"university"},"amenity/community_centre":{"name":"Community Center","terms":"event,hall"},"amenity/compressed_air":{"name":"Compressed Air","terms":""},"amenity/courthouse":{"name":"Courthouse","terms":""},"amenity/crematorium":{"name":"Crematorium","terms":"cemetery,funeral"},"amenity/dentist":{"name":"Dentist","terms":"tooth,teeth"},"amenity/doctors":{"name":"Doctor","terms":"medic*"},"amenity/dojo":{"name":"Dojo / Martial Arts Academy","terms":"martial arts,dojang"},"amenity/drinking_water":{"name":"Drinking Water","terms":"fountain,potable"},"amenity/driving_school":{"name":"Driving School","terms":""},"amenity/embassy":{"name":"Embassy","terms":""},"amenity/fast_food":{"name":"Fast Food","terms":"restaurant,takeaway"},"amenity/ferry_terminal":{"name":"Ferry Terminal","terms":""},"amenity/fire_station":{"name":"Fire Station","terms":""},"amenity/food_court":{"name":"Food Court","terms":"fast food,restaurant,food"},"amenity/fountain":{"name":"Fountain","terms":""},"amenity/fuel":{"name":"Gas Station","terms":"petrol,fuel,gasoline,propane,diesel,lng,cng,biodiesel"},"amenity/grave_yard":{"name":"Graveyard","terms":""},"amenity/grit_bin":{"name":"Grit Bin","terms":"salt,sand"},"amenity/hospital":{"name":"Hospital Grounds","terms":"clinic,doctor,emergency room,health,infirmary,institution,sanatorium,sanitarium,sick,surgery,ward"},"amenity/hunting_stand":{"name":"Hunting Stand","terms":"game,gun,lookout,rifle,shoot*,wild,watch"},"amenity/ice_cream":{"name":"Ice Cream Shop","terms":"gelato,sorbet,sherbet,frozen,yogurt"},"amenity/internet_cafe":{"name":"Internet Cafe","terms":"cybercafe,taxiphone,teleboutique,coffee,cafe,net,lanhouse"},"amenity/kindergarten":{"name":"Preschool/Kindergarten Grounds","terms":"kindergarden,pre-school"},"amenity/library":{"name":"Library","terms":"book"},"amenity/marketplace":{"name":"Marketplace","terms":""},"amenity/motorcycle_parking":{"name":"Motorcycle Parking","terms":""},"amenity/nightclub":{"name":"Nightclub","terms":"disco*,night club,dancing,dance club"},"amenity/parking_entrance":{"name":"Parking Garage Entrance/Exit","terms":""},"amenity/parking_space":{"name":"Parking Space","terms":""},"amenity/parking":{"name":"Car Parking","terms":""},"amenity/pavilion":{"name":"Pavilion","terms":""},"amenity/pharmacy":{"name":"Pharmacy","terms":"drug*,med*,prescription"},"amenity/place_of_worship":{"name":"Place of Worship","terms":"abbey,basilica,bethel,cathedral,chancel,chantry,chapel,church,fold,house of God,house of prayer,house of worship,minster,mission,mosque,oratory,parish,sacellum,sanctuary,shrine,synagogue,tabernacle,temple"},"amenity/place_of_worship/buddhist":{"name":"Buddhist Temple","terms":"stupa,vihara,monastery,temple,pagoda,zendo,dojo"},"amenity/place_of_worship/christian":{"name":"Church","terms":"christian,abbey,basilica,bethel,cathedral,chancel,chantry,chapel,fold,house of God,house of prayer,house of worship,minster,mission,oratory,parish,sacellum,sanctuary,shrine,tabernacle,temple"},"amenity/place_of_worship/jewish":{"name":"Synagogue","terms":"jewish"},"amenity/place_of_worship/muslim":{"name":"Mosque","terms":"muslim"},"amenity/planetarium":{"name":"Planetarium","terms":"museum,astronomy,observatory"},"amenity/police":{"name":"Police","terms":"badge,constable,constabulary,cop,detective,fed,law,enforcement,officer,patrol"},"amenity/post_box":{"name":"Mailbox","terms":"letter,post"},"amenity/post_office":{"name":"Post Office","terms":"letter,mail"},"amenity/prison":{"name":"Prison Grounds","terms":"cell,jail"},"amenity/pub":{"name":"Pub","terms":"alcohol,drink,dive,beer,bier,booze"},"amenity/public_bath":{"name":"Public Bath","terms":"onsen,foot bath,hot springs"},"amenity/public_bookcase":{"name":"Public Bookcase","terms":"library,bookcrossing"},"amenity/ranger_station":{"name":"Ranger Station","terms":"visitor center,visitor centre,permit center,permit centre,backcountry office,warden office,warden center"},"amenity/recycling_centre":{"name":"Recycling Center","terms":"bottle,can,dump,glass,garbage,rubbish,scrap,trash"},"amenity/recycling":{"name":"Recycling","terms":"bin,can,bottle,glass,garbage,rubbish,scrap,trash"},"amenity/restaurant":{"name":"Restaurant","terms":"bar,breakfast,cafe,café,canteen,coffee,dine,dining,dinner,drive-in,eat,grill,lunch,table"},"amenity/sanitary_dump_station":{"name":"RV Toilet Disposal","terms":"Motor Home,Camper,Sanitary,Dump Station,Elsan,CDP,CTDP,Chemical Toilet"},"amenity/school":{"name":"School Grounds","terms":"academy,elementary school,middle school,high school"},"amenity/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/water_point":{"name":"RV Drinking Water","terms":""},"amenity/watering_place":{"name":"Animal Watering Place","terms":""},"area":{"name":"Area","terms":""},"area/highway":{"name":"Road Surface","terms":""},"barrier":{"name":"Barrier","terms":""},"barrier/entrance":{"name":"Entrance","terms":""},"barrier/block":{"name":"Block","terms":""},"barrier/bollard":{"name":"Bollard","terms":""},"barrier/border_control":{"name":"Border Control","terms":""},"barrier/cattle_grid":{"name":"Cattle Grid","terms":""},"barrier/city_wall":{"name":"City Wall","terms":""},"barrier/cycle_barrier":{"name":"Cycle Barrier","terms":""},"barrier/ditch":{"name":"Trench","terms":""},"barrier/fence":{"name":"Fence","terms":""},"barrier/gate":{"name":"Gate","terms":""},"barrier/hedge":{"name":"Hedge","terms":""},"barrier/kissing_gate":{"name":"Kissing Gate","terms":""},"barrier/lift_gate":{"name":"Lift Gate","terms":""},"barrier/retaining_wall":{"name":"Retaining Wall","terms":""},"barrier/stile":{"name":"Stile","terms":""},"barrier/toll_booth":{"name":"Toll Booth","terms":""},"barrier/wall":{"name":"Wall","terms":""},"boundary/administrative":{"name":"Administrative Boundary","terms":""},"building":{"name":"Building","terms":""},"building/bunker":{"name":"Bunker","terms":""},"building/entrance":{"name":"Entrance/Exit","terms":""},"building/train_station":{"name":"Train Station","terms":""},"building/apartments":{"name":"Apartments","terms":""},"building/barn":{"name":"Barn","terms":""},"building/cabin":{"name":"Cabin","terms":""},"building/cathedral":{"name":"Cathedral Building","terms":""},"building/chapel":{"name":"Chapel Building","terms":""},"building/church":{"name":"Church Building","terms":""},"building/college":{"name":"College Building","terms":"university"},"building/commercial":{"name":"Commercial Building","terms":""},"building/construction":{"name":"Building Under Construction","terms":""},"building/detached":{"name":"Detached House","terms":"home,single,family,residence,dwelling"},"building/dormitory":{"name":"Dormitory","terms":""},"building/garage":{"name":"Garage","terms":""},"building/garages":{"name":"Garages","terms":""},"building/greenhouse":{"name":"Greenhouse","terms":""},"building/hospital":{"name":"Hospital Building","terms":""},"building/hotel":{"name":"Hotel Building","terms":""},"building/house":{"name":"House","terms":"home,family,residence,dwelling"},"building/hut":{"name":"Hut","terms":""},"building/industrial":{"name":"Industrial Building","terms":""},"building/kindergarten":{"name":"Preschool/Kindergarten Building","terms":"kindergarden,pre-school"},"building/public":{"name":"Public Building","terms":""},"building/residential":{"name":"Residential Building","terms":""},"building/retail":{"name":"Retail Building","terms":""},"building/roof":{"name":"Roof","terms":""},"building/school":{"name":"School Building","terms":"academy,elementary school,middle school,high school"},"building/semidetached_house":{"name":"Semi-Detached House","terms":"home,double,duplex,twin,family,residence,dwelling"},"building/shed":{"name":"Shed","terms":""},"building/stable":{"name":"Stable","terms":""},"building/static_caravan":{"name":"Static Mobile Home","terms":""},"building/terrace":{"name":"Row Houses","terms":"home,terrace,brownstone,family,residence,dwelling"},"building/university":{"name":"University Building","terms":"college"},"building/warehouse":{"name":"Warehouse","terms":""},"camp_site/camp_pitch":{"name":"Camp Pitch","terms":"tent,rv"},"club":{"name":"Club","terms":"social"},"craft":{"name":"Craft","terms":""},"craft/jeweler":{"name":"Jeweler","terms":""},"craft/locksmith":{"name":"Locksmith","terms":""},"craft/optician":{"name":"Optician","terms":""},"craft/tailor":{"name":"Tailor","terms":"clothes,suit"},"craft/basket_maker":{"name":"Basket Maker","terms":""},"craft/beekeeper":{"name":"Beekeeper","terms":""},"craft/blacksmith":{"name":"Blacksmith","terms":""},"craft/boatbuilder":{"name":"Boat Builder","terms":""},"craft/bookbinder":{"name":"Bookbinder","terms":"book repair"},"craft/brewery":{"name":"Brewery","terms":"alcohol,beer,beverage,bier,booze,cider"},"craft/carpenter":{"name":"Carpenter","terms":"woodworker"},"craft/carpet_layer":{"name":"Carpet Layer","terms":""},"craft/caterer":{"name":"Caterer","terms":""},"craft/clockmaker":{"name":"Clockmaker","terms":""},"craft/confectionery":{"name":"Confectionery","terms":"sweets,candy"},"craft/distillery":{"name":"Distillery","terms":"alcohol,beverage,bourbon,booze,brandy,gin,hooch,liquor,mezcal,moonshine,rum,scotch,spirits,still,tequila,vodka,whiskey,whisky"},"craft/dressmaker":{"name":"Dressmaker","terms":"seamstress"},"craft/electrician":{"name":"Electrician","terms":"power,wire"},"craft/electronics_repair":{"name":"Electronics Repair Shop","terms":""},"craft/gardener":{"name":"Gardener","terms":"landscaper,grounds keeper"},"craft/glaziery":{"name":"Glaziery","terms":"glass,stained-glass,window"},"craft/handicraft":{"name":"Handicraft","terms":""},"craft/hvac":{"name":"HVAC","terms":"heat*,vent*,air conditioning"},"craft/insulator":{"name":"Insulator","terms":""},"craft/key_cutter":{"name":"Key Cutter","terms":""},"craft/metal_construction":{"name":"Metal Construction","terms":""},"craft/painter":{"name":"Painter","terms":""},"craft/photographer":{"name":"Photographer","terms":""},"craft/photographic_laboratory":{"name":"Photographic Laboratory","terms":"film"},"craft/plasterer":{"name":"Plasterer","terms":""},"craft/plumber":{"name":"Plumber","terms":"pipe"},"craft/pottery":{"name":"Pottery","terms":"ceramic"},"craft/rigger":{"name":"Rigger","terms":""},"craft/roofer":{"name":"Roofer","terms":""},"craft/saddler":{"name":"Saddler","terms":""},"craft/sailmaker":{"name":"Sailmaker","terms":""},"craft/sawmill":{"name":"Sawmill","terms":"lumber"},"craft/scaffolder":{"name":"Scaffolder","terms":""},"craft/sculpter":{"name":"Sculpter","terms":""},"craft/shoemaker":{"name":"Shoemaker","terms":"cobbler"},"craft/stonemason":{"name":"Stonemason","terms":"masonry"},"craft/sweep":{"name":"Chimney Sweep","terms":""},"craft/tiler":{"name":"Tiler","terms":""},"craft/tinsmith":{"name":"Tinsmith","terms":""},"craft/upholsterer":{"name":"Upholsterer","terms":""},"craft/watchmaker":{"name":"Watchmaker","terms":""},"craft/window_construction":{"name":"Window Construction","terms":"glass"},"craft/winery":{"name":"Winery","terms":""},"embankment":{"name":"Embankment","terms":""},"emergency/designated":{"name":"Emergency Access Designated","terms":""},"emergency/destination":{"name":"Emergency Access Destination","terms":""},"emergency/no":{"name":"Emergency Access No","terms":""},"emergency/official":{"name":"Emergency Access Official","terms":""},"emergency/private":{"name":"Emergency Access Private","terms":""},"emergency/yes":{"name":"Emergency Access Yes","terms":""},"emergency/ambulance_station":{"name":"Ambulance Station","terms":"EMS,EMT,rescue"},"emergency/defibrillator":{"name":"Defibrillator","terms":"AED"},"emergency/fire_hydrant":{"name":"Fire Hydrant","terms":"fire plug"},"emergency/phone":{"name":"Emergency Phone","terms":""},"entrance":{"name":"Entrance/Exit","terms":""},"footway/crossing":{"name":"Street Crossing","terms":""},"footway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"footway/sidewalk":{"name":"Sidewalk","terms":""},"ford":{"name":"Ford","terms":""},"golf/bunker":{"name":"Sand Trap","terms":"hazard,bunker"},"golf/fairway":{"name":"Fairway","terms":""},"golf/green":{"name":"Putting Green","terms":""},"golf/hole":{"name":"Golf Hole","terms":""},"golf/lateral_water_hazard_area":{"name":"Lateral Water Hazard","terms":""},"golf/lateral_water_hazard_line":{"name":"Lateral Water Hazard","terms":""},"golf/rough":{"name":"Rough","terms":""},"golf/tee":{"name":"Tee Box","terms":"teeing ground"},"golf/water_hazard_area":{"name":"Water Hazard","terms":""},"golf/water_hazard_line":{"name":"Water Hazard","terms":""},"healthcare/blood_donation":{"name":"Blood Donor Center","terms":"blood bank,blood donation,blood transfusion,apheresis,plasmapheresis,plateletpheresis,stem cell donation"},"highway/bridleway":{"name":"Bridle Path","terms":"bridleway,equestrian,horse"},"highway/bus_stop":{"name":"Bus Stop","terms":""},"highway/corridor":{"name":"Indoor Corridor","terms":"gallery,hall,hallway,indoor,passage,passageway"},"highway/crossing":{"name":"Street Crossing","terms":""},"highway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"highway/cycleway":{"name":"Cycle Path","terms":"bike"},"highway/elevator":{"name":"Elevator","terms":"lift"},"highway/footway":{"name":"Foot Path","terms":"hike,hiking,trackway,trail,walk"},"highway/give_way":{"name":"Yield Sign","terms":"give way,yield,sign"},"highway/living_street":{"name":"Living Street","terms":""},"highway/mini_roundabout":{"name":"Mini-Roundabout","terms":""},"highway/motorway_junction":{"name":"Motorway Junction / Exit","terms":""},"highway/motorway_link":{"name":"Motorway Link","terms":"ramp,on ramp,off ramp"},"highway/motorway":{"name":"Motorway","terms":"autobahn,expressway,freeway,highway,interstate,parkway,thruway,turnpike"},"highway/path":{"name":"Path","terms":"hike,hiking,trackway,trail,walk"},"highway/pedestrian":{"name":"Pedestrian Street","terms":""},"highway/primary_link":{"name":"Primary Link","terms":"ramp,on ramp,off ramp"},"highway/primary":{"name":"Primary Road","terms":""},"highway/raceway":{"name":"Racetrack (Motorsport)","terms":"auto*,formula one,kart,motocross,nascar,race*,track"},"highway/residential":{"name":"Residential Road","terms":""},"highway/rest_area":{"name":"Rest Area","terms":"rest stop"},"highway/road":{"name":"Unknown Road","terms":""},"highway/secondary_link":{"name":"Secondary Link","terms":"ramp,on ramp,off ramp"},"highway/secondary":{"name":"Secondary Road","terms":""},"highway/service":{"name":"Service Road","terms":""},"highway/service/alley":{"name":"Alley","terms":""},"highway/service/drive-through":{"name":"Drive-Through","terms":""},"highway/service/driveway":{"name":"Driveway","terms":""},"highway/service/emergency_access":{"name":"Emergency Access","terms":""},"highway/service/parking_aisle":{"name":"Parking Aisle","terms":""},"highway/services":{"name":"Service Area","terms":"services,travel plaza,service station"},"highway/speed_camera":{"name":"Speed Camera","terms":""},"highway/steps":{"name":"Steps","terms":"stairs,staircase"},"highway/stop":{"name":"Stop Sign","terms":"stop,halt,sign"},"highway/street_lamp":{"name":"Street Lamp","terms":"streetlight,street light,lamp,light,gaslight"},"highway/tertiary_link":{"name":"Tertiary Link","terms":"ramp,on ramp,off ramp"},"highway/tertiary":{"name":"Tertiary Road","terms":""},"highway/track":{"name":"Unmaintained Track Road","terms":"woods road,forest road,logging road,fire road,farm road,agricultural road,ranch road,carriage road,primitive,unmaintained,rut,offroad,4wd,4x4,four wheel drive,atv,quad,jeep,double track,two track"},"highway/traffic_mirror":{"name":"Traffic Mirror","terms":"blind spot,convex,corner,curved,roadside,round,safety,sphere,visibility"},"highway/traffic_signals":{"name":"Traffic Signals","terms":"light,stoplight,traffic light"},"highway/trunk_link":{"name":"Trunk Link","terms":"ramp,on ramp,off ramp"},"highway/trunk":{"name":"Trunk Road","terms":""},"highway/turning_circle":{"name":"Turning Circle","terms":"cul-de-sac"},"highway/turning_loop":{"name":"Turning Loop (Island)","terms":"cul-de-sac"},"highway/unclassified":{"name":"Minor/Unclassified Road","terms":""},"historic":{"name":"Historic Site","terms":""},"historic/archaeological_site":{"name":"Archaeological Site","terms":""},"historic/boundary_stone":{"name":"Boundary Stone","terms":""},"historic/castle":{"name":"Castle","terms":""},"historic/memorial":{"name":"Memorial","terms":""},"historic/monument":{"name":"Monument","terms":""},"historic/ruins":{"name":"Ruins","terms":""},"historic/tomb":{"name":"Tomb","terms":""},"historic/wayside_cross":{"name":"Wayside Cross","terms":""},"historic/wayside_shrine":{"name":"Wayside Shrine","terms":""},"junction":{"name":"Junction","terms":""},"landuse":{"name":"Land Use","terms":""},"landuse/farm":{"name":"Farmland","terms":""},"landuse/allotments":{"name":"Community Garden","terms":"allotment,garden"},"landuse/aquaculture":{"name":"Aquaculture","terms":"fish farm,crustacean,algae,aquafarming,shrimp farm,oyster farm,mariculture,algaculture"},"landuse/basin":{"name":"Basin","terms":""},"landuse/cemetery":{"name":"Cemetery","terms":""},"landuse/churchyard":{"name":"Churchyard","terms":""},"landuse/commercial":{"name":"Commercial Area","terms":""},"landuse/construction":{"name":"Construction","terms":""},"landuse/farmland":{"name":"Farmland","terms":"crop,grow,plant"},"landuse/farmyard":{"name":"Farmyard","terms":"crop,grow,plant"},"landuse/forest":{"name":"Forest","terms":"tree"},"landuse/garages":{"name":"Garages","terms":""},"landuse/grass":{"name":"Grass","terms":""},"landuse/harbour":{"name":"Harbor","terms":"boat"},"landuse/industrial":{"name":"Industrial Area","terms":""},"landuse/landfill":{"name":"Landfill","terms":"dump"},"landuse/meadow":{"name":"Meadow","terms":""},"landuse/military":{"name":"Military Area","terms":""},"landuse/military/airfield":{"name":"Military Airfield","terms":"air force,army,base,bomb,fight,force,guard,heli*,jet,marine,navy,plane,troop,war"},"landuse/military/barracks":{"name":"Barracks","terms":"air force,army,base,fight,force,guard,marine,navy,troop,war"},"landuse/military/bunker":{"name":"Military Bunker","terms":"air force,army,base,fight,force,guard,marine,navy,troop,war"},"landuse/military/checkpoint":{"name":"Checkpoint","terms":"air force,army,base,force,guard,marine,navy,troop,war"},"landuse/military/danger_area":{"name":"Danger Area","terms":"air force,army,base,blast,bomb,explo*,force,guard,mine,marine,navy,troop,war"},"landuse/military/naval_base":{"name":"Naval Base","terms":"base,fight,force,guard,marine,navy,ship,sub,troop,war"},"landuse/military/nuclear_explosion_site":{"name":"Nuclear Explosion Site","terms":"atom,blast,bomb,detonat*,nuke,site,test"},"landuse/military/obstacle_course":{"name":"Obstacle Course","terms":"army,base,force,guard,marine,navy,troop,war"},"landuse/military/office":{"name":"Military Office","terms":"air force,army,base,enlist,fight,force,guard,marine,navy,recruit,troop,war"},"landuse/military/range":{"name":"Military Range","terms":"air force,army,base,fight,fire,force,guard,gun,marine,navy,rifle,shoot*,snip*,train,troop,war"},"landuse/military/training_area":{"name":"Training Area","terms":"air force,army,base,fight,fire,force,guard,gun,marine,navy,rifle,shoot*,snip*,train,troop,war"},"landuse/orchard":{"name":"Orchard","terms":"fruit"},"landuse/plant_nursery":{"name":"Plant Nursery","terms":"flower,garden,grow,vivero"},"landuse/quarry":{"name":"Quarry","terms":""},"landuse/railway":{"name":"Railway Corridor","terms":"rail,train,track"},"landuse/recreation_ground":{"name":"Recreation Ground","terms":"playing fields"},"landuse/residential":{"name":"Residential Area","terms":""},"landuse/retail":{"name":"Retail Area","terms":""},"landuse/vineyard":{"name":"Vineyard","terms":"grape,wine"},"leisure":{"name":"Leisure","terms":""},"leisure/adult_gaming_centre":{"name":"Adult Gaming Center","terms":"gambling,slot machine"},"leisure/bird_hide":{"name":"Bird Hide","terms":"machan,ornithology"},"leisure/bowling_alley":{"name":"Bowling Alley","terms":""},"leisure/common":{"name":"Common","terms":"open space"},"leisure/dance":{"name":"Dance Hall","terms":"ballroom,jive,swing,tango,waltz"},"leisure/dog_park":{"name":"Dog Park","terms":""},"leisure/firepit":{"name":"Firepit","terms":"fireplace,campfire"},"leisure/fitness_centre":{"name":"Gym / Fitness Center","terms":"health,gym,leisure,studio"},"leisure/fitness_centre/yoga":{"name":"Yoga Studio","terms":"studio"},"leisure/fitness_station":{"name":"Outdoor Fitness Station","terms":"fitness,gym"},"leisure/garden":{"name":"Garden","terms":""},"leisure/golf_course":{"name":"Golf Course","terms":"links"},"leisure/horse_riding":{"name":"Horseback Riding Facility","terms":"equestrian,stable"},"leisure/ice_rink":{"name":"Ice Rink","terms":"hockey,skating,curling"},"leisure/marina":{"name":"Marina","terms":"boat"},"leisure/miniature_golf":{"name":"Miniature Golf","terms":"crazy golf,mini golf,putt-putt"},"leisure/nature_reserve":{"name":"Nature Reserve","terms":"protected,wildlife"},"leisure/park":{"name":"Park","terms":"esplanade,estate,forest,garden,grass,green,grounds,lawn,lot,meadow,parkland,place,playground,plaza,pleasure garden,recreation area,square,tract,village green,woodland"},"leisure/picnic_table":{"name":"Picnic Table","terms":"bench"},"leisure/pitch":{"name":"Sport Pitch","terms":"field"},"leisure/pitch/american_football":{"name":"American Football Field","terms":""},"leisure/pitch/baseball":{"name":"Baseball Diamond","terms":""},"leisure/pitch/basketball":{"name":"Basketball Court","terms":""},"leisure/pitch/beachvolleyball":{"name":"Beach Volleyball Court","terms":"volleyball"},"leisure/pitch/bowls":{"name":"Bowling Green","terms":""},"leisure/pitch/cricket":{"name":"Cricket Field","terms":""},"leisure/pitch/equestrian":{"name":"Riding Arena","terms":"dressage,equestrian,horse,horseback,riding"},"leisure/pitch/rugby_league":{"name":"Rugby League Field","terms":""},"leisure/pitch/rugby_union":{"name":"Rugby Union Field","terms":""},"leisure/pitch/skateboard":{"name":"Skate Park","terms":""},"leisure/pitch/soccer":{"name":"Soccer Field","terms":"football"},"leisure/pitch/table_tennis":{"name":"Ping Pong Table","terms":"table tennis,ping pong"},"leisure/pitch/tennis":{"name":"Tennis Court","terms":""},"leisure/pitch/volleyball":{"name":"Volleyball Court","terms":""},"leisure/playground":{"name":"Playground","terms":"jungle gym,play area"},"leisure/resort":{"name":"Resort","terms":""},"leisure/running_track":{"name":"Racetrack (Running)","terms":"race*,running,sprint,track"},"leisure/slipway":{"name":"Slipway","terms":"boat launch,boat ramp"},"leisure/sports_centre":{"name":"Sports Center / Complex","terms":""},"leisure/sports_centre/swimming":{"name":"Swimming Pool Facility","terms":"dive,water"},"leisure/stadium":{"name":"Stadium","terms":""},"leisure/swimming_pool":{"name":"Swimming Pool","terms":"dive,water"},"leisure/track":{"name":"Racetrack (Non-Motorsport)","terms":"cycle,dog,greyhound,horse,race*,track"},"leisure/water_park":{"name":"Water Park","terms":"swim,pool,dive"},"line":{"name":"Line","terms":""},"man_made":{"name":"Man Made","terms":""},"man_made/embankment":{"name":"Embankment","terms":""},"man_made/adit":{"name":"Adit","terms":"entrance,underground,mine,cave"},"man_made/breakwater":{"name":"Breakwater","terms":""},"man_made/bridge":{"name":"Bridge","terms":""},"man_made/chimney":{"name":"Chimney","terms":""},"man_made/cutline":{"name":"Cut line","terms":""},"man_made/flagpole":{"name":"Flagpole","terms":""},"man_made/gasometer":{"name":"Gasometer","terms":"gas holder"},"man_made/groyne":{"name":"Groyne","terms":""},"man_made/lighthouse":{"name":"Lighthouse","terms":""},"man_made/mast":{"name":"Mast","terms":"antenna,broadcast tower,cell phone tower,cell tower,communication mast,communication tower,guyed tower,mobile phone tower,radio mast,radio tower,television tower,transmission mast,transmission tower,tv tower"},"man_made/observation":{"name":"Observation Tower","terms":"lookout tower,fire tower"},"man_made/petroleum_well":{"name":"Oil Well","terms":"drilling rig,oil derrick,oil drill,oil horse,oil rig,oil pump,petroleum well,pumpjack"},"man_made/pier":{"name":"Pier","terms":"dock"},"man_made/pipeline":{"name":"Pipeline","terms":""},"man_made/pumping_station":{"name":"Pumping Station","terms":""},"man_made/silo":{"name":"Silo","terms":"grain,corn,wheat"},"man_made/storage_tank":{"name":"Storage Tank","terms":"water,oil,gas,petrol"},"man_made/surveillance_camera":{"name":"Surveillance Camera","terms":"anpr,alpr,camera,car plate recognition,cctv,guard,license plate recognition,monitoring,number plate recognition,security,video,webcam"},"man_made/surveillance":{"name":"Surveillance","terms":"anpr,alpr,camera,car plate recognition,cctv,guard,license plate recognition,monitoring,number plate recognition,security,video,webcam"},"man_made/survey_point":{"name":"Survey Point","terms":""},"man_made/tower":{"name":"Tower","terms":""},"man_made/wastewater_plant":{"name":"Wastewater Plant","terms":"sewage*,water treatment plant,reclamation plant"},"man_made/water_tower":{"name":"Water Tower","terms":""},"man_made/water_well":{"name":"Water Well","terms":""},"man_made/water_works":{"name":"Water Works","terms":""},"man_made/works":{"name":"Factory","terms":"assembly,build,brewery,car,plant,plastic,processing,manufacture,refinery"},"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/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/jewish":{"icon":"religious-jewish","fields":["denomination","building_area","address","service_times"],"geometry":["point","area"],"terms":["jewish"],"tags":{"amenity":"place_of_worship","religion":"jewish"},"reference":{"key":"amenity","value":"place_of_worship"},"name":"Synagogue"},"amenity/place_of_worship/muslim":{"icon":"religious-muslim","fields":["denomination","building_area","address","service_times"],"geometry":["point","area"],"terms":["muslim"],"tags":{"amenity":"place_of_worship","religion":"muslim"},"reference":{"key":"amenity","value":"place_of_worship"},"name":"Mosque"},"amenity/planetarium":{"icon":"museum","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["museum","astronomy","observatory"],"tags":{"amenity":"planetarium"},"name":"Planetarium"},"amenity/police":{"icon":"police","fields":["operator","address","building_area"],"geometry":["point","area"],"terms":["badge","constable","constabulary","cop","detective","fed","law","enforcement","officer","patrol"],"tags":{"amenity":"police"},"name":"Police"},"amenity/post_box":{"icon":"post","fields":["operator","collection_times","drive_through","ref"],"geometry":["point","vertex"],"tags":{"amenity":"post_box"},"terms":["letter","post"],"name":"Mailbox"},"amenity/post_office":{"icon":"post","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["letter","mail"],"tags":{"amenity":"post_office"},"name":"Post Office"},"amenity/prison":{"icon":"prison","fields":["operator","address"],"geometry":["point","area"],"terms":["cell","jail"],"tags":{"amenity":"prison"},"name":"Prison Grounds"},"amenity/pub":{"icon":"beer","fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"geometry":["point","area"],"tags":{"amenity":"pub"},"terms":["alcohol","drink","dive","beer","bier","booze"],"name":"Pub"},"amenity/public_bath":{"icon":"water","fields":["bath/type","bath/open_air","bath/sand_bath","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"amenity":"public_bath"},"terms":["onsen","foot bath","hot springs"],"name":"Public Bath"},"amenity/public_bookcase":{"icon":"library","fields":["name","operator","capacity","website"],"geometry":["point","area"],"terms":["library","bookcrossing"],"tags":{"amenity":"public_bookcase"},"name":"Public Bookcase"},"amenity/ranger_station":{"fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["visitor center","visitor centre","permit center","permit centre","backcountry office","warden office","warden center"],"tags":{"amenity":"ranger_station"},"name":"Ranger Station"},"amenity/recycling_centre":{"icon":"waste-basket","fields":["operator","address","opening_hours","recycling_accepts"],"geometry":["point","area"],"terms":["bottle","can","dump","glass","garbage","rubbish","scrap","trash"],"tags":{"amenity":"recycling","recycling_type":"centre"},"name":"Recycling Center"},"amenity/recycling":{"icon":"recycling","fields":["recycling_type","recycling_accepts","collection_times"],"geometry":["point","area"],"terms":["bin","can","bottle","glass","garbage","rubbish","scrap","trash"],"tags":{"amenity":"recycling"},"name":"Recycling"},"amenity/restaurant":{"icon":"restaurant","fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"geometry":["point","area"],"terms":["bar","breakfast","cafe","café","canteen","coffee","dine","dining","dinner","drive-in","eat","grill","lunch","table"],"tags":{"amenity":"restaurant"},"name":"Restaurant"},"amenity/sanitary_dump_station":{"icon":"poi-storage-tank","fields":["operator","access_toilets","fee","water_point"],"geometry":["point","vertex","area"],"terms":["Motor Home","Camper","Sanitary","Dump Station","Elsan","CDP","CTDP","Chemical Toilet"],"tags":{"amenity":"sanitary_dump_station"},"name":"RV Toilet Disposal"},"amenity/school":{"icon":"school","fields":["operator","address"],"geometry":["point","area"],"terms":["academy","elementary school","middle school","high school"],"tags":{"amenity":"school"},"name":"School Grounds"},"amenity/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/water_point":{"icon":"drinking-water","geometry":["area","vertex","point"],"tags":{"amenity":"water_point"},"name":"RV Drinking Water"},"amenity/watering_place":{"icon":"drinking-water","geometry":["area","vertex","point"],"tags":{"amenity":"watering_place"},"name":"Animal Watering Place"},"area":{"name":"Area","tags":{"area":"yes"},"geometry":["area"],"matchScore":0.1},"area/highway":{"fields":["area/highway"],"geometry":["area"],"tags":{"area:highway":"*"},"name":"Road Surface"},"barrier":{"icon":"roadblock","geometry":["point","vertex","line","area"],"tags":{"barrier":"*"},"fields":["barrier"],"name":"Barrier","matchScore":0.4},"barrier/entrance":{"icon":"entrance-alt1","geometry":["vertex"],"tags":{"barrier":"entrance"},"name":"Entrance","searchable":false},"barrier/block":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex"],"tags":{"barrier":"block"},"name":"Block"},"barrier/bollard":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex","line"],"tags":{"barrier":"bollard"},"name":"Bollard"},"barrier/border_control":{"icon":"roadblock","fields":["access","building_area"],"geometry":["vertex","area"],"tags":{"barrier":"border_control"},"name":"Border Control"},"barrier/cattle_grid":{"icon":"barrier","geometry":["vertex"],"tags":{"barrier":"cattle_grid"},"name":"Cattle Grid"},"barrier/city_wall":{"icon":"barrier","fields":["height"],"geometry":["line","area"],"tags":{"barrier":"city_wall"},"name":"City Wall"},"barrier/cycle_barrier":{"icon":"roadblock","fields":["access"],"geometry":["vertex"],"tags":{"barrier":"cycle_barrier"},"name":"Cycle Barrier"},"barrier/ditch":{"icon":"roadblock","geometry":["line","area"],"tags":{"barrier":"ditch"},"name":"Trench","matchScore":0.25},"barrier/fence":{"icon":"fence","fields":["fence_type","height"],"geometry":["line"],"tags":{"barrier":"fence"},"name":"Fence","matchScore":0.25},"barrier/gate":{"icon":"barrier","fields":["access"],"geometry":["point","vertex","line"],"tags":{"barrier":"gate"},"name":"Gate"},"barrier/hedge":{"fields":["height"],"geometry":["line","area"],"tags":{"barrier":"hedge"},"name":"Hedge","matchScore":0.25},"barrier/kissing_gate":{"icon":"barrier","fields":["access"],"geometry":["vertex"],"tags":{"barrier":"kissing_gate"},"name":"Kissing Gate"},"barrier/lift_gate":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex"],"tags":{"barrier":"lift_gate"},"name":"Lift Gate"},"barrier/retaining_wall":{"geometry":["line","area"],"tags":{"barrier":"retaining_wall"},"name":"Retaining Wall"},"barrier/stile":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex"],"tags":{"barrier":"stile"},"name":"Stile"},"barrier/toll_booth":{"icon":"roadblock","fields":["access","building_area"],"geometry":["vertex","area"],"tags":{"barrier":"toll_booth"},"name":"Toll Booth"},"barrier/wall":{"icon":"barrier","fields":["wall","height"],"geometry":["line","area"],"tags":{"barrier":"wall"},"name":"Wall","matchScore":0.25},"boundary/administrative":{"name":"Administrative Boundary","geometry":["line"],"tags":{"boundary":"administrative"},"fields":["admin_level"]},"building":{"icon":"home","fields":["building","levels","address"],"geometry":["point","area"],"tags":{"building":"*"},"matchScore":0.6,"terms":[],"name":"Building"},"building/bunker":{"fields":["address","levels"],"geometry":["area"],"tags":{"building":"bunker"},"matchScore":0.5,"name":"Bunker","searchable":false},"building/entrance":{"icon":"entrance-alt1","geometry":["vertex"],"tags":{"building":"entrance"},"name":"Entrance/Exit","searchable":false},"building/train_station":{"icon":"building","fields":["address","levels"],"geometry":["point","vertex","area"],"tags":{"building":"train_station"},"matchScore":0.5,"name":"Train Station","searchable":false},"building/apartments":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"apartments"},"matchScore":0.5,"name":"Apartments"},"building/barn":{"icon":"farm","fields":["address","levels"],"geometry":["area"],"tags":{"building":"barn"},"matchScore":0.5,"name":"Barn"},"building/cabin":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"cabin"},"matchScore":0.5,"name":"Cabin"},"building/cathedral":{"icon":"place-of-worship","fields":["address","levels"],"geometry":["area"],"tags":{"building":"cathedral"},"matchScore":0.5,"name":"Cathedral Building"},"building/chapel":{"icon":"place-of-worship","fields":["address","levels"],"geometry":["area"],"tags":{"building":"chapel"},"matchScore":0.5,"name":"Chapel Building"},"building/church":{"icon":"place-of-worship","fields":["address","levels"],"geometry":["area"],"tags":{"building":"church"},"matchScore":0.5,"name":"Church Building"},"building/college":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["university"],"tags":{"building":"college"},"matchScore":0.5,"name":"College Building"},"building/commercial":{"icon":"commercial","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"commercial"},"matchScore":0.5,"name":"Commercial Building"},"building/construction":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"construction"},"matchScore":0.5,"name":"Building Under Construction"},"building/detached":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"detached"},"terms":["home","single","family","residence","dwelling"],"matchScore":0.5,"name":"Detached House"},"building/dormitory":{"icon":"building","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"dormitory"},"matchScore":0.5,"name":"Dormitory"},"building/garage":{"icon":"warehouse","fields":["capacity"],"geometry":["area"],"tags":{"building":"garage"},"matchScore":0.5,"name":"Garage"},"building/garages":{"icon":"warehouse","fields":["capacity"],"geometry":["area"],"tags":{"building":"garages"},"matchScore":0.5,"name":"Garages"},"building/greenhouse":{"icon":"garden-center","fields":["address","levels"],"geometry":["area"],"tags":{"building":"greenhouse"},"matchScore":0.5,"name":"Greenhouse"},"building/hospital":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"hospital"},"matchScore":0.5,"name":"Hospital Building"},"building/hotel":{"icon":"building","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"hotel"},"matchScore":0.5,"name":"Hotel Building"},"building/house":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"house"},"terms":["home","family","residence","dwelling"],"matchScore":0.5,"name":"House"},"building/hut":{"geometry":["area"],"tags":{"building":"hut"},"matchScore":0.5,"name":"Hut"},"building/industrial":{"icon":"industry","fields":["address","levels"],"geometry":["area"],"tags":{"building":"industrial"},"matchScore":0.5,"name":"Industrial Building"},"building/kindergarten":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["kindergarden","pre-school"],"tags":{"building":"kindergarten"},"matchScore":0.5,"name":"Preschool/Kindergarten Building"},"building/public":{"icon":"building","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"public"},"matchScore":0.5,"name":"Public Building"},"building/residential":{"icon":"residential-community","fields":["address","levels"],"geometry":["area"],"tags":{"building":"residential"},"matchScore":0.5,"name":"Residential Building"},"building/retail":{"icon":"commercial","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"retail"},"matchScore":0.5,"name":"Retail Building"},"building/roof":{"icon":"shelter","fields":["address"],"geometry":["area"],"tags":{"building":"roof"},"matchScore":0.5,"name":"Roof"},"building/school":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["academy","elementary school","middle school","high school"],"tags":{"building":"school"},"matchScore":0.5,"name":"School Building"},"building/semidetached_house":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"semidetached_house"},"terms":["home","double","duplex","twin","family","residence","dwelling"],"matchScore":0.5,"name":"Semi-Detached House"},"building/shed":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"shed"},"matchScore":0.5,"name":"Shed"},"building/stable":{"icon":"horse-riding","fields":["address","levels"],"geometry":["area"],"tags":{"building":"stable"},"matchScore":0.5,"name":"Stable"},"building/static_caravan":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"static_caravan"},"matchScore":0.5,"name":"Static Mobile Home"},"building/terrace":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"terrace"},"terms":["home","terrace","brownstone","family","residence","dwelling"],"matchScore":0.5,"name":"Row Houses"},"building/university":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["college"],"tags":{"building":"university"},"matchScore":0.5,"name":"University Building"},"building/warehouse":{"icon":"warehouse","fields":["address","levels"],"geometry":["area"],"tags":{"building":"warehouse"},"matchScore":0.5,"name":"Warehouse"},"camp_site/camp_pitch":{"icon":"campsite","fields":["ref"],"geometry":["point","area"],"terms":["tent","rv"],"tags":{"camp_site":"camp_pitch"},"name":"Camp Pitch"},"club":{"icon":"heart","fields":["club","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"club":"*"},"terms":["social"],"name":"Club"},"craft":{"icon":"poi-tool","fields":["craft","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"*"},"terms":[],"name":"Craft"},"craft/jeweler":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"jeweler"},"reference":{"key":"shop","value":"jewelry"},"name":"Jeweler","searchable":false},"craft/locksmith":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"locksmith"},"reference":{"key":"shop","value":"locksmith"},"name":"Locksmith","searchable":false},"craft/optician":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"optician"},"reference":{"key":"shop","value":"optician"},"name":"Optician","searchable":false},"craft/tailor":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["clothes","suit"],"tags":{"craft":"tailor"},"reference":{"key":"shop","value":"tailor"},"name":"Tailor","searchable":false},"craft/basket_maker":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"basket_maker"},"name":"Basket Maker"},"craft/beekeeper":{"icon":"farm","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"beekeeper"},"name":"Beekeeper"},"craft/blacksmith":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"blacksmith"},"name":"Blacksmith"},"craft/boatbuilder":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"boatbuilder"},"name":"Boat Builder"},"craft/bookbinder":{"icon":"library","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["book repair"],"tags":{"craft":"bookbinder"},"name":"Bookbinder"},"craft/brewery":{"icon":"poi-storage-tank","fields":["operator","address","building_area","opening_hours","product"],"geometry":["point","area"],"terms":["alcohol","beer","beverage","bier","booze","cider"],"tags":{"craft":"brewery"},"name":"Brewery"},"craft/carpenter":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["woodworker"],"tags":{"craft":"carpenter"},"name":"Carpenter"},"craft/carpet_layer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"carpet_layer"},"name":"Carpet Layer"},"craft/caterer":{"icon":"restaurant","fields":["cuisine","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"caterer"},"name":"Caterer"},"craft/clockmaker":{"icon":"poi-clock","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"clockmaker"},"name":"Clockmaker"},"craft/confectionery":{"icon":"bakery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sweets","candy"],"tags":{"craft":"confectionery"},"name":"Confectionery"},"craft/distillery":{"icon":"poi-storage-tank","fields":["operator","address","building_area","opening_hours","product"],"geometry":["point","area"],"terms":["alcohol","beverage","bourbon","booze","brandy","gin","hooch","liquor","mezcal","moonshine","rum","scotch","spirits","still","tequila","vodka","whiskey","whisky"],"tags":{"craft":"distillery"},"name":"Distillery"},"craft/dressmaker":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["seamstress"],"tags":{"craft":"dressmaker"},"name":"Dressmaker"},"craft/electrician":{"icon":"poi-power","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["power","wire"],"tags":{"craft":"electrician"},"name":"Electrician"},"craft/electronics_repair":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"electronics_repair"},"name":"Electronics Repair Shop"},"craft/gardener":{"icon":"garden","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["landscaper","grounds keeper"],"tags":{"craft":"gardener"},"name":"Gardener"},"craft/glaziery":{"icon":"fire-station","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["glass","stained-glass","window"],"tags":{"craft":"glaziery"},"name":"Glaziery"},"craft/handicraft":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"handicraft"},"name":"Handicraft"},"craft/hvac":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["heat*","vent*","air conditioning"],"tags":{"craft":"hvac"},"name":"HVAC"},"craft/insulator":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"insulation"},"name":"Insulator"},"craft/key_cutter":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"key_cutter"},"name":"Key Cutter"},"craft/metal_construction":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"metal_construction"},"name":"Metal Construction"},"craft/painter":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"painter"},"name":"Painter"},"craft/photographer":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"photographer"},"name":"Photographer"},"craft/photographic_laboratory":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["film"],"tags":{"craft":"photographic_laboratory"},"name":"Photographic Laboratory"},"craft/plasterer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"plasterer"},"name":"Plasterer"},"craft/plumber":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["pipe"],"tags":{"craft":"plumber"},"name":"Plumber"},"craft/pottery":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ceramic"],"tags":{"craft":"pottery"},"name":"Pottery"},"craft/rigger":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"rigger"},"name":"Rigger"},"craft/roofer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"roofer"},"name":"Roofer"},"craft/saddler":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"saddler"},"name":"Saddler"},"craft/sailmaker":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sailmaker"},"name":"Sailmaker"},"craft/sawmill":{"icon":"logging","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["lumber"],"tags":{"craft":"sawmill"},"name":"Sawmill"},"craft/scaffolder":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"scaffolder"},"name":"Scaffolder"},"craft/sculpter":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sculpter"},"name":"Sculpter"},"craft/shoemaker":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["cobbler"],"tags":{"craft":"shoemaker"},"name":"Shoemaker"},"craft/stonemason":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["masonry"],"tags":{"craft":"stonemason"},"name":"Stonemason"},"craft/sweep":{"icon":"poi-chimney","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sweep"},"name":"Chimney Sweep"},"craft/tiler":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"tiler"},"name":"Tiler"},"craft/tinsmith":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"tinsmith"},"name":"Tinsmith"},"craft/upholsterer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"upholsterer"},"name":"Upholsterer"},"craft/watchmaker":{"icon":"poi-clock","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"watchmaker"},"name":"Watchmaker"},"craft/window_construction":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["glass"],"tags":{"craft":"window_construction"},"name":"Window Construction"},"craft/winery":{"icon":"alcohol-shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"winery"},"name":"Winery"},"embankment":{"geometry":["line"],"tags":{"embankment":"yes"},"name":"Embankment","matchScore":0.2},"emergency/designated":{"fields":[],"geometry":["line"],"tags":{"emergency":"designated"},"terms":[],"name":"Emergency Access Designated","searchable":false,"matchScore":0.01},"emergency/destination":{"fields":[],"geometry":["line"],"tags":{"emergency":"destination"},"terms":[],"name":"Emergency Access Destination","searchable":false,"matchScore":0.01},"emergency/no":{"fields":[],"geometry":["line"],"tags":{"emergency":"no"},"terms":[],"name":"Emergency Access No","searchable":false,"matchScore":0.01},"emergency/official":{"fields":[],"geometry":["line"],"tags":{"emergency":"official"},"terms":[],"name":"Emergency Access Official","searchable":false,"matchScore":0.01},"emergency/private":{"fields":[],"geometry":["line"],"tags":{"emergency":"private"},"terms":[],"name":"Emergency Access Private","searchable":false,"matchScore":0.01},"emergency/yes":{"fields":[],"geometry":["line"],"tags":{"emergency":"yes"},"terms":[],"name":"Emergency Access Yes","searchable":false,"matchScore":0.01},"emergency/ambulance_station":{"icon":"hospital","fields":["operator","building_area","address"],"geometry":["point","area"],"terms":["EMS","EMT","rescue"],"tags":{"emergency":"ambulance_station"},"name":"Ambulance Station"},"emergency/defibrillator":{"icon":"defibrillator","fields":["access","opening_hours","indoor","phone"],"geometry":["point"],"terms":["AED"],"tags":{"emergency":"defibrillator"},"name":"Defibrillator"},"emergency/fire_hydrant":{"icon":"poi-fire-hydrant","fields":["fire_hydrant/type","fire_hydrant/position","ref","operator"],"geometry":["point","vertex"],"terms":["fire plug"],"tags":{"emergency":"fire_hydrant"},"name":"Fire Hydrant"},"emergency/phone":{"icon":"emergency-phone","fields":["operator"],"geometry":["point","vertex"],"tags":{"emergency":"phone"},"name":"Emergency Phone"},"entrance":{"icon":"entrance-alt1","geometry":["vertex"],"tags":{"entrance":"*"},"fields":["entrance","access_simple","address"],"name":"Entrance/Exit"},"footway/crossing":{"fields":["crossing","access","surface","kerb","tactile_paving"],"geometry":["line"],"tags":{"highway":"footway","footway":"crossing"},"reference":{"key":"footway","value":"crossing"},"terms":[],"name":"Street Crossing"},"footway/crosswalk":{"icon":"highway-footway","fields":["crossing","access","surface","kerb","tactile_paving"],"geometry":["line"],"tags":{"highway":"footway","footway":"crossing","crossing":"zebra"},"reference":{"key":"highway","value":"crossing"},"terms":["zebra crossing"],"name":"Pedestrian Crosswalk"},"footway/sidewalk":{"icon":"highway-footway","fields":["surface","lit","width","structure","access"],"geometry":["line"],"tags":{"highway":"footway","footway":"sidewalk"},"reference":{"key":"footway","value":"sidewalk"},"terms":[],"name":"Sidewalk"},"ford":{"geometry":["vertex"],"tags":{"ford":"yes"},"name":"Ford"},"golf/bunker":{"icon":"golf","geometry":["area"],"tags":{"golf":"bunker","natural":"sand"},"terms":["hazard","bunker"],"reference":{"key":"golf","value":"bunker"},"name":"Sand Trap"},"golf/fairway":{"icon":"golf","geometry":["area"],"tags":{"golf":"fairway","landuse":"grass"},"reference":{"key":"golf","value":"fairway"},"name":"Fairway"},"golf/green":{"icon":"golf","geometry":["area"],"tags":{"golf":"green","landuse":"grass","leisure":"pitch","sport":"golf"},"reference":{"key":"golf","value":"green"},"name":"Putting Green"},"golf/hole":{"icon":"golf","fields":["golf_hole","par","handicap"],"geometry":["line"],"tags":{"golf":"hole"},"name":"Golf Hole"},"golf/lateral_water_hazard_area":{"icon":"golf","geometry":["area"],"tags":{"golf":"lateral_water_hazard","natural":"water"},"reference":{"key":"golf","value":"lateral_water_hazard"},"name":"Lateral Water Hazard"},"golf/lateral_water_hazard_line":{"icon":"golf","geometry":["line"],"tags":{"golf":"lateral_water_hazard"},"name":"Lateral Water Hazard"},"golf/rough":{"icon":"golf","geometry":["area"],"tags":{"golf":"rough","landuse":"grass"},"reference":{"key":"golf","value":"rough"},"name":"Rough"},"golf/tee":{"icon":"golf","geometry":["area"],"tags":{"golf":"tee","landuse":"grass"},"terms":["teeing ground"],"reference":{"key":"golf","value":"tee"},"name":"Tee Box"},"golf/water_hazard_area":{"icon":"golf","geometry":["area"],"tags":{"golf":"water_hazard","natural":"water"},"reference":{"key":"golf","value":"water_hazard"},"name":"Water Hazard"},"golf/water_hazard_line":{"icon":"golf","geometry":["line"],"tags":{"golf":"water_hazard"},"name":"Water Hazard"},"healthcare/blood_donation":{"icon":"blood-bank","fields":["operator","address","blood_components","opening_hours","ref"],"geometry":["point","area"],"terms":["blood bank","blood donation","blood transfusion","apheresis","plasmapheresis","plateletpheresis","stem cell donation"],"tags":{"healthcare":"blood_donation"},"name":"Blood Donor Center"},"highway/bridleway":{"fields":["surface","width","structure","access"],"icon":"highway-bridleway","geometry":["line"],"tags":{"highway":"bridleway"},"terms":["bridleway","equestrian","horse"],"name":"Bridle Path"},"highway/bus_stop":{"icon":"bus","fields":["network","operator","bench","shelter"],"geometry":["point","vertex"],"tags":{"highway":"bus_stop"},"terms":[],"name":"Bus Stop"},"highway/corridor":{"icon":"highway-footway","fields":["width","level","access_simple"],"geometry":["line"],"tags":{"highway":"corridor"},"terms":["gallery","hall","hallway","indoor","passage","passageway"],"name":"Indoor Corridor"},"highway/crossing":{"fields":["crossing","kerb","tactile_paving"],"geometry":["vertex"],"tags":{"highway":"crossing"},"reference":{"key":"footway","value":"crossing"},"terms":[],"name":"Street Crossing"},"highway/crosswalk":{"icon":"poi-foot","fields":["crossing","kerb","tactile_paving"],"geometry":["vertex"],"tags":{"highway":"crossing","crossing":"zebra"},"reference":{"key":"highway","value":"crossing"},"terms":["zebra crossing"],"name":"Pedestrian Crosswalk"},"highway/cycleway":{"icon":"highway-cycleway","fields":["oneway","surface","lit","width","structure","access"],"geometry":["line"],"tags":{"highway":"cycleway"},"terms":["bike"],"name":"Cycle Path"},"highway/elevator":{"icon":"poi-elevator","fields":["access_simple","opening_hours","maxweight","ref"],"geometry":["vertex"],"tags":{"highway":"elevator"},"terms":["lift"],"name":"Elevator"},"highway/footway":{"icon":"highway-footway","fields":["surface","lit","width","structure","access"],"geometry":["line","area"],"terms":["hike","hiking","trackway","trail","walk"],"tags":{"highway":"footway"},"name":"Foot Path"},"highway/give_way":{"icon":"poi-yield","fields":["parallel_direction"],"geometry":["vertex"],"tags":{"highway":"give_way"},"terms":["give way","yield","sign"],"name":"Yield Sign"},"highway/living_street":{"icon":"highway-living-street","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","access","cycleway"],"geometry":["line"],"tags":{"highway":"living_street"},"name":"Living Street"},"highway/mini_roundabout":{"icon":"circle-stroked","geometry":["vertex"],"tags":{"highway":"mini_roundabout"},"fields":["clock_direction"],"name":"Mini-Roundabout"},"highway/motorway_junction":{"icon":"poi-junction","geometry":["vertex"],"tags":{"highway":"motorway_junction"},"fields":["ref"],"name":"Motorway Junction / Exit"},"highway/motorway_link":{"icon":"highway-motorway-link","fields":["ref","oneway_yes","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"motorway_link"},"addTags":{"highway":"motorway_link","oneway":"yes"},"removeTags":{"highway":"motorway_link","oneway":"yes"},"terms":["ramp","on ramp","off ramp"],"name":"Motorway Link"},"highway/motorway":{"icon":"highway-motorway","fields":["ref","oneway_yes","maxspeed","lanes","surface","structure","maxheight","toll","access"],"geometry":["line"],"tags":{"highway":"motorway"},"terms":["autobahn","expressway","freeway","highway","interstate","parkway","thruway","turnpike"],"name":"Motorway"},"highway/path":{"icon":"highway-path","fields":["surface","width","structure","access","incline","sac_scale","trail_visibility","mtb/scale","mtb/scale/uphill","mtb/scale/imba","ref"],"geometry":["line"],"terms":["hike","hiking","trackway","trail","walk"],"tags":{"highway":"path"},"name":"Path"},"highway/pedestrian":{"icon":"highway-footway","fields":["surface","lit","width","oneway","structure","access"],"geometry":["line","area"],"tags":{"highway":"pedestrian"},"terms":[],"name":"Pedestrian Street"},"highway/primary_link":{"icon":"highway-primary-link","fields":["oneway","maxspeed","lanes","surface","maxheight","ref","cycleway","structure","access"],"geometry":["line"],"tags":{"highway":"primary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Primary Link"},"highway/primary":{"icon":"highway-primary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"primary"},"terms":[],"name":"Primary Road"},"highway/raceway":{"icon":"highway-unclassified","fields":["oneway","surface","sport_racing_motor","lit","width","lanes","structure"],"geometry":["point","line","area"],"tags":{"highway":"raceway"},"addTags":{"highway":"raceway","sport":"motor"},"terms":["auto*","formula one","kart","motocross","nascar","race*","track"],"name":"Racetrack (Motorsport)"},"highway/residential":{"icon":"highway-residential","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","cycleway","access"],"geometry":["line"],"tags":{"highway":"residential"},"terms":[],"name":"Residential Road"},"highway/rest_area":{"icon":"car","geometry":["point","vertex","area"],"tags":{"highway":"rest_area"},"terms":["rest stop"],"name":"Rest Area"},"highway/road":{"icon":"highway-road","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"road"},"terms":[],"name":"Unknown Road"},"highway/secondary_link":{"icon":"highway-secondary-link","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"secondary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Secondary Link"},"highway/secondary":{"icon":"highway-secondary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"secondary"},"terms":[],"name":"Secondary Road"},"highway/service":{"icon":"highway-service","fields":["service","oneway","maxspeed","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"service"},"terms":[],"name":"Service Road"},"highway/service/alley":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"alley"},"reference":{"key":"service","value":"alley"},"name":"Alley"},"highway/service/drive-through":{"icon":"highway-service","fields":["oneway","covered","maxheight","maxspeed","structure","access","surface"],"geometry":["line"],"tags":{"highway":"service","service":"drive-through"},"reference":{"key":"service","value":"drive-through"},"name":"Drive-Through"},"highway/service/driveway":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"driveway"},"reference":{"key":"service","value":"driveway"},"name":"Driveway"},"highway/service/emergency_access":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"emergency_access"},"reference":{"key":"service","value":"emergency_access"},"name":"Emergency Access"},"highway/service/parking_aisle":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"parking_aisle"},"reference":{"key":"service","value":"parking_aisle"},"name":"Parking Aisle"},"highway/services":{"icon":"car","geometry":["point","vertex","area"],"tags":{"highway":"services"},"terms":["services","travel plaza","service station"],"name":"Service Area"},"highway/speed_camera":{"icon":"attraction","geometry":["point"],"fields":["ref"],"tags":{"highway":"speed_camera"},"terms":[],"name":"Speed Camera"},"highway/steps":{"icon":"highway-steps","fields":["surface","lit","width","incline_steps","handrail","step_count"],"geometry":["line"],"tags":{"highway":"steps"},"terms":["stairs","staircase"],"name":"Steps"},"highway/stop":{"icon":"poi-stop","fields":["stop","parallel_direction"],"geometry":["vertex"],"tags":{"highway":"stop"},"terms":["stop","halt","sign"],"name":"Stop Sign"},"highway/street_lamp":{"icon":"poi-street-lamp","geometry":["point","vertex"],"tags":{"highway":"street_lamp"},"fields":["lamp_type","ref"],"terms":["streetlight","street light","lamp","light","gaslight"],"name":"Street Lamp"},"highway/tertiary_link":{"icon":"highway-tertiary-link","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"tertiary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Tertiary Link"},"highway/tertiary":{"icon":"highway-tertiary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"tertiary"},"terms":[],"name":"Tertiary Road"},"highway/track":{"icon":"highway-track","fields":["tracktype","surface","width","structure","access","incline","smoothness","mtb/scale","mtb/scale/uphill","mtb/scale/imba"],"geometry":["line"],"tags":{"highway":"track"},"terms":["woods road","forest road","logging road","fire road","farm road","agricultural road","ranch road","carriage road","primitive","unmaintained","rut","offroad","4wd","4x4","four wheel drive","atv","quad","jeep","double track","two track"],"name":"Unmaintained Track Road"},"highway/traffic_mirror":{"geometry":["point"],"tags":{"highway":"traffic_mirror"},"terms":["blind spot","convex","corner","curved","roadside","round","safety","sphere","visibility"],"name":"Traffic Mirror"},"highway/traffic_signals":{"icon":"poi-traffic-signals","geometry":["vertex"],"tags":{"highway":"traffic_signals"},"fields":["traffic_signals"],"terms":["light","stoplight","traffic light"],"name":"Traffic Signals"},"highway/trunk_link":{"icon":"highway-trunk-link","fields":["ref","oneway","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"trunk_link"},"terms":["ramp","on ramp","off ramp"],"name":"Trunk Link"},"highway/trunk":{"icon":"highway-trunk","fields":["ref","oneway","maxspeed","lanes","surface","structure","maxheight","toll","access"],"geometry":["line"],"tags":{"highway":"trunk"},"terms":[],"name":"Trunk Road"},"highway/turning_circle":{"icon":"circle-stroked","geometry":["vertex"],"tags":{"highway":"turning_circle"},"terms":["cul-de-sac"],"name":"Turning Circle"},"highway/turning_loop":{"icon":"circle","geometry":["vertex"],"tags":{"highway":"turning_loop"},"terms":["cul-de-sac"],"name":"Turning Loop (Island)"},"highway/unclassified":{"icon":"highway-unclassified","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","cycleway","access"],"geometry":["line"],"tags":{"highway":"unclassified"},"terms":[],"name":"Minor/Unclassified Road"},"historic":{"icon":"poi-ruins","fields":["historic","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"*"},"name":"Historic Site"},"historic/archaeological_site":{"icon":"poi-ruins","fields":["historic/civilization","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"archaeological_site"},"name":"Archaeological Site"},"historic/boundary_stone":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex"],"tags":{"historic":"boundary_stone"},"name":"Boundary Stone"},"historic/castle":{"icon":"castle","fields":["castle_type","building_area","historic/civilization"],"geometry":["point","area"],"tags":{"historic":"castle"},"name":"Castle"},"historic/memorial":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"memorial"},"name":"Memorial"},"historic/monument":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"monument"},"name":"Monument"},"historic/ruins":{"icon":"poi-ruins","fields":["historic/civilization","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"ruins"},"name":"Ruins"},"historic/tomb":{"icon":"cemetery","fields":["tomb","building_area","inscription"],"geometry":["point","area"],"tags":{"historic":"tomb"},"name":"Tomb"},"historic/wayside_cross":{"icon":"religious-christian","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"wayside_cross"},"name":"Wayside Cross"},"historic/wayside_shrine":{"icon":"landmark","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"wayside_shrine"},"name":"Wayside Shrine"},"junction":{"icon":"poi-junction","geometry":["vertex","area"],"tags":{"junction":"yes"},"name":"Junction"},"landuse":{"fields":["landuse"],"geometry":["area"],"tags":{"landuse":"*"},"matchScore":0.9,"name":"Land Use"},"landuse/farm":{"icon":"farm","fields":["operator","crop"],"geometry":["point","area"],"tags":{"landuse":"farm"},"terms":[],"name":"Farmland","searchable":false},"landuse/allotments":{"geometry":["area"],"tags":{"landuse":"allotments"},"terms":["allotment","garden"],"name":"Community Garden"},"landuse/aquaculture":{"icon":"aquarium","fields":["operator","produce"],"geometry":["area"],"tags":{"landuse":"aquaculture"},"terms":["fish farm","crustacean","algae","aquafarming","shrimp farm","oyster farm","mariculture","algaculture"],"name":"Aquaculture"},"landuse/basin":{"icon":"water","geometry":["area"],"tags":{"landuse":"basin"},"terms":[],"name":"Basin"},"landuse/cemetery":{"icon":"cemetery","fields":["religion","denomination"],"geometry":["area"],"tags":{"landuse":"cemetery"},"terms":[],"name":"Cemetery"},"landuse/churchyard":{"fields":["religion","denomination"],"geometry":["area"],"tags":{"landuse":"churchyard"},"terms":[],"name":"Churchyard"},"landuse/commercial":{"icon":"commercial","geometry":["area"],"tags":{"landuse":"commercial"},"terms":[],"name":"Commercial Area"},"landuse/construction":{"fields":["construction","operator"],"geometry":["area"],"tags":{"landuse":"construction"},"terms":[],"name":"Construction"},"landuse/farmland":{"icon":"farm","fields":["operator","crop","produce"],"geometry":["area"],"tags":{"landuse":"farmland"},"terms":["crop","grow","plant"],"name":"Farmland"},"landuse/farmyard":{"icon":"farm","fields":["operator","crop"],"geometry":["area"],"tags":{"landuse":"farmyard"},"terms":["crop","grow","plant"],"name":"Farmyard"},"landuse/forest":{"icon":"park-alt1","fields":["leaf_type","leaf_cycle","produce"],"geometry":["area"],"tags":{"landuse":"forest"},"terms":["tree"],"name":"Forest"},"landuse/garages":{"geometry":["area"],"tags":{"landuse":"garages"},"terms":[],"name":"Garages"},"landuse/grass":{"geometry":["area"],"tags":{"landuse":"grass"},"terms":[],"name":"Grass"},"landuse/harbour":{"icon":"harbor","fields":["operator"],"geometry":["area"],"terms":["boat"],"tags":{"landuse":"harbour"},"name":"Harbor"},"landuse/industrial":{"icon":"industry","geometry":["area"],"tags":{"landuse":"industrial"},"terms":[],"matchScore":0.9,"name":"Industrial Area"},"landuse/landfill":{"geometry":["area"],"tags":{"landuse":"landfill"},"terms":["dump"],"name":"Landfill"},"landuse/meadow":{"geometry":["area"],"tags":{"landuse":"meadow"},"terms":[],"name":"Meadow"},"landuse/military":{"icon":"poi-military","geometry":["area"],"tags":{"landuse":"military"},"terms":[],"matchScore":0.9,"name":"Military Area"},"landuse/military/airfield":{"icon":"airfield","fields":["ref","iata","icao"],"geometry":["point","area"],"tags":{"military":"airfield"},"addTags":{"landuse":"military","military":"airfield"},"removeTags":{"landuse":"military","military":"airfield"},"terms":["air force","army","base","bomb","fight","force","guard","heli*","jet","marine","navy","plane","troop","war"],"name":"Military Airfield"},"landuse/military/barracks":{"icon":"poi-military","fields":["building_area"],"geometry":["point","area"],"tags":{"military":"barracks"},"addTags":{"landuse":"military","military":"barracks"},"removeTags":{"landuse":"military","military":"barracks"},"terms":["air force","army","base","fight","force","guard","marine","navy","troop","war"],"name":"Barracks"},"landuse/military/bunker":{"icon":"poi-military","fields":["bunker_type","building_area"],"geometry":["point","area"],"tags":{"military":"bunker"},"addTags":{"building":"bunker","landuse":"military","military":"bunker"},"removeTags":{"building":"bunker","landuse":"military","military":"bunker"},"terms":["air force","army","base","fight","force","guard","marine","navy","troop","war"],"name":"Military Bunker"},"landuse/military/checkpoint":{"icon":"barrier","geometry":["point","vertex","area"],"tags":{"military":"checkpoint"},"addTags":{"landuse":"military","military":"checkpoint"},"removeTags":{"landuse":"military","military":"checkpoint"},"terms":["air force","army","base","force","guard","marine","navy","troop","war"],"name":"Checkpoint"},"landuse/military/danger_area":{"icon":"danger","geometry":["point","vertex","area"],"tags":{"military":"danger_area"},"addTags":{"landuse":"military","military":"danger_area"},"removeTags":{"landuse":"military","military":"danger_area"},"terms":["air force","army","base","blast","bomb","explo*","force","guard","mine","marine","navy","troop","war"],"name":"Danger Area"},"landuse/military/naval_base":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"naval_base"},"addTags":{"landuse":"military","military":"naval_base"},"removeTags":{"landuse":"military","military":"naval_base"},"terms":["base","fight","force","guard","marine","navy","ship","sub","troop","war"],"name":"Naval Base"},"landuse/military/nuclear_explosion_site":{"icon":"danger","geometry":["point","vertex","area"],"tags":{"military":"nuclear_explosion_site"},"addTags":{"landuse":"military","military":"nuclear_explosion_site"},"removeTags":{"landuse":"military","military":"nuclear_explosion_site"},"terms":["atom","blast","bomb","detonat*","nuke","site","test"],"name":"Nuclear Explosion Site"},"landuse/military/obstacle_course":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"obstacle_course"},"addTags":{"landuse":"military","military":"obstacle_course"},"removeTags":{"landuse":"military","military":"obstacle_course"},"terms":["army","base","force","guard","marine","navy","troop","war"],"name":"Obstacle Course"},"landuse/military/office":{"icon":"poi-military","fields":["building_area"],"geometry":["point","area"],"tags":{"military":"office"},"addTags":{"landuse":"military","military":"office"},"removeTags":{"landuse":"military","military":"office"},"terms":["air force","army","base","enlist","fight","force","guard","marine","navy","recruit","troop","war"],"name":"Military Office"},"landuse/military/range":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"range"},"addTags":{"landuse":"military","military":"range"},"removeTags":{"landuse":"military","military":"range"},"terms":["air force","army","base","fight","fire","force","guard","gun","marine","navy","rifle","shoot*","snip*","train","troop","war"],"name":"Military Range"},"landuse/military/training_area":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"training_area"},"addTags":{"landuse":"military","military":"training_area"},"removeTags":{"landuse":"military","military":"training_area"},"terms":["air force","army","base","fight","fire","force","guard","gun","marine","navy","rifle","shoot*","snip*","train","troop","war"],"name":"Training Area"},"landuse/orchard":{"icon":"park-alt1","fields":["operator","trees"],"geometry":["area"],"tags":{"landuse":"orchard"},"terms":["fruit"],"name":"Orchard"},"landuse/plant_nursery":{"icon":"garden","fields":["operator","plant"],"geometry":["area"],"tags":{"landuse":"plant_nursery"},"terms":["flower","garden","grow","vivero"],"name":"Plant Nursery"},"landuse/quarry":{"geometry":["area"],"tags":{"landuse":"quarry"},"terms":[],"name":"Quarry"},"landuse/railway":{"icon":"rail","fields":["operator"],"geometry":["area"],"tags":{"landuse":"railway"},"terms":["rail","train","track"],"name":"Railway Corridor"},"landuse/recreation_ground":{"icon":"pitch","geometry":["area"],"tags":{"landuse":"recreation_ground"},"terms":["playing fields"],"name":"Recreation Ground"},"landuse/residential":{"icon":"building","geometry":["area"],"tags":{"landuse":"residential"},"terms":[],"name":"Residential Area"},"landuse/retail":{"icon":"shop","geometry":["area"],"tags":{"landuse":"retail"},"name":"Retail Area"},"landuse/vineyard":{"fields":["operator","grape_variety"],"geometry":["area"],"tags":{"landuse":"vineyard"},"addTags":{"landuse":"vineyard","crop":"grape"},"removeTags":{"landuse":"vineyard","crop":"grape","grape_variety":"*"},"terms":["grape","wine"],"name":"Vineyard"},"leisure":{"icon":"pitch","fields":["leisure"],"geometry":["point","vertex","area"],"tags":{"leisure":"*"},"name":"Leisure"},"leisure/adult_gaming_centre":{"icon":"poi-dice","fields":["operator","address","building_area","opening_hours","smoking"],"geometry":["point","area"],"terms":["gambling","slot machine"],"tags":{"leisure":"adult_gaming_centre"},"name":"Adult Gaming Center"},"leisure/bird_hide":{"icon":"poi-binoculars","fields":["building_area"],"geometry":["point","area"],"tags":{"leisure":"bird_hide"},"terms":["machan","ornithology"],"name":"Bird Hide"},"leisure/bowling_alley":{"icon":"poi-bowling","fields":["operator","address","building_area","opening_hours","smoking"],"geometry":["point","area"],"terms":[],"tags":{"leisure":"bowling_alley"},"name":"Bowling Alley"},"leisure/common":{"icon":"poi-foot","geometry":["point","area"],"terms":["open space"],"tags":{"leisure":"common"},"name":"Common"},"leisure/dance":{"icon":"music","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ballroom","jive","swing","tango","waltz"],"tags":{"leisure":"dance"},"name":"Dance Hall"},"leisure/dog_park":{"icon":"dog-park","geometry":["point","area"],"terms":[],"tags":{"leisure":"dog_park"},"name":"Dog Park"},"leisure/firepit":{"icon":"fire-station","geometry":["point","area"],"tags":{"leisure":"firepit"},"terms":["fireplace","campfire"],"name":"Firepit"},"leisure/fitness_centre":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"fitness_centre"},"terms":["health","gym","leisure","studio"],"name":"Gym / Fitness Center"},"leisure/fitness_centre/yoga":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["studio"],"tags":{"leisure":"fitness_centre","sport":"yoga"},"reference":{"key":"sport","value":"yoga"},"name":"Yoga Studio"},"leisure/fitness_station":{"icon":"pitch","fields":["sport","address","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"fitness_station"},"terms":["fitness","gym"],"name":"Outdoor Fitness Station"},"leisure/garden":{"icon":"garden","fields":["access_simple"],"geometry":["point","vertex","area"],"tags":{"leisure":"garden"},"name":"Garden"},"leisure/golf_course":{"icon":"golf","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["links"],"tags":{"leisure":"golf_course"},"name":"Golf Course"},"leisure/horse_riding":{"icon":"horse-riding","fields":["access_simple","operator","address","building"],"geometry":["point","area"],"terms":["equestrian","stable"],"tags":{"leisure":"horse_riding"},"name":"Horseback Riding Facility"},"leisure/ice_rink":{"icon":"pitch","fields":["seasonal","sport_ice","operator","address","building","opening_hours"],"geometry":["point","area"],"terms":["hockey","skating","curling"],"tags":{"leisure":"ice_rink"},"name":"Ice Rink"},"leisure/marina":{"icon":"harbor","fields":["operator","address","capacity","fee","sanitary_dump_station","power_supply","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"terms":["boat"],"tags":{"leisure":"marina"},"name":"Marina"},"leisure/miniature_golf":{"icon":"golf","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["crazy golf","mini golf","putt-putt"],"tags":{"leisure":"miniature_golf"},"name":"Miniature Golf"},"leisure/nature_reserve":{"icon":"park","geometry":["point","area"],"tags":{"leisure":"nature_reserve"},"terms":["protected","wildlife"],"name":"Nature Reserve"},"leisure/park":{"icon":"park","geometry":["point","area"],"terms":["esplanade","estate","forest","garden","grass","green","grounds","lawn","lot","meadow","parkland","place","playground","plaza","pleasure garden","recreation area","square","tract","village green","woodland"],"tags":{"leisure":"park"},"name":"Park"},"leisure/picnic_table":{"icon":"picnic-site","geometry":["point"],"tags":{"leisure":"picnic_table"},"terms":["bench"],"name":"Picnic Table"},"leisure/pitch":{"icon":"pitch","fields":["sport","surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch"},"terms":["field"],"name":"Sport Pitch"},"leisure/pitch/american_football":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"american_football"},"reference":{"key":"sport","value":"american_football"},"terms":[],"name":"American Football Field"},"leisure/pitch/baseball":{"icon":"baseball","fields":["lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"baseball"},"reference":{"key":"sport","value":"baseball"},"terms":[],"name":"Baseball Diamond"},"leisure/pitch/basketball":{"icon":"basketball","fields":["surface","hoops","lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"basketball"},"reference":{"key":"sport","value":"basketball"},"terms":[],"name":"Basketball Court"},"leisure/pitch/beachvolleyball":{"icon":"basketball","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"beachvolleyball"},"addTags":{"leisure":"pitch","sport":"beachvolleyball","surface":"sand"},"removeTags":{"leisure":"pitch","sport":"beachvolleyball","surface":"sand"},"reference":{"key":"sport","value":"beachvolleyball"},"terms":["volleyball"],"name":"Beach Volleyball Court"},"leisure/pitch/bowls":{"icon":"pitch","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"bowls"},"reference":{"key":"sport","value":"bowls"},"terms":[],"name":"Bowling Green"},"leisure/pitch/cricket":{"icon":"cricket","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"cricket"},"reference":{"key":"sport","value":"cricket"},"terms":[],"name":"Cricket Field"},"leisure/pitch/equestrian":{"icon":"horse-riding","fields":["surface","lit","building"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"equestrian"},"reference":{"key":"sport","value":"equestrian"},"terms":["dressage","equestrian","horse","horseback","riding"],"name":"Riding Arena"},"leisure/pitch/rugby_league":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"rugby_league"},"reference":{"key":"sport","value":"rugby_league"},"terms":[],"name":"Rugby League Field"},"leisure/pitch/rugby_union":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"rugby_union"},"reference":{"key":"sport","value":"rugby_union"},"terms":[],"name":"Rugby Union Field"},"leisure/pitch/skateboard":{"icon":"pitch","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"skateboard"},"reference":{"key":"sport","value":"skateboard"},"terms":[],"name":"Skate Park"},"leisure/pitch/soccer":{"icon":"soccer","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"soccer"},"reference":{"key":"sport","value":"soccer"},"terms":["football"],"name":"Soccer Field"},"leisure/pitch/table_tennis":{"icon":"tennis","fields":["lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"table_tennis"},"reference":{"key":"sport","value":"table_tennis"},"terms":["table tennis","ping pong"],"name":"Ping Pong Table"},"leisure/pitch/tennis":{"icon":"tennis","fields":["surface","lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"tennis"},"reference":{"key":"sport","value":"tennis"},"terms":[],"name":"Tennis Court"},"leisure/pitch/volleyball":{"icon":"basketball","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"volleyball"},"reference":{"key":"sport","value":"volleyball"},"terms":[],"name":"Volleyball Court"},"leisure/playground":{"icon":"playground","geometry":["point","area"],"terms":["jungle gym","play area"],"tags":{"leisure":"playground"},"name":"Playground"},"leisure/resort":{"icon":"lodging","fields":["operator","address","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"resort"},"name":"Resort"},"leisure/running_track":{"icon":"pitch","fields":["surface","sport_racing_nonmotor","lit","width","lanes"],"geometry":["point","line","area"],"tags":{"leisure":"track","sport":"running"},"terms":["race*","running","sprint","track"],"name":"Racetrack (Running)"},"leisure/slipway":{"icon":"poi-beach","geometry":["point","line"],"terms":["boat launch","boat ramp"],"tags":{"leisure":"slipway"},"name":"Slipway"},"leisure/sports_centre":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"sports_centre"},"terms":[],"name":"Sports Center / Complex"},"leisure/sports_centre/swimming":{"icon":"swimming","fields":["access_simple","operator","address","building"],"geometry":["point","area"],"terms":["dive","water"],"tags":{"leisure":"sports_centre","sport":"swimming"},"reference":{"key":"sport","value":"swimming"},"name":"Swimming Pool Facility"},"leisure/stadium":{"icon":"pitch","fields":["sport","address"],"geometry":["point","area"],"tags":{"leisure":"stadium"},"name":"Stadium"},"leisure/swimming_pool":{"icon":"swimming","fields":["access_simple","operator","address"],"geometry":["point","area"],"terms":["dive","water"],"tags":{"leisure":"swimming_pool"},"name":"Swimming Pool"},"leisure/track":{"icon":"highway-road","fields":["surface","sport_racing_nonmotor","lit","width","lanes"],"geometry":["point","line","area"],"tags":{"leisure":"track"},"terms":["cycle","dog","greyhound","horse","race*","track"],"name":"Racetrack (Non-Motorsport)"},"leisure/water_park":{"icon":"swimming","fields":["operator","address"],"geometry":["point","area"],"terms":["swim","pool","dive"],"tags":{"leisure":"water_park"},"name":"Water Park"},"line":{"name":"Line","tags":{},"geometry":["line"],"matchScore":0.1},"man_made":{"icon":"poi-storage-tank","fields":["man_made"],"geometry":["point","vertex","line","area"],"tags":{"man_made":"*"},"name":"Man Made"},"man_made/embankment":{"geometry":["line"],"tags":{"man_made":"embankment"},"name":"Embankment","searchable":false},"man_made/adit":{"icon":"triangle","geometry":["point","area"],"fields":["operator"],"terms":["entrance","underground","mine","cave"],"tags":{"man_made":"adit"},"name":"Adit"},"man_made/breakwater":{"geometry":["line","area"],"tags":{"man_made":"breakwater"},"name":"Breakwater"},"man_made/bridge":{"geometry":["area"],"tags":{"man_made":"bridge"},"name":"Bridge"},"man_made/chimney":{"icon":"poi-chimney","geometry":["point","area"],"tags":{"man_made":"chimney"},"name":"Chimney"},"man_made/cutline":{"geometry":["line"],"tags":{"man_made":"cutline"},"name":"Cut line"},"man_made/flagpole":{"icon":"embassy","geometry":["point"],"tags":{"man_made":"flagpole"},"name":"Flagpole"},"man_made/gasometer":{"icon":"poi-storage-tank","geometry":["point","area"],"terms":["gas holder"],"tags":{"man_made":"gasometer"},"name":"Gasometer"},"man_made/groyne":{"geometry":["line","area"],"tags":{"man_made":"groyne"},"name":"Groyne"},"man_made/lighthouse":{"icon":"lighthouse","fields":["building_area"],"geometry":["point","area"],"tags":{"man_made":"lighthouse"},"name":"Lighthouse"},"man_made/mast":{"icon":"poi-mast","fields":["tower/type","tower/construction","height","communication_multi"],"geometry":["point"],"terms":["antenna","broadcast tower","cell phone tower","cell tower","communication mast","communication tower","guyed tower","mobile phone tower","radio mast","radio tower","television tower","transmission mast","transmission tower","tv tower"],"tags":{"man_made":"mast"},"name":"Mast"},"man_made/observation":{"icon":"poi-tower","geometry":["point","area"],"terms":["lookout tower","fire tower"],"tags":{"man_made":"tower","tower:type":"observation"},"name":"Observation Tower"},"man_made/petroleum_well":{"icon":"poi-storage-tank","geometry":["point"],"terms":["drilling rig","oil derrick","oil drill","oil horse","oil rig","oil pump","petroleum well","pumpjack"],"tags":{"man_made":"petroleum_well"},"name":"Oil Well"},"man_made/pier":{"geometry":["line","area"],"terms":["dock"],"tags":{"man_made":"pier"},"name":"Pier"},"man_made/pipeline":{"icon":"pipeline-line","fields":["location","operator"],"geometry":["line"],"tags":{"man_made":"pipeline"},"name":"Pipeline"},"man_made/pumping_station":{"icon":"water","geometry":["point","area"],"tags":{"man_made":"pumping_station"},"name":"Pumping Station"},"man_made/silo":{"icon":"poi-silo","fields":["building_area","crop"],"geometry":["point","area"],"terms":["grain","corn","wheat"],"tags":{"man_made":"silo"},"name":"Silo"},"man_made/storage_tank":{"icon":"poi-storage-tank","fields":["building_area","content"],"geometry":["point","area"],"terms":["water","oil","gas","petrol"],"tags":{"man_made":"storage_tank"},"name":"Storage Tank"},"man_made/surveillance_camera":{"icon":"attraction","geometry":["point"],"fields":["surveillance","surveillance/type","camera/type","camera/mount","camera/direction","surveillance/zone","contact/webcam"],"terms":["anpr","alpr","camera","car plate recognition","cctv","guard","license plate recognition","monitoring","number plate recognition","security","video","webcam"],"tags":{"man_made":"surveillance","surveillance:type":"camera"},"name":"Surveillance Camera"},"man_made/surveillance":{"icon":"attraction","geometry":["point"],"fields":["surveillance","surveillance/type","surveillance/zone"],"terms":["anpr","alpr","camera","car plate recognition","cctv","guard","license plate recognition","monitoring","number plate recognition","security","video","webcam"],"tags":{"man_made":"surveillance"},"name":"Surveillance"},"man_made/survey_point":{"icon":"monument","fields":["ref"],"geometry":["point","vertex"],"tags":{"man_made":"survey_point"},"name":"Survey Point"},"man_made/tower":{"icon":"poi-tower","fields":["tower/type","tower/construction","height"],"geometry":["point","area"],"tags":{"man_made":"tower"},"name":"Tower"},"man_made/wastewater_plant":{"icon":"water","fields":["operator","address"],"geometry":["point","area"],"terms":["sewage*","water treatment plant","reclamation plant"],"tags":{"man_made":"wastewater_plant"},"name":"Wastewater Plant"},"man_made/water_tower":{"icon":"water","fields":["operator"],"geometry":["point","area"],"tags":{"man_made":"water_tower"},"name":"Water Tower"},"man_made/water_well":{"icon":"water","fields":["operator"],"geometry":["point","area"],"tags":{"man_made":"water_well"},"name":"Water Well"},"man_made/water_works":{"icon":"water","fields":["operator","address"],"geometry":["point","area"],"tags":{"man_made":"water_works"},"name":"Water Works"},"man_made/works":{"icon":"industry","fields":["operator","address","building_area","product"],"geometry":["point","area"],"terms":["assembly","build","brewery","car","plant","plastic","processing","manufacture","refinery"],"tags":{"man_made":"works"},"name":"Factory"},"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"],"geometry":["point","vertex","area"],"terms":["hydro","solar","turbine","wind"],"tags":{"power":"generator"},"name":"Power Generator"},"power/line":{"icon":"power-line","geometry":["line"],"tags":{"power":"line"},"name":"Power Line"},"power/minor_line":{"icon":"power-line","geometry":["line"],"tags":{"power":"minor_line"},"name":"Minor Power Line"},"power/plant":{"icon":"industry","fields":["operator"],"geometry":["area"],"tags":{"power":"plant"},"addTags":{"power":"plant","landuse":"industrial"},"removeTags":{"power":"plant","landuse":"industrial"},"terms":["coal","gas","generat*","hydro","nuclear","power","station"],"name":"Power Station Grounds"},"power/pole":{"geometry":["vertex"],"tags":{"power":"pole"},"name":"Power Pole"},"power/substation":{"icon":"poi-power","fields":["substation","operator","building"],"geometry":["point","area"],"tags":{"power":"substation"},"name":"Substation"},"power/tower":{"geometry":["vertex"],"tags":{"power":"tower"},"name":"High-Voltage Tower"},"power/transformer":{"icon":"poi-power","geometry":["point","vertex","area"],"tags":{"power":"transformer"},"name":"Transformer"},"public_transport/platform":{"icon":"bus","fields":["ref","network","operator","shelter"],"geometry":["point","vertex","line","area"],"tags":{"public_transport":"platform"},"name":"Platform"},"public_transport/stop_position":{"icon":"bus","fields":["ref","network","operator"],"geometry":["vertex"],"tags":{"public_transport":"stop_position"},"name":"Stop Position"},"railway/abandoned":{"icon":"railway-abandoned","geometry":["line"],"tags":{"railway":"abandoned"},"fields":["structure","service_rail"],"terms":[],"name":"Abandoned Railway"},"railway/crossing":{"icon":"cross","geometry":["vertex"],"tags":{"railway":"crossing"},"terms":["crossing","pedestrian crossing","railroad crossing","level crossing","grade crossing","path through railroad","train crossing"],"name":"Railway Crossing (Path)"},"railway/disused":{"icon":"railway-disused","geometry":["line"],"tags":{"railway":"disused"},"fields":["structure","service_rail"],"terms":[],"name":"Disused Railway"},"railway/funicular":{"icon":"railway-rail","geometry":["line"],"terms":["venicular","cliff railway","cable car","cable railway","funicular railway"],"fields":["structure","gauge","service_rail"],"tags":{"railway":"funicular"},"name":"Funicular"},"railway/halt":{"icon":"rail","geometry":["point","vertex"],"tags":{"railway":"halt"},"name":"Railway Halt","terms":["break","interrupt","rest","wait","interruption"]},"railway/level_crossing":{"icon":"cross","geometry":["vertex"],"tags":{"railway":"level_crossing"},"terms":["crossing","railroad crossing","level crossing","grade crossing","road through railroad","train crossing"],"name":"Railway Crossing (Road)"},"railway/monorail":{"icon":"railway-monorail","geometry":["line"],"tags":{"railway":"monorail"},"fields":["structure","electrified","service_rail"],"terms":[],"name":"Monorail"},"railway/narrow_gauge":{"icon":"railway-rail","geometry":["line"],"tags":{"railway":"narrow_gauge"},"fields":["structure","gauge","electrified","service_rail"],"terms":["narrow gauge railway","narrow gauge railroad"],"name":"Narrow Gauge Rail"},"railway/platform":{"icon":"rail","geometry":["point","vertex","line","area"],"tags":{"railway":"platform"},"name":"Railway Platform"},"railway/rail":{"icon":"railway-rail","geometry":["line"],"tags":{"railway":"rail"},"fields":["structure","gauge","electrified","maxspeed","service_rail"],"terms":[],"name":"Rail"},"railway/station":{"icon":"rail","fields":["network","operator","address","building_area","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"tags":{"railway":"station"},"terms":["train station","station"],"name":"Railway Station"},"railway/subway_entrance":{"icon":"entrance","geometry":["point","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":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"boutique"},"name":"Boutique"},"shop/butcher":{"icon":"slaughterhouse","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["meat"],"tags":{"shop":"butcher"},"name":"Butcher"},"shop/candles":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"candles"},"name":"Candle Shop"},"shop/car_parts":{"icon":"car","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["auto"],"tags":{"shop":"car_parts"},"name":"Car Parts Store"},"shop/car_repair":{"icon":"car","fields":["operator","address","building_area","opening_hours","service/vehicle"],"geometry":["point","area"],"terms":["auto","garage","service"],"tags":{"shop":"car_repair"},"name":"Car Repair Shop"},"shop/car":{"icon":"car","fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"geometry":["point","area"],"terms":["auto"],"tags":{"shop":"car"},"name":"Car Dealership"},"shop/carpet":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["rug"],"tags":{"shop":"carpet"},"name":"Carpet Store"},"shop/charity":{"icon":"shop","fields":["operator","address","building_area","opening_hours","second_hand"],"geometry":["point","area"],"terms":["thrift","op shop","nonprofit"],"tags":{"shop":"charity"},"name":"Charity Store"},"shop/cheese":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"cheese"},"name":"Cheese Store"},"shop/chemist":{"icon":"grocery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"chemist"},"terms":["med*","drug*","gift"],"name":"Drugstore"},"shop/chocolate":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"chocolate"},"name":"Chocolate Store"},"shop/clothes":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"clothes"},"name":"Clothing Store"},"shop/coffee":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"coffee"},"name":"Coffee Store"},"shop/computer":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"computer"},"name":"Computer Store"},"shop/confectionery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"confectionery"},"name":"Candy Store"},"shop/convenience":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"convenience"},"name":"Convenience Store"},"shop/copyshop":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"copyshop"},"name":"Copy Store"},"shop/cosmetics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"cosmetics"},"name":"Cosmetics Store"},"shop/craft":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"craft"},"terms":["art*","paint*","frame"],"name":"Arts and Crafts Store"},"shop/curtain":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["drape*","window"],"tags":{"shop":"curtain"},"name":"Curtain Store"},"shop/dairy":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["milk","egg","cheese"],"tags":{"shop":"dairy"},"name":"Dairy Store"},"shop/deli":{"icon":"restaurant","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["lunch","meat","sandwich"],"tags":{"shop":"deli"},"name":"Deli"},"shop/department_store":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"department_store"},"name":"Department Store"},"shop/doityourself":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"doityourself"},"name":"DIY Store"},"shop/dry_cleaning":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"dry_cleaning"},"name":"Dry Cleaner"},"shop/e-cigarette":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"e-cigarette"},"terms":["electronic","vapor"],"name":"E-Cigarette Shop"},"shop/electronics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["appliance","audio","blueray","camera","computer","dvd","home theater","radio","speaker","tv","video"],"tags":{"shop":"electronics"},"name":"Electronics Store"},"shop/erotic":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sex","porn"],"tags":{"shop":"erotic"},"name":"Erotic Store"},"shop/fabric":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sew"],"tags":{"shop":"fabric"},"name":"Fabric Store"},"shop/farm":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["farm shop","farm stand"],"tags":{"shop":"farm"},"name":"Produce Stand"},"shop/fashion":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"fashion"},"name":"Fashion Store"},"shop/florist":{"icon":"florist","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["flower"],"tags":{"shop":"florist"},"name":"Florist"},"shop/frame":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"frame"},"terms":["art*","paint*","photo*","frame"],"name":"Framing Shop"},"shop/funeral_directors":{"icon":"cemetery","fields":["operator","address","building_area","religion","denomination"],"geometry":["point","area"],"terms":["undertaker","memorial home"],"tags":{"shop":"funeral_directors"},"name":"Funeral Home"},"shop/furnace":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["oven","stove"],"tags":{"shop":"furnace"},"name":"Furnace Store"},"shop/furniture":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["chair","sofa","table"],"tags":{"shop":"furniture"},"name":"Furniture Store"},"shop/garden_centre":{"icon":"garden-center","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["landscape","mulch","shrub","tree"],"tags":{"shop":"garden_centre"},"name":"Garden Center"},"shop/gas":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["cng","lpg","natural gas","propane","refill","tank"],"tags":{"shop":"gas"},"name":"Bottled Gas Shop"},"shop/gift":{"icon":"gift","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["souvenir"],"tags":{"shop":"gift"},"name":"Gift Shop"},"shop/greengrocer":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["fruit","vegetable"],"tags":{"shop":"greengrocer"},"name":"Greengrocer"},"shop/hairdresser":{"icon":"hairdresser","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["barber"],"tags":{"shop":"hairdresser"},"name":"Hairdresser"},"shop/hardware":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"hardware"},"name":"Hardware Store"},"shop/hearing_aids":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"hearing_aids"},"name":"Hearing Aids Store"},"shop/herbalist":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"herbalist"},"name":"Herbalist"},"shop/hifi":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["stereo","video"],"tags":{"shop":"hifi"},"name":"Hifi Store"},"shop/houseware":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["home","household"],"tags":{"shop":"houseware"},"name":"Houseware Store"},"shop/interior_decoration":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"interior_decoration"},"name":"Interior Decoration Store"},"shop/jewelry":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["diamond","gem","ring"],"tags":{"shop":"jewelry"},"name":"Jeweler"},"shop/kiosk":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"kiosk"},"name":"News Kiosk"},"shop/kitchen":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"kitchen"},"name":"Kitchen Design Store"},"shop/laundry":{"icon":"laundry","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"laundry"},"name":"Laundry"},"shop/leather":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"leather"},"name":"Leather Store"},"shop/locksmith":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["key","lockpick"],"tags":{"shop":"locksmith"},"name":"Locksmith"},"shop/lottery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"lottery"},"name":"Lottery Shop"},"shop/mall":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["shopping"],"tags":{"shop":"mall"},"name":"Mall"},"shop/massage":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"massage"},"name":"Massage Shop"},"shop/medical_supply":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"medical_supply"},"name":"Medical Supply Store"},"shop/mobile_phone":{"icon":"mobile-phone","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"mobile_phone"},"name":"Mobile Phone Store"},"shop/money_lender":{"icon":"bank","fields":["operator","address","building_area","opening_hours","currency_multi"],"geometry":["point","area"],"tags":{"shop":"money_lender"},"name":"Money Lender"},"shop/motorcycle":{"icon":"scooter","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["bike"],"tags":{"shop":"motorcycle"},"name":"Motorcycle Dealership"},"shop/music":{"icon":"music","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["CD","vinyl"],"tags":{"shop":"music"},"name":"Music Store"},"shop/musical_instrument":{"icon":"music","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["guitar"],"tags":{"shop":"musical_instrument"},"name":"Musical Instrument Store"},"shop/newsagent":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"newsagent"},"name":"Newspaper/Magazine Shop"},"shop/nutrition_supplements":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"nutrition_supplements"},"name":"Nutrition Supplements Store"},"shop/optician":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["eye","glasses"],"tags":{"shop":"optician"},"name":"Optician"},"shop/organic":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"supermarket","organic":"only"},"name":"Organic Goods Store"},"shop/outdoor":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["camping","climbing","hiking"],"tags":{"shop":"outdoor"},"name":"Outdoors Store"},"shop/paint":{"icon":"water","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"paint"},"name":"Paint Store"},"shop/pastry":{"icon":"bakery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"pastry"},"terms":["patisserie","cake shop","cakery"],"name":"Pastry Shop"},"shop/pawnbroker":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"pawnbroker"},"name":"Pawn Shop"},"shop/perfumery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"perfumery"},"name":"Perfume Store"},"shop/pet":{"icon":"dog-park","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["animal","cat","dog","fish","kitten","puppy","reptile"],"tags":{"shop":"pet"},"name":"Pet Store"},"shop/photo":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["camera","film"],"tags":{"shop":"photo"},"name":"Photography Store"},"shop/pyrotechnics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"pyrotechnics"},"name":"Fireworks Store"},"shop/radiotechnics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"radiotechnics"},"name":"Radio/Electronic Component Store"},"shop/religion":{"icon":"shop","fields":["operator","address","building_area","opening_hours","religion","denomination"],"geometry":["point","area"],"tags":{"shop":"religion"},"name":"Religious Store"},"shop/scuba_diving":{"icon":"swimming","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"scuba_diving"},"name":"Scuba Diving Shop"},"shop/seafood":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["fishmonger"],"tags":{"shop":"seafood"},"name":"Seafood Shop"},"shop/second_hand":{"icon":"shop","fields":["operator","address","building_area","opening_hours","second_hand"],"geometry":["point","area"],"terms":["secondhand","second hand","resale","thrift","used"],"tags":{"shop":"second_hand"},"name":"Consignment/Thrift Store"},"shop/shoes":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"shoes"},"name":"Shoe Store"},"shop/sports":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"sports"},"name":"Sporting Goods Store"},"shop/stationery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["card","paper"],"tags":{"shop":"stationery"},"name":"Stationery Store"},"shop/storage_rental":{"icon":"shop","fields":["operator","address","building","opening_hours"],"geometry":["point","area"],"tags":{"shop":"storage_rental"},"name":"Storage Rental"},"shop/supermarket":{"icon":"grocery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["grocery","store","shop"],"tags":{"shop":"supermarket"},"name":"Supermarket"},"shop/tailor":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["clothes","suit"],"tags":{"shop":"tailor"},"name":"Tailor"},"shop/tattoo":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tattoo"},"name":"Tattoo Parlor"},"shop/tea":{"icon":"teahouse","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tea"},"name":"Tea Store"},"shop/ticket":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"ticket"},"name":"Ticket Seller"},"shop/tobacco":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tobacco"},"name":"Tobacco Shop"},"shop/toys":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"toys"},"name":"Toy Store"},"shop/travel_agency":{"icon":"suitcase","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"travel_agency"},"name":"Travel Agency"},"shop/tyres":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tyres"},"name":"Tire Store"},"shop/vacuum_cleaner":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"vacuum_cleaner"},"name":"Vacuum Cleaner Store"},"shop/variety_store":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"variety_store"},"name":"Variety Store"},"shop/video_games":{"icon":"gaming","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"video_games"},"name":"Video Game Store"},"shop/video":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["DVD"],"tags":{"shop":"video"},"name":"Video Store"},"shop/watches":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"watches"},"name":"Watches Shop"},"shop/water_sports":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"water_sports"},"name":"Watersport/Swim Shop"},"shop/weapons":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ammo","gun","knife","knives"],"tags":{"shop":"weapons"},"name":"Weapon Shop"},"shop/window_blind":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"window_blind"},"name":"Window Blind Store"},"shop/wine":{"icon":"alcohol-shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"wine"},"name":"Wine Shop"},"tourism":{"icon":"attraction","fields":["tourism"],"geometry":["point","vertex","area"],"tags":{"tourism":"*"},"name":"Tourism"},"tourism/alpine_hut":{"icon":"lodging","fields":["operator","address","building_area","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"alpine_hut"},"name":"Alpine Hut"},"tourism/apartment":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"apartment"},"name":"Guest Apartment / Condo"},"tourism/aquarium":{"icon":"aquarium","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["fish","sea","water"],"tags":{"tourism":"aquarium"},"name":"Aquarium"},"tourism/artwork":{"icon":"art-gallery","fields":["artwork_type","artist"],"geometry":["point","vertex","area"],"tags":{"tourism":"artwork"},"terms":["mural","sculpture","statue"],"name":"Artwork"},"tourism/attraction":{"icon":"monument","fields":["operator","address"],"geometry":["point","vertex","area"],"tags":{"tourism":"attraction"},"name":"Tourist Attraction"},"tourism/camp_site":{"icon":"campsite","fields":["operator","address","capacity","fee","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"terms":["tent","rv"],"tags":{"tourism":"camp_site"},"name":"Campground"},"tourism/caravan_site":{"icon":"bus","fields":["operator","address","capacity","fee","sanitary_dump_station","power_supply","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"terms":["Motor Home","Camper"],"tags":{"tourism":"caravan_site"},"name":"RV Park"},"tourism/chalet":{"icon":"lodging","fields":["operator","address","building_area","smoking","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"chalet"},"name":"Chalet"},"tourism/gallery":{"icon":"art-gallery","fields":["artwork_type","operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["art*","exhibit*","paint*","photo*","sculpt*"],"tags":{"tourism":"gallery"},"name":"Art Gallery"},"tourism/guest_house":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"guest_house"},"terms":["B&B","Bed and Breakfast"],"name":"Guest House"},"tourism/hostel":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"hostel"},"name":"Hostel"},"tourism/hotel":{"icon":"lodging","fields":["operator","address","building_area","smoking","stars","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"hotel"},"name":"Hotel"},"tourism/information":{"icon":"information","fields":["information","operator","address","building_area"],"geometry":["point","vertex","area"],"tags":{"tourism":"information"},"name":"Information"},"tourism/information/board":{"icon":"information","fields":["operator","board_type"],"geometry":["point","vertex"],"tags":{"tourism":"information","information":"board"},"reference":{"key":"information","value":"board"},"name":"Information Board"},"tourism/information/guidepost":{"icon":"information","fields":["operator","ref"],"geometry":["point","vertex"],"tags":{"tourism":"information","information":"guidepost"},"reference":{"key":"information","value":"guidepost"},"name":"Guidepost"},"tourism/information/map":{"icon":"information","fields":["operator","map_type","map_size"],"geometry":["point","vertex"],"tags":{"tourism":"information","information":"map"},"reference":{"key":"information","value":"map"},"name":"Map"},"tourism/information/office":{"icon":"information","fields":["operator","address","building_area"],"geometry":["point","vertex","area"],"tags":{"tourism":"information","information":"office"},"reference":{"key":"information","value":"office"},"name":"Tourist Information Office"},"tourism/motel":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"motel"},"name":"Motel"},"tourism/museum":{"icon":"museum","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["art*","exhibit*","gallery","foundation","hall","institution","paint*","photo*","sculpt*"],"tags":{"tourism":"museum"},"name":"Museum"},"tourism/picnic_site":{"icon":"picnic-site","fields":["operator","address","smoking"],"geometry":["point","vertex","area"],"terms":["camp"],"tags":{"tourism":"picnic_site"},"name":"Picnic Site"},"tourism/theme_park":{"icon":"amusement-park","fields":["operator","address","opening_hours"],"geometry":["point","area"],"tags":{"tourism":"theme_park"},"name":"Theme Park"},"tourism/viewpoint":{"icon":"poi-binoculars","geometry":["point","vertex"],"tags":{"tourism":"viewpoint"},"name":"Viewpoint"},"tourism/zoo":{"icon":"zoo","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["animal"],"tags":{"tourism":"zoo"},"name":"Zoo"},"traffic_calming":{"icon":"poi-warning","fields":["traffic_calming","parallel_direction"],"geometry":["vertex","line"],"tags":{"traffic_calming":"*"},"terms":["bump","hump","slow","speed"],"name":"Traffic Calming"},"traffic_calming/bump":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["hump","speed","slow"],"tags":{"traffic_calming":"bump"},"name":"Speed Bump"},"traffic_calming/chicane":{"icon":"poi-warning","fields":["parallel_direction"],"geometry":["vertex","line"],"terms":["driveway link","speed","slow"],"tags":{"traffic_calming":"chicane"},"name":"Traffic Chicane"},"traffic_calming/choker":{"icon":"poi-warning","fields":["parallel_direction"],"geometry":["vertex","line"],"terms":["speed","slow"],"tags":{"traffic_calming":"choker"},"name":"Traffic Choker"},"traffic_calming/cushion":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["bump","hump","speed","slow"],"tags":{"traffic_calming":"cushion"},"name":"Speed Cushion"},"traffic_calming/dip":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["speed","slow"],"tags":{"traffic_calming":"dip"},"name":"Dip"},"traffic_calming/hump":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["bump","speed","slow"],"tags":{"traffic_calming":"hump"},"name":"Speed Hump"},"traffic_calming/island":{"icon":"poi-warning","geometry":["vertex"],"terms":["circle","roundabout","slow"],"tags":{"traffic_calming":"island"},"name":"Traffic Island"},"traffic_calming/rumble_strip":{"icon":"poi-warning","fields":["parallel_direction"],"geometry":["vertex","line"],"terms":["audible lines","sleeper lines","growlers"],"tags":{"traffic_calming":"rumble_strip"},"name":"Rumble Strip"},"traffic_calming/table":{"icon":"poi-warning","fields":["surface"],"geometry":["vertex","line"],"terms":["flat top","hump","speed","slow"],"tags":{"highway":"crossing","traffic_calming":"table"},"name":"Raised Pedestrian Crossing"},"type/multipolygon":{"geometry":["area","relation"],"tags":{"type":"multipolygon"},"removeTags":{},"name":"Multipolygon","icon":"multipolygon","searchable":false,"matchScore":0.1},"type/boundary":{"geometry":["relation"],"tags":{"type":"boundary"},"name":"Boundary","icon":"boundary","fields":["boundary"]},"type/boundary/administrative":{"icon":"boundary","fields":["admin_level"],"geometry":["relation"],"tags":{"type":"boundary","boundary":"administrative"},"reference":{"key":"boundary","value":"administrative"},"name":"Administrative Boundary"},"type/restriction":{"geometry":["relation"],"tags":{"type":"restriction"},"name":"Restriction","icon":"restriction","fields":["restriction","except"]},"type/restriction/no_left_turn":{"name":"No Left Turn","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_left_turn"},"fields":["except"],"icon":"restriction-no-left-turn"},"type/restriction/no_right_turn":{"name":"No Right Turn","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_right_turn"},"fields":["except"],"icon":"restriction-no-right-turn"},"type/restriction/no_straight_on":{"name":"No Straight On","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_straight_on"},"fields":["except"],"icon":"restriction-no-straight-on"},"type/restriction/no_u_turn":{"name":"No U-turn","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_u_turn"},"fields":["except"],"icon":"restriction-no-u-turn"},"type/restriction/only_left_turn":{"name":"Left Turn Only","geometry":["relation"],"tags":{"type":"restriction","restriction":"only_left_turn"},"fields":["except"],"icon":"restriction-only-left-turn"},"type/restriction/only_right_turn":{"name":"Right Turn Only","geometry":["relation"],"tags":{"type":"restriction","restriction":"only_right_turn"},"fields":["except"],"icon":"restriction-only-right-turn"},"type/restriction/only_straight_on":{"name":"No Turns","geometry":["relation"],"tags":{"type":"restriction","restriction":"only_straight_on"},"fields":["except"],"icon":"restriction-only-straight-on"},"type/route_master":{"geometry":["relation"],"tags":{"type":"route_master"},"name":"Route Master","icon":"route-master","fields":["route_master","ref","operator","network"]},"type/route":{"geometry":["relation"],"tags":{"type":"route"},"name":"Route","icon":"route","fields":["route","ref","operator","network"]},"type/route/bicycle":{"geometry":["relation"],"tags":{"type":"route","route":"bicycle"},"name":"Cycle Route","icon":"route-bicycle","fields":["ref","network_bicycle","cycle_network"]},"type/route/bus":{"geometry":["relation"],"tags":{"type":"route","route":"bus"},"name":"Bus Route","icon":"route-bus","fields":["ref","operator","network"]},"type/route/detour":{"geometry":["relation"],"tags":{"type":"route","route":"detour"},"name":"Detour Route","icon":"route-detour","fields":["ref"]},"type/route/ferry":{"geometry":["relation"],"tags":{"type":"route","route":"ferry"},"name":"Ferry Route","icon":"route-ferry","fields":["ref","operator","network"]},"type/route/foot":{"geometry":["relation"],"tags":{"type":"route","route":"foot"},"name":"Foot Route","icon":"route-foot","fields":["ref","operator","network_foot"]},"type/route/hiking":{"geometry":["relation"],"tags":{"type":"route","route":"hiking"},"name":"Hiking Route","icon":"route-foot","fields":["ref","operator","network_foot"]},"type/route/horse":{"geometry":["relation"],"tags":{"type":"route","route":"horse"},"name":"Riding Route","icon":"route-horse","fields":["ref","operator","network_horse"]},"type/route/pipeline":{"geometry":["relation"],"tags":{"type":"route","route":"pipeline"},"name":"Pipeline Route","icon":"route-pipeline","fields":["ref","operator"]},"type/route/power":{"geometry":["relation"],"tags":{"type":"route","route":"power"},"name":"Power Route","icon":"route-power","fields":["ref","operator"]},"type/route/road":{"geometry":["relation"],"tags":{"type":"route","route":"road"},"name":"Road Route","icon":"route-road","fields":["ref","network_road"]},"type/route/train":{"geometry":["relation"],"tags":{"type":"route","route":"train"},"name":"Train Route","icon":"route-train","fields":["ref","operator","network"]},"type/route/tram":{"geometry":["relation"],"tags":{"type":"route","route":"tram"},"name":"Tram Route","icon":"route-tram","fields":["ref","operator","network"]},"type/site":{"geometry":["relation"],"tags":{"type":"site"},"name":"Site","icon":"relation","fields":["site"]},"vertex":{"name":"Other","tags":{},"geometry":["vertex"],"matchScore":0.1},"waterway/boatyard":{"icon":"harbor","fields":["operator"],"geometry":["area","vertex","point"],"tags":{"waterway":"boatyard"},"name":"Boatyard"},"waterway/canal":{"icon":"waterway-canal","fields":["width"],"geometry":["line"],"tags":{"waterway":"canal"},"name":"Canal"},"waterway/dam":{"icon":"dam","geometry":["point","vertex","line","area"],"tags":{"waterway":"dam"},"name":"Dam"},"waterway/ditch":{"icon":"waterway-ditch","fields":["tunnel"],"geometry":["line"],"tags":{"waterway":"ditch"},"name":"Ditch"},"waterway/dock":{"icon":"harbor","fields":["dock","operator"],"geometry":["area","vertex","point"],"terms":["boat","ship","vessel","marine"],"tags":{"waterway":"dock"},"name":"Wet Dock / Dry Dock"},"waterway/drain":{"icon":"waterway-stream","fields":["tunnel"],"geometry":["line"],"tags":{"waterway":"drain"},"name":"Drain"},"waterway/fuel":{"icon":"fuel","fields":["operator","address","opening_hours","fuel_multi"],"geometry":["point","area"],"terms":["petrol","gas","diesel","boat"],"tags":{"waterway":"fuel"},"name":"Marine Fuel Station"},"waterway/river":{"icon":"waterway-river","fields":["tunnel","width"],"geometry":["line"],"terms":["beck","branch","brook","course","creek","estuary","rill","rivulet","run","runnel","stream","tributary","watercourse"],"tags":{"waterway":"river"},"name":"River"},"waterway/riverbank":{"icon":"water","geometry":["area"],"tags":{"waterway":"riverbank"},"name":"Riverbank"},"waterway/sanitary_dump_station":{"icon":"poi-storage-tank","fields":["operator","access_toilets","fee","water_point"],"geometry":["point","vertex","area"],"terms":["Boat","Watercraft","Sanitary","Dump Station","Pumpout","Pump out","Elsan","CDP","CTDP","Chemical Toilet"],"tags":{"waterway":"sanitary_dump_station"},"name":"Marine Toilet Disposal"},"waterway/stream":{"icon":"waterway-stream","fields":["tunnel","width"],"geometry":["line"],"terms":["beck","branch","brook","burn","course","creek","current","drift","flood","flow","freshet","race","rill","rindle","rivulet","run","runnel","rush","spate","spritz","surge","tide","torrent","tributary","watercourse"],"tags":{"waterway":"stream"},"name":"Stream"},"waterway/water_point":{"icon":"drinking-water","geometry":["area","vertex","point"],"tags":{"waterway":"water_point"},"name":"Marine Drinking Water"},"waterway/waterfall":{"icon":"water","fields":["height","width"],"geometry":["vertex"],"terms":["fall"],"tags":{"waterway":"waterfall"},"name":"Waterfall"},"waterway/weir":{"icon":"dam","geometry":["vertex","line"],"tags":{"waterway":"weir"},"name":"Weir"},"amenity/fuel/76":{"tags":{"name":"76","amenity":"fuel"},"name":"76","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Neste":{"tags":{"name":"Neste","amenity":"fuel"},"name":"Neste","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/BP":{"tags":{"name":"BP","amenity":"fuel"},"name":"BP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Shell":{"tags":{"name":"Shell","amenity":"fuel"},"name":"Shell","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Agip":{"tags":{"name":"Agip","amenity":"fuel"},"name":"Agip","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Migrol":{"tags":{"name":"Migrol","amenity":"fuel"},"name":"Migrol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Avia":{"tags":{"name":"Avia","amenity":"fuel"},"name":"Avia","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Texaco":{"tags":{"name":"Texaco","amenity":"fuel"},"name":"Texaco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Total":{"tags":{"name":"Total","amenity":"fuel"},"name":"Total","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Statoil":{"tags":{"name":"Statoil","amenity":"fuel"},"name":"Statoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Esso":{"tags":{"name":"Esso","amenity":"fuel"},"name":"Esso","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Jet":{"tags":{"name":"Jet","amenity":"fuel"},"name":"Jet","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Avanti":{"tags":{"name":"Avanti","amenity":"fuel"},"name":"Avanti","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OMV":{"tags":{"name":"OMV","amenity":"fuel"},"name":"OMV","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Aral":{"tags":{"name":"Aral","amenity":"fuel"},"name":"Aral","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/JET":{"tags":{"name":"JET","amenity":"fuel"},"name":"JET","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/United":{"tags":{"name":"United","amenity":"fuel"},"name":"United","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Mobil":{"tags":{"name":"Mobil","amenity":"fuel"},"name":"Mobil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Caltex":{"tags":{"name":"Caltex","amenity":"fuel"},"name":"Caltex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sunoco":{"tags":{"name":"Sunoco","amenity":"fuel"},"name":"Sunoco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Q8":{"tags":{"name":"Q8","amenity":"fuel"},"name":"Q8","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ARAL":{"tags":{"name":"ARAL","amenity":"fuel"},"name":"ARAL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CEPSA":{"tags":{"name":"CEPSA","amenity":"fuel"},"name":"CEPSA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/BFT":{"tags":{"name":"BFT","amenity":"fuel"},"name":"BFT","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petron":{"tags":{"name":"Petron","amenity":"fuel"},"name":"Petron","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Total Access":{"tags":{"name":"Total Access","amenity":"fuel"},"name":"Total Access","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Elf":{"tags":{"name":"Elf","amenity":"fuel"},"name":"Elf","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Station Service E. Leclerc":{"tags":{"name":"Station Service E. Leclerc","amenity":"fuel"},"name":"Station Service E. Leclerc","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Shell Express":{"tags":{"name":"Shell Express","amenity":"fuel"},"name":"Shell Express","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Hess":{"tags":{"name":"Hess","amenity":"fuel"},"name":"Hess","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Flying V":{"tags":{"name":"Flying V","amenity":"fuel"},"name":"Flying V","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/bft":{"tags":{"name":"bft","amenity":"fuel"},"name":"bft","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Gulf":{"tags":{"name":"Gulf","amenity":"fuel"},"name":"Gulf","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/PTT":{"tags":{"name":"PTT","amenity":"fuel"},"name":"PTT","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/St1":{"tags":{"name":"St1","amenity":"fuel"},"name":"St1","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Teboil":{"tags":{"name":"Teboil","amenity":"fuel"},"name":"Teboil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/HEM":{"tags":{"name":"HEM","amenity":"fuel"},"name":"HEM","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/GALP":{"tags":{"name":"GALP","amenity":"fuel"},"name":"GALP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OK":{"tags":{"name":"OK","amenity":"fuel"},"name":"OK","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ÖMV":{"tags":{"name":"ÖMV","amenity":"fuel"},"name":"ÖMV","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tinq":{"tags":{"name":"Tinq","amenity":"fuel"},"name":"Tinq","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OKQ8":{"tags":{"name":"OKQ8","amenity":"fuel"},"name":"OKQ8","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Repsol":{"tags":{"name":"Repsol","amenity":"fuel"},"name":"Repsol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Westfalen":{"tags":{"name":"Westfalen","amenity":"fuel"},"name":"Westfalen","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Esso Express":{"tags":{"name":"Esso Express","amenity":"fuel"},"name":"Esso Express","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tamoil":{"tags":{"name":"Tamoil","amenity":"fuel"},"name":"Tamoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Engen":{"tags":{"name":"Engen","amenity":"fuel"},"name":"Engen","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sasol":{"tags":{"name":"Sasol","amenity":"fuel"},"name":"Sasol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Topaz":{"tags":{"name":"Topaz","amenity":"fuel"},"name":"Topaz","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/LPG":{"tags":{"name":"LPG","amenity":"fuel"},"name":"LPG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Orlen":{"tags":{"name":"Orlen","amenity":"fuel"},"name":"Orlen","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Oilibya":{"tags":{"name":"Oilibya","amenity":"fuel"},"name":"Oilibya","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tango":{"tags":{"name":"Tango","amenity":"fuel"},"name":"Tango","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Star":{"tags":{"name":"Star","amenity":"fuel"},"name":"Star","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Петрол":{"tags":{"name":"Петрол","amenity":"fuel"},"name":"Петрол","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Cepsa":{"tags":{"name":"Cepsa","amenity":"fuel"},"name":"Cepsa","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OIL!":{"tags":{"name":"OIL!","amenity":"fuel"},"name":"OIL!","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Ultramar":{"tags":{"name":"Ultramar","amenity":"fuel"},"name":"Ultramar","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Irving":{"tags":{"name":"Irving","amenity":"fuel"},"name":"Irving","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Lukoil":{"tags":{"name":"Lukoil","amenity":"fuel"},"name":"Lukoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petro-Canada":{"tags":{"name":"Petro-Canada","amenity":"fuel"},"name":"Petro-Canada","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Agrola":{"tags":{"name":"Agrola","amenity":"fuel"},"name":"Agrola","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Husky":{"tags":{"name":"Husky","amenity":"fuel"},"name":"Husky","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Slovnaft":{"tags":{"name":"Slovnaft","amenity":"fuel"},"name":"Slovnaft","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sheetz":{"tags":{"name":"Sheetz","amenity":"fuel"},"name":"Sheetz","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Mol":{"tags":{"name":"Mol","amenity":"fuel"},"name":"Mol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petronas":{"tags":{"name":"Petronas","amenity":"fuel"},"name":"Petronas","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Газпромнефть":{"tags":{"name":"Газпромнефть","amenity":"fuel"},"name":"Газпромнефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Лукойл":{"tags":{"name":"Лукойл","amenity":"fuel"},"name":"Лукойл","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Elan":{"tags":{"name":"Elan","amenity":"fuel"},"name":"Elan","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Роснефть":{"tags":{"name":"Роснефть","amenity":"fuel"},"name":"Роснефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Turmöl":{"tags":{"name":"Turmöl","amenity":"fuel"},"name":"Turmöl","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Neste A24":{"tags":{"name":"Neste A24","amenity":"fuel"},"name":"Neste A24","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Marathon":{"tags":{"name":"Marathon","amenity":"fuel"},"name":"Marathon","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Valero":{"tags":{"name":"Valero","amenity":"fuel"},"name":"Valero","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Eni":{"tags":{"name":"Eni","amenity":"fuel"},"name":"Eni","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Chevron":{"tags":{"name":"Chevron","amenity":"fuel"},"name":"Chevron","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ТНК":{"tags":{"name":"ТНК","amenity":"fuel"},"name":"ТНК","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/REPSOL":{"tags":{"name":"REPSOL","amenity":"fuel"},"name":"REPSOL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/MOL":{"tags":{"name":"MOL","amenity":"fuel"},"name":"MOL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Bliska":{"tags":{"name":"Bliska","amenity":"fuel"},"name":"Bliska","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Api":{"tags":{"name":"Api","amenity":"fuel"},"name":"Api","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Arco":{"tags":{"name":"Arco","amenity":"fuel"},"name":"Arco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Pemex":{"tags":{"name":"Pemex","amenity":"fuel"},"name":"Pemex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Exxon":{"tags":{"name":"Exxon","amenity":"fuel"},"name":"Exxon","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Coles Express":{"tags":{"name":"Coles Express","amenity":"fuel"},"name":"Coles Express","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petrom":{"tags":{"name":"Petrom","amenity":"fuel"},"name":"Petrom","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/PETRONOR":{"tags":{"name":"PETRONOR","amenity":"fuel"},"name":"PETRONOR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Rompetrol":{"tags":{"name":"Rompetrol","amenity":"fuel"},"name":"Rompetrol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Lotos":{"tags":{"name":"Lotos","amenity":"fuel"},"name":"Lotos","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ОМВ":{"tags":{"name":"ОМВ","amenity":"fuel"},"name":"ОМВ","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/BR":{"tags":{"name":"BR","amenity":"fuel"},"name":"BR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Copec":{"tags":{"name":"Copec","amenity":"fuel"},"name":"Copec","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petrobras":{"tags":{"name":"Petrobras","amenity":"fuel"},"name":"Petrobras","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Liberty":{"tags":{"name":"Liberty","amenity":"fuel"},"name":"Liberty","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/IP":{"tags":{"name":"IP","amenity":"fuel"},"name":"IP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Erg":{"tags":{"name":"Erg","amenity":"fuel"},"name":"Erg","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Eneos":{"tags":{"name":"Eneos","amenity":"fuel"},"name":"Eneos","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Citgo":{"tags":{"name":"Citgo","amenity":"fuel"},"name":"Citgo","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Metano":{"tags":{"name":"Metano","amenity":"fuel"},"name":"Metano","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Сургутнефтегаз":{"tags":{"name":"Сургутнефтегаз","amenity":"fuel"},"name":"Сургутнефтегаз","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/EKO":{"tags":{"name":"EKO","amenity":"fuel"},"name":"EKO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Eko":{"tags":{"name":"Eko","amenity":"fuel"},"name":"Eko","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Indipend.":{"tags":{"name":"Indipend.","amenity":"fuel"},"name":"Indipend.","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/IES":{"tags":{"name":"IES","amenity":"fuel"},"name":"IES","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/TotalErg":{"tags":{"name":"TotalErg","amenity":"fuel"},"name":"TotalErg","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Cenex":{"tags":{"name":"Cenex","amenity":"fuel"},"name":"Cenex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ПТК":{"tags":{"name":"ПТК","amenity":"fuel"},"name":"ПТК","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/HP":{"tags":{"name":"HP","amenity":"fuel"},"name":"HP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Phillips 66":{"tags":{"name":"Phillips 66","amenity":"fuel"},"name":"Phillips 66","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CARREFOUR":{"tags":{"name":"CARREFOUR","amenity":"fuel"},"name":"CARREFOUR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ERG":{"tags":{"name":"ERG","amenity":"fuel"},"name":"ERG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Speedway":{"tags":{"name":"Speedway","amenity":"fuel"},"name":"Speedway","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Benzina":{"tags":{"name":"Benzina","amenity":"fuel"},"name":"Benzina","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Татнефть":{"tags":{"name":"Татнефть","amenity":"fuel"},"name":"Татнефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Terpel":{"tags":{"name":"Terpel","amenity":"fuel"},"name":"Terpel","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/WOG":{"tags":{"name":"WOG","amenity":"fuel"},"name":"WOG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Seaoil":{"tags":{"name":"Seaoil","amenity":"fuel"},"name":"Seaoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/АЗС":{"tags":{"name":"АЗС","amenity":"fuel"},"name":"АЗС","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Kwik Trip":{"tags":{"name":"Kwik Trip","amenity":"fuel"},"name":"Kwik Trip","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Pertamina":{"tags":{"name":"Pertamina","amenity":"fuel"},"name":"Pertamina","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/COSMO":{"tags":{"name":"COSMO","amenity":"fuel"},"name":"COSMO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Z":{"tags":{"name":"Z","amenity":"fuel"},"name":"Z","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Indian Oil":{"tags":{"name":"Indian Oil","amenity":"fuel"},"name":"Indian Oil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/АГЗС":{"tags":{"name":"АГЗС","amenity":"fuel"},"name":"АГЗС","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/INA":{"tags":{"name":"INA","amenity":"fuel"},"name":"INA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/JOMO":{"tags":{"name":"JOMO","amenity":"fuel"},"name":"JOMO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Holiday":{"tags":{"name":"Holiday","amenity":"fuel"},"name":"Holiday","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/YPF":{"tags":{"name":"YPF","amenity":"fuel"},"name":"YPF","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/IDEMITSU":{"tags":{"name":"IDEMITSU","amenity":"fuel"},"name":"IDEMITSU","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ENEOS":{"tags":{"name":"ENEOS","amenity":"fuel"},"name":"ENEOS","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Bharat Petroleum":{"tags":{"name":"Bharat Petroleum","amenity":"fuel"},"name":"Bharat Petroleum","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CAMPSA":{"tags":{"name":"CAMPSA","amenity":"fuel"},"name":"CAMPSA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Casey's General Store":{"tags":{"name":"Casey's General Store","amenity":"fuel"},"name":"Casey's General Store","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Башнефть":{"tags":{"name":"Башнефть","amenity":"fuel"},"name":"Башнефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Kangaroo":{"tags":{"name":"Kangaroo","amenity":"fuel"},"name":"Kangaroo","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/コスモ石油 (COSMO)":{"tags":{"name":"コスモ石油 (COSMO)","amenity":"fuel"},"name":"コスモ石油 (COSMO)","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/MEROIL":{"tags":{"name":"MEROIL","amenity":"fuel"},"name":"MEROIL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/1-2-3":{"tags":{"name":"1-2-3","amenity":"fuel"},"name":"1-2-3","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/出光":{"tags":{"name":"出光","name:en":"IDEMITSU","amenity":"fuel"},"name":"出光","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/НК Альянс":{"tags":{"name":"НК Альянс","amenity":"fuel"},"name":"НК Альянс","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sinclair":{"tags":{"name":"Sinclair","amenity":"fuel"},"name":"Sinclair","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Conoco":{"tags":{"name":"Conoco","amenity":"fuel"},"name":"Conoco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/SPBU":{"tags":{"name":"SPBU","amenity":"fuel"},"name":"SPBU","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Макпетрол":{"tags":{"name":"Макпетрол","amenity":"fuel"},"name":"Макпетрол","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto Ipiranga":{"tags":{"name":"Posto Ipiranga","amenity":"fuel"},"name":"Posto Ipiranga","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto Shell":{"tags":{"name":"Posto Shell","amenity":"fuel"},"name":"Posto Shell","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Phoenix":{"tags":{"name":"Phoenix","amenity":"fuel"},"name":"Phoenix","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Ipiranga":{"tags":{"name":"Ipiranga","amenity":"fuel"},"name":"Ipiranga","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OKKO":{"tags":{"name":"OKKO","amenity":"fuel"},"name":"OKKO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ОККО":{"tags":{"name":"ОККО","amenity":"fuel"},"name":"ОККО","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/บางจาก":{"tags":{"name":"บางจาก","amenity":"fuel"},"name":"บางจาก","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/QuikTrip":{"tags":{"name":"QuikTrip","amenity":"fuel"},"name":"QuikTrip","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto BR":{"tags":{"name":"Posto BR","amenity":"fuel"},"name":"Posto BR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ป ต ท":{"tags":{"name":"ป ต ท","amenity":"fuel"},"name":"ป ต ท","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ปตท":{"tags":{"name":"ปตท","amenity":"fuel"},"name":"ปตท","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ANP":{"tags":{"name":"ANP","amenity":"fuel"},"name":"ANP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Kum & Go":{"tags":{"name":"Kum & Go","amenity":"fuel"},"name":"Kum & Go","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petrolimex":{"tags":{"name":"Petrolimex","amenity":"fuel"},"name":"Petrolimex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sokimex":{"tags":{"name":"Sokimex","amenity":"fuel"},"name":"Sokimex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tela":{"tags":{"name":"Tela","amenity":"fuel"},"name":"Tela","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto":{"tags":{"name":"Posto","amenity":"fuel"},"name":"Posto","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Укрнафта":{"tags":{"name":"Укрнафта","amenity":"fuel"},"name":"Укрнафта","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Татнефтепродукт":{"tags":{"name":"Татнефтепродукт","amenity":"fuel"},"name":"Татнефтепродукт","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Afriquia":{"tags":{"name":"Afriquia","amenity":"fuel"},"name":"Afriquia","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Murphy USA":{"tags":{"name":"Murphy USA","amenity":"fuel"},"name":"Murphy USA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/昭和シェル (Showa-shell)":{"tags":{"name":"昭和シェル (Showa-shell)","amenity":"fuel"},"name":"昭和シェル (Showa-shell)","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/エネオス":{"tags":{"name":"エネオス","amenity":"fuel"},"name":"エネオス","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CNG":{"tags":{"name":"CNG","amenity":"fuel"},"name":"CNG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/pub/Kings Arms":{"tags":{"name":"Kings Arms","amenity":"pub"},"name":"Kings Arms","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Ship":{"tags":{"name":"The Ship","amenity":"pub"},"name":"The Ship","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The White Horse":{"tags":{"name":"The White Horse","amenity":"pub"},"name":"The White Horse","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The White Hart":{"tags":{"name":"The White Hart","amenity":"pub"},"name":"The White Hart","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Royal Oak":{"tags":{"name":"Royal Oak","amenity":"pub"},"name":"Royal Oak","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Red Lion":{"tags":{"name":"The Red Lion","amenity":"pub"},"name":"The Red Lion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Kings Arms":{"tags":{"name":"The Kings Arms","amenity":"pub"},"name":"The Kings Arms","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Star":{"tags":{"name":"The Star","amenity":"pub"},"name":"The Star","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Anchor":{"tags":{"name":"The Anchor","amenity":"pub"},"name":"The Anchor","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Cross Keys":{"tags":{"name":"The Cross Keys","amenity":"pub"},"name":"The Cross Keys","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Wheatsheaf":{"tags":{"name":"The Wheatsheaf","amenity":"pub"},"name":"The Wheatsheaf","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Crown Inn":{"tags":{"name":"The Crown Inn","amenity":"pub"},"name":"The Crown Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Kings Head":{"tags":{"name":"The Kings Head","amenity":"pub"},"name":"The Kings Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Castle":{"tags":{"name":"The Castle","amenity":"pub"},"name":"The Castle","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Railway":{"tags":{"name":"The Railway","amenity":"pub"},"name":"The Railway","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The White Lion":{"tags":{"name":"The White Lion","amenity":"pub"},"name":"The White Lion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Bell":{"tags":{"name":"The Bell","amenity":"pub"},"name":"The Bell","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Bull":{"tags":{"name":"The Bull","amenity":"pub"},"name":"The Bull","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Plough":{"tags":{"name":"The Plough","amenity":"pub"},"name":"The Plough","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The George":{"tags":{"name":"The George","amenity":"pub"},"name":"The George","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Royal Oak":{"tags":{"name":"The Royal Oak","amenity":"pub"},"name":"The Royal Oak","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Fox":{"tags":{"name":"The Fox","amenity":"pub"},"name":"The Fox","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Prince of Wales":{"tags":{"name":"Prince of Wales","amenity":"pub"},"name":"Prince of Wales","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Rising Sun":{"tags":{"name":"The Rising Sun","amenity":"pub"},"name":"The Rising Sun","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Prince of Wales":{"tags":{"name":"The Prince of Wales","amenity":"pub"},"name":"The Prince of Wales","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Crown":{"tags":{"name":"The Crown","amenity":"pub"},"name":"The Crown","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Chequers":{"tags":{"name":"The Chequers","amenity":"pub"},"name":"The Chequers","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Swan":{"tags":{"name":"The Swan","amenity":"pub"},"name":"The Swan","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Rose and Crown":{"tags":{"name":"Rose and Crown","amenity":"pub"},"name":"Rose and Crown","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Victoria":{"tags":{"name":"The Victoria","amenity":"pub"},"name":"The Victoria","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/New Inn":{"tags":{"name":"New Inn","amenity":"pub"},"name":"New Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Royal Hotel":{"tags":{"name":"Royal Hotel","amenity":"pub"},"name":"Royal Hotel","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Red Lion":{"tags":{"name":"Red Lion","amenity":"pub"},"name":"Red Lion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Cross Keys":{"tags":{"name":"Cross Keys","amenity":"pub"},"name":"Cross Keys","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Greyhound":{"tags":{"name":"The Greyhound","amenity":"pub"},"name":"The Greyhound","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Black Horse":{"tags":{"name":"The Black Horse","amenity":"pub"},"name":"The Black Horse","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The New Inn":{"tags":{"name":"The New Inn","amenity":"pub"},"name":"The New Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Kings Head":{"tags":{"name":"Kings Head","amenity":"pub"},"name":"Kings Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Albion":{"tags":{"name":"The Albion","amenity":"pub"},"name":"The Albion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Angel":{"tags":{"name":"The Angel","amenity":"pub"},"name":"The Angel","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Queens Head":{"tags":{"name":"The Queens Head","amenity":"pub"},"name":"The Queens Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Ship Inn":{"tags":{"name":"The Ship Inn","amenity":"pub"},"name":"The Ship Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Rose & Crown":{"tags":{"name":"Rose & Crown","amenity":"pub"},"name":"Rose & Crown","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Queens Head":{"tags":{"name":"Queens Head","amenity":"pub"},"name":"Queens Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Irish Pub":{"tags":{"name":"Irish Pub","amenity":"pub"},"name":"Irish Pub","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Quick":{"tags":{"name":"Quick","amenity":"fast_food"},"name":"Quick","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/McDonald's":{"tags":{"name":"McDonald's","cuisine":"burger","amenity":"fast_food"},"name":"McDonald's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Subway":{"tags":{"name":"Subway","cuisine":"sandwich","amenity":"fast_food"},"name":"Subway","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Burger King":{"tags":{"name":"Burger King","cuisine":"burger","amenity":"fast_food"},"name":"Burger King","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Ali Baba":{"tags":{"name":"Ali Baba","amenity":"fast_food"},"name":"Ali Baba","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hungry Jacks":{"tags":{"name":"Hungry Jacks","cuisine":"burger","amenity":"fast_food"},"name":"Hungry Jacks","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Red Rooster":{"tags":{"name":"Red Rooster","amenity":"fast_food"},"name":"Red Rooster","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/KFC":{"tags":{"name":"KFC","cuisine":"chicken","amenity":"fast_food"},"name":"KFC","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Domino's Pizza":{"tags":{"name":"Domino's Pizza","cuisine":"pizza","amenity":"fast_food"},"name":"Domino's Pizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Chowking":{"tags":{"name":"Chowking","amenity":"fast_food"},"name":"Chowking","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jollibee":{"tags":{"name":"Jollibee","amenity":"fast_food"},"name":"Jollibee","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hesburger":{"tags":{"name":"Hesburger","amenity":"fast_food"},"name":"Hesburger","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/肯德基":{"tags":{"name":"肯德基","amenity":"fast_food"},"name":"肯德基","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Wendy's":{"tags":{"name":"Wendy's","cuisine":"burger","amenity":"fast_food"},"name":"Wendy's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Tim Hortons":{"tags":{"name":"Tim Hortons","amenity":"fast_food"},"name":"Tim Hortons","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Steers":{"tags":{"name":"Steers","amenity":"fast_food"},"name":"Steers","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hardee's":{"tags":{"name":"Hardee's","cuisine":"burger","amenity":"fast_food"},"name":"Hardee's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Arby's":{"tags":{"name":"Arby's","amenity":"fast_food"},"name":"Arby's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/A&W":{"tags":{"name":"A&W","amenity":"fast_food"},"name":"A&W","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Dairy Queen":{"tags":{"name":"Dairy Queen","amenity":"fast_food"},"name":"Dairy Queen","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hallo Pizza":{"tags":{"name":"Hallo Pizza","amenity":"fast_food"},"name":"Hallo Pizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Fish & Chips":{"tags":{"name":"Fish & Chips","amenity":"fast_food"},"name":"Fish & Chips","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Harvey's":{"tags":{"name":"Harvey's","amenity":"fast_food"},"name":"Harvey's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/麥當勞":{"tags":{"name":"麥當勞","amenity":"fast_food"},"name":"麥當勞","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Pizza Pizza":{"tags":{"name":"Pizza Pizza","amenity":"fast_food"},"name":"Pizza Pizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Kotipizza":{"tags":{"name":"Kotipizza","amenity":"fast_food"},"name":"Kotipizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jack in the Box":{"tags":{"name":"Jack in the Box","cuisine":"burger","amenity":"fast_food"},"name":"Jack in the Box","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Istanbul":{"tags":{"name":"Istanbul","amenity":"fast_food"},"name":"Istanbul","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Kochlöffel":{"tags":{"name":"Kochlöffel","amenity":"fast_food"},"name":"Kochlöffel","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Döner":{"tags":{"name":"Döner","amenity":"fast_food"},"name":"Döner","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Telepizza":{"tags":{"name":"Telepizza","amenity":"fast_food"},"name":"Telepizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Sibylla":{"tags":{"name":"Sibylla","amenity":"fast_food"},"name":"Sibylla","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Carl's Jr.":{"tags":{"name":"Carl's Jr.","cuisine":"burger","amenity":"fast_food"},"name":"Carl's Jr.","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Quiznos":{"tags":{"name":"Quiznos","cuisine":"sandwich","amenity":"fast_food"},"name":"Quiznos","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Wimpy":{"tags":{"name":"Wimpy","amenity":"fast_food"},"name":"Wimpy","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Sonic":{"tags":{"name":"Sonic","cuisine":"burger","amenity":"fast_food"},"name":"Sonic","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Taco Bell":{"tags":{"name":"Taco Bell","cuisine":"mexican","amenity":"fast_food"},"name":"Taco Bell","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Pizza Nova":{"tags":{"name":"Pizza Nova","amenity":"fast_food"},"name":"Pizza Nova","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Papa John's":{"tags":{"name":"Papa John's","cuisine":"pizza","amenity":"fast_food"},"name":"Papa John's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Nordsee":{"tags":{"name":"Nordsee","amenity":"fast_food"},"name":"Nordsee","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Mr. Sub":{"tags":{"name":"Mr. Sub","amenity":"fast_food"},"name":"Mr. Sub","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Макдоналдс":{"tags":{"name":"Макдоналдс","name:en":"McDonald's","amenity":"fast_food"},"name":"Макдоналдс","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Asia Imbiss":{"tags":{"name":"Asia Imbiss","amenity":"fast_food"},"name":"Asia Imbiss","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Chipotle":{"tags":{"name":"Chipotle","cuisine":"mexican","amenity":"fast_food"},"name":"Chipotle","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/マクドナルド":{"tags":{"name":"マクドナルド","name:en":"McDonald's","cuisine":"burger","amenity":"fast_food"},"name":"マクドナルド","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/In-N-Out Burger":{"tags":{"name":"In-N-Out Burger","amenity":"fast_food"},"name":"In-N-Out Burger","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jimmy John's":{"tags":{"name":"Jimmy John's","amenity":"fast_food"},"name":"Jimmy John's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jamba Juice":{"tags":{"name":"Jamba Juice","amenity":"fast_food"},"name":"Jamba Juice","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Робин Сдобин":{"tags":{"name":"Робин Сдобин","amenity":"fast_food"},"name":"Робин Сдобин","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Baskin Robbins":{"tags":{"name":"Baskin Robbins","amenity":"fast_food"},"name":"Baskin Robbins","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/ケンタッキーフライドチキン":{"tags":{"name":"ケンタッキーフライドチキン","name:en":"KFC","cuisine":"chicken","amenity":"fast_food"},"name":"ケンタッキーフライドチキン","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/吉野家":{"tags":{"name":"吉野家","amenity":"fast_food"},"name":"吉野家","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Taco Time":{"tags":{"name":"Taco Time","amenity":"fast_food"},"name":"Taco Time","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/松屋":{"tags":{"name":"松屋","name:en":"Matsuya","amenity":"fast_food"},"name":"松屋","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Little Caesars":{"tags":{"name":"Little Caesars","amenity":"fast_food"},"name":"Little Caesars","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/El Pollo Loco":{"tags":{"name":"El Pollo Loco","amenity":"fast_food"},"name":"El Pollo Loco","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Del Taco":{"tags":{"name":"Del Taco","amenity":"fast_food"},"name":"Del Taco","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/White Castle":{"tags":{"name":"White Castle","amenity":"fast_food"},"name":"White Castle","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Boston Market":{"tags":{"name":"Boston Market","amenity":"fast_food"},"name":"Boston Market","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Chick-fil-A":{"tags":{"name":"Chick-fil-A","cuisine":"chicken","amenity":"fast_food"},"name":"Chick-fil-A","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Panda Express":{"tags":{"name":"Panda Express","cuisine":"chinese","amenity":"fast_food"},"name":"Panda Express","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Whataburger":{"tags":{"name":"Whataburger","amenity":"fast_food"},"name":"Whataburger","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Taco John's":{"tags":{"name":"Taco John's","amenity":"fast_food"},"name":"Taco John's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Теремок":{"tags":{"name":"Теремок","amenity":"fast_food"},"name":"Теремок","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Culver's":{"tags":{"name":"Culver's","amenity":"fast_food"},"name":"Culver's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Five Guys":{"tags":{"name":"Five Guys","amenity":"fast_food"},"name":"Five Guys","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Church's Chicken":{"tags":{"name":"Church's Chicken","amenity":"fast_food"},"name":"Church's Chicken","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Popeye's":{"tags":{"name":"Popeye's","cuisine":"chicken","amenity":"fast_food"},"name":"Popeye's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Long John Silver's":{"tags":{"name":"Long John Silver's","amenity":"fast_food"},"name":"Long John Silver's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Pollo Campero":{"tags":{"name":"Pollo Campero","amenity":"fast_food"},"name":"Pollo Campero","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Zaxby's":{"tags":{"name":"Zaxby's","amenity":"fast_food"},"name":"Zaxby's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/すき家":{"tags":{"name":"すき家","name:en":"SUKIYA","amenity":"fast_food"},"name":"すき家","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/モスバーガー":{"tags":{"name":"モスバーガー","name:en":"MOS BURGER","amenity":"fast_food"},"name":"モスバーガー","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Русский Аппетит":{"tags":{"name":"Русский Аппетит","amenity":"fast_food"},"name":"Русский Аппетит","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/なか卯":{"tags":{"name":"なか卯","amenity":"fast_food"},"name":"なか卯","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Pizza Hut":{"tags":{"name":"Pizza Hut","cuisine":"pizza","amenity":"restaurant"},"name":"Pizza Hut","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Little Chef":{"tags":{"name":"Little Chef","amenity":"restaurant"},"name":"Little Chef","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Adler":{"tags":{"name":"Adler","amenity":"restaurant"},"name":"Adler","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Krone":{"tags":{"name":"Zur Krone","amenity":"restaurant"},"name":"Zur Krone","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Deutsches Haus":{"tags":{"name":"Deutsches Haus","amenity":"restaurant"},"name":"Deutsches Haus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Krone":{"tags":{"name":"Krone","amenity":"restaurant"},"name":"Krone","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Akropolis":{"tags":{"name":"Akropolis","amenity":"restaurant"},"name":"Akropolis","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Schützenhaus":{"tags":{"name":"Schützenhaus","amenity":"restaurant"},"name":"Schützenhaus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kreuz":{"tags":{"name":"Kreuz","amenity":"restaurant"},"name":"Kreuz","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Waldschänke":{"tags":{"name":"Waldschänke","amenity":"restaurant"},"name":"Waldschänke","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Piazza":{"tags":{"name":"La Piazza","amenity":"restaurant"},"name":"La Piazza","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Lamm":{"tags":{"name":"Lamm","amenity":"restaurant"},"name":"Lamm","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Sonne":{"tags":{"name":"Zur Sonne","amenity":"restaurant"},"name":"Zur Sonne","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Linde":{"tags":{"name":"Zur Linde","amenity":"restaurant"},"name":"Zur Linde","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Poseidon":{"tags":{"name":"Poseidon","amenity":"restaurant"},"name":"Poseidon","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Shanghai":{"tags":{"name":"Shanghai","amenity":"restaurant"},"name":"Shanghai","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Red Lobster":{"tags":{"name":"Red Lobster","amenity":"restaurant"},"name":"Red Lobster","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zum Löwen":{"tags":{"name":"Zum Löwen","amenity":"restaurant"},"name":"Zum Löwen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Swiss Chalet":{"tags":{"name":"Swiss Chalet","amenity":"restaurant"},"name":"Swiss Chalet","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Olympia":{"tags":{"name":"Olympia","amenity":"restaurant"},"name":"Olympia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Wagamama":{"tags":{"name":"Wagamama","amenity":"restaurant"},"name":"Wagamama","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Frankie & Benny's":{"tags":{"name":"Frankie & Benny's","amenity":"restaurant"},"name":"Frankie & Benny's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hooters":{"tags":{"name":"Hooters","amenity":"restaurant"},"name":"Hooters","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sternen":{"tags":{"name":"Sternen","amenity":"restaurant"},"name":"Sternen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hirschen":{"tags":{"name":"Hirschen","amenity":"restaurant"},"name":"Hirschen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Denny's":{"tags":{"name":"Denny's","amenity":"restaurant"},"name":"Denny's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Athen":{"tags":{"name":"Athen","amenity":"restaurant"},"name":"Athen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sonne":{"tags":{"name":"Sonne","amenity":"restaurant"},"name":"Sonne","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hirsch":{"tags":{"name":"Hirsch","amenity":"restaurant"},"name":"Hirsch","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Ratskeller":{"tags":{"name":"Ratskeller","amenity":"restaurant"},"name":"Ratskeller","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Cantina":{"tags":{"name":"La Cantina","amenity":"restaurant"},"name":"La Cantina","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Gasthaus Krone":{"tags":{"name":"Gasthaus Krone","amenity":"restaurant"},"name":"Gasthaus Krone","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/El Greco":{"tags":{"name":"El Greco","amenity":"restaurant"},"name":"El Greco","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Gasthof zur Post":{"tags":{"name":"Gasthof zur Post","amenity":"restaurant"},"name":"Gasthof zur Post","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Nando's":{"tags":{"name":"Nando's","amenity":"restaurant"},"name":"Nando's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Löwen":{"tags":{"name":"Löwen","amenity":"restaurant"},"name":"Löwen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Pataterie":{"tags":{"name":"La Pataterie","amenity":"restaurant"},"name":"La Pataterie","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bella Napoli":{"tags":{"name":"Bella Napoli","amenity":"restaurant"},"name":"Bella Napoli","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Pizza Express":{"tags":{"name":"Pizza Express","amenity":"restaurant"},"name":"Pizza Express","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mandarin":{"tags":{"name":"Mandarin","amenity":"restaurant"},"name":"Mandarin","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hong Kong":{"tags":{"name":"Hong Kong","amenity":"restaurant"},"name":"Hong Kong","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zizzi":{"tags":{"name":"Zizzi","amenity":"restaurant"},"name":"Zizzi","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Cracker Barrel":{"tags":{"name":"Cracker Barrel","amenity":"restaurant"},"name":"Cracker Barrel","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Rhodos":{"tags":{"name":"Rhodos","amenity":"restaurant"},"name":"Rhodos","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Lindenhof":{"tags":{"name":"Lindenhof","amenity":"restaurant"},"name":"Lindenhof","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Milano":{"tags":{"name":"Milano","amenity":"restaurant"},"name":"Milano","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Dolce Vita":{"tags":{"name":"Dolce Vita","amenity":"restaurant"},"name":"Dolce Vita","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kirchenwirt":{"tags":{"name":"Kirchenwirt","amenity":"restaurant"},"name":"Kirchenwirt","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kantine":{"tags":{"name":"Kantine","amenity":"restaurant"},"name":"Kantine","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Ochsen":{"tags":{"name":"Ochsen","amenity":"restaurant"},"name":"Ochsen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Spur":{"tags":{"name":"Spur","amenity":"restaurant"},"name":"Spur","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mykonos":{"tags":{"name":"Mykonos","amenity":"restaurant"},"name":"Mykonos","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Lotus":{"tags":{"name":"Lotus","amenity":"restaurant"},"name":"Lotus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Applebee's":{"tags":{"name":"Applebee's","amenity":"restaurant"},"name":"Applebee's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Flunch":{"tags":{"name":"Flunch","amenity":"restaurant"},"name":"Flunch","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Post":{"tags":{"name":"Zur Post","amenity":"restaurant"},"name":"Zur Post","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/China Town":{"tags":{"name":"China Town","amenity":"restaurant"},"name":"China Town","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Dolce Vita":{"tags":{"name":"La Dolce Vita","amenity":"restaurant"},"name":"La Dolce Vita","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Waffle House":{"tags":{"name":"Waffle House","amenity":"restaurant"},"name":"Waffle House","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Delphi":{"tags":{"name":"Delphi","amenity":"restaurant"},"name":"Delphi","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Linde":{"tags":{"name":"Linde","amenity":"restaurant"},"name":"Linde","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Outback Steakhouse":{"tags":{"name":"Outback Steakhouse","amenity":"restaurant"},"name":"Outback Steakhouse","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Dionysos":{"tags":{"name":"Dionysos","amenity":"restaurant"},"name":"Dionysos","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kelsey's":{"tags":{"name":"Kelsey's","amenity":"restaurant"},"name":"Kelsey's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Boston Pizza":{"tags":{"name":"Boston Pizza","amenity":"restaurant"},"name":"Boston Pizza","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bella Italia":{"tags":{"name":"Bella Italia","amenity":"restaurant"},"name":"Bella Italia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sizzler":{"tags":{"name":"Sizzler","amenity":"restaurant"},"name":"Sizzler","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Grüner Baum":{"tags":{"name":"Grüner Baum","amenity":"restaurant"},"name":"Grüner Baum","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Taj Mahal":{"tags":{"name":"Taj Mahal","amenity":"restaurant"},"name":"Taj Mahal","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Rössli":{"tags":{"name":"Rössli","amenity":"restaurant"},"name":"Rössli","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Traube":{"tags":{"name":"Traube","amenity":"restaurant"},"name":"Traube","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Adria":{"tags":{"name":"Adria","amenity":"restaurant"},"name":"Adria","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Red Robin":{"tags":{"name":"Red Robin","amenity":"restaurant"},"name":"Red Robin","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Roma":{"tags":{"name":"Roma","amenity":"restaurant"},"name":"Roma","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/San Marco":{"tags":{"name":"San Marco","amenity":"restaurant"},"name":"San Marco","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hellas":{"tags":{"name":"Hellas","amenity":"restaurant"},"name":"Hellas","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Perla":{"tags":{"name":"La Perla","amenity":"restaurant"},"name":"La Perla","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Vips":{"tags":{"name":"Vips","amenity":"restaurant"},"name":"Vips","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Panera Bread":{"tags":{"name":"Panera Bread","amenity":"restaurant"},"name":"Panera Bread","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Da Vinci":{"tags":{"name":"Da Vinci","amenity":"restaurant"},"name":"Da Vinci","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hippopotamus":{"tags":{"name":"Hippopotamus","amenity":"restaurant"},"name":"Hippopotamus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Prezzo":{"tags":{"name":"Prezzo","amenity":"restaurant"},"name":"Prezzo","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Courtepaille":{"tags":{"name":"Courtepaille","amenity":"restaurant"},"name":"Courtepaille","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hard Rock Cafe":{"tags":{"name":"Hard Rock Cafe","amenity":"restaurant"},"name":"Hard Rock Cafe","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Panorama":{"tags":{"name":"Panorama","amenity":"restaurant"},"name":"Panorama","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/デニーズ":{"tags":{"name":"デニーズ","amenity":"restaurant"},"name":"デニーズ","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sportheim":{"tags":{"name":"Sportheim","amenity":"restaurant"},"name":"Sportheim","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/餃子の王将":{"tags":{"name":"餃子の王将","amenity":"restaurant"},"name":"餃子の王将","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bären":{"tags":{"name":"Bären","amenity":"restaurant"},"name":"Bären","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Alte Post":{"tags":{"name":"Alte Post","amenity":"restaurant"},"name":"Alte Post","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Pizzeria Roma":{"tags":{"name":"Pizzeria Roma","amenity":"restaurant"},"name":"Pizzeria Roma","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/China Garden":{"tags":{"name":"China Garden","amenity":"restaurant"},"name":"China Garden","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Vapiano":{"tags":{"name":"Vapiano","amenity":"restaurant"},"name":"Vapiano","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mamma Mia":{"tags":{"name":"Mamma Mia","amenity":"restaurant"},"name":"Mamma Mia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Schwarzer Adler":{"tags":{"name":"Schwarzer Adler","amenity":"restaurant"},"name":"Schwarzer Adler","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/IHOP":{"tags":{"name":"IHOP","amenity":"restaurant"},"name":"IHOP","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Chili's":{"tags":{"name":"Chili's","amenity":"restaurant"},"name":"Chili's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Asia":{"tags":{"name":"Asia","amenity":"restaurant"},"name":"Asia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Olive Garden":{"tags":{"name":"Olive Garden","amenity":"restaurant"},"name":"Olive Garden","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/TGI Friday's":{"tags":{"name":"TGI Friday's","amenity":"restaurant"},"name":"TGI Friday's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Friendly's":{"tags":{"name":"Friendly's","amenity":"restaurant"},"name":"Friendly's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Buffalo Grill":{"tags":{"name":"Buffalo Grill","amenity":"restaurant"},"name":"Buffalo Grill","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Texas Roadhouse":{"tags":{"name":"Texas Roadhouse","amenity":"restaurant"},"name":"Texas Roadhouse","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/ガスト":{"tags":{"name":"ガスト","name:en":"Gusto","amenity":"restaurant"},"name":"ガスト","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sakura":{"tags":{"name":"Sakura","amenity":"restaurant"},"name":"Sakura","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mensa":{"tags":{"name":"Mensa","amenity":"restaurant"},"name":"Mensa","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/The Keg":{"tags":{"name":"The Keg","amenity":"restaurant"},"name":"The Keg","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/サイゼリヤ":{"tags":{"name":"サイゼリヤ","amenity":"restaurant"},"name":"サイゼリヤ","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Strada":{"tags":{"name":"La Strada","amenity":"restaurant"},"name":"La Strada","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Village Inn":{"tags":{"name":"Village Inn","amenity":"restaurant"},"name":"Village Inn","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Buffalo Wild Wings":{"tags":{"name":"Buffalo Wild Wings","amenity":"restaurant"},"name":"Buffalo Wild Wings","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Peking":{"tags":{"name":"Peking","amenity":"restaurant"},"name":"Peking","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Round Table Pizza":{"tags":{"name":"Round Table Pizza","amenity":"restaurant"},"name":"Round Table Pizza","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/California Pizza Kitchen":{"tags":{"name":"California Pizza Kitchen","amenity":"restaurant"},"name":"California Pizza Kitchen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Якитория":{"tags":{"name":"Якитория","amenity":"restaurant"},"name":"Якитория","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Golden Corral":{"tags":{"name":"Golden Corral","amenity":"restaurant"},"name":"Golden Corral","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Perkins":{"tags":{"name":"Perkins","amenity":"restaurant"},"name":"Perkins","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Ruby Tuesday":{"tags":{"name":"Ruby Tuesday","amenity":"restaurant"},"name":"Ruby Tuesday","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Shari's":{"tags":{"name":"Shari's","amenity":"restaurant"},"name":"Shari's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bob Evans":{"tags":{"name":"Bob Evans","amenity":"restaurant"},"name":"Bob Evans","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/바다횟집 (Bada Fish Restaurant)":{"tags":{"name":"바다횟집 (Bada Fish Restaurant)","amenity":"restaurant"},"name":"바다횟집 (Bada Fish Restaurant)","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mang Inasal":{"tags":{"name":"Mang Inasal","amenity":"restaurant"},"name":"Mang Inasal","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Евразия":{"tags":{"name":"Евразия","amenity":"restaurant"},"name":"Евразия","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/ジョナサン":{"tags":{"name":"ジョナサン","amenity":"restaurant"},"name":"ジョナサン","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Longhorn Steakhouse":{"tags":{"name":"Longhorn Steakhouse","amenity":"restaurant"},"name":"Longhorn Steakhouse","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/bank/Chase":{"tags":{"name":"Chase","amenity":"bank"},"name":"Chase","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Commonwealth Bank":{"tags":{"name":"Commonwealth Bank","amenity":"bank"},"name":"Commonwealth Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Citibank":{"tags":{"name":"Citibank","amenity":"bank"},"name":"Citibank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/HSBC":{"tags":{"name":"HSBC","amenity":"bank"},"name":"HSBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Barclays":{"tags":{"name":"Barclays","amenity":"bank"},"name":"Barclays","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Westpac":{"tags":{"name":"Westpac","amenity":"bank"},"name":"Westpac","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/NAB":{"tags":{"name":"NAB","amenity":"bank"},"name":"NAB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ANZ":{"tags":{"name":"ANZ","amenity":"bank"},"name":"ANZ","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Lloyds Bank":{"tags":{"name":"Lloyds Bank","amenity":"bank"},"name":"Lloyds Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Landbank":{"tags":{"name":"Landbank","amenity":"bank"},"name":"Landbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparkasse":{"tags":{"name":"Sparkasse","amenity":"bank"},"name":"Sparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/UCPB":{"tags":{"name":"UCPB","amenity":"bank"},"name":"UCPB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PNB":{"tags":{"name":"PNB","amenity":"bank"},"name":"PNB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Metrobank":{"tags":{"name":"Metrobank","amenity":"bank"},"name":"Metrobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BDO":{"tags":{"name":"BDO","amenity":"bank"},"name":"BDO","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Volksbank":{"tags":{"name":"Volksbank","amenity":"bank"},"name":"Volksbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BPI":{"tags":{"name":"BPI","amenity":"bank"},"name":"BPI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Postbank":{"tags":{"name":"Postbank","amenity":"bank"},"name":"Postbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/NatWest":{"tags":{"name":"NatWest","amenity":"bank"},"name":"NatWest","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Raiffeisenbank":{"tags":{"name":"Raiffeisenbank","amenity":"bank"},"name":"Raiffeisenbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Yorkshire Bank":{"tags":{"name":"Yorkshire Bank","amenity":"bank"},"name":"Yorkshire Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ABSA":{"tags":{"name":"ABSA","amenity":"bank"},"name":"ABSA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Standard Bank":{"tags":{"name":"Standard Bank","amenity":"bank"},"name":"Standard Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/FNB":{"tags":{"name":"FNB","amenity":"bank"},"name":"FNB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Deutsche Bank":{"tags":{"name":"Deutsche Bank","amenity":"bank"},"name":"Deutsche Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/SEB":{"tags":{"name":"SEB","amenity":"bank"},"name":"SEB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Commerzbank":{"tags":{"name":"Commerzbank","amenity":"bank"},"name":"Commerzbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Targobank":{"tags":{"name":"Targobank","amenity":"bank"},"name":"Targobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ABN AMRO":{"tags":{"name":"ABN AMRO","amenity":"bank"},"name":"ABN AMRO","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Handelsbanken":{"tags":{"name":"Handelsbanken","amenity":"bank"},"name":"Handelsbanken","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Swedbank":{"tags":{"name":"Swedbank","amenity":"bank"},"name":"Swedbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Kreissparkasse":{"tags":{"name":"Kreissparkasse","amenity":"bank"},"name":"Kreissparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/UniCredit Bank":{"tags":{"name":"UniCredit Bank","amenity":"bank"},"name":"UniCredit Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Monte dei Paschi di Siena":{"tags":{"name":"Monte dei Paschi di Siena","amenity":"bank"},"name":"Monte dei Paschi di Siena","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Rural":{"tags":{"name":"Caja Rural","amenity":"bank"},"name":"Caja Rural","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Dresdner Bank":{"tags":{"name":"Dresdner Bank","amenity":"bank"},"name":"Dresdner Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparda-Bank":{"tags":{"name":"Sparda-Bank","amenity":"bank"},"name":"Sparda-Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/VÚB":{"tags":{"name":"VÚB","amenity":"bank"},"name":"VÚB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Slovenská sporiteľňa":{"tags":{"name":"Slovenská sporiteľňa","amenity":"bank"},"name":"Slovenská sporiteľňa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of Montreal":{"tags":{"name":"Bank of Montreal","amenity":"bank"},"name":"Bank of Montreal","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/KBC":{"tags":{"name":"KBC","amenity":"bank"},"name":"KBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Royal Bank of Scotland":{"tags":{"name":"Royal Bank of Scotland","amenity":"bank"},"name":"Royal Bank of Scotland","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/TSB":{"tags":{"name":"TSB","amenity":"bank"},"name":"TSB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/US Bank":{"tags":{"name":"US Bank","amenity":"bank"},"name":"US Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/HypoVereinsbank":{"tags":{"name":"HypoVereinsbank","amenity":"bank"},"name":"HypoVereinsbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank Austria":{"tags":{"name":"Bank Austria","amenity":"bank"},"name":"Bank Austria","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ING":{"tags":{"name":"ING","amenity":"bank"},"name":"ING","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Erste Bank":{"tags":{"name":"Erste Bank","amenity":"bank"},"name":"Erste Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/CIBC":{"tags":{"name":"CIBC","amenity":"bank"},"name":"CIBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Scotiabank":{"tags":{"name":"Scotiabank","amenity":"bank"},"name":"Scotiabank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caisse d'Épargne":{"tags":{"name":"Caisse d'Épargne","amenity":"bank"},"name":"Caisse d'Épargne","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Santander":{"tags":{"name":"Santander","amenity":"bank"},"name":"Santander","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of Scotland":{"tags":{"name":"Bank of Scotland","amenity":"bank"},"name":"Bank of Scotland","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/TD Canada Trust":{"tags":{"name":"TD Canada Trust","amenity":"bank"},"name":"TD Canada Trust","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BMO":{"tags":{"name":"BMO","amenity":"bank"},"name":"BMO","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Danske Bank":{"tags":{"name":"Danske Bank","amenity":"bank"},"name":"Danske Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/OTP":{"tags":{"name":"OTP","amenity":"bank"},"name":"OTP","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit Agricole":{"tags":{"name":"Crédit Agricole","amenity":"bank"},"name":"Crédit Agricole","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/LCL":{"tags":{"name":"LCL","amenity":"bank"},"name":"LCL","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/VR-Bank":{"tags":{"name":"VR-Bank","amenity":"bank"},"name":"VR-Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ČSOB":{"tags":{"name":"ČSOB","amenity":"bank"},"name":"ČSOB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Česká spořitelna":{"tags":{"name":"Česká spořitelna","amenity":"bank"},"name":"Česká spořitelna","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNP":{"tags":{"name":"BNP","amenity":"bank"},"name":"BNP","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Royal Bank":{"tags":{"name":"Royal Bank","amenity":"bank"},"name":"Royal Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Nationwide":{"tags":{"name":"Nationwide","amenity":"bank"},"name":"Nationwide","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Halifax":{"tags":{"name":"Halifax","amenity":"bank"},"name":"Halifax","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BAWAG PSK":{"tags":{"name":"BAWAG PSK","amenity":"bank"},"name":"BAWAG PSK","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/National Bank":{"tags":{"name":"National Bank","amenity":"bank"},"name":"National Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Nedbank":{"tags":{"name":"Nedbank","amenity":"bank"},"name":"Nedbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/First National Bank":{"tags":{"name":"First National Bank","amenity":"bank"},"name":"First National Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Nordea":{"tags":{"name":"Nordea","amenity":"bank"},"name":"Nordea","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Rabobank":{"tags":{"name":"Rabobank","amenity":"bank"},"name":"Rabobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparkasse KölnBonn":{"tags":{"name":"Sparkasse KölnBonn","amenity":"bank"},"name":"Sparkasse KölnBonn","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Tatra banka":{"tags":{"name":"Tatra banka","amenity":"bank"},"name":"Tatra banka","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Berliner Sparkasse":{"tags":{"name":"Berliner Sparkasse","amenity":"bank"},"name":"Berliner Sparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Berliner Volksbank":{"tags":{"name":"Berliner Volksbank","amenity":"bank"},"name":"Berliner Volksbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Wells Fargo":{"tags":{"name":"Wells Fargo","amenity":"bank"},"name":"Wells Fargo","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Credit Suisse":{"tags":{"name":"Credit Suisse","amenity":"bank"},"name":"Credit Suisse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Société Générale":{"tags":{"name":"Société Générale","amenity":"bank"},"name":"Société Générale","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Osuuspankki":{"tags":{"name":"Osuuspankki","amenity":"bank"},"name":"Osuuspankki","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparkasse Aachen":{"tags":{"name":"Sparkasse Aachen","amenity":"bank"},"name":"Sparkasse Aachen","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Hamburger Sparkasse":{"tags":{"name":"Hamburger Sparkasse","amenity":"bank"},"name":"Hamburger Sparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Cassa di Risparmio del Veneto":{"tags":{"name":"Cassa di Risparmio del Veneto","amenity":"bank"},"name":"Cassa di Risparmio del Veneto","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNP Paribas":{"tags":{"name":"BNP Paribas","amenity":"bank"},"name":"BNP Paribas","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banque Populaire":{"tags":{"name":"Banque Populaire","amenity":"bank"},"name":"Banque Populaire","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNP Paribas Fortis":{"tags":{"name":"BNP Paribas Fortis","amenity":"bank"},"name":"BNP Paribas Fortis","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Popular":{"tags":{"name":"Banco Popular","amenity":"bank"},"name":"Banco Popular","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancaja":{"tags":{"name":"Bancaja","amenity":"bank"},"name":"Bancaja","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banesto":{"tags":{"name":"Banesto","amenity":"bank"},"name":"Banesto","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/La Caixa":{"tags":{"name":"La Caixa","amenity":"bank"},"name":"La Caixa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Santander Consumer Bank":{"tags":{"name":"Santander Consumer Bank","amenity":"bank"},"name":"Santander Consumer Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BRD":{"tags":{"name":"BRD","amenity":"bank"},"name":"BRD","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BCR":{"tags":{"name":"BCR","amenity":"bank"},"name":"BCR","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banca Transilvania":{"tags":{"name":"Banca Transilvania","amenity":"bank"},"name":"Banca Transilvania","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BW-Bank":{"tags":{"name":"BW-Bank","amenity":"bank"},"name":"BW-Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Komerční banka":{"tags":{"name":"Komerční banka","amenity":"bank"},"name":"Komerční banka","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Pastor":{"tags":{"name":"Banco Pastor","amenity":"bank"},"name":"Banco Pastor","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Stadtsparkasse":{"tags":{"name":"Stadtsparkasse","amenity":"bank"},"name":"Stadtsparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ulster Bank":{"tags":{"name":"Ulster Bank","amenity":"bank"},"name":"Ulster Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sberbank":{"tags":{"name":"Sberbank","amenity":"bank"},"name":"Sberbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/CIC":{"tags":{"name":"CIC","amenity":"bank"},"name":"CIC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancpost":{"tags":{"name":"Bancpost","amenity":"bank"},"name":"Bancpost","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Madrid":{"tags":{"name":"Caja Madrid","amenity":"bank"},"name":"Caja Madrid","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Maybank":{"tags":{"name":"Maybank","amenity":"bank"},"name":"Maybank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/中国银行":{"tags":{"name":"中国银行","amenity":"bank"},"name":"中国银行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Unicredit Banca":{"tags":{"name":"Unicredit Banca","amenity":"bank"},"name":"Unicredit Banca","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit Mutuel":{"tags":{"name":"Crédit Mutuel","amenity":"bank"},"name":"Crédit Mutuel","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BBVA":{"tags":{"name":"BBVA","amenity":"bank"},"name":"BBVA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Intesa San Paolo":{"tags":{"name":"Intesa San Paolo","amenity":"bank"},"name":"Intesa San Paolo","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/TD Bank":{"tags":{"name":"TD Bank","amenity":"bank"},"name":"TD Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Belfius":{"tags":{"name":"Belfius","amenity":"bank"},"name":"Belfius","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of America":{"tags":{"name":"Bank of America","amenity":"bank"},"name":"Bank of America","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/RBC":{"tags":{"name":"RBC","amenity":"bank"},"name":"RBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Alpha Bank":{"tags":{"name":"Alpha Bank","amenity":"bank"},"name":"Alpha Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Сбербанк":{"tags":{"name":"Сбербанк","amenity":"bank"},"name":"Сбербанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Россельхозбанк":{"tags":{"name":"Россельхозбанк","amenity":"bank"},"name":"Россельхозбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit du Nord":{"tags":{"name":"Crédit du Nord","amenity":"bank"},"name":"Crédit du Nord","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BancoEstado":{"tags":{"name":"BancoEstado","amenity":"bank"},"name":"BancoEstado","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Millennium Bank":{"tags":{"name":"Millennium Bank","amenity":"bank"},"name":"Millennium Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/State Bank of India":{"tags":{"name":"State Bank of India","amenity":"bank"},"name":"State Bank of India","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Беларусбанк":{"tags":{"name":"Беларусбанк","amenity":"bank"},"name":"Беларусбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ING Bank Śląski":{"tags":{"name":"ING Bank Śląski","amenity":"bank"},"name":"ING Bank Śląski","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caixa Geral de Depósitos":{"tags":{"name":"Caixa Geral de Depósitos","amenity":"bank"},"name":"Caixa Geral de Depósitos","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Kreissparkasse Köln":{"tags":{"name":"Kreissparkasse Köln","amenity":"bank"},"name":"Kreissparkasse Köln","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco BCI":{"tags":{"name":"Banco BCI","amenity":"bank"},"name":"Banco BCI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de Chile":{"tags":{"name":"Banco de Chile","amenity":"bank"},"name":"Banco de Chile","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ВТБ24":{"tags":{"name":"ВТБ24","amenity":"bank"},"name":"ВТБ24","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/UBS":{"tags":{"name":"UBS","amenity":"bank"},"name":"UBS","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PKO BP":{"tags":{"name":"PKO BP","amenity":"bank"},"name":"PKO BP","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Chinabank":{"tags":{"name":"Chinabank","amenity":"bank"},"name":"Chinabank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PSBank":{"tags":{"name":"PSBank","amenity":"bank"},"name":"PSBank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Union Bank":{"tags":{"name":"Union Bank","amenity":"bank"},"name":"Union Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/China Bank":{"tags":{"name":"China Bank","amenity":"bank"},"name":"China Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/RCBC":{"tags":{"name":"RCBC","amenity":"bank"},"name":"RCBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Unicaja":{"tags":{"name":"Unicaja","amenity":"bank"},"name":"Unicaja","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BBK":{"tags":{"name":"BBK","amenity":"bank"},"name":"BBK","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ibercaja":{"tags":{"name":"Ibercaja","amenity":"bank"},"name":"Ibercaja","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/RBS":{"tags":{"name":"RBS","amenity":"bank"},"name":"RBS","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Commercial Bank of Ceylon PLC":{"tags":{"name":"Commercial Bank of Ceylon PLC","amenity":"bank"},"name":"Commercial Bank of Ceylon PLC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of Ireland":{"tags":{"name":"Bank of Ireland","amenity":"bank"},"name":"Bank of Ireland","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNL":{"tags":{"name":"BNL","amenity":"bank"},"name":"BNL","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Santander":{"tags":{"name":"Banco Santander","amenity":"bank"},"name":"Banco Santander","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Itaú":{"tags":{"name":"Banco Itaú","amenity":"bank"},"name":"Banco Itaú","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/AIB":{"tags":{"name":"AIB","amenity":"bank"},"name":"AIB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BZ WBK":{"tags":{"name":"BZ WBK","amenity":"bank"},"name":"BZ WBK","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco do Brasil":{"tags":{"name":"Banco do Brasil","amenity":"bank"},"name":"Banco do Brasil","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caixa Econômica Federal":{"tags":{"name":"Caixa Econômica Federal","amenity":"bank"},"name":"Caixa Econômica Federal","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Fifth Third Bank":{"tags":{"name":"Fifth Third Bank","amenity":"bank"},"name":"Fifth Third Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banca Popolare di Vicenza":{"tags":{"name":"Banca Popolare di Vicenza","amenity":"bank"},"name":"Banca Popolare di Vicenza","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Wachovia":{"tags":{"name":"Wachovia","amenity":"bank"},"name":"Wachovia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/OLB":{"tags":{"name":"OLB","amenity":"bank"},"name":"OLB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/みずほ銀行":{"tags":{"name":"みずほ銀行","amenity":"bank"},"name":"みずほ銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BES":{"tags":{"name":"BES","amenity":"bank"},"name":"BES","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ICICI Bank":{"tags":{"name":"ICICI Bank","amenity":"bank"},"name":"ICICI Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/HDFC Bank":{"tags":{"name":"HDFC Bank","amenity":"bank"},"name":"HDFC Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/La Banque Postale":{"tags":{"name":"La Banque Postale","amenity":"bank"},"name":"La Banque Postale","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Pekao SA":{"tags":{"name":"Pekao SA","amenity":"bank"},"name":"Pekao SA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Oberbank":{"tags":{"name":"Oberbank","amenity":"bank"},"name":"Oberbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bradesco":{"tags":{"name":"Bradesco","amenity":"bank"},"name":"Bradesco","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Oldenburgische Landesbank":{"tags":{"name":"Oldenburgische Landesbank","amenity":"bank"},"name":"Oldenburgische Landesbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bendigo Bank":{"tags":{"name":"Bendigo Bank","amenity":"bank"},"name":"Bendigo Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Argenta":{"tags":{"name":"Argenta","amenity":"bank"},"name":"Argenta","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/AXA":{"tags":{"name":"AXA","amenity":"bank"},"name":"AXA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Axis Bank":{"tags":{"name":"Axis Bank","amenity":"bank"},"name":"Axis Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Nación":{"tags":{"name":"Banco Nación","amenity":"bank"},"name":"Banco Nación","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/GE Money Bank":{"tags":{"name":"GE Money Bank","amenity":"bank"},"name":"GE Money Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Альфа-Банк":{"tags":{"name":"Альфа-Банк","amenity":"bank"},"name":"Альфа-Банк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Белагропромбанк":{"tags":{"name":"Белагропромбанк","amenity":"bank"},"name":"Белагропромбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Círculo":{"tags":{"name":"Caja Círculo","amenity":"bank"},"name":"Caja Círculo","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Galicia":{"tags":{"name":"Banco Galicia","amenity":"bank"},"name":"Banco Galicia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Eurobank":{"tags":{"name":"Eurobank","amenity":"bank"},"name":"Eurobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banca Intesa":{"tags":{"name":"Banca Intesa","amenity":"bank"},"name":"Banca Intesa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Canara Bank":{"tags":{"name":"Canara Bank","amenity":"bank"},"name":"Canara Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Cajamar":{"tags":{"name":"Cajamar","amenity":"bank"},"name":"Cajamar","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banamex":{"tags":{"name":"Banamex","amenity":"bank"},"name":"Banamex","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit Mutuel de Bretagne":{"tags":{"name":"Crédit Mutuel de Bretagne","amenity":"bank"},"name":"Crédit Mutuel de Bretagne","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Davivienda":{"tags":{"name":"Davivienda","amenity":"bank"},"name":"Davivienda","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank Spółdzielczy":{"tags":{"name":"Bank Spółdzielczy","amenity":"bank"},"name":"Bank Spółdzielczy","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Credit Agricole":{"tags":{"name":"Credit Agricole","amenity":"bank"},"name":"Credit Agricole","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bankinter":{"tags":{"name":"Bankinter","amenity":"bank"},"name":"Bankinter","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banque Nationale":{"tags":{"name":"Banque Nationale","amenity":"bank"},"name":"Banque Nationale","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of the West":{"tags":{"name":"Bank of the West","amenity":"bank"},"name":"Bank of the West","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Key Bank":{"tags":{"name":"Key Bank","amenity":"bank"},"name":"Key Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Western Union":{"tags":{"name":"Western Union","amenity":"bank"},"name":"Western Union","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Citizens Bank":{"tags":{"name":"Citizens Bank","amenity":"bank"},"name":"Citizens Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ПриватБанк":{"tags":{"name":"ПриватБанк","amenity":"bank"},"name":"ПриватБанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Security Bank":{"tags":{"name":"Security Bank","amenity":"bank"},"name":"Security Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Millenium":{"tags":{"name":"Millenium","amenity":"bank"},"name":"Millenium","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bankia":{"tags":{"name":"Bankia","amenity":"bank"},"name":"Bankia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/三菱東京UFJ銀行":{"tags":{"name":"三菱東京UFJ銀行","amenity":"bank"},"name":"三菱東京UFJ銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caixa":{"tags":{"name":"Caixa","amenity":"bank"},"name":"Caixa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de Costa Rica":{"tags":{"name":"Banco de Costa Rica","amenity":"bank"},"name":"Banco de Costa Rica","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/SunTrust Bank":{"tags":{"name":"SunTrust Bank","amenity":"bank"},"name":"SunTrust Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Itaú":{"tags":{"name":"Itaú","amenity":"bank"},"name":"Itaú","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PBZ":{"tags":{"name":"PBZ","amenity":"bank"},"name":"PBZ","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/中国工商银行":{"tags":{"name":"中国工商银行","amenity":"bank"},"name":"中国工商银行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancolombia":{"tags":{"name":"Bancolombia","amenity":"bank"},"name":"Bancolombia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Райффайзен Банк Аваль":{"tags":{"name":"Райффайзен Банк Аваль","amenity":"bank"},"name":"Райффайзен Банк Аваль","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancomer":{"tags":{"name":"Bancomer","amenity":"bank"},"name":"Bancomer","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banorte":{"tags":{"name":"Banorte","amenity":"bank"},"name":"Banorte","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Alior Bank":{"tags":{"name":"Alior Bank","amenity":"bank"},"name":"Alior Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BOC":{"tags":{"name":"BOC","amenity":"bank"},"name":"BOC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Банк Москвы":{"tags":{"name":"Банк Москвы","amenity":"bank"},"name":"Банк Москвы","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ВТБ":{"tags":{"name":"ВТБ","amenity":"bank"},"name":"ВТБ","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Getin Bank":{"tags":{"name":"Getin Bank","amenity":"bank"},"name":"Getin Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Duero":{"tags":{"name":"Caja Duero","amenity":"bank"},"name":"Caja Duero","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Regions Bank":{"tags":{"name":"Regions Bank","amenity":"bank"},"name":"Regions Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Росбанк":{"tags":{"name":"Росбанк","amenity":"bank"},"name":"Росбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Estado":{"tags":{"name":"Banco Estado","amenity":"bank"},"name":"Banco Estado","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BCI":{"tags":{"name":"BCI","amenity":"bank"},"name":"BCI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/SunTrust":{"tags":{"name":"SunTrust","amenity":"bank"},"name":"SunTrust","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PNC Bank":{"tags":{"name":"PNC Bank","amenity":"bank"},"name":"PNC Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/신한은행":{"tags":{"name":"신한은행","name:en":"Sinhan Bank","amenity":"bank"},"name":"신한은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/우리은행":{"tags":{"name":"우리은행","name:en":"Uri Bank","amenity":"bank"},"name":"우리은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/국민은행":{"tags":{"name":"국민은행","name:en":"Gungmin Bank","amenity":"bank"},"name":"국민은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/중소기업은행":{"tags":{"name":"중소기업은행","name:en":"Industrial Bank of Korea","amenity":"bank"},"name":"중소기업은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/광주은행":{"tags":{"name":"광주은행","name:en":"Gwangju Bank","amenity":"bank"},"name":"광주은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Газпромбанк":{"tags":{"name":"Газпромбанк","amenity":"bank"},"name":"Газпромбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/M&T Bank":{"tags":{"name":"M&T Bank","amenity":"bank"},"name":"M&T Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja de Burgos":{"tags":{"name":"Caja de Burgos","amenity":"bank"},"name":"Caja de Burgos","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Santander Totta":{"tags":{"name":"Santander Totta","amenity":"bank"},"name":"Santander Totta","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/УкрСиббанк":{"tags":{"name":"УкрСиббанк","amenity":"bank"},"name":"УкрСиббанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ощадбанк":{"tags":{"name":"Ощадбанк","amenity":"bank"},"name":"Ощадбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Уралсиб":{"tags":{"name":"Уралсиб","amenity":"bank"},"name":"Уралсиб","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/りそな銀行":{"tags":{"name":"りそな銀行","name:en":"Mizuho Bank","amenity":"bank"},"name":"りそな銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ecobank":{"tags":{"name":"Ecobank","amenity":"bank"},"name":"Ecobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Cajero Automatico Bancared":{"tags":{"name":"Cajero Automatico Bancared","amenity":"bank"},"name":"Cajero Automatico Bancared","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Промсвязьбанк":{"tags":{"name":"Промсвязьбанк","amenity":"bank"},"name":"Промсвязьбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/三井住友銀行":{"tags":{"name":"三井住友銀行","amenity":"bank"},"name":"三井住友銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Provincia":{"tags":{"name":"Banco Provincia","amenity":"bank"},"name":"Banco Provincia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BB&T":{"tags":{"name":"BB&T","amenity":"bank"},"name":"BB&T","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Возрождение":{"tags":{"name":"Возрождение","amenity":"bank"},"name":"Возрождение","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Capital One":{"tags":{"name":"Capital One","amenity":"bank"},"name":"Capital One","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/横浜銀行":{"tags":{"name":"横浜銀行","amenity":"bank"},"name":"横浜銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank Mandiri":{"tags":{"name":"Bank Mandiri","amenity":"bank"},"name":"Bank Mandiri","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de la Nación":{"tags":{"name":"Banco de la Nación","amenity":"bank"},"name":"Banco de la Nación","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco G&T Continental":{"tags":{"name":"Banco G&T Continental","amenity":"bank"},"name":"Banco G&T Continental","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Peoples Bank":{"tags":{"name":"Peoples Bank","amenity":"bank"},"name":"Peoples Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/工商银行":{"tags":{"name":"工商银行","amenity":"bank"},"name":"工商银行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Совкомбанк":{"tags":{"name":"Совкомбанк","amenity":"bank"},"name":"Совкомбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Provincial":{"tags":{"name":"Provincial","amenity":"bank"},"name":"Provincial","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de Desarrollo Banrural":{"tags":{"name":"Banco de Desarrollo Banrural","amenity":"bank"},"name":"Banco de Desarrollo Banrural","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Bradesco":{"tags":{"name":"Banco Bradesco","amenity":"bank"},"name":"Banco Bradesco","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bicentenario":{"tags":{"name":"Bicentenario","amenity":"bank"},"name":"Bicentenario","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ლიბერთი ბანკი":{"tags":{"name":"ლიბერთი ბანკი","name:en":"Liberty Bank","amenity":"bank"},"name":"ლიბერთი ბანკი","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banesco":{"tags":{"name":"Banesco","amenity":"bank"},"name":"Banesco","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Mercantil":{"tags":{"name":"Mercantil","amenity":"bank"},"name":"Mercantil","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank BRI":{"tags":{"name":"Bank BRI","amenity":"bank"},"name":"Bank BRI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Del Tesoro":{"tags":{"name":"Del Tesoro","amenity":"bank"},"name":"Del Tesoro","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/하나은행":{"tags":{"name":"하나은행","amenity":"bank"},"name":"하나은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/CityCommerce Bank":{"tags":{"name":"CityCommerce Bank","amenity":"bank"},"name":"CityCommerce Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/De Venezuela":{"tags":{"name":"De Venezuela","amenity":"bank"},"name":"De Venezuela","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/car_rental/Europcar":{"tags":{"name":"Europcar","amenity":"car_rental"},"name":"Europcar","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Budget":{"tags":{"name":"Budget","amenity":"car_rental"},"name":"Budget","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Sixt":{"tags":{"name":"Sixt","amenity":"car_rental"},"name":"Sixt","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Avis":{"tags":{"name":"Avis","amenity":"car_rental"},"name":"Avis","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Hertz":{"tags":{"name":"Hertz","amenity":"car_rental"},"name":"Hertz","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Enterprise":{"tags":{"name":"Enterprise","amenity":"car_rental"},"name":"Enterprise","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/stadtmobil CarSharing-Station":{"tags":{"name":"stadtmobil CarSharing-Station","amenity":"car_rental"},"name":"stadtmobil CarSharing-Station","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/pharmacy/Rowlands Pharmacy":{"tags":{"name":"Rowlands Pharmacy","amenity":"pharmacy"},"name":"Rowlands Pharmacy","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Boots":{"tags":{"name":"Boots","amenity":"pharmacy"},"name":"Boots","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Marien-Apotheke":{"tags":{"name":"Marien-Apotheke","amenity":"pharmacy"},"name":"Marien-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Mercury Drug":{"tags":{"name":"Mercury Drug","amenity":"pharmacy"},"name":"Mercury Drug","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Löwen-Apotheke":{"tags":{"name":"Löwen-Apotheke","amenity":"pharmacy"},"name":"Löwen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Superdrug":{"tags":{"name":"Superdrug","amenity":"pharmacy"},"name":"Superdrug","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Sonnen-Apotheke":{"tags":{"name":"Sonnen-Apotheke","amenity":"pharmacy"},"name":"Sonnen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rathaus-Apotheke":{"tags":{"name":"Rathaus-Apotheke","amenity":"pharmacy"},"name":"Rathaus-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Engel-Apotheke":{"tags":{"name":"Engel-Apotheke","amenity":"pharmacy"},"name":"Engel-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Hirsch-Apotheke":{"tags":{"name":"Hirsch-Apotheke","amenity":"pharmacy"},"name":"Hirsch-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Stern-Apotheke":{"tags":{"name":"Stern-Apotheke","amenity":"pharmacy"},"name":"Stern-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Lloyds Pharmacy":{"tags":{"name":"Lloyds Pharmacy","amenity":"pharmacy"},"name":"Lloyds Pharmacy","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rosen-Apotheke":{"tags":{"name":"Rosen-Apotheke","amenity":"pharmacy"},"name":"Rosen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Stadt-Apotheke":{"tags":{"name":"Stadt-Apotheke","amenity":"pharmacy"},"name":"Stadt-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Markt-Apotheke":{"tags":{"name":"Markt-Apotheke","amenity":"pharmacy"},"name":"Markt-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Аптека":{"tags":{"name":"Аптека","amenity":"pharmacy"},"name":"Аптека","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Pharmasave":{"tags":{"name":"Pharmasave","amenity":"pharmacy"},"name":"Pharmasave","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Brunnen-Apotheke":{"tags":{"name":"Brunnen-Apotheke","amenity":"pharmacy"},"name":"Brunnen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Shoppers Drug Mart":{"tags":{"name":"Shoppers Drug Mart","amenity":"pharmacy"},"name":"Shoppers Drug Mart","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Apotheke am Markt":{"tags":{"name":"Apotheke am Markt","amenity":"pharmacy"},"name":"Apotheke am Markt","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Alte Apotheke":{"tags":{"name":"Alte Apotheke","amenity":"pharmacy"},"name":"Alte Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Neue Apotheke":{"tags":{"name":"Neue Apotheke","amenity":"pharmacy"},"name":"Neue Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Gintarinė vaistinė":{"tags":{"name":"Gintarinė vaistinė","amenity":"pharmacy"},"name":"Gintarinė vaistinė","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rats-Apotheke":{"tags":{"name":"Rats-Apotheke","amenity":"pharmacy"},"name":"Rats-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Adler Apotheke":{"tags":{"name":"Adler Apotheke","amenity":"pharmacy"},"name":"Adler Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Pharmacie Centrale":{"tags":{"name":"Pharmacie Centrale","amenity":"pharmacy"},"name":"Pharmacie Centrale","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Walgreens":{"tags":{"name":"Walgreens","amenity":"pharmacy"},"name":"Walgreens","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rite Aid":{"tags":{"name":"Rite Aid","amenity":"pharmacy"},"name":"Rite Aid","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Apotheke":{"tags":{"name":"Apotheke","amenity":"pharmacy"},"name":"Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Linden-Apotheke":{"tags":{"name":"Linden-Apotheke","amenity":"pharmacy"},"name":"Linden-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Bahnhof-Apotheke":{"tags":{"name":"Bahnhof-Apotheke","amenity":"pharmacy"},"name":"Bahnhof-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Burg-Apotheke":{"tags":{"name":"Burg-Apotheke","amenity":"pharmacy"},"name":"Burg-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Jean Coutu":{"tags":{"name":"Jean Coutu","amenity":"pharmacy"},"name":"Jean Coutu","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Pharmaprix":{"tags":{"name":"Pharmaprix","amenity":"pharmacy"},"name":"Pharmaprix","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacias Ahumada":{"tags":{"name":"Farmacias Ahumada","amenity":"pharmacy"},"name":"Farmacias Ahumada","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacia Comunale":{"tags":{"name":"Farmacia Comunale","amenity":"pharmacy"},"name":"Farmacia Comunale","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacias Cruz Verde":{"tags":{"name":"Farmacias Cruz Verde","amenity":"pharmacy"},"name":"Farmacias Cruz Verde","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Cruz Verde":{"tags":{"name":"Cruz Verde","amenity":"pharmacy"},"name":"Cruz Verde","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Hubertus Apotheke":{"tags":{"name":"Hubertus Apotheke","amenity":"pharmacy"},"name":"Hubertus Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/CVS":{"tags":{"name":"CVS","amenity":"pharmacy"},"name":"CVS","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacias SalcoBrand":{"tags":{"name":"Farmacias SalcoBrand","amenity":"pharmacy"},"name":"Farmacias SalcoBrand","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Фармация":{"tags":{"name":"Фармация","amenity":"pharmacy"},"name":"Фармация","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Bären-Apotheke":{"tags":{"name":"Bären-Apotheke","amenity":"pharmacy"},"name":"Bären-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Clicks":{"tags":{"name":"Clicks","amenity":"pharmacy"},"name":"Clicks","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/セイジョー":{"tags":{"name":"セイジョー","amenity":"pharmacy"},"name":"セイジョー","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/マツモトキヨシ":{"tags":{"name":"マツモトキヨシ","amenity":"pharmacy"},"name":"マツモトキヨシ","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Dr. Max":{"tags":{"name":"Dr. Max","amenity":"pharmacy"},"name":"Dr. Max","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Вита":{"tags":{"name":"Вита","amenity":"pharmacy"},"name":"Вита","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/サンドラッグ":{"tags":{"name":"サンドラッグ","amenity":"pharmacy"},"name":"サンドラッグ","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Apteka":{"tags":{"name":"Apteka","amenity":"pharmacy"},"name":"Apteka","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Первая помощь":{"tags":{"name":"Первая помощь","amenity":"pharmacy"},"name":"Первая помощь","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Ригла":{"tags":{"name":"Ригла","amenity":"pharmacy"},"name":"Ригла","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Имплозия":{"tags":{"name":"Имплозия","amenity":"pharmacy"},"name":"Имплозия","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Kinney Drugs":{"tags":{"name":"Kinney Drugs","amenity":"pharmacy"},"name":"Kinney Drugs","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Классика":{"tags":{"name":"Классика","amenity":"pharmacy"},"name":"Классика","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Ljekarna":{"tags":{"name":"Ljekarna","amenity":"pharmacy"},"name":"Ljekarna","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/SalcoBrand":{"tags":{"name":"SalcoBrand","amenity":"pharmacy"},"name":"SalcoBrand","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Аптека 36,6":{"tags":{"name":"Аптека 36,6","amenity":"pharmacy"},"name":"Аптека 36,6","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Фармакор":{"tags":{"name":"Фармакор","amenity":"pharmacy"},"name":"Фармакор","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/スギ薬局":{"tags":{"name":"スギ薬局","amenity":"pharmacy"},"name":"スギ薬局","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Аптечный пункт":{"tags":{"name":"Аптечный пункт","amenity":"pharmacy"},"name":"Аптечный пункт","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Невис":{"tags":{"name":"Невис","amenity":"pharmacy"},"name":"Невис","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/トモズ (Tomod's)":{"tags":{"name":"トモズ (Tomod's)","amenity":"pharmacy"},"name":"トモズ (Tomod's)","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Eurovaistinė":{"tags":{"name":"Eurovaistinė","amenity":"pharmacy"},"name":"Eurovaistinė","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacity":{"tags":{"name":"Farmacity","amenity":"pharmacy"},"name":"Farmacity","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/аптека":{"tags":{"name":"аптека","amenity":"pharmacy"},"name":"аптека","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/The Generics Pharmacy":{"tags":{"name":"The Generics Pharmacy","amenity":"pharmacy"},"name":"The Generics Pharmacy","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmatodo":{"tags":{"name":"Farmatodo","amenity":"pharmacy"},"name":"Farmatodo","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Duane Reade":{"tags":{"name":"Duane Reade","amenity":"pharmacy"},"name":"Duane Reade","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Фармленд":{"tags":{"name":"Фармленд","amenity":"pharmacy"},"name":"Фармленд","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/ドラッグてらしま (Drug Terashima)":{"tags":{"name":"ドラッグてらしま (Drug Terashima)","amenity":"pharmacy"},"name":"ドラッグてらしま (Drug Terashima)","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Арніка":{"tags":{"name":"Арніка","amenity":"pharmacy"},"name":"Арніка","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/ავერსი (Aversi)":{"tags":{"name":"ავერსი (Aversi)","amenity":"pharmacy"},"name":"ავერსი (Aversi)","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmahorro":{"tags":{"name":"Farmahorro","amenity":"pharmacy"},"name":"Farmahorro","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/cafe/Starbucks":{"tags":{"name":"Starbucks","cuisine":"coffee_shop","amenity":"cafe"},"name":"Starbucks","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Cafeteria":{"tags":{"name":"Cafeteria","amenity":"cafe"},"name":"Cafeteria","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Costa":{"tags":{"name":"Costa","amenity":"cafe"},"name":"Costa","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Caffè Nero":{"tags":{"name":"Caffè Nero","amenity":"cafe"},"name":"Caffè Nero","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Кафе":{"tags":{"name":"Кафе","amenity":"cafe"},"name":"Кафе","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Café Central":{"tags":{"name":"Café Central","amenity":"cafe"},"name":"Café Central","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Second Cup":{"tags":{"name":"Second Cup","amenity":"cafe"},"name":"Second Cup","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Dunkin Donuts":{"tags":{"name":"Dunkin Donuts","cuisine":"donut","amenity":"cafe"},"name":"Dunkin Donuts","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Espresso House":{"tags":{"name":"Espresso House","amenity":"cafe"},"name":"Espresso House","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Segafredo":{"tags":{"name":"Segafredo","amenity":"cafe"},"name":"Segafredo","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Coffee Time":{"tags":{"name":"Coffee Time","amenity":"cafe"},"name":"Coffee Time","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Cafe Coffee Day":{"tags":{"name":"Cafe Coffee Day","amenity":"cafe"},"name":"Cafe Coffee Day","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Eiscafe Venezia":{"tags":{"name":"Eiscafe Venezia","amenity":"cafe"},"name":"Eiscafe Venezia","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/スターバックス":{"tags":{"name":"スターバックス","name:en":"Starbucks","amenity":"cafe"},"name":"スターバックス","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Шоколадница":{"tags":{"name":"Шоколадница","amenity":"cafe"},"name":"Шоколадница","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Pret A Manger":{"tags":{"name":"Pret A Manger","amenity":"cafe"},"name":"Pret A Manger","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Столовая":{"tags":{"name":"Столовая","amenity":"cafe"},"name":"Столовая","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/ドトール":{"tags":{"name":"ドトール","name:en":"DOUTOR","amenity":"cafe"},"name":"ドトール","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Tchibo":{"tags":{"name":"Tchibo","amenity":"cafe"},"name":"Tchibo","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Кофе Хауз":{"tags":{"name":"Кофе Хауз","amenity":"cafe"},"name":"Кофе Хауз","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Caribou Coffee":{"tags":{"name":"Caribou Coffee","amenity":"cafe"},"name":"Caribou Coffee","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Уют":{"tags":{"name":"Уют","amenity":"cafe"},"name":"Уют","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Шашлычная":{"tags":{"name":"Шашлычная","amenity":"cafe"},"name":"Шашлычная","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/คาเฟ่ อเมซอน":{"tags":{"name":"คาเฟ่ อเมซอน","amenity":"cafe"},"name":"คาเฟ่ อเมซอน","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Traveler's Coffee":{"tags":{"name":"Traveler's Coffee","amenity":"cafe"},"name":"Traveler's Coffee","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/カフェ・ド・クリエ":{"tags":{"name":"カフェ・ド・クリエ","name:en":"Cafe de CRIE","amenity":"cafe"},"name":"カフェ・ド・クリエ","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Cafe Amazon":{"tags":{"name":"Cafe Amazon","amenity":"cafe"},"name":"Cafe Amazon","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"shop/supermarket/Budgens":{"tags":{"name":"Budgens","shop":"supermarket"},"name":"Budgens","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Morrisons":{"tags":{"name":"Morrisons","shop":"supermarket"},"name":"Morrisons","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Interspar":{"tags":{"name":"Interspar","shop":"supermarket"},"name":"Interspar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Merkur":{"tags":{"name":"Merkur","shop":"supermarket"},"name":"Merkur","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sainsbury's":{"tags":{"name":"Sainsbury's","shop":"supermarket"},"name":"Sainsbury's","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Lidl":{"tags":{"name":"Lidl","shop":"supermarket"},"name":"Lidl","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Edeka":{"tags":{"name":"Edeka","shop":"supermarket"},"name":"Edeka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coles":{"tags":{"name":"Coles","shop":"supermarket"},"name":"Coles","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Iceland":{"tags":{"name":"Iceland","shop":"supermarket"},"name":"Iceland","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coop":{"tags":{"name":"Coop","shop":"supermarket"},"name":"Coop","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco":{"tags":{"name":"Tesco","shop":"supermarket"},"name":"Tesco","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Woolworths":{"tags":{"name":"Woolworths","shop":"supermarket"},"name":"Woolworths","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Zielpunkt":{"tags":{"name":"Zielpunkt","shop":"supermarket"},"name":"Zielpunkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Nahkauf":{"tags":{"name":"Nahkauf","shop":"supermarket"},"name":"Nahkauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Billa":{"tags":{"name":"Billa","shop":"supermarket"},"name":"Billa","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kaufland":{"tags":{"name":"Kaufland","shop":"supermarket"},"name":"Kaufland","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Plus":{"tags":{"name":"Plus","shop":"supermarket"},"name":"Plus","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ALDI":{"tags":{"name":"ALDI","shop":"supermarket"},"name":"ALDI","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Checkers":{"tags":{"name":"Checkers","shop":"supermarket"},"name":"Checkers","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco Metro":{"tags":{"name":"Tesco Metro","shop":"supermarket"},"name":"Tesco Metro","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/NP":{"tags":{"name":"NP","shop":"supermarket"},"name":"NP","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Penny":{"tags":{"name":"Penny","shop":"supermarket"},"name":"Penny","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Norma":{"tags":{"name":"Norma","shop":"supermarket"},"name":"Norma","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Asda":{"tags":{"name":"Asda","shop":"supermarket"},"name":"Asda","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Netto":{"tags":{"name":"Netto","shop":"supermarket"},"name":"Netto","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Rewe":{"tags":{"name":"Rewe","shop":"supermarket"},"name":"Rewe","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Aldi Süd":{"tags":{"name":"Aldi Süd","shop":"supermarket"},"name":"Aldi Süd","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Real":{"tags":{"name":"Real","shop":"supermarket"},"name":"Real","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/King Soopers":{"tags":{"name":"King Soopers","shop":"supermarket"},"name":"King Soopers","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kiwi":{"tags":{"name":"Kiwi","shop":"supermarket"},"name":"Kiwi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Pick n Pay":{"tags":{"name":"Pick n Pay","shop":"supermarket"},"name":"Pick n Pay","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ICA":{"tags":{"name":"ICA","shop":"supermarket"},"name":"ICA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tengelmann":{"tags":{"name":"Tengelmann","shop":"supermarket"},"name":"Tengelmann","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour":{"tags":{"name":"Carrefour","shop":"supermarket"},"name":"Carrefour","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Waitrose":{"tags":{"name":"Waitrose","shop":"supermarket"},"name":"Waitrose","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Spar":{"tags":{"name":"Spar","shop":"supermarket"},"name":"Spar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hofer":{"tags":{"name":"Hofer","shop":"supermarket"},"name":"Hofer","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/M-Preis":{"tags":{"name":"M-Preis","shop":"supermarket"},"name":"M-Preis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/tegut":{"tags":{"name":"tegut","shop":"supermarket"},"name":"tegut","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sainsbury's Local":{"tags":{"name":"Sainsbury's Local","shop":"supermarket"},"name":"Sainsbury's Local","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/E-Center":{"tags":{"name":"E-Center","shop":"supermarket"},"name":"E-Center","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Aldi Nord":{"tags":{"name":"Aldi Nord","shop":"supermarket"},"name":"Aldi Nord","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/nahkauf":{"tags":{"name":"nahkauf","shop":"supermarket"},"name":"nahkauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Meijer":{"tags":{"name":"Meijer","shop":"supermarket"},"name":"Meijer","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Safeway":{"tags":{"name":"Safeway","shop":"supermarket"},"name":"Safeway","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Costco":{"tags":{"name":"Costco","shop":"supermarket"},"name":"Costco","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Albert":{"tags":{"name":"Albert","shop":"supermarket"},"name":"Albert","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Jumbo":{"tags":{"name":"Jumbo","shop":"supermarket"},"name":"Jumbo","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Shoprite":{"tags":{"name":"Shoprite","shop":"supermarket"},"name":"Shoprite","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/MPreis":{"tags":{"name":"MPreis","shop":"supermarket"},"name":"MPreis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Penny Market":{"tags":{"name":"Penny Market","shop":"supermarket"},"name":"Penny Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco Extra":{"tags":{"name":"Tesco Extra","shop":"supermarket"},"name":"Tesco Extra","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Albert Heijn":{"tags":{"name":"Albert Heijn","shop":"supermarket"},"name":"Albert Heijn","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/IGA":{"tags":{"name":"IGA","shop":"supermarket"},"name":"IGA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Super U":{"tags":{"name":"Super U","shop":"supermarket"},"name":"Super U","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Metro":{"tags":{"name":"Metro","shop":"supermarket"},"name":"Metro","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Neukauf":{"tags":{"name":"Neukauf","shop":"supermarket"},"name":"Neukauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Migros":{"tags":{"name":"Migros","shop":"supermarket"},"name":"Migros","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Marktkauf":{"tags":{"name":"Marktkauf","shop":"supermarket"},"name":"Marktkauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Delikatesy Centrum":{"tags":{"name":"Delikatesy Centrum","shop":"supermarket"},"name":"Delikatesy Centrum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/C1000":{"tags":{"name":"C1000","shop":"supermarket"},"name":"C1000","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hoogvliet":{"tags":{"name":"Hoogvliet","shop":"supermarket"},"name":"Hoogvliet","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Food Basics":{"tags":{"name":"Food Basics","shop":"supermarket"},"name":"Food Basics","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Casino":{"tags":{"name":"Casino","shop":"supermarket"},"name":"Casino","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Penny Markt":{"tags":{"name":"Penny Markt","shop":"supermarket"},"name":"Penny Markt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Giant":{"tags":{"name":"Giant","shop":"supermarket"},"name":"Giant","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Rema 1000":{"tags":{"name":"Rema 1000","shop":"supermarket"},"name":"Rema 1000","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kaufpark":{"tags":{"name":"Kaufpark","shop":"supermarket"},"name":"Kaufpark","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ALDI SÜD":{"tags":{"name":"ALDI SÜD","shop":"supermarket"},"name":"ALDI SÜD","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Simply Market":{"tags":{"name":"Simply Market","shop":"supermarket"},"name":"Simply Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Konzum":{"tags":{"name":"Konzum","shop":"supermarket"},"name":"Konzum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour Express":{"tags":{"name":"Carrefour Express","shop":"supermarket"},"name":"Carrefour Express","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Eurospar":{"tags":{"name":"Eurospar","shop":"supermarket"},"name":"Eurospar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Mercator":{"tags":{"name":"Mercator","shop":"supermarket"},"name":"Mercator","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Famila":{"tags":{"name":"Famila","shop":"supermarket"},"name":"Famila","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hemköp":{"tags":{"name":"Hemköp","shop":"supermarket"},"name":"Hemköp","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/real,-":{"tags":{"name":"real,-","shop":"supermarket"},"name":"real,-","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Markant":{"tags":{"name":"Markant","shop":"supermarket"},"name":"Markant","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Volg":{"tags":{"name":"Volg","shop":"supermarket"},"name":"Volg","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Leader Price":{"tags":{"name":"Leader Price","shop":"supermarket"},"name":"Leader Price","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Treff 3000":{"tags":{"name":"Treff 3000","shop":"supermarket"},"name":"Treff 3000","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/SuperBrugsen":{"tags":{"name":"SuperBrugsen","shop":"supermarket"},"name":"SuperBrugsen","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kaiser's":{"tags":{"name":"Kaiser's","shop":"supermarket"},"name":"Kaiser's","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/K+K":{"tags":{"name":"K+K","shop":"supermarket"},"name":"K+K","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Unimarkt":{"tags":{"name":"Unimarkt","shop":"supermarket"},"name":"Unimarkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour City":{"tags":{"name":"Carrefour City","shop":"supermarket"},"name":"Carrefour City","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sobeys":{"tags":{"name":"Sobeys","shop":"supermarket"},"name":"Sobeys","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/S-Market":{"tags":{"name":"S-Market","shop":"supermarket"},"name":"S-Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Combi":{"tags":{"name":"Combi","shop":"supermarket"},"name":"Combi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Denner":{"tags":{"name":"Denner","shop":"supermarket"},"name":"Denner","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Konsum":{"tags":{"name":"Konsum","shop":"supermarket"},"name":"Konsum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Franprix":{"tags":{"name":"Franprix","shop":"supermarket"},"name":"Franprix","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Monoprix":{"tags":{"name":"Monoprix","shop":"supermarket"},"name":"Monoprix","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Diska":{"tags":{"name":"Diska","shop":"supermarket"},"name":"Diska","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/PENNY":{"tags":{"name":"PENNY","shop":"supermarket"},"name":"PENNY","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Dia":{"tags":{"name":"Dia","shop":"supermarket"},"name":"Dia","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Giant Eagle":{"tags":{"name":"Giant Eagle","shop":"supermarket"},"name":"Giant Eagle","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/NORMA":{"tags":{"name":"NORMA","shop":"supermarket"},"name":"NORMA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/AD Delhaize":{"tags":{"name":"AD Delhaize","shop":"supermarket"},"name":"AD Delhaize","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Auchan":{"tags":{"name":"Auchan","shop":"supermarket"},"name":"Auchan","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Mercadona":{"tags":{"name":"Mercadona","shop":"supermarket"},"name":"Mercadona","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Consum":{"tags":{"name":"Consum","shop":"supermarket"},"name":"Consum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour Market":{"tags":{"name":"Carrefour Market","shop":"supermarket"},"name":"Carrefour Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Whole Foods":{"tags":{"name":"Whole Foods","shop":"supermarket"},"name":"Whole Foods","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Pam":{"tags":{"name":"Pam","shop":"supermarket"},"name":"Pam","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/sky":{"tags":{"name":"sky","shop":"supermarket"},"name":"sky","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Despar":{"tags":{"name":"Despar","shop":"supermarket"},"name":"Despar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Eroski":{"tags":{"name":"Eroski","shop":"supermarket"},"name":"Eroski","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Maxi":{"tags":{"name":"Maxi","shop":"supermarket"},"name":"Maxi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Colruyt":{"tags":{"name":"Colruyt","shop":"supermarket"},"name":"Colruyt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/The Co-operative":{"tags":{"name":"The Co-operative","shop":"supermarket"},"name":"The Co-operative","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Intermarché":{"tags":{"name":"Intermarché","shop":"supermarket"},"name":"Intermarché","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Delhaize":{"tags":{"name":"Delhaize","shop":"supermarket"},"name":"Delhaize","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/CBA":{"tags":{"name":"CBA","shop":"supermarket"},"name":"CBA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Shopi":{"tags":{"name":"Shopi","shop":"supermarket"},"name":"Shopi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Walmart":{"tags":{"name":"Walmart","shop":"supermarket"},"name":"Walmart","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kroger":{"tags":{"name":"Kroger","shop":"supermarket"},"name":"Kroger","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Albertsons":{"tags":{"name":"Albertsons","shop":"supermarket"},"name":"Albertsons","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Trader Joe's":{"tags":{"name":"Trader Joe's","shop":"supermarket"},"name":"Trader Joe's","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Feneberg":{"tags":{"name":"Feneberg","shop":"supermarket"},"name":"Feneberg","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/denn's Biomarkt":{"tags":{"name":"denn's Biomarkt","shop":"supermarket"},"name":"denn's Biomarkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kvickly":{"tags":{"name":"Kvickly","shop":"supermarket"},"name":"Kvickly","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Makro":{"tags":{"name":"Makro","shop":"supermarket"},"name":"Makro","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Dico":{"tags":{"name":"Dico","shop":"supermarket"},"name":"Dico","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Nah & Frisch":{"tags":{"name":"Nah & Frisch","shop":"supermarket"},"name":"Nah & Frisch","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Champion":{"tags":{"name":"Champion","shop":"supermarket"},"name":"Champion","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ICA Supermarket":{"tags":{"name":"ICA Supermarket","shop":"supermarket"},"name":"ICA Supermarket","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Fakta":{"tags":{"name":"Fakta","shop":"supermarket"},"name":"Fakta","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Магнит":{"tags":{"name":"Магнит","shop":"supermarket"},"name":"Магнит","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Caprabo":{"tags":{"name":"Caprabo","shop":"supermarket"},"name":"Caprabo","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Famiglia Cooperativa":{"tags":{"name":"Famiglia Cooperativa","shop":"supermarket"},"name":"Famiglia Cooperativa","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Народная 7Я семьЯ":{"tags":{"name":"Народная 7Я семьЯ","shop":"supermarket"},"name":"Народная 7Я семьЯ","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Esselunga":{"tags":{"name":"Esselunga","shop":"supermarket"},"name":"Esselunga","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Maxima":{"tags":{"name":"Maxima","shop":"supermarket"},"name":"Maxima","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Wasgau":{"tags":{"name":"Wasgau","shop":"supermarket"},"name":"Wasgau","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Pingo Doce":{"tags":{"name":"Pingo Doce","shop":"supermarket"},"name":"Pingo Doce","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Match":{"tags":{"name":"Match","shop":"supermarket"},"name":"Match","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Profi":{"tags":{"name":"Profi","shop":"supermarket"},"name":"Profi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Lider":{"tags":{"name":"Lider","shop":"supermarket"},"name":"Lider","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Unimarc":{"tags":{"name":"Unimarc","shop":"supermarket"},"name":"Unimarc","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/The Co-operative Food":{"tags":{"name":"The Co-operative Food","shop":"supermarket"},"name":"The Co-operative Food","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Santa Isabel":{"tags":{"name":"Santa Isabel","shop":"supermarket"},"name":"Santa Isabel","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Седьмой континент":{"tags":{"name":"Седьмой континент","shop":"supermarket"},"name":"Седьмой континент","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/HIT":{"tags":{"name":"HIT","shop":"supermarket"},"name":"HIT","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Rimi":{"tags":{"name":"Rimi","shop":"supermarket"},"name":"Rimi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Conad":{"tags":{"name":"Conad","shop":"supermarket"},"name":"Conad","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Фуршет":{"tags":{"name":"Фуршет","shop":"supermarket"},"name":"Фуршет","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Willys":{"tags":{"name":"Willys","shop":"supermarket"},"name":"Willys","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Farmfoods":{"tags":{"name":"Farmfoods","shop":"supermarket"},"name":"Farmfoods","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/U Express":{"tags":{"name":"U Express","shop":"supermarket"},"name":"U Express","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Фора":{"tags":{"name":"Фора","shop":"supermarket"},"name":"Фора","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Dunnes Stores":{"tags":{"name":"Dunnes Stores","shop":"supermarket"},"name":"Dunnes Stores","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Сільпо":{"tags":{"name":"Сільпо","shop":"supermarket"},"name":"Сільпо","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/マルエツ":{"tags":{"name":"マルエツ","shop":"supermarket"},"name":"マルエツ","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Piggly Wiggly":{"tags":{"name":"Piggly Wiggly","shop":"supermarket"},"name":"Piggly Wiggly","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Crai":{"tags":{"name":"Crai","shop":"supermarket"},"name":"Crai","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/El Árbol":{"tags":{"name":"El Árbol","shop":"supermarket"},"name":"El Árbol","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Centre Commercial E. Leclerc":{"tags":{"name":"Centre Commercial E. Leclerc","shop":"supermarket"},"name":"Centre Commercial E. Leclerc","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Foodland":{"tags":{"name":"Foodland","shop":"supermarket"},"name":"Foodland","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Super Brugsen":{"tags":{"name":"Super Brugsen","shop":"supermarket"},"name":"Super Brugsen","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Дикси":{"tags":{"name":"Дикси","shop":"supermarket"},"name":"Дикси","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Пятёрочка":{"tags":{"name":"Пятёрочка","shop":"supermarket"},"name":"Пятёрочка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Publix":{"tags":{"name":"Publix","shop":"supermarket"},"name":"Publix","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Føtex":{"tags":{"name":"Føtex","shop":"supermarket"},"name":"Føtex","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/coop":{"tags":{"name":"coop","shop":"supermarket"},"name":"coop","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coop Konsum":{"tags":{"name":"Coop Konsum","shop":"supermarket"},"name":"Coop Konsum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour Contact":{"tags":{"name":"Carrefour Contact","shop":"supermarket"},"name":"Carrefour Contact","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/No Frills":{"tags":{"name":"No Frills","shop":"supermarket"},"name":"No Frills","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Plodine":{"tags":{"name":"Plodine","shop":"supermarket"},"name":"Plodine","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ADEG":{"tags":{"name":"ADEG","shop":"supermarket"},"name":"ADEG","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Minipreço":{"tags":{"name":"Minipreço","shop":"supermarket"},"name":"Minipreço","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Biedronka":{"tags":{"name":"Biedronka","shop":"supermarket"},"name":"Biedronka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Eurospin":{"tags":{"name":"Eurospin","shop":"supermarket"},"name":"Eurospin","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Семья":{"tags":{"name":"Семья","shop":"supermarket"},"name":"Семья","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Gadis":{"tags":{"name":"Gadis","shop":"supermarket"},"name":"Gadis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Евроопт":{"tags":{"name":"Евроопт","shop":"supermarket"},"name":"Евроопт","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Квартал":{"tags":{"name":"Квартал","shop":"supermarket"},"name":"Квартал","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/New World":{"tags":{"name":"New World","shop":"supermarket"},"name":"New World","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Countdown":{"tags":{"name":"Countdown","shop":"supermarket"},"name":"Countdown","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Reliance Fresh":{"tags":{"name":"Reliance Fresh","shop":"supermarket"},"name":"Reliance Fresh","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Stokrotka":{"tags":{"name":"Stokrotka","shop":"supermarket"},"name":"Stokrotka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coop Jednota":{"tags":{"name":"Coop Jednota","shop":"supermarket"},"name":"Coop Jednota","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Fred Meyer":{"tags":{"name":"Fred Meyer","shop":"supermarket"},"name":"Fred Meyer","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Irma":{"tags":{"name":"Irma","shop":"supermarket"},"name":"Irma","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Continente":{"tags":{"name":"Continente","shop":"supermarket"},"name":"Continente","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Price Chopper":{"tags":{"name":"Price Chopper","shop":"supermarket"},"name":"Price Chopper","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Game":{"tags":{"name":"Game","shop":"supermarket"},"name":"Game","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Soriana":{"tags":{"name":"Soriana","shop":"supermarket"},"name":"Soriana","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Alimerka":{"tags":{"name":"Alimerka","shop":"supermarket"},"name":"Alimerka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Piotr i Paweł":{"tags":{"name":"Piotr i Paweł","shop":"supermarket"},"name":"Piotr i Paweł","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Перекресток":{"tags":{"name":"Перекресток","shop":"supermarket"},"name":"Перекресток","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Maxima X":{"tags":{"name":"Maxima X","shop":"supermarket"},"name":"Maxima X","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Карусель":{"tags":{"name":"Карусель","shop":"supermarket"},"name":"Карусель","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ALDI Nord":{"tags":{"name":"ALDI Nord","shop":"supermarket"},"name":"ALDI Nord","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Condis":{"tags":{"name":"Condis","shop":"supermarket"},"name":"Condis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sam's Club":{"tags":{"name":"Sam's Club","shop":"supermarket"},"name":"Sam's Club","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Копейка":{"tags":{"name":"Копейка","shop":"supermarket"},"name":"Копейка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Géant Casino":{"tags":{"name":"Géant Casino","shop":"supermarket"},"name":"Géant Casino","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ASDA":{"tags":{"name":"ASDA","shop":"supermarket"},"name":"ASDA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Intermarche":{"tags":{"name":"Intermarche","shop":"supermarket"},"name":"Intermarche","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Stop & Shop":{"tags":{"name":"Stop & Shop","shop":"supermarket"},"name":"Stop & Shop","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Food Lion":{"tags":{"name":"Food Lion","shop":"supermarket"},"name":"Food Lion","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Harris Teeter":{"tags":{"name":"Harris Teeter","shop":"supermarket"},"name":"Harris Teeter","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Foodworks":{"tags":{"name":"Foodworks","shop":"supermarket"},"name":"Foodworks","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Polo Market":{"tags":{"name":"Polo Market","shop":"supermarket"},"name":"Polo Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Лента":{"tags":{"name":"Лента","shop":"supermarket"},"name":"Лента","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/西友 (SEIYU)":{"tags":{"name":"西友 (SEIYU)","shop":"supermarket"},"name":"西友 (SEIYU)","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/H-E-B":{"tags":{"name":"H-E-B","shop":"supermarket"},"name":"H-E-B","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Атак":{"tags":{"name":"Атак","shop":"supermarket"},"name":"Атак","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Полушка":{"tags":{"name":"Полушка","shop":"supermarket"},"name":"Полушка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Extra":{"tags":{"name":"Extra","shop":"supermarket"},"name":"Extra","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sigma":{"tags":{"name":"Sigma","shop":"supermarket"},"name":"Sigma","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/АТБ":{"tags":{"name":"АТБ","shop":"supermarket"},"name":"АТБ","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Bodega Aurrera":{"tags":{"name":"Bodega Aurrera","shop":"supermarket"},"name":"Bodega Aurrera","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco Lotus":{"tags":{"name":"Tesco Lotus","shop":"supermarket"},"name":"Tesco Lotus","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Мария-Ра":{"tags":{"name":"Мария-Ра","shop":"supermarket"},"name":"Мария-Ра","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Магнолия":{"tags":{"name":"Магнолия","shop":"supermarket"},"name":"Магнолия","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Монетка":{"tags":{"name":"Монетка","shop":"supermarket"},"name":"Монетка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hy-Vee":{"tags":{"name":"Hy-Vee","shop":"supermarket"},"name":"Hy-Vee","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Walmart Supercenter":{"tags":{"name":"Walmart Supercenter","shop":"supermarket"},"name":"Walmart Supercenter","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hannaford":{"tags":{"name":"Hannaford","shop":"supermarket"},"name":"Hannaford","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Wegmans":{"tags":{"name":"Wegmans","shop":"supermarket"},"name":"Wegmans","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/業務スーパー":{"tags":{"name":"業務スーパー","shop":"supermarket"},"name":"業務スーパー","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Norfa XL":{"tags":{"name":"Norfa XL","shop":"supermarket"},"name":"Norfa XL","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ヨークマート (YorkMart)":{"tags":{"name":"ヨークマート (YorkMart)","shop":"supermarket"},"name":"ヨークマート (YorkMart)","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Leclerc Drive":{"tags":{"name":"Leclerc Drive","shop":"supermarket"},"name":"Leclerc Drive","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Media Markt":{"tags":{"name":"Media Markt","shop":"electronics"},"name":"Media Markt","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Maplin":{"tags":{"name":"Maplin","shop":"electronics"},"name":"Maplin","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Best Buy":{"tags":{"name":"Best Buy","shop":"electronics"},"name":"Best Buy","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Future Shop":{"tags":{"name":"Future Shop","shop":"electronics"},"name":"Future Shop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Saturn":{"tags":{"name":"Saturn","shop":"electronics"},"name":"Saturn","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Currys":{"tags":{"name":"Currys","shop":"electronics"},"name":"Currys","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Radio Shack":{"tags":{"name":"Radio Shack","shop":"electronics"},"name":"Radio Shack","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Euronics":{"tags":{"name":"Euronics","shop":"electronics"},"name":"Euronics","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Expert":{"tags":{"name":"Expert","shop":"electronics"},"name":"Expert","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Эльдорадо":{"tags":{"name":"Эльдорадо","shop":"electronics"},"name":"Эльдорадо","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Darty":{"tags":{"name":"Darty","shop":"electronics"},"name":"Darty","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/М.Видео":{"tags":{"name":"М.Видео","shop":"electronics"},"name":"М.Видео","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/ヤマダ電機":{"tags":{"name":"ヤマダ電機","shop":"electronics"},"name":"ヤマダ電機","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/McColl's":{"tags":{"name":"McColl's","shop":"convenience"},"name":"McColl's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Tesco Express":{"tags":{"name":"Tesco Express","shop":"convenience"},"name":"Tesco Express","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/One Stop":{"tags":{"name":"One Stop","shop":"convenience"},"name":"One Stop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Londis":{"tags":{"name":"Londis","shop":"convenience"},"name":"Londis","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/7-Eleven":{"tags":{"name":"7-Eleven","shop":"convenience"},"name":"7-Eleven","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Sale":{"tags":{"name":"Sale","shop":"convenience"},"name":"Sale","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Siwa":{"tags":{"name":"Siwa","shop":"convenience"},"name":"Siwa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/COOP Jednota":{"tags":{"name":"COOP Jednota","shop":"convenience"},"name":"COOP Jednota","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mac's":{"tags":{"name":"Mac's","shop":"convenience"},"name":"Mac's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Alepa":{"tags":{"name":"Alepa","shop":"convenience"},"name":"Alepa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Hasty Market":{"tags":{"name":"Hasty Market","shop":"convenience"},"name":"Hasty Market","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/K-Market":{"tags":{"name":"K-Market","shop":"convenience"},"name":"K-Market","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Costcutter":{"tags":{"name":"Costcutter","shop":"convenience"},"name":"Costcutter","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Valintatalo":{"tags":{"name":"Valintatalo","shop":"convenience"},"name":"Valintatalo","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Circle K":{"tags":{"name":"Circle K","shop":"convenience"},"name":"Circle K","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/セブンイレブン":{"tags":{"name":"セブンイレブン","name:en":"7-Eleven","shop":"convenience"},"name":"セブンイレブン","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ローソン":{"tags":{"name":"ローソン","name:en":"LAWSON","shop":"convenience"},"name":"ローソン","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Petit Casino":{"tags":{"name":"Petit Casino","shop":"convenience"},"name":"Petit Casino","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mace":{"tags":{"name":"Mace","shop":"convenience"},"name":"Mace","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mini Market":{"tags":{"name":"Mini Market","shop":"convenience"},"name":"Mini Market","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Nisa Local":{"tags":{"name":"Nisa Local","shop":"convenience"},"name":"Nisa Local","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Dorfladen":{"tags":{"name":"Dorfladen","shop":"convenience"},"name":"Dorfladen","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продукты":{"tags":{"name":"Продукты","shop":"convenience"},"name":"Продукты","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mini Stop":{"tags":{"name":"Mini Stop","shop":"convenience"},"name":"Mini Stop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/LAWSON":{"tags":{"name":"LAWSON","shop":"convenience"},"name":"LAWSON","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/デイリーヤマザキ":{"tags":{"name":"デイリーヤマザキ","shop":"convenience"},"name":"デイリーヤマザキ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Надежда":{"tags":{"name":"Надежда","shop":"convenience"},"name":"Надежда","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Nisa":{"tags":{"name":"Nisa","shop":"convenience"},"name":"Nisa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Premier":{"tags":{"name":"Premier","shop":"convenience"},"name":"Premier","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ABC":{"tags":{"name":"ABC","shop":"convenience"},"name":"ABC","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ミニストップ":{"tags":{"name":"ミニストップ","name:en":"MINISTOP","shop":"convenience"},"name":"ミニストップ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/サンクス":{"tags":{"name":"サンクス","name:en":"sunkus","shop":"convenience"},"name":"サンクス","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/スリーエフ":{"tags":{"name":"スリーエフ","shop":"convenience"},"name":"スリーエフ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/8 à Huit":{"tags":{"name":"8 à Huit","shop":"convenience"},"name":"8 à Huit","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Żabka":{"tags":{"name":"Żabka","shop":"convenience"},"name":"Żabka","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Almacen":{"tags":{"name":"Almacen","shop":"convenience"},"name":"Almacen","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Vival":{"tags":{"name":"Vival","shop":"convenience"},"name":"Vival","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/FamilyMart":{"tags":{"name":"FamilyMart","shop":"convenience"},"name":"FamilyMart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ファミリーマート":{"tags":{"name":"ファミリーマート","name:en":"FamilyMart","shop":"convenience"},"name":"ファミリーマート","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Sunkus":{"tags":{"name":"Sunkus","shop":"convenience"},"name":"Sunkus","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/セブンイレブン(Seven-Eleven)":{"tags":{"name":"セブンイレブン(Seven-Eleven)","shop":"convenience"},"name":"セブンイレブン(Seven-Eleven)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Jednota":{"tags":{"name":"Jednota","shop":"convenience"},"name":"Jednota","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Магазин":{"tags":{"name":"Магазин","shop":"convenience"},"name":"Магазин","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Гастроном":{"tags":{"name":"Гастроном","shop":"convenience"},"name":"Гастроном","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Centra":{"tags":{"name":"Centra","shop":"convenience"},"name":"Centra","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/サークルK":{"tags":{"name":"サークルK","name:en":"Circle K","shop":"convenience"},"name":"サークルK","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Wawa":{"tags":{"name":"Wawa","shop":"convenience"},"name":"Wawa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Proxi":{"tags":{"name":"Proxi","shop":"convenience"},"name":"Proxi","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Универсам":{"tags":{"name":"Универсам","shop":"convenience"},"name":"Универсам","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Groszek":{"tags":{"name":"Groszek","shop":"convenience"},"name":"Groszek","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Select":{"tags":{"name":"Select","shop":"convenience"},"name":"Select","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Večerka":{"tags":{"name":"Večerka","shop":"convenience"},"name":"Večerka","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Potraviny":{"tags":{"name":"Potraviny","shop":"convenience"},"name":"Potraviny","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Смак":{"tags":{"name":"Смак","shop":"convenience"},"name":"Смак","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Эконом":{"tags":{"name":"Эконом","shop":"convenience"},"name":"Эконом","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Березка":{"tags":{"name":"Березка","shop":"convenience"},"name":"Березка","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Społem":{"tags":{"name":"Społem","shop":"convenience"},"name":"Społem","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Cumberland Farms":{"tags":{"name":"Cumberland Farms","shop":"convenience"},"name":"Cumberland Farms","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Tesco Lotus Express":{"tags":{"name":"Tesco Lotus Express","shop":"convenience"},"name":"Tesco Lotus Express","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Kiosk":{"tags":{"name":"Kiosk","shop":"convenience"},"name":"Kiosk","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Sklep spożywczy":{"tags":{"name":"Sklep spożywczy","shop":"convenience"},"name":"Sklep spożywczy","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/24 часа":{"tags":{"name":"24 часа","shop":"convenience"},"name":"24 часа","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Минимаркет":{"tags":{"name":"Минимаркет","shop":"convenience"},"name":"Минимаркет","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Oxxo":{"tags":{"name":"Oxxo","shop":"convenience"},"name":"Oxxo","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/abc":{"tags":{"name":"abc","shop":"convenience"},"name":"abc","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/7/11":{"tags":{"name":"7/11","shop":"convenience"},"name":"7/11","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Stewart's":{"tags":{"name":"Stewart's","shop":"convenience"},"name":"Stewart's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продукти":{"tags":{"name":"Продукти","shop":"convenience"},"name":"Продукти","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ローソンストア100 (LAWSON STORE 100)":{"tags":{"name":"ローソンストア100 (LAWSON STORE 100)","shop":"convenience"},"name":"ローソンストア100 (LAWSON STORE 100)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Радуга":{"tags":{"name":"Радуга","shop":"convenience"},"name":"Радуга","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ローソンストア100":{"tags":{"name":"ローソンストア100","shop":"convenience"},"name":"ローソンストア100","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/เซเว่นอีเลฟเว่น":{"tags":{"name":"เซเว่นอีเลฟเว่น","shop":"convenience"},"name":"เซเว่นอีเลฟเว่น","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Фортуна":{"tags":{"name":"Фортуна","shop":"convenience"},"name":"Фортуна","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Picard":{"tags":{"name":"Picard","shop":"convenience"},"name":"Picard","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Four Square":{"tags":{"name":"Four Square","shop":"convenience"},"name":"Four Square","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Визит":{"tags":{"name":"Визит","shop":"convenience"},"name":"Визит","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Авоська":{"tags":{"name":"Авоська","shop":"convenience"},"name":"Авоська","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Dollar General":{"tags":{"name":"Dollar General","shop":"convenience"},"name":"Dollar General","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Studenac":{"tags":{"name":"Studenac","shop":"convenience"},"name":"Studenac","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Central Convenience Store":{"tags":{"name":"Central Convenience Store","shop":"convenience"},"name":"Central Convenience Store","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/продукты":{"tags":{"name":"продукты","shop":"convenience"},"name":"продукты","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Кулинария":{"tags":{"name":"Кулинария","shop":"convenience"},"name":"Кулинария","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/全家":{"tags":{"name":"全家","shop":"convenience"},"name":"全家","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Мечта":{"tags":{"name":"Мечта","shop":"convenience"},"name":"Мечта","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Epicerie":{"tags":{"name":"Epicerie","shop":"convenience"},"name":"Epicerie","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Кировский":{"tags":{"name":"Кировский","shop":"convenience"},"name":"Кировский","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Food Mart":{"tags":{"name":"Food Mart","shop":"convenience"},"name":"Food Mart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Delikatesy":{"tags":{"name":"Delikatesy","shop":"convenience"},"name":"Delikatesy","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ポプラ":{"tags":{"name":"ポプラ","shop":"convenience"},"name":"ポプラ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Lewiatan":{"tags":{"name":"Lewiatan","shop":"convenience"},"name":"Lewiatan","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продуктовый магазин":{"tags":{"name":"Продуктовый магазин","shop":"convenience"},"name":"Продуктовый магазин","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продуктовый":{"tags":{"name":"Продуктовый","shop":"convenience"},"name":"Продуктовый","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/セイコーマート (Seicomart)":{"tags":{"name":"セイコーマート (Seicomart)","shop":"convenience"},"name":"セイコーマート (Seicomart)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Виктория":{"tags":{"name":"Виктория","shop":"convenience"},"name":"Виктория","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Весна":{"tags":{"name":"Весна","shop":"convenience"},"name":"Весна","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mini Market Non-Stop":{"tags":{"name":"Mini Market Non-Stop","shop":"convenience"},"name":"Mini Market Non-Stop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Копеечка":{"tags":{"name":"Копеечка","shop":"convenience"},"name":"Копеечка","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Royal Farms":{"tags":{"name":"Royal Farms","shop":"convenience"},"name":"Royal Farms","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Alfamart":{"tags":{"name":"Alfamart","shop":"convenience"},"name":"Alfamart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Indomaret":{"tags":{"name":"Indomaret","shop":"convenience"},"name":"Indomaret","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/магазин":{"tags":{"name":"магазин","shop":"convenience"},"name":"магазин","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/全家便利商店":{"tags":{"name":"全家便利商店","shop":"convenience"},"name":"全家便利商店","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Boutique":{"tags":{"name":"Boutique","shop":"convenience"},"name":"Boutique","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/მარკეტი (Market)":{"tags":{"name":"მარკეტი (Market)","shop":"convenience"},"name":"მარკეტი (Market)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Stores":{"tags":{"name":"Stores","shop":"convenience"},"name":"Stores","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/dm":{"tags":{"name":"dm","shop":"chemist"},"name":"dm","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Müller":{"tags":{"name":"Müller","shop":"chemist"},"name":"Müller","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Schlecker":{"tags":{"name":"Schlecker","shop":"chemist"},"name":"Schlecker","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Etos":{"tags":{"name":"Etos","shop":"chemist"},"name":"Etos","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Bipa":{"tags":{"name":"Bipa","shop":"chemist"},"name":"Bipa","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Rossmann":{"tags":{"name":"Rossmann","shop":"chemist"},"name":"Rossmann","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/DM Drogeriemarkt":{"tags":{"name":"DM Drogeriemarkt","shop":"chemist"},"name":"DM Drogeriemarkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Ihr Platz":{"tags":{"name":"Ihr Platz","shop":"chemist"},"name":"Ihr Platz","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Douglas":{"tags":{"name":"Douglas","shop":"chemist"},"name":"Douglas","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Kruidvat":{"tags":{"name":"Kruidvat","shop":"chemist"},"name":"Kruidvat","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/car_repair/Kwik Fit":{"tags":{"name":"Kwik Fit","shop":"car_repair"},"name":"Kwik Fit","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/ATU":{"tags":{"name":"ATU","shop":"car_repair"},"name":"ATU","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Midas":{"tags":{"name":"Midas","shop":"car_repair"},"name":"Midas","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Feu Vert":{"tags":{"name":"Feu Vert","shop":"car_repair"},"name":"Feu Vert","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Norauto":{"tags":{"name":"Norauto","shop":"car_repair"},"name":"Norauto","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Speedy":{"tags":{"name":"Speedy","shop":"car_repair"},"name":"Speedy","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Pit Stop":{"tags":{"name":"Pit Stop","shop":"car_repair"},"name":"Pit Stop","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Jiffy Lube":{"tags":{"name":"Jiffy Lube","shop":"car_repair"},"name":"Jiffy Lube","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Шиномонтаж":{"tags":{"name":"Шиномонтаж","shop":"car_repair"},"name":"Шиномонтаж","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/СТО":{"tags":{"name":"СТО","shop":"car_repair"},"name":"СТО","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/O'Reilly Auto Parts":{"tags":{"name":"O'Reilly Auto Parts","shop":"car_repair"},"name":"O'Reilly Auto Parts","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Carglass":{"tags":{"name":"Carglass","shop":"car_repair"},"name":"Carglass","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/шиномонтаж":{"tags":{"name":"шиномонтаж","shop":"car_repair"},"name":"шиномонтаж","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Euromaster":{"tags":{"name":"Euromaster","shop":"car_repair"},"name":"Euromaster","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Firestone":{"tags":{"name":"Firestone","shop":"car_repair"},"name":"Firestone","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Автосервис":{"tags":{"name":"Автосервис","shop":"car_repair"},"name":"Автосервис","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Advance Auto Parts":{"tags":{"name":"Advance Auto Parts","shop":"car_repair"},"name":"Advance Auto Parts","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Roady":{"tags":{"name":"Roady","shop":"car_repair"},"name":"Roady","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/furniture/IKEA":{"tags":{"name":"IKEA","shop":"furniture"},"name":"IKEA","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Jysk":{"tags":{"name":"Jysk","shop":"furniture"},"name":"Jysk","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Roller":{"tags":{"name":"Roller","shop":"furniture"},"name":"Roller","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Dänisches Bettenlager":{"tags":{"name":"Dänisches Bettenlager","shop":"furniture"},"name":"Dänisches Bettenlager","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Conforama":{"tags":{"name":"Conforama","shop":"furniture"},"name":"Conforama","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Matratzen Concord":{"tags":{"name":"Matratzen Concord","shop":"furniture"},"name":"Matratzen Concord","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Мебель":{"tags":{"name":"Мебель","shop":"furniture"},"name":"Мебель","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/But":{"tags":{"name":"But","shop":"furniture"},"name":"But","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hornbach":{"tags":{"name":"Hornbach","shop":"doityourself"},"name":"Hornbach","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/B&Q":{"tags":{"name":"B&Q","shop":"doityourself"},"name":"B&Q","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hubo":{"tags":{"name":"Hubo","shop":"doityourself"},"name":"Hubo","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Mr Bricolage":{"tags":{"name":"Mr Bricolage","shop":"doityourself"},"name":"Mr Bricolage","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Gamma":{"tags":{"name":"Gamma","shop":"doityourself"},"name":"Gamma","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/OBI":{"tags":{"name":"OBI","shop":"doityourself"},"name":"OBI","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Lowes":{"tags":{"name":"Lowes","shop":"doityourself"},"name":"Lowes","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Wickes":{"tags":{"name":"Wickes","shop":"doityourself"},"name":"Wickes","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hagebau":{"tags":{"name":"Hagebau","shop":"doityourself"},"name":"Hagebau","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Max Bahr":{"tags":{"name":"Max Bahr","shop":"doityourself"},"name":"Max Bahr","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Castorama":{"tags":{"name":"Castorama","shop":"doityourself"},"name":"Castorama","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Rona":{"tags":{"name":"Rona","shop":"doityourself"},"name":"Rona","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Home Depot":{"tags":{"name":"Home Depot","shop":"doityourself"},"name":"Home Depot","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Toom Baumarkt":{"tags":{"name":"Toom Baumarkt","shop":"doityourself"},"name":"Toom Baumarkt","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Homebase":{"tags":{"name":"Homebase","shop":"doityourself"},"name":"Homebase","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Baumax":{"tags":{"name":"Baumax","shop":"doityourself"},"name":"Baumax","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Lagerhaus":{"tags":{"name":"Lagerhaus","shop":"doityourself"},"name":"Lagerhaus","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bauhaus":{"tags":{"name":"Bauhaus","shop":"doityourself"},"name":"Bauhaus","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Canadian Tire":{"tags":{"name":"Canadian Tire","shop":"doityourself"},"name":"Canadian Tire","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Leroy Merlin":{"tags":{"name":"Leroy Merlin","shop":"doityourself"},"name":"Leroy Merlin","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hellweg":{"tags":{"name":"Hellweg","shop":"doityourself"},"name":"Hellweg","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Brico":{"tags":{"name":"Brico","shop":"doityourself"},"name":"Brico","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bricomarché":{"tags":{"name":"Bricomarché","shop":"doityourself"},"name":"Bricomarché","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Toom":{"tags":{"name":"Toom","shop":"doityourself"},"name":"Toom","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hagebaumarkt":{"tags":{"name":"Hagebaumarkt","shop":"doityourself"},"name":"Hagebaumarkt","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Praktiker":{"tags":{"name":"Praktiker","shop":"doityourself"},"name":"Praktiker","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Menards":{"tags":{"name":"Menards","shop":"doityourself"},"name":"Menards","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Weldom":{"tags":{"name":"Weldom","shop":"doityourself"},"name":"Weldom","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bunnings Warehouse":{"tags":{"name":"Bunnings Warehouse","shop":"doityourself"},"name":"Bunnings Warehouse","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Ace Hardware":{"tags":{"name":"Ace Hardware","shop":"doityourself"},"name":"Ace Hardware","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Home Hardware":{"tags":{"name":"Home Hardware","shop":"doityourself"},"name":"Home Hardware","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Стройматериалы":{"tags":{"name":"Стройматериалы","shop":"doityourself"},"name":"Стройматериалы","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bricorama":{"tags":{"name":"Bricorama","shop":"doityourself"},"name":"Bricorama","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Point P":{"tags":{"name":"Point P","shop":"doityourself"},"name":"Point P","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/Staples":{"tags":{"name":"Staples","shop":"stationery"},"name":"Staples","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/McPaper":{"tags":{"name":"McPaper","shop":"stationery"},"name":"McPaper","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/Office Depot":{"tags":{"name":"Office Depot","shop":"stationery"},"name":"Office Depot","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/Канцтовары":{"tags":{"name":"Канцтовары","shop":"stationery"},"name":"Канцтовары","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/car/Skoda":{"tags":{"name":"Skoda","shop":"car"},"name":"Skoda","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/BMW":{"tags":{"name":"BMW","shop":"car"},"name":"BMW","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Citroen":{"tags":{"name":"Citroen","shop":"car"},"name":"Citroen","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Renault":{"tags":{"name":"Renault","shop":"car"},"name":"Renault","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Mercedes-Benz":{"tags":{"name":"Mercedes-Benz","shop":"car"},"name":"Mercedes-Benz","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Volvo":{"tags":{"name":"Volvo","shop":"car"},"name":"Volvo","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Ford":{"tags":{"name":"Ford","shop":"car"},"name":"Ford","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Volkswagen":{"tags":{"name":"Volkswagen","shop":"car"},"name":"Volkswagen","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Mazda":{"tags":{"name":"Mazda","shop":"car"},"name":"Mazda","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Mitsubishi":{"tags":{"name":"Mitsubishi","shop":"car"},"name":"Mitsubishi","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Fiat":{"tags":{"name":"Fiat","shop":"car"},"name":"Fiat","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Автозапчасти":{"tags":{"name":"Автозапчасти","shop":"car"},"name":"Автозапчасти","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Opel":{"tags":{"name":"Opel","shop":"car"},"name":"Opel","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Audi":{"tags":{"name":"Audi","shop":"car"},"name":"Audi","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Toyota":{"tags":{"name":"Toyota","shop":"car"},"name":"Toyota","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Nissan":{"tags":{"name":"Nissan","shop":"car"},"name":"Nissan","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Suzuki":{"tags":{"name":"Suzuki","shop":"car"},"name":"Suzuki","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Honda":{"tags":{"name":"Honda","shop":"car"},"name":"Honda","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Peugeot":{"tags":{"name":"Peugeot","shop":"car"},"name":"Peugeot","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Hyundai":{"tags":{"name":"Hyundai","shop":"car"},"name":"Hyundai","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Subaru":{"tags":{"name":"Subaru","shop":"car"},"name":"Subaru","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Chevrolet":{"tags":{"name":"Chevrolet","shop":"car"},"name":"Chevrolet","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Автомагазин":{"tags":{"name":"Автомагазин","shop":"car"},"name":"Автомагазин","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/clothes/Matalan":{"tags":{"name":"Matalan","shop":"clothes"},"name":"Matalan","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/KiK":{"tags":{"name":"KiK","shop":"clothes"},"name":"KiK","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/H&M":{"tags":{"name":"H&M","shop":"clothes"},"name":"H&M","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Urban Outfitters":{"tags":{"name":"Urban Outfitters","shop":"clothes"},"name":"Urban Outfitters","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Vögele":{"tags":{"name":"Vögele","shop":"clothes"},"name":"Vögele","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Zeeman":{"tags":{"name":"Zeeman","shop":"clothes"},"name":"Zeeman","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Takko":{"tags":{"name":"Takko","shop":"clothes"},"name":"Takko","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/C&A":{"tags":{"name":"C&A","shop":"clothes"},"name":"C&A","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Zara":{"tags":{"name":"Zara","shop":"clothes"},"name":"Zara","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Vero Moda":{"tags":{"name":"Vero Moda","shop":"clothes"},"name":"Vero Moda","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/NKD":{"tags":{"name":"NKD","shop":"clothes"},"name":"NKD","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ernsting's family":{"tags":{"name":"Ernsting's family","shop":"clothes"},"name":"Ernsting's family","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Winners":{"tags":{"name":"Winners","shop":"clothes"},"name":"Winners","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/River Island":{"tags":{"name":"River Island","shop":"clothes"},"name":"River Island","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Next":{"tags":{"name":"Next","shop":"clothes"},"name":"Next","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Gap":{"tags":{"name":"Gap","shop":"clothes"},"name":"Gap","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Adidas":{"tags":{"name":"Adidas","shop":"clothes"},"name":"Adidas","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Mr Price":{"tags":{"name":"Mr Price","shop":"clothes"},"name":"Mr Price","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Pep":{"tags":{"name":"Pep","shop":"clothes"},"name":"Pep","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Edgars":{"tags":{"name":"Edgars","shop":"clothes"},"name":"Edgars","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ackermans":{"tags":{"name":"Ackermans","shop":"clothes"},"name":"Ackermans","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Truworths":{"tags":{"name":"Truworths","shop":"clothes"},"name":"Truworths","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ross":{"tags":{"name":"Ross","shop":"clothes"},"name":"Ross","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Burton":{"tags":{"name":"Burton","shop":"clothes"},"name":"Burton","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Dorothy Perkins":{"tags":{"name":"Dorothy Perkins","shop":"clothes"},"name":"Dorothy Perkins","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Lindex":{"tags":{"name":"Lindex","shop":"clothes"},"name":"Lindex","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/s.Oliver":{"tags":{"name":"s.Oliver","shop":"clothes"},"name":"s.Oliver","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Cecil":{"tags":{"name":"Cecil","shop":"clothes"},"name":"Cecil","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Dress Barn":{"tags":{"name":"Dress Barn","shop":"clothes"},"name":"Dress Barn","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Old Navy":{"tags":{"name":"Old Navy","shop":"clothes"},"name":"Old Navy","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jack & Jones":{"tags":{"name":"Jack & Jones","shop":"clothes"},"name":"Jack & Jones","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Pimkie":{"tags":{"name":"Pimkie","shop":"clothes"},"name":"Pimkie","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Esprit":{"tags":{"name":"Esprit","shop":"clothes"},"name":"Esprit","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Primark":{"tags":{"name":"Primark","shop":"clothes"},"name":"Primark","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Bonita":{"tags":{"name":"Bonita","shop":"clothes"},"name":"Bonita","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Mexx":{"tags":{"name":"Mexx","shop":"clothes"},"name":"Mexx","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Gerry Weber":{"tags":{"name":"Gerry Weber","shop":"clothes"},"name":"Gerry Weber","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Tally Weijl":{"tags":{"name":"Tally Weijl","shop":"clothes"},"name":"Tally Weijl","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Mango":{"tags":{"name":"Mango","shop":"clothes"},"name":"Mango","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/TK Maxx":{"tags":{"name":"TK Maxx","shop":"clothes"},"name":"TK Maxx","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Benetton":{"tags":{"name":"Benetton","shop":"clothes"},"name":"Benetton","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ulla Popken":{"tags":{"name":"Ulla Popken","shop":"clothes"},"name":"Ulla Popken","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/AWG":{"tags":{"name":"AWG","shop":"clothes"},"name":"AWG","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Tommy Hilfiger":{"tags":{"name":"Tommy Hilfiger","shop":"clothes"},"name":"Tommy Hilfiger","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/New Yorker":{"tags":{"name":"New Yorker","shop":"clothes"},"name":"New Yorker","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Orsay":{"tags":{"name":"Orsay","shop":"clothes"},"name":"Orsay","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jeans Fritz":{"tags":{"name":"Jeans Fritz","shop":"clothes"},"name":"Jeans Fritz","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Charles Vögele":{"tags":{"name":"Charles Vögele","shop":"clothes"},"name":"Charles Vögele","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/New Look":{"tags":{"name":"New Look","shop":"clothes"},"name":"New Look","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Lacoste":{"tags":{"name":"Lacoste","shop":"clothes"},"name":"Lacoste","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Etam":{"tags":{"name":"Etam","shop":"clothes"},"name":"Etam","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Kiabi":{"tags":{"name":"Kiabi","shop":"clothes"},"name":"Kiabi","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jack Wolfskin":{"tags":{"name":"Jack Wolfskin","shop":"clothes"},"name":"Jack Wolfskin","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/American Apparel":{"tags":{"name":"American Apparel","shop":"clothes"},"name":"American Apparel","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Men's Wearhouse":{"tags":{"name":"Men's Wearhouse","shop":"clothes"},"name":"Men's Wearhouse","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Intimissimi":{"tags":{"name":"Intimissimi","shop":"clothes"},"name":"Intimissimi","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/United Colors of Benetton":{"tags":{"name":"United Colors of Benetton","shop":"clothes"},"name":"United Colors of Benetton","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jules":{"tags":{"name":"Jules","shop":"clothes"},"name":"Jules","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Second Hand":{"tags":{"name":"Second Hand","shop":"clothes"},"name":"Second Hand","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/AOKI":{"tags":{"name":"AOKI","shop":"clothes"},"name":"AOKI","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Calzedonia":{"tags":{"name":"Calzedonia","shop":"clothes"},"name":"Calzedonia","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/洋服の青山":{"tags":{"name":"洋服の青山","shop":"clothes"},"name":"洋服の青山","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Levi's":{"tags":{"name":"Levi's","shop":"clothes"},"name":"Levi's","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Celio":{"tags":{"name":"Celio","shop":"clothes"},"name":"Celio","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/TJ Maxx":{"tags":{"name":"TJ Maxx","shop":"clothes"},"name":"TJ Maxx","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Promod":{"tags":{"name":"Promod","shop":"clothes"},"name":"Promod","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Street One":{"tags":{"name":"Street One","shop":"clothes"},"name":"Street One","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/ユニクロ":{"tags":{"name":"ユニクロ","shop":"clothes"},"name":"ユニクロ","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Banana Republic":{"tags":{"name":"Banana Republic","shop":"clothes"},"name":"Banana Republic","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Одежда":{"tags":{"name":"Одежда","shop":"clothes"},"name":"Одежда","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Marshalls":{"tags":{"name":"Marshalls","shop":"clothes"},"name":"Marshalls","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/La Halle":{"tags":{"name":"La Halle","shop":"clothes"},"name":"La Halle","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Peacocks":{"tags":{"name":"Peacocks","shop":"clothes"},"name":"Peacocks","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/しまむら":{"tags":{"name":"しまむら","shop":"clothes"},"name":"しまむら","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/books/Bruna":{"tags":{"name":"Bruna","shop":"books"},"name":"Bruna","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Waterstones":{"tags":{"name":"Waterstones","shop":"books"},"name":"Waterstones","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Libro":{"tags":{"name":"Libro","shop":"books"},"name":"Libro","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Barnes & Noble":{"tags":{"name":"Barnes & Noble","shop":"books"},"name":"Barnes & Noble","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Weltbild":{"tags":{"name":"Weltbild","shop":"books"},"name":"Weltbild","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Thalia":{"tags":{"name":"Thalia","shop":"books"},"name":"Thalia","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Книги":{"tags":{"name":"Книги","shop":"books"},"name":"Книги","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/department_store/Debenhams":{"tags":{"name":"Debenhams","shop":"department_store"},"name":"Debenhams","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Karstadt":{"tags":{"name":"Karstadt","shop":"department_store"},"name":"Karstadt","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Kmart":{"tags":{"name":"Kmart","shop":"department_store"},"name":"Kmart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Target":{"tags":{"name":"Target","shop":"department_store"},"name":"Target","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Galeria Kaufhof":{"tags":{"name":"Galeria Kaufhof","shop":"department_store"},"name":"Galeria Kaufhof","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Marks & Spencer":{"tags":{"name":"Marks & Spencer","shop":"department_store"},"name":"Marks & Spencer","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Big W":{"tags":{"name":"Big W","shop":"department_store"},"name":"Big W","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Woolworth":{"tags":{"name":"Woolworth","shop":"department_store"},"name":"Woolworth","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Универмаг":{"tags":{"name":"Универмаг","shop":"department_store"},"name":"Универмаг","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Sears":{"tags":{"name":"Sears","shop":"department_store"},"name":"Sears","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Kohl's":{"tags":{"name":"Kohl's","shop":"department_store"},"name":"Kohl's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Macy's":{"tags":{"name":"Macy's","shop":"department_store"},"name":"Macy's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/JCPenney":{"tags":{"name":"JCPenney","shop":"department_store"},"name":"JCPenney","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/alcohol/Alko":{"tags":{"name":"Alko","shop":"alcohol"},"name":"Alko","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/The Beer Store":{"tags":{"name":"The Beer Store","shop":"alcohol"},"name":"The Beer Store","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Systembolaget":{"tags":{"name":"Systembolaget","shop":"alcohol"},"name":"Systembolaget","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/LCBO":{"tags":{"name":"LCBO","shop":"alcohol"},"name":"LCBO","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Ароматный мир":{"tags":{"name":"Ароматный мир","shop":"alcohol"},"name":"Ароматный мир","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Bargain Booze":{"tags":{"name":"Bargain Booze","shop":"alcohol"},"name":"Bargain Booze","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Nicolas":{"tags":{"name":"Nicolas","shop":"alcohol"},"name":"Nicolas","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/BWS":{"tags":{"name":"BWS","shop":"alcohol"},"name":"BWS","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Botilleria":{"tags":{"name":"Botilleria","shop":"alcohol"},"name":"Botilleria","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/SAQ":{"tags":{"name":"SAQ","shop":"alcohol"},"name":"SAQ","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Gall & Gall":{"tags":{"name":"Gall & Gall","shop":"alcohol"},"name":"Gall & Gall","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Живое пиво":{"tags":{"name":"Живое пиво","shop":"alcohol"},"name":"Живое пиво","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/bakery/Kamps":{"tags":{"name":"Kamps","shop":"bakery"},"name":"Kamps","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Banette":{"tags":{"name":"Banette","shop":"bakery"},"name":"Banette","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Bäckerei Schmidt":{"tags":{"name":"Bäckerei Schmidt","shop":"bakery"},"name":"Bäckerei Schmidt","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Anker":{"tags":{"name":"Anker","shop":"bakery"},"name":"Anker","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Hofpfisterei":{"tags":{"name":"Hofpfisterei","shop":"bakery"},"name":"Hofpfisterei","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Greggs":{"tags":{"name":"Greggs","shop":"bakery"},"name":"Greggs","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Oebel":{"tags":{"name":"Oebel","shop":"bakery"},"name":"Oebel","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Boulangerie":{"tags":{"name":"Boulangerie","shop":"bakery"},"name":"Boulangerie","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Stadtbäckerei":{"tags":{"name":"Stadtbäckerei","shop":"bakery"},"name":"Stadtbäckerei","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Steinecke":{"tags":{"name":"Steinecke","shop":"bakery"},"name":"Steinecke","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Ihle":{"tags":{"name":"Ihle","shop":"bakery"},"name":"Ihle","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Goldilocks":{"tags":{"name":"Goldilocks","shop":"bakery"},"name":"Goldilocks","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Dat Backhus":{"tags":{"name":"Dat Backhus","shop":"bakery"},"name":"Dat Backhus","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/K&U":{"tags":{"name":"K&U","shop":"bakery"},"name":"K&U","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Der Beck":{"tags":{"name":"Der Beck","shop":"bakery"},"name":"Der Beck","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Thürmann":{"tags":{"name":"Thürmann","shop":"bakery"},"name":"Thürmann","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Backwerk":{"tags":{"name":"Backwerk","shop":"bakery"},"name":"Backwerk","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Schäfer's":{"tags":{"name":"Schäfer's","shop":"bakery"},"name":"Schäfer's","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Panaderia":{"tags":{"name":"Panaderia","shop":"bakery"},"name":"Panaderia","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Goeken backen":{"tags":{"name":"Goeken backen","shop":"bakery"},"name":"Goeken backen","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Stadtbäckerei Junge":{"tags":{"name":"Stadtbäckerei Junge","shop":"bakery"},"name":"Stadtbäckerei Junge","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Boulangerie Patisserie":{"tags":{"name":"Boulangerie Patisserie","shop":"bakery"},"name":"Boulangerie Patisserie","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Paul":{"tags":{"name":"Paul","shop":"bakery"},"name":"Paul","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Хлеб":{"tags":{"name":"Хлеб","shop":"bakery"},"name":"Хлеб","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Пекарня":{"tags":{"name":"Пекарня","shop":"bakery"},"name":"Пекарня","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Кулиничи":{"tags":{"name":"Кулиничи","shop":"bakery"},"name":"Кулиничи","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Sports Direct":{"tags":{"name":"Sports Direct","shop":"sports"},"name":"Sports Direct","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Decathlon":{"tags":{"name":"Decathlon","shop":"sports"},"name":"Decathlon","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Intersport":{"tags":{"name":"Intersport","shop":"sports"},"name":"Intersport","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Sports Authority":{"tags":{"name":"Sports Authority","shop":"sports"},"name":"Sports Authority","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Спортмастер":{"tags":{"name":"Спортмастер","shop":"sports"},"name":"Спортмастер","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Sport 2000":{"tags":{"name":"Sport 2000","shop":"sports"},"name":"Sport 2000","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Dick's Sporting Goods":{"tags":{"name":"Dick's Sporting Goods","shop":"sports"},"name":"Dick's Sporting Goods","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Tedi":{"tags":{"name":"Tedi","shop":"variety_store"},"name":"Tedi","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Dollarama":{"tags":{"name":"Dollarama","shop":"variety_store"},"name":"Dollarama","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Family Dollar":{"tags":{"name":"Family Dollar","shop":"variety_store"},"name":"Family Dollar","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Dollar Tree":{"tags":{"name":"Dollar Tree","shop":"variety_store"},"name":"Dollar Tree","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Fressnapf":{"tags":{"name":"Fressnapf","shop":"pet"},"name":"Fressnapf","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/PetSmart":{"tags":{"name":"PetSmart","shop":"pet"},"name":"PetSmart","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Das Futterhaus":{"tags":{"name":"Das Futterhaus","shop":"pet"},"name":"Das Futterhaus","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Pets at Home":{"tags":{"name":"Pets at Home","shop":"pet"},"name":"Pets at Home","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Petco":{"tags":{"name":"Petco","shop":"pet"},"name":"Petco","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Зоомагазин":{"tags":{"name":"Зоомагазин","shop":"pet"},"name":"Зоомагазин","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Deichmann":{"tags":{"name":"Deichmann","shop":"shoes"},"name":"Deichmann","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Reno":{"tags":{"name":"Reno","shop":"shoes"},"name":"Reno","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Ecco":{"tags":{"name":"Ecco","shop":"shoes"},"name":"Ecco","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Clarks":{"tags":{"name":"Clarks","shop":"shoes"},"name":"Clarks","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/La Halle aux Chaussures":{"tags":{"name":"La Halle aux Chaussures","shop":"shoes"},"name":"La Halle aux Chaussures","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Brantano":{"tags":{"name":"Brantano","shop":"shoes"},"name":"Brantano","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Geox":{"tags":{"name":"Geox","shop":"shoes"},"name":"Geox","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Salamander":{"tags":{"name":"Salamander","shop":"shoes"},"name":"Salamander","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Обувь":{"tags":{"name":"Обувь","shop":"shoes"},"name":"Обувь","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Payless Shoe Source":{"tags":{"name":"Payless Shoe Source","shop":"shoes"},"name":"Payless Shoe Source","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Famous Footwear":{"tags":{"name":"Famous Footwear","shop":"shoes"},"name":"Famous Footwear","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Quick Schuh":{"tags":{"name":"Quick Schuh","shop":"shoes"},"name":"Quick Schuh","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Shoe Zone":{"tags":{"name":"Shoe Zone","shop":"shoes"},"name":"Shoe Zone","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Foot Locker":{"tags":{"name":"Foot Locker","shop":"shoes"},"name":"Foot Locker","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Bata":{"tags":{"name":"Bata","shop":"shoes"},"name":"Bata","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/ЦентрОбувь":{"tags":{"name":"ЦентрОбувь","shop":"shoes"},"name":"ЦентрОбувь","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/La Grande Récré":{"tags":{"name":"La Grande Récré","shop":"toys"},"name":"La Grande Récré","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Toys R Us":{"tags":{"name":"Toys R Us","shop":"toys"},"name":"Toys R Us","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Intertoys":{"tags":{"name":"Intertoys","shop":"toys"},"name":"Intertoys","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Детский мир":{"tags":{"name":"Детский мир","shop":"toys"},"name":"Детский мир","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Игрушки":{"tags":{"name":"Игрушки","shop":"toys"},"name":"Игрушки","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/travel_agency/Flight Centre":{"tags":{"name":"Flight Centre","shop":"travel_agency"},"name":"Flight Centre","icon":"suitcase","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/travel_agency/Thomas Cook":{"tags":{"name":"Thomas Cook","shop":"travel_agency"},"name":"Thomas Cook","icon":"suitcase","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/jewelry/Bijou Brigitte":{"tags":{"name":"Bijou Brigitte","shop":"jewelry"},"name":"Bijou Brigitte","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/jewelry/Christ":{"tags":{"name":"Christ","shop":"jewelry"},"name":"Christ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/jewelry/Swarovski":{"tags":{"name":"Swarovski","shop":"jewelry"},"name":"Swarovski","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Fielmann":{"tags":{"name":"Fielmann","shop":"optician"},"name":"Fielmann","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Apollo Optik":{"tags":{"name":"Apollo Optik","shop":"optician"},"name":"Apollo Optik","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Vision Express":{"tags":{"name":"Vision Express","shop":"optician"},"name":"Vision Express","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Оптика":{"tags":{"name":"Оптика","shop":"optician"},"name":"Оптика","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Optic 2000":{"tags":{"name":"Optic 2000","shop":"optician"},"name":"Optic 2000","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Alain Afflelou":{"tags":{"name":"Alain Afflelou","shop":"optician"},"name":"Alain Afflelou","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Specsavers":{"tags":{"name":"Specsavers","shop":"optician"},"name":"Specsavers","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Krys":{"tags":{"name":"Krys","shop":"optician"},"name":"Krys","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Atol":{"tags":{"name":"Atol","shop":"optician"},"name":"Atol","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/video/Blockbuster":{"tags":{"name":"Blockbuster","shop":"video"},"name":"Blockbuster","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/video/World of Video":{"tags":{"name":"World of Video","shop":"video"},"name":"World of Video","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Билайн":{"tags":{"name":"Билайн","shop":"mobile_phone"},"name":"Билайн","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/ソフトバンクショップ (SoftBank shop)":{"tags":{"name":"ソフトバンクショップ (SoftBank shop)","shop":"mobile_phone"},"name":"ソフトバンクショップ (SoftBank shop)","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Vodafone":{"tags":{"name":"Vodafone","shop":"mobile_phone"},"name":"Vodafone","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/O2":{"tags":{"name":"O2","shop":"mobile_phone"},"name":"O2","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Carphone Warehouse":{"tags":{"name":"Carphone Warehouse","shop":"mobile_phone"},"name":"Carphone Warehouse","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Orange":{"tags":{"name":"Orange","shop":"mobile_phone"},"name":"Orange","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Verizon Wireless":{"tags":{"name":"Verizon Wireless","shop":"mobile_phone"},"name":"Verizon Wireless","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Sprint":{"tags":{"name":"Sprint","shop":"mobile_phone"},"name":"Sprint","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/T-Mobile":{"tags":{"name":"T-Mobile","shop":"mobile_phone"},"name":"T-Mobile","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/МТС":{"tags":{"name":"МТС","shop":"mobile_phone"},"name":"МТС","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Евросеть":{"tags":{"name":"Евросеть","shop":"mobile_phone"},"name":"Евросеть","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Bell":{"tags":{"name":"Bell","shop":"mobile_phone"},"name":"Bell","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/The Phone House":{"tags":{"name":"The Phone House","shop":"mobile_phone"},"name":"The Phone House","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/SFR":{"tags":{"name":"SFR","shop":"mobile_phone"},"name":"SFR","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Связной":{"tags":{"name":"Связной","shop":"mobile_phone"},"name":"Связной","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Мегафон":{"tags":{"name":"Мегафон","shop":"mobile_phone"},"name":"Мегафон","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/AT&T":{"tags":{"name":"AT&T","shop":"mobile_phone"},"name":"AT&T","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/ドコモショップ (docomo shop)":{"tags":{"name":"ドコモショップ (docomo shop)","shop":"mobile_phone"},"name":"ドコモショップ (docomo shop)","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/au":{"tags":{"name":"au","shop":"mobile_phone"},"name":"au","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Movistar":{"tags":{"name":"Movistar","shop":"mobile_phone"},"name":"Movistar","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Bitė":{"tags":{"name":"Bitė","shop":"mobile_phone"},"name":"Bitė","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/computer/PC World":{"tags":{"name":"PC World","shop":"computer"},"name":"PC World","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/computer/DNS":{"tags":{"name":"DNS","shop":"computer"},"name":"DNS","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Klier":{"tags":{"name":"Klier","shop":"hairdresser"},"name":"Klier","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Supercuts":{"tags":{"name":"Supercuts","shop":"hairdresser"},"name":"Supercuts","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Hairkiller":{"tags":{"name":"Hairkiller","shop":"hairdresser"},"name":"Hairkiller","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Great Clips":{"tags":{"name":"Great Clips","shop":"hairdresser"},"name":"Great Clips","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Парикмахерская":{"tags":{"name":"Парикмахерская","shop":"hairdresser"},"name":"Парикмахерская","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Стиль":{"tags":{"name":"Стиль","shop":"hairdresser"},"name":"Стиль","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Franck Provost":{"tags":{"name":"Franck Provost","shop":"hairdresser"},"name":"Franck Provost","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Салон красоты":{"tags":{"name":"Салон красоты","shop":"hairdresser"},"name":"Салон красоты","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hardware/1000 мелочей":{"tags":{"name":"1000 мелочей","shop":"hardware"},"name":"1000 мелочей","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hardware/Хозтовары":{"tags":{"name":"Хозтовары","shop":"hardware"},"name":"Хозтовары","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/motorcycle/Yamaha":{"tags":{"name":"Yamaha","shop":"motorcycle"},"name":"Yamaha","icon":"scooter","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true}};
18630
18631 var defaults = {"area":["category-landuse","category-building","category-water-area","category-natural-area","leisure/park","amenity/hospital","amenity/place_of_worship","amenity/cafe","amenity/restaurant","area"],"line":["category-road","category-rail","category-path","category-water-line","category-barrier","category-natural-line","power/line","line"],"point":["category-natural-point","leisure/park","amenity/hospital","amenity/place_of_worship","amenity/cafe","amenity/restaurant","amenity/fast_food","amenity/bar","amenity/bank","shop/supermarket","point"],"vertex":["highway/crosswalk","highway/crossing","railway/level_crossing","highway/traffic_signals","highway/turning_circle","highway/turning_loop","traffic_calming","highway/mini_roundabout","highway/motorway_junction","vertex"],"relation":["category-route","category-restriction","type/boundary","type/multipolygon","type/site","relation"]};
18632
18633 var categories = {"category-barrier":{"icon":"roadblock","geometry":"line","name":"Barrier Features","members":["barrier/fence","barrier/wall","barrier/ditch","barrier/gate","barrier"]},"category-building":{"icon":"building","geometry":"area","name":"Building Features","members":["building","building/house","building/apartments","building/commercial","building/industrial","building/residential"]},"category-golf":{"icon":"golf","geometry":"area","name":"Golf Features","members":["golf/fairway","golf/green","golf/lateral_water_hazard_area","golf/rough","golf/bunker","golf/tee","golf/water_hazard_area"]},"category-landuse":{"icon":"landuse","geometry":"area","name":"Land Use Features","members":["landuse/residential","landuse/industrial","landuse/commercial","landuse/retail","landuse/farmland","landuse/farmyard","landuse/forest","landuse/meadow","landuse/aquaculture","landuse/cemetery","landuse/military"]},"category-natural-area":{"icon":"natural","geometry":"area","name":"Natural Features","members":["natural/water","natural/wood","natural/scrub","natural/wetland","natural/grassland","natural/heath","natural/bare_rock","natural/beach","natural/cave_entrance","natural/glacier"]},"category-natural-line":{"icon":"natural","geometry":"line","name":"Natural Features","members":["natural/coastline","natural/tree_row"]},"category-natural-point":{"icon":"natural","geometry":"point","name":"Natural Features","members":["natural/peak","natural/cliff","natural/beach","natural/cave_entrance"]},"category-path":{"icon":"category-path","geometry":"line","name":"Path Features","members":["footway/crosswalk","footway/sidewalk","highway/steps","highway/path","highway/footway","highway/cycleway","highway/bridleway","highway/pedestrian"]},"category-rail":{"icon":"category-rail","geometry":"line","name":"Rail Features","members":["railway/rail","railway/subway","railway/tram","railway/monorail","railway/disused","railway/abandoned"]},"category-restriction":{"icon":"restriction","geometry":"relation","name":"Restriction Features","members":["type/restriction/no_left_turn","type/restriction/no_right_turn","type/restriction/no_straight_on","type/restriction/no_u_turn","type/restriction/only_left_turn","type/restriction/only_right_turn","type/restriction/only_straight_on","type/restriction"]},"category-road":{"icon":"category-roads","geometry":"line","name":"Road Features","members":["highway/residential","highway/motorway","highway/trunk","highway/primary","highway/secondary","highway/tertiary","highway/living_street","highway/unclassified","highway/service","highway/track","highway/motorway_link","highway/trunk_link","highway/primary_link","highway/secondary_link","highway/tertiary_link","highway/road"]},"category-route":{"icon":"route","geometry":"relation","name":"Route Features","members":["type/route/road","type/route/bicycle","type/route/foot","type/route/hiking","type/route/horse","type/route/bus","type/route/train","type/route/tram","type/route/ferry","type/route/power","type/route/pipeline","type/route/detour","type/route_master","type/route"]},"category-water-area":{"icon":"water","geometry":"area","name":"Water Features","members":["natural/water/lake","natural/water/pond","natural/water/reservoir","natural/water"]},"category-water-line":{"icon":"category-water","geometry":"line","name":"Water Features","members":["waterway/river","waterway/stream","waterway/canal","waterway/ditch","waterway/drain"]}};
18634
18635 var fields = {"access_simple":{"key":"access","type":"combo","label":"Allowed Access","options":["permissive","private","customers","no"]},"access_toilets":{"key":"access","type":"combo","label":"Access","options":["yes","permissive","private","customers"]},"access":{"keys":["access","foot","motor_vehicle","bicycle","horse"],"reference":{"key":"access"},"type":"access","label":"Allowed Access","placeholder":"Not Specified","strings":{"types":{"access":"All","foot":"Foot","motor_vehicle":"Motor Vehicles","bicycle":"Bicycles","horse":"Horses"},"options":{"yes":{"title":"Allowed","description":"Access permitted by law; a right of way"},"no":{"title":"Prohibited","description":"Access not permitted to the general public"},"permissive":{"title":"Permissive","description":"Access permitted until such time as the owner revokes the permission"},"private":{"title":"Private","description":"Access permitted only with permission of the owner on an individual basis"},"designated":{"title":"Designated","description":"Access permitted according to signs or specific local laws"},"destination":{"title":"Destination","description":"Access permitted only to reach a destination"},"dismount":{"title":"Dismount","description":"Access permitted but rider must dismount"}}}},"address":{"type":"address","keys":["addr:block_number","addr:city","addr:block_number","addr:conscriptionnumber","addr:county","addr:country","addr:county","addr:district","addr:floor","addr:hamlet","addr:housename","addr:housenumber","addr:neighbourhood","addr:place","addr:postcode","addr:province","addr:quarter","addr:state","addr:street","addr:subdistrict","addr:suburb"],"reference":{"key":"addr"},"icon":"address","universal":true,"label":"Address","strings":{"placeholders":{"block_number":"Block Number","block_number!jp":"Block No.","city":"City","city!jp":"City/Town/Village/Tokyo Special Ward","city!vn":"City/Town","conscriptionnumber":"123","country":"Country","county":"County","county!jp":"District","district":"District","district!vn":"Arrondissement/Town/District","floor":"Floor","hamlet":"Hamlet","housename":"Housename","housenumber":"123","housenumber!jp":"Building No./Lot No.","neighbourhood":"Neighbourhood","neighbourhood!jp":"Chōme/Aza/Koaza","place":"Place","postcode":"Postcode","province":"Province","province!jp":"Prefecture","quarter":"Quarter","quarter!jp":"Ōaza/Machi","state":"State","street":"Street","subdistrict":"Subdistrict","subdistrict!vn":"Ward/Commune/Townlet","suburb":"Suburb","suburb!jp":"Ward"}}},"admin_level":{"key":"admin_level","type":"number","label":"Admin Level"},"aerialway":{"key":"aerialway","type":"typeCombo","label":"Type"},"aerialway/access":{"key":"aerialway:access","type":"combo","label":"Access","strings":{"options":{"entry":"Entry","exit":"Exit","both":"Both"}}},"aerialway/bubble":{"key":"aerialway:bubble","type":"check","label":"Bubble"},"aerialway/capacity":{"key":"aerialway:capacity","type":"number","label":"Capacity (per hour)","placeholder":"500, 2500, 5000..."},"aerialway/duration":{"key":"aerialway:duration","type":"number","label":"Duration (minutes)","placeholder":"1, 2, 3..."},"aerialway/heating":{"key":"aerialway:heating","type":"check","label":"Heated"},"aerialway/occupancy":{"key":"aerialway:occupancy","type":"number","label":"Occupancy","placeholder":"2, 4, 8..."},"aerialway/summer/access":{"key":"aerialway:summer:access","type":"combo","label":"Access (summer)","strings":{"options":{"entry":"Entry","exit":"Exit","both":"Both"}}},"aeroway":{"key":"aeroway","type":"typeCombo","label":"Type"},"amenity":{"key":"amenity","type":"typeCombo","label":"Type"},"animal_boarding":{"key":"animal_boarding","type":"semiCombo","label":"For Animals"},"animal_breeding":{"key":"animal_breeding","type":"semiCombo","label":"For Animals"},"animal_shelter":{"key":"animal_shelter","type":"semiCombo","label":"For Animals"},"area/highway":{"key":"area:highway","type":"typeCombo","label":"Type"},"artist":{"key":"artist_name","type":"text","label":"Artist"},"artwork_type":{"key":"artwork_type","type":"combo","label":"Type"},"atm":{"key":"atm","type":"check","label":"ATM"},"backrest":{"key":"backrest","type":"check","label":"Backrest"},"barrier":{"key":"barrier","type":"typeCombo","label":"Type"},"bath/open_air":{"key":"bath:open_air","label":"Open Air","type":"check"},"bath/sand_bath":{"key":"bath:sand_bath","label":"Sand Bath","type":"check"},"bath/type":{"key":"bath:type","type":"combo","label":"Specialty","strings":{"options":{"onsen":"Japanese Onsen","foot_bath":"Foot Bath","hot_spring":"Hot Spring"}}},"beauty":{"key":"beauty","type":"combo","label":"Shop Type"},"bench":{"key":"bench","type":"check","label":"Bench"},"bicycle_parking":{"key":"bicycle_parking","type":"combo","label":"Type"},"bin":{"key":"bin","type":"check","label":"Waste Bin"},"blood_components":{"key":"blood:","type":"multiCombo","label":"Blood Components","strings":{"options":{"whole":"whole blood","plasma":"plasma","platelets":"platelets","stemcells":"stem cell samples"}}},"board_type":{"key":"board_type","type":"typeCombo","label":"Type"},"boundary":{"key":"boundary","type":"combo","label":"Type"},"brand":{"key":"brand","type":"text","label":"Brand"},"building_area":{"key":"building","type":"combo","default":"yes","geometry":"area","label":"Building"},"building":{"key":"building","type":"combo","label":"Building"},"bunker_type":{"key":"bunker_type","type":"combo","label":"Type"},"camera/direction":{"key":"camera:direction","type":"number","label":"Direction (Degrees Clockwise)","placeholder":"45, 90, 180, 270"},"camera/mount":{"key":"camera:mount","type":"combo","label":"Camera Mount"},"camera/type":{"key":"camera:type","type":"combo","label":"Camera Type","strings":{"options":{"fixed":"Fixed","panning":"Panning","dome":"Dome"}}},"capacity":{"key":"capacity","type":"number","label":"Capacity","placeholder":"50, 100, 200..."},"cardinal_direction":{"key":"direction","type":"combo","label":"Direction","strings":{"options":{"N":"North","E":"East","S":"South","W":"West","NE":"Northeast","SE":"Southeast","SW":"Southwest","NW":"Northwest","NNE":"North-northeast","ENE":"East-northeast","ESE":"East-southeast","SSE":"South-southeast","SSW":"South-southwest","WSW":"West-southwest","WNW":"West-northwest","NNW":"North-northwest"}}},"castle_type":{"key":"castle_type","type":"combo","label":"Type"},"clock_direction":{"key":"direction","type":"combo","label":"Direction","strings":{"options":{"clockwise":"Clockwise","anticlockwise":"Counterclockwise"}}},"club":{"key":"club","type":"typeCombo","label":"Type"},"collection_times":{"key":"collection_times","type":"text","label":"Collection Times"},"communication_multi":{"key":"communication:","type":"multiCombo","label":"Communication Types"},"construction":{"key":"construction","type":"combo","label":"Type"},"contact/webcam":{"key":"contact:webcam","type":"url","icon":"website","label":"Webcam URL","placeholder":"http://example.com/"},"content":{"key":"content","type":"combo","label":"Contents"},"country":{"key":"country","type":"combo","label":"Country"},"covered":{"key":"covered","type":"check","label":"Covered"},"craft":{"key":"craft","type":"typeCombo","label":"Type"},"crop":{"key":"crop","type":"semiCombo","label":"Crops"},"crossing":{"key":"crossing","type":"combo","label":"Type"},"cuisine":{"key":"cuisine","type":"semiCombo","label":"Cuisines"},"currency_multi":{"key":"currency:","type":"multiCombo","label":"Currency Types"},"cycle_network":{"key":"cycle_network","type":"networkCombo","label":"Network"},"cycleway":{"keys":["cycleway:left","cycleway:right"],"reference":{"key":"cycleway"},"type":"cycleway","label":"Bike Lanes","placeholder":"none","strings":{"types":{"cycleway:left":"Left side","cycleway:right":"Right side"},"options":{"none":{"title":"None","description":"No bike lane"},"lane":{"title":"Standard bike lane","description":"A bike lane separated from auto traffic by a painted line"},"shared_lane":{"title":"Shared bike lane","description":"A bike lane with no separation from auto traffic"},"track":{"title":"Bike track","description":"A bike lane separated from traffic by a physical barrier"},"share_busway":{"title":"Bike lane shared with bus","description":"A bike lane shared with a bus lane"},"opposite_lane":{"title":"Opposite bike lane","description":"A bike lane that travels in the opposite direction of traffic"},"opposite":{"title":"Contraflow bike lane","description":"A bike lane that travels in both directions on a one-way street"}}}},"date":{"key":"date","type":"check","label":"Date"},"delivery":{"key":"delivery","type":"check","label":"Delivery"},"denomination":{"key":"denomination","type":"combo","label":"Denomination"},"denotation":{"key":"denotation","type":"combo","label":"Denotation"},"description":{"key":"description","type":"textarea","label":"Description","universal":true},"diaper":{"key":"diaper","type":"combo","label":"Diaper Changing Available","options":["yes","no","room","1","2","3","4","5"]},"display":{"key":"display","type":"combo","label":"Display","options":["analog","digital","sundial","unorthodox"]},"dock":{"key":"dock","type":"combo","label":"Type"},"drive_through":{"key":"drive_through","type":"check","label":"Drive-Through"},"electrified":{"key":"electrified","type":"combo","label":"Electrification","placeholder":"Contact Line, Electrified Rail...","strings":{"options":{"contact_line":"Contact Line","rail":"Electrified Rail","yes":"Yes (unspecified)","no":"No"}}},"elevation":{"key":"ele","type":"number","icon":"elevation","universal":true,"label":"Elevation"},"email":{"key":"email","type":"email","placeholder":"example@example.com","universal":true,"label":"Email"},"emergency":{"key":"emergency","type":"check","label":"Emergency"},"entrance":{"key":"entrance","type":"typeCombo","label":"Type"},"except":{"key":"except","type":"combo","label":"Exceptions"},"fax":{"key":"fax","type":"tel","label":"Fax","universal":true,"placeholder":"+31 42 123 4567"},"fee":{"key":"fee","type":"check","label":"Fee"},"fence_type":{"key":"fence_type","type":"combo","label":"Type"},"fire_hydrant/position":{"key":"fire_hydrant:position","type":"combo","label":"Position","strings":{"options":{"lane":"Lane","parking_lot":"Parking Lot","sidewalk":"Sidewalk","green":"Green"}}},"fire_hydrant/type":{"key":"fire_hydrant:type","type":"combo","label":"Type","strings":{"options":{"pillar":"Pillar/Aboveground","underground":"Underground","wall":"Wall","pond":"Pond"}}},"fixme":{"key":"fixme","type":"textarea","label":"Fix Me","universal":true},"fuel_multi":{"key":"fuel:","type":"multiCombo","label":"Fuel Types"},"fuel":{"key":"fuel","type":"combo","label":"Fuel"},"gauge":{"key":"gauge","type":"combo","label":"Gauge"},"gender":{"type":"radio","keys":["male","female","unisex"],"label":"Gender","placeholder":"Unknown","strings":{"options":{"male":"Male","female":"Female","unisex":"Unisex"}}},"generator/method":{"key":"generator:method","type":"combo","label":"Method"},"generator/source":{"key":"generator:source","type":"combo","label":"Source"},"generator/type":{"key":"generator:type","type":"combo","label":"Type"},"golf_hole":{"key":"ref","type":"text","label":"Reference","placeholder":"Hole number (1-18)"},"grape_variety":{"key":"grape_variety","type":"semiCombo","label":"Grape Varieties"},"handicap":{"key":"handicap","type":"number","label":"Handicap","placeholder":"1-18"},"handrail":{"key":"handrail","type":"check","label":"Handrail"},"height":{"key":"height","type":"number","label":"Height (Meters)"},"highway":{"key":"highway","type":"typeCombo","label":"Type"},"historic":{"key":"historic","type":"typeCombo","label":"Type"},"historic/civilization":{"key":"historic:civilization","type":"combo","label":"Historic Civilization"},"hoops":{"key":"hoops","type":"number","label":"Hoops","placeholder":"1, 2, 4..."},"iata":{"key":"iata","type":"text","label":"IATA"},"icao":{"key":"icao","type":"text","label":"ICAO"},"incline_steps":{"key":"incline","type":"combo","label":"Incline","strings":{"options":{"up":"Up","down":"Down"}}},"incline":{"key":"incline","type":"combo","label":"Incline"},"indoor":{"key":"indoor","type":"check","label":"Indoor"},"information":{"key":"information","type":"typeCombo","label":"Type"},"inscription":{"key":"inscription","type":"textarea","label":"Inscription"},"internet_access":{"key":"internet_access","type":"combo","label":"Internet Access","strings":{"options":{"yes":"Yes","no":"No","wlan":"Wifi","wired":"Wired","terminal":"Terminal"}}},"internet_access/fee":{"key":"internet_access:fee","type":"check","label":"Internet Access Fee"},"internet_access/ssid":{"key":"internet_access:ssid","type":"text","label":"SSID (Network Name)"},"kerb":{"key":"kerb","type":"combo","label":"Curb"},"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"},"population":{"key":"population","type":"text","label":"Population"},"power_supply":{"key":"power_supply","type":"check","label":"Power Supply"},"power":{"key":"power","type":"typeCombo","label":"Type"},"produce":{"key":"produce","type":"semiCombo","label":"Produce"},"product":{"key":"product","type":"semiCombo","label":"Products"},"railway":{"key":"railway","type":"typeCombo","label":"Type"},"recycling_accepts":{"key":"recycling:","type":"multiCombo","label":"Accepts"},"recycling_type":{"key":"recycling_type","default":"container","type":"combo","label":"Recycling Type","strings":{"options":{"container":"Container","centre":"Recycling Center"}}},"ref":{"key":"ref","type":"text","label":"Reference"},"relation":{"key":"type","type":"combo","label":"Type"},"religion":{"key":"religion","type":"combo","label":"Religion"},"restriction":{"key":"restriction","type":"combo","label":"Type"},"restrictions":{"type":"restrictions","geometry":"vertex","icon":"restrictions","reference":{"rtype":"restriction"},"label":"Turn Restrictions"},"rooms":{"key":"rooms","type":"number","label":"Rooms"},"route_master":{"key":"route_master","type":"combo","label":"Type"},"route":{"key":"route","type":"combo","label":"Type"},"sac_scale":{"key":"sac_scale","type":"combo","label":"Hiking Difficulty","placeholder":"Mountain Hiking, Alpine Hiking...","strings":{"options":{"hiking":"T1: Hiking","mountain_hiking":"T2: Mountain Hiking","demanding_mountain_hiking":"T3: Demanding Mountain Hiking","alpine_hiking":"T4: Alpine Hiking","demanding_alpine_hiking":"T5: Demanding Alpine Hiking","difficult_alpine_hiking":"T6: Difficult Alpine Hiking"}}},"sanitary_dump_station":{"key":"sanitary_dump_station","type":"check","label":"Toilet Disposal"},"seasonal":{"key":"seasonal","type":"check","label":"Seasonal"},"second_hand":{"key":"second_hand","type":"combo","label":"Sells Used","placeholder":"Yes, No, Only","strings":{"options":{"yes":"Yes","no":"No","only":"Only"}}},"service_rail":{"key":"service","type":"combo","label":"Service Type","strings":{"options":{"spur":"Spur","yard":"Yard","siding":"Siding","crossover":"Crossover"}}},"service_times":{"key":"service_times","type":"text","label":"Service Times"},"service":{"key":"service","type":"combo","label":"Type","options":["parking_aisle","driveway","alley","emergency_access","drive-through"]},"service/bicycle":{"key":"service:bicycle:","type":"multiCombo","label":"Services"},"service/vehicle":{"key":"service:vehicle:","type":"multiCombo","label":"Services"},"shelter_type":{"key":"shelter_type","type":"combo","label":"Type"},"shelter":{"key":"shelter","type":"check","label":"Shelter"},"shop":{"key":"shop","type":"typeCombo","label":"Type"},"site":{"key":"site","type":"combo","label":"Type"},"smoking":{"key":"smoking","type":"combo","label":"Smoking","placeholder":"No, Separated, Yes...","strings":{"options":{"no":"No smoking anywhere","separated":"In smoking areas, not physically isolated","isolated":"In smoking areas, physically isolated","outside":"Allowed outside","yes":"Allowed everywhere","dedicated":"Dedicated to smokers (e.g. smokers' club)"}}},"smoothness":{"key":"smoothness","type":"combo","label":"Smoothness","placeholder":"Thin Rollers, Wheels, Off-Road...","strings":{"options":{"excellent":"Thin Rollers: rollerblade, skateboard","good":"Thin Wheels: racing bike","intermediate":"Wheels: city bike, wheelchair, scooter","bad":"Robust Wheels: trekking bike, car, rickshaw","very_bad":"High Clearance: light duty off-road vehicle","horrible":"Off-Road: heavy duty off-road vehicle","very_horrible":"Specialized off-road: tractor, ATV","impassable":"Impassable / No wheeled vehicle"}}},"social_facility_for":{"key":"social_facility:for","type":"combo","label":"People Served"},"social_facility":{"key":"social_facility","type":"combo","label":"Type"},"source":{"key":"source","type":"text","icon":"source","universal":true,"label":"Source"},"sport_ice":{"key":"sport","type":"semiCombo","label":"Sports","options":["skating","hockey","multi","curling","ice_stock"]},"sport_racing_motor":{"key":"sport","type":"semiCombo","label":"Sports","options":["motor","karting","motocross"]},"sport_racing_nonmotor":{"key":"sport","type":"semiCombo","label":"Sports","options":["bmx","cycling","dog_racing","horse_racing","running"]},"sport":{"key":"sport","type":"semiCombo","label":"Sports"},"stars":{"key":"stars","type":"number","label":"Stars"},"start_date":{"key":"start_date","type":"text","universal":true,"label":"Start Date"},"step_count":{"key":"step_count","type":"number","label":"Number of Steps"},"stop":{"key":"stop","type":"combo","label":"Stop Type","strings":{"options":{"all":"All Ways","minor":"Minor Road"}}},"structure":{"type":"structureRadio","keys":["bridge","tunnel","embankment","cutting","ford"],"label":"Structure","placeholder":"Unknown","strings":{"options":{"bridge":"Bridge","tunnel":"Tunnel","embankment":"Embankment","cutting":"Cutting","ford":"Ford"}}},"studio":{"key":"studio","type":"combo","label":"Type"},"substation":{"key":"substation","type":"typeCombo","label":"Type"},"supervised":{"key":"supervised","type":"check","label":"Supervised"},"support":{"key":"support","type":"combo","label":"Support"},"surface":{"key":"surface","type":"combo","label":"Surface"},"surveillance":{"key":"surveillance","type":"combo","label":"Surveillance Kind"},"surveillance/type":{"key":"surveillance:type","type":"combo","label":"Surveillance Type","strings":{"options":{"camera":"Camera","guard":"Guard","ALPR":"Automatic License Plate Reader"}}},"surveillance/zone":{"key":"surveillance:zone","type":"combo","label":"Surveillance Zone"},"tactile_paving":{"key":"tactile_paving","type":"check","label":"Tactile Paving"},"takeaway":{"key":"takeaway","type":"combo","label":"Takeaway","placeholder":"Yes, No, Takeaway Only...","strings":{"options":{"yes":"Yes","no":"No","only":"Takeaway Only"}}},"toilets/disposal":{"key":"toilets:disposal","type":"combo","label":"Disposal","strings":{"options":{"flush":"Flush","pitlatrine":"Pit/Latrine","chemical":"Chemical","bucket":"Bucket"}}},"toll":{"key":"toll","type":"check","label":"Toll"},"tomb":{"key":"tomb","type":"typeCombo","label":"Type"},"tourism":{"key":"tourism","type":"typeCombo","label":"Type"},"tower/construction":{"key":"tower:construction","type":"combo","label":"Construction","placeholder":"Guyed, Lattice, Concealed, ..."},"tower/type":{"key":"tower:type","type":"combo","label":"Type"},"tracktype":{"key":"tracktype","type":"combo","label":"Track Type","placeholder":"Solid, Mostly Solid, Soft...","strings":{"options":{"grade1":"Solid: paved or heavily compacted hardcore surface","grade2":"Mostly Solid: gravel/rock with some soft material mixed in","grade3":"Even mixture of hard and soft materials","grade4":"Mostly Soft: soil/sand/grass with some hard material mixed in","grade5":"Soft: soil/sand/grass"}}},"traffic_calming":{"key":"traffic_calming","type":"typeCombo","label":"Type"},"traffic_signals":{"key":"traffic_signals","type":"combo","label":"Type","default":"signal"},"trail_visibility":{"key":"trail_visibility","type":"combo","label":"Trail Visibility","placeholder":"Excellent, Good, Bad...","strings":{"options":{"excellent":"Excellent: unambiguous path or markers everywhere","good":"Good: markers visible, sometimes require searching","intermediate":"Intermediate: few markers, path mostly visible","bad":"Bad: no markers, path sometimes invisible/pathless","horrible":"Horrible: often pathless, some orientation skills required","no":"No: pathless, excellent orientation skills required"}}},"trees":{"key":"trees","type":"semiCombo","label":"Trees"},"tunnel":{"key":"tunnel","type":"combo","label":"Tunnel"},"vending":{"key":"vending","type":"combo","label":"Type of Goods"},"visibility":{"key":"visibility","type":"combo","label":"Visibility","strings":{"options":{"house":"Up to 5m (16ft)","street":"5 to 20m (16 to 65ft)","area":"Over 20m (65ft)"}}},"wall":{"key":"wall","type":"combo","label":"Type"},"water_point":{"key":"water_point","type":"check","label":"Water Point"},"water":{"key":"water","type":"combo","label":"Type"},"waterway":{"key":"waterway","type":"typeCombo","label":"Type"},"website":{"key":"website","type":"url","icon":"website","placeholder":"http://example.com/","universal":true,"label":"Website"},"wetland":{"key":"wetland","type":"combo","label":"Type"},"wheelchair":{"key":"wheelchair","type":"radio","options":["yes","limited","no"],"icon":"wheelchair","universal":true,"label":"Wheelchair Access"},"width":{"key":"width","type":"number","label":"Width (Meters)"},"wikipedia":{"key":"wikipedia","keys":["wikipedia","wikidata"],"type":"wikipedia","icon":"wikipedia","universal":true,"label":"Wikipedia"}};
18636
18637 var all = ["aerialway","airfield","airport","alcohol-shop","america-football","amusement-park","aquarium","art-gallery","attraction","bakery","bank","bar","barrier","baseball","basketball","bbq","beer","bicycle","bicycle-share","blood-bank","buddhism","building","building-alt1","bus","cafe","campsite","car","castle","cemetery","cinema","circle","circle-stroked","city","clothing-store","college","commercial","cricket","cross","dam","danger","defibrillator","dentist","doctor","dog-park","drinking-water","embassy","emergency-phone","entrance","entrance-alt1","farm","fast-food","fence","ferry","fire-station","florist","fuel","gaming","garden","garden-center","gift","golf","grocery","hairdresser","harbor","heart","heliport","home","horse-riding","hospital","ice-cream","industry","information","karaoke","landmark","landuse","laundry","library","lighthouse","lodging","logging","marker","marker-stroked","mobile-phone","monument","mountain","museum","music","natural","park","park-alt1","parking","parking-garage","pharmacy","picnic-site","pitch","place-of-worship","playground","police","post","prison","rail","rail-light","rail-metro","ranger-station","recycling","religious-christian","religious-jewish","religious-muslim","residential-community","restaurant","roadblock","rocket","school","scooter","shelter","shop","skiing","slaughterhouse","snowmobile","soccer","square","square-stroked","stadium","star","star-stroked","suitcase","sushi","swimming","teahouse","telephone","tennis","theatre","toilet","town","town-hall","triangle","triangle-stroked","veterinary","village","volcano","warehouse","waste-basket","water","wetland","wheelchair","zoo"];
18638 var all$1 = {
18639         all: all
18640 };
18641
18642 var all$2 = Object.freeze({
18643         all: all,
18644         default: all$1
18645 });
18646
18647 var Airport = ["airfield","airport","heliport","rocket"];
18648 var Dining = ["bakery","bar","beer","cafe","fast-food","ice-cream","restaurant"];
18649 var Education = ["college","school"];
18650 var General = ["alcohol-shop","amusement-park","aquarium","art-gallery","attraction","bank","bicycle","bicycle-share","car","castle","cinema","circle","circle-stroked","clothing-store","drinking-water","embassy","fire-station","fuel","grocery","harbor","information","laundry","library","lodging","marker","monument","museum","music","place-of-worship","police","post","prison","religious-christian","religious-jewish","religious-muslim","shop","stadium","star","suitcase","swimming","theatre","toilet","town-hall","triangle","triangle-stroked","veterinary"];
18651 var Health = ["dentist","doctor","hospital","pharmacy"];
18652 var Outdoors = ["campsite","cemetery","dog-park","garden","golf","park","picnic-site","playground","zoo"];
18653 var Transit = ["bus","ferry"];
18654 var streets = {
18655         Airport: Airport,
18656         Dining: Dining,
18657         Education: Education,
18658         General: General,
18659         Health: Health,
18660         Outdoors: Outdoors,
18661         Transit: Transit,
18662         "Mountain peak": ["mountain","volcano"],
18663         "Rail station": ["entrance","rail","rail-light","rail-metro"]
18664 };
18665
18666 var streets$1 = Object.freeze({
18667         Airport: Airport,
18668         Dining: Dining,
18669         Education: Education,
18670         General: General,
18671         Health: Health,
18672         Outdoors: Outdoors,
18673         Transit: Transit,
18674         default: streets
18675 });
18676
18677 var require$$0 = ( all$2 && all$1 ) || all$2;
18678
18679 var require$$1 = ( streets$1 && streets ) || streets$1;
18680
18681 var index$1 = {
18682   layouts: {
18683     all: require$$0,
18684     streets: require$$1
18685   }
18686 };
18687
18688 var dataFeatureIcons = index$1.layouts.all.all;
18689
18690 var data = {
18691     imagery: dataImagery,
18692     presets: {
18693         presets: presets,
18694         defaults: defaults,
18695         categories: categories,
18696         fields: fields
18697     }
18698 };
18699
18700 function osmEntity$$1(attrs) {
18701     // For prototypal inheritance.
18702     if (this instanceof osmEntity$$1) return;
18703
18704     // Create the appropriate subtype.
18705     if (attrs && attrs.type) {
18706         return osmEntity$$1[attrs.type].apply(this, arguments);
18707     } else if (attrs && attrs.id) {
18708         return osmEntity$$1[osmEntity$$1.id.type(attrs.id)].apply(this, arguments);
18709     }
18710
18711     // Initialize a generic Entity (used only in tests).
18712     return (new osmEntity$$1()).initialize(arguments);
18713 }
18714
18715
18716 osmEntity$$1.id = function(type) {
18717     return osmEntity$$1.id.fromOSM(type, osmEntity$$1.id.next[type]--);
18718 };
18719
18720
18721 osmEntity$$1.id.next = {
18722     changeset: -1, node: -1, way: -1, relation: -1
18723 };
18724
18725
18726 osmEntity$$1.id.fromOSM = function(type, id) {
18727     return type[0] + id;
18728 };
18729
18730
18731 osmEntity$$1.id.toOSM = function(id) {
18732     return id.slice(1);
18733 };
18734
18735
18736 osmEntity$$1.id.type = function(id) {
18737     return { 'c': 'changeset', 'n': 'node', 'w': 'way', 'r': 'relation' }[id[0]];
18738 };
18739
18740
18741 // A function suitable for use as the second argument to d3.selection#data().
18742 osmEntity$$1.key = function(entity) {
18743     return entity.id + 'v' + (entity.v || 0);
18744 };
18745
18746
18747 osmEntity$$1.prototype = {
18748
18749     tags: {},
18750
18751
18752     initialize: function(sources) {
18753         for (var i = 0; i < sources.length; ++i) {
18754             var source = sources[i];
18755             for (var prop in source) {
18756                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
18757                     if (source[prop] === undefined) {
18758                         delete this[prop];
18759                     } else {
18760                         this[prop] = source[prop];
18761                     }
18762                 }
18763             }
18764         }
18765
18766         if (!this.id && this.type) {
18767             this.id = osmEntity$$1.id(this.type);
18768         }
18769         if (!this.hasOwnProperty('visible')) {
18770             this.visible = true;
18771         }
18772
18773         if (debug) {
18774             Object.freeze(this);
18775             Object.freeze(this.tags);
18776
18777             if (this.loc) Object.freeze(this.loc);
18778             if (this.nodes) Object.freeze(this.nodes);
18779             if (this.members) Object.freeze(this.members);
18780         }
18781
18782         return this;
18783     },
18784
18785
18786     copy: function(resolver, copies) {
18787         if (copies[this.id])
18788             return copies[this.id];
18789
18790         var copy = osmEntity$$1(this, {id: undefined, user: undefined, version: undefined});
18791         copies[this.id] = copy;
18792
18793         return copy;
18794     },
18795
18796
18797     osmId: function() {
18798         return osmEntity$$1.id.toOSM(this.id);
18799     },
18800
18801
18802     isNew: function() {
18803         return this.osmId() < 0;
18804     },
18805
18806
18807     update: function(attrs) {
18808         return osmEntity$$1(this, attrs, {v: 1 + (this.v || 0)});
18809     },
18810
18811
18812     mergeTags: function(tags) {
18813         var merged = lodash.clone(this.tags), changed = false;
18814         for (var k in tags) {
18815             var t1 = merged[k],
18816                 t2 = tags[k];
18817             if (!t1) {
18818                 changed = true;
18819                 merged[k] = t2;
18820             } else if (t1 !== t2) {
18821                 changed = true;
18822                 merged[k] = lodash.union(t1.split(/;\s*/), t2.split(/;\s*/)).join(';');
18823             }
18824         }
18825         return changed ? this.update({tags: merged}) : this;
18826     },
18827
18828
18829     intersects: function(extent, resolver) {
18830         return this.extent(resolver).intersects(extent);
18831     },
18832
18833
18834     isUsed: function(resolver) {
18835         return lodash.without(Object.keys(this.tags), 'area').length > 0 ||
18836             resolver.parentRelations(this).length > 0;
18837     },
18838
18839
18840     hasInterestingTags: function() {
18841         return lodash.keys(this.tags).some(osmIsInterestingTag);
18842     },
18843
18844
18845     isHighwayIntersection: function() {
18846         return false;
18847     },
18848
18849     isDegenerate: function() {
18850         return true;
18851     },
18852
18853     deprecatedTags: function() {
18854         var tags = lodash.toPairs(this.tags);
18855         var deprecated = {};
18856
18857         dataDeprecated.forEach(function(d) {
18858             var match = lodash.toPairs(d.old)[0];
18859             tags.forEach(function(t) {
18860                 if (t[0] === match[0] &&
18861                     (t[1] === match[1] || match[1] === '*')) {
18862                     deprecated[t[0]] = t[1];
18863                 }
18864             });
18865         });
18866
18867         return deprecated;
18868     }
18869 };
18870
18871 function geoRoundCoords(c) {
18872     return [Math.floor(c[0]), Math.floor(c[1])];
18873 }
18874
18875
18876 function geoInterp(p1, p2, t) {
18877     return [p1[0] + (p2[0] - p1[0]) * t,
18878             p1[1] + (p2[1] - p1[1]) * t];
18879 }
18880
18881
18882 // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
18883 // Returns a positive value, if OAB makes a counter-clockwise turn,
18884 // negative for clockwise turn, and zero if the points are collinear.
18885 function geoCross(o, a, b) {
18886     return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
18887 }
18888
18889
18890 // http://jsperf.com/id-dist-optimization
18891 function geoEuclideanDistance(a, b) {
18892     var x = a[0] - b[0], y = a[1] - b[1];
18893     return Math.sqrt((x * x) + (y * y));
18894 }
18895
18896
18897 // using WGS84 polar radius (6356752.314245179 m)
18898 // const = 2 * PI * r / 360
18899 function geoLatToMeters(dLat) {
18900     return dLat * 110946.257617;
18901 }
18902
18903
18904 // using WGS84 equatorial radius (6378137.0 m)
18905 // const = 2 * PI * r / 360
18906 function geoLonToMeters(dLon, atLat) {
18907     return Math.abs(atLat) >= 90 ? 0 :
18908         dLon * 111319.490793 * Math.abs(Math.cos(atLat * (Math.PI/180)));
18909 }
18910
18911
18912 // using WGS84 polar radius (6356752.314245179 m)
18913 // const = 2 * PI * r / 360
18914 function geoMetersToLat(m) {
18915     return m / 110946.257617;
18916 }
18917
18918
18919 // using WGS84 equatorial radius (6378137.0 m)
18920 // const = 2 * PI * r / 360
18921 function geoMetersToLon(m, atLat) {
18922     return Math.abs(atLat) >= 90 ? 0 :
18923         m / 111319.490793 / Math.abs(Math.cos(atLat * (Math.PI/180)));
18924 }
18925
18926
18927 function geoOffsetToMeters(offset) {
18928     var equatRadius = 6356752.314245179,
18929         polarRadius = 6378137.0,
18930         tileSize = 256;
18931
18932     return [
18933         offset[0] * 2 * Math.PI * equatRadius / tileSize,
18934         -offset[1] * 2 * Math.PI * polarRadius / tileSize
18935     ];
18936 }
18937
18938
18939 function geoMetersToOffset(meters) {
18940     var equatRadius = 6356752.314245179,
18941         polarRadius = 6378137.0,
18942         tileSize = 256;
18943
18944     return [
18945         meters[0] * tileSize / (2 * Math.PI * equatRadius),
18946         -meters[1] * tileSize / (2 * Math.PI * polarRadius)
18947     ];
18948 }
18949
18950
18951 // Equirectangular approximation of spherical distances on Earth
18952 function geoSphericalDistance(a, b) {
18953     var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2),
18954         y = geoLatToMeters(a[1] - b[1]);
18955     return Math.sqrt((x * x) + (y * y));
18956 }
18957
18958
18959 function geoEdgeEqual(a, b) {
18960     return (a[0] === b[0] && a[1] === b[1]) ||
18961         (a[0] === b[1] && a[1] === b[0]);
18962 }
18963
18964
18965 // Return the counterclockwise angle in the range (-pi, pi)
18966 // between the positive X axis and the line intersecting a and b.
18967 function geoAngle(a, b, projection) {
18968     a = projection(a.loc);
18969     b = projection(b.loc);
18970     return Math.atan2(b[1] - a[1], b[0] - a[0]);
18971 }
18972
18973
18974 // Rotate all points counterclockwise around a pivot point by given angle
18975 function geoRotate(points, angle, around) {
18976     return points.map(function(point) {
18977         var radial = [point[0] - around[0], point[1] - around[1]];
18978         return [
18979             radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + around[0],
18980             radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + around[1]
18981         ];
18982     });
18983 }
18984
18985
18986 // Choose the edge with the minimal distance from `point` to its orthogonal
18987 // projection onto that edge, if such a projection exists, or the distance to
18988 // the closest vertex on that edge. Returns an object with the `index` of the
18989 // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
18990 function geoChooseEdge(nodes, point, projection) {
18991     var dist = geoEuclideanDistance,
18992         points = nodes.map(function(n) { return projection(n.loc); }),
18993         min = Infinity,
18994         idx, loc;
18995
18996     function dot(p, q) {
18997         return p[0] * q[0] + p[1] * q[1];
18998     }
18999
19000     for (var i = 0; i < points.length - 1; i++) {
19001         var o = points[i],
19002             s = [points[i + 1][0] - o[0],
19003                  points[i + 1][1] - o[1]],
19004             v = [point[0] - o[0],
19005                  point[1] - o[1]],
19006             proj = dot(v, s) / dot(s, s),
19007             p;
19008
19009         if (proj < 0) {
19010             p = o;
19011         } else if (proj > 1) {
19012             p = points[i + 1];
19013         } else {
19014             p = [o[0] + proj * s[0], o[1] + proj * s[1]];
19015         }
19016
19017         var d = dist(p, point);
19018         if (d < min) {
19019             min = d;
19020             idx = i + 1;
19021             loc = projection.invert(p);
19022         }
19023     }
19024
19025     return {
19026         index: idx,
19027         distance: min,
19028         loc: loc
19029     };
19030 }
19031
19032
19033 // Return the intersection point of 2 line segments.
19034 // From https://github.com/pgkelley4/line-segments-intersect
19035 // This uses the vector cross product approach described below:
19036 //  http://stackoverflow.com/a/565282/786339
19037 function geoLineIntersection(a, b) {
19038     function subtractPoints(point1, point2) {
19039         return [point1[0] - point2[0], point1[1] - point2[1]];
19040     }
19041     function crossProduct(point1, point2) {
19042         return point1[0] * point2[1] - point1[1] * point2[0];
19043     }
19044
19045     var p = [a[0][0], a[0][1]],
19046         p2 = [a[1][0], a[1][1]],
19047         q = [b[0][0], b[0][1]],
19048         q2 = [b[1][0], b[1][1]],
19049         r = subtractPoints(p2, p),
19050         s = subtractPoints(q2, q),
19051         uNumerator = crossProduct(subtractPoints(q, p), r),
19052         denominator = crossProduct(r, s);
19053
19054     if (uNumerator && denominator) {
19055         var u = uNumerator / denominator,
19056             t = crossProduct(subtractPoints(q, p), s) / denominator;
19057
19058         if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
19059             return geoInterp(p, p2, t);
19060         }
19061     }
19062
19063     return null;
19064 }
19065
19066
19067 function geoPathIntersections(path1, path2) {
19068     var intersections = [];
19069     for (var i = 0; i < path1.length - 1; i++) {
19070         for (var j = 0; j < path2.length - 1; j++) {
19071             var a = [ path1[i], path1[i+1] ],
19072                 b = [ path2[j], path2[j+1] ],
19073                 hit = geoLineIntersection(a, b);
19074             if (hit) intersections.push(hit);
19075         }
19076     }
19077     return intersections;
19078 }
19079
19080
19081 // Return whether point is contained in polygon.
19082 //
19083 // `point` should be a 2-item array of coordinates.
19084 // `polygon` should be an array of 2-item arrays of coordinates.
19085 //
19086 // From https://github.com/substack/point-in-polygon.
19087 // ray-casting algorithm based on
19088 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
19089 //
19090 function geoPointInPolygon(point, polygon) {
19091     var x = point[0],
19092         y = point[1],
19093         inside = false;
19094
19095     for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
19096         var xi = polygon[i][0], yi = polygon[i][1];
19097         var xj = polygon[j][0], yj = polygon[j][1];
19098
19099         var intersect = ((yi > y) !== (yj > y)) &&
19100             (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
19101         if (intersect) inside = !inside;
19102     }
19103
19104     return inside;
19105 }
19106
19107
19108 function geoPolygonContainsPolygon(outer, inner) {
19109     return lodash.every(inner, function(point) {
19110         return geoPointInPolygon(point, outer);
19111     });
19112 }
19113
19114
19115 function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
19116     function testSegments(outer, inner) {
19117         for (var i = 0; i < outer.length - 1; i++) {
19118             for (var j = 0; j < inner.length - 1; j++) {
19119                 var a = [ outer[i], outer[i+1] ],
19120                     b = [ inner[j], inner[j+1] ];
19121                 if (geoLineIntersection(a, b)) return true;
19122             }
19123         }
19124         return false;
19125     }
19126
19127     function testPoints(outer, inner) {
19128         return lodash.some(inner, function(point) {
19129             return geoPointInPolygon(point, outer);
19130         });
19131     }
19132
19133    return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
19134 }
19135
19136
19137 function geoPathLength(path) {
19138     var length = 0;
19139     for (var i = 0; i < path.length - 1; i++) {
19140         length += geoEuclideanDistance(path[i], path[i + 1]);
19141     }
19142     return length;
19143 }
19144
19145 function geoExtent$$1(min, max) {
19146     if (!(this instanceof geoExtent$$1)) return new geoExtent$$1(min, max);
19147     if (min instanceof geoExtent$$1) {
19148         return min;
19149     } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
19150         this[0] = min[0];
19151         this[1] = min[1];
19152     } else {
19153         this[0] = min        || [ Infinity,  Infinity];
19154         this[1] = max || min || [-Infinity, -Infinity];
19155     }
19156 }
19157
19158 geoExtent$$1.prototype = new Array(2);
19159
19160 lodash.extend(geoExtent$$1.prototype, {
19161
19162     equals: function (obj) {
19163         return this[0][0] === obj[0][0] &&
19164             this[0][1] === obj[0][1] &&
19165             this[1][0] === obj[1][0] &&
19166             this[1][1] === obj[1][1];
19167     },
19168
19169
19170     extend: function(obj) {
19171         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19172         return geoExtent$$1(
19173             [Math.min(obj[0][0], this[0][0]), Math.min(obj[0][1], this[0][1])],
19174             [Math.max(obj[1][0], this[1][0]), Math.max(obj[1][1], this[1][1])]
19175         );
19176     },
19177
19178
19179     _extend: function(extent) {
19180         this[0][0] = Math.min(extent[0][0], this[0][0]);
19181         this[0][1] = Math.min(extent[0][1], this[0][1]);
19182         this[1][0] = Math.max(extent[1][0], this[1][0]);
19183         this[1][1] = Math.max(extent[1][1], this[1][1]);
19184     },
19185
19186
19187     area: function() {
19188         return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
19189     },
19190
19191
19192     center: function() {
19193         return [(this[0][0] + this[1][0]) / 2,
19194                 (this[0][1] + this[1][1]) / 2];
19195     },
19196
19197
19198     rectangle: function() {
19199         return [this[0][0], this[0][1], this[1][0], this[1][1]];
19200     },
19201
19202
19203     bbox: function() {
19204         return { minX: this[0][0], minY: this[0][1], maxX: this[1][0], maxY: this[1][1] };
19205     },
19206
19207
19208     polygon: function() {
19209         return [
19210             [this[0][0], this[0][1]],
19211             [this[0][0], this[1][1]],
19212             [this[1][0], this[1][1]],
19213             [this[1][0], this[0][1]],
19214             [this[0][0], this[0][1]]
19215         ];
19216     },
19217
19218
19219     contains: function(obj) {
19220         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19221         return obj[0][0] >= this[0][0] &&
19222                obj[0][1] >= this[0][1] &&
19223                obj[1][0] <= this[1][0] &&
19224                obj[1][1] <= this[1][1];
19225     },
19226
19227
19228     intersects: function(obj) {
19229         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19230         return obj[0][0] <= this[1][0] &&
19231                obj[0][1] <= this[1][1] &&
19232                obj[1][0] >= this[0][0] &&
19233                obj[1][1] >= this[0][1];
19234     },
19235
19236
19237     intersection: function(obj) {
19238         if (!this.intersects(obj)) return new geoExtent$$1();
19239         return new geoExtent$$1(
19240             [Math.max(obj[0][0], this[0][0]), Math.max(obj[0][1], this[0][1])],
19241             [Math.min(obj[1][0], this[1][0]), Math.min(obj[1][1], this[1][1])]
19242         );
19243     },
19244
19245
19246     percentContainedIn: function(obj) {
19247         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19248         var a1 = this.intersection(obj).area(),
19249             a2 = this.area();
19250
19251         if (a1 === Infinity || a2 === Infinity || a1 === 0 || a2 === 0) {
19252             return 0;
19253         } else {
19254             return a1 / a2;
19255         }
19256     },
19257
19258
19259     padByMeters: function(meters) {
19260         var dLat = geoMetersToLat(meters),
19261             dLon = geoMetersToLon(meters, this.center()[1]);
19262         return geoExtent$$1(
19263             [this[0][0] - dLon, this[0][1] - dLat],
19264             [this[1][0] + dLon, this[1][1] + dLat]
19265         );
19266     },
19267
19268
19269     toParam: function() {
19270         return this.rectangle().join(',');
19271     }
19272
19273 });
19274
19275 var version = "4.9.1";
19276
19277 var ascending = function(a, b) {
19278   return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
19279 };
19280
19281 var bisector = function(compare) {
19282   if (compare.length === 1) compare = ascendingComparator(compare);
19283   return {
19284     left: function(a, x, lo, hi) {
19285       if (lo == null) lo = 0;
19286       if (hi == null) hi = a.length;
19287       while (lo < hi) {
19288         var mid = lo + hi >>> 1;
19289         if (compare(a[mid], x) < 0) lo = mid + 1;
19290         else hi = mid;
19291       }
19292       return lo;
19293     },
19294     right: function(a, x, lo, hi) {
19295       if (lo == null) lo = 0;
19296       if (hi == null) hi = a.length;
19297       while (lo < hi) {
19298         var mid = lo + hi >>> 1;
19299         if (compare(a[mid], x) > 0) hi = mid;
19300         else lo = mid + 1;
19301       }
19302       return lo;
19303     }
19304   };
19305 };
19306
19307 function ascendingComparator(f) {
19308   return function(d, x) {
19309     return ascending(f(d), x);
19310   };
19311 }
19312
19313 var ascendingBisect = bisector(ascending);
19314 var bisectRight = ascendingBisect.right;
19315 var bisectLeft = ascendingBisect.left;
19316
19317 var pairs = function(array, f) {
19318   if (f == null) f = pair;
19319   var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
19320   while (i < n) pairs[i] = f(p, p = array[++i]);
19321   return pairs;
19322 };
19323
19324 function pair(a, b) {
19325   return [a, b];
19326 }
19327
19328 var cross = function(values0, values1, reduce) {
19329   var n0 = values0.length,
19330       n1 = values1.length,
19331       values = new Array(n0 * n1),
19332       i0,
19333       i1,
19334       i,
19335       value0;
19336
19337   if (reduce == null) reduce = pair;
19338
19339   for (i0 = i = 0; i0 < n0; ++i0) {
19340     for (value0 = values0[i0], i1 = 0; i1 < n1; ++i1, ++i) {
19341       values[i] = reduce(value0, values1[i1]);
19342     }
19343   }
19344
19345   return values;
19346 };
19347
19348 var descending = function(a, b) {
19349   return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
19350 };
19351
19352 var number = function(x) {
19353   return x === null ? NaN : +x;
19354 };
19355
19356 var variance = function(values, valueof) {
19357   var n = values.length,
19358       m = 0,
19359       i = -1,
19360       mean = 0,
19361       value,
19362       delta,
19363       sum = 0;
19364
19365   if (valueof == null) {
19366     while (++i < n) {
19367       if (!isNaN(value = number(values[i]))) {
19368         delta = value - mean;
19369         mean += delta / ++m;
19370         sum += delta * (value - mean);
19371       }
19372     }
19373   }
19374
19375   else {
19376     while (++i < n) {
19377       if (!isNaN(value = number(valueof(values[i], i, values)))) {
19378         delta = value - mean;
19379         mean += delta / ++m;
19380         sum += delta * (value - mean);
19381       }
19382     }
19383   }
19384
19385   if (m > 1) return sum / (m - 1);
19386 };
19387
19388 var deviation = function(array, f) {
19389   var v = variance(array, f);
19390   return v ? Math.sqrt(v) : v;
19391 };
19392
19393 var extent = function(values, valueof) {
19394   var n = values.length,
19395       i = -1,
19396       value,
19397       min,
19398       max;
19399
19400   if (valueof == null) {
19401     while (++i < n) { // Find the first comparable value.
19402       if ((value = values[i]) != null && value >= value) {
19403         min = max = value;
19404         while (++i < n) { // Compare the remaining values.
19405           if ((value = values[i]) != null) {
19406             if (min > value) min = value;
19407             if (max < value) max = value;
19408           }
19409         }
19410       }
19411     }
19412   }
19413
19414   else {
19415     while (++i < n) { // Find the first comparable value.
19416       if ((value = valueof(values[i], i, values)) != null && value >= value) {
19417         min = max = value;
19418         while (++i < n) { // Compare the remaining values.
19419           if ((value = valueof(values[i], i, values)) != null) {
19420             if (min > value) min = value;
19421             if (max < value) max = value;
19422           }
19423         }
19424       }
19425     }
19426   }
19427
19428   return [min, max];
19429 };
19430
19431 var array = Array.prototype;
19432
19433 var slice = array.slice;
19434 var map = array.map;
19435
19436 var constant = function(x) {
19437   return function() {
19438     return x;
19439   };
19440 };
19441
19442 var identity = function(x) {
19443   return x;
19444 };
19445
19446 var sequence = function(start, stop, step) {
19447   start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
19448
19449   var i = -1,
19450       n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
19451       range = new Array(n);
19452
19453   while (++i < n) {
19454     range[i] = start + i * step;
19455   }
19456
19457   return range;
19458 };
19459
19460 var e10 = Math.sqrt(50);
19461 var e5 = Math.sqrt(10);
19462 var e2 = Math.sqrt(2);
19463
19464 var ticks = function(start, stop, count) {
19465   var reverse = stop < start,
19466       i = -1,
19467       n,
19468       ticks,
19469       step;
19470
19471   if (reverse) n = start, start = stop, stop = n;
19472
19473   if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
19474
19475   if (step > 0) {
19476     start = Math.ceil(start / step);
19477     stop = Math.floor(stop / step);
19478     ticks = new Array(n = Math.ceil(stop - start + 1));
19479     while (++i < n) ticks[i] = (start + i) * step;
19480   } else {
19481     start = Math.floor(start * step);
19482     stop = Math.ceil(stop * step);
19483     ticks = new Array(n = Math.ceil(start - stop + 1));
19484     while (++i < n) ticks[i] = (start - i) / step;
19485   }
19486
19487   if (reverse) ticks.reverse();
19488
19489   return ticks;
19490 };
19491
19492 function tickIncrement(start, stop, count) {
19493   var step = (stop - start) / Math.max(0, count),
19494       power = Math.floor(Math.log(step) / Math.LN10),
19495       error = step / Math.pow(10, power);
19496   return power >= 0
19497       ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)
19498       : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
19499 }
19500
19501 function tickStep(start, stop, count) {
19502   var step0 = Math.abs(stop - start) / Math.max(0, count),
19503       step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
19504       error = step0 / step1;
19505   if (error >= e10) step1 *= 10;
19506   else if (error >= e5) step1 *= 5;
19507   else if (error >= e2) step1 *= 2;
19508   return stop < start ? -step1 : step1;
19509 }
19510
19511 var sturges = function(values) {
19512   return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
19513 };
19514
19515 var histogram = function() {
19516   var value = identity,
19517       domain = extent,
19518       threshold = sturges;
19519
19520   function histogram(data) {
19521     var i,
19522         n = data.length,
19523         x,
19524         values = new Array(n);
19525
19526     for (i = 0; i < n; ++i) {
19527       values[i] = value(data[i], i, data);
19528     }
19529
19530     var xz = domain(values),
19531         x0 = xz[0],
19532         x1 = xz[1],
19533         tz = threshold(values, x0, x1);
19534
19535     // Convert number of thresholds into uniform thresholds.
19536     if (!Array.isArray(tz)) {
19537       tz = tickStep(x0, x1, tz);
19538       tz = sequence(Math.ceil(x0 / tz) * tz, Math.floor(x1 / tz) * tz, tz); // exclusive
19539     }
19540
19541     // Remove any thresholds outside the domain.
19542     var m = tz.length;
19543     while (tz[0] <= x0) tz.shift(), --m;
19544     while (tz[m - 1] > x1) tz.pop(), --m;
19545
19546     var bins = new Array(m + 1),
19547         bin;
19548
19549     // Initialize bins.
19550     for (i = 0; i <= m; ++i) {
19551       bin = bins[i] = [];
19552       bin.x0 = i > 0 ? tz[i - 1] : x0;
19553       bin.x1 = i < m ? tz[i] : x1;
19554     }
19555
19556     // Assign data to bins by value, ignoring any outside the domain.
19557     for (i = 0; i < n; ++i) {
19558       x = values[i];
19559       if (x0 <= x && x <= x1) {
19560         bins[bisectRight(tz, x, 0, m)].push(data[i]);
19561       }
19562     }
19563
19564     return bins;
19565   }
19566
19567   histogram.value = function(_) {
19568     return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
19569   };
19570
19571   histogram.domain = function(_) {
19572     return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
19573   };
19574
19575   histogram.thresholds = function(_) {
19576     return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold;
19577   };
19578
19579   return histogram;
19580 };
19581
19582 var threshold = function(values, p, valueof) {
19583   if (valueof == null) valueof = number;
19584   if (!(n = values.length)) return;
19585   if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
19586   if (p >= 1) return +valueof(values[n - 1], n - 1, values);
19587   var n,
19588       i = (n - 1) * p,
19589       i0 = Math.floor(i),
19590       value0 = +valueof(values[i0], i0, values),
19591       value1 = +valueof(values[i0 + 1], i0 + 1, values);
19592   return value0 + (value1 - value0) * (i - i0);
19593 };
19594
19595 var freedmanDiaconis = function(values, min, max) {
19596   values = map.call(values, number).sort(ascending);
19597   return Math.ceil((max - min) / (2 * (threshold(values, 0.75) - threshold(values, 0.25)) * Math.pow(values.length, -1 / 3)));
19598 };
19599
19600 var scott = function(values, min, max) {
19601   return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
19602 };
19603
19604 var max = function(values, valueof) {
19605   var n = values.length,
19606       i = -1,
19607       value,
19608       max;
19609
19610   if (valueof == null) {
19611     while (++i < n) { // Find the first comparable value.
19612       if ((value = values[i]) != null && value >= value) {
19613         max = value;
19614         while (++i < n) { // Compare the remaining values.
19615           if ((value = values[i]) != null && value > max) {
19616             max = value;
19617           }
19618         }
19619       }
19620     }
19621   }
19622
19623   else {
19624     while (++i < n) { // Find the first comparable value.
19625       if ((value = valueof(values[i], i, values)) != null && value >= value) {
19626         max = value;
19627         while (++i < n) { // Compare the remaining values.
19628           if ((value = valueof(values[i], i, values)) != null && value > max) {
19629             max = value;
19630           }
19631         }
19632       }
19633     }
19634   }
19635
19636   return max;
19637 };
19638
19639 var mean = function(values, valueof) {
19640   var n = values.length,
19641       m = n,
19642       i = -1,
19643       value,
19644       sum = 0;
19645
19646   if (valueof == null) {
19647     while (++i < n) {
19648       if (!isNaN(value = number(values[i]))) sum += value;
19649       else --m;
19650     }
19651   }
19652
19653   else {
19654     while (++i < n) {
19655       if (!isNaN(value = number(valueof(values[i], i, values)))) sum += value;
19656       else --m;
19657     }
19658   }
19659
19660   if (m) return sum / m;
19661 };
19662
19663 var median = function(values, valueof) {
19664   var n = values.length,
19665       i = -1,
19666       value,
19667       numbers = [];
19668
19669   if (valueof == null) {
19670     while (++i < n) {
19671       if (!isNaN(value = number(values[i]))) {
19672         numbers.push(value);
19673       }
19674     }
19675   }
19676
19677   else {
19678     while (++i < n) {
19679       if (!isNaN(value = number(valueof(values[i], i, values)))) {
19680         numbers.push(value);
19681       }
19682     }
19683   }
19684
19685   return threshold(numbers.sort(ascending), 0.5);
19686 };
19687
19688 var merge = function(arrays) {
19689   var n = arrays.length,
19690       m,
19691       i = -1,
19692       j = 0,
19693       merged,
19694       array;
19695
19696   while (++i < n) j += arrays[i].length;
19697   merged = new Array(j);
19698
19699   while (--n >= 0) {
19700     array = arrays[n];
19701     m = array.length;
19702     while (--m >= 0) {
19703       merged[--j] = array[m];
19704     }
19705   }
19706
19707   return merged;
19708 };
19709
19710 var min = function(values, valueof) {
19711   var n = values.length,
19712       i = -1,
19713       value,
19714       min;
19715
19716   if (valueof == null) {
19717     while (++i < n) { // Find the first comparable value.
19718       if ((value = values[i]) != null && value >= value) {
19719         min = value;
19720         while (++i < n) { // Compare the remaining values.
19721           if ((value = values[i]) != null && min > value) {
19722             min = value;
19723           }
19724         }
19725       }
19726     }
19727   }
19728
19729   else {
19730     while (++i < n) { // Find the first comparable value.
19731       if ((value = valueof(values[i], i, values)) != null && value >= value) {
19732         min = value;
19733         while (++i < n) { // Compare the remaining values.
19734           if ((value = valueof(values[i], i, values)) != null && min > value) {
19735             min = value;
19736           }
19737         }
19738       }
19739     }
19740   }
19741
19742   return min;
19743 };
19744
19745 var permute = function(array, indexes) {
19746   var i = indexes.length, permutes = new Array(i);
19747   while (i--) permutes[i] = array[indexes[i]];
19748   return permutes;
19749 };
19750
19751 var scan = function(values, compare) {
19752   if (!(n = values.length)) return;
19753   var n,
19754       i = 0,
19755       j = 0,
19756       xi,
19757       xj = values[j];
19758
19759   if (compare == null) compare = ascending;
19760
19761   while (++i < n) {
19762     if (compare(xi = values[i], xj) < 0 || compare(xj, xj) !== 0) {
19763       xj = xi, j = i;
19764     }
19765   }
19766
19767   if (compare(xj, xj) === 0) return j;
19768 };
19769
19770 var shuffle = function(array, i0, i1) {
19771   var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
19772       t,
19773       i;
19774
19775   while (m) {
19776     i = Math.random() * m-- | 0;
19777     t = array[m + i0];
19778     array[m + i0] = array[i + i0];
19779     array[i + i0] = t;
19780   }
19781
19782   return array;
19783 };
19784
19785 var sum = function(values, valueof) {
19786   var n = values.length,
19787       i = -1,
19788       value,
19789       sum = 0;
19790
19791   if (valueof == null) {
19792     while (++i < n) {
19793       if (value = +values[i]) sum += value; // Note: zero and null are equivalent.
19794     }
19795   }
19796
19797   else {
19798     while (++i < n) {
19799       if (value = +valueof(values[i], i, values)) sum += value;
19800     }
19801   }
19802
19803   return sum;
19804 };
19805
19806 var transpose = function(matrix) {
19807   if (!(n = matrix.length)) return [];
19808   for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
19809     for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
19810       row[j] = matrix[j][i];
19811     }
19812   }
19813   return transpose;
19814 };
19815
19816 function length(d) {
19817   return d.length;
19818 }
19819
19820 var zip = function() {
19821   return transpose(arguments);
19822 };
19823
19824 var slice$1 = Array.prototype.slice;
19825
19826 var identity$1 = function(x) {
19827   return x;
19828 };
19829
19830 var top = 1;
19831 var right = 2;
19832 var bottom = 3;
19833 var left = 4;
19834 var epsilon = 1e-6;
19835
19836 function translateX(x) {
19837   return "translate(" + (x + 0.5) + ",0)";
19838 }
19839
19840 function translateY(y) {
19841   return "translate(0," + (y + 0.5) + ")";
19842 }
19843
19844 function center(scale) {
19845   var offset = Math.max(0, scale.bandwidth() - 1) / 2; // Adjust for 0.5px offset.
19846   if (scale.round()) offset = Math.round(offset);
19847   return function(d) {
19848     return scale(d) + offset;
19849   };
19850 }
19851
19852 function entering() {
19853   return !this.__axis;
19854 }
19855
19856 function axis(orient, scale) {
19857   var tickArguments = [],
19858       tickValues = null,
19859       tickFormat = null,
19860       tickSizeInner = 6,
19861       tickSizeOuter = 6,
19862       tickPadding = 3,
19863       k = orient === top || orient === left ? -1 : 1,
19864       x = orient === left || orient === right ? "x" : "y",
19865       transform = orient === top || orient === bottom ? translateX : translateY;
19866
19867   function axis(context) {
19868     var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,
19869         format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$1) : tickFormat,
19870         spacing = Math.max(tickSizeInner, 0) + tickPadding,
19871         range = scale.range(),
19872         range0 = range[0] + 0.5,
19873         range1 = range[range.length - 1] + 0.5,
19874         position = (scale.bandwidth ? center : identity$1)(scale.copy()),
19875         selection = context.selection ? context.selection() : context,
19876         path = selection.selectAll(".domain").data([null]),
19877         tick = selection.selectAll(".tick").data(values, scale).order(),
19878         tickExit = tick.exit(),
19879         tickEnter = tick.enter().append("g").attr("class", "tick"),
19880         line = tick.select("line"),
19881         text = tick.select("text");
19882
19883     path = path.merge(path.enter().insert("path", ".tick")
19884         .attr("class", "domain")
19885         .attr("stroke", "#000"));
19886
19887     tick = tick.merge(tickEnter);
19888
19889     line = line.merge(tickEnter.append("line")
19890         .attr("stroke", "#000")
19891         .attr(x + "2", k * tickSizeInner));
19892
19893     text = text.merge(tickEnter.append("text")
19894         .attr("fill", "#000")
19895         .attr(x, k * spacing)
19896         .attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em"));
19897
19898     if (context !== selection) {
19899       path = path.transition(context);
19900       tick = tick.transition(context);
19901       line = line.transition(context);
19902       text = text.transition(context);
19903
19904       tickExit = tickExit.transition(context)
19905           .attr("opacity", epsilon)
19906           .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); });
19907
19908       tickEnter
19909           .attr("opacity", epsilon)
19910           .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); });
19911     }
19912
19913     tickExit.remove();
19914
19915     path
19916         .attr("d", orient === left || orient == right
19917             ? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter
19918             : "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter);
19919
19920     tick
19921         .attr("opacity", 1)
19922         .attr("transform", function(d) { return transform(position(d)); });
19923
19924     line
19925         .attr(x + "2", k * tickSizeInner);
19926
19927     text
19928         .attr(x, k * spacing)
19929         .text(format);
19930
19931     selection.filter(entering)
19932         .attr("fill", "none")
19933         .attr("font-size", 10)
19934         .attr("font-family", "sans-serif")
19935         .attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
19936
19937     selection
19938         .each(function() { this.__axis = position; });
19939   }
19940
19941   axis.scale = function(_) {
19942     return arguments.length ? (scale = _, axis) : scale;
19943   };
19944
19945   axis.ticks = function() {
19946     return tickArguments = slice$1.call(arguments), axis;
19947   };
19948
19949   axis.tickArguments = function(_) {
19950     return arguments.length ? (tickArguments = _ == null ? [] : slice$1.call(_), axis) : tickArguments.slice();
19951   };
19952
19953   axis.tickValues = function(_) {
19954     return arguments.length ? (tickValues = _ == null ? null : slice$1.call(_), axis) : tickValues && tickValues.slice();
19955   };
19956
19957   axis.tickFormat = function(_) {
19958     return arguments.length ? (tickFormat = _, axis) : tickFormat;
19959   };
19960
19961   axis.tickSize = function(_) {
19962     return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;
19963   };
19964
19965   axis.tickSizeInner = function(_) {
19966     return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;
19967   };
19968
19969   axis.tickSizeOuter = function(_) {
19970     return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;
19971   };
19972
19973   axis.tickPadding = function(_) {
19974     return arguments.length ? (tickPadding = +_, axis) : tickPadding;
19975   };
19976
19977   return axis;
19978 }
19979
19980 function axisTop(scale) {
19981   return axis(top, scale);
19982 }
19983
19984 function axisRight(scale) {
19985   return axis(right, scale);
19986 }
19987
19988 function axisBottom(scale) {
19989   return axis(bottom, scale);
19990 }
19991
19992 function axisLeft(scale) {
19993   return axis(left, scale);
19994 }
19995
19996 var noop = {value: function() {}};
19997
19998 function dispatch() {
19999   for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
20000     if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
20001     _[t] = [];
20002   }
20003   return new Dispatch(_);
20004 }
20005
20006 function Dispatch(_) {
20007   this._ = _;
20008 }
20009
20010 function parseTypenames(typenames, types) {
20011   return typenames.trim().split(/^|\s+/).map(function(t) {
20012     var name = "", i = t.indexOf(".");
20013     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
20014     if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
20015     return {type: t, name: name};
20016   });
20017 }
20018
20019 Dispatch.prototype = dispatch.prototype = {
20020   constructor: Dispatch,
20021   on: function(typename, callback) {
20022     var _ = this._,
20023         T = parseTypenames(typename + "", _),
20024         t,
20025         i = -1,
20026         n = T.length;
20027
20028     // If no callback was specified, return the callback of the given type and name.
20029     if (arguments.length < 2) {
20030       while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
20031       return;
20032     }
20033
20034     // If a type was specified, set the callback for the given type and name.
20035     // Otherwise, if a null callback was specified, remove callbacks of the given name.
20036     if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
20037     while (++i < n) {
20038       if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
20039       else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
20040     }
20041
20042     return this;
20043   },
20044   copy: function() {
20045     var copy = {}, _ = this._;
20046     for (var t in _) copy[t] = _[t].slice();
20047     return new Dispatch(copy);
20048   },
20049   call: function(type, that) {
20050     if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
20051     if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
20052     for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
20053   },
20054   apply: function(type, that, args) {
20055     if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
20056     for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
20057   }
20058 };
20059
20060 function get(type, name) {
20061   for (var i = 0, n = type.length, c; i < n; ++i) {
20062     if ((c = type[i]).name === name) {
20063       return c.value;
20064     }
20065   }
20066 }
20067
20068 function set(type, name, callback) {
20069   for (var i = 0, n = type.length; i < n; ++i) {
20070     if (type[i].name === name) {
20071       type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
20072       break;
20073     }
20074   }
20075   if (callback != null) type.push({name: name, value: callback});
20076   return type;
20077 }
20078
20079 var xhtml = "http://www.w3.org/1999/xhtml";
20080
20081 var namespaces = {
20082   svg: "http://www.w3.org/2000/svg",
20083   xhtml: xhtml,
20084   xlink: "http://www.w3.org/1999/xlink",
20085   xml: "http://www.w3.org/XML/1998/namespace",
20086   xmlns: "http://www.w3.org/2000/xmlns/"
20087 };
20088
20089 var namespace = function(name) {
20090   var prefix = name += "", i = prefix.indexOf(":");
20091   if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
20092   return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
20093 };
20094
20095 function creatorInherit(name) {
20096   return function() {
20097     var document = this.ownerDocument,
20098         uri = this.namespaceURI;
20099     return uri === xhtml && document.documentElement.namespaceURI === xhtml
20100         ? document.createElement(name)
20101         : document.createElementNS(uri, name);
20102   };
20103 }
20104
20105 function creatorFixed(fullname) {
20106   return function() {
20107     return this.ownerDocument.createElementNS(fullname.space, fullname.local);
20108   };
20109 }
20110
20111 var creator = function(name) {
20112   var fullname = namespace(name);
20113   return (fullname.local
20114       ? creatorFixed
20115       : creatorInherit)(fullname);
20116 };
20117
20118 var nextId = 0;
20119
20120 function local$1() {
20121   return new Local;
20122 }
20123
20124 function Local() {
20125   this._ = "@" + (++nextId).toString(36);
20126 }
20127
20128 Local.prototype = local$1.prototype = {
20129   constructor: Local,
20130   get: function(node) {
20131     var id = this._;
20132     while (!(id in node)) if (!(node = node.parentNode)) return;
20133     return node[id];
20134   },
20135   set: function(node, value) {
20136     return node[this._] = value;
20137   },
20138   remove: function(node) {
20139     return this._ in node && delete node[this._];
20140   },
20141   toString: function() {
20142     return this._;
20143   }
20144 };
20145
20146 var matcher = function(selector) {
20147   return function() {
20148     return this.matches(selector);
20149   };
20150 };
20151
20152 if (typeof document !== "undefined") {
20153   var element = document.documentElement;
20154   if (!element.matches) {
20155     var vendorMatches = element.webkitMatchesSelector
20156         || element.msMatchesSelector
20157         || element.mozMatchesSelector
20158         || element.oMatchesSelector;
20159     matcher = function(selector) {
20160       return function() {
20161         return vendorMatches.call(this, selector);
20162       };
20163     };
20164   }
20165 }
20166
20167 var matcher$1 = matcher;
20168
20169 var filterEvents = {};
20170
20171 var event = null;
20172
20173 if (typeof document !== "undefined") {
20174   var element$1 = document.documentElement;
20175   if (!("onmouseenter" in element$1)) {
20176     filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
20177   }
20178 }
20179
20180 function filterContextListener(listener, index, group) {
20181   listener = contextListener(listener, index, group);
20182   return function(event) {
20183     var related = event.relatedTarget;
20184     if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
20185       listener.call(this, event);
20186     }
20187   };
20188 }
20189
20190 function contextListener(listener, index, group) {
20191   return function(event1) {
20192     var event0 = event; // Events can be reentrant (e.g., focus).
20193     event = event1;
20194     try {
20195       listener.call(this, this.__data__, index, group);
20196     } finally {
20197       event = event0;
20198     }
20199   };
20200 }
20201
20202 function parseTypenames$1(typenames) {
20203   return typenames.trim().split(/^|\s+/).map(function(t) {
20204     var name = "", i = t.indexOf(".");
20205     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
20206     return {type: t, name: name};
20207   });
20208 }
20209
20210 function onRemove(typename) {
20211   return function() {
20212     var on = this.__on;
20213     if (!on) return;
20214     for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
20215       if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
20216         this.removeEventListener(o.type, o.listener, o.capture);
20217       } else {
20218         on[++i] = o;
20219       }
20220     }
20221     if (++i) on.length = i;
20222     else delete this.__on;
20223   };
20224 }
20225
20226 function onAdd(typename, value, capture) {
20227   var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
20228   return function(d, i, group) {
20229     var on = this.__on, o, listener = wrap(value, i, group);
20230     if (on) for (var j = 0, m = on.length; j < m; ++j) {
20231       if ((o = on[j]).type === typename.type && o.name === typename.name) {
20232         this.removeEventListener(o.type, o.listener, o.capture);
20233         this.addEventListener(o.type, o.listener = listener, o.capture = capture);
20234         o.value = value;
20235         return;
20236       }
20237     }
20238     this.addEventListener(typename.type, listener, capture);
20239     o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
20240     if (!on) this.__on = [o];
20241     else on.push(o);
20242   };
20243 }
20244
20245 var selection_on = function(typename, value, capture) {
20246   var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t;
20247
20248   if (arguments.length < 2) {
20249     var on = this.node().__on;
20250     if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
20251       for (i = 0, o = on[j]; i < n; ++i) {
20252         if ((t = typenames[i]).type === o.type && t.name === o.name) {
20253           return o.value;
20254         }
20255       }
20256     }
20257     return;
20258   }
20259
20260   on = value ? onAdd : onRemove;
20261   if (capture == null) capture = false;
20262   for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
20263   return this;
20264 };
20265
20266 function customEvent(event1, listener, that, args) {
20267   var event0 = event;
20268   event1.sourceEvent = event;
20269   event = event1;
20270   try {
20271     return listener.apply(that, args);
20272   } finally {
20273     event = event0;
20274   }
20275 }
20276
20277 var sourceEvent = function() {
20278   var current = event, source;
20279   while (source = current.sourceEvent) current = source;
20280   return current;
20281 };
20282
20283 var point = function(node, event) {
20284   var svg = node.ownerSVGElement || node;
20285
20286   if (svg.createSVGPoint) {
20287     var point = svg.createSVGPoint();
20288     point.x = event.clientX, point.y = event.clientY;
20289     point = point.matrixTransform(node.getScreenCTM().inverse());
20290     return [point.x, point.y];
20291   }
20292
20293   var rect = node.getBoundingClientRect();
20294   return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
20295 };
20296
20297 var mouse = function(node) {
20298   var event = sourceEvent();
20299   if (event.changedTouches) event = event.changedTouches[0];
20300   return point(node, event);
20301 };
20302
20303 function none() {}
20304
20305 var selector = function(selector) {
20306   return selector == null ? none : function() {
20307     return this.querySelector(selector);
20308   };
20309 };
20310
20311 var selection_select = function(select) {
20312   if (typeof select !== "function") select = selector(select);
20313
20314   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
20315     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
20316       if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
20317         if ("__data__" in node) subnode.__data__ = node.__data__;
20318         subgroup[i] = subnode;
20319       }
20320     }
20321   }
20322
20323   return new Selection(subgroups, this._parents);
20324 };
20325
20326 function empty$1() {
20327   return [];
20328 }
20329
20330 var selectorAll = function(selector) {
20331   return selector == null ? empty$1 : function() {
20332     return this.querySelectorAll(selector);
20333   };
20334 };
20335
20336 var selection_selectAll = function(select) {
20337   if (typeof select !== "function") select = selectorAll(select);
20338
20339   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
20340     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
20341       if (node = group[i]) {
20342         subgroups.push(select.call(node, node.__data__, i, group));
20343         parents.push(node);
20344       }
20345     }
20346   }
20347
20348   return new Selection(subgroups, parents);
20349 };
20350
20351 var selection_filter = function(match) {
20352   if (typeof match !== "function") match = matcher$1(match);
20353
20354   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
20355     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
20356       if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
20357         subgroup.push(node);
20358       }
20359     }
20360   }
20361
20362   return new Selection(subgroups, this._parents);
20363 };
20364
20365 var sparse = function(update) {
20366   return new Array(update.length);
20367 };
20368
20369 var selection_enter = function() {
20370   return new Selection(this._enter || this._groups.map(sparse), this._parents);
20371 };
20372
20373 function EnterNode(parent, datum) {
20374   this.ownerDocument = parent.ownerDocument;
20375   this.namespaceURI = parent.namespaceURI;
20376   this._next = null;
20377   this._parent = parent;
20378   this.__data__ = datum;
20379 }
20380
20381 EnterNode.prototype = {
20382   constructor: EnterNode,
20383   appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
20384   insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
20385   querySelector: function(selector) { return this._parent.querySelector(selector); },
20386   querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
20387 };
20388
20389 var constant$1 = function(x) {
20390   return function() {
20391     return x;
20392   };
20393 };
20394
20395 var keyPrefix = "$"; // Protect against keys like “__proto__”.
20396
20397 function bindIndex(parent, group, enter, update, exit, data) {
20398   var i = 0,
20399       node,
20400       groupLength = group.length,
20401       dataLength = data.length;
20402
20403   // Put any non-null nodes that fit into update.
20404   // Put any null nodes into enter.
20405   // Put any remaining data into enter.
20406   for (; i < dataLength; ++i) {
20407     if (node = group[i]) {
20408       node.__data__ = data[i];
20409       update[i] = node;
20410     } else {
20411       enter[i] = new EnterNode(parent, data[i]);
20412     }
20413   }
20414
20415   // Put any non-null nodes that don’t fit into exit.
20416   for (; i < groupLength; ++i) {
20417     if (node = group[i]) {
20418       exit[i] = node;
20419     }
20420   }
20421 }
20422
20423 function bindKey(parent, group, enter, update, exit, data, key) {
20424   var i,
20425       node,
20426       nodeByKeyValue = {},
20427       groupLength = group.length,
20428       dataLength = data.length,
20429       keyValues = new Array(groupLength),
20430       keyValue;
20431
20432   // Compute the key for each node.
20433   // If multiple nodes have the same key, the duplicates are added to exit.
20434   for (i = 0; i < groupLength; ++i) {
20435     if (node = group[i]) {
20436       keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
20437       if (keyValue in nodeByKeyValue) {
20438         exit[i] = node;
20439       } else {
20440         nodeByKeyValue[keyValue] = node;
20441       }
20442     }
20443   }
20444
20445   // Compute the key for each datum.
20446   // If there a node associated with this key, join and add it to update.
20447   // If there is not (or the key is a duplicate), add it to enter.
20448   for (i = 0; i < dataLength; ++i) {
20449     keyValue = keyPrefix + key.call(parent, data[i], i, data);
20450     if (node = nodeByKeyValue[keyValue]) {
20451       update[i] = node;
20452       node.__data__ = data[i];
20453       nodeByKeyValue[keyValue] = null;
20454     } else {
20455       enter[i] = new EnterNode(parent, data[i]);
20456     }
20457   }
20458
20459   // Add any remaining nodes that were not bound to data to exit.
20460   for (i = 0; i < groupLength; ++i) {
20461     if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
20462       exit[i] = node;
20463     }
20464   }
20465 }
20466
20467 var selection_data = function(value, key) {
20468   if (!value) {
20469     data = new Array(this.size()), j = -1;
20470     this.each(function(d) { data[++j] = d; });
20471     return data;
20472   }
20473
20474   var bind = key ? bindKey : bindIndex,
20475       parents = this._parents,
20476       groups = this._groups;
20477
20478   if (typeof value !== "function") value = constant$1(value);
20479
20480   for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
20481     var parent = parents[j],
20482         group = groups[j],
20483         groupLength = group.length,
20484         data = value.call(parent, parent && parent.__data__, j, parents),
20485         dataLength = data.length,
20486         enterGroup = enter[j] = new Array(dataLength),
20487         updateGroup = update[j] = new Array(dataLength),
20488         exitGroup = exit[j] = new Array(groupLength);
20489
20490     bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
20491
20492     // Now connect the enter nodes to their following update node, such that
20493     // appendChild can insert the materialized enter node before this node,
20494     // rather than at the end of the parent node.
20495     for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
20496       if (previous = enterGroup[i0]) {
20497         if (i0 >= i1) i1 = i0 + 1;
20498         while (!(next = updateGroup[i1]) && ++i1 < dataLength);
20499         previous._next = next || null;
20500       }
20501     }
20502   }
20503
20504   update = new Selection(update, parents);
20505   update._enter = enter;
20506   update._exit = exit;
20507   return update;
20508 };
20509
20510 var selection_exit = function() {
20511   return new Selection(this._exit || this._groups.map(sparse), this._parents);
20512 };
20513
20514 var selection_merge = function(selection$$1) {
20515
20516   for (var groups0 = this._groups, groups1 = selection$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
20517     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
20518       if (node = group0[i] || group1[i]) {
20519         merge[i] = node;
20520       }
20521     }
20522   }
20523
20524   for (; j < m0; ++j) {
20525     merges[j] = groups0[j];
20526   }
20527
20528   return new Selection(merges, this._parents);
20529 };
20530
20531 var selection_order = function() {
20532
20533   for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
20534     for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
20535       if (node = group[i]) {
20536         if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
20537         next = node;
20538       }
20539     }
20540   }
20541
20542   return this;
20543 };
20544
20545 var selection_sort = function(compare) {
20546   if (!compare) compare = ascending$1;
20547
20548   function compareNode(a, b) {
20549     return a && b ? compare(a.__data__, b.__data__) : !a - !b;
20550   }
20551
20552   for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
20553     for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
20554       if (node = group[i]) {
20555         sortgroup[i] = node;
20556       }
20557     }
20558     sortgroup.sort(compareNode);
20559   }
20560
20561   return new Selection(sortgroups, this._parents).order();
20562 };
20563
20564 function ascending$1(a, b) {
20565   return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
20566 }
20567
20568 var selection_call = function() {
20569   var callback = arguments[0];
20570   arguments[0] = this;
20571   callback.apply(null, arguments);
20572   return this;
20573 };
20574
20575 var selection_nodes = function() {
20576   var nodes = new Array(this.size()), i = -1;
20577   this.each(function() { nodes[++i] = this; });
20578   return nodes;
20579 };
20580
20581 var selection_node = function() {
20582
20583   for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
20584     for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
20585       var node = group[i];
20586       if (node) return node;
20587     }
20588   }
20589
20590   return null;
20591 };
20592
20593 var selection_size = function() {
20594   var size = 0;
20595   this.each(function() { ++size; });
20596   return size;
20597 };
20598
20599 var selection_empty = function() {
20600   return !this.node();
20601 };
20602
20603 var selection_each = function(callback) {
20604
20605   for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
20606     for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
20607       if (node = group[i]) callback.call(node, node.__data__, i, group);
20608     }
20609   }
20610
20611   return this;
20612 };
20613
20614 function attrRemove(name) {
20615   return function() {
20616     this.removeAttribute(name);
20617   };
20618 }
20619
20620 function attrRemoveNS(fullname) {
20621   return function() {
20622     this.removeAttributeNS(fullname.space, fullname.local);
20623   };
20624 }
20625
20626 function attrConstant(name, value) {
20627   return function() {
20628     this.setAttribute(name, value);
20629   };
20630 }
20631
20632 function attrConstantNS(fullname, value) {
20633   return function() {
20634     this.setAttributeNS(fullname.space, fullname.local, value);
20635   };
20636 }
20637
20638 function attrFunction(name, value) {
20639   return function() {
20640     var v = value.apply(this, arguments);
20641     if (v == null) this.removeAttribute(name);
20642     else this.setAttribute(name, v);
20643   };
20644 }
20645
20646 function attrFunctionNS(fullname, value) {
20647   return function() {
20648     var v = value.apply(this, arguments);
20649     if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
20650     else this.setAttributeNS(fullname.space, fullname.local, v);
20651   };
20652 }
20653
20654 var selection_attr = function(name, value) {
20655   var fullname = namespace(name);
20656
20657   if (arguments.length < 2) {
20658     var node = this.node();
20659     return fullname.local
20660         ? node.getAttributeNS(fullname.space, fullname.local)
20661         : node.getAttribute(fullname);
20662   }
20663
20664   return this.each((value == null
20665       ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
20666       ? (fullname.local ? attrFunctionNS : attrFunction)
20667       : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
20668 };
20669
20670 var defaultView = function(node) {
20671   return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
20672       || (node.document && node) // node is a Window
20673       || node.defaultView; // node is a Document
20674 };
20675
20676 function styleRemove(name) {
20677   return function() {
20678     this.style.removeProperty(name);
20679   };
20680 }
20681
20682 function styleConstant(name, value, priority) {
20683   return function() {
20684     this.style.setProperty(name, value, priority);
20685   };
20686 }
20687
20688 function styleFunction(name, value, priority) {
20689   return function() {
20690     var v = value.apply(this, arguments);
20691     if (v == null) this.style.removeProperty(name);
20692     else this.style.setProperty(name, v, priority);
20693   };
20694 }
20695
20696 var selection_style = function(name, value, priority) {
20697   return arguments.length > 1
20698       ? this.each((value == null
20699             ? styleRemove : typeof value === "function"
20700             ? styleFunction
20701             : styleConstant)(name, value, priority == null ? "" : priority))
20702       : styleValue(this.node(), name);
20703 };
20704
20705 function styleValue(node, name) {
20706   return node.style.getPropertyValue(name)
20707       || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
20708 }
20709
20710 function propertyRemove(name) {
20711   return function() {
20712     delete this[name];
20713   };
20714 }
20715
20716 function propertyConstant(name, value) {
20717   return function() {
20718     this[name] = value;
20719   };
20720 }
20721
20722 function propertyFunction(name, value) {
20723   return function() {
20724     var v = value.apply(this, arguments);
20725     if (v == null) delete this[name];
20726     else this[name] = v;
20727   };
20728 }
20729
20730 var selection_property = function(name, value) {
20731   return arguments.length > 1
20732       ? this.each((value == null
20733           ? propertyRemove : typeof value === "function"
20734           ? propertyFunction
20735           : propertyConstant)(name, value))
20736       : this.node()[name];
20737 };
20738
20739 function classArray(string) {
20740   return string.trim().split(/^|\s+/);
20741 }
20742
20743 function classList(node) {
20744   return node.classList || new ClassList(node);
20745 }
20746
20747 function ClassList(node) {
20748   this._node = node;
20749   this._names = classArray(node.getAttribute("class") || "");
20750 }
20751
20752 ClassList.prototype = {
20753   add: function(name) {
20754     var i = this._names.indexOf(name);
20755     if (i < 0) {
20756       this._names.push(name);
20757       this._node.setAttribute("class", this._names.join(" "));
20758     }
20759   },
20760   remove: function(name) {
20761     var i = this._names.indexOf(name);
20762     if (i >= 0) {
20763       this._names.splice(i, 1);
20764       this._node.setAttribute("class", this._names.join(" "));
20765     }
20766   },
20767   contains: function(name) {
20768     return this._names.indexOf(name) >= 0;
20769   }
20770 };
20771
20772 function classedAdd(node, names) {
20773   var list = classList(node), i = -1, n = names.length;
20774   while (++i < n) list.add(names[i]);
20775 }
20776
20777 function classedRemove(node, names) {
20778   var list = classList(node), i = -1, n = names.length;
20779   while (++i < n) list.remove(names[i]);
20780 }
20781
20782 function classedTrue(names) {
20783   return function() {
20784     classedAdd(this, names);
20785   };
20786 }
20787
20788 function classedFalse(names) {
20789   return function() {
20790     classedRemove(this, names);
20791   };
20792 }
20793
20794 function classedFunction(names, value) {
20795   return function() {
20796     (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
20797   };
20798 }
20799
20800 var selection_classed = function(name, value) {
20801   var names = classArray(name + "");
20802
20803   if (arguments.length < 2) {
20804     var list = classList(this.node()), i = -1, n = names.length;
20805     while (++i < n) if (!list.contains(names[i])) return false;
20806     return true;
20807   }
20808
20809   return this.each((typeof value === "function"
20810       ? classedFunction : value
20811       ? classedTrue
20812       : classedFalse)(names, value));
20813 };
20814
20815 function textRemove() {
20816   this.textContent = "";
20817 }
20818
20819 function textConstant(value) {
20820   return function() {
20821     this.textContent = value;
20822   };
20823 }
20824
20825 function textFunction(value) {
20826   return function() {
20827     var v = value.apply(this, arguments);
20828     this.textContent = v == null ? "" : v;
20829   };
20830 }
20831
20832 var selection_text = function(value) {
20833   return arguments.length
20834       ? this.each(value == null
20835           ? textRemove : (typeof value === "function"
20836           ? textFunction
20837           : textConstant)(value))
20838       : this.node().textContent;
20839 };
20840
20841 function htmlRemove() {
20842   this.innerHTML = "";
20843 }
20844
20845 function htmlConstant(value) {
20846   return function() {
20847     this.innerHTML = value;
20848   };
20849 }
20850
20851 function htmlFunction(value) {
20852   return function() {
20853     var v = value.apply(this, arguments);
20854     this.innerHTML = v == null ? "" : v;
20855   };
20856 }
20857
20858 var selection_html = function(value) {
20859   return arguments.length
20860       ? this.each(value == null
20861           ? htmlRemove : (typeof value === "function"
20862           ? htmlFunction
20863           : htmlConstant)(value))
20864       : this.node().innerHTML;
20865 };
20866
20867 function raise() {
20868   if (this.nextSibling) this.parentNode.appendChild(this);
20869 }
20870
20871 var selection_raise = function() {
20872   return this.each(raise);
20873 };
20874
20875 function lower() {
20876   if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
20877 }
20878
20879 var selection_lower = function() {
20880   return this.each(lower);
20881 };
20882
20883 var selection_append = function(name) {
20884   var create = typeof name === "function" ? name : creator(name);
20885   return this.select(function() {
20886     return this.appendChild(create.apply(this, arguments));
20887   });
20888 };
20889
20890 function constantNull() {
20891   return null;
20892 }
20893
20894 var selection_insert = function(name, before) {
20895   var create = typeof name === "function" ? name : creator(name),
20896       select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
20897   return this.select(function() {
20898     return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
20899   });
20900 };
20901
20902 function remove() {
20903   var parent = this.parentNode;
20904   if (parent) parent.removeChild(this);
20905 }
20906
20907 var selection_remove = function() {
20908   return this.each(remove);
20909 };
20910
20911 var selection_datum = function(value) {
20912   return arguments.length
20913       ? this.property("__data__", value)
20914       : this.node().__data__;
20915 };
20916
20917 function dispatchEvent(node, type, params) {
20918   var window = defaultView(node),
20919       event = window.CustomEvent;
20920
20921   if (typeof event === "function") {
20922     event = new event(type, params);
20923   } else {
20924     event = window.document.createEvent("Event");
20925     if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
20926     else event.initEvent(type, false, false);
20927   }
20928
20929   node.dispatchEvent(event);
20930 }
20931
20932 function dispatchConstant(type, params) {
20933   return function() {
20934     return dispatchEvent(this, type, params);
20935   };
20936 }
20937
20938 function dispatchFunction(type, params) {
20939   return function() {
20940     return dispatchEvent(this, type, params.apply(this, arguments));
20941   };
20942 }
20943
20944 var selection_dispatch = function(type, params) {
20945   return this.each((typeof params === "function"
20946       ? dispatchFunction
20947       : dispatchConstant)(type, params));
20948 };
20949
20950 var root = [null];
20951
20952 function Selection(groups, parents) {
20953   this._groups = groups;
20954   this._parents = parents;
20955 }
20956
20957 function selection() {
20958   return new Selection([[document.documentElement]], root);
20959 }
20960
20961 Selection.prototype = selection.prototype = {
20962   constructor: Selection,
20963   select: selection_select,
20964   selectAll: selection_selectAll,
20965   filter: selection_filter,
20966   data: selection_data,
20967   enter: selection_enter,
20968   exit: selection_exit,
20969   merge: selection_merge,
20970   order: selection_order,
20971   sort: selection_sort,
20972   call: selection_call,
20973   nodes: selection_nodes,
20974   node: selection_node,
20975   size: selection_size,
20976   empty: selection_empty,
20977   each: selection_each,
20978   attr: selection_attr,
20979   style: selection_style,
20980   property: selection_property,
20981   classed: selection_classed,
20982   text: selection_text,
20983   html: selection_html,
20984   raise: selection_raise,
20985   lower: selection_lower,
20986   append: selection_append,
20987   insert: selection_insert,
20988   remove: selection_remove,
20989   datum: selection_datum,
20990   on: selection_on,
20991   dispatch: selection_dispatch
20992 };
20993
20994 var select = function(selector) {
20995   return typeof selector === "string"
20996       ? new Selection([[document.querySelector(selector)]], [document.documentElement])
20997       : new Selection([[selector]], root);
20998 };
20999
21000 var selectAll = function(selector) {
21001   return typeof selector === "string"
21002       ? new Selection([document.querySelectorAll(selector)], [document.documentElement])
21003       : new Selection([selector == null ? [] : selector], root);
21004 };
21005
21006 var touch = function(node, touches, identifier) {
21007   if (arguments.length < 3) identifier = touches, touches = sourceEvent().changedTouches;
21008
21009   for (var i = 0, n = touches ? touches.length : 0, touch; i < n; ++i) {
21010     if ((touch = touches[i]).identifier === identifier) {
21011       return point(node, touch);
21012     }
21013   }
21014
21015   return null;
21016 };
21017
21018 var touches = function(node, touches) {
21019   if (touches == null) touches = sourceEvent().touches;
21020
21021   for (var i = 0, n = touches ? touches.length : 0, points = new Array(n); i < n; ++i) {
21022     points[i] = point(node, touches[i]);
21023   }
21024
21025   return points;
21026 };
21027
21028 function nopropagation() {
21029   event.stopImmediatePropagation();
21030 }
21031
21032 var noevent = function() {
21033   event.preventDefault();
21034   event.stopImmediatePropagation();
21035 };
21036
21037 var dragDisable = function(view) {
21038   var root = view.document.documentElement,
21039       selection$$1 = select(view).on("dragstart.drag", noevent, true);
21040   if ("onselectstart" in root) {
21041     selection$$1.on("selectstart.drag", noevent, true);
21042   } else {
21043     root.__noselect = root.style.MozUserSelect;
21044     root.style.MozUserSelect = "none";
21045   }
21046 };
21047
21048 function yesdrag(view, noclick) {
21049   var root = view.document.documentElement,
21050       selection$$1 = select(view).on("dragstart.drag", null);
21051   if (noclick) {
21052     selection$$1.on("click.drag", noevent, true);
21053     setTimeout(function() { selection$$1.on("click.drag", null); }, 0);
21054   }
21055   if ("onselectstart" in root) {
21056     selection$$1.on("selectstart.drag", null);
21057   } else {
21058     root.style.MozUserSelect = root.__noselect;
21059     delete root.__noselect;
21060   }
21061 }
21062
21063 var constant$2 = function(x) {
21064   return function() {
21065     return x;
21066   };
21067 };
21068
21069 function DragEvent(target, type, subject, id, active, x, y, dx, dy, dispatch) {
21070   this.target = target;
21071   this.type = type;
21072   this.subject = subject;
21073   this.identifier = id;
21074   this.active = active;
21075   this.x = x;
21076   this.y = y;
21077   this.dx = dx;
21078   this.dy = dy;
21079   this._ = dispatch;
21080 }
21081
21082 DragEvent.prototype.on = function() {
21083   var value = this._.on.apply(this._, arguments);
21084   return value === this._ ? this : value;
21085 };
21086
21087 // Ignore right-click, since that should open the context menu.
21088 function defaultFilter$1() {
21089   return !event.button;
21090 }
21091
21092 function defaultContainer() {
21093   return this.parentNode;
21094 }
21095
21096 function defaultSubject(d) {
21097   return d == null ? {x: event.x, y: event.y} : d;
21098 }
21099
21100 var drag = function() {
21101   var filter = defaultFilter$1,
21102       container = defaultContainer,
21103       subject = defaultSubject,
21104       gestures = {},
21105       listeners = dispatch("start", "drag", "end"),
21106       active = 0,
21107       mousedownx,
21108       mousedowny,
21109       mousemoving,
21110       touchending,
21111       clickDistance2 = 0;
21112
21113   function drag(selection) {
21114     selection
21115         .on("mousedown.drag", mousedowned)
21116         .on("touchstart.drag", touchstarted)
21117         .on("touchmove.drag", touchmoved)
21118         .on("touchend.drag touchcancel.drag", touchended)
21119         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
21120   }
21121
21122   function mousedowned() {
21123     if (touchending || !filter.apply(this, arguments)) return;
21124     var gesture = beforestart("mouse", container.apply(this, arguments), mouse, this, arguments);
21125     if (!gesture) return;
21126     select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
21127     dragDisable(event.view);
21128     nopropagation();
21129     mousemoving = false;
21130     mousedownx = event.clientX;
21131     mousedowny = event.clientY;
21132     gesture("start");
21133   }
21134
21135   function mousemoved() {
21136     noevent();
21137     if (!mousemoving) {
21138       var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny;
21139       mousemoving = dx * dx + dy * dy > clickDistance2;
21140     }
21141     gestures.mouse("drag");
21142   }
21143
21144   function mouseupped() {
21145     select(event.view).on("mousemove.drag mouseup.drag", null);
21146     yesdrag(event.view, mousemoving);
21147     noevent();
21148     gestures.mouse("end");
21149   }
21150
21151   function touchstarted() {
21152     if (!filter.apply(this, arguments)) return;
21153     var touches$$1 = event.changedTouches,
21154         c = container.apply(this, arguments),
21155         n = touches$$1.length, i, gesture;
21156
21157     for (i = 0; i < n; ++i) {
21158       if (gesture = beforestart(touches$$1[i].identifier, c, touch, this, arguments)) {
21159         nopropagation();
21160         gesture("start");
21161       }
21162     }
21163   }
21164
21165   function touchmoved() {
21166     var touches$$1 = event.changedTouches,
21167         n = touches$$1.length, i, gesture;
21168
21169     for (i = 0; i < n; ++i) {
21170       if (gesture = gestures[touches$$1[i].identifier]) {
21171         noevent();
21172         gesture("drag");
21173       }
21174     }
21175   }
21176
21177   function touchended() {
21178     var touches$$1 = event.changedTouches,
21179         n = touches$$1.length, i, gesture;
21180
21181     if (touchending) clearTimeout(touchending);
21182     touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
21183     for (i = 0; i < n; ++i) {
21184       if (gesture = gestures[touches$$1[i].identifier]) {
21185         nopropagation();
21186         gesture("end");
21187       }
21188     }
21189   }
21190
21191   function beforestart(id, container, point, that, args) {
21192     var p = point(container, id), s, dx, dy,
21193         sublisteners = listeners.copy();
21194
21195     if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() {
21196       if ((event.subject = s = subject.apply(that, args)) == null) return false;
21197       dx = s.x - p[0] || 0;
21198       dy = s.y - p[1] || 0;
21199       return true;
21200     })) return;
21201
21202     return function gesture(type) {
21203       var p0 = p, n;
21204       switch (type) {
21205         case "start": gestures[id] = gesture, n = active++; break;
21206         case "end": delete gestures[id], --active; // nobreak
21207         case "drag": p = point(container, id), n = active; break;
21208       }
21209       customEvent(new DragEvent(drag, type, s, id, n, p[0] + dx, p[1] + dy, p[0] - p0[0], p[1] - p0[1], sublisteners), sublisteners.apply, sublisteners, [type, that, args]);
21210     };
21211   }
21212
21213   drag.filter = function(_) {
21214     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$2(!!_), drag) : filter;
21215   };
21216
21217   drag.container = function(_) {
21218     return arguments.length ? (container = typeof _ === "function" ? _ : constant$2(_), drag) : container;
21219   };
21220
21221   drag.subject = function(_) {
21222     return arguments.length ? (subject = typeof _ === "function" ? _ : constant$2(_), drag) : subject;
21223   };
21224
21225   drag.on = function() {
21226     var value = listeners.on.apply(listeners, arguments);
21227     return value === listeners ? drag : value;
21228   };
21229
21230   drag.clickDistance = function(_) {
21231     return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
21232   };
21233
21234   return drag;
21235 };
21236
21237 var define = function(constructor, factory, prototype) {
21238   constructor.prototype = factory.prototype = prototype;
21239   prototype.constructor = constructor;
21240 };
21241
21242 function extend(parent, definition) {
21243   var prototype = Object.create(parent.prototype);
21244   for (var key in definition) prototype[key] = definition[key];
21245   return prototype;
21246 }
21247
21248 function Color() {}
21249
21250 var darker = 0.7;
21251 var brighter = 1 / darker;
21252
21253 var reI = "\\s*([+-]?\\d+)\\s*";
21254 var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*";
21255 var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
21256 var reHex3 = /^#([0-9a-f]{3})$/;
21257 var reHex6 = /^#([0-9a-f]{6})$/;
21258 var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$");
21259 var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$");
21260 var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$");
21261 var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$");
21262 var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$");
21263 var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
21264
21265 var named = {
21266   aliceblue: 0xf0f8ff,
21267   antiquewhite: 0xfaebd7,
21268   aqua: 0x00ffff,
21269   aquamarine: 0x7fffd4,
21270   azure: 0xf0ffff,
21271   beige: 0xf5f5dc,
21272   bisque: 0xffe4c4,
21273   black: 0x000000,
21274   blanchedalmond: 0xffebcd,
21275   blue: 0x0000ff,
21276   blueviolet: 0x8a2be2,
21277   brown: 0xa52a2a,
21278   burlywood: 0xdeb887,
21279   cadetblue: 0x5f9ea0,
21280   chartreuse: 0x7fff00,
21281   chocolate: 0xd2691e,
21282   coral: 0xff7f50,
21283   cornflowerblue: 0x6495ed,
21284   cornsilk: 0xfff8dc,
21285   crimson: 0xdc143c,
21286   cyan: 0x00ffff,
21287   darkblue: 0x00008b,
21288   darkcyan: 0x008b8b,
21289   darkgoldenrod: 0xb8860b,
21290   darkgray: 0xa9a9a9,
21291   darkgreen: 0x006400,
21292   darkgrey: 0xa9a9a9,
21293   darkkhaki: 0xbdb76b,
21294   darkmagenta: 0x8b008b,
21295   darkolivegreen: 0x556b2f,
21296   darkorange: 0xff8c00,
21297   darkorchid: 0x9932cc,
21298   darkred: 0x8b0000,
21299   darksalmon: 0xe9967a,
21300   darkseagreen: 0x8fbc8f,
21301   darkslateblue: 0x483d8b,
21302   darkslategray: 0x2f4f4f,
21303   darkslategrey: 0x2f4f4f,
21304   darkturquoise: 0x00ced1,
21305   darkviolet: 0x9400d3,
21306   deeppink: 0xff1493,
21307   deepskyblue: 0x00bfff,
21308   dimgray: 0x696969,
21309   dimgrey: 0x696969,
21310   dodgerblue: 0x1e90ff,
21311   firebrick: 0xb22222,
21312   floralwhite: 0xfffaf0,
21313   forestgreen: 0x228b22,
21314   fuchsia: 0xff00ff,
21315   gainsboro: 0xdcdcdc,
21316   ghostwhite: 0xf8f8ff,
21317   gold: 0xffd700,
21318   goldenrod: 0xdaa520,
21319   gray: 0x808080,
21320   green: 0x008000,
21321   greenyellow: 0xadff2f,
21322   grey: 0x808080,
21323   honeydew: 0xf0fff0,
21324   hotpink: 0xff69b4,
21325   indianred: 0xcd5c5c,
21326   indigo: 0x4b0082,
21327   ivory: 0xfffff0,
21328   khaki: 0xf0e68c,
21329   lavender: 0xe6e6fa,
21330   lavenderblush: 0xfff0f5,
21331   lawngreen: 0x7cfc00,
21332   lemonchiffon: 0xfffacd,
21333   lightblue: 0xadd8e6,
21334   lightcoral: 0xf08080,
21335   lightcyan: 0xe0ffff,
21336   lightgoldenrodyellow: 0xfafad2,
21337   lightgray: 0xd3d3d3,
21338   lightgreen: 0x90ee90,
21339   lightgrey: 0xd3d3d3,
21340   lightpink: 0xffb6c1,
21341   lightsalmon: 0xffa07a,
21342   lightseagreen: 0x20b2aa,
21343   lightskyblue: 0x87cefa,
21344   lightslategray: 0x778899,
21345   lightslategrey: 0x778899,
21346   lightsteelblue: 0xb0c4de,
21347   lightyellow: 0xffffe0,
21348   lime: 0x00ff00,
21349   limegreen: 0x32cd32,
21350   linen: 0xfaf0e6,
21351   magenta: 0xff00ff,
21352   maroon: 0x800000,
21353   mediumaquamarine: 0x66cdaa,
21354   mediumblue: 0x0000cd,
21355   mediumorchid: 0xba55d3,
21356   mediumpurple: 0x9370db,
21357   mediumseagreen: 0x3cb371,
21358   mediumslateblue: 0x7b68ee,
21359   mediumspringgreen: 0x00fa9a,
21360   mediumturquoise: 0x48d1cc,
21361   mediumvioletred: 0xc71585,
21362   midnightblue: 0x191970,
21363   mintcream: 0xf5fffa,
21364   mistyrose: 0xffe4e1,
21365   moccasin: 0xffe4b5,
21366   navajowhite: 0xffdead,
21367   navy: 0x000080,
21368   oldlace: 0xfdf5e6,
21369   olive: 0x808000,
21370   olivedrab: 0x6b8e23,
21371   orange: 0xffa500,
21372   orangered: 0xff4500,
21373   orchid: 0xda70d6,
21374   palegoldenrod: 0xeee8aa,
21375   palegreen: 0x98fb98,
21376   paleturquoise: 0xafeeee,
21377   palevioletred: 0xdb7093,
21378   papayawhip: 0xffefd5,
21379   peachpuff: 0xffdab9,
21380   peru: 0xcd853f,
21381   pink: 0xffc0cb,
21382   plum: 0xdda0dd,
21383   powderblue: 0xb0e0e6,
21384   purple: 0x800080,
21385   rebeccapurple: 0x663399,
21386   red: 0xff0000,
21387   rosybrown: 0xbc8f8f,
21388   royalblue: 0x4169e1,
21389   saddlebrown: 0x8b4513,
21390   salmon: 0xfa8072,
21391   sandybrown: 0xf4a460,
21392   seagreen: 0x2e8b57,
21393   seashell: 0xfff5ee,
21394   sienna: 0xa0522d,
21395   silver: 0xc0c0c0,
21396   skyblue: 0x87ceeb,
21397   slateblue: 0x6a5acd,
21398   slategray: 0x708090,
21399   slategrey: 0x708090,
21400   snow: 0xfffafa,
21401   springgreen: 0x00ff7f,
21402   steelblue: 0x4682b4,
21403   tan: 0xd2b48c,
21404   teal: 0x008080,
21405   thistle: 0xd8bfd8,
21406   tomato: 0xff6347,
21407   turquoise: 0x40e0d0,
21408   violet: 0xee82ee,
21409   wheat: 0xf5deb3,
21410   white: 0xffffff,
21411   whitesmoke: 0xf5f5f5,
21412   yellow: 0xffff00,
21413   yellowgreen: 0x9acd32
21414 };
21415
21416 define(Color, color, {
21417   displayable: function() {
21418     return this.rgb().displayable();
21419   },
21420   toString: function() {
21421     return this.rgb() + "";
21422   }
21423 });
21424
21425 function color(format) {
21426   var m;
21427   format = (format + "").trim().toLowerCase();
21428   return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00
21429       : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
21430       : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
21431       : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
21432       : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
21433       : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
21434       : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
21435       : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
21436       : named.hasOwnProperty(format) ? rgbn(named[format])
21437       : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
21438       : null;
21439 }
21440
21441 function rgbn(n) {
21442   return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
21443 }
21444
21445 function rgba(r, g, b, a) {
21446   if (a <= 0) r = g = b = NaN;
21447   return new Rgb(r, g, b, a);
21448 }
21449
21450 function rgbConvert(o) {
21451   if (!(o instanceof Color)) o = color(o);
21452   if (!o) return new Rgb;
21453   o = o.rgb();
21454   return new Rgb(o.r, o.g, o.b, o.opacity);
21455 }
21456
21457 function rgb(r, g, b, opacity) {
21458   return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
21459 }
21460
21461 function Rgb(r, g, b, opacity) {
21462   this.r = +r;
21463   this.g = +g;
21464   this.b = +b;
21465   this.opacity = +opacity;
21466 }
21467
21468 define(Rgb, rgb, extend(Color, {
21469   brighter: function(k) {
21470     k = k == null ? brighter : Math.pow(brighter, k);
21471     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
21472   },
21473   darker: function(k) {
21474     k = k == null ? darker : Math.pow(darker, k);
21475     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
21476   },
21477   rgb: function() {
21478     return this;
21479   },
21480   displayable: function() {
21481     return (0 <= this.r && this.r <= 255)
21482         && (0 <= this.g && this.g <= 255)
21483         && (0 <= this.b && this.b <= 255)
21484         && (0 <= this.opacity && this.opacity <= 1);
21485   },
21486   toString: function() {
21487     var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
21488     return (a === 1 ? "rgb(" : "rgba(")
21489         + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
21490         + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
21491         + Math.max(0, Math.min(255, Math.round(this.b) || 0))
21492         + (a === 1 ? ")" : ", " + a + ")");
21493   }
21494 }));
21495
21496 function hsla(h, s, l, a) {
21497   if (a <= 0) h = s = l = NaN;
21498   else if (l <= 0 || l >= 1) h = s = NaN;
21499   else if (s <= 0) h = NaN;
21500   return new Hsl(h, s, l, a);
21501 }
21502
21503 function hslConvert(o) {
21504   if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
21505   if (!(o instanceof Color)) o = color(o);
21506   if (!o) return new Hsl;
21507   if (o instanceof Hsl) return o;
21508   o = o.rgb();
21509   var r = o.r / 255,
21510       g = o.g / 255,
21511       b = o.b / 255,
21512       min = Math.min(r, g, b),
21513       max = Math.max(r, g, b),
21514       h = NaN,
21515       s = max - min,
21516       l = (max + min) / 2;
21517   if (s) {
21518     if (r === max) h = (g - b) / s + (g < b) * 6;
21519     else if (g === max) h = (b - r) / s + 2;
21520     else h = (r - g) / s + 4;
21521     s /= l < 0.5 ? max + min : 2 - max - min;
21522     h *= 60;
21523   } else {
21524     s = l > 0 && l < 1 ? 0 : h;
21525   }
21526   return new Hsl(h, s, l, o.opacity);
21527 }
21528
21529 function hsl(h, s, l, opacity) {
21530   return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
21531 }
21532
21533 function Hsl(h, s, l, opacity) {
21534   this.h = +h;
21535   this.s = +s;
21536   this.l = +l;
21537   this.opacity = +opacity;
21538 }
21539
21540 define(Hsl, hsl, extend(Color, {
21541   brighter: function(k) {
21542     k = k == null ? brighter : Math.pow(brighter, k);
21543     return new Hsl(this.h, this.s, this.l * k, this.opacity);
21544   },
21545   darker: function(k) {
21546     k = k == null ? darker : Math.pow(darker, k);
21547     return new Hsl(this.h, this.s, this.l * k, this.opacity);
21548   },
21549   rgb: function() {
21550     var h = this.h % 360 + (this.h < 0) * 360,
21551         s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
21552         l = this.l,
21553         m2 = l + (l < 0.5 ? l : 1 - l) * s,
21554         m1 = 2 * l - m2;
21555     return new Rgb(
21556       hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
21557       hsl2rgb(h, m1, m2),
21558       hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
21559       this.opacity
21560     );
21561   },
21562   displayable: function() {
21563     return (0 <= this.s && this.s <= 1 || isNaN(this.s))
21564         && (0 <= this.l && this.l <= 1)
21565         && (0 <= this.opacity && this.opacity <= 1);
21566   }
21567 }));
21568
21569 /* From FvD 13.37, CSS Color Module Level 3 */
21570 function hsl2rgb(h, m1, m2) {
21571   return (h < 60 ? m1 + (m2 - m1) * h / 60
21572       : h < 180 ? m2
21573       : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
21574       : m1) * 255;
21575 }
21576
21577 var deg2rad = Math.PI / 180;
21578 var rad2deg = 180 / Math.PI;
21579
21580 var Kn = 18;
21581 var Xn = 0.950470;
21582 var Yn = 1;
21583 var Zn = 1.088830;
21584 var t0 = 4 / 29;
21585 var t1 = 6 / 29;
21586 var t2 = 3 * t1 * t1;
21587 var t3 = t1 * t1 * t1;
21588
21589 function labConvert(o) {
21590   if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
21591   if (o instanceof Hcl) {
21592     var h = o.h * deg2rad;
21593     return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
21594   }
21595   if (!(o instanceof Rgb)) o = rgbConvert(o);
21596   var b = rgb2xyz(o.r),
21597       a = rgb2xyz(o.g),
21598       l = rgb2xyz(o.b),
21599       x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
21600       y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
21601       z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
21602   return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
21603 }
21604
21605 function lab(l, a, b, opacity) {
21606   return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
21607 }
21608
21609 function Lab(l, a, b, opacity) {
21610   this.l = +l;
21611   this.a = +a;
21612   this.b = +b;
21613   this.opacity = +opacity;
21614 }
21615
21616 define(Lab, lab, extend(Color, {
21617   brighter: function(k) {
21618     return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
21619   },
21620   darker: function(k) {
21621     return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
21622   },
21623   rgb: function() {
21624     var y = (this.l + 16) / 116,
21625         x = isNaN(this.a) ? y : y + this.a / 500,
21626         z = isNaN(this.b) ? y : y - this.b / 200;
21627     y = Yn * lab2xyz(y);
21628     x = Xn * lab2xyz(x);
21629     z = Zn * lab2xyz(z);
21630     return new Rgb(
21631       xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
21632       xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
21633       xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
21634       this.opacity
21635     );
21636   }
21637 }));
21638
21639 function xyz2lab(t) {
21640   return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
21641 }
21642
21643 function lab2xyz(t) {
21644   return t > t1 ? t * t * t : t2 * (t - t0);
21645 }
21646
21647 function xyz2rgb(x) {
21648   return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
21649 }
21650
21651 function rgb2xyz(x) {
21652   return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
21653 }
21654
21655 function hclConvert(o) {
21656   if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
21657   if (!(o instanceof Lab)) o = labConvert(o);
21658   var h = Math.atan2(o.b, o.a) * rad2deg;
21659   return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
21660 }
21661
21662 function hcl(h, c, l, opacity) {
21663   return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
21664 }
21665
21666 function Hcl(h, c, l, opacity) {
21667   this.h = +h;
21668   this.c = +c;
21669   this.l = +l;
21670   this.opacity = +opacity;
21671 }
21672
21673 define(Hcl, hcl, extend(Color, {
21674   brighter: function(k) {
21675     return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
21676   },
21677   darker: function(k) {
21678     return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
21679   },
21680   rgb: function() {
21681     return labConvert(this).rgb();
21682   }
21683 }));
21684
21685 var A = -0.14861;
21686 var B = +1.78277;
21687 var C = -0.29227;
21688 var D = -0.90649;
21689 var E = +1.97294;
21690 var ED = E * D;
21691 var EB = E * B;
21692 var BC_DA = B * C - D * A;
21693
21694 function cubehelixConvert(o) {
21695   if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
21696   if (!(o instanceof Rgb)) o = rgbConvert(o);
21697   var r = o.r / 255,
21698       g = o.g / 255,
21699       b = o.b / 255,
21700       l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
21701       bl = b - l,
21702       k = (E * (g - l) - C * bl) / D,
21703       s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
21704       h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
21705   return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
21706 }
21707
21708 function cubehelix(h, s, l, opacity) {
21709   return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
21710 }
21711
21712 function Cubehelix(h, s, l, opacity) {
21713   this.h = +h;
21714   this.s = +s;
21715   this.l = +l;
21716   this.opacity = +opacity;
21717 }
21718
21719 define(Cubehelix, cubehelix, extend(Color, {
21720   brighter: function(k) {
21721     k = k == null ? brighter : Math.pow(brighter, k);
21722     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
21723   },
21724   darker: function(k) {
21725     k = k == null ? darker : Math.pow(darker, k);
21726     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
21727   },
21728   rgb: function() {
21729     var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
21730         l = +this.l,
21731         a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
21732         cosh = Math.cos(h),
21733         sinh = Math.sin(h);
21734     return new Rgb(
21735       255 * (l + a * (A * cosh + B * sinh)),
21736       255 * (l + a * (C * cosh + D * sinh)),
21737       255 * (l + a * (E * cosh)),
21738       this.opacity
21739     );
21740   }
21741 }));
21742
21743 function basis(t1, v0, v1, v2, v3) {
21744   var t2 = t1 * t1, t3 = t2 * t1;
21745   return ((1 - 3 * t1 + 3 * t2 - t3) * v0
21746       + (4 - 6 * t2 + 3 * t3) * v1
21747       + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
21748       + t3 * v3) / 6;
21749 }
21750
21751 var basis$1 = function(values) {
21752   var n = values.length - 1;
21753   return function(t) {
21754     var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
21755         v1 = values[i],
21756         v2 = values[i + 1],
21757         v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
21758         v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
21759     return basis((t - i / n) * n, v0, v1, v2, v3);
21760   };
21761 };
21762
21763 var basisClosed = function(values) {
21764   var n = values.length;
21765   return function(t) {
21766     var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
21767         v0 = values[(i + n - 1) % n],
21768         v1 = values[i % n],
21769         v2 = values[(i + 1) % n],
21770         v3 = values[(i + 2) % n];
21771     return basis((t - i / n) * n, v0, v1, v2, v3);
21772   };
21773 };
21774
21775 var constant$3 = function(x) {
21776   return function() {
21777     return x;
21778   };
21779 };
21780
21781 function linear(a, d) {
21782   return function(t) {
21783     return a + t * d;
21784   };
21785 }
21786
21787 function exponential(a, b, y) {
21788   return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
21789     return Math.pow(a + t * b, y);
21790   };
21791 }
21792
21793 function hue(a, b) {
21794   var d = b - a;
21795   return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$3(isNaN(a) ? b : a);
21796 }
21797
21798 function gamma(y) {
21799   return (y = +y) === 1 ? nogamma : function(a, b) {
21800     return b - a ? exponential(a, b, y) : constant$3(isNaN(a) ? b : a);
21801   };
21802 }
21803
21804 function nogamma(a, b) {
21805   var d = b - a;
21806   return d ? linear(a, d) : constant$3(isNaN(a) ? b : a);
21807 }
21808
21809 var interpolateRgb = ((function rgbGamma(y) {
21810   var color$$1 = gamma(y);
21811
21812   function rgb$$1(start, end) {
21813     var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r),
21814         g = color$$1(start.g, end.g),
21815         b = color$$1(start.b, end.b),
21816         opacity = nogamma(start.opacity, end.opacity);
21817     return function(t) {
21818       start.r = r(t);
21819       start.g = g(t);
21820       start.b = b(t);
21821       start.opacity = opacity(t);
21822       return start + "";
21823     };
21824   }
21825
21826   rgb$$1.gamma = rgbGamma;
21827
21828   return rgb$$1;
21829 }))(1);
21830
21831 function rgbSpline(spline) {
21832   return function(colors) {
21833     var n = colors.length,
21834         r = new Array(n),
21835         g = new Array(n),
21836         b = new Array(n),
21837         i, color$$1;
21838     for (i = 0; i < n; ++i) {
21839       color$$1 = rgb(colors[i]);
21840       r[i] = color$$1.r || 0;
21841       g[i] = color$$1.g || 0;
21842       b[i] = color$$1.b || 0;
21843     }
21844     r = spline(r);
21845     g = spline(g);
21846     b = spline(b);
21847     color$$1.opacity = 1;
21848     return function(t) {
21849       color$$1.r = r(t);
21850       color$$1.g = g(t);
21851       color$$1.b = b(t);
21852       return color$$1 + "";
21853     };
21854   };
21855 }
21856
21857 var rgbBasis = rgbSpline(basis$1);
21858 var rgbBasisClosed = rgbSpline(basisClosed);
21859
21860 var array$1 = function(a, b) {
21861   var nb = b ? b.length : 0,
21862       na = a ? Math.min(nb, a.length) : 0,
21863       x = new Array(nb),
21864       c = new Array(nb),
21865       i;
21866
21867   for (i = 0; i < na; ++i) x[i] = interpolateValue(a[i], b[i]);
21868   for (; i < nb; ++i) c[i] = b[i];
21869
21870   return function(t) {
21871     for (i = 0; i < na; ++i) c[i] = x[i](t);
21872     return c;
21873   };
21874 };
21875
21876 var date = function(a, b) {
21877   var d = new Date;
21878   return a = +a, b -= a, function(t) {
21879     return d.setTime(a + b * t), d;
21880   };
21881 };
21882
21883 var reinterpolate = function(a, b) {
21884   return a = +a, b -= a, function(t) {
21885     return a + b * t;
21886   };
21887 };
21888
21889 var object = function(a, b) {
21890   var i = {},
21891       c = {},
21892       k;
21893
21894   if (a === null || typeof a !== "object") a = {};
21895   if (b === null || typeof b !== "object") b = {};
21896
21897   for (k in b) {
21898     if (k in a) {
21899       i[k] = interpolateValue(a[k], b[k]);
21900     } else {
21901       c[k] = b[k];
21902     }
21903   }
21904
21905   return function(t) {
21906     for (k in i) c[k] = i[k](t);
21907     return c;
21908   };
21909 };
21910
21911 var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
21912 var reB = new RegExp(reA.source, "g");
21913
21914 function zero(b) {
21915   return function() {
21916     return b;
21917   };
21918 }
21919
21920 function one(b) {
21921   return function(t) {
21922     return b(t) + "";
21923   };
21924 }
21925
21926 var interpolateString = function(a, b) {
21927   var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
21928       am, // current match in a
21929       bm, // current match in b
21930       bs, // string preceding current number in b, if any
21931       i = -1, // index in s
21932       s = [], // string constants and placeholders
21933       q = []; // number interpolators
21934
21935   // Coerce inputs to strings.
21936   a = a + "", b = b + "";
21937
21938   // Interpolate pairs of numbers in a & b.
21939   while ((am = reA.exec(a))
21940       && (bm = reB.exec(b))) {
21941     if ((bs = bm.index) > bi) { // a string precedes the next number in b
21942       bs = b.slice(bi, bs);
21943       if (s[i]) s[i] += bs; // coalesce with previous string
21944       else s[++i] = bs;
21945     }
21946     if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
21947       if (s[i]) s[i] += bm; // coalesce with previous string
21948       else s[++i] = bm;
21949     } else { // interpolate non-matching numbers
21950       s[++i] = null;
21951       q.push({i: i, x: reinterpolate(am, bm)});
21952     }
21953     bi = reB.lastIndex;
21954   }
21955
21956   // Add remains of b.
21957   if (bi < b.length) {
21958     bs = b.slice(bi);
21959     if (s[i]) s[i] += bs; // coalesce with previous string
21960     else s[++i] = bs;
21961   }
21962
21963   // Special optimization for only a single match.
21964   // Otherwise, interpolate each of the numbers and rejoin the string.
21965   return s.length < 2 ? (q[0]
21966       ? one(q[0].x)
21967       : zero(b))
21968       : (b = q.length, function(t) {
21969           for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
21970           return s.join("");
21971         });
21972 };
21973
21974 var interpolateValue = function(a, b) {
21975   var t = typeof b, c;
21976   return b == null || t === "boolean" ? constant$3(b)
21977       : (t === "number" ? reinterpolate
21978       : t === "string" ? ((c = color(b)) ? (b = c, interpolateRgb) : interpolateString)
21979       : b instanceof color ? interpolateRgb
21980       : b instanceof Date ? date
21981       : Array.isArray(b) ? array$1
21982       : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
21983       : reinterpolate)(a, b);
21984 };
21985
21986 var interpolateRound = function(a, b) {
21987   return a = +a, b -= a, function(t) {
21988     return Math.round(a + b * t);
21989   };
21990 };
21991
21992 var degrees = 180 / Math.PI;
21993
21994 var identity$2 = {
21995   translateX: 0,
21996   translateY: 0,
21997   rotate: 0,
21998   skewX: 0,
21999   scaleX: 1,
22000   scaleY: 1
22001 };
22002
22003 var decompose = function(a, b, c, d, e, f) {
22004   var scaleX, scaleY, skewX;
22005   if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
22006   if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
22007   if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
22008   if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
22009   return {
22010     translateX: e,
22011     translateY: f,
22012     rotate: Math.atan2(b, a) * degrees,
22013     skewX: Math.atan(skewX) * degrees,
22014     scaleX: scaleX,
22015     scaleY: scaleY
22016   };
22017 };
22018
22019 var cssNode;
22020 var cssRoot;
22021 var cssView;
22022 var svgNode;
22023
22024 function parseCss(value) {
22025   if (value === "none") return identity$2;
22026   if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
22027   cssNode.style.transform = value;
22028   value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
22029   cssRoot.removeChild(cssNode);
22030   value = value.slice(7, -1).split(",");
22031   return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);
22032 }
22033
22034 function parseSvg(value) {
22035   if (value == null) return identity$2;
22036   if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
22037   svgNode.setAttribute("transform", value);
22038   if (!(value = svgNode.transform.baseVal.consolidate())) return identity$2;
22039   value = value.matrix;
22040   return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
22041 }
22042
22043 function interpolateTransform(parse, pxComma, pxParen, degParen) {
22044
22045   function pop(s) {
22046     return s.length ? s.pop() + " " : "";
22047   }
22048
22049   function translate(xa, ya, xb, yb, s, q) {
22050     if (xa !== xb || ya !== yb) {
22051       var i = s.push("translate(", null, pxComma, null, pxParen);
22052       q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)});
22053     } else if (xb || yb) {
22054       s.push("translate(" + xb + pxComma + yb + pxParen);
22055     }
22056   }
22057
22058   function rotate(a, b, s, q) {
22059     if (a !== b) {
22060       if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
22061       q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: reinterpolate(a, b)});
22062     } else if (b) {
22063       s.push(pop(s) + "rotate(" + b + degParen);
22064     }
22065   }
22066
22067   function skewX(a, b, s, q) {
22068     if (a !== b) {
22069       q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: reinterpolate(a, b)});
22070     } else if (b) {
22071       s.push(pop(s) + "skewX(" + b + degParen);
22072     }
22073   }
22074
22075   function scale(xa, ya, xb, yb, s, q) {
22076     if (xa !== xb || ya !== yb) {
22077       var i = s.push(pop(s) + "scale(", null, ",", null, ")");
22078       q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)});
22079     } else if (xb !== 1 || yb !== 1) {
22080       s.push(pop(s) + "scale(" + xb + "," + yb + ")");
22081     }
22082   }
22083
22084   return function(a, b) {
22085     var s = [], // string constants and placeholders
22086         q = []; // number interpolators
22087     a = parse(a), b = parse(b);
22088     translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
22089     rotate(a.rotate, b.rotate, s, q);
22090     skewX(a.skewX, b.skewX, s, q);
22091     scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
22092     a = b = null; // gc
22093     return function(t) {
22094       var i = -1, n = q.length, o;
22095       while (++i < n) s[(o = q[i]).i] = o.x(t);
22096       return s.join("");
22097     };
22098   };
22099 }
22100
22101 var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
22102 var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
22103
22104 var rho = Math.SQRT2;
22105 var rho2 = 2;
22106 var rho4 = 4;
22107 var epsilon2 = 1e-12;
22108
22109 function cosh(x) {
22110   return ((x = Math.exp(x)) + 1 / x) / 2;
22111 }
22112
22113 function sinh(x) {
22114   return ((x = Math.exp(x)) - 1 / x) / 2;
22115 }
22116
22117 function tanh(x) {
22118   return ((x = Math.exp(2 * x)) - 1) / (x + 1);
22119 }
22120
22121 // p0 = [ux0, uy0, w0]
22122 // p1 = [ux1, uy1, w1]
22123 var interpolateZoom = function(p0, p1) {
22124   var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
22125       ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
22126       dx = ux1 - ux0,
22127       dy = uy1 - uy0,
22128       d2 = dx * dx + dy * dy,
22129       i,
22130       S;
22131
22132   // Special case for u0 ≅ u1.
22133   if (d2 < epsilon2) {
22134     S = Math.log(w1 / w0) / rho;
22135     i = function(t) {
22136       return [
22137         ux0 + t * dx,
22138         uy0 + t * dy,
22139         w0 * Math.exp(rho * t * S)
22140       ];
22141     };
22142   }
22143
22144   // General case.
22145   else {
22146     var d1 = Math.sqrt(d2),
22147         b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
22148         b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
22149         r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
22150         r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
22151     S = (r1 - r0) / rho;
22152     i = function(t) {
22153       var s = t * S,
22154           coshr0 = cosh(r0),
22155           u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
22156       return [
22157         ux0 + u * dx,
22158         uy0 + u * dy,
22159         w0 * coshr0 / cosh(rho * s + r0)
22160       ];
22161     };
22162   }
22163
22164   i.duration = S * 1000;
22165
22166   return i;
22167 };
22168
22169 function hsl$1(hue$$1) {
22170   return function(start, end) {
22171     var h = hue$$1((start = hsl(start)).h, (end = hsl(end)).h),
22172         s = nogamma(start.s, end.s),
22173         l = nogamma(start.l, end.l),
22174         opacity = nogamma(start.opacity, end.opacity);
22175     return function(t) {
22176       start.h = h(t);
22177       start.s = s(t);
22178       start.l = l(t);
22179       start.opacity = opacity(t);
22180       return start + "";
22181     };
22182   }
22183 }
22184
22185 var hsl$2 = hsl$1(hue);
22186 var hslLong = hsl$1(nogamma);
22187
22188 function lab$1(start, end) {
22189   var l = nogamma((start = lab(start)).l, (end = lab(end)).l),
22190       a = nogamma(start.a, end.a),
22191       b = nogamma(start.b, end.b),
22192       opacity = nogamma(start.opacity, end.opacity);
22193   return function(t) {
22194     start.l = l(t);
22195     start.a = a(t);
22196     start.b = b(t);
22197     start.opacity = opacity(t);
22198     return start + "";
22199   };
22200 }
22201
22202 function hcl$1(hue$$1) {
22203   return function(start, end) {
22204     var h = hue$$1((start = hcl(start)).h, (end = hcl(end)).h),
22205         c = nogamma(start.c, end.c),
22206         l = nogamma(start.l, end.l),
22207         opacity = nogamma(start.opacity, end.opacity);
22208     return function(t) {
22209       start.h = h(t);
22210       start.c = c(t);
22211       start.l = l(t);
22212       start.opacity = opacity(t);
22213       return start + "";
22214     };
22215   }
22216 }
22217
22218 var hcl$2 = hcl$1(hue);
22219 var hclLong = hcl$1(nogamma);
22220
22221 function cubehelix$1(hue$$1) {
22222   return (function cubehelixGamma(y) {
22223     y = +y;
22224
22225     function cubehelix$$1(start, end) {
22226       var h = hue$$1((start = cubehelix(start)).h, (end = cubehelix(end)).h),
22227           s = nogamma(start.s, end.s),
22228           l = nogamma(start.l, end.l),
22229           opacity = nogamma(start.opacity, end.opacity);
22230       return function(t) {
22231         start.h = h(t);
22232         start.s = s(t);
22233         start.l = l(Math.pow(t, y));
22234         start.opacity = opacity(t);
22235         return start + "";
22236       };
22237     }
22238
22239     cubehelix$$1.gamma = cubehelixGamma;
22240
22241     return cubehelix$$1;
22242   })(1);
22243 }
22244
22245 var cubehelix$2 = cubehelix$1(hue);
22246 var cubehelixLong = cubehelix$1(nogamma);
22247
22248 var quantize = function(interpolator, n) {
22249   var samples = new Array(n);
22250   for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
22251   return samples;
22252 };
22253
22254 var frame = 0;
22255 var timeout = 0;
22256 var interval = 0;
22257 var pokeDelay = 1000;
22258 var taskHead;
22259 var taskTail;
22260 var clockLast = 0;
22261 var clockNow = 0;
22262 var clockSkew = 0;
22263 var clock = typeof performance === "object" && performance.now ? performance : Date;
22264 var setFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : function(f) { setTimeout(f, 17); };
22265
22266 function now() {
22267   return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
22268 }
22269
22270 function clearNow() {
22271   clockNow = 0;
22272 }
22273
22274 function Timer() {
22275   this._call =
22276   this._time =
22277   this._next = null;
22278 }
22279
22280 Timer.prototype = timer.prototype = {
22281   constructor: Timer,
22282   restart: function(callback, delay, time) {
22283     if (typeof callback !== "function") throw new TypeError("callback is not a function");
22284     time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
22285     if (!this._next && taskTail !== this) {
22286       if (taskTail) taskTail._next = this;
22287       else taskHead = this;
22288       taskTail = this;
22289     }
22290     this._call = callback;
22291     this._time = time;
22292     sleep();
22293   },
22294   stop: function() {
22295     if (this._call) {
22296       this._call = null;
22297       this._time = Infinity;
22298       sleep();
22299     }
22300   }
22301 };
22302
22303 function timer(callback, delay, time) {
22304   var t = new Timer;
22305   t.restart(callback, delay, time);
22306   return t;
22307 }
22308
22309 function timerFlush() {
22310   now(); // Get the current time, if not already set.
22311   ++frame; // Pretend we’ve set an alarm, if we haven’t already.
22312   var t = taskHead, e;
22313   while (t) {
22314     if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
22315     t = t._next;
22316   }
22317   --frame;
22318 }
22319
22320 function wake() {
22321   clockNow = (clockLast = clock.now()) + clockSkew;
22322   frame = timeout = 0;
22323   try {
22324     timerFlush();
22325   } finally {
22326     frame = 0;
22327     nap();
22328     clockNow = 0;
22329   }
22330 }
22331
22332 function poke() {
22333   var now = clock.now(), delay = now - clockLast;
22334   if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
22335 }
22336
22337 function nap() {
22338   var t0, t1 = taskHead, t2, time = Infinity;
22339   while (t1) {
22340     if (t1._call) {
22341       if (time > t1._time) time = t1._time;
22342       t0 = t1, t1 = t1._next;
22343     } else {
22344       t2 = t1._next, t1._next = null;
22345       t1 = t0 ? t0._next = t2 : taskHead = t2;
22346     }
22347   }
22348   taskTail = t0;
22349   sleep(time);
22350 }
22351
22352 function sleep(time) {
22353   if (frame) return; // Soonest alarm already set, or will be.
22354   if (timeout) timeout = clearTimeout(timeout);
22355   var delay = time - clockNow;
22356   if (delay > 24) {
22357     if (time < Infinity) timeout = setTimeout(wake, delay);
22358     if (interval) interval = clearInterval(interval);
22359   } else {
22360     if (!interval) clockLast = clockNow, interval = setInterval(poke, pokeDelay);
22361     frame = 1, setFrame(wake);
22362   }
22363 }
22364
22365 var timeout$1 = function(callback, delay, time) {
22366   var t = new Timer;
22367   delay = delay == null ? 0 : +delay;
22368   t.restart(function(elapsed) {
22369     t.stop();
22370     callback(elapsed + delay);
22371   }, delay, time);
22372   return t;
22373 };
22374
22375 var interval$1 = function(callback, delay, time) {
22376   var t = new Timer, total = delay;
22377   if (delay == null) return t.restart(callback, delay, time), t;
22378   delay = +delay, time = time == null ? now() : +time;
22379   t.restart(function tick(elapsed) {
22380     elapsed += total;
22381     t.restart(tick, total += delay, time);
22382     callback(elapsed);
22383   }, delay, time);
22384   return t;
22385 };
22386
22387 var emptyOn = dispatch("start", "end", "interrupt");
22388 var emptyTween = [];
22389
22390 var CREATED = 0;
22391 var SCHEDULED = 1;
22392 var STARTING = 2;
22393 var STARTED = 3;
22394 var RUNNING = 4;
22395 var ENDING = 5;
22396 var ENDED = 6;
22397
22398 var schedule = function(node, name, id, index, group, timing) {
22399   var schedules = node.__transition;
22400   if (!schedules) node.__transition = {};
22401   else if (id in schedules) return;
22402   create(node, id, {
22403     name: name,
22404     index: index, // For context during callback.
22405     group: group, // For context during callback.
22406     on: emptyOn,
22407     tween: emptyTween,
22408     time: timing.time,
22409     delay: timing.delay,
22410     duration: timing.duration,
22411     ease: timing.ease,
22412     timer: null,
22413     state: CREATED
22414   });
22415 };
22416
22417 function init(node, id) {
22418   var schedule = node.__transition;
22419   if (!schedule || !(schedule = schedule[id]) || schedule.state > CREATED) throw new Error("too late");
22420   return schedule;
22421 }
22422
22423 function set$1(node, id) {
22424   var schedule = node.__transition;
22425   if (!schedule || !(schedule = schedule[id]) || schedule.state > STARTING) throw new Error("too late");
22426   return schedule;
22427 }
22428
22429 function get$1(node, id) {
22430   var schedule = node.__transition;
22431   if (!schedule || !(schedule = schedule[id])) throw new Error("too late");
22432   return schedule;
22433 }
22434
22435 function create(node, id, self) {
22436   var schedules = node.__transition,
22437       tween;
22438
22439   // Initialize the self timer when the transition is created.
22440   // Note the actual delay is not known until the first callback!
22441   schedules[id] = self;
22442   self.timer = timer(schedule, 0, self.time);
22443
22444   function schedule(elapsed) {
22445     self.state = SCHEDULED;
22446     self.timer.restart(start, self.delay, self.time);
22447
22448     // If the elapsed delay is less than our first sleep, start immediately.
22449     if (self.delay <= elapsed) start(elapsed - self.delay);
22450   }
22451
22452   function start(elapsed) {
22453     var i, j, n, o;
22454
22455     // If the state is not SCHEDULED, then we previously errored on start.
22456     if (self.state !== SCHEDULED) return stop();
22457
22458     for (i in schedules) {
22459       o = schedules[i];
22460       if (o.name !== self.name) continue;
22461
22462       // While this element already has a starting transition during this frame,
22463       // defer starting an interrupting transition until that transition has a
22464       // chance to tick (and possibly end); see d3/d3-transition#54!
22465       if (o.state === STARTED) return timeout$1(start);
22466
22467       // Interrupt the active transition, if any.
22468       // Dispatch the interrupt event.
22469       if (o.state === RUNNING) {
22470         o.state = ENDED;
22471         o.timer.stop();
22472         o.on.call("interrupt", node, node.__data__, o.index, o.group);
22473         delete schedules[i];
22474       }
22475
22476       // Cancel any pre-empted transitions. No interrupt event is dispatched
22477       // because the cancelled transitions never started. Note that this also
22478       // removes this transition from the pending list!
22479       else if (+i < id) {
22480         o.state = ENDED;
22481         o.timer.stop();
22482         delete schedules[i];
22483       }
22484     }
22485
22486     // Defer the first tick to end of the current frame; see d3/d3#1576.
22487     // Note the transition may be canceled after start and before the first tick!
22488     // Note this must be scheduled before the start event; see d3/d3-transition#16!
22489     // Assuming this is successful, subsequent callbacks go straight to tick.
22490     timeout$1(function() {
22491       if (self.state === STARTED) {
22492         self.state = RUNNING;
22493         self.timer.restart(tick, self.delay, self.time);
22494         tick(elapsed);
22495       }
22496     });
22497
22498     // Dispatch the start event.
22499     // Note this must be done before the tween are initialized.
22500     self.state = STARTING;
22501     self.on.call("start", node, node.__data__, self.index, self.group);
22502     if (self.state !== STARTING) return; // interrupted
22503     self.state = STARTED;
22504
22505     // Initialize the tween, deleting null tween.
22506     tween = new Array(n = self.tween.length);
22507     for (i = 0, j = -1; i < n; ++i) {
22508       if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
22509         tween[++j] = o;
22510       }
22511     }
22512     tween.length = j + 1;
22513   }
22514
22515   function tick(elapsed) {
22516     var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
22517         i = -1,
22518         n = tween.length;
22519
22520     while (++i < n) {
22521       tween[i].call(null, t);
22522     }
22523
22524     // Dispatch the end event.
22525     if (self.state === ENDING) {
22526       self.on.call("end", node, node.__data__, self.index, self.group);
22527       stop();
22528     }
22529   }
22530
22531   function stop() {
22532     self.state = ENDED;
22533     self.timer.stop();
22534     delete schedules[id];
22535     for (var i in schedules) return; // eslint-disable-line no-unused-vars
22536     delete node.__transition;
22537   }
22538 }
22539
22540 var interrupt = function(node, name) {
22541   var schedules = node.__transition,
22542       schedule$$1,
22543       active,
22544       empty = true,
22545       i;
22546
22547   if (!schedules) return;
22548
22549   name = name == null ? null : name + "";
22550
22551   for (i in schedules) {
22552     if ((schedule$$1 = schedules[i]).name !== name) { empty = false; continue; }
22553     active = schedule$$1.state > STARTING && schedule$$1.state < ENDING;
22554     schedule$$1.state = ENDED;
22555     schedule$$1.timer.stop();
22556     if (active) schedule$$1.on.call("interrupt", node, node.__data__, schedule$$1.index, schedule$$1.group);
22557     delete schedules[i];
22558   }
22559
22560   if (empty) delete node.__transition;
22561 };
22562
22563 var selection_interrupt = function(name) {
22564   return this.each(function() {
22565     interrupt(this, name);
22566   });
22567 };
22568
22569 function tweenRemove(id, name) {
22570   var tween0, tween1;
22571   return function() {
22572     var schedule$$1 = set$1(this, id),
22573         tween = schedule$$1.tween;
22574
22575     // If this node shared tween with the previous node,
22576     // just assign the updated shared tween and we’re done!
22577     // Otherwise, copy-on-write.
22578     if (tween !== tween0) {
22579       tween1 = tween0 = tween;
22580       for (var i = 0, n = tween1.length; i < n; ++i) {
22581         if (tween1[i].name === name) {
22582           tween1 = tween1.slice();
22583           tween1.splice(i, 1);
22584           break;
22585         }
22586       }
22587     }
22588
22589     schedule$$1.tween = tween1;
22590   };
22591 }
22592
22593 function tweenFunction(id, name, value) {
22594   var tween0, tween1;
22595   if (typeof value !== "function") throw new Error;
22596   return function() {
22597     var schedule$$1 = set$1(this, id),
22598         tween = schedule$$1.tween;
22599
22600     // If this node shared tween with the previous node,
22601     // just assign the updated shared tween and we’re done!
22602     // Otherwise, copy-on-write.
22603     if (tween !== tween0) {
22604       tween1 = (tween0 = tween).slice();
22605       for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) {
22606         if (tween1[i].name === name) {
22607           tween1[i] = t;
22608           break;
22609         }
22610       }
22611       if (i === n) tween1.push(t);
22612     }
22613
22614     schedule$$1.tween = tween1;
22615   };
22616 }
22617
22618 var transition_tween = function(name, value) {
22619   var id = this._id;
22620
22621   name += "";
22622
22623   if (arguments.length < 2) {
22624     var tween = get$1(this.node(), id).tween;
22625     for (var i = 0, n = tween.length, t; i < n; ++i) {
22626       if ((t = tween[i]).name === name) {
22627         return t.value;
22628       }
22629     }
22630     return null;
22631   }
22632
22633   return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
22634 };
22635
22636 function tweenValue(transition, name, value) {
22637   var id = transition._id;
22638
22639   transition.each(function() {
22640     var schedule$$1 = set$1(this, id);
22641     (schedule$$1.value || (schedule$$1.value = {}))[name] = value.apply(this, arguments);
22642   });
22643
22644   return function(node) {
22645     return get$1(node, id).value[name];
22646   };
22647 }
22648
22649 var interpolate = function(a, b) {
22650   var c;
22651   return (typeof b === "number" ? reinterpolate
22652       : b instanceof color ? interpolateRgb
22653       : (c = color(b)) ? (b = c, interpolateRgb)
22654       : interpolateString)(a, b);
22655 };
22656
22657 function attrRemove$1(name) {
22658   return function() {
22659     this.removeAttribute(name);
22660   };
22661 }
22662
22663 function attrRemoveNS$1(fullname) {
22664   return function() {
22665     this.removeAttributeNS(fullname.space, fullname.local);
22666   };
22667 }
22668
22669 function attrConstant$1(name, interpolate$$1, value1) {
22670   var value00,
22671       interpolate0;
22672   return function() {
22673     var value0 = this.getAttribute(name);
22674     return value0 === value1 ? null
22675         : value0 === value00 ? interpolate0
22676         : interpolate0 = interpolate$$1(value00 = value0, value1);
22677   };
22678 }
22679
22680 function attrConstantNS$1(fullname, interpolate$$1, value1) {
22681   var value00,
22682       interpolate0;
22683   return function() {
22684     var value0 = this.getAttributeNS(fullname.space, fullname.local);
22685     return value0 === value1 ? null
22686         : value0 === value00 ? interpolate0
22687         : interpolate0 = interpolate$$1(value00 = value0, value1);
22688   };
22689 }
22690
22691 function attrFunction$1(name, interpolate$$1, value) {
22692   var value00,
22693       value10,
22694       interpolate0;
22695   return function() {
22696     var value0, value1 = value(this);
22697     if (value1 == null) return void this.removeAttribute(name);
22698     value0 = this.getAttribute(name);
22699     return value0 === value1 ? null
22700         : value0 === value00 && value1 === value10 ? interpolate0
22701         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22702   };
22703 }
22704
22705 function attrFunctionNS$1(fullname, interpolate$$1, value) {
22706   var value00,
22707       value10,
22708       interpolate0;
22709   return function() {
22710     var value0, value1 = value(this);
22711     if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
22712     value0 = this.getAttributeNS(fullname.space, fullname.local);
22713     return value0 === value1 ? null
22714         : value0 === value00 && value1 === value10 ? interpolate0
22715         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22716   };
22717 }
22718
22719 var transition_attr = function(name, value) {
22720   var fullname = namespace(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate;
22721   return this.attrTween(name, typeof value === "function"
22722       ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value))
22723       : value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname)
22724       : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value + ""));
22725 };
22726
22727 function attrTweenNS(fullname, value) {
22728   function tween() {
22729     var node = this, i = value.apply(node, arguments);
22730     return i && function(t) {
22731       node.setAttributeNS(fullname.space, fullname.local, i(t));
22732     };
22733   }
22734   tween._value = value;
22735   return tween;
22736 }
22737
22738 function attrTween(name, value) {
22739   function tween() {
22740     var node = this, i = value.apply(node, arguments);
22741     return i && function(t) {
22742       node.setAttribute(name, i(t));
22743     };
22744   }
22745   tween._value = value;
22746   return tween;
22747 }
22748
22749 var transition_attrTween = function(name, value) {
22750   var key = "attr." + name;
22751   if (arguments.length < 2) return (key = this.tween(key)) && key._value;
22752   if (value == null) return this.tween(key, null);
22753   if (typeof value !== "function") throw new Error;
22754   var fullname = namespace(name);
22755   return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
22756 };
22757
22758 function delayFunction(id, value) {
22759   return function() {
22760     init(this, id).delay = +value.apply(this, arguments);
22761   };
22762 }
22763
22764 function delayConstant(id, value) {
22765   return value = +value, function() {
22766     init(this, id).delay = value;
22767   };
22768 }
22769
22770 var transition_delay = function(value) {
22771   var id = this._id;
22772
22773   return arguments.length
22774       ? this.each((typeof value === "function"
22775           ? delayFunction
22776           : delayConstant)(id, value))
22777       : get$1(this.node(), id).delay;
22778 };
22779
22780 function durationFunction(id, value) {
22781   return function() {
22782     set$1(this, id).duration = +value.apply(this, arguments);
22783   };
22784 }
22785
22786 function durationConstant(id, value) {
22787   return value = +value, function() {
22788     set$1(this, id).duration = value;
22789   };
22790 }
22791
22792 var transition_duration = function(value) {
22793   var id = this._id;
22794
22795   return arguments.length
22796       ? this.each((typeof value === "function"
22797           ? durationFunction
22798           : durationConstant)(id, value))
22799       : get$1(this.node(), id).duration;
22800 };
22801
22802 function easeConstant(id, value) {
22803   if (typeof value !== "function") throw new Error;
22804   return function() {
22805     set$1(this, id).ease = value;
22806   };
22807 }
22808
22809 var transition_ease = function(value) {
22810   var id = this._id;
22811
22812   return arguments.length
22813       ? this.each(easeConstant(id, value))
22814       : get$1(this.node(), id).ease;
22815 };
22816
22817 var transition_filter = function(match) {
22818   if (typeof match !== "function") match = matcher$1(match);
22819
22820   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
22821     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
22822       if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
22823         subgroup.push(node);
22824       }
22825     }
22826   }
22827
22828   return new Transition(subgroups, this._parents, this._name, this._id);
22829 };
22830
22831 var transition_merge = function(transition$$1) {
22832   if (transition$$1._id !== this._id) throw new Error;
22833
22834   for (var groups0 = this._groups, groups1 = transition$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
22835     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
22836       if (node = group0[i] || group1[i]) {
22837         merge[i] = node;
22838       }
22839     }
22840   }
22841
22842   for (; j < m0; ++j) {
22843     merges[j] = groups0[j];
22844   }
22845
22846   return new Transition(merges, this._parents, this._name, this._id);
22847 };
22848
22849 function start(name) {
22850   return (name + "").trim().split(/^|\s+/).every(function(t) {
22851     var i = t.indexOf(".");
22852     if (i >= 0) t = t.slice(0, i);
22853     return !t || t === "start";
22854   });
22855 }
22856
22857 function onFunction(id, name, listener) {
22858   var on0, on1, sit = start(name) ? init : set$1;
22859   return function() {
22860     var schedule$$1 = sit(this, id),
22861         on = schedule$$1.on;
22862
22863     // If this node shared a dispatch with the previous node,
22864     // just assign the updated shared dispatch and we’re done!
22865     // Otherwise, copy-on-write.
22866     if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
22867
22868     schedule$$1.on = on1;
22869   };
22870 }
22871
22872 var transition_on = function(name, listener) {
22873   var id = this._id;
22874
22875   return arguments.length < 2
22876       ? get$1(this.node(), id).on.on(name)
22877       : this.each(onFunction(id, name, listener));
22878 };
22879
22880 function removeFunction(id) {
22881   return function() {
22882     var parent = this.parentNode;
22883     for (var i in this.__transition) if (+i !== id) return;
22884     if (parent) parent.removeChild(this);
22885   };
22886 }
22887
22888 var transition_remove = function() {
22889   return this.on("end.remove", removeFunction(this._id));
22890 };
22891
22892 var transition_select = function(select$$1) {
22893   var name = this._name,
22894       id = this._id;
22895
22896   if (typeof select$$1 !== "function") select$$1 = selector(select$$1);
22897
22898   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
22899     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
22900       if ((node = group[i]) && (subnode = select$$1.call(node, node.__data__, i, group))) {
22901         if ("__data__" in node) subnode.__data__ = node.__data__;
22902         subgroup[i] = subnode;
22903         schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
22904       }
22905     }
22906   }
22907
22908   return new Transition(subgroups, this._parents, name, id);
22909 };
22910
22911 var transition_selectAll = function(select$$1) {
22912   var name = this._name,
22913       id = this._id;
22914
22915   if (typeof select$$1 !== "function") select$$1 = selectorAll(select$$1);
22916
22917   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
22918     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
22919       if (node = group[i]) {
22920         for (var children = select$$1.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) {
22921           if (child = children[k]) {
22922             schedule(child, name, id, k, children, inherit);
22923           }
22924         }
22925         subgroups.push(children);
22926         parents.push(node);
22927       }
22928     }
22929   }
22930
22931   return new Transition(subgroups, parents, name, id);
22932 };
22933
22934 var Selection$1 = selection.prototype.constructor;
22935
22936 var transition_selection = function() {
22937   return new Selection$1(this._groups, this._parents);
22938 };
22939
22940 function styleRemove$1(name, interpolate$$1) {
22941   var value00,
22942       value10,
22943       interpolate0;
22944   return function() {
22945     var value0 = styleValue(this, name),
22946         value1 = (this.style.removeProperty(name), styleValue(this, name));
22947     return value0 === value1 ? null
22948         : value0 === value00 && value1 === value10 ? interpolate0
22949         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22950   };
22951 }
22952
22953 function styleRemoveEnd(name) {
22954   return function() {
22955     this.style.removeProperty(name);
22956   };
22957 }
22958
22959 function styleConstant$1(name, interpolate$$1, value1) {
22960   var value00,
22961       interpolate0;
22962   return function() {
22963     var value0 = styleValue(this, name);
22964     return value0 === value1 ? null
22965         : value0 === value00 ? interpolate0
22966         : interpolate0 = interpolate$$1(value00 = value0, value1);
22967   };
22968 }
22969
22970 function styleFunction$1(name, interpolate$$1, value) {
22971   var value00,
22972       value10,
22973       interpolate0;
22974   return function() {
22975     var value0 = styleValue(this, name),
22976         value1 = value(this);
22977     if (value1 == null) value1 = (this.style.removeProperty(name), styleValue(this, name));
22978     return value0 === value1 ? null
22979         : value0 === value00 && value1 === value10 ? interpolate0
22980         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22981   };
22982 }
22983
22984 var transition_style = function(name, value, priority) {
22985   var i = (name += "") === "transform" ? interpolateTransformCss : interpolate;
22986   return value == null ? this
22987           .styleTween(name, styleRemove$1(name, i))
22988           .on("end.style." + name, styleRemoveEnd(name))
22989       : this.styleTween(name, typeof value === "function"
22990           ? styleFunction$1(name, i, tweenValue(this, "style." + name, value))
22991           : styleConstant$1(name, i, value + ""), priority);
22992 };
22993
22994 function styleTween(name, value, priority) {
22995   function tween() {
22996     var node = this, i = value.apply(node, arguments);
22997     return i && function(t) {
22998       node.style.setProperty(name, i(t), priority);
22999     };
23000   }
23001   tween._value = value;
23002   return tween;
23003 }
23004
23005 var transition_styleTween = function(name, value, priority) {
23006   var key = "style." + (name += "");
23007   if (arguments.length < 2) return (key = this.tween(key)) && key._value;
23008   if (value == null) return this.tween(key, null);
23009   if (typeof value !== "function") throw new Error;
23010   return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
23011 };
23012
23013 function textConstant$1(value) {
23014   return function() {
23015     this.textContent = value;
23016   };
23017 }
23018
23019 function textFunction$1(value) {
23020   return function() {
23021     var value1 = value(this);
23022     this.textContent = value1 == null ? "" : value1;
23023   };
23024 }
23025
23026 var transition_text = function(value) {
23027   return this.tween("text", typeof value === "function"
23028       ? textFunction$1(tweenValue(this, "text", value))
23029       : textConstant$1(value == null ? "" : value + ""));
23030 };
23031
23032 var transition_transition = function() {
23033   var name = this._name,
23034       id0 = this._id,
23035       id1 = newId();
23036
23037   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
23038     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
23039       if (node = group[i]) {
23040         var inherit = get$1(node, id0);
23041         schedule(node, name, id1, i, group, {
23042           time: inherit.time + inherit.delay + inherit.duration,
23043           delay: 0,
23044           duration: inherit.duration,
23045           ease: inherit.ease
23046         });
23047       }
23048     }
23049   }
23050
23051   return new Transition(groups, this._parents, name, id1);
23052 };
23053
23054 var id = 0;
23055
23056 function Transition(groups, parents, name, id) {
23057   this._groups = groups;
23058   this._parents = parents;
23059   this._name = name;
23060   this._id = id;
23061 }
23062
23063 function transition(name) {
23064   return selection().transition(name);
23065 }
23066
23067 function newId() {
23068   return ++id;
23069 }
23070
23071 var selection_prototype = selection.prototype;
23072
23073 Transition.prototype = transition.prototype = {
23074   constructor: Transition,
23075   select: transition_select,
23076   selectAll: transition_selectAll,
23077   filter: transition_filter,
23078   merge: transition_merge,
23079   selection: transition_selection,
23080   transition: transition_transition,
23081   call: selection_prototype.call,
23082   nodes: selection_prototype.nodes,
23083   node: selection_prototype.node,
23084   size: selection_prototype.size,
23085   empty: selection_prototype.empty,
23086   each: selection_prototype.each,
23087   on: transition_on,
23088   attr: transition_attr,
23089   attrTween: transition_attrTween,
23090   style: transition_style,
23091   styleTween: transition_styleTween,
23092   text: transition_text,
23093   remove: transition_remove,
23094   tween: transition_tween,
23095   delay: transition_delay,
23096   duration: transition_duration,
23097   ease: transition_ease
23098 };
23099
23100 function linear$1(t) {
23101   return +t;
23102 }
23103
23104 function quadIn(t) {
23105   return t * t;
23106 }
23107
23108 function quadOut(t) {
23109   return t * (2 - t);
23110 }
23111
23112 function quadInOut(t) {
23113   return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
23114 }
23115
23116 function cubicIn(t) {
23117   return t * t * t;
23118 }
23119
23120 function cubicOut(t) {
23121   return --t * t * t + 1;
23122 }
23123
23124 function cubicInOut(t) {
23125   return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
23126 }
23127
23128 var exponent = 3;
23129
23130 var polyIn = (function custom(e) {
23131   e = +e;
23132
23133   function polyIn(t) {
23134     return Math.pow(t, e);
23135   }
23136
23137   polyIn.exponent = custom;
23138
23139   return polyIn;
23140 })(exponent);
23141
23142 var polyOut = (function custom(e) {
23143   e = +e;
23144
23145   function polyOut(t) {
23146     return 1 - Math.pow(1 - t, e);
23147   }
23148
23149   polyOut.exponent = custom;
23150
23151   return polyOut;
23152 })(exponent);
23153
23154 var polyInOut = (function custom(e) {
23155   e = +e;
23156
23157   function polyInOut(t) {
23158     return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
23159   }
23160
23161   polyInOut.exponent = custom;
23162
23163   return polyInOut;
23164 })(exponent);
23165
23166 var pi = Math.PI;
23167 var halfPi = pi / 2;
23168
23169 function sinIn(t) {
23170   return 1 - Math.cos(t * halfPi);
23171 }
23172
23173 function sinOut(t) {
23174   return Math.sin(t * halfPi);
23175 }
23176
23177 function sinInOut(t) {
23178   return (1 - Math.cos(pi * t)) / 2;
23179 }
23180
23181 function expIn(t) {
23182   return Math.pow(2, 10 * t - 10);
23183 }
23184
23185 function expOut(t) {
23186   return 1 - Math.pow(2, -10 * t);
23187 }
23188
23189 function expInOut(t) {
23190   return ((t *= 2) <= 1 ? Math.pow(2, 10 * t - 10) : 2 - Math.pow(2, 10 - 10 * t)) / 2;
23191 }
23192
23193 function circleIn(t) {
23194   return 1 - Math.sqrt(1 - t * t);
23195 }
23196
23197 function circleOut(t) {
23198   return Math.sqrt(1 - --t * t);
23199 }
23200
23201 function circleInOut(t) {
23202   return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
23203 }
23204
23205 var b1 = 4 / 11;
23206 var b2 = 6 / 11;
23207 var b3 = 8 / 11;
23208 var b4 = 3 / 4;
23209 var b5 = 9 / 11;
23210 var b6 = 10 / 11;
23211 var b7 = 15 / 16;
23212 var b8 = 21 / 22;
23213 var b9 = 63 / 64;
23214 var b0 = 1 / b1 / b1;
23215
23216 function bounceIn(t) {
23217   return 1 - bounceOut(1 - t);
23218 }
23219
23220 function bounceOut(t) {
23221   return (t = +t) < b1 ? b0 * t * t : t < b3 ? b0 * (t -= b2) * t + b4 : t < b6 ? b0 * (t -= b5) * t + b7 : b0 * (t -= b8) * t + b9;
23222 }
23223
23224 function bounceInOut(t) {
23225   return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
23226 }
23227
23228 var overshoot = 1.70158;
23229
23230 var backIn = (function custom(s) {
23231   s = +s;
23232
23233   function backIn(t) {
23234     return t * t * ((s + 1) * t - s);
23235   }
23236
23237   backIn.overshoot = custom;
23238
23239   return backIn;
23240 })(overshoot);
23241
23242 var backOut = (function custom(s) {
23243   s = +s;
23244
23245   function backOut(t) {
23246     return --t * t * ((s + 1) * t + s) + 1;
23247   }
23248
23249   backOut.overshoot = custom;
23250
23251   return backOut;
23252 })(overshoot);
23253
23254 var backInOut = (function custom(s) {
23255   s = +s;
23256
23257   function backInOut(t) {
23258     return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
23259   }
23260
23261   backInOut.overshoot = custom;
23262
23263   return backInOut;
23264 })(overshoot);
23265
23266 var tau = 2 * Math.PI;
23267 var amplitude = 1;
23268 var period = 0.3;
23269
23270 var elasticIn = (function custom(a, p) {
23271   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23272
23273   function elasticIn(t) {
23274     return a * Math.pow(2, 10 * --t) * Math.sin((s - t) / p);
23275   }
23276
23277   elasticIn.amplitude = function(a) { return custom(a, p * tau); };
23278   elasticIn.period = function(p) { return custom(a, p); };
23279
23280   return elasticIn;
23281 })(amplitude, period);
23282
23283 var elasticOut = (function custom(a, p) {
23284   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23285
23286   function elasticOut(t) {
23287     return 1 - a * Math.pow(2, -10 * (t = +t)) * Math.sin((t + s) / p);
23288   }
23289
23290   elasticOut.amplitude = function(a) { return custom(a, p * tau); };
23291   elasticOut.period = function(p) { return custom(a, p); };
23292
23293   return elasticOut;
23294 })(amplitude, period);
23295
23296 var elasticInOut = (function custom(a, p) {
23297   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23298
23299   function elasticInOut(t) {
23300     return ((t = t * 2 - 1) < 0
23301         ? a * Math.pow(2, 10 * t) * Math.sin((s - t) / p)
23302         : 2 - a * Math.pow(2, -10 * t) * Math.sin((s + t) / p)) / 2;
23303   }
23304
23305   elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
23306   elasticInOut.period = function(p) { return custom(a, p); };
23307
23308   return elasticInOut;
23309 })(amplitude, period);
23310
23311 var defaultTiming = {
23312   time: null, // Set on use.
23313   delay: 0,
23314   duration: 250,
23315   ease: cubicInOut
23316 };
23317
23318 function inherit(node, id) {
23319   var timing;
23320   while (!(timing = node.__transition) || !(timing = timing[id])) {
23321     if (!(node = node.parentNode)) {
23322       return defaultTiming.time = now(), defaultTiming;
23323     }
23324   }
23325   return timing;
23326 }
23327
23328 var selection_transition = function(name) {
23329   var id,
23330       timing;
23331
23332   if (name instanceof Transition) {
23333     id = name._id, name = name._name;
23334   } else {
23335     id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
23336   }
23337
23338   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
23339     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
23340       if (node = group[i]) {
23341         schedule(node, name, id, i, group, timing || inherit(node, id));
23342       }
23343     }
23344   }
23345
23346   return new Transition(groups, this._parents, name, id);
23347 };
23348
23349 selection.prototype.interrupt = selection_interrupt;
23350 selection.prototype.transition = selection_transition;
23351
23352 var root$1 = [null];
23353
23354 var active = function(node, name) {
23355   var schedules = node.__transition,
23356       schedule$$1,
23357       i;
23358
23359   if (schedules) {
23360     name = name == null ? null : name + "";
23361     for (i in schedules) {
23362       if ((schedule$$1 = schedules[i]).state > SCHEDULED && schedule$$1.name === name) {
23363         return new Transition([[node]], root$1, name, +i);
23364       }
23365     }
23366   }
23367
23368   return null;
23369 };
23370
23371 var constant$4 = function(x) {
23372   return function() {
23373     return x;
23374   };
23375 };
23376
23377 var BrushEvent = function(target, type, selection) {
23378   this.target = target;
23379   this.type = type;
23380   this.selection = selection;
23381 };
23382
23383 function nopropagation$1() {
23384   event.stopImmediatePropagation();
23385 }
23386
23387 var noevent$1 = function() {
23388   event.preventDefault();
23389   event.stopImmediatePropagation();
23390 };
23391
23392 var MODE_DRAG = {name: "drag"};
23393 var MODE_SPACE = {name: "space"};
23394 var MODE_HANDLE = {name: "handle"};
23395 var MODE_CENTER = {name: "center"};
23396
23397 var X = {
23398   name: "x",
23399   handles: ["e", "w"].map(type$2),
23400   input: function(x, e) { return x && [[x[0], e[0][1]], [x[1], e[1][1]]]; },
23401   output: function(xy) { return xy && [xy[0][0], xy[1][0]]; }
23402 };
23403
23404 var Y = {
23405   name: "y",
23406   handles: ["n", "s"].map(type$2),
23407   input: function(y, e) { return y && [[e[0][0], y[0]], [e[1][0], y[1]]]; },
23408   output: function(xy) { return xy && [xy[0][1], xy[1][1]]; }
23409 };
23410
23411 var XY = {
23412   name: "xy",
23413   handles: ["n", "e", "s", "w", "nw", "ne", "se", "sw"].map(type$2),
23414   input: function(xy) { return xy; },
23415   output: function(xy) { return xy; }
23416 };
23417
23418 var cursors = {
23419   overlay: "crosshair",
23420   selection: "move",
23421   n: "ns-resize",
23422   e: "ew-resize",
23423   s: "ns-resize",
23424   w: "ew-resize",
23425   nw: "nwse-resize",
23426   ne: "nesw-resize",
23427   se: "nwse-resize",
23428   sw: "nesw-resize"
23429 };
23430
23431 var flipX = {
23432   e: "w",
23433   w: "e",
23434   nw: "ne",
23435   ne: "nw",
23436   se: "sw",
23437   sw: "se"
23438 };
23439
23440 var flipY = {
23441   n: "s",
23442   s: "n",
23443   nw: "sw",
23444   ne: "se",
23445   se: "ne",
23446   sw: "nw"
23447 };
23448
23449 var signsX = {
23450   overlay: +1,
23451   selection: +1,
23452   n: null,
23453   e: +1,
23454   s: null,
23455   w: -1,
23456   nw: -1,
23457   ne: +1,
23458   se: +1,
23459   sw: -1
23460 };
23461
23462 var signsY = {
23463   overlay: +1,
23464   selection: +1,
23465   n: -1,
23466   e: null,
23467   s: +1,
23468   w: null,
23469   nw: -1,
23470   ne: -1,
23471   se: +1,
23472   sw: +1
23473 };
23474
23475 function type$2(t) {
23476   return {type: t};
23477 }
23478
23479 // Ignore right-click, since that should open the context menu.
23480 function defaultFilter() {
23481   return !event.button;
23482 }
23483
23484 function defaultExtent() {
23485   var svg = this.ownerSVGElement || this;
23486   return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]];
23487 }
23488
23489 // Like d3.local, but with the name “__brush” rather than auto-generated.
23490 function local$$1(node) {
23491   while (!node.__brush) if (!(node = node.parentNode)) return;
23492   return node.__brush;
23493 }
23494
23495 function empty(extent) {
23496   return extent[0][0] === extent[1][0]
23497       || extent[0][1] === extent[1][1];
23498 }
23499
23500 function brushSelection(node) {
23501   var state = node.__brush;
23502   return state ? state.dim.output(state.selection) : null;
23503 }
23504
23505 function brushX() {
23506   return brush$1(X);
23507 }
23508
23509 function brushY() {
23510   return brush$1(Y);
23511 }
23512
23513 var brush = function() {
23514   return brush$1(XY);
23515 };
23516
23517 function brush$1(dim) {
23518   var extent = defaultExtent,
23519       filter = defaultFilter,
23520       listeners = dispatch(brush, "start", "brush", "end"),
23521       handleSize = 6,
23522       touchending;
23523
23524   function brush(group) {
23525     var overlay = group
23526         .property("__brush", initialize)
23527       .selectAll(".overlay")
23528       .data([type$2("overlay")]);
23529
23530     overlay.enter().append("rect")
23531         .attr("class", "overlay")
23532         .attr("pointer-events", "all")
23533         .attr("cursor", cursors.overlay)
23534       .merge(overlay)
23535         .each(function() {
23536           var extent = local$$1(this).extent;
23537           select(this)
23538               .attr("x", extent[0][0])
23539               .attr("y", extent[0][1])
23540               .attr("width", extent[1][0] - extent[0][0])
23541               .attr("height", extent[1][1] - extent[0][1]);
23542         });
23543
23544     group.selectAll(".selection")
23545       .data([type$2("selection")])
23546       .enter().append("rect")
23547         .attr("class", "selection")
23548         .attr("cursor", cursors.selection)
23549         .attr("fill", "#777")
23550         .attr("fill-opacity", 0.3)
23551         .attr("stroke", "#fff")
23552         .attr("shape-rendering", "crispEdges");
23553
23554     var handle = group.selectAll(".handle")
23555       .data(dim.handles, function(d) { return d.type; });
23556
23557     handle.exit().remove();
23558
23559     handle.enter().append("rect")
23560         .attr("class", function(d) { return "handle handle--" + d.type; })
23561         .attr("cursor", function(d) { return cursors[d.type]; });
23562
23563     group
23564         .each(redraw)
23565         .attr("fill", "none")
23566         .attr("pointer-events", "all")
23567         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
23568         .on("mousedown.brush touchstart.brush", started);
23569   }
23570
23571   brush.move = function(group, selection) {
23572     if (group.selection) {
23573       group
23574           .on("start.brush", function() { emitter(this, arguments).beforestart().start(); })
23575           .on("interrupt.brush end.brush", function() { emitter(this, arguments).end(); })
23576           .tween("brush", function() {
23577             var that = this,
23578                 state = that.__brush,
23579                 emit = emitter(that, arguments),
23580                 selection0 = state.selection,
23581                 selection1 = dim.input(typeof selection === "function" ? selection.apply(this, arguments) : selection, state.extent),
23582                 i = interpolateValue(selection0, selection1);
23583
23584             function tween(t) {
23585               state.selection = t === 1 && empty(selection1) ? null : i(t);
23586               redraw.call(that);
23587               emit.brush();
23588             }
23589
23590             return selection0 && selection1 ? tween : tween(1);
23591           });
23592     } else {
23593       group
23594           .each(function() {
23595             var that = this,
23596                 args = arguments,
23597                 state = that.__brush,
23598                 selection1 = dim.input(typeof selection === "function" ? selection.apply(that, args) : selection, state.extent),
23599                 emit = emitter(that, args).beforestart();
23600
23601             interrupt(that);
23602             state.selection = selection1 == null || empty(selection1) ? null : selection1;
23603             redraw.call(that);
23604             emit.start().brush().end();
23605           });
23606     }
23607   };
23608
23609   function redraw() {
23610     var group = select(this),
23611         selection = local$$1(this).selection;
23612
23613     if (selection) {
23614       group.selectAll(".selection")
23615           .style("display", null)
23616           .attr("x", selection[0][0])
23617           .attr("y", selection[0][1])
23618           .attr("width", selection[1][0] - selection[0][0])
23619           .attr("height", selection[1][1] - selection[0][1]);
23620
23621       group.selectAll(".handle")
23622           .style("display", null)
23623           .attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection[1][0] - handleSize / 2 : selection[0][0] - handleSize / 2; })
23624           .attr("y", function(d) { return d.type[0] === "s" ? selection[1][1] - handleSize / 2 : selection[0][1] - handleSize / 2; })
23625           .attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection[1][0] - selection[0][0] + handleSize : handleSize; })
23626           .attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection[1][1] - selection[0][1] + handleSize : handleSize; });
23627     }
23628
23629     else {
23630       group.selectAll(".selection,.handle")
23631           .style("display", "none")
23632           .attr("x", null)
23633           .attr("y", null)
23634           .attr("width", null)
23635           .attr("height", null);
23636     }
23637   }
23638
23639   function emitter(that, args) {
23640     return that.__brush.emitter || new Emitter(that, args);
23641   }
23642
23643   function Emitter(that, args) {
23644     this.that = that;
23645     this.args = args;
23646     this.state = that.__brush;
23647     this.active = 0;
23648   }
23649
23650   Emitter.prototype = {
23651     beforestart: function() {
23652       if (++this.active === 1) this.state.emitter = this, this.starting = true;
23653       return this;
23654     },
23655     start: function() {
23656       if (this.starting) this.starting = false, this.emit("start");
23657       return this;
23658     },
23659     brush: function() {
23660       this.emit("brush");
23661       return this;
23662     },
23663     end: function() {
23664       if (--this.active === 0) delete this.state.emitter, this.emit("end");
23665       return this;
23666     },
23667     emit: function(type) {
23668       customEvent(new BrushEvent(brush, type, dim.output(this.state.selection)), listeners.apply, listeners, [type, this.that, this.args]);
23669     }
23670   };
23671
23672   function started() {
23673     if (event.touches) { if (event.changedTouches.length < event.touches.length) return noevent$1(); }
23674     else if (touchending) return;
23675     if (!filter.apply(this, arguments)) return;
23676
23677     var that = this,
23678         type = event.target.__data__.type,
23679         mode = (event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (event.altKey ? MODE_CENTER : MODE_HANDLE),
23680         signX = dim === Y ? null : signsX[type],
23681         signY = dim === X ? null : signsY[type],
23682         state = local$$1(that),
23683         extent = state.extent,
23684         selection = state.selection,
23685         W = extent[0][0], w0, w1,
23686         N = extent[0][1], n0, n1,
23687         E = extent[1][0], e0, e1,
23688         S = extent[1][1], s0, s1,
23689         dx,
23690         dy,
23691         moving,
23692         shifting = signX && signY && event.shiftKey,
23693         lockX,
23694         lockY,
23695         point0 = mouse(that),
23696         point = point0,
23697         emit = emitter(that, arguments).beforestart();
23698
23699     if (type === "overlay") {
23700       state.selection = selection = [
23701         [w0 = dim === Y ? W : point0[0], n0 = dim === X ? N : point0[1]],
23702         [e0 = dim === Y ? E : w0, s0 = dim === X ? S : n0]
23703       ];
23704     } else {
23705       w0 = selection[0][0];
23706       n0 = selection[0][1];
23707       e0 = selection[1][0];
23708       s0 = selection[1][1];
23709     }
23710
23711     w1 = w0;
23712     n1 = n0;
23713     e1 = e0;
23714     s1 = s0;
23715
23716     var group = select(that)
23717         .attr("pointer-events", "none");
23718
23719     var overlay = group.selectAll(".overlay")
23720         .attr("cursor", cursors[type]);
23721
23722     if (event.touches) {
23723       group
23724           .on("touchmove.brush", moved, true)
23725           .on("touchend.brush touchcancel.brush", ended, true);
23726     } else {
23727       var view = select(event.view)
23728           .on("keydown.brush", keydowned, true)
23729           .on("keyup.brush", keyupped, true)
23730           .on("mousemove.brush", moved, true)
23731           .on("mouseup.brush", ended, true);
23732
23733       dragDisable(event.view);
23734     }
23735
23736     nopropagation$1();
23737     interrupt(that);
23738     redraw.call(that);
23739     emit.start();
23740
23741     function moved() {
23742       var point1 = mouse(that);
23743       if (shifting && !lockX && !lockY) {
23744         if (Math.abs(point1[0] - point[0]) > Math.abs(point1[1] - point[1])) lockY = true;
23745         else lockX = true;
23746       }
23747       point = point1;
23748       moving = true;
23749       noevent$1();
23750       move();
23751     }
23752
23753     function move() {
23754       var t;
23755
23756       dx = point[0] - point0[0];
23757       dy = point[1] - point0[1];
23758
23759       switch (mode) {
23760         case MODE_SPACE:
23761         case MODE_DRAG: {
23762           if (signX) dx = Math.max(W - w0, Math.min(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx;
23763           if (signY) dy = Math.max(N - n0, Math.min(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy;
23764           break;
23765         }
23766         case MODE_HANDLE: {
23767           if (signX < 0) dx = Math.max(W - w0, Math.min(E - w0, dx)), w1 = w0 + dx, e1 = e0;
23768           else if (signX > 0) dx = Math.max(W - e0, Math.min(E - e0, dx)), w1 = w0, e1 = e0 + dx;
23769           if (signY < 0) dy = Math.max(N - n0, Math.min(S - n0, dy)), n1 = n0 + dy, s1 = s0;
23770           else if (signY > 0) dy = Math.max(N - s0, Math.min(S - s0, dy)), n1 = n0, s1 = s0 + dy;
23771           break;
23772         }
23773         case MODE_CENTER: {
23774           if (signX) w1 = Math.max(W, Math.min(E, w0 - dx * signX)), e1 = Math.max(W, Math.min(E, e0 + dx * signX));
23775           if (signY) n1 = Math.max(N, Math.min(S, n0 - dy * signY)), s1 = Math.max(N, Math.min(S, s0 + dy * signY));
23776           break;
23777         }
23778       }
23779
23780       if (e1 < w1) {
23781         signX *= -1;
23782         t = w0, w0 = e0, e0 = t;
23783         t = w1, w1 = e1, e1 = t;
23784         if (type in flipX) overlay.attr("cursor", cursors[type = flipX[type]]);
23785       }
23786
23787       if (s1 < n1) {
23788         signY *= -1;
23789         t = n0, n0 = s0, s0 = t;
23790         t = n1, n1 = s1, s1 = t;
23791         if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]);
23792       }
23793
23794       if (state.selection) selection = state.selection; // May be set by brush.move!
23795       if (lockX) w1 = selection[0][0], e1 = selection[1][0];
23796       if (lockY) n1 = selection[0][1], s1 = selection[1][1];
23797
23798       if (selection[0][0] !== w1
23799           || selection[0][1] !== n1
23800           || selection[1][0] !== e1
23801           || selection[1][1] !== s1) {
23802         state.selection = [[w1, n1], [e1, s1]];
23803         redraw.call(that);
23804         emit.brush();
23805       }
23806     }
23807
23808     function ended() {
23809       nopropagation$1();
23810       if (event.touches) {
23811         if (event.touches.length) return;
23812         if (touchending) clearTimeout(touchending);
23813         touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
23814         group.on("touchmove.brush touchend.brush touchcancel.brush", null);
23815       } else {
23816         yesdrag(event.view, moving);
23817         view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null);
23818       }
23819       group.attr("pointer-events", "all");
23820       overlay.attr("cursor", cursors.overlay);
23821       if (state.selection) selection = state.selection; // May be set by brush.move (on start)!
23822       if (empty(selection)) state.selection = null, redraw.call(that);
23823       emit.end();
23824     }
23825
23826     function keydowned() {
23827       switch (event.keyCode) {
23828         case 16: { // SHIFT
23829           shifting = signX && signY;
23830           break;
23831         }
23832         case 18: { // ALT
23833           if (mode === MODE_HANDLE) {
23834             if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
23835             if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
23836             mode = MODE_CENTER;
23837             move();
23838           }
23839           break;
23840         }
23841         case 32: { // SPACE; takes priority over ALT
23842           if (mode === MODE_HANDLE || mode === MODE_CENTER) {
23843             if (signX < 0) e0 = e1 - dx; else if (signX > 0) w0 = w1 - dx;
23844             if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy;
23845             mode = MODE_SPACE;
23846             overlay.attr("cursor", cursors.selection);
23847             move();
23848           }
23849           break;
23850         }
23851         default: return;
23852       }
23853       noevent$1();
23854     }
23855
23856     function keyupped() {
23857       switch (event.keyCode) {
23858         case 16: { // SHIFT
23859           if (shifting) {
23860             lockX = lockY = shifting = false;
23861             move();
23862           }
23863           break;
23864         }
23865         case 18: { // ALT
23866           if (mode === MODE_CENTER) {
23867             if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
23868             if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
23869             mode = MODE_HANDLE;
23870             move();
23871           }
23872           break;
23873         }
23874         case 32: { // SPACE
23875           if (mode === MODE_SPACE) {
23876             if (event.altKey) {
23877               if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
23878               if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
23879               mode = MODE_CENTER;
23880             } else {
23881               if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
23882               if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
23883               mode = MODE_HANDLE;
23884             }
23885             overlay.attr("cursor", cursors[type]);
23886             move();
23887           }
23888           break;
23889         }
23890         default: return;
23891       }
23892       noevent$1();
23893     }
23894   }
23895
23896   function initialize() {
23897     var state = this.__brush || {selection: null};
23898     state.extent = extent.apply(this, arguments);
23899     state.dim = dim;
23900     return state;
23901   }
23902
23903   brush.extent = function(_) {
23904     return arguments.length ? (extent = typeof _ === "function" ? _ : constant$4([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), brush) : extent;
23905   };
23906
23907   brush.filter = function(_) {
23908     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$4(!!_), brush) : filter;
23909   };
23910
23911   brush.handleSize = function(_) {
23912     return arguments.length ? (handleSize = +_, brush) : handleSize;
23913   };
23914
23915   brush.on = function() {
23916     var value = listeners.on.apply(listeners, arguments);
23917     return value === listeners ? brush : value;
23918   };
23919
23920   return brush;
23921 }
23922
23923 var cos = Math.cos;
23924 var sin = Math.sin;
23925 var pi$1 = Math.PI;
23926 var halfPi$1 = pi$1 / 2;
23927 var tau$1 = pi$1 * 2;
23928 var max$1 = Math.max;
23929
23930 function compareValue(compare) {
23931   return function(a, b) {
23932     return compare(
23933       a.source.value + a.target.value,
23934       b.source.value + b.target.value
23935     );
23936   };
23937 }
23938
23939 var chord = function() {
23940   var padAngle = 0,
23941       sortGroups = null,
23942       sortSubgroups = null,
23943       sortChords = null;
23944
23945   function chord(matrix) {
23946     var n = matrix.length,
23947         groupSums = [],
23948         groupIndex = sequence(n),
23949         subgroupIndex = [],
23950         chords = [],
23951         groups = chords.groups = new Array(n),
23952         subgroups = new Array(n * n),
23953         k,
23954         x,
23955         x0,
23956         dx,
23957         i,
23958         j;
23959
23960     // Compute the sum.
23961     k = 0, i = -1; while (++i < n) {
23962       x = 0, j = -1; while (++j < n) {
23963         x += matrix[i][j];
23964       }
23965       groupSums.push(x);
23966       subgroupIndex.push(sequence(n));
23967       k += x;
23968     }
23969
23970     // Sort groups…
23971     if (sortGroups) groupIndex.sort(function(a, b) {
23972       return sortGroups(groupSums[a], groupSums[b]);
23973     });
23974
23975     // Sort subgroups…
23976     if (sortSubgroups) subgroupIndex.forEach(function(d, i) {
23977       d.sort(function(a, b) {
23978         return sortSubgroups(matrix[i][a], matrix[i][b]);
23979       });
23980     });
23981
23982     // Convert the sum to scaling factor for [0, 2pi].
23983     // TODO Allow start and end angle to be specified?
23984     // TODO Allow padding to be specified as percentage?
23985     k = max$1(0, tau$1 - padAngle * n) / k;
23986     dx = k ? padAngle : tau$1 / n;
23987
23988     // Compute the start and end angle for each group and subgroup.
23989     // Note: Opera has a bug reordering object literal properties!
23990     x = 0, i = -1; while (++i < n) {
23991       x0 = x, j = -1; while (++j < n) {
23992         var di = groupIndex[i],
23993             dj = subgroupIndex[di][j],
23994             v = matrix[di][dj],
23995             a0 = x,
23996             a1 = x += v * k;
23997         subgroups[dj * n + di] = {
23998           index: di,
23999           subindex: dj,
24000           startAngle: a0,
24001           endAngle: a1,
24002           value: v
24003         };
24004       }
24005       groups[di] = {
24006         index: di,
24007         startAngle: x0,
24008         endAngle: x,
24009         value: groupSums[di]
24010       };
24011       x += dx;
24012     }
24013
24014     // Generate chords for each (non-empty) subgroup-subgroup link.
24015     i = -1; while (++i < n) {
24016       j = i - 1; while (++j < n) {
24017         var source = subgroups[j * n + i],
24018             target = subgroups[i * n + j];
24019         if (source.value || target.value) {
24020           chords.push(source.value < target.value
24021               ? {source: target, target: source}
24022               : {source: source, target: target});
24023         }
24024       }
24025     }
24026
24027     return sortChords ? chords.sort(sortChords) : chords;
24028   }
24029
24030   chord.padAngle = function(_) {
24031     return arguments.length ? (padAngle = max$1(0, _), chord) : padAngle;
24032   };
24033
24034   chord.sortGroups = function(_) {
24035     return arguments.length ? (sortGroups = _, chord) : sortGroups;
24036   };
24037
24038   chord.sortSubgroups = function(_) {
24039     return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups;
24040   };
24041
24042   chord.sortChords = function(_) {
24043     return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._;
24044   };
24045
24046   return chord;
24047 };
24048
24049 var slice$2 = Array.prototype.slice;
24050
24051 var constant$5 = function(x) {
24052   return function() {
24053     return x;
24054   };
24055 };
24056
24057 var pi$2 = Math.PI;
24058 var tau$2 = 2 * pi$2;
24059 var epsilon$1 = 1e-6;
24060 var tauEpsilon = tau$2 - epsilon$1;
24061
24062 function Path() {
24063   this._x0 = this._y0 = // start of current subpath
24064   this._x1 = this._y1 = null; // end of current subpath
24065   this._ = "";
24066 }
24067
24068 function path() {
24069   return new Path;
24070 }
24071
24072 Path.prototype = path.prototype = {
24073   constructor: Path,
24074   moveTo: function(x, y) {
24075     this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y);
24076   },
24077   closePath: function() {
24078     if (this._x1 !== null) {
24079       this._x1 = this._x0, this._y1 = this._y0;
24080       this._ += "Z";
24081     }
24082   },
24083   lineTo: function(x, y) {
24084     this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y);
24085   },
24086   quadraticCurveTo: function(x1, y1, x, y) {
24087     this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
24088   },
24089   bezierCurveTo: function(x1, y1, x2, y2, x, y) {
24090     this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
24091   },
24092   arcTo: function(x1, y1, x2, y2, r) {
24093     x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
24094     var x0 = this._x1,
24095         y0 = this._y1,
24096         x21 = x2 - x1,
24097         y21 = y2 - y1,
24098         x01 = x0 - x1,
24099         y01 = y0 - y1,
24100         l01_2 = x01 * x01 + y01 * y01;
24101
24102     // Is the radius negative? Error.
24103     if (r < 0) throw new Error("negative radius: " + r);
24104
24105     // Is this path empty? Move to (x1,y1).
24106     if (this._x1 === null) {
24107       this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1);
24108     }
24109
24110     // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
24111     else if (!(l01_2 > epsilon$1)) {}
24112
24113     // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?
24114     // Equivalently, is (x1,y1) coincident with (x2,y2)?
24115     // Or, is the radius zero? Line to (x1,y1).
24116     else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon$1) || !r) {
24117       this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1);
24118     }
24119
24120     // Otherwise, draw an arc!
24121     else {
24122       var x20 = x2 - x0,
24123           y20 = y2 - y0,
24124           l21_2 = x21 * x21 + y21 * y21,
24125           l20_2 = x20 * x20 + y20 * y20,
24126           l21 = Math.sqrt(l21_2),
24127           l01 = Math.sqrt(l01_2),
24128           l = r * Math.tan((pi$2 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),
24129           t01 = l / l01,
24130           t21 = l / l21;
24131
24132       // If the start tangent is not coincident with (x0,y0), line to.
24133       if (Math.abs(t01 - 1) > epsilon$1) {
24134         this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01);
24135       }
24136
24137       this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21);
24138     }
24139   },
24140   arc: function(x, y, r, a0, a1, ccw) {
24141     x = +x, y = +y, r = +r;
24142     var dx = r * Math.cos(a0),
24143         dy = r * Math.sin(a0),
24144         x0 = x + dx,
24145         y0 = y + dy,
24146         cw = 1 ^ ccw,
24147         da = ccw ? a0 - a1 : a1 - a0;
24148
24149     // Is the radius negative? Error.
24150     if (r < 0) throw new Error("negative radius: " + r);
24151
24152     // Is this path empty? Move to (x0,y0).
24153     if (this._x1 === null) {
24154       this._ += "M" + x0 + "," + y0;
24155     }
24156
24157     // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
24158     else if (Math.abs(this._x1 - x0) > epsilon$1 || Math.abs(this._y1 - y0) > epsilon$1) {
24159       this._ += "L" + x0 + "," + y0;
24160     }
24161
24162     // Is this arc empty? We’re done.
24163     if (!r) return;
24164
24165     // Does the angle go the wrong way? Flip the direction.
24166     if (da < 0) da = da % tau$2 + tau$2;
24167
24168     // Is this a complete circle? Draw two arcs to complete the circle.
24169     if (da > tauEpsilon) {
24170       this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0);
24171     }
24172
24173     // Is this arc non-empty? Draw an arc!
24174     else if (da > epsilon$1) {
24175       this._ += "A" + r + "," + r + ",0," + (+(da >= pi$2)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1));
24176     }
24177   },
24178   rect: function(x, y, w, h) {
24179     this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z";
24180   },
24181   toString: function() {
24182     return this._;
24183   }
24184 };
24185
24186 function defaultSource(d) {
24187   return d.source;
24188 }
24189
24190 function defaultTarget(d) {
24191   return d.target;
24192 }
24193
24194 function defaultRadius(d) {
24195   return d.radius;
24196 }
24197
24198 function defaultStartAngle(d) {
24199   return d.startAngle;
24200 }
24201
24202 function defaultEndAngle(d) {
24203   return d.endAngle;
24204 }
24205
24206 var ribbon = function() {
24207   var source = defaultSource,
24208       target = defaultTarget,
24209       radius = defaultRadius,
24210       startAngle = defaultStartAngle,
24211       endAngle = defaultEndAngle,
24212       context = null;
24213
24214   function ribbon() {
24215     var buffer,
24216         argv = slice$2.call(arguments),
24217         s = source.apply(this, argv),
24218         t = target.apply(this, argv),
24219         sr = +radius.apply(this, (argv[0] = s, argv)),
24220         sa0 = startAngle.apply(this, argv) - halfPi$1,
24221         sa1 = endAngle.apply(this, argv) - halfPi$1,
24222         sx0 = sr * cos(sa0),
24223         sy0 = sr * sin(sa0),
24224         tr = +radius.apply(this, (argv[0] = t, argv)),
24225         ta0 = startAngle.apply(this, argv) - halfPi$1,
24226         ta1 = endAngle.apply(this, argv) - halfPi$1;
24227
24228     if (!context) context = buffer = path();
24229
24230     context.moveTo(sx0, sy0);
24231     context.arc(0, 0, sr, sa0, sa1);
24232     if (sa0 !== ta0 || sa1 !== ta1) { // TODO sr !== tr?
24233       context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));
24234       context.arc(0, 0, tr, ta0, ta1);
24235     }
24236     context.quadraticCurveTo(0, 0, sx0, sy0);
24237     context.closePath();
24238
24239     if (buffer) return context = null, buffer + "" || null;
24240   }
24241
24242   ribbon.radius = function(_) {
24243     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$5(+_), ribbon) : radius;
24244   };
24245
24246   ribbon.startAngle = function(_) {
24247     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : startAngle;
24248   };
24249
24250   ribbon.endAngle = function(_) {
24251     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : endAngle;
24252   };
24253
24254   ribbon.source = function(_) {
24255     return arguments.length ? (source = _, ribbon) : source;
24256   };
24257
24258   ribbon.target = function(_) {
24259     return arguments.length ? (target = _, ribbon) : target;
24260   };
24261
24262   ribbon.context = function(_) {
24263     return arguments.length ? ((context = _ == null ? null : _), ribbon) : context;
24264   };
24265
24266   return ribbon;
24267 };
24268
24269 var prefix = "$";
24270
24271 function Map() {}
24272
24273 Map.prototype = map$1.prototype = {
24274   constructor: Map,
24275   has: function(key) {
24276     return (prefix + key) in this;
24277   },
24278   get: function(key) {
24279     return this[prefix + key];
24280   },
24281   set: function(key, value) {
24282     this[prefix + key] = value;
24283     return this;
24284   },
24285   remove: function(key) {
24286     var property = prefix + key;
24287     return property in this && delete this[property];
24288   },
24289   clear: function() {
24290     for (var property in this) if (property[0] === prefix) delete this[property];
24291   },
24292   keys: function() {
24293     var keys = [];
24294     for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
24295     return keys;
24296   },
24297   values: function() {
24298     var values = [];
24299     for (var property in this) if (property[0] === prefix) values.push(this[property]);
24300     return values;
24301   },
24302   entries: function() {
24303     var entries = [];
24304     for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
24305     return entries;
24306   },
24307   size: function() {
24308     var size = 0;
24309     for (var property in this) if (property[0] === prefix) ++size;
24310     return size;
24311   },
24312   empty: function() {
24313     for (var property in this) if (property[0] === prefix) return false;
24314     return true;
24315   },
24316   each: function(f) {
24317     for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
24318   }
24319 };
24320
24321 function map$1(object, f) {
24322   var map = new Map;
24323
24324   // Copy constructor.
24325   if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
24326
24327   // Index array by numeric index or specified key function.
24328   else if (Array.isArray(object)) {
24329     var i = -1,
24330         n = object.length,
24331         o;
24332
24333     if (f == null) while (++i < n) map.set(i, object[i]);
24334     else while (++i < n) map.set(f(o = object[i], i, object), o);
24335   }
24336
24337   // Convert object to map.
24338   else if (object) for (var key in object) map.set(key, object[key]);
24339
24340   return map;
24341 }
24342
24343 var nest = function() {
24344   var keys = [],
24345       sortKeys = [],
24346       sortValues,
24347       rollup,
24348       nest;
24349
24350   function apply(array, depth, createResult, setResult) {
24351     if (depth >= keys.length) return rollup != null
24352         ? rollup(array) : (sortValues != null
24353         ? array.sort(sortValues)
24354         : array);
24355
24356     var i = -1,
24357         n = array.length,
24358         key = keys[depth++],
24359         keyValue,
24360         value,
24361         valuesByKey = map$1(),
24362         values,
24363         result = createResult();
24364
24365     while (++i < n) {
24366       if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
24367         values.push(value);
24368       } else {
24369         valuesByKey.set(keyValue, [value]);
24370       }
24371     }
24372
24373     valuesByKey.each(function(values, key) {
24374       setResult(result, key, apply(values, depth, createResult, setResult));
24375     });
24376
24377     return result;
24378   }
24379
24380   function entries(map, depth) {
24381     if (++depth > keys.length) return map;
24382     var array, sortKey = sortKeys[depth - 1];
24383     if (rollup != null && depth >= keys.length) array = map.entries();
24384     else array = [], map.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); });
24385     return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array;
24386   }
24387
24388   return nest = {
24389     object: function(array) { return apply(array, 0, createObject, setObject); },
24390     map: function(array) { return apply(array, 0, createMap, setMap); },
24391     entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); },
24392     key: function(d) { keys.push(d); return nest; },
24393     sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; },
24394     sortValues: function(order) { sortValues = order; return nest; },
24395     rollup: function(f) { rollup = f; return nest; }
24396   };
24397 };
24398
24399 function createObject() {
24400   return {};
24401 }
24402
24403 function setObject(object, key, value) {
24404   object[key] = value;
24405 }
24406
24407 function createMap() {
24408   return map$1();
24409 }
24410
24411 function setMap(map, key, value) {
24412   map.set(key, value);
24413 }
24414
24415 function Set() {}
24416
24417 var proto = map$1.prototype;
24418
24419 Set.prototype = set$2.prototype = {
24420   constructor: Set,
24421   has: proto.has,
24422   add: function(value) {
24423     value += "";
24424     this[prefix + value] = value;
24425     return this;
24426   },
24427   remove: proto.remove,
24428   clear: proto.clear,
24429   values: proto.keys,
24430   size: proto.size,
24431   empty: proto.empty,
24432   each: proto.each
24433 };
24434
24435 function set$2(object, f) {
24436   var set = new Set;
24437
24438   // Copy constructor.
24439   if (object instanceof Set) object.each(function(value) { set.add(value); });
24440
24441   // Otherwise, assume it’s an array.
24442   else if (object) {
24443     var i = -1, n = object.length;
24444     if (f == null) while (++i < n) set.add(object[i]);
24445     else while (++i < n) set.add(f(object[i], i, object));
24446   }
24447
24448   return set;
24449 }
24450
24451 var keys = function(map) {
24452   var keys = [];
24453   for (var key in map) keys.push(key);
24454   return keys;
24455 };
24456
24457 var values = function(map) {
24458   var values = [];
24459   for (var key in map) values.push(map[key]);
24460   return values;
24461 };
24462
24463 var entries = function(map) {
24464   var entries = [];
24465   for (var key in map) entries.push({key: key, value: map[key]});
24466   return entries;
24467 };
24468
24469 function objectConverter(columns) {
24470   return new Function("d", "return {" + columns.map(function(name, i) {
24471     return JSON.stringify(name) + ": d[" + i + "]";
24472   }).join(",") + "}");
24473 }
24474
24475 function customConverter(columns, f) {
24476   var object = objectConverter(columns);
24477   return function(row, i) {
24478     return f(object(row), i, columns);
24479   };
24480 }
24481
24482 // Compute unique columns in order of discovery.
24483 function inferColumns(rows) {
24484   var columnSet = Object.create(null),
24485       columns = [];
24486
24487   rows.forEach(function(row) {
24488     for (var column in row) {
24489       if (!(column in columnSet)) {
24490         columns.push(columnSet[column] = column);
24491       }
24492     }
24493   });
24494
24495   return columns;
24496 }
24497
24498 var dsv = function(delimiter) {
24499   var reFormat = new RegExp("[\"" + delimiter + "\n\r]"),
24500       delimiterCode = delimiter.charCodeAt(0);
24501
24502   function parse(text, f) {
24503     var convert, columns, rows = parseRows(text, function(row, i) {
24504       if (convert) return convert(row, i - 1);
24505       columns = row, convert = f ? customConverter(row, f) : objectConverter(row);
24506     });
24507     rows.columns = columns;
24508     return rows;
24509   }
24510
24511   function parseRows(text, f) {
24512     var EOL = {}, // sentinel value for end-of-line
24513         EOF = {}, // sentinel value for end-of-file
24514         rows = [], // output rows
24515         N = text.length,
24516         I = 0, // current character index
24517         n = 0, // the current line number
24518         t, // the current token
24519         eol; // is the current token followed by EOL?
24520
24521     function token() {
24522       if (I >= N) return EOF; // special case: end of file
24523       if (eol) return eol = false, EOL; // special case: end of line
24524
24525       // special case: quotes
24526       var j = I, c;
24527       if (text.charCodeAt(j) === 34) {
24528         var i = j;
24529         while (i++ < N) {
24530           if (text.charCodeAt(i) === 34) {
24531             if (text.charCodeAt(i + 1) !== 34) break;
24532             ++i;
24533           }
24534         }
24535         I = i + 2;
24536         c = text.charCodeAt(i + 1);
24537         if (c === 13) {
24538           eol = true;
24539           if (text.charCodeAt(i + 2) === 10) ++I;
24540         } else if (c === 10) {
24541           eol = true;
24542         }
24543         return text.slice(j + 1, i).replace(/""/g, "\"");
24544       }
24545
24546       // common case: find next delimiter or newline
24547       while (I < N) {
24548         var k = 1;
24549         c = text.charCodeAt(I++);
24550         if (c === 10) eol = true; // \n
24551         else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \r|\r\n
24552         else if (c !== delimiterCode) continue;
24553         return text.slice(j, I - k);
24554       }
24555
24556       // special case: last token before EOF
24557       return text.slice(j);
24558     }
24559
24560     while ((t = token()) !== EOF) {
24561       var a = [];
24562       while (t !== EOL && t !== EOF) {
24563         a.push(t);
24564         t = token();
24565       }
24566       if (f && (a = f(a, n++)) == null) continue;
24567       rows.push(a);
24568     }
24569
24570     return rows;
24571   }
24572
24573   function format(rows, columns) {
24574     if (columns == null) columns = inferColumns(rows);
24575     return [columns.map(formatValue).join(delimiter)].concat(rows.map(function(row) {
24576       return columns.map(function(column) {
24577         return formatValue(row[column]);
24578       }).join(delimiter);
24579     })).join("\n");
24580   }
24581
24582   function formatRows(rows) {
24583     return rows.map(formatRow).join("\n");
24584   }
24585
24586   function formatRow(row) {
24587     return row.map(formatValue).join(delimiter);
24588   }
24589
24590   function formatValue(text) {
24591     return text == null ? ""
24592         : reFormat.test(text += "") ? "\"" + text.replace(/\"/g, "\"\"") + "\""
24593         : text;
24594   }
24595
24596   return {
24597     parse: parse,
24598     parseRows: parseRows,
24599     format: format,
24600     formatRows: formatRows
24601   };
24602 };
24603
24604 var csv = dsv(",");
24605
24606 var csvParse = csv.parse;
24607 var csvParseRows = csv.parseRows;
24608 var csvFormat = csv.format;
24609 var csvFormatRows = csv.formatRows;
24610
24611 var tsv = dsv("\t");
24612
24613 var tsvParse = tsv.parse;
24614 var tsvParseRows = tsv.parseRows;
24615 var tsvFormat = tsv.format;
24616 var tsvFormatRows = tsv.formatRows;
24617
24618 var center$1 = function(x, y) {
24619   var nodes;
24620
24621   if (x == null) x = 0;
24622   if (y == null) y = 0;
24623
24624   function force() {
24625     var i,
24626         n = nodes.length,
24627         node,
24628         sx = 0,
24629         sy = 0;
24630
24631     for (i = 0; i < n; ++i) {
24632       node = nodes[i], sx += node.x, sy += node.y;
24633     }
24634
24635     for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
24636       node = nodes[i], node.x -= sx, node.y -= sy;
24637     }
24638   }
24639
24640   force.initialize = function(_) {
24641     nodes = _;
24642   };
24643
24644   force.x = function(_) {
24645     return arguments.length ? (x = +_, force) : x;
24646   };
24647
24648   force.y = function(_) {
24649     return arguments.length ? (y = +_, force) : y;
24650   };
24651
24652   return force;
24653 };
24654
24655 var constant$6 = function(x) {
24656   return function() {
24657     return x;
24658   };
24659 };
24660
24661 var jiggle = function() {
24662   return (Math.random() - 0.5) * 1e-6;
24663 };
24664
24665 var tree_add = function(d) {
24666   var x = +this._x.call(null, d),
24667       y = +this._y.call(null, d);
24668   return add(this.cover(x, y), x, y, d);
24669 };
24670
24671 function add(tree, x, y, d) {
24672   if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points
24673
24674   var parent,
24675       node = tree._root,
24676       leaf = {data: d},
24677       x0 = tree._x0,
24678       y0 = tree._y0,
24679       x1 = tree._x1,
24680       y1 = tree._y1,
24681       xm,
24682       ym,
24683       xp,
24684       yp,
24685       right,
24686       bottom,
24687       i,
24688       j;
24689
24690   // If the tree is empty, initialize the root as a leaf.
24691   if (!node) return tree._root = leaf, tree;
24692
24693   // Find the existing leaf for the new point, or add it.
24694   while (node.length) {
24695     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24696     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24697     if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree;
24698   }
24699
24700   // Is the new point is exactly coincident with the existing point?
24701   xp = +tree._x.call(null, node.data);
24702   yp = +tree._y.call(null, node.data);
24703   if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
24704
24705   // Otherwise, split the leaf node until the old and new point are separated.
24706   do {
24707     parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
24708     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24709     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24710   } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm)));
24711   return parent[j] = node, parent[i] = leaf, tree;
24712 }
24713
24714 function addAll(data) {
24715   var d, i, n = data.length,
24716       x,
24717       y,
24718       xz = new Array(n),
24719       yz = new Array(n),
24720       x0 = Infinity,
24721       y0 = Infinity,
24722       x1 = -Infinity,
24723       y1 = -Infinity;
24724
24725   // Compute the points and their extent.
24726   for (i = 0; i < n; ++i) {
24727     if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue;
24728     xz[i] = x;
24729     yz[i] = y;
24730     if (x < x0) x0 = x;
24731     if (x > x1) x1 = x;
24732     if (y < y0) y0 = y;
24733     if (y > y1) y1 = y;
24734   }
24735
24736   // If there were no (valid) points, inherit the existing extent.
24737   if (x1 < x0) x0 = this._x0, x1 = this._x1;
24738   if (y1 < y0) y0 = this._y0, y1 = this._y1;
24739
24740   // Expand the tree to cover the new points.
24741   this.cover(x0, y0).cover(x1, y1);
24742
24743   // Add the new points.
24744   for (i = 0; i < n; ++i) {
24745     add(this, xz[i], yz[i], data[i]);
24746   }
24747
24748   return this;
24749 }
24750
24751 var tree_cover = function(x, y) {
24752   if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points
24753
24754   var x0 = this._x0,
24755       y0 = this._y0,
24756       x1 = this._x1,
24757       y1 = this._y1;
24758
24759   // If the quadtree has no extent, initialize them.
24760   // Integer extent are necessary so that if we later double the extent,
24761   // the existing quadrant boundaries don’t change due to floating point error!
24762   if (isNaN(x0)) {
24763     x1 = (x0 = Math.floor(x)) + 1;
24764     y1 = (y0 = Math.floor(y)) + 1;
24765   }
24766
24767   // Otherwise, double repeatedly to cover.
24768   else if (x0 > x || x > x1 || y0 > y || y > y1) {
24769     var z = x1 - x0,
24770         node = this._root,
24771         parent,
24772         i;
24773
24774     switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) {
24775       case 0: {
24776         do parent = new Array(4), parent[i] = node, node = parent;
24777         while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1);
24778         break;
24779       }
24780       case 1: {
24781         do parent = new Array(4), parent[i] = node, node = parent;
24782         while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1);
24783         break;
24784       }
24785       case 2: {
24786         do parent = new Array(4), parent[i] = node, node = parent;
24787         while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y);
24788         break;
24789       }
24790       case 3: {
24791         do parent = new Array(4), parent[i] = node, node = parent;
24792         while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y);
24793         break;
24794       }
24795     }
24796
24797     if (this._root && this._root.length) this._root = node;
24798   }
24799
24800   // If the quadtree covers the point already, just return.
24801   else return this;
24802
24803   this._x0 = x0;
24804   this._y0 = y0;
24805   this._x1 = x1;
24806   this._y1 = y1;
24807   return this;
24808 };
24809
24810 var tree_data = function() {
24811   var data = [];
24812   this.visit(function(node) {
24813     if (!node.length) do data.push(node.data); while (node = node.next)
24814   });
24815   return data;
24816 };
24817
24818 var tree_extent = function(_) {
24819   return arguments.length
24820       ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1])
24821       : isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]];
24822 };
24823
24824 var Quad = function(node, x0, y0, x1, y1) {
24825   this.node = node;
24826   this.x0 = x0;
24827   this.y0 = y0;
24828   this.x1 = x1;
24829   this.y1 = y1;
24830 };
24831
24832 var tree_find = function(x, y, radius) {
24833   var data,
24834       x0 = this._x0,
24835       y0 = this._y0,
24836       x1,
24837       y1,
24838       x2,
24839       y2,
24840       x3 = this._x1,
24841       y3 = this._y1,
24842       quads = [],
24843       node = this._root,
24844       q,
24845       i;
24846
24847   if (node) quads.push(new Quad(node, x0, y0, x3, y3));
24848   if (radius == null) radius = Infinity;
24849   else {
24850     x0 = x - radius, y0 = y - radius;
24851     x3 = x + radius, y3 = y + radius;
24852     radius *= radius;
24853   }
24854
24855   while (q = quads.pop()) {
24856
24857     // Stop searching if this quadrant can’t contain a closer node.
24858     if (!(node = q.node)
24859         || (x1 = q.x0) > x3
24860         || (y1 = q.y0) > y3
24861         || (x2 = q.x1) < x0
24862         || (y2 = q.y1) < y0) continue;
24863
24864     // Bisect the current quadrant.
24865     if (node.length) {
24866       var xm = (x1 + x2) / 2,
24867           ym = (y1 + y2) / 2;
24868
24869       quads.push(
24870         new Quad(node[3], xm, ym, x2, y2),
24871         new Quad(node[2], x1, ym, xm, y2),
24872         new Quad(node[1], xm, y1, x2, ym),
24873         new Quad(node[0], x1, y1, xm, ym)
24874       );
24875
24876       // Visit the closest quadrant first.
24877       if (i = (y >= ym) << 1 | (x >= xm)) {
24878         q = quads[quads.length - 1];
24879         quads[quads.length - 1] = quads[quads.length - 1 - i];
24880         quads[quads.length - 1 - i] = q;
24881       }
24882     }
24883
24884     // Visit this point. (Visiting coincident points isn’t necessary!)
24885     else {
24886       var dx = x - +this._x.call(null, node.data),
24887           dy = y - +this._y.call(null, node.data),
24888           d2 = dx * dx + dy * dy;
24889       if (d2 < radius) {
24890         var d = Math.sqrt(radius = d2);
24891         x0 = x - d, y0 = y - d;
24892         x3 = x + d, y3 = y + d;
24893         data = node.data;
24894       }
24895     }
24896   }
24897
24898   return data;
24899 };
24900
24901 var tree_remove = function(d) {
24902   if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points
24903
24904   var parent,
24905       node = this._root,
24906       retainer,
24907       previous,
24908       next,
24909       x0 = this._x0,
24910       y0 = this._y0,
24911       x1 = this._x1,
24912       y1 = this._y1,
24913       x,
24914       y,
24915       xm,
24916       ym,
24917       right,
24918       bottom,
24919       i,
24920       j;
24921
24922   // If the tree is empty, initialize the root as a leaf.
24923   if (!node) return this;
24924
24925   // Find the leaf node for the point.
24926   // While descending, also retain the deepest parent with a non-removed sibling.
24927   if (node.length) while (true) {
24928     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24929     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24930     if (!(parent = node, node = node[i = bottom << 1 | right])) return this;
24931     if (!node.length) break;
24932     if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i;
24933   }
24934
24935   // Find the point to remove.
24936   while (node.data !== d) if (!(previous = node, node = node.next)) return this;
24937   if (next = node.next) delete node.next;
24938
24939   // If there are multiple coincident points, remove just the point.
24940   if (previous) return (next ? previous.next = next : delete previous.next), this;
24941
24942   // If this is the root point, remove it.
24943   if (!parent) return this._root = next, this;
24944
24945   // Remove this leaf.
24946   next ? parent[i] = next : delete parent[i];
24947
24948   // If the parent now contains exactly one leaf, collapse superfluous parents.
24949   if ((node = parent[0] || parent[1] || parent[2] || parent[3])
24950       && node === (parent[3] || parent[2] || parent[1] || parent[0])
24951       && !node.length) {
24952     if (retainer) retainer[j] = node;
24953     else this._root = node;
24954   }
24955
24956   return this;
24957 };
24958
24959 function removeAll(data) {
24960   for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
24961   return this;
24962 }
24963
24964 var tree_root = function() {
24965   return this._root;
24966 };
24967
24968 var tree_size = function() {
24969   var size = 0;
24970   this.visit(function(node) {
24971     if (!node.length) do ++size; while (node = node.next)
24972   });
24973   return size;
24974 };
24975
24976 var tree_visit = function(callback) {
24977   var quads = [], q, node = this._root, child, x0, y0, x1, y1;
24978   if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1));
24979   while (q = quads.pop()) {
24980     if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) {
24981       var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
24982       if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
24983       if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
24984       if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
24985       if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
24986     }
24987   }
24988   return this;
24989 };
24990
24991 var tree_visitAfter = function(callback) {
24992   var quads = [], next = [], q;
24993   if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1));
24994   while (q = quads.pop()) {
24995     var node = q.node;
24996     if (node.length) {
24997       var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
24998       if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
24999       if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
25000       if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
25001       if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
25002     }
25003     next.push(q);
25004   }
25005   while (q = next.pop()) {
25006     callback(q.node, q.x0, q.y0, q.x1, q.y1);
25007   }
25008   return this;
25009 };
25010
25011 function defaultX(d) {
25012   return d[0];
25013 }
25014
25015 var tree_x = function(_) {
25016   return arguments.length ? (this._x = _, this) : this._x;
25017 };
25018
25019 function defaultY(d) {
25020   return d[1];
25021 }
25022
25023 var tree_y = function(_) {
25024   return arguments.length ? (this._y = _, this) : this._y;
25025 };
25026
25027 function quadtree(nodes, x, y) {
25028   var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN);
25029   return nodes == null ? tree : tree.addAll(nodes);
25030 }
25031
25032 function Quadtree(x, y, x0, y0, x1, y1) {
25033   this._x = x;
25034   this._y = y;
25035   this._x0 = x0;
25036   this._y0 = y0;
25037   this._x1 = x1;
25038   this._y1 = y1;
25039   this._root = undefined;
25040 }
25041
25042 function leaf_copy(leaf) {
25043   var copy = {data: leaf.data}, next = copy;
25044   while (leaf = leaf.next) next = next.next = {data: leaf.data};
25045   return copy;
25046 }
25047
25048 var treeProto = quadtree.prototype = Quadtree.prototype;
25049
25050 treeProto.copy = function() {
25051   var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1),
25052       node = this._root,
25053       nodes,
25054       child;
25055
25056   if (!node) return copy;
25057
25058   if (!node.length) return copy._root = leaf_copy(node), copy;
25059
25060   nodes = [{source: node, target: copy._root = new Array(4)}];
25061   while (node = nodes.pop()) {
25062     for (var i = 0; i < 4; ++i) {
25063       if (child = node.source[i]) {
25064         if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)});
25065         else node.target[i] = leaf_copy(child);
25066       }
25067     }
25068   }
25069
25070   return copy;
25071 };
25072
25073 treeProto.add = tree_add;
25074 treeProto.addAll = addAll;
25075 treeProto.cover = tree_cover;
25076 treeProto.data = tree_data;
25077 treeProto.extent = tree_extent;
25078 treeProto.find = tree_find;
25079 treeProto.remove = tree_remove;
25080 treeProto.removeAll = removeAll;
25081 treeProto.root = tree_root;
25082 treeProto.size = tree_size;
25083 treeProto.visit = tree_visit;
25084 treeProto.visitAfter = tree_visitAfter;
25085 treeProto.x = tree_x;
25086 treeProto.y = tree_y;
25087
25088 function x(d) {
25089   return d.x + d.vx;
25090 }
25091
25092 function y(d) {
25093   return d.y + d.vy;
25094 }
25095
25096 var collide = function(radius) {
25097   var nodes,
25098       radii,
25099       strength = 1,
25100       iterations = 1;
25101
25102   if (typeof radius !== "function") radius = constant$6(radius == null ? 1 : +radius);
25103
25104   function force() {
25105     var i, n = nodes.length,
25106         tree,
25107         node,
25108         xi,
25109         yi,
25110         ri,
25111         ri2;
25112
25113     for (var k = 0; k < iterations; ++k) {
25114       tree = quadtree(nodes, x, y).visitAfter(prepare);
25115       for (i = 0; i < n; ++i) {
25116         node = nodes[i];
25117         ri = radii[node.index], ri2 = ri * ri;
25118         xi = node.x + node.vx;
25119         yi = node.y + node.vy;
25120         tree.visit(apply);
25121       }
25122     }
25123
25124     function apply(quad, x0, y0, x1, y1) {
25125       var data = quad.data, rj = quad.r, r = ri + rj;
25126       if (data) {
25127         if (data.index > node.index) {
25128           var x = xi - data.x - data.vx,
25129               y = yi - data.y - data.vy,
25130               l = x * x + y * y;
25131           if (l < r * r) {
25132             if (x === 0) x = jiggle(), l += x * x;
25133             if (y === 0) y = jiggle(), l += y * y;
25134             l = (r - (l = Math.sqrt(l))) / l * strength;
25135             node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
25136             node.vy += (y *= l) * r;
25137             data.vx -= x * (r = 1 - r);
25138             data.vy -= y * r;
25139           }
25140         }
25141         return;
25142       }
25143       return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
25144     }
25145   }
25146
25147   function prepare(quad) {
25148     if (quad.data) return quad.r = radii[quad.data.index];
25149     for (var i = quad.r = 0; i < 4; ++i) {
25150       if (quad[i] && quad[i].r > quad.r) {
25151         quad.r = quad[i].r;
25152       }
25153     }
25154   }
25155
25156   function initialize() {
25157     if (!nodes) return;
25158     var i, n = nodes.length, node;
25159     radii = new Array(n);
25160     for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
25161   }
25162
25163   force.initialize = function(_) {
25164     nodes = _;
25165     initialize();
25166   };
25167
25168   force.iterations = function(_) {
25169     return arguments.length ? (iterations = +_, force) : iterations;
25170   };
25171
25172   force.strength = function(_) {
25173     return arguments.length ? (strength = +_, force) : strength;
25174   };
25175
25176   force.radius = function(_) {
25177     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : radius;
25178   };
25179
25180   return force;
25181 };
25182
25183 function index$3(d) {
25184   return d.index;
25185 }
25186
25187 function find(nodeById, nodeId) {
25188   var node = nodeById.get(nodeId);
25189   if (!node) throw new Error("missing: " + nodeId);
25190   return node;
25191 }
25192
25193 var link = function(links) {
25194   var id = index$3,
25195       strength = defaultStrength,
25196       strengths,
25197       distance = constant$6(30),
25198       distances,
25199       nodes,
25200       count,
25201       bias,
25202       iterations = 1;
25203
25204   if (links == null) links = [];
25205
25206   function defaultStrength(link) {
25207     return 1 / Math.min(count[link.source.index], count[link.target.index]);
25208   }
25209
25210   function force(alpha) {
25211     for (var k = 0, n = links.length; k < iterations; ++k) {
25212       for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
25213         link = links[i], source = link.source, target = link.target;
25214         x = target.x + target.vx - source.x - source.vx || jiggle();
25215         y = target.y + target.vy - source.y - source.vy || jiggle();
25216         l = Math.sqrt(x * x + y * y);
25217         l = (l - distances[i]) / l * alpha * strengths[i];
25218         x *= l, y *= l;
25219         target.vx -= x * (b = bias[i]);
25220         target.vy -= y * b;
25221         source.vx += x * (b = 1 - b);
25222         source.vy += y * b;
25223       }
25224     }
25225   }
25226
25227   function initialize() {
25228     if (!nodes) return;
25229
25230     var i,
25231         n = nodes.length,
25232         m = links.length,
25233         nodeById = map$1(nodes, id),
25234         link;
25235
25236     for (i = 0, count = new Array(n); i < m; ++i) {
25237       link = links[i], link.index = i;
25238       if (typeof link.source !== "object") link.source = find(nodeById, link.source);
25239       if (typeof link.target !== "object") link.target = find(nodeById, link.target);
25240       count[link.source.index] = (count[link.source.index] || 0) + 1;
25241       count[link.target.index] = (count[link.target.index] || 0) + 1;
25242     }
25243
25244     for (i = 0, bias = new Array(m); i < m; ++i) {
25245       link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
25246     }
25247
25248     strengths = new Array(m), initializeStrength();
25249     distances = new Array(m), initializeDistance();
25250   }
25251
25252   function initializeStrength() {
25253     if (!nodes) return;
25254
25255     for (var i = 0, n = links.length; i < n; ++i) {
25256       strengths[i] = +strength(links[i], i, links);
25257     }
25258   }
25259
25260   function initializeDistance() {
25261     if (!nodes) return;
25262
25263     for (var i = 0, n = links.length; i < n; ++i) {
25264       distances[i] = +distance(links[i], i, links);
25265     }
25266   }
25267
25268   force.initialize = function(_) {
25269     nodes = _;
25270     initialize();
25271   };
25272
25273   force.links = function(_) {
25274     return arguments.length ? (links = _, initialize(), force) : links;
25275   };
25276
25277   force.id = function(_) {
25278     return arguments.length ? (id = _, force) : id;
25279   };
25280
25281   force.iterations = function(_) {
25282     return arguments.length ? (iterations = +_, force) : iterations;
25283   };
25284
25285   force.strength = function(_) {
25286     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initializeStrength(), force) : strength;
25287   };
25288
25289   force.distance = function(_) {
25290     return arguments.length ? (distance = typeof _ === "function" ? _ : constant$6(+_), initializeDistance(), force) : distance;
25291   };
25292
25293   return force;
25294 };
25295
25296 function x$1(d) {
25297   return d.x;
25298 }
25299
25300 function y$1(d) {
25301   return d.y;
25302 }
25303
25304 var initialRadius = 10;
25305 var initialAngle = Math.PI * (3 - Math.sqrt(5));
25306
25307 var simulation = function(nodes) {
25308   var simulation,
25309       alpha = 1,
25310       alphaMin = 0.001,
25311       alphaDecay = 1 - Math.pow(alphaMin, 1 / 300),
25312       alphaTarget = 0,
25313       velocityDecay = 0.6,
25314       forces = map$1(),
25315       stepper = timer(step),
25316       event = dispatch("tick", "end");
25317
25318   if (nodes == null) nodes = [];
25319
25320   function step() {
25321     tick();
25322     event.call("tick", simulation);
25323     if (alpha < alphaMin) {
25324       stepper.stop();
25325       event.call("end", simulation);
25326     }
25327   }
25328
25329   function tick() {
25330     var i, n = nodes.length, node;
25331
25332     alpha += (alphaTarget - alpha) * alphaDecay;
25333
25334     forces.each(function(force) {
25335       force(alpha);
25336     });
25337
25338     for (i = 0; i < n; ++i) {
25339       node = nodes[i];
25340       if (node.fx == null) node.x += node.vx *= velocityDecay;
25341       else node.x = node.fx, node.vx = 0;
25342       if (node.fy == null) node.y += node.vy *= velocityDecay;
25343       else node.y = node.fy, node.vy = 0;
25344     }
25345   }
25346
25347   function initializeNodes() {
25348     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25349       node = nodes[i], node.index = i;
25350       if (isNaN(node.x) || isNaN(node.y)) {
25351         var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle;
25352         node.x = radius * Math.cos(angle);
25353         node.y = radius * Math.sin(angle);
25354       }
25355       if (isNaN(node.vx) || isNaN(node.vy)) {
25356         node.vx = node.vy = 0;
25357       }
25358     }
25359   }
25360
25361   function initializeForce(force) {
25362     if (force.initialize) force.initialize(nodes);
25363     return force;
25364   }
25365
25366   initializeNodes();
25367
25368   return simulation = {
25369     tick: tick,
25370
25371     restart: function() {
25372       return stepper.restart(step), simulation;
25373     },
25374
25375     stop: function() {
25376       return stepper.stop(), simulation;
25377     },
25378
25379     nodes: function(_) {
25380       return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes;
25381     },
25382
25383     alpha: function(_) {
25384       return arguments.length ? (alpha = +_, simulation) : alpha;
25385     },
25386
25387     alphaMin: function(_) {
25388       return arguments.length ? (alphaMin = +_, simulation) : alphaMin;
25389     },
25390
25391     alphaDecay: function(_) {
25392       return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay;
25393     },
25394
25395     alphaTarget: function(_) {
25396       return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget;
25397     },
25398
25399     velocityDecay: function(_) {
25400       return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
25401     },
25402
25403     force: function(name, _) {
25404       return arguments.length > 1 ? ((_ == null ? forces.remove(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
25405     },
25406
25407     find: function(x, y, radius) {
25408       var i = 0,
25409           n = nodes.length,
25410           dx,
25411           dy,
25412           d2,
25413           node,
25414           closest;
25415
25416       if (radius == null) radius = Infinity;
25417       else radius *= radius;
25418
25419       for (i = 0; i < n; ++i) {
25420         node = nodes[i];
25421         dx = x - node.x;
25422         dy = y - node.y;
25423         d2 = dx * dx + dy * dy;
25424         if (d2 < radius) closest = node, radius = d2;
25425       }
25426
25427       return closest;
25428     },
25429
25430     on: function(name, _) {
25431       return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name);
25432     }
25433   };
25434 };
25435
25436 var manyBody = function() {
25437   var nodes,
25438       node,
25439       alpha,
25440       strength = constant$6(-30),
25441       strengths,
25442       distanceMin2 = 1,
25443       distanceMax2 = Infinity,
25444       theta2 = 0.81;
25445
25446   function force(_) {
25447     var i, n = nodes.length, tree = quadtree(nodes, x$1, y$1).visitAfter(accumulate);
25448     for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
25449   }
25450
25451   function initialize() {
25452     if (!nodes) return;
25453     var i, n = nodes.length, node;
25454     strengths = new Array(n);
25455     for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
25456   }
25457
25458   function accumulate(quad) {
25459     var strength = 0, q, c, x, y, i;
25460
25461     // For internal nodes, accumulate forces from child quadrants.
25462     if (quad.length) {
25463       for (x = y = i = 0; i < 4; ++i) {
25464         if ((q = quad[i]) && (c = q.value)) {
25465           strength += c, x += c * q.x, y += c * q.y;
25466         }
25467       }
25468       quad.x = x / strength;
25469       quad.y = y / strength;
25470     }
25471
25472     // For leaf nodes, accumulate forces from coincident quadrants.
25473     else {
25474       q = quad;
25475       q.x = q.data.x;
25476       q.y = q.data.y;
25477       do strength += strengths[q.data.index];
25478       while (q = q.next);
25479     }
25480
25481     quad.value = strength;
25482   }
25483
25484   function apply(quad, x1, _, x2) {
25485     if (!quad.value) return true;
25486
25487     var x = quad.x - node.x,
25488         y = quad.y - node.y,
25489         w = x2 - x1,
25490         l = x * x + y * y;
25491
25492     // Apply the Barnes-Hut approximation if possible.
25493     // Limit forces for very close nodes; randomize direction if coincident.
25494     if (w * w / theta2 < l) {
25495       if (l < distanceMax2) {
25496         if (x === 0) x = jiggle(), l += x * x;
25497         if (y === 0) y = jiggle(), l += y * y;
25498         if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
25499         node.vx += x * quad.value * alpha / l;
25500         node.vy += y * quad.value * alpha / l;
25501       }
25502       return true;
25503     }
25504
25505     // Otherwise, process points directly.
25506     else if (quad.length || l >= distanceMax2) return;
25507
25508     // Limit forces for very close nodes; randomize direction if coincident.
25509     if (quad.data !== node || quad.next) {
25510       if (x === 0) x = jiggle(), l += x * x;
25511       if (y === 0) y = jiggle(), l += y * y;
25512       if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
25513     }
25514
25515     do if (quad.data !== node) {
25516       w = strengths[quad.data.index] * alpha / l;
25517       node.vx += x * w;
25518       node.vy += y * w;
25519     } while (quad = quad.next);
25520   }
25521
25522   force.initialize = function(_) {
25523     nodes = _;
25524     initialize();
25525   };
25526
25527   force.strength = function(_) {
25528     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25529   };
25530
25531   force.distanceMin = function(_) {
25532     return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
25533   };
25534
25535   force.distanceMax = function(_) {
25536     return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
25537   };
25538
25539   force.theta = function(_) {
25540     return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
25541   };
25542
25543   return force;
25544 };
25545
25546 var x$2 = function(x) {
25547   var strength = constant$6(0.1),
25548       nodes,
25549       strengths,
25550       xz;
25551
25552   if (typeof x !== "function") x = constant$6(x == null ? 0 : +x);
25553
25554   function force(alpha) {
25555     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25556       node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
25557     }
25558   }
25559
25560   function initialize() {
25561     if (!nodes) return;
25562     var i, n = nodes.length;
25563     strengths = new Array(n);
25564     xz = new Array(n);
25565     for (i = 0; i < n; ++i) {
25566       strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
25567     }
25568   }
25569
25570   force.initialize = function(_) {
25571     nodes = _;
25572     initialize();
25573   };
25574
25575   force.strength = function(_) {
25576     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25577   };
25578
25579   force.x = function(_) {
25580     return arguments.length ? (x = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : x;
25581   };
25582
25583   return force;
25584 };
25585
25586 var y$2 = function(y) {
25587   var strength = constant$6(0.1),
25588       nodes,
25589       strengths,
25590       yz;
25591
25592   if (typeof y !== "function") y = constant$6(y == null ? 0 : +y);
25593
25594   function force(alpha) {
25595     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25596       node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
25597     }
25598   }
25599
25600   function initialize() {
25601     if (!nodes) return;
25602     var i, n = nodes.length;
25603     strengths = new Array(n);
25604     yz = new Array(n);
25605     for (i = 0; i < n; ++i) {
25606       strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
25607     }
25608   }
25609
25610   force.initialize = function(_) {
25611     nodes = _;
25612     initialize();
25613   };
25614
25615   force.strength = function(_) {
25616     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25617   };
25618
25619   force.y = function(_) {
25620     return arguments.length ? (y = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : y;
25621   };
25622
25623   return force;
25624 };
25625
25626 // Computes the decimal coefficient and exponent of the specified number x with
25627 // significant digits p, where x is positive and p is in [1, 21] or undefined.
25628 // For example, formatDecimal(1.23) returns ["123", 0].
25629 var formatDecimal = function(x, p) {
25630   if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
25631   var i, coefficient = x.slice(0, i);
25632
25633   // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
25634   // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
25635   return [
25636     coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
25637     +x.slice(i + 1)
25638   ];
25639 };
25640
25641 var exponent$1 = function(x) {
25642   return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
25643 };
25644
25645 var formatGroup = function(grouping, thousands) {
25646   return function(value, width) {
25647     var i = value.length,
25648         t = [],
25649         j = 0,
25650         g = grouping[0],
25651         length = 0;
25652
25653     while (i > 0 && g > 0) {
25654       if (length + g + 1 > width) g = Math.max(1, width - length);
25655       t.push(value.substring(i -= g, i + g));
25656       if ((length += g + 1) > width) break;
25657       g = grouping[j = (j + 1) % grouping.length];
25658     }
25659
25660     return t.reverse().join(thousands);
25661   };
25662 };
25663
25664 var formatNumerals = function(numerals) {
25665   return function(value) {
25666     return value.replace(/[0-9]/g, function(i) {
25667       return numerals[+i];
25668     });
25669   };
25670 };
25671
25672 var formatDefault = function(x, p) {
25673   x = x.toPrecision(p);
25674
25675   out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
25676     switch (x[i]) {
25677       case ".": i0 = i1 = i; break;
25678       case "0": if (i0 === 0) i0 = i; i1 = i; break;
25679       case "e": break out;
25680       default: if (i0 > 0) i0 = 0; break;
25681     }
25682   }
25683
25684   return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
25685 };
25686
25687 var prefixExponent;
25688
25689 var formatPrefixAuto = function(x, p) {
25690   var d = formatDecimal(x, p);
25691   if (!d) return x + "";
25692   var coefficient = d[0],
25693       exponent = d[1],
25694       i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
25695       n = coefficient.length;
25696   return i === n ? coefficient
25697       : i > n ? coefficient + new Array(i - n + 1).join("0")
25698       : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
25699       : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
25700 };
25701
25702 var formatRounded = function(x, p) {
25703   var d = formatDecimal(x, p);
25704   if (!d) return x + "";
25705   var coefficient = d[0],
25706       exponent = d[1];
25707   return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
25708       : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
25709       : coefficient + new Array(exponent - coefficient.length + 2).join("0");
25710 };
25711
25712 var formatTypes = {
25713   "": formatDefault,
25714   "%": function(x, p) { return (x * 100).toFixed(p); },
25715   "b": function(x) { return Math.round(x).toString(2); },
25716   "c": function(x) { return x + ""; },
25717   "d": function(x) { return Math.round(x).toString(10); },
25718   "e": function(x, p) { return x.toExponential(p); },
25719   "f": function(x, p) { return x.toFixed(p); },
25720   "g": function(x, p) { return x.toPrecision(p); },
25721   "o": function(x) { return Math.round(x).toString(8); },
25722   "p": function(x, p) { return formatRounded(x * 100, p); },
25723   "r": formatRounded,
25724   "s": formatPrefixAuto,
25725   "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
25726   "x": function(x) { return Math.round(x).toString(16); }
25727 };
25728
25729 // [[fill]align][sign][symbol][0][width][,][.precision][type]
25730 var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
25731
25732 function formatSpecifier(specifier) {
25733   return new FormatSpecifier(specifier);
25734 }
25735
25736 formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
25737
25738 function FormatSpecifier(specifier) {
25739   if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
25740
25741   var match,
25742       fill = match[1] || " ",
25743       align = match[2] || ">",
25744       sign = match[3] || "-",
25745       symbol = match[4] || "",
25746       zero = !!match[5],
25747       width = match[6] && +match[6],
25748       comma = !!match[7],
25749       precision = match[8] && +match[8].slice(1),
25750       type = match[9] || "";
25751
25752   // The "n" type is an alias for ",g".
25753   if (type === "n") comma = true, type = "g";
25754
25755   // Map invalid types to the default format.
25756   else if (!formatTypes[type]) type = "";
25757
25758   // If zero fill is specified, padding goes after sign and before digits.
25759   if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
25760
25761   this.fill = fill;
25762   this.align = align;
25763   this.sign = sign;
25764   this.symbol = symbol;
25765   this.zero = zero;
25766   this.width = width;
25767   this.comma = comma;
25768   this.precision = precision;
25769   this.type = type;
25770 }
25771
25772 FormatSpecifier.prototype.toString = function() {
25773   return this.fill
25774       + this.align
25775       + this.sign
25776       + this.symbol
25777       + (this.zero ? "0" : "")
25778       + (this.width == null ? "" : Math.max(1, this.width | 0))
25779       + (this.comma ? "," : "")
25780       + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
25781       + this.type;
25782 };
25783
25784 var identity$3 = function(x) {
25785   return x;
25786 };
25787
25788 var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
25789
25790 var formatLocale = function(locale) {
25791   var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3,
25792       currency = locale.currency,
25793       decimal = locale.decimal,
25794       numerals = locale.numerals ? formatNumerals(locale.numerals) : identity$3,
25795       percent = locale.percent || "%";
25796
25797   function newFormat(specifier) {
25798     specifier = formatSpecifier(specifier);
25799
25800     var fill = specifier.fill,
25801         align = specifier.align,
25802         sign = specifier.sign,
25803         symbol = specifier.symbol,
25804         zero = specifier.zero,
25805         width = specifier.width,
25806         comma = specifier.comma,
25807         precision = specifier.precision,
25808         type = specifier.type;
25809
25810     // Compute the prefix and suffix.
25811     // For SI-prefix, the suffix is lazily computed.
25812     var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
25813         suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? percent : "";
25814
25815     // What format function should we use?
25816     // Is this an integer type?
25817     // Can this type generate exponential notation?
25818     var formatType = formatTypes[type],
25819         maybeSuffix = !type || /[defgprs%]/.test(type);
25820
25821     // Set the default precision if not specified,
25822     // or clamp the specified precision to the supported range.
25823     // For significant precision, it must be in [1, 21].
25824     // For fixed precision, it must be in [0, 20].
25825     precision = precision == null ? (type ? 6 : 12)
25826         : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
25827         : Math.max(0, Math.min(20, precision));
25828
25829     function format(value) {
25830       var valuePrefix = prefix,
25831           valueSuffix = suffix,
25832           i, n, c;
25833
25834       if (type === "c") {
25835         valueSuffix = formatType(value) + valueSuffix;
25836         value = "";
25837       } else {
25838         value = +value;
25839
25840         // Perform the initial formatting.
25841         var valueNegative = value < 0;
25842         value = formatType(Math.abs(value), precision);
25843
25844         // If a negative value rounds to zero during formatting, treat as positive.
25845         if (valueNegative && +value === 0) valueNegative = false;
25846
25847         // Compute the prefix and suffix.
25848         valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
25849         valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
25850
25851         // Break the formatted value into the integer “value” part that can be
25852         // grouped, and fractional or exponential “suffix” part that is not.
25853         if (maybeSuffix) {
25854           i = -1, n = value.length;
25855           while (++i < n) {
25856             if (c = value.charCodeAt(i), 48 > c || c > 57) {
25857               valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
25858               value = value.slice(0, i);
25859               break;
25860             }
25861           }
25862         }
25863       }
25864
25865       // If the fill character is not "0", grouping is applied before padding.
25866       if (comma && !zero) value = group(value, Infinity);
25867
25868       // Compute the padding.
25869       var length = valuePrefix.length + value.length + valueSuffix.length,
25870           padding = length < width ? new Array(width - length + 1).join(fill) : "";
25871
25872       // If the fill character is "0", grouping is applied after padding.
25873       if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
25874
25875       // Reconstruct the final output based on the desired alignment.
25876       switch (align) {
25877         case "<": value = valuePrefix + value + valueSuffix + padding; break;
25878         case "=": value = valuePrefix + padding + value + valueSuffix; break;
25879         case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;
25880         default: value = padding + valuePrefix + value + valueSuffix; break;
25881       }
25882
25883       return numerals(value);
25884     }
25885
25886     format.toString = function() {
25887       return specifier + "";
25888     };
25889
25890     return format;
25891   }
25892
25893   function formatPrefix(specifier, value) {
25894     var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
25895         e = Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3,
25896         k = Math.pow(10, -e),
25897         prefix = prefixes[8 + e / 3];
25898     return function(value) {
25899       return f(k * value) + prefix;
25900     };
25901   }
25902
25903   return {
25904     format: newFormat,
25905     formatPrefix: formatPrefix
25906   };
25907 };
25908
25909 var locale$1;
25910 var format;
25911 var formatPrefix;
25912
25913 defaultLocale({
25914   decimal: ".",
25915   thousands: ",",
25916   grouping: [3],
25917   currency: ["$", ""]
25918 });
25919
25920 function defaultLocale(definition) {
25921   locale$1 = formatLocale(definition);
25922   format = locale$1.format;
25923   formatPrefix = locale$1.formatPrefix;
25924   return locale$1;
25925 }
25926
25927 var precisionFixed = function(step) {
25928   return Math.max(0, -exponent$1(Math.abs(step)));
25929 };
25930
25931 var precisionPrefix = function(step, value) {
25932   return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3 - exponent$1(Math.abs(step)));
25933 };
25934
25935 var precisionRound = function(step, max) {
25936   step = Math.abs(step), max = Math.abs(max) - step;
25937   return Math.max(0, exponent$1(max) - exponent$1(step)) + 1;
25938 };
25939
25940 // Adds floating point numbers with twice the normal precision.
25941 // Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
25942 // Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
25943 // 305–363 (1997).
25944 // Code adapted from GeographicLib by Charles F. F. Karney,
25945 // http://geographiclib.sourceforge.net/
25946
25947 var adder = function() {
25948   return new Adder;
25949 };
25950
25951 function Adder() {
25952   this.reset();
25953 }
25954
25955 Adder.prototype = {
25956   constructor: Adder,
25957   reset: function() {
25958     this.s = // rounded value
25959     this.t = 0; // exact error
25960   },
25961   add: function(y) {
25962     add$1(temp, y, this.t);
25963     add$1(this, temp.s, this.s);
25964     if (this.s) this.t += temp.t;
25965     else this.s = temp.t;
25966   },
25967   valueOf: function() {
25968     return this.s;
25969   }
25970 };
25971
25972 var temp = new Adder;
25973
25974 function add$1(adder, a, b) {
25975   var x = adder.s = a + b,
25976       bv = x - a,
25977       av = x - bv;
25978   adder.t = (a - av) + (b - bv);
25979 }
25980
25981 var epsilon$2 = 1e-6;
25982 var epsilon2$1 = 1e-12;
25983 var pi$3 = Math.PI;
25984 var halfPi$2 = pi$3 / 2;
25985 var quarterPi = pi$3 / 4;
25986 var tau$3 = pi$3 * 2;
25987
25988 var degrees$1 = 180 / pi$3;
25989 var radians = pi$3 / 180;
25990
25991 var abs = Math.abs;
25992 var atan = Math.atan;
25993 var atan2 = Math.atan2;
25994 var cos$1 = Math.cos;
25995 var ceil = Math.ceil;
25996 var exp = Math.exp;
25997
25998 var log = Math.log;
25999 var pow = Math.pow;
26000 var sin$1 = Math.sin;
26001 var sign = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
26002 var sqrt = Math.sqrt;
26003 var tan = Math.tan;
26004
26005 function acos(x) {
26006   return x > 1 ? 0 : x < -1 ? pi$3 : Math.acos(x);
26007 }
26008
26009 function asin(x) {
26010   return x > 1 ? halfPi$2 : x < -1 ? -halfPi$2 : Math.asin(x);
26011 }
26012
26013 function haversin(x) {
26014   return (x = sin$1(x / 2)) * x;
26015 }
26016
26017 function noop$1() {}
26018
26019 function streamGeometry(geometry, stream) {
26020   if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
26021     streamGeometryType[geometry.type](geometry, stream);
26022   }
26023 }
26024
26025 var streamObjectType = {
26026   Feature: function(object, stream) {
26027     streamGeometry(object.geometry, stream);
26028   },
26029   FeatureCollection: function(object, stream) {
26030     var features = object.features, i = -1, n = features.length;
26031     while (++i < n) streamGeometry(features[i].geometry, stream);
26032   }
26033 };
26034
26035 var streamGeometryType = {
26036   Sphere: function(object, stream) {
26037     stream.sphere();
26038   },
26039   Point: function(object, stream) {
26040     object = object.coordinates;
26041     stream.point(object[0], object[1], object[2]);
26042   },
26043   MultiPoint: function(object, stream) {
26044     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26045     while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
26046   },
26047   LineString: function(object, stream) {
26048     streamLine(object.coordinates, stream, 0);
26049   },
26050   MultiLineString: function(object, stream) {
26051     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26052     while (++i < n) streamLine(coordinates[i], stream, 0);
26053   },
26054   Polygon: function(object, stream) {
26055     streamPolygon(object.coordinates, stream);
26056   },
26057   MultiPolygon: function(object, stream) {
26058     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26059     while (++i < n) streamPolygon(coordinates[i], stream);
26060   },
26061   GeometryCollection: function(object, stream) {
26062     var geometries = object.geometries, i = -1, n = geometries.length;
26063     while (++i < n) streamGeometry(geometries[i], stream);
26064   }
26065 };
26066
26067 function streamLine(coordinates, stream, closed) {
26068   var i = -1, n = coordinates.length - closed, coordinate;
26069   stream.lineStart();
26070   while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
26071   stream.lineEnd();
26072 }
26073
26074 function streamPolygon(coordinates, stream) {
26075   var i = -1, n = coordinates.length;
26076   stream.polygonStart();
26077   while (++i < n) streamLine(coordinates[i], stream, 1);
26078   stream.polygonEnd();
26079 }
26080
26081 var geoStream = function(object, stream) {
26082   if (object && streamObjectType.hasOwnProperty(object.type)) {
26083     streamObjectType[object.type](object, stream);
26084   } else {
26085     streamGeometry(object, stream);
26086   }
26087 };
26088
26089 var areaRingSum = adder();
26090
26091 var areaSum = adder();
26092 var lambda00;
26093 var phi00;
26094 var lambda0;
26095 var cosPhi0;
26096 var sinPhi0;
26097
26098 var areaStream = {
26099   point: noop$1,
26100   lineStart: noop$1,
26101   lineEnd: noop$1,
26102   polygonStart: function() {
26103     areaRingSum.reset();
26104     areaStream.lineStart = areaRingStart;
26105     areaStream.lineEnd = areaRingEnd;
26106   },
26107   polygonEnd: function() {
26108     var areaRing = +areaRingSum;
26109     areaSum.add(areaRing < 0 ? tau$3 + areaRing : areaRing);
26110     this.lineStart = this.lineEnd = this.point = noop$1;
26111   },
26112   sphere: function() {
26113     areaSum.add(tau$3);
26114   }
26115 };
26116
26117 function areaRingStart() {
26118   areaStream.point = areaPointFirst;
26119 }
26120
26121 function areaRingEnd() {
26122   areaPoint(lambda00, phi00);
26123 }
26124
26125 function areaPointFirst(lambda, phi) {
26126   areaStream.point = areaPoint;
26127   lambda00 = lambda, phi00 = phi;
26128   lambda *= radians, phi *= radians;
26129   lambda0 = lambda, cosPhi0 = cos$1(phi = phi / 2 + quarterPi), sinPhi0 = sin$1(phi);
26130 }
26131
26132 function areaPoint(lambda, phi) {
26133   lambda *= radians, phi *= radians;
26134   phi = phi / 2 + quarterPi; // half the angular distance from south pole
26135
26136   // Spherical excess E for a spherical triangle with vertices: south pole,
26137   // previous point, current point.  Uses a formula derived from Cagnoli’s
26138   // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
26139   var dLambda = lambda - lambda0,
26140       sdLambda = dLambda >= 0 ? 1 : -1,
26141       adLambda = sdLambda * dLambda,
26142       cosPhi = cos$1(phi),
26143       sinPhi = sin$1(phi),
26144       k = sinPhi0 * sinPhi,
26145       u = cosPhi0 * cosPhi + k * cos$1(adLambda),
26146       v = k * sdLambda * sin$1(adLambda);
26147   areaRingSum.add(atan2(v, u));
26148
26149   // Advance the previous points.
26150   lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
26151 }
26152
26153 var area = function(object) {
26154   areaSum.reset();
26155   geoStream(object, areaStream);
26156   return areaSum * 2;
26157 };
26158
26159 function spherical(cartesian) {
26160   return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
26161 }
26162
26163 function cartesian(spherical) {
26164   var lambda = spherical[0], phi = spherical[1], cosPhi = cos$1(phi);
26165   return [cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi)];
26166 }
26167
26168 function cartesianDot(a, b) {
26169   return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
26170 }
26171
26172 function cartesianCross(a, b) {
26173   return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
26174 }
26175
26176 // TODO return a
26177 function cartesianAddInPlace(a, b) {
26178   a[0] += b[0], a[1] += b[1], a[2] += b[2];
26179 }
26180
26181 function cartesianScale(vector, k) {
26182   return [vector[0] * k, vector[1] * k, vector[2] * k];
26183 }
26184
26185 // TODO return d
26186 function cartesianNormalizeInPlace(d) {
26187   var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
26188   d[0] /= l, d[1] /= l, d[2] /= l;
26189 }
26190
26191 var lambda0$1;
26192 var phi0;
26193 var lambda1;
26194 var phi1;
26195 var lambda2;
26196 var lambda00$1;
26197 var phi00$1;
26198 var p0;
26199 var deltaSum = adder();
26200 var ranges;
26201 var range;
26202
26203 var boundsStream = {
26204   point: boundsPoint,
26205   lineStart: boundsLineStart,
26206   lineEnd: boundsLineEnd,
26207   polygonStart: function() {
26208     boundsStream.point = boundsRingPoint;
26209     boundsStream.lineStart = boundsRingStart;
26210     boundsStream.lineEnd = boundsRingEnd;
26211     deltaSum.reset();
26212     areaStream.polygonStart();
26213   },
26214   polygonEnd: function() {
26215     areaStream.polygonEnd();
26216     boundsStream.point = boundsPoint;
26217     boundsStream.lineStart = boundsLineStart;
26218     boundsStream.lineEnd = boundsLineEnd;
26219     if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
26220     else if (deltaSum > epsilon$2) phi1 = 90;
26221     else if (deltaSum < -epsilon$2) phi0 = -90;
26222     range[0] = lambda0$1, range[1] = lambda1;
26223   }
26224 };
26225
26226 function boundsPoint(lambda, phi) {
26227   ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
26228   if (phi < phi0) phi0 = phi;
26229   if (phi > phi1) phi1 = phi;
26230 }
26231
26232 function linePoint(lambda, phi) {
26233   var p = cartesian([lambda * radians, phi * radians]);
26234   if (p0) {
26235     var normal = cartesianCross(p0, p),
26236         equatorial = [normal[1], -normal[0], 0],
26237         inflection = cartesianCross(equatorial, normal);
26238     cartesianNormalizeInPlace(inflection);
26239     inflection = spherical(inflection);
26240     var delta = lambda - lambda2,
26241         sign$$1 = delta > 0 ? 1 : -1,
26242         lambdai = inflection[0] * degrees$1 * sign$$1,
26243         phii,
26244         antimeridian = abs(delta) > 180;
26245     if (antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) {
26246       phii = inflection[1] * degrees$1;
26247       if (phii > phi1) phi1 = phii;
26248     } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) {
26249       phii = -inflection[1] * degrees$1;
26250       if (phii < phi0) phi0 = phii;
26251     } else {
26252       if (phi < phi0) phi0 = phi;
26253       if (phi > phi1) phi1 = phi;
26254     }
26255     if (antimeridian) {
26256       if (lambda < lambda2) {
26257         if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
26258       } else {
26259         if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
26260       }
26261     } else {
26262       if (lambda1 >= lambda0$1) {
26263         if (lambda < lambda0$1) lambda0$1 = lambda;
26264         if (lambda > lambda1) lambda1 = lambda;
26265       } else {
26266         if (lambda > lambda2) {
26267           if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
26268         } else {
26269           if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
26270         }
26271       }
26272     }
26273   } else {
26274     ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
26275   }
26276   if (phi < phi0) phi0 = phi;
26277   if (phi > phi1) phi1 = phi;
26278   p0 = p, lambda2 = lambda;
26279 }
26280
26281 function boundsLineStart() {
26282   boundsStream.point = linePoint;
26283 }
26284
26285 function boundsLineEnd() {
26286   range[0] = lambda0$1, range[1] = lambda1;
26287   boundsStream.point = boundsPoint;
26288   p0 = null;
26289 }
26290
26291 function boundsRingPoint(lambda, phi) {
26292   if (p0) {
26293     var delta = lambda - lambda2;
26294     deltaSum.add(abs(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
26295   } else {
26296     lambda00$1 = lambda, phi00$1 = phi;
26297   }
26298   areaStream.point(lambda, phi);
26299   linePoint(lambda, phi);
26300 }
26301
26302 function boundsRingStart() {
26303   areaStream.lineStart();
26304 }
26305
26306 function boundsRingEnd() {
26307   boundsRingPoint(lambda00$1, phi00$1);
26308   areaStream.lineEnd();
26309   if (abs(deltaSum) > epsilon$2) lambda0$1 = -(lambda1 = 180);
26310   range[0] = lambda0$1, range[1] = lambda1;
26311   p0 = null;
26312 }
26313
26314 // Finds the left-right distance between two longitudes.
26315 // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
26316 // the distance between ±180° to be 360°.
26317 function angle(lambda0, lambda1) {
26318   return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
26319 }
26320
26321 function rangeCompare(a, b) {
26322   return a[0] - b[0];
26323 }
26324
26325 function rangeContains(range, x) {
26326   return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
26327 }
26328
26329 var bounds = function(feature) {
26330   var i, n, a, b, merged, deltaMax, delta;
26331
26332   phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
26333   ranges = [];
26334   geoStream(feature, boundsStream);
26335
26336   // First, sort ranges by their minimum longitudes.
26337   if (n = ranges.length) {
26338     ranges.sort(rangeCompare);
26339
26340     // Then, merge any ranges that overlap.
26341     for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
26342       b = ranges[i];
26343       if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
26344         if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
26345         if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
26346       } else {
26347         merged.push(a = b);
26348       }
26349     }
26350
26351     // Finally, find the largest gap between the merged ranges.
26352     // The final bounding box will be the inverse of this gap.
26353     for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
26354       b = merged[i];
26355       if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
26356     }
26357   }
26358
26359   ranges = range = null;
26360
26361   return lambda0$1 === Infinity || phi0 === Infinity
26362       ? [[NaN, NaN], [NaN, NaN]]
26363       : [[lambda0$1, phi0], [lambda1, phi1]];
26364 };
26365
26366 var W0;
26367 var W1;
26368 var X0;
26369 var Y0;
26370 var Z0;
26371 var X1;
26372 var Y1;
26373 var Z1;
26374 var X2;
26375 var Y2;
26376 var Z2;
26377 var lambda00$2;
26378 var phi00$2;
26379 var x0;
26380 var y0;
26381 var z0; // previous point
26382
26383 var centroidStream = {
26384   sphere: noop$1,
26385   point: centroidPoint,
26386   lineStart: centroidLineStart,
26387   lineEnd: centroidLineEnd,
26388   polygonStart: function() {
26389     centroidStream.lineStart = centroidRingStart;
26390     centroidStream.lineEnd = centroidRingEnd;
26391   },
26392   polygonEnd: function() {
26393     centroidStream.lineStart = centroidLineStart;
26394     centroidStream.lineEnd = centroidLineEnd;
26395   }
26396 };
26397
26398 // Arithmetic mean of Cartesian vectors.
26399 function centroidPoint(lambda, phi) {
26400   lambda *= radians, phi *= radians;
26401   var cosPhi = cos$1(phi);
26402   centroidPointCartesian(cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi));
26403 }
26404
26405 function centroidPointCartesian(x, y, z) {
26406   ++W0;
26407   X0 += (x - X0) / W0;
26408   Y0 += (y - Y0) / W0;
26409   Z0 += (z - Z0) / W0;
26410 }
26411
26412 function centroidLineStart() {
26413   centroidStream.point = centroidLinePointFirst;
26414 }
26415
26416 function centroidLinePointFirst(lambda, phi) {
26417   lambda *= radians, phi *= radians;
26418   var cosPhi = cos$1(phi);
26419   x0 = cosPhi * cos$1(lambda);
26420   y0 = cosPhi * sin$1(lambda);
26421   z0 = sin$1(phi);
26422   centroidStream.point = centroidLinePoint;
26423   centroidPointCartesian(x0, y0, z0);
26424 }
26425
26426 function centroidLinePoint(lambda, phi) {
26427   lambda *= radians, phi *= radians;
26428   var cosPhi = cos$1(phi),
26429       x = cosPhi * cos$1(lambda),
26430       y = cosPhi * sin$1(lambda),
26431       z = sin$1(phi),
26432       w = atan2(sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
26433   W1 += w;
26434   X1 += w * (x0 + (x0 = x));
26435   Y1 += w * (y0 + (y0 = y));
26436   Z1 += w * (z0 + (z0 = z));
26437   centroidPointCartesian(x0, y0, z0);
26438 }
26439
26440 function centroidLineEnd() {
26441   centroidStream.point = centroidPoint;
26442 }
26443
26444 // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
26445 // J. Applied Mechanics 42, 239 (1975).
26446 function centroidRingStart() {
26447   centroidStream.point = centroidRingPointFirst;
26448 }
26449
26450 function centroidRingEnd() {
26451   centroidRingPoint(lambda00$2, phi00$2);
26452   centroidStream.point = centroidPoint;
26453 }
26454
26455 function centroidRingPointFirst(lambda, phi) {
26456   lambda00$2 = lambda, phi00$2 = phi;
26457   lambda *= radians, phi *= radians;
26458   centroidStream.point = centroidRingPoint;
26459   var cosPhi = cos$1(phi);
26460   x0 = cosPhi * cos$1(lambda);
26461   y0 = cosPhi * sin$1(lambda);
26462   z0 = sin$1(phi);
26463   centroidPointCartesian(x0, y0, z0);
26464 }
26465
26466 function centroidRingPoint(lambda, phi) {
26467   lambda *= radians, phi *= radians;
26468   var cosPhi = cos$1(phi),
26469       x = cosPhi * cos$1(lambda),
26470       y = cosPhi * sin$1(lambda),
26471       z = sin$1(phi),
26472       cx = y0 * z - z0 * y,
26473       cy = z0 * x - x0 * z,
26474       cz = x0 * y - y0 * x,
26475       m = sqrt(cx * cx + cy * cy + cz * cz),
26476       w = asin(m), // line weight = angle
26477       v = m && -w / m; // area weight multiplier
26478   X2 += v * cx;
26479   Y2 += v * cy;
26480   Z2 += v * cz;
26481   W1 += w;
26482   X1 += w * (x0 + (x0 = x));
26483   Y1 += w * (y0 + (y0 = y));
26484   Z1 += w * (z0 + (z0 = z));
26485   centroidPointCartesian(x0, y0, z0);
26486 }
26487
26488 var d3GeoCentroid = function(object) {
26489   W0 = W1 =
26490   X0 = Y0 = Z0 =
26491   X1 = Y1 = Z1 =
26492   X2 = Y2 = Z2 = 0;
26493   geoStream(object, centroidStream);
26494
26495   var x = X2,
26496       y = Y2,
26497       z = Z2,
26498       m = x * x + y * y + z * z;
26499
26500   // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
26501   if (m < epsilon2$1) {
26502     x = X1, y = Y1, z = Z1;
26503     // If the feature has zero length, fall back to arithmetic mean of point vectors.
26504     if (W1 < epsilon$2) x = X0, y = Y0, z = Z0;
26505     m = x * x + y * y + z * z;
26506     // If the feature still has an undefined ccentroid, then return.
26507     if (m < epsilon2$1) return [NaN, NaN];
26508   }
26509
26510   return [atan2(y, x) * degrees$1, asin(z / sqrt(m)) * degrees$1];
26511 };
26512
26513 var constant$7 = function(x) {
26514   return function() {
26515     return x;
26516   };
26517 };
26518
26519 var compose = function(a, b) {
26520
26521   function compose(x, y) {
26522     return x = a(x, y), b(x[0], x[1]);
26523   }
26524
26525   if (a.invert && b.invert) compose.invert = function(x, y) {
26526     return x = b.invert(x, y), x && a.invert(x[0], x[1]);
26527   };
26528
26529   return compose;
26530 };
26531
26532 function rotationIdentity(lambda, phi) {
26533   return [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
26534 }
26535
26536 rotationIdentity.invert = rotationIdentity;
26537
26538 function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
26539   return (deltaLambda %= tau$3) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
26540     : rotationLambda(deltaLambda))
26541     : (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma)
26542     : rotationIdentity);
26543 }
26544
26545 function forwardRotationLambda(deltaLambda) {
26546   return function(lambda, phi) {
26547     return lambda += deltaLambda, [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
26548   };
26549 }
26550
26551 function rotationLambda(deltaLambda) {
26552   var rotation = forwardRotationLambda(deltaLambda);
26553   rotation.invert = forwardRotationLambda(-deltaLambda);
26554   return rotation;
26555 }
26556
26557 function rotationPhiGamma(deltaPhi, deltaGamma) {
26558   var cosDeltaPhi = cos$1(deltaPhi),
26559       sinDeltaPhi = sin$1(deltaPhi),
26560       cosDeltaGamma = cos$1(deltaGamma),
26561       sinDeltaGamma = sin$1(deltaGamma);
26562
26563   function rotation(lambda, phi) {
26564     var cosPhi = cos$1(phi),
26565         x = cos$1(lambda) * cosPhi,
26566         y = sin$1(lambda) * cosPhi,
26567         z = sin$1(phi),
26568         k = z * cosDeltaPhi + x * sinDeltaPhi;
26569     return [
26570       atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
26571       asin(k * cosDeltaGamma + y * sinDeltaGamma)
26572     ];
26573   }
26574
26575   rotation.invert = function(lambda, phi) {
26576     var cosPhi = cos$1(phi),
26577         x = cos$1(lambda) * cosPhi,
26578         y = sin$1(lambda) * cosPhi,
26579         z = sin$1(phi),
26580         k = z * cosDeltaGamma - y * sinDeltaGamma;
26581     return [
26582       atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
26583       asin(k * cosDeltaPhi - x * sinDeltaPhi)
26584     ];
26585   };
26586
26587   return rotation;
26588 }
26589
26590 var rotation = function(rotate) {
26591   rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
26592
26593   function forward(coordinates) {
26594     coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
26595     return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
26596   }
26597
26598   forward.invert = function(coordinates) {
26599     coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
26600     return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
26601   };
26602
26603   return forward;
26604 };
26605
26606 // Generates a circle centered at [0°, 0°], with a given radius and precision.
26607 function circleStream(stream, radius, delta, direction, t0, t1) {
26608   if (!delta) return;
26609   var cosRadius = cos$1(radius),
26610       sinRadius = sin$1(radius),
26611       step = direction * delta;
26612   if (t0 == null) {
26613     t0 = radius + direction * tau$3;
26614     t1 = radius - step / 2;
26615   } else {
26616     t0 = circleRadius(cosRadius, t0);
26617     t1 = circleRadius(cosRadius, t1);
26618     if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$3;
26619   }
26620   for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
26621     point = spherical([cosRadius, -sinRadius * cos$1(t), -sinRadius * sin$1(t)]);
26622     stream.point(point[0], point[1]);
26623   }
26624 }
26625
26626 // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
26627 function circleRadius(cosRadius, point) {
26628   point = cartesian(point), point[0] -= cosRadius;
26629   cartesianNormalizeInPlace(point);
26630   var radius = acos(-point[1]);
26631   return ((-point[2] < 0 ? -radius : radius) + tau$3 - epsilon$2) % tau$3;
26632 }
26633
26634 var circle = function() {
26635   var center = constant$7([0, 0]),
26636       radius = constant$7(90),
26637       precision = constant$7(6),
26638       ring,
26639       rotate,
26640       stream = {point: point};
26641
26642   function point(x, y) {
26643     ring.push(x = rotate(x, y));
26644     x[0] *= degrees$1, x[1] *= degrees$1;
26645   }
26646
26647   function circle() {
26648     var c = center.apply(this, arguments),
26649         r = radius.apply(this, arguments) * radians,
26650         p = precision.apply(this, arguments) * radians;
26651     ring = [];
26652     rotate = rotateRadians(-c[0] * radians, -c[1] * radians, 0).invert;
26653     circleStream(stream, r, p, 1);
26654     c = {type: "Polygon", coordinates: [ring]};
26655     ring = rotate = null;
26656     return c;
26657   }
26658
26659   circle.center = function(_) {
26660     return arguments.length ? (center = typeof _ === "function" ? _ : constant$7([+_[0], +_[1]]), circle) : center;
26661   };
26662
26663   circle.radius = function(_) {
26664     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$7(+_), circle) : radius;
26665   };
26666
26667   circle.precision = function(_) {
26668     return arguments.length ? (precision = typeof _ === "function" ? _ : constant$7(+_), circle) : precision;
26669   };
26670
26671   return circle;
26672 };
26673
26674 var clipBuffer = function() {
26675   var lines = [],
26676       line;
26677   return {
26678     point: function(x, y) {
26679       line.push([x, y]);
26680     },
26681     lineStart: function() {
26682       lines.push(line = []);
26683     },
26684     lineEnd: noop$1,
26685     rejoin: function() {
26686       if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
26687     },
26688     result: function() {
26689       var result = lines;
26690       lines = [];
26691       line = null;
26692       return result;
26693     }
26694   };
26695 };
26696
26697 var clipLine = function(a, b, x0, y0, x1, y1) {
26698   var ax = a[0],
26699       ay = a[1],
26700       bx = b[0],
26701       by = b[1],
26702       t0 = 0,
26703       t1 = 1,
26704       dx = bx - ax,
26705       dy = by - ay,
26706       r;
26707
26708   r = x0 - ax;
26709   if (!dx && r > 0) return;
26710   r /= dx;
26711   if (dx < 0) {
26712     if (r < t0) return;
26713     if (r < t1) t1 = r;
26714   } else if (dx > 0) {
26715     if (r > t1) return;
26716     if (r > t0) t0 = r;
26717   }
26718
26719   r = x1 - ax;
26720   if (!dx && r < 0) return;
26721   r /= dx;
26722   if (dx < 0) {
26723     if (r > t1) return;
26724     if (r > t0) t0 = r;
26725   } else if (dx > 0) {
26726     if (r < t0) return;
26727     if (r < t1) t1 = r;
26728   }
26729
26730   r = y0 - ay;
26731   if (!dy && r > 0) return;
26732   r /= dy;
26733   if (dy < 0) {
26734     if (r < t0) return;
26735     if (r < t1) t1 = r;
26736   } else if (dy > 0) {
26737     if (r > t1) return;
26738     if (r > t0) t0 = r;
26739   }
26740
26741   r = y1 - ay;
26742   if (!dy && r < 0) return;
26743   r /= dy;
26744   if (dy < 0) {
26745     if (r > t1) return;
26746     if (r > t0) t0 = r;
26747   } else if (dy > 0) {
26748     if (r < t0) return;
26749     if (r < t1) t1 = r;
26750   }
26751
26752   if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
26753   if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
26754   return true;
26755 };
26756
26757 var pointEqual = function(a, b) {
26758   return abs(a[0] - b[0]) < epsilon$2 && abs(a[1] - b[1]) < epsilon$2;
26759 };
26760
26761 function Intersection(point, points, other, entry) {
26762   this.x = point;
26763   this.z = points;
26764   this.o = other; // another intersection
26765   this.e = entry; // is an entry?
26766   this.v = false; // visited
26767   this.n = this.p = null; // next & previous
26768 }
26769
26770 // A generalized polygon clipping algorithm: given a polygon that has been cut
26771 // into its visible line segments, and rejoins the segments by interpolating
26772 // along the clip edge.
26773 var clipPolygon = function(segments, compareIntersection, startInside, interpolate, stream) {
26774   var subject = [],
26775       clip = [],
26776       i,
26777       n;
26778
26779   segments.forEach(function(segment) {
26780     if ((n = segment.length - 1) <= 0) return;
26781     var n, p0 = segment[0], p1 = segment[n], x;
26782
26783     // If the first and last points of a segment are coincident, then treat as a
26784     // closed ring. TODO if all rings are closed, then the winding order of the
26785     // exterior ring should be checked.
26786     if (pointEqual(p0, p1)) {
26787       stream.lineStart();
26788       for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
26789       stream.lineEnd();
26790       return;
26791     }
26792
26793     subject.push(x = new Intersection(p0, segment, null, true));
26794     clip.push(x.o = new Intersection(p0, null, x, false));
26795     subject.push(x = new Intersection(p1, segment, null, false));
26796     clip.push(x.o = new Intersection(p1, null, x, true));
26797   });
26798
26799   if (!subject.length) return;
26800
26801   clip.sort(compareIntersection);
26802   link$1(subject);
26803   link$1(clip);
26804
26805   for (i = 0, n = clip.length; i < n; ++i) {
26806     clip[i].e = startInside = !startInside;
26807   }
26808
26809   var start = subject[0],
26810       points,
26811       point;
26812
26813   while (1) {
26814     // Find first unvisited intersection.
26815     var current = start,
26816         isSubject = true;
26817     while (current.v) if ((current = current.n) === start) return;
26818     points = current.z;
26819     stream.lineStart();
26820     do {
26821       current.v = current.o.v = true;
26822       if (current.e) {
26823         if (isSubject) {
26824           for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]);
26825         } else {
26826           interpolate(current.x, current.n.x, 1, stream);
26827         }
26828         current = current.n;
26829       } else {
26830         if (isSubject) {
26831           points = current.p.z;
26832           for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]);
26833         } else {
26834           interpolate(current.x, current.p.x, -1, stream);
26835         }
26836         current = current.p;
26837       }
26838       current = current.o;
26839       points = current.z;
26840       isSubject = !isSubject;
26841     } while (!current.v);
26842     stream.lineEnd();
26843   }
26844 };
26845
26846 function link$1(array) {
26847   if (!(n = array.length)) return;
26848   var n,
26849       i = 0,
26850       a = array[0],
26851       b;
26852   while (++i < n) {
26853     a.n = b = array[i];
26854     b.p = a;
26855     a = b;
26856   }
26857   a.n = b = array[0];
26858   b.p = a;
26859 }
26860
26861 var clipMax = 1e9;
26862 var clipMin = -clipMax;
26863
26864 // TODO Use d3-polygon’s polygonContains here for the ring check?
26865 // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
26866
26867 function clipExtent(x0, y0, x1, y1) {
26868
26869   function visible(x, y) {
26870     return x0 <= x && x <= x1 && y0 <= y && y <= y1;
26871   }
26872
26873   function interpolate(from, to, direction, stream) {
26874     var a = 0, a1 = 0;
26875     if (from == null
26876         || (a = corner(from, direction)) !== (a1 = corner(to, direction))
26877         || comparePoint(from, to) < 0 ^ direction > 0) {
26878       do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
26879       while ((a = (a + direction + 4) % 4) !== a1);
26880     } else {
26881       stream.point(to[0], to[1]);
26882     }
26883   }
26884
26885   function corner(p, direction) {
26886     return abs(p[0] - x0) < epsilon$2 ? direction > 0 ? 0 : 3
26887         : abs(p[0] - x1) < epsilon$2 ? direction > 0 ? 2 : 1
26888         : abs(p[1] - y0) < epsilon$2 ? direction > 0 ? 1 : 0
26889         : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
26890   }
26891
26892   function compareIntersection(a, b) {
26893     return comparePoint(a.x, b.x);
26894   }
26895
26896   function comparePoint(a, b) {
26897     var ca = corner(a, 1),
26898         cb = corner(b, 1);
26899     return ca !== cb ? ca - cb
26900         : ca === 0 ? b[1] - a[1]
26901         : ca === 1 ? a[0] - b[0]
26902         : ca === 2 ? a[1] - b[1]
26903         : b[0] - a[0];
26904   }
26905
26906   return function(stream) {
26907     var activeStream = stream,
26908         bufferStream = clipBuffer(),
26909         segments,
26910         polygon,
26911         ring,
26912         x__, y__, v__, // first point
26913         x_, y_, v_, // previous point
26914         first,
26915         clean;
26916
26917     var clipStream = {
26918       point: point,
26919       lineStart: lineStart,
26920       lineEnd: lineEnd,
26921       polygonStart: polygonStart,
26922       polygonEnd: polygonEnd
26923     };
26924
26925     function point(x, y) {
26926       if (visible(x, y)) activeStream.point(x, y);
26927     }
26928
26929     function polygonInside() {
26930       var winding = 0;
26931
26932       for (var i = 0, n = polygon.length; i < n; ++i) {
26933         for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
26934           a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
26935           if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; }
26936           else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; }
26937         }
26938       }
26939
26940       return winding;
26941     }
26942
26943     // Buffer geometry within a polygon and then clip it en masse.
26944     function polygonStart() {
26945       activeStream = bufferStream, segments = [], polygon = [], clean = true;
26946     }
26947
26948     function polygonEnd() {
26949       var startInside = polygonInside(),
26950           cleanInside = clean && startInside,
26951           visible = (segments = merge(segments)).length;
26952       if (cleanInside || visible) {
26953         stream.polygonStart();
26954         if (cleanInside) {
26955           stream.lineStart();
26956           interpolate(null, null, 1, stream);
26957           stream.lineEnd();
26958         }
26959         if (visible) {
26960           clipPolygon(segments, compareIntersection, startInside, interpolate, stream);
26961         }
26962         stream.polygonEnd();
26963       }
26964       activeStream = stream, segments = polygon = ring = null;
26965     }
26966
26967     function lineStart() {
26968       clipStream.point = linePoint;
26969       if (polygon) polygon.push(ring = []);
26970       first = true;
26971       v_ = false;
26972       x_ = y_ = NaN;
26973     }
26974
26975     // TODO rather than special-case polygons, simply handle them separately.
26976     // Ideally, coincident intersection points should be jittered to avoid
26977     // clipping issues.
26978     function lineEnd() {
26979       if (segments) {
26980         linePoint(x__, y__);
26981         if (v__ && v_) bufferStream.rejoin();
26982         segments.push(bufferStream.result());
26983       }
26984       clipStream.point = point;
26985       if (v_) activeStream.lineEnd();
26986     }
26987
26988     function linePoint(x, y) {
26989       var v = visible(x, y);
26990       if (polygon) ring.push([x, y]);
26991       if (first) {
26992         x__ = x, y__ = y, v__ = v;
26993         first = false;
26994         if (v) {
26995           activeStream.lineStart();
26996           activeStream.point(x, y);
26997         }
26998       } else {
26999         if (v && v_) activeStream.point(x, y);
27000         else {
27001           var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
27002               b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
27003           if (clipLine(a, b, x0, y0, x1, y1)) {
27004             if (!v_) {
27005               activeStream.lineStart();
27006               activeStream.point(a[0], a[1]);
27007             }
27008             activeStream.point(b[0], b[1]);
27009             if (!v) activeStream.lineEnd();
27010             clean = false;
27011           } else if (v) {
27012             activeStream.lineStart();
27013             activeStream.point(x, y);
27014             clean = false;
27015           }
27016         }
27017       }
27018       x_ = x, y_ = y, v_ = v;
27019     }
27020
27021     return clipStream;
27022   };
27023 }
27024
27025 var extent$1 = function() {
27026   var x0 = 0,
27027       y0 = 0,
27028       x1 = 960,
27029       y1 = 500,
27030       cache,
27031       cacheStream,
27032       clip;
27033
27034   return clip = {
27035     stream: function(stream) {
27036       return cache && cacheStream === stream ? cache : cache = clipExtent(x0, y0, x1, y1)(cacheStream = stream);
27037     },
27038     extent: function(_) {
27039       return arguments.length ? (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1], cache = cacheStream = null, clip) : [[x0, y0], [x1, y1]];
27040     }
27041   };
27042 };
27043
27044 var sum$1 = adder();
27045
27046 var polygonContains = function(polygon, point) {
27047   var lambda = point[0],
27048       phi = point[1],
27049       normal = [sin$1(lambda), -cos$1(lambda), 0],
27050       angle = 0,
27051       winding = 0;
27052
27053   sum$1.reset();
27054
27055   for (var i = 0, n = polygon.length; i < n; ++i) {
27056     if (!(m = (ring = polygon[i]).length)) continue;
27057     var ring,
27058         m,
27059         point0 = ring[m - 1],
27060         lambda0 = point0[0],
27061         phi0 = point0[1] / 2 + quarterPi,
27062         sinPhi0 = sin$1(phi0),
27063         cosPhi0 = cos$1(phi0);
27064
27065     for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
27066       var point1 = ring[j],
27067           lambda1 = point1[0],
27068           phi1 = point1[1] / 2 + quarterPi,
27069           sinPhi1 = sin$1(phi1),
27070           cosPhi1 = cos$1(phi1),
27071           delta = lambda1 - lambda0,
27072           sign$$1 = delta >= 0 ? 1 : -1,
27073           absDelta = sign$$1 * delta,
27074           antimeridian = absDelta > pi$3,
27075           k = sinPhi0 * sinPhi1;
27076
27077       sum$1.add(atan2(k * sign$$1 * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta)));
27078       angle += antimeridian ? delta + sign$$1 * tau$3 : delta;
27079
27080       // Are the longitudes either side of the point’s meridian (lambda),
27081       // and are the latitudes smaller than the parallel (phi)?
27082       if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
27083         var arc = cartesianCross(cartesian(point0), cartesian(point1));
27084         cartesianNormalizeInPlace(arc);
27085         var intersection = cartesianCross(normal, arc);
27086         cartesianNormalizeInPlace(intersection);
27087         var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
27088         if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
27089           winding += antimeridian ^ delta >= 0 ? 1 : -1;
27090         }
27091       }
27092     }
27093   }
27094
27095   // First, determine whether the South pole is inside or outside:
27096   //
27097   // It is inside if:
27098   // * the polygon winds around it in a clockwise direction.
27099   // * the polygon does not (cumulatively) wind around it, but has a negative
27100   //   (counter-clockwise) area.
27101   //
27102   // Second, count the (signed) number of times a segment crosses a lambda
27103   // from the point to the South pole.  If it is zero, then the point is the
27104   // same side as the South pole.
27105
27106   return (angle < -epsilon$2 || angle < epsilon$2 && sum$1 < -epsilon$2) ^ (winding & 1);
27107 };
27108
27109 var lengthSum = adder();
27110 var lambda0$2;
27111 var sinPhi0$1;
27112 var cosPhi0$1;
27113
27114 var lengthStream = {
27115   sphere: noop$1,
27116   point: noop$1,
27117   lineStart: lengthLineStart,
27118   lineEnd: noop$1,
27119   polygonStart: noop$1,
27120   polygonEnd: noop$1
27121 };
27122
27123 function lengthLineStart() {
27124   lengthStream.point = lengthPointFirst;
27125   lengthStream.lineEnd = lengthLineEnd;
27126 }
27127
27128 function lengthLineEnd() {
27129   lengthStream.point = lengthStream.lineEnd = noop$1;
27130 }
27131
27132 function lengthPointFirst(lambda, phi) {
27133   lambda *= radians, phi *= radians;
27134   lambda0$2 = lambda, sinPhi0$1 = sin$1(phi), cosPhi0$1 = cos$1(phi);
27135   lengthStream.point = lengthPoint;
27136 }
27137
27138 function lengthPoint(lambda, phi) {
27139   lambda *= radians, phi *= radians;
27140   var sinPhi = sin$1(phi),
27141       cosPhi = cos$1(phi),
27142       delta = abs(lambda - lambda0$2),
27143       cosDelta = cos$1(delta),
27144       sinDelta = sin$1(delta),
27145       x = cosPhi * sinDelta,
27146       y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
27147       z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
27148   lengthSum.add(atan2(sqrt(x * x + y * y), z));
27149   lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
27150 }
27151
27152 var d3GeoLength = function(object) {
27153   lengthSum.reset();
27154   geoStream(object, lengthStream);
27155   return +lengthSum;
27156 };
27157
27158 var coordinates = [null, null];
27159 var object$1 = {type: "LineString", coordinates: coordinates};
27160
27161 var distance = function(a, b) {
27162   coordinates[0] = a;
27163   coordinates[1] = b;
27164   return d3GeoLength(object$1);
27165 };
27166
27167 var containsObjectType = {
27168   Feature: function(object, point) {
27169     return containsGeometry(object.geometry, point);
27170   },
27171   FeatureCollection: function(object, point) {
27172     var features = object.features, i = -1, n = features.length;
27173     while (++i < n) if (containsGeometry(features[i].geometry, point)) return true;
27174     return false;
27175   }
27176 };
27177
27178 var containsGeometryType = {
27179   Sphere: function() {
27180     return true;
27181   },
27182   Point: function(object, point) {
27183     return containsPoint(object.coordinates, point);
27184   },
27185   MultiPoint: function(object, point) {
27186     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27187     while (++i < n) if (containsPoint(coordinates[i], point)) return true;
27188     return false;
27189   },
27190   LineString: function(object, point) {
27191     return containsLine(object.coordinates, point);
27192   },
27193   MultiLineString: function(object, point) {
27194     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27195     while (++i < n) if (containsLine(coordinates[i], point)) return true;
27196     return false;
27197   },
27198   Polygon: function(object, point) {
27199     return containsPolygon(object.coordinates, point);
27200   },
27201   MultiPolygon: function(object, point) {
27202     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27203     while (++i < n) if (containsPolygon(coordinates[i], point)) return true;
27204     return false;
27205   },
27206   GeometryCollection: function(object, point) {
27207     var geometries = object.geometries, i = -1, n = geometries.length;
27208     while (++i < n) if (containsGeometry(geometries[i], point)) return true;
27209     return false;
27210   }
27211 };
27212
27213 function containsGeometry(geometry, point) {
27214   return geometry && containsGeometryType.hasOwnProperty(geometry.type)
27215       ? containsGeometryType[geometry.type](geometry, point)
27216       : false;
27217 }
27218
27219 function containsPoint(coordinates, point) {
27220   return distance(coordinates, point) === 0;
27221 }
27222
27223 function containsLine(coordinates, point) {
27224   var ab = distance(coordinates[0], coordinates[1]),
27225       ao = distance(coordinates[0], point),
27226       ob = distance(point, coordinates[1]);
27227   return ao + ob <= ab + epsilon$2;
27228 }
27229
27230 function containsPolygon(coordinates, point) {
27231   return !!polygonContains(coordinates.map(ringRadians), pointRadians(point));
27232 }
27233
27234 function ringRadians(ring) {
27235   return ring = ring.map(pointRadians), ring.pop(), ring;
27236 }
27237
27238 function pointRadians(point) {
27239   return [point[0] * radians, point[1] * radians];
27240 }
27241
27242 var contains = function(object, point) {
27243   return (object && containsObjectType.hasOwnProperty(object.type)
27244       ? containsObjectType[object.type]
27245       : containsGeometry)(object, point);
27246 };
27247
27248 function graticuleX(y0, y1, dy) {
27249   var y = sequence(y0, y1 - epsilon$2, dy).concat(y1);
27250   return function(x) { return y.map(function(y) { return [x, y]; }); };
27251 }
27252
27253 function graticuleY(x0, x1, dx) {
27254   var x = sequence(x0, x1 - epsilon$2, dx).concat(x1);
27255   return function(y) { return x.map(function(x) { return [x, y]; }); };
27256 }
27257
27258 function graticule() {
27259   var x1, x0, X1, X0,
27260       y1, y0, Y1, Y0,
27261       dx = 10, dy = dx, DX = 90, DY = 360,
27262       x, y, X, Y,
27263       precision = 2.5;
27264
27265   function graticule() {
27266     return {type: "MultiLineString", coordinates: lines()};
27267   }
27268
27269   function lines() {
27270     return sequence(ceil(X0 / DX) * DX, X1, DX).map(X)
27271         .concat(sequence(ceil(Y0 / DY) * DY, Y1, DY).map(Y))
27272         .concat(sequence(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs(x % DX) > epsilon$2; }).map(x))
27273         .concat(sequence(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs(y % DY) > epsilon$2; }).map(y));
27274   }
27275
27276   graticule.lines = function() {
27277     return lines().map(function(coordinates) { return {type: "LineString", coordinates: coordinates}; });
27278   };
27279
27280   graticule.outline = function() {
27281     return {
27282       type: "Polygon",
27283       coordinates: [
27284         X(X0).concat(
27285         Y(Y1).slice(1),
27286         X(X1).reverse().slice(1),
27287         Y(Y0).reverse().slice(1))
27288       ]
27289     };
27290   };
27291
27292   graticule.extent = function(_) {
27293     if (!arguments.length) return graticule.extentMinor();
27294     return graticule.extentMajor(_).extentMinor(_);
27295   };
27296
27297   graticule.extentMajor = function(_) {
27298     if (!arguments.length) return [[X0, Y0], [X1, Y1]];
27299     X0 = +_[0][0], X1 = +_[1][0];
27300     Y0 = +_[0][1], Y1 = +_[1][1];
27301     if (X0 > X1) _ = X0, X0 = X1, X1 = _;
27302     if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
27303     return graticule.precision(precision);
27304   };
27305
27306   graticule.extentMinor = function(_) {
27307     if (!arguments.length) return [[x0, y0], [x1, y1]];
27308     x0 = +_[0][0], x1 = +_[1][0];
27309     y0 = +_[0][1], y1 = +_[1][1];
27310     if (x0 > x1) _ = x0, x0 = x1, x1 = _;
27311     if (y0 > y1) _ = y0, y0 = y1, y1 = _;
27312     return graticule.precision(precision);
27313   };
27314
27315   graticule.step = function(_) {
27316     if (!arguments.length) return graticule.stepMinor();
27317     return graticule.stepMajor(_).stepMinor(_);
27318   };
27319
27320   graticule.stepMajor = function(_) {
27321     if (!arguments.length) return [DX, DY];
27322     DX = +_[0], DY = +_[1];
27323     return graticule;
27324   };
27325
27326   graticule.stepMinor = function(_) {
27327     if (!arguments.length) return [dx, dy];
27328     dx = +_[0], dy = +_[1];
27329     return graticule;
27330   };
27331
27332   graticule.precision = function(_) {
27333     if (!arguments.length) return precision;
27334     precision = +_;
27335     x = graticuleX(y0, y1, 90);
27336     y = graticuleY(x0, x1, precision);
27337     X = graticuleX(Y0, Y1, 90);
27338     Y = graticuleY(X0, X1, precision);
27339     return graticule;
27340   };
27341
27342   return graticule
27343       .extentMajor([[-180, -90 + epsilon$2], [180, 90 - epsilon$2]])
27344       .extentMinor([[-180, -80 - epsilon$2], [180, 80 + epsilon$2]]);
27345 }
27346
27347 function graticule10() {
27348   return graticule()();
27349 }
27350
27351 var interpolate$1 = function(a, b) {
27352   var x0 = a[0] * radians,
27353       y0 = a[1] * radians,
27354       x1 = b[0] * radians,
27355       y1 = b[1] * radians,
27356       cy0 = cos$1(y0),
27357       sy0 = sin$1(y0),
27358       cy1 = cos$1(y1),
27359       sy1 = sin$1(y1),
27360       kx0 = cy0 * cos$1(x0),
27361       ky0 = cy0 * sin$1(x0),
27362       kx1 = cy1 * cos$1(x1),
27363       ky1 = cy1 * sin$1(x1),
27364       d = 2 * asin(sqrt(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
27365       k = sin$1(d);
27366
27367   var interpolate = d ? function(t) {
27368     var B = sin$1(t *= d) / k,
27369         A = sin$1(d - t) / k,
27370         x = A * kx0 + B * kx1,
27371         y = A * ky0 + B * ky1,
27372         z = A * sy0 + B * sy1;
27373     return [
27374       atan2(y, x) * degrees$1,
27375       atan2(z, sqrt(x * x + y * y)) * degrees$1
27376     ];
27377   } : function() {
27378     return [x0 * degrees$1, y0 * degrees$1];
27379   };
27380
27381   interpolate.distance = d;
27382
27383   return interpolate;
27384 };
27385
27386 var identity$4 = function(x) {
27387   return x;
27388 };
27389
27390 var areaSum$1 = adder();
27391 var areaRingSum$1 = adder();
27392 var x00;
27393 var y00;
27394 var x0$1;
27395 var y0$1;
27396
27397 var areaStream$1 = {
27398   point: noop$1,
27399   lineStart: noop$1,
27400   lineEnd: noop$1,
27401   polygonStart: function() {
27402     areaStream$1.lineStart = areaRingStart$1;
27403     areaStream$1.lineEnd = areaRingEnd$1;
27404   },
27405   polygonEnd: function() {
27406     areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop$1;
27407     areaSum$1.add(abs(areaRingSum$1));
27408     areaRingSum$1.reset();
27409   },
27410   result: function() {
27411     var area = areaSum$1 / 2;
27412     areaSum$1.reset();
27413     return area;
27414   }
27415 };
27416
27417 function areaRingStart$1() {
27418   areaStream$1.point = areaPointFirst$1;
27419 }
27420
27421 function areaPointFirst$1(x, y) {
27422   areaStream$1.point = areaPoint$1;
27423   x00 = x0$1 = x, y00 = y0$1 = y;
27424 }
27425
27426 function areaPoint$1(x, y) {
27427   areaRingSum$1.add(y0$1 * x - x0$1 * y);
27428   x0$1 = x, y0$1 = y;
27429 }
27430
27431 function areaRingEnd$1() {
27432   areaPoint$1(x00, y00);
27433 }
27434
27435 var x0$2 = Infinity;
27436 var y0$2 = x0$2;
27437 var x1 = -x0$2;
27438 var y1 = x1;
27439
27440 var boundsStream$1 = {
27441   point: boundsPoint$1,
27442   lineStart: noop$1,
27443   lineEnd: noop$1,
27444   polygonStart: noop$1,
27445   polygonEnd: noop$1,
27446   result: function() {
27447     var bounds = [[x0$2, y0$2], [x1, y1]];
27448     x1 = y1 = -(y0$2 = x0$2 = Infinity);
27449     return bounds;
27450   }
27451 };
27452
27453 function boundsPoint$1(x, y) {
27454   if (x < x0$2) x0$2 = x;
27455   if (x > x1) x1 = x;
27456   if (y < y0$2) y0$2 = y;
27457   if (y > y1) y1 = y;
27458 }
27459
27460 // TODO Enforce positive area for exterior, negative area for interior?
27461
27462 var X0$1 = 0;
27463 var Y0$1 = 0;
27464 var Z0$1 = 0;
27465 var X1$1 = 0;
27466 var Y1$1 = 0;
27467 var Z1$1 = 0;
27468 var X2$1 = 0;
27469 var Y2$1 = 0;
27470 var Z2$1 = 0;
27471 var x00$1;
27472 var y00$1;
27473 var x0$3;
27474 var y0$3;
27475
27476 var centroidStream$1 = {
27477   point: centroidPoint$1,
27478   lineStart: centroidLineStart$1,
27479   lineEnd: centroidLineEnd$1,
27480   polygonStart: function() {
27481     centroidStream$1.lineStart = centroidRingStart$1;
27482     centroidStream$1.lineEnd = centroidRingEnd$1;
27483   },
27484   polygonEnd: function() {
27485     centroidStream$1.point = centroidPoint$1;
27486     centroidStream$1.lineStart = centroidLineStart$1;
27487     centroidStream$1.lineEnd = centroidLineEnd$1;
27488   },
27489   result: function() {
27490     var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1]
27491         : Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1]
27492         : Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1]
27493         : [NaN, NaN];
27494     X0$1 = Y0$1 = Z0$1 =
27495     X1$1 = Y1$1 = Z1$1 =
27496     X2$1 = Y2$1 = Z2$1 = 0;
27497     return centroid;
27498   }
27499 };
27500
27501 function centroidPoint$1(x, y) {
27502   X0$1 += x;
27503   Y0$1 += y;
27504   ++Z0$1;
27505 }
27506
27507 function centroidLineStart$1() {
27508   centroidStream$1.point = centroidPointFirstLine;
27509 }
27510
27511 function centroidPointFirstLine(x, y) {
27512   centroidStream$1.point = centroidPointLine;
27513   centroidPoint$1(x0$3 = x, y0$3 = y);
27514 }
27515
27516 function centroidPointLine(x, y) {
27517   var dx = x - x0$3, dy = y - y0$3, z = sqrt(dx * dx + dy * dy);
27518   X1$1 += z * (x0$3 + x) / 2;
27519   Y1$1 += z * (y0$3 + y) / 2;
27520   Z1$1 += z;
27521   centroidPoint$1(x0$3 = x, y0$3 = y);
27522 }
27523
27524 function centroidLineEnd$1() {
27525   centroidStream$1.point = centroidPoint$1;
27526 }
27527
27528 function centroidRingStart$1() {
27529   centroidStream$1.point = centroidPointFirstRing;
27530 }
27531
27532 function centroidRingEnd$1() {
27533   centroidPointRing(x00$1, y00$1);
27534 }
27535
27536 function centroidPointFirstRing(x, y) {
27537   centroidStream$1.point = centroidPointRing;
27538   centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
27539 }
27540
27541 function centroidPointRing(x, y) {
27542   var dx = x - x0$3,
27543       dy = y - y0$3,
27544       z = sqrt(dx * dx + dy * dy);
27545
27546   X1$1 += z * (x0$3 + x) / 2;
27547   Y1$1 += z * (y0$3 + y) / 2;
27548   Z1$1 += z;
27549
27550   z = y0$3 * x - x0$3 * y;
27551   X2$1 += z * (x0$3 + x);
27552   Y2$1 += z * (y0$3 + y);
27553   Z2$1 += z * 3;
27554   centroidPoint$1(x0$3 = x, y0$3 = y);
27555 }
27556
27557 function PathContext(context) {
27558   this._context = context;
27559 }
27560
27561 PathContext.prototype = {
27562   _radius: 4.5,
27563   pointRadius: function(_) {
27564     return this._radius = _, this;
27565   },
27566   polygonStart: function() {
27567     this._line = 0;
27568   },
27569   polygonEnd: function() {
27570     this._line = NaN;
27571   },
27572   lineStart: function() {
27573     this._point = 0;
27574   },
27575   lineEnd: function() {
27576     if (this._line === 0) this._context.closePath();
27577     this._point = NaN;
27578   },
27579   point: function(x, y) {
27580     switch (this._point) {
27581       case 0: {
27582         this._context.moveTo(x, y);
27583         this._point = 1;
27584         break;
27585       }
27586       case 1: {
27587         this._context.lineTo(x, y);
27588         break;
27589       }
27590       default: {
27591         this._context.moveTo(x + this._radius, y);
27592         this._context.arc(x, y, this._radius, 0, tau$3);
27593         break;
27594       }
27595     }
27596   },
27597   result: noop$1
27598 };
27599
27600 var lengthSum$1 = adder();
27601 var lengthRing;
27602 var x00$2;
27603 var y00$2;
27604 var x0$4;
27605 var y0$4;
27606
27607 var lengthStream$1 = {
27608   point: noop$1,
27609   lineStart: function() {
27610     lengthStream$1.point = lengthPointFirst$1;
27611   },
27612   lineEnd: function() {
27613     if (lengthRing) lengthPoint$1(x00$2, y00$2);
27614     lengthStream$1.point = noop$1;
27615   },
27616   polygonStart: function() {
27617     lengthRing = true;
27618   },
27619   polygonEnd: function() {
27620     lengthRing = null;
27621   },
27622   result: function() {
27623     var length = +lengthSum$1;
27624     lengthSum$1.reset();
27625     return length;
27626   }
27627 };
27628
27629 function lengthPointFirst$1(x, y) {
27630   lengthStream$1.point = lengthPoint$1;
27631   x00$2 = x0$4 = x, y00$2 = y0$4 = y;
27632 }
27633
27634 function lengthPoint$1(x, y) {
27635   x0$4 -= x, y0$4 -= y;
27636   lengthSum$1.add(sqrt(x0$4 * x0$4 + y0$4 * y0$4));
27637   x0$4 = x, y0$4 = y;
27638 }
27639
27640 function PathString() {
27641   this._string = [];
27642 }
27643
27644 PathString.prototype = {
27645   _radius: 4.5,
27646   _circle: circle$1(4.5),
27647   pointRadius: function(_) {
27648     if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
27649     return this;
27650   },
27651   polygonStart: function() {
27652     this._line = 0;
27653   },
27654   polygonEnd: function() {
27655     this._line = NaN;
27656   },
27657   lineStart: function() {
27658     this._point = 0;
27659   },
27660   lineEnd: function() {
27661     if (this._line === 0) this._string.push("Z");
27662     this._point = NaN;
27663   },
27664   point: function(x, y) {
27665     switch (this._point) {
27666       case 0: {
27667         this._string.push("M", x, ",", y);
27668         this._point = 1;
27669         break;
27670       }
27671       case 1: {
27672         this._string.push("L", x, ",", y);
27673         break;
27674       }
27675       default: {
27676         if (this._circle == null) this._circle = circle$1(this._radius);
27677         this._string.push("M", x, ",", y, this._circle);
27678         break;
27679       }
27680     }
27681   },
27682   result: function() {
27683     if (this._string.length) {
27684       var result = this._string.join("");
27685       this._string = [];
27686       return result;
27687     } else {
27688       return null;
27689     }
27690   }
27691 };
27692
27693 function circle$1(radius) {
27694   return "m0," + radius
27695       + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
27696       + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
27697       + "z";
27698 }
27699
27700 var index$4 = function(projection, context) {
27701   var pointRadius = 4.5,
27702       projectionStream,
27703       contextStream;
27704
27705   function path(object) {
27706     if (object) {
27707       if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
27708       geoStream(object, projectionStream(contextStream));
27709     }
27710     return contextStream.result();
27711   }
27712
27713   path.area = function(object) {
27714     geoStream(object, projectionStream(areaStream$1));
27715     return areaStream$1.result();
27716   };
27717
27718   path.measure = function(object) {
27719     geoStream(object, projectionStream(lengthStream$1));
27720     return lengthStream$1.result();
27721   };
27722
27723   path.bounds = function(object) {
27724     geoStream(object, projectionStream(boundsStream$1));
27725     return boundsStream$1.result();
27726   };
27727
27728   path.centroid = function(object) {
27729     geoStream(object, projectionStream(centroidStream$1));
27730     return centroidStream$1.result();
27731   };
27732
27733   path.projection = function(_) {
27734     return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$4) : (projection = _).stream, path) : projection;
27735   };
27736
27737   path.context = function(_) {
27738     if (!arguments.length) return context;
27739     contextStream = _ == null ? (context = null, new PathString) : new PathContext(context = _);
27740     if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
27741     return path;
27742   };
27743
27744   path.pointRadius = function(_) {
27745     if (!arguments.length) return pointRadius;
27746     pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
27747     return path;
27748   };
27749
27750   return path.projection(projection).context(context);
27751 };
27752
27753 var clip = function(pointVisible, clipLine, interpolate, start) {
27754   return function(rotate, sink) {
27755     var line = clipLine(sink),
27756         rotatedStart = rotate.invert(start[0], start[1]),
27757         ringBuffer = clipBuffer(),
27758         ringSink = clipLine(ringBuffer),
27759         polygonStarted = false,
27760         polygon,
27761         segments,
27762         ring;
27763
27764     var clip = {
27765       point: point,
27766       lineStart: lineStart,
27767       lineEnd: lineEnd,
27768       polygonStart: function() {
27769         clip.point = pointRing;
27770         clip.lineStart = ringStart;
27771         clip.lineEnd = ringEnd;
27772         segments = [];
27773         polygon = [];
27774       },
27775       polygonEnd: function() {
27776         clip.point = point;
27777         clip.lineStart = lineStart;
27778         clip.lineEnd = lineEnd;
27779         segments = merge(segments);
27780         var startInside = polygonContains(polygon, rotatedStart);
27781         if (segments.length) {
27782           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27783           clipPolygon(segments, compareIntersection, startInside, interpolate, sink);
27784         } else if (startInside) {
27785           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27786           sink.lineStart();
27787           interpolate(null, null, 1, sink);
27788           sink.lineEnd();
27789         }
27790         if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
27791         segments = polygon = null;
27792       },
27793       sphere: function() {
27794         sink.polygonStart();
27795         sink.lineStart();
27796         interpolate(null, null, 1, sink);
27797         sink.lineEnd();
27798         sink.polygonEnd();
27799       }
27800     };
27801
27802     function point(lambda, phi) {
27803       var point = rotate(lambda, phi);
27804       if (pointVisible(lambda = point[0], phi = point[1])) sink.point(lambda, phi);
27805     }
27806
27807     function pointLine(lambda, phi) {
27808       var point = rotate(lambda, phi);
27809       line.point(point[0], point[1]);
27810     }
27811
27812     function lineStart() {
27813       clip.point = pointLine;
27814       line.lineStart();
27815     }
27816
27817     function lineEnd() {
27818       clip.point = point;
27819       line.lineEnd();
27820     }
27821
27822     function pointRing(lambda, phi) {
27823       ring.push([lambda, phi]);
27824       var point = rotate(lambda, phi);
27825       ringSink.point(point[0], point[1]);
27826     }
27827
27828     function ringStart() {
27829       ringSink.lineStart();
27830       ring = [];
27831     }
27832
27833     function ringEnd() {
27834       pointRing(ring[0][0], ring[0][1]);
27835       ringSink.lineEnd();
27836
27837       var clean = ringSink.clean(),
27838           ringSegments = ringBuffer.result(),
27839           i, n = ringSegments.length, m,
27840           segment,
27841           point;
27842
27843       ring.pop();
27844       polygon.push(ring);
27845       ring = null;
27846
27847       if (!n) return;
27848
27849       // No intersections.
27850       if (clean & 1) {
27851         segment = ringSegments[0];
27852         if ((m = segment.length - 1) > 0) {
27853           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27854           sink.lineStart();
27855           for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]);
27856           sink.lineEnd();
27857         }
27858         return;
27859       }
27860
27861       // Rejoin connected segments.
27862       // TODO reuse ringBuffer.rejoin()?
27863       if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
27864
27865       segments.push(ringSegments.filter(validSegment));
27866     }
27867
27868     return clip;
27869   };
27870 };
27871
27872 function validSegment(segment) {
27873   return segment.length > 1;
27874 }
27875
27876 // Intersections are sorted along the clip edge. For both antimeridian cutting
27877 // and circle clipping, the same comparison is used.
27878 function compareIntersection(a, b) {
27879   return ((a = a.x)[0] < 0 ? a[1] - halfPi$2 - epsilon$2 : halfPi$2 - a[1])
27880        - ((b = b.x)[0] < 0 ? b[1] - halfPi$2 - epsilon$2 : halfPi$2 - b[1]);
27881 }
27882
27883 var clipAntimeridian = clip(
27884   function() { return true; },
27885   clipAntimeridianLine,
27886   clipAntimeridianInterpolate,
27887   [-pi$3, -halfPi$2]
27888 );
27889
27890 // Takes a line and cuts into visible segments. Return values: 0 - there were
27891 // intersections or the line was empty; 1 - no intersections; 2 - there were
27892 // intersections, and the first and last segments should be rejoined.
27893 function clipAntimeridianLine(stream) {
27894   var lambda0 = NaN,
27895       phi0 = NaN,
27896       sign0 = NaN,
27897       clean; // no intersections
27898
27899   return {
27900     lineStart: function() {
27901       stream.lineStart();
27902       clean = 1;
27903     },
27904     point: function(lambda1, phi1) {
27905       var sign1 = lambda1 > 0 ? pi$3 : -pi$3,
27906           delta = abs(lambda1 - lambda0);
27907       if (abs(delta - pi$3) < epsilon$2) { // line crosses a pole
27908         stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$2 : -halfPi$2);
27909         stream.point(sign0, phi0);
27910         stream.lineEnd();
27911         stream.lineStart();
27912         stream.point(sign1, phi0);
27913         stream.point(lambda1, phi0);
27914         clean = 0;
27915       } else if (sign0 !== sign1 && delta >= pi$3) { // line crosses antimeridian
27916         if (abs(lambda0 - sign0) < epsilon$2) lambda0 -= sign0 * epsilon$2; // handle degeneracies
27917         if (abs(lambda1 - sign1) < epsilon$2) lambda1 -= sign1 * epsilon$2;
27918         phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
27919         stream.point(sign0, phi0);
27920         stream.lineEnd();
27921         stream.lineStart();
27922         stream.point(sign1, phi0);
27923         clean = 0;
27924       }
27925       stream.point(lambda0 = lambda1, phi0 = phi1);
27926       sign0 = sign1;
27927     },
27928     lineEnd: function() {
27929       stream.lineEnd();
27930       lambda0 = phi0 = NaN;
27931     },
27932     clean: function() {
27933       return 2 - clean; // if intersections, rejoin first and last segments
27934     }
27935   };
27936 }
27937
27938 function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
27939   var cosPhi0,
27940       cosPhi1,
27941       sinLambda0Lambda1 = sin$1(lambda0 - lambda1);
27942   return abs(sinLambda0Lambda1) > epsilon$2
27943       ? atan((sin$1(phi0) * (cosPhi1 = cos$1(phi1)) * sin$1(lambda1)
27944           - sin$1(phi1) * (cosPhi0 = cos$1(phi0)) * sin$1(lambda0))
27945           / (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
27946       : (phi0 + phi1) / 2;
27947 }
27948
27949 function clipAntimeridianInterpolate(from, to, direction, stream) {
27950   var phi;
27951   if (from == null) {
27952     phi = direction * halfPi$2;
27953     stream.point(-pi$3, phi);
27954     stream.point(0, phi);
27955     stream.point(pi$3, phi);
27956     stream.point(pi$3, 0);
27957     stream.point(pi$3, -phi);
27958     stream.point(0, -phi);
27959     stream.point(-pi$3, -phi);
27960     stream.point(-pi$3, 0);
27961     stream.point(-pi$3, phi);
27962   } else if (abs(from[0] - to[0]) > epsilon$2) {
27963     var lambda = from[0] < to[0] ? pi$3 : -pi$3;
27964     phi = direction * lambda / 2;
27965     stream.point(-lambda, phi);
27966     stream.point(0, phi);
27967     stream.point(lambda, phi);
27968   } else {
27969     stream.point(to[0], to[1]);
27970   }
27971 }
27972
27973 var clipCircle = function(radius, delta) {
27974   var cr = cos$1(radius),
27975       smallRadius = cr > 0,
27976       notHemisphere = abs(cr) > epsilon$2; // TODO optimise for this common case
27977
27978   function interpolate(from, to, direction, stream) {
27979     circleStream(stream, radius, delta, direction, from, to);
27980   }
27981
27982   function visible(lambda, phi) {
27983     return cos$1(lambda) * cos$1(phi) > cr;
27984   }
27985
27986   // Takes a line and cuts into visible segments. Return values used for polygon
27987   // clipping: 0 - there were intersections or the line was empty; 1 - no
27988   // intersections 2 - there were intersections, and the first and last segments
27989   // should be rejoined.
27990   function clipLine(stream) {
27991     var point0, // previous point
27992         c0, // code for previous point
27993         v0, // visibility of previous point
27994         v00, // visibility of first point
27995         clean; // no intersections
27996     return {
27997       lineStart: function() {
27998         v00 = v0 = false;
27999         clean = 1;
28000       },
28001       point: function(lambda, phi) {
28002         var point1 = [lambda, phi],
28003             point2,
28004             v = visible(lambda, phi),
28005             c = smallRadius
28006               ? v ? 0 : code(lambda, phi)
28007               : v ? code(lambda + (lambda < 0 ? pi$3 : -pi$3), phi) : 0;
28008         if (!point0 && (v00 = v0 = v)) stream.lineStart();
28009         // Handle degeneracies.
28010         // TODO ignore if not clipping polygons.
28011         if (v !== v0) {
28012           point2 = intersect(point0, point1);
28013           if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) {
28014             point1[0] += epsilon$2;
28015             point1[1] += epsilon$2;
28016             v = visible(point1[0], point1[1]);
28017           }
28018         }
28019         if (v !== v0) {
28020           clean = 0;
28021           if (v) {
28022             // outside going in
28023             stream.lineStart();
28024             point2 = intersect(point1, point0);
28025             stream.point(point2[0], point2[1]);
28026           } else {
28027             // inside going out
28028             point2 = intersect(point0, point1);
28029             stream.point(point2[0], point2[1]);
28030             stream.lineEnd();
28031           }
28032           point0 = point2;
28033         } else if (notHemisphere && point0 && smallRadius ^ v) {
28034           var t;
28035           // If the codes for two points are different, or are both zero,
28036           // and there this segment intersects with the small circle.
28037           if (!(c & c0) && (t = intersect(point1, point0, true))) {
28038             clean = 0;
28039             if (smallRadius) {
28040               stream.lineStart();
28041               stream.point(t[0][0], t[0][1]);
28042               stream.point(t[1][0], t[1][1]);
28043               stream.lineEnd();
28044             } else {
28045               stream.point(t[1][0], t[1][1]);
28046               stream.lineEnd();
28047               stream.lineStart();
28048               stream.point(t[0][0], t[0][1]);
28049             }
28050           }
28051         }
28052         if (v && (!point0 || !pointEqual(point0, point1))) {
28053           stream.point(point1[0], point1[1]);
28054         }
28055         point0 = point1, v0 = v, c0 = c;
28056       },
28057       lineEnd: function() {
28058         if (v0) stream.lineEnd();
28059         point0 = null;
28060       },
28061       // Rejoin first and last segments if there were intersections and the first
28062       // and last points were visible.
28063       clean: function() {
28064         return clean | ((v00 && v0) << 1);
28065       }
28066     };
28067   }
28068
28069   // Intersects the great circle between a and b with the clip circle.
28070   function intersect(a, b, two) {
28071     var pa = cartesian(a),
28072         pb = cartesian(b);
28073
28074     // We have two planes, n1.p = d1 and n2.p = d2.
28075     // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
28076     var n1 = [1, 0, 0], // normal
28077         n2 = cartesianCross(pa, pb),
28078         n2n2 = cartesianDot(n2, n2),
28079         n1n2 = n2[0], // cartesianDot(n1, n2),
28080         determinant = n2n2 - n1n2 * n1n2;
28081
28082     // Two polar points.
28083     if (!determinant) return !two && a;
28084
28085     var c1 =  cr * n2n2 / determinant,
28086         c2 = -cr * n1n2 / determinant,
28087         n1xn2 = cartesianCross(n1, n2),
28088         A = cartesianScale(n1, c1),
28089         B = cartesianScale(n2, c2);
28090     cartesianAddInPlace(A, B);
28091
28092     // Solve |p(t)|^2 = 1.
28093     var u = n1xn2,
28094         w = cartesianDot(A, u),
28095         uu = cartesianDot(u, u),
28096         t2 = w * w - uu * (cartesianDot(A, A) - 1);
28097
28098     if (t2 < 0) return;
28099
28100     var t = sqrt(t2),
28101         q = cartesianScale(u, (-w - t) / uu);
28102     cartesianAddInPlace(q, A);
28103     q = spherical(q);
28104
28105     if (!two) return q;
28106
28107     // Two intersection points.
28108     var lambda0 = a[0],
28109         lambda1 = b[0],
28110         phi0 = a[1],
28111         phi1 = b[1],
28112         z;
28113
28114     if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
28115
28116     var delta = lambda1 - lambda0,
28117         polar = abs(delta - pi$3) < epsilon$2,
28118         meridian = polar || delta < epsilon$2;
28119
28120     if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z;
28121
28122     // Check that the first point is between a and b.
28123     if (meridian
28124         ? polar
28125           ? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon$2 ? phi0 : phi1)
28126           : phi0 <= q[1] && q[1] <= phi1
28127         : delta > pi$3 ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
28128       var q1 = cartesianScale(u, (-w + t) / uu);
28129       cartesianAddInPlace(q1, A);
28130       return [q, spherical(q1)];
28131     }
28132   }
28133
28134   // Generates a 4-bit vector representing the location of a point relative to
28135   // the small circle's bounding box.
28136   function code(lambda, phi) {
28137     var r = smallRadius ? radius : pi$3 - radius,
28138         code = 0;
28139     if (lambda < -r) code |= 1; // left
28140     else if (lambda > r) code |= 2; // right
28141     if (phi < -r) code |= 4; // below
28142     else if (phi > r) code |= 8; // above
28143     return code;
28144   }
28145
28146   return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$3, radius - pi$3]);
28147 };
28148
28149 var transform = function(methods) {
28150   return {
28151     stream: transformer(methods)
28152   };
28153 };
28154
28155 function transformer(methods) {
28156   return function(stream) {
28157     var s = new TransformStream;
28158     for (var key in methods) s[key] = methods[key];
28159     s.stream = stream;
28160     return s;
28161   };
28162 }
28163
28164 function TransformStream() {}
28165
28166 TransformStream.prototype = {
28167   constructor: TransformStream,
28168   point: function(x, y) { this.stream.point(x, y); },
28169   sphere: function() { this.stream.sphere(); },
28170   lineStart: function() { this.stream.lineStart(); },
28171   lineEnd: function() { this.stream.lineEnd(); },
28172   polygonStart: function() { this.stream.polygonStart(); },
28173   polygonEnd: function() { this.stream.polygonEnd(); }
28174 };
28175
28176 function fitExtent(projection, extent, object) {
28177   var w = extent[1][0] - extent[0][0],
28178       h = extent[1][1] - extent[0][1],
28179       clip = projection.clipExtent && projection.clipExtent();
28180
28181   projection
28182       .scale(150)
28183       .translate([0, 0]);
28184
28185   if (clip != null) projection.clipExtent(null);
28186
28187   geoStream(object, projection.stream(boundsStream$1));
28188
28189   var b = boundsStream$1.result(),
28190       k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
28191       x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
28192       y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
28193
28194   if (clip != null) projection.clipExtent(clip);
28195
28196   return projection
28197       .scale(k * 150)
28198       .translate([x, y]);
28199 }
28200
28201 function fitSize(projection, size, object) {
28202   return fitExtent(projection, [[0, 0], size], object);
28203 }
28204
28205 var maxDepth = 16;
28206 var cosMinDistance = cos$1(30 * radians); // cos(minimum angular distance)
28207
28208 var resample = function(project, delta2) {
28209   return +delta2 ? resample$1(project, delta2) : resampleNone(project);
28210 };
28211
28212 function resampleNone(project) {
28213   return transformer({
28214     point: function(x, y) {
28215       x = project(x, y);
28216       this.stream.point(x[0], x[1]);
28217     }
28218   });
28219 }
28220
28221 function resample$1(project, delta2) {
28222
28223   function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
28224     var dx = x1 - x0,
28225         dy = y1 - y0,
28226         d2 = dx * dx + dy * dy;
28227     if (d2 > 4 * delta2 && depth--) {
28228       var a = a0 + a1,
28229           b = b0 + b1,
28230           c = c0 + c1,
28231           m = sqrt(a * a + b * b + c * c),
28232           phi2 = asin(c /= m),
28233           lambda2 = abs(abs(c) - 1) < epsilon$2 || abs(lambda0 - lambda1) < epsilon$2 ? (lambda0 + lambda1) / 2 : atan2(b, a),
28234           p = project(lambda2, phi2),
28235           x2 = p[0],
28236           y2 = p[1],
28237           dx2 = x2 - x0,
28238           dy2 = y2 - y0,
28239           dz = dy * dx2 - dx * dy2;
28240       if (dz * dz / d2 > delta2 // perpendicular projected distance
28241           || abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
28242           || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
28243         resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
28244         stream.point(x2, y2);
28245         resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
28246       }
28247     }
28248   }
28249   return function(stream) {
28250     var lambda00, x00, y00, a00, b00, c00, // first point
28251         lambda0, x0, y0, a0, b0, c0; // previous point
28252
28253     var resampleStream = {
28254       point: point,
28255       lineStart: lineStart,
28256       lineEnd: lineEnd,
28257       polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; },
28258       polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; }
28259     };
28260
28261     function point(x, y) {
28262       x = project(x, y);
28263       stream.point(x[0], x[1]);
28264     }
28265
28266     function lineStart() {
28267       x0 = NaN;
28268       resampleStream.point = linePoint;
28269       stream.lineStart();
28270     }
28271
28272     function linePoint(lambda, phi) {
28273       var c = cartesian([lambda, phi]), p = project(lambda, phi);
28274       resampleLineTo(x0, y0, lambda0, a0, b0, c0, x0 = p[0], y0 = p[1], lambda0 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
28275       stream.point(x0, y0);
28276     }
28277
28278     function lineEnd() {
28279       resampleStream.point = point;
28280       stream.lineEnd();
28281     }
28282
28283     function ringStart() {
28284       lineStart();
28285       resampleStream.point = ringPoint;
28286       resampleStream.lineEnd = ringEnd;
28287     }
28288
28289     function ringPoint(lambda, phi) {
28290       linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
28291       resampleStream.point = linePoint;
28292     }
28293
28294     function ringEnd() {
28295       resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
28296       resampleStream.lineEnd = lineEnd;
28297       lineEnd();
28298     }
28299
28300     return resampleStream;
28301   };
28302 }
28303
28304 var transformRadians = transformer({
28305   point: function(x, y) {
28306     this.stream.point(x * radians, y * radians);
28307   }
28308 });
28309
28310 function projection(project) {
28311   return projectionMutator(function() { return project; })();
28312 }
28313
28314 function projectionMutator(projectAt) {
28315   var project,
28316       k = 150, // scale
28317       x = 480, y = 250, // translate
28318       dx, dy, lambda = 0, phi = 0, // center
28319       deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate
28320       theta = null, preclip = clipAntimeridian, // clip angle
28321       x0 = null, y0, x1, y1, postclip = identity$4, // clip extent
28322       delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision
28323       cache,
28324       cacheStream;
28325
28326   function projection(point) {
28327     point = projectRotate(point[0] * radians, point[1] * radians);
28328     return [point[0] * k + dx, dy - point[1] * k];
28329   }
28330
28331   function invert(point) {
28332     point = projectRotate.invert((point[0] - dx) / k, (dy - point[1]) / k);
28333     return point && [point[0] * degrees$1, point[1] * degrees$1];
28334   }
28335
28336   function projectTransform(x, y) {
28337     return x = project(x, y), [x[0] * k + dx, dy - x[1] * k];
28338   }
28339
28340   projection.stream = function(stream) {
28341     return cache && cacheStream === stream ? cache : cache = transformRadians(preclip(rotate, projectResample(postclip(cacheStream = stream))));
28342   };
28343
28344   projection.clipAngle = function(_) {
28345     return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians, 6 * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
28346   };
28347
28348   projection.clipExtent = function(_) {
28349     return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
28350   };
28351
28352   projection.scale = function(_) {
28353     return arguments.length ? (k = +_, recenter()) : k;
28354   };
28355
28356   projection.translate = function(_) {
28357     return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
28358   };
28359
28360   projection.center = function(_) {
28361     return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
28362   };
28363
28364   projection.rotate = function(_) {
28365     return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees$1, deltaPhi * degrees$1, deltaGamma * degrees$1];
28366   };
28367
28368   projection.precision = function(_) {
28369     return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
28370   };
28371
28372   projection.fitExtent = function(extent, object) {
28373     return fitExtent(projection, extent, object);
28374   };
28375
28376   projection.fitSize = function(size, object) {
28377     return fitSize(projection, size, object);
28378   };
28379
28380   function recenter() {
28381     projectRotate = compose(rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma), project);
28382     var center = project(lambda, phi);
28383     dx = x - center[0] * k;
28384     dy = y + center[1] * k;
28385     return reset();
28386   }
28387
28388   function reset() {
28389     cache = cacheStream = null;
28390     return projection;
28391   }
28392
28393   return function() {
28394     project = projectAt.apply(this, arguments);
28395     projection.invert = project.invert && invert;
28396     return recenter();
28397   };
28398 }
28399
28400 function conicProjection(projectAt) {
28401   var phi0 = 0,
28402       phi1 = pi$3 / 3,
28403       m = projectionMutator(projectAt),
28404       p = m(phi0, phi1);
28405
28406   p.parallels = function(_) {
28407     return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees$1, phi1 * degrees$1];
28408   };
28409
28410   return p;
28411 }
28412
28413 function cylindricalEqualAreaRaw(phi0) {
28414   var cosPhi0 = cos$1(phi0);
28415
28416   function forward(lambda, phi) {
28417     return [lambda * cosPhi0, sin$1(phi) / cosPhi0];
28418   }
28419
28420   forward.invert = function(x, y) {
28421     return [x / cosPhi0, asin(y * cosPhi0)];
28422   };
28423
28424   return forward;
28425 }
28426
28427 function conicEqualAreaRaw(y0, y1) {
28428   var sy0 = sin$1(y0), n = (sy0 + sin$1(y1)) / 2;
28429
28430   // Are the parallels symmetrical around the Equator?
28431   if (abs(n) < epsilon$2) return cylindricalEqualAreaRaw(y0);
28432
28433   var c = 1 + sy0 * (2 * n - sy0), r0 = sqrt(c) / n;
28434
28435   function project(x, y) {
28436     var r = sqrt(c - 2 * n * sin$1(y)) / n;
28437     return [r * sin$1(x *= n), r0 - r * cos$1(x)];
28438   }
28439
28440   project.invert = function(x, y) {
28441     var r0y = r0 - y;
28442     return [atan2(x, abs(r0y)) / n * sign(r0y), asin((c - (x * x + r0y * r0y) * n * n) / (2 * n))];
28443   };
28444
28445   return project;
28446 }
28447
28448 var conicEqualArea = function() {
28449   return conicProjection(conicEqualAreaRaw)
28450       .scale(155.424)
28451       .center([0, 33.6442]);
28452 };
28453
28454 var albers = function() {
28455   return conicEqualArea()
28456       .parallels([29.5, 45.5])
28457       .scale(1070)
28458       .translate([480, 250])
28459       .rotate([96, 0])
28460       .center([-0.6, 38.7]);
28461 };
28462
28463 // The projections must have mutually exclusive clip regions on the sphere,
28464 // as this will avoid emitting interleaving lines and polygons.
28465 function multiplex(streams) {
28466   var n = streams.length;
28467   return {
28468     point: function(x, y) { var i = -1; while (++i < n) streams[i].point(x, y); },
28469     sphere: function() { var i = -1; while (++i < n) streams[i].sphere(); },
28470     lineStart: function() { var i = -1; while (++i < n) streams[i].lineStart(); },
28471     lineEnd: function() { var i = -1; while (++i < n) streams[i].lineEnd(); },
28472     polygonStart: function() { var i = -1; while (++i < n) streams[i].polygonStart(); },
28473     polygonEnd: function() { var i = -1; while (++i < n) streams[i].polygonEnd(); }
28474   };
28475 }
28476
28477 // A composite projection for the United States, configured by default for
28478 // 960×500. The projection also works quite well at 960×600 if you change the
28479 // scale to 1285 and adjust the translate accordingly. The set of standard
28480 // parallels for each region comes from USGS, which is published here:
28481 // http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
28482 var albersUsa = function() {
28483   var cache,
28484       cacheStream,
28485       lower48 = albers(), lower48Point,
28486       alaska = conicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]), alaskaPoint, // EPSG:3338
28487       hawaii = conicEqualArea().rotate([157, 0]).center([-3, 19.9]).parallels([8, 18]), hawaiiPoint, // ESRI:102007
28488       point, pointStream = {point: function(x, y) { point = [x, y]; }};
28489
28490   function albersUsa(coordinates) {
28491     var x = coordinates[0], y = coordinates[1];
28492     return point = null,
28493         (lower48Point.point(x, y), point)
28494         || (alaskaPoint.point(x, y), point)
28495         || (hawaiiPoint.point(x, y), point);
28496   }
28497
28498   albersUsa.invert = function(coordinates) {
28499     var k = lower48.scale(),
28500         t = lower48.translate(),
28501         x = (coordinates[0] - t[0]) / k,
28502         y = (coordinates[1] - t[1]) / k;
28503     return (y >= 0.120 && y < 0.234 && x >= -0.425 && x < -0.214 ? alaska
28504         : y >= 0.166 && y < 0.234 && x >= -0.214 && x < -0.115 ? hawaii
28505         : lower48).invert(coordinates);
28506   };
28507
28508   albersUsa.stream = function(stream) {
28509     return cache && cacheStream === stream ? cache : cache = multiplex([lower48.stream(cacheStream = stream), alaska.stream(stream), hawaii.stream(stream)]);
28510   };
28511
28512   albersUsa.precision = function(_) {
28513     if (!arguments.length) return lower48.precision();
28514     lower48.precision(_), alaska.precision(_), hawaii.precision(_);
28515     return reset();
28516   };
28517
28518   albersUsa.scale = function(_) {
28519     if (!arguments.length) return lower48.scale();
28520     lower48.scale(_), alaska.scale(_ * 0.35), hawaii.scale(_);
28521     return albersUsa.translate(lower48.translate());
28522   };
28523
28524   albersUsa.translate = function(_) {
28525     if (!arguments.length) return lower48.translate();
28526     var k = lower48.scale(), x = +_[0], y = +_[1];
28527
28528     lower48Point = lower48
28529         .translate(_)
28530         .clipExtent([[x - 0.455 * k, y - 0.238 * k], [x + 0.455 * k, y + 0.238 * k]])
28531         .stream(pointStream);
28532
28533     alaskaPoint = alaska
28534         .translate([x - 0.307 * k, y + 0.201 * k])
28535         .clipExtent([[x - 0.425 * k + epsilon$2, y + 0.120 * k + epsilon$2], [x - 0.214 * k - epsilon$2, y + 0.234 * k - epsilon$2]])
28536         .stream(pointStream);
28537
28538     hawaiiPoint = hawaii
28539         .translate([x - 0.205 * k, y + 0.212 * k])
28540         .clipExtent([[x - 0.214 * k + epsilon$2, y + 0.166 * k + epsilon$2], [x - 0.115 * k - epsilon$2, y + 0.234 * k - epsilon$2]])
28541         .stream(pointStream);
28542
28543     return reset();
28544   };
28545
28546   albersUsa.fitExtent = function(extent, object) {
28547     return fitExtent(albersUsa, extent, object);
28548   };
28549
28550   albersUsa.fitSize = function(size, object) {
28551     return fitSize(albersUsa, size, object);
28552   };
28553
28554   function reset() {
28555     cache = cacheStream = null;
28556     return albersUsa;
28557   }
28558
28559   return albersUsa.scale(1070);
28560 };
28561
28562 function azimuthalRaw(scale) {
28563   return function(x, y) {
28564     var cx = cos$1(x),
28565         cy = cos$1(y),
28566         k = scale(cx * cy);
28567     return [
28568       k * cy * sin$1(x),
28569       k * sin$1(y)
28570     ];
28571   }
28572 }
28573
28574 function azimuthalInvert(angle) {
28575   return function(x, y) {
28576     var z = sqrt(x * x + y * y),
28577         c = angle(z),
28578         sc = sin$1(c),
28579         cc = cos$1(c);
28580     return [
28581       atan2(x * sc, z * cc),
28582       asin(z && y * sc / z)
28583     ];
28584   }
28585 }
28586
28587 var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) {
28588   return sqrt(2 / (1 + cxcy));
28589 });
28590
28591 azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) {
28592   return 2 * asin(z / 2);
28593 });
28594
28595 var azimuthalEqualArea = function() {
28596   return projection(azimuthalEqualAreaRaw)
28597       .scale(124.75)
28598       .clipAngle(180 - 1e-3);
28599 };
28600
28601 var azimuthalEquidistantRaw = azimuthalRaw(function(c) {
28602   return (c = acos(c)) && c / sin$1(c);
28603 });
28604
28605 azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) {
28606   return z;
28607 });
28608
28609 var azimuthalEquidistant = function() {
28610   return projection(azimuthalEquidistantRaw)
28611       .scale(79.4188)
28612       .clipAngle(180 - 1e-3);
28613 };
28614
28615 function mercatorRaw(lambda, phi) {
28616   return [lambda, log(tan((halfPi$2 + phi) / 2))];
28617 }
28618
28619 mercatorRaw.invert = function(x, y) {
28620   return [x, 2 * atan(exp(y)) - halfPi$2];
28621 };
28622
28623 var mercator = function() {
28624   return mercatorProjection(mercatorRaw)
28625       .scale(961 / tau$3);
28626 };
28627
28628 function mercatorProjection(project) {
28629   var m = projection(project),
28630       center = m.center,
28631       scale = m.scale,
28632       translate = m.translate,
28633       clipExtent = m.clipExtent,
28634       x0 = null, y0, x1, y1; // clip extent
28635
28636   m.scale = function(_) {
28637     return arguments.length ? (scale(_), reclip()) : scale();
28638   };
28639
28640   m.translate = function(_) {
28641     return arguments.length ? (translate(_), reclip()) : translate();
28642   };
28643
28644   m.center = function(_) {
28645     return arguments.length ? (center(_), reclip()) : center();
28646   };
28647
28648   m.clipExtent = function(_) {
28649     return arguments.length ? ((_ == null ? x0 = y0 = x1 = y1 = null : (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1])), reclip()) : x0 == null ? null : [[x0, y0], [x1, y1]];
28650   };
28651
28652   function reclip() {
28653     var k = pi$3 * scale(),
28654         t = m(rotation(m.rotate()).invert([0, 0]));
28655     return clipExtent(x0 == null
28656         ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw
28657         ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]]
28658         : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]);
28659   }
28660
28661   return reclip();
28662 }
28663
28664 function tany(y) {
28665   return tan((halfPi$2 + y) / 2);
28666 }
28667
28668 function conicConformalRaw(y0, y1) {
28669   var cy0 = cos$1(y0),
28670       n = y0 === y1 ? sin$1(y0) : log(cy0 / cos$1(y1)) / log(tany(y1) / tany(y0)),
28671       f = cy0 * pow(tany(y0), n) / n;
28672
28673   if (!n) return mercatorRaw;
28674
28675   function project(x, y) {
28676     if (f > 0) { if (y < -halfPi$2 + epsilon$2) y = -halfPi$2 + epsilon$2; }
28677     else { if (y > halfPi$2 - epsilon$2) y = halfPi$2 - epsilon$2; }
28678     var r = f / pow(tany(y), n);
28679     return [r * sin$1(n * x), f - r * cos$1(n * x)];
28680   }
28681
28682   project.invert = function(x, y) {
28683     var fy = f - y, r = sign(n) * sqrt(x * x + fy * fy);
28684     return [atan2(x, abs(fy)) / n * sign(fy), 2 * atan(pow(f / r, 1 / n)) - halfPi$2];
28685   };
28686
28687   return project;
28688 }
28689
28690 var conicConformal = function() {
28691   return conicProjection(conicConformalRaw)
28692       .scale(109.5)
28693       .parallels([30, 30]);
28694 };
28695
28696 function equirectangularRaw(lambda, phi) {
28697   return [lambda, phi];
28698 }
28699
28700 equirectangularRaw.invert = equirectangularRaw;
28701
28702 var equirectangular = function() {
28703   return projection(equirectangularRaw)
28704       .scale(152.63);
28705 };
28706
28707 function conicEquidistantRaw(y0, y1) {
28708   var cy0 = cos$1(y0),
28709       n = y0 === y1 ? sin$1(y0) : (cy0 - cos$1(y1)) / (y1 - y0),
28710       g = cy0 / n + y0;
28711
28712   if (abs(n) < epsilon$2) return equirectangularRaw;
28713
28714   function project(x, y) {
28715     var gy = g - y, nx = n * x;
28716     return [gy * sin$1(nx), g - gy * cos$1(nx)];
28717   }
28718
28719   project.invert = function(x, y) {
28720     var gy = g - y;
28721     return [atan2(x, abs(gy)) / n * sign(gy), g - sign(n) * sqrt(x * x + gy * gy)];
28722   };
28723
28724   return project;
28725 }
28726
28727 var conicEquidistant = function() {
28728   return conicProjection(conicEquidistantRaw)
28729       .scale(131.154)
28730       .center([0, 13.9389]);
28731 };
28732
28733 function gnomonicRaw(x, y) {
28734   var cy = cos$1(y), k = cos$1(x) * cy;
28735   return [cy * sin$1(x) / k, sin$1(y) / k];
28736 }
28737
28738 gnomonicRaw.invert = azimuthalInvert(atan);
28739
28740 var gnomonic = function() {
28741   return projection(gnomonicRaw)
28742       .scale(144.049)
28743       .clipAngle(60);
28744 };
28745
28746 function scaleTranslate(kx, ky, tx, ty) {
28747   return kx === 1 && ky === 1 && tx === 0 && ty === 0 ? identity$4 : transformer({
28748     point: function(x, y) {
28749       this.stream.point(x * kx + tx, y * ky + ty);
28750     }
28751   });
28752 }
28753
28754 var identity$5 = function() {
28755   var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, transform$$1 = identity$4, // scale, translate and reflect
28756       x0 = null, y0, x1, y1, clip = identity$4, // clip extent
28757       cache,
28758       cacheStream,
28759       projection;
28760
28761   function reset() {
28762     cache = cacheStream = null;
28763     return projection;
28764   }
28765
28766   return projection = {
28767     stream: function(stream) {
28768       return cache && cacheStream === stream ? cache : cache = transform$$1(clip(cacheStream = stream));
28769     },
28770     clipExtent: function(_) {
28771       return arguments.length ? (clip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
28772     },
28773     scale: function(_) {
28774       return arguments.length ? (transform$$1 = scaleTranslate((k = +_) * sx, k * sy, tx, ty), reset()) : k;
28775     },
28776     translate: function(_) {
28777       return arguments.length ? (transform$$1 = scaleTranslate(k * sx, k * sy, tx = +_[0], ty = +_[1]), reset()) : [tx, ty];
28778     },
28779     reflectX: function(_) {
28780       return arguments.length ? (transform$$1 = scaleTranslate(k * (sx = _ ? -1 : 1), k * sy, tx, ty), reset()) : sx < 0;
28781     },
28782     reflectY: function(_) {
28783       return arguments.length ? (transform$$1 = scaleTranslate(k * sx, k * (sy = _ ? -1 : 1), tx, ty), reset()) : sy < 0;
28784     },
28785     fitExtent: function(extent, object) {
28786       return fitExtent(projection, extent, object);
28787     },
28788     fitSize: function(size, object) {
28789       return fitSize(projection, size, object);
28790     }
28791   };
28792 };
28793
28794 function orthographicRaw(x, y) {
28795   return [cos$1(y) * sin$1(x), sin$1(y)];
28796 }
28797
28798 orthographicRaw.invert = azimuthalInvert(asin);
28799
28800 var orthographic = function() {
28801   return projection(orthographicRaw)
28802       .scale(249.5)
28803       .clipAngle(90 + epsilon$2);
28804 };
28805
28806 function stereographicRaw(x, y) {
28807   var cy = cos$1(y), k = 1 + cos$1(x) * cy;
28808   return [cy * sin$1(x) / k, sin$1(y) / k];
28809 }
28810
28811 stereographicRaw.invert = azimuthalInvert(function(z) {
28812   return 2 * atan(z);
28813 });
28814
28815 var stereographic = function() {
28816   return projection(stereographicRaw)
28817       .scale(250)
28818       .clipAngle(142);
28819 };
28820
28821 function transverseMercatorRaw(lambda, phi) {
28822   return [log(tan((halfPi$2 + phi) / 2)), -lambda];
28823 }
28824
28825 transverseMercatorRaw.invert = function(x, y) {
28826   return [-y, 2 * atan(exp(x)) - halfPi$2];
28827 };
28828
28829 var transverseMercator = function() {
28830   var m = mercatorProjection(transverseMercatorRaw),
28831       center = m.center,
28832       rotate = m.rotate;
28833
28834   m.center = function(_) {
28835     return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]);
28836   };
28837
28838   m.rotate = function(_) {
28839     return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]);
28840   };
28841
28842   return rotate([0, 0, 90])
28843       .scale(159.155);
28844 };
28845
28846 function defaultSeparation(a, b) {
28847   return a.parent === b.parent ? 1 : 2;
28848 }
28849
28850 function meanX(children) {
28851   return children.reduce(meanXReduce, 0) / children.length;
28852 }
28853
28854 function meanXReduce(x, c) {
28855   return x + c.x;
28856 }
28857
28858 function maxY(children) {
28859   return 1 + children.reduce(maxYReduce, 0);
28860 }
28861
28862 function maxYReduce(y, c) {
28863   return Math.max(y, c.y);
28864 }
28865
28866 function leafLeft(node) {
28867   var children;
28868   while (children = node.children) node = children[0];
28869   return node;
28870 }
28871
28872 function leafRight(node) {
28873   var children;
28874   while (children = node.children) node = children[children.length - 1];
28875   return node;
28876 }
28877
28878 var cluster = function() {
28879   var separation = defaultSeparation,
28880       dx = 1,
28881       dy = 1,
28882       nodeSize = false;
28883
28884   function cluster(root) {
28885     var previousNode,
28886         x = 0;
28887
28888     // First walk, computing the initial x & y values.
28889     root.eachAfter(function(node) {
28890       var children = node.children;
28891       if (children) {
28892         node.x = meanX(children);
28893         node.y = maxY(children);
28894       } else {
28895         node.x = previousNode ? x += separation(node, previousNode) : 0;
28896         node.y = 0;
28897         previousNode = node;
28898       }
28899     });
28900
28901     var left = leafLeft(root),
28902         right = leafRight(root),
28903         x0 = left.x - separation(left, right) / 2,
28904         x1 = right.x + separation(right, left) / 2;
28905
28906     // Second walk, normalizing x & y to the desired size.
28907     return root.eachAfter(nodeSize ? function(node) {
28908       node.x = (node.x - root.x) * dx;
28909       node.y = (root.y - node.y) * dy;
28910     } : function(node) {
28911       node.x = (node.x - x0) / (x1 - x0) * dx;
28912       node.y = (1 - (root.y ? node.y / root.y : 1)) * dy;
28913     });
28914   }
28915
28916   cluster.separation = function(x) {
28917     return arguments.length ? (separation = x, cluster) : separation;
28918   };
28919
28920   cluster.size = function(x) {
28921     return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? null : [dx, dy]);
28922   };
28923
28924   cluster.nodeSize = function(x) {
28925     return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? [dx, dy] : null);
28926   };
28927
28928   return cluster;
28929 };
28930
28931 function count(node) {
28932   var sum = 0,
28933       children = node.children,
28934       i = children && children.length;
28935   if (!i) sum = 1;
28936   else while (--i >= 0) sum += children[i].value;
28937   node.value = sum;
28938 }
28939
28940 var node_count = function() {
28941   return this.eachAfter(count);
28942 };
28943
28944 var node_each = function(callback) {
28945   var node = this, current, next = [node], children, i, n;
28946   do {
28947     current = next.reverse(), next = [];
28948     while (node = current.pop()) {
28949       callback(node), children = node.children;
28950       if (children) for (i = 0, n = children.length; i < n; ++i) {
28951         next.push(children[i]);
28952       }
28953     }
28954   } while (next.length);
28955   return this;
28956 };
28957
28958 var node_eachBefore = function(callback) {
28959   var node = this, nodes = [node], children, i;
28960   while (node = nodes.pop()) {
28961     callback(node), children = node.children;
28962     if (children) for (i = children.length - 1; i >= 0; --i) {
28963       nodes.push(children[i]);
28964     }
28965   }
28966   return this;
28967 };
28968
28969 var node_eachAfter = function(callback) {
28970   var node = this, nodes = [node], next = [], children, i, n;
28971   while (node = nodes.pop()) {
28972     next.push(node), children = node.children;
28973     if (children) for (i = 0, n = children.length; i < n; ++i) {
28974       nodes.push(children[i]);
28975     }
28976   }
28977   while (node = next.pop()) {
28978     callback(node);
28979   }
28980   return this;
28981 };
28982
28983 var node_sum = function(value) {
28984   return this.eachAfter(function(node) {
28985     var sum = +value(node.data) || 0,
28986         children = node.children,
28987         i = children && children.length;
28988     while (--i >= 0) sum += children[i].value;
28989     node.value = sum;
28990   });
28991 };
28992
28993 var node_sort = function(compare) {
28994   return this.eachBefore(function(node) {
28995     if (node.children) {
28996       node.children.sort(compare);
28997     }
28998   });
28999 };
29000
29001 var node_path = function(end) {
29002   var start = this,
29003       ancestor = leastCommonAncestor(start, end),
29004       nodes = [start];
29005   while (start !== ancestor) {
29006     start = start.parent;
29007     nodes.push(start);
29008   }
29009   var k = nodes.length;
29010   while (end !== ancestor) {
29011     nodes.splice(k, 0, end);
29012     end = end.parent;
29013   }
29014   return nodes;
29015 };
29016
29017 function leastCommonAncestor(a, b) {
29018   if (a === b) return a;
29019   var aNodes = a.ancestors(),
29020       bNodes = b.ancestors(),
29021       c = null;
29022   a = aNodes.pop();
29023   b = bNodes.pop();
29024   while (a === b) {
29025     c = a;
29026     a = aNodes.pop();
29027     b = bNodes.pop();
29028   }
29029   return c;
29030 }
29031
29032 var node_ancestors = function() {
29033   var node = this, nodes = [node];
29034   while (node = node.parent) {
29035     nodes.push(node);
29036   }
29037   return nodes;
29038 };
29039
29040 var node_descendants = function() {
29041   var nodes = [];
29042   this.each(function(node) {
29043     nodes.push(node);
29044   });
29045   return nodes;
29046 };
29047
29048 var node_leaves = function() {
29049   var leaves = [];
29050   this.eachBefore(function(node) {
29051     if (!node.children) {
29052       leaves.push(node);
29053     }
29054   });
29055   return leaves;
29056 };
29057
29058 var node_links = function() {
29059   var root = this, links = [];
29060   root.each(function(node) {
29061     if (node !== root) { // Don’t include the root’s parent, if any.
29062       links.push({source: node.parent, target: node});
29063     }
29064   });
29065   return links;
29066 };
29067
29068 function hierarchy(data, children) {
29069   var root = new Node(data),
29070       valued = +data.value && (root.value = data.value),
29071       node,
29072       nodes = [root],
29073       child,
29074       childs,
29075       i,
29076       n;
29077
29078   if (children == null) children = defaultChildren;
29079
29080   while (node = nodes.pop()) {
29081     if (valued) node.value = +node.data.value;
29082     if ((childs = children(node.data)) && (n = childs.length)) {
29083       node.children = new Array(n);
29084       for (i = n - 1; i >= 0; --i) {
29085         nodes.push(child = node.children[i] = new Node(childs[i]));
29086         child.parent = node;
29087         child.depth = node.depth + 1;
29088       }
29089     }
29090   }
29091
29092   return root.eachBefore(computeHeight);
29093 }
29094
29095 function node_copy() {
29096   return hierarchy(this).eachBefore(copyData);
29097 }
29098
29099 function defaultChildren(d) {
29100   return d.children;
29101 }
29102
29103 function copyData(node) {
29104   node.data = node.data.data;
29105 }
29106
29107 function computeHeight(node) {
29108   var height = 0;
29109   do node.height = height;
29110   while ((node = node.parent) && (node.height < ++height));
29111 }
29112
29113 function Node(data) {
29114   this.data = data;
29115   this.depth =
29116   this.height = 0;
29117   this.parent = null;
29118 }
29119
29120 Node.prototype = hierarchy.prototype = {
29121   constructor: Node,
29122   count: node_count,
29123   each: node_each,
29124   eachAfter: node_eachAfter,
29125   eachBefore: node_eachBefore,
29126   sum: node_sum,
29127   sort: node_sort,
29128   path: node_path,
29129   ancestors: node_ancestors,
29130   descendants: node_descendants,
29131   leaves: node_leaves,
29132   links: node_links,
29133   copy: node_copy
29134 };
29135
29136 function Node$2(value) {
29137   this._ = value;
29138   this.next = null;
29139 }
29140
29141 var shuffle$1 = function(array) {
29142   var i,
29143       n = (array = array.slice()).length,
29144       head = null,
29145       node = head;
29146
29147   while (n) {
29148     var next = new Node$2(array[n - 1]);
29149     if (node) node = node.next = next;
29150     else node = head = next;
29151     array[i] = array[--n];
29152   }
29153
29154   return {
29155     head: head,
29156     tail: node
29157   };
29158 };
29159
29160 var enclose = function(circles) {
29161   return encloseN(shuffle$1(circles), []);
29162 };
29163
29164 function encloses(a, b) {
29165   var dx = b.x - a.x,
29166       dy = b.y - a.y,
29167       dr = a.r - b.r;
29168   return dr * dr + 1e-6 > dx * dx + dy * dy;
29169 }
29170
29171 // Returns the smallest circle that contains circles L and intersects circles B.
29172 function encloseN(L, B) {
29173   var circle,
29174       l0 = null,
29175       l1 = L.head,
29176       l2,
29177       p1;
29178
29179   switch (B.length) {
29180     case 1: circle = enclose1(B[0]); break;
29181     case 2: circle = enclose2(B[0], B[1]); break;
29182     case 3: circle = enclose3(B[0], B[1], B[2]); break;
29183   }
29184
29185   while (l1) {
29186     p1 = l1._, l2 = l1.next;
29187     if (!circle || !encloses(circle, p1)) {
29188
29189       // Temporarily truncate L before l1.
29190       if (l0) L.tail = l0, l0.next = null;
29191       else L.head = L.tail = null;
29192
29193       B.push(p1);
29194       circle = encloseN(L, B); // Note: reorders L!
29195       B.pop();
29196
29197       // Move l1 to the front of L and reconnect the truncated list L.
29198       if (L.head) l1.next = L.head, L.head = l1;
29199       else l1.next = null, L.head = L.tail = l1;
29200       l0 = L.tail, l0.next = l2;
29201
29202     } else {
29203       l0 = l1;
29204     }
29205     l1 = l2;
29206   }
29207
29208   L.tail = l0;
29209   return circle;
29210 }
29211
29212 function enclose1(a) {
29213   return {
29214     x: a.x,
29215     y: a.y,
29216     r: a.r
29217   };
29218 }
29219
29220 function enclose2(a, b) {
29221   var x1 = a.x, y1 = a.y, r1 = a.r,
29222       x2 = b.x, y2 = b.y, r2 = b.r,
29223       x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
29224       l = Math.sqrt(x21 * x21 + y21 * y21);
29225   return {
29226     x: (x1 + x2 + x21 / l * r21) / 2,
29227     y: (y1 + y2 + y21 / l * r21) / 2,
29228     r: (l + r1 + r2) / 2
29229   };
29230 }
29231
29232 function enclose3(a, b, c) {
29233   var x1 = a.x, y1 = a.y, r1 = a.r,
29234       x2 = b.x, y2 = b.y, r2 = b.r,
29235       x3 = c.x, y3 = c.y, r3 = c.r,
29236       a2 = 2 * (x1 - x2),
29237       b2 = 2 * (y1 - y2),
29238       c2 = 2 * (r2 - r1),
29239       d2 = x1 * x1 + y1 * y1 - r1 * r1 - x2 * x2 - y2 * y2 + r2 * r2,
29240       a3 = 2 * (x1 - x3),
29241       b3 = 2 * (y1 - y3),
29242       c3 = 2 * (r3 - r1),
29243       d3 = x1 * x1 + y1 * y1 - r1 * r1 - x3 * x3 - y3 * y3 + r3 * r3,
29244       ab = a3 * b2 - a2 * b3,
29245       xa = (b2 * d3 - b3 * d2) / ab - x1,
29246       xb = (b3 * c2 - b2 * c3) / ab,
29247       ya = (a3 * d2 - a2 * d3) / ab - y1,
29248       yb = (a2 * c3 - a3 * c2) / ab,
29249       A = xb * xb + yb * yb - 1,
29250       B = 2 * (xa * xb + ya * yb + r1),
29251       C = xa * xa + ya * ya - r1 * r1,
29252       r = (-B - Math.sqrt(B * B - 4 * A * C)) / (2 * A);
29253   return {
29254     x: xa + xb * r + x1,
29255     y: ya + yb * r + y1,
29256     r: r
29257   };
29258 }
29259
29260 function place(a, b, c) {
29261   var ax = a.x,
29262       ay = a.y,
29263       da = b.r + c.r,
29264       db = a.r + c.r,
29265       dx = b.x - ax,
29266       dy = b.y - ay,
29267       dc = dx * dx + dy * dy;
29268   if (dc) {
29269     var x = 0.5 + ((db *= db) - (da *= da)) / (2 * dc),
29270         y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
29271     c.x = ax + x * dx + y * dy;
29272     c.y = ay + x * dy - y * dx;
29273   } else {
29274     c.x = ax + db;
29275     c.y = ay;
29276   }
29277 }
29278
29279 function intersects(a, b) {
29280   var dx = b.x - a.x,
29281       dy = b.y - a.y,
29282       dr = a.r + b.r;
29283   return dr * dr - 1e-6 > dx * dx + dy * dy;
29284 }
29285
29286 function distance2(node, x, y) {
29287   var a = node._,
29288       b = node.next._,
29289       ab = a.r + b.r,
29290       dx = (a.x * b.r + b.x * a.r) / ab - x,
29291       dy = (a.y * b.r + b.y * a.r) / ab - y;
29292   return dx * dx + dy * dy;
29293 }
29294
29295 function Node$1(circle) {
29296   this._ = circle;
29297   this.next = null;
29298   this.previous = null;
29299 }
29300
29301 function packEnclose(circles) {
29302   if (!(n = circles.length)) return 0;
29303
29304   var a, b, c, n;
29305
29306   // Place the first circle.
29307   a = circles[0], a.x = 0, a.y = 0;
29308   if (!(n > 1)) return a.r;
29309
29310   // Place the second circle.
29311   b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0;
29312   if (!(n > 2)) return a.r + b.r;
29313
29314   // Place the third circle.
29315   place(b, a, c = circles[2]);
29316
29317   // Initialize the weighted centroid.
29318   var aa = a.r * a.r,
29319       ba = b.r * b.r,
29320       ca = c.r * c.r,
29321       oa = aa + ba + ca,
29322       ox = aa * a.x + ba * b.x + ca * c.x,
29323       oy = aa * a.y + ba * b.y + ca * c.y,
29324       cx, cy, i, j, k, sj, sk;
29325
29326   // Initialize the front-chain using the first three circles a, b and c.
29327   a = new Node$1(a), b = new Node$1(b), c = new Node$1(c);
29328   a.next = c.previous = b;
29329   b.next = a.previous = c;
29330   c.next = b.previous = a;
29331
29332   // Attempt to place each remaining circle…
29333   pack: for (i = 3; i < n; ++i) {
29334     place(a._, b._, c = circles[i]), c = new Node$1(c);
29335
29336     // Find the closest intersecting circle on the front-chain, if any.
29337     // “Closeness” is determined by linear distance along the front-chain.
29338     // “Ahead” or “behind” is likewise determined by linear distance.
29339     j = b.next, k = a.previous, sj = b._.r, sk = a._.r;
29340     do {
29341       if (sj <= sk) {
29342         if (intersects(j._, c._)) {
29343           b = j, a.next = b, b.previous = a, --i;
29344           continue pack;
29345         }
29346         sj += j._.r, j = j.next;
29347       } else {
29348         if (intersects(k._, c._)) {
29349           a = k, a.next = b, b.previous = a, --i;
29350           continue pack;
29351         }
29352         sk += k._.r, k = k.previous;
29353       }
29354     } while (j !== k.next);
29355
29356     // Success! Insert the new circle c between a and b.
29357     c.previous = a, c.next = b, a.next = b.previous = b = c;
29358
29359     // Update the weighted centroid.
29360     oa += ca = c._.r * c._.r;
29361     ox += ca * c._.x;
29362     oy += ca * c._.y;
29363
29364     // Compute the new closest circle pair to the centroid.
29365     aa = distance2(a, cx = ox / oa, cy = oy / oa);
29366     while ((c = c.next) !== b) {
29367       if ((ca = distance2(c, cx, cy)) < aa) {
29368         a = c, aa = ca;
29369       }
29370     }
29371     b = a.next;
29372   }
29373
29374   // Compute the enclosing circle of the front chain.
29375   a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a);
29376
29377   // Translate the circles to put the enclosing circle around the origin.
29378   for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
29379
29380   return c.r;
29381 }
29382
29383 var siblings = function(circles) {
29384   packEnclose(circles);
29385   return circles;
29386 };
29387
29388 function optional(f) {
29389   return f == null ? null : required(f);
29390 }
29391
29392 function required(f) {
29393   if (typeof f !== "function") throw new Error;
29394   return f;
29395 }
29396
29397 function constantZero() {
29398   return 0;
29399 }
29400
29401 var constant$8 = function(x) {
29402   return function() {
29403     return x;
29404   };
29405 };
29406
29407 function defaultRadius$1(d) {
29408   return Math.sqrt(d.value);
29409 }
29410
29411 var index$5 = function() {
29412   var radius = null,
29413       dx = 1,
29414       dy = 1,
29415       padding = constantZero;
29416
29417   function pack(root) {
29418     root.x = dx / 2, root.y = dy / 2;
29419     if (radius) {
29420       root.eachBefore(radiusLeaf(radius))
29421           .eachAfter(packChildren(padding, 0.5))
29422           .eachBefore(translateChild(1));
29423     } else {
29424       root.eachBefore(radiusLeaf(defaultRadius$1))
29425           .eachAfter(packChildren(constantZero, 1))
29426           .eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))
29427           .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));
29428     }
29429     return root;
29430   }
29431
29432   pack.radius = function(x) {
29433     return arguments.length ? (radius = optional(x), pack) : radius;
29434   };
29435
29436   pack.size = function(x) {
29437     return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy];
29438   };
29439
29440   pack.padding = function(x) {
29441     return arguments.length ? (padding = typeof x === "function" ? x : constant$8(+x), pack) : padding;
29442   };
29443
29444   return pack;
29445 };
29446
29447 function radiusLeaf(radius) {
29448   return function(node) {
29449     if (!node.children) {
29450       node.r = Math.max(0, +radius(node) || 0);
29451     }
29452   };
29453 }
29454
29455 function packChildren(padding, k) {
29456   return function(node) {
29457     if (children = node.children) {
29458       var children,
29459           i,
29460           n = children.length,
29461           r = padding(node) * k || 0,
29462           e;
29463
29464       if (r) for (i = 0; i < n; ++i) children[i].r += r;
29465       e = packEnclose(children);
29466       if (r) for (i = 0; i < n; ++i) children[i].r -= r;
29467       node.r = e + r;
29468     }
29469   };
29470 }
29471
29472 function translateChild(k) {
29473   return function(node) {
29474     var parent = node.parent;
29475     node.r *= k;
29476     if (parent) {
29477       node.x = parent.x + k * node.x;
29478       node.y = parent.y + k * node.y;
29479     }
29480   };
29481 }
29482
29483 var roundNode = function(node) {
29484   node.x0 = Math.round(node.x0);
29485   node.y0 = Math.round(node.y0);
29486   node.x1 = Math.round(node.x1);
29487   node.y1 = Math.round(node.y1);
29488 };
29489
29490 var treemapDice = function(parent, x0, y0, x1, y1) {
29491   var nodes = parent.children,
29492       node,
29493       i = -1,
29494       n = nodes.length,
29495       k = parent.value && (x1 - x0) / parent.value;
29496
29497   while (++i < n) {
29498     node = nodes[i], node.y0 = y0, node.y1 = y1;
29499     node.x0 = x0, node.x1 = x0 += node.value * k;
29500   }
29501 };
29502
29503 var partition = function() {
29504   var dx = 1,
29505       dy = 1,
29506       padding = 0,
29507       round = false;
29508
29509   function partition(root) {
29510     var n = root.height + 1;
29511     root.x0 =
29512     root.y0 = padding;
29513     root.x1 = dx;
29514     root.y1 = dy / n;
29515     root.eachBefore(positionNode(dy, n));
29516     if (round) root.eachBefore(roundNode);
29517     return root;
29518   }
29519
29520   function positionNode(dy, n) {
29521     return function(node) {
29522       if (node.children) {
29523         treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n);
29524       }
29525       var x0 = node.x0,
29526           y0 = node.y0,
29527           x1 = node.x1 - padding,
29528           y1 = node.y1 - padding;
29529       if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29530       if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29531       node.x0 = x0;
29532       node.y0 = y0;
29533       node.x1 = x1;
29534       node.y1 = y1;
29535     };
29536   }
29537
29538   partition.round = function(x) {
29539     return arguments.length ? (round = !!x, partition) : round;
29540   };
29541
29542   partition.size = function(x) {
29543     return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy];
29544   };
29545
29546   partition.padding = function(x) {
29547     return arguments.length ? (padding = +x, partition) : padding;
29548   };
29549
29550   return partition;
29551 };
29552
29553 var keyPrefix$1 = "$";
29554 var preroot = {depth: -1};
29555 var ambiguous = {};
29556
29557 function defaultId(d) {
29558   return d.id;
29559 }
29560
29561 function defaultParentId(d) {
29562   return d.parentId;
29563 }
29564
29565 var stratify = function() {
29566   var id = defaultId,
29567       parentId = defaultParentId;
29568
29569   function stratify(data) {
29570     var d,
29571         i,
29572         n = data.length,
29573         root,
29574         parent,
29575         node,
29576         nodes = new Array(n),
29577         nodeId,
29578         nodeKey,
29579         nodeByKey = {};
29580
29581     for (i = 0; i < n; ++i) {
29582       d = data[i], node = nodes[i] = new Node(d);
29583       if ((nodeId = id(d, i, data)) != null && (nodeId += "")) {
29584         nodeKey = keyPrefix$1 + (node.id = nodeId);
29585         nodeByKey[nodeKey] = nodeKey in nodeByKey ? ambiguous : node;
29586       }
29587     }
29588
29589     for (i = 0; i < n; ++i) {
29590       node = nodes[i], nodeId = parentId(data[i], i, data);
29591       if (nodeId == null || !(nodeId += "")) {
29592         if (root) throw new Error("multiple roots");
29593         root = node;
29594       } else {
29595         parent = nodeByKey[keyPrefix$1 + nodeId];
29596         if (!parent) throw new Error("missing: " + nodeId);
29597         if (parent === ambiguous) throw new Error("ambiguous: " + nodeId);
29598         if (parent.children) parent.children.push(node);
29599         else parent.children = [node];
29600         node.parent = parent;
29601       }
29602     }
29603
29604     if (!root) throw new Error("no root");
29605     root.parent = preroot;
29606     root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
29607     root.parent = null;
29608     if (n > 0) throw new Error("cycle");
29609
29610     return root;
29611   }
29612
29613   stratify.id = function(x) {
29614     return arguments.length ? (id = required(x), stratify) : id;
29615   };
29616
29617   stratify.parentId = function(x) {
29618     return arguments.length ? (parentId = required(x), stratify) : parentId;
29619   };
29620
29621   return stratify;
29622 };
29623
29624 function defaultSeparation$1(a, b) {
29625   return a.parent === b.parent ? 1 : 2;
29626 }
29627
29628 // function radialSeparation(a, b) {
29629 //   return (a.parent === b.parent ? 1 : 2) / a.depth;
29630 // }
29631
29632 // This function is used to traverse the left contour of a subtree (or
29633 // subforest). It returns the successor of v on this contour. This successor is
29634 // either given by the leftmost child of v or by the thread of v. The function
29635 // returns null if and only if v is on the highest level of its subtree.
29636 function nextLeft(v) {
29637   var children = v.children;
29638   return children ? children[0] : v.t;
29639 }
29640
29641 // This function works analogously to nextLeft.
29642 function nextRight(v) {
29643   var children = v.children;
29644   return children ? children[children.length - 1] : v.t;
29645 }
29646
29647 // Shifts the current subtree rooted at w+. This is done by increasing
29648 // prelim(w+) and mod(w+) by shift.
29649 function moveSubtree(wm, wp, shift) {
29650   var change = shift / (wp.i - wm.i);
29651   wp.c -= change;
29652   wp.s += shift;
29653   wm.c += change;
29654   wp.z += shift;
29655   wp.m += shift;
29656 }
29657
29658 // All other shifts, applied to the smaller subtrees between w- and w+, are
29659 // performed by this function. To prepare the shifts, we have to adjust
29660 // change(w+), shift(w+), and change(w-).
29661 function executeShifts(v) {
29662   var shift = 0,
29663       change = 0,
29664       children = v.children,
29665       i = children.length,
29666       w;
29667   while (--i >= 0) {
29668     w = children[i];
29669     w.z += shift;
29670     w.m += shift;
29671     shift += w.s + (change += w.c);
29672   }
29673 }
29674
29675 // If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise,
29676 // returns the specified (default) ancestor.
29677 function nextAncestor(vim, v, ancestor) {
29678   return vim.a.parent === v.parent ? vim.a : ancestor;
29679 }
29680
29681 function TreeNode(node, i) {
29682   this._ = node;
29683   this.parent = null;
29684   this.children = null;
29685   this.A = null; // default ancestor
29686   this.a = this; // ancestor
29687   this.z = 0; // prelim
29688   this.m = 0; // mod
29689   this.c = 0; // change
29690   this.s = 0; // shift
29691   this.t = null; // thread
29692   this.i = i; // number
29693 }
29694
29695 TreeNode.prototype = Object.create(Node.prototype);
29696
29697 function treeRoot(root) {
29698   var tree = new TreeNode(root, 0),
29699       node,
29700       nodes = [tree],
29701       child,
29702       children,
29703       i,
29704       n;
29705
29706   while (node = nodes.pop()) {
29707     if (children = node._.children) {
29708       node.children = new Array(n = children.length);
29709       for (i = n - 1; i >= 0; --i) {
29710         nodes.push(child = node.children[i] = new TreeNode(children[i], i));
29711         child.parent = node;
29712       }
29713     }
29714   }
29715
29716   (tree.parent = new TreeNode(null, 0)).children = [tree];
29717   return tree;
29718 }
29719
29720 // Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
29721 var tree = function() {
29722   var separation = defaultSeparation$1,
29723       dx = 1,
29724       dy = 1,
29725       nodeSize = null;
29726
29727   function tree(root) {
29728     var t = treeRoot(root);
29729
29730     // Compute the layout using Buchheim et al.’s algorithm.
29731     t.eachAfter(firstWalk), t.parent.m = -t.z;
29732     t.eachBefore(secondWalk);
29733
29734     // If a fixed node size is specified, scale x and y.
29735     if (nodeSize) root.eachBefore(sizeNode);
29736
29737     // If a fixed tree size is specified, scale x and y based on the extent.
29738     // Compute the left-most, right-most, and depth-most nodes for extents.
29739     else {
29740       var left = root,
29741           right = root,
29742           bottom = root;
29743       root.eachBefore(function(node) {
29744         if (node.x < left.x) left = node;
29745         if (node.x > right.x) right = node;
29746         if (node.depth > bottom.depth) bottom = node;
29747       });
29748       var s = left === right ? 1 : separation(left, right) / 2,
29749           tx = s - left.x,
29750           kx = dx / (right.x + s + tx),
29751           ky = dy / (bottom.depth || 1);
29752       root.eachBefore(function(node) {
29753         node.x = (node.x + tx) * kx;
29754         node.y = node.depth * ky;
29755       });
29756     }
29757
29758     return root;
29759   }
29760
29761   // Computes a preliminary x-coordinate for v. Before that, FIRST WALK is
29762   // applied recursively to the children of v, as well as the function
29763   // APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the
29764   // node v is placed to the midpoint of its outermost children.
29765   function firstWalk(v) {
29766     var children = v.children,
29767         siblings = v.parent.children,
29768         w = v.i ? siblings[v.i - 1] : null;
29769     if (children) {
29770       executeShifts(v);
29771       var midpoint = (children[0].z + children[children.length - 1].z) / 2;
29772       if (w) {
29773         v.z = w.z + separation(v._, w._);
29774         v.m = v.z - midpoint;
29775       } else {
29776         v.z = midpoint;
29777       }
29778     } else if (w) {
29779       v.z = w.z + separation(v._, w._);
29780     }
29781     v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
29782   }
29783
29784   // Computes all real x-coordinates by summing up the modifiers recursively.
29785   function secondWalk(v) {
29786     v._.x = v.z + v.parent.m;
29787     v.m += v.parent.m;
29788   }
29789
29790   // The core of the algorithm. Here, a new subtree is combined with the
29791   // previous subtrees. Threads are used to traverse the inside and outside
29792   // contours of the left and right subtree up to the highest common level. The
29793   // vertices used for the traversals are vi+, vi-, vo-, and vo+, where the
29794   // superscript o means outside and i means inside, the subscript - means left
29795   // subtree and + means right subtree. For summing up the modifiers along the
29796   // contour, we use respective variables si+, si-, so-, and so+. Whenever two
29797   // nodes of the inside contours conflict, we compute the left one of the
29798   // greatest uncommon ancestors using the function ANCESTOR and call MOVE
29799   // SUBTREE to shift the subtree and prepare the shifts of smaller subtrees.
29800   // Finally, we add a new thread (if necessary).
29801   function apportion(v, w, ancestor) {
29802     if (w) {
29803       var vip = v,
29804           vop = v,
29805           vim = w,
29806           vom = vip.parent.children[0],
29807           sip = vip.m,
29808           sop = vop.m,
29809           sim = vim.m,
29810           som = vom.m,
29811           shift;
29812       while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) {
29813         vom = nextLeft(vom);
29814         vop = nextRight(vop);
29815         vop.a = v;
29816         shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
29817         if (shift > 0) {
29818           moveSubtree(nextAncestor(vim, v, ancestor), v, shift);
29819           sip += shift;
29820           sop += shift;
29821         }
29822         sim += vim.m;
29823         sip += vip.m;
29824         som += vom.m;
29825         sop += vop.m;
29826       }
29827       if (vim && !nextRight(vop)) {
29828         vop.t = vim;
29829         vop.m += sim - sop;
29830       }
29831       if (vip && !nextLeft(vom)) {
29832         vom.t = vip;
29833         vom.m += sip - som;
29834         ancestor = v;
29835       }
29836     }
29837     return ancestor;
29838   }
29839
29840   function sizeNode(node) {
29841     node.x *= dx;
29842     node.y = node.depth * dy;
29843   }
29844
29845   tree.separation = function(x) {
29846     return arguments.length ? (separation = x, tree) : separation;
29847   };
29848
29849   tree.size = function(x) {
29850     return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]);
29851   };
29852
29853   tree.nodeSize = function(x) {
29854     return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null);
29855   };
29856
29857   return tree;
29858 };
29859
29860 var treemapSlice = function(parent, x0, y0, x1, y1) {
29861   var nodes = parent.children,
29862       node,
29863       i = -1,
29864       n = nodes.length,
29865       k = parent.value && (y1 - y0) / parent.value;
29866
29867   while (++i < n) {
29868     node = nodes[i], node.x0 = x0, node.x1 = x1;
29869     node.y0 = y0, node.y1 = y0 += node.value * k;
29870   }
29871 };
29872
29873 var phi = (1 + Math.sqrt(5)) / 2;
29874
29875 function squarifyRatio(ratio, parent, x0, y0, x1, y1) {
29876   var rows = [],
29877       nodes = parent.children,
29878       row,
29879       nodeValue,
29880       i0 = 0,
29881       i1 = 0,
29882       n = nodes.length,
29883       dx, dy,
29884       value = parent.value,
29885       sumValue,
29886       minValue,
29887       maxValue,
29888       newRatio,
29889       minRatio,
29890       alpha,
29891       beta;
29892
29893   while (i0 < n) {
29894     dx = x1 - x0, dy = y1 - y0;
29895
29896     // Find the next non-empty node.
29897     do sumValue = nodes[i1++].value; while (!sumValue && i1 < n);
29898     minValue = maxValue = sumValue;
29899     alpha = Math.max(dy / dx, dx / dy) / (value * ratio);
29900     beta = sumValue * sumValue * alpha;
29901     minRatio = Math.max(maxValue / beta, beta / minValue);
29902
29903     // Keep adding nodes while the aspect ratio maintains or improves.
29904     for (; i1 < n; ++i1) {
29905       sumValue += nodeValue = nodes[i1].value;
29906       if (nodeValue < minValue) minValue = nodeValue;
29907       if (nodeValue > maxValue) maxValue = nodeValue;
29908       beta = sumValue * sumValue * alpha;
29909       newRatio = Math.max(maxValue / beta, beta / minValue);
29910       if (newRatio > minRatio) { sumValue -= nodeValue; break; }
29911       minRatio = newRatio;
29912     }
29913
29914     // Position and record the row orientation.
29915     rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)});
29916     if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1);
29917     else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1);
29918     value -= sumValue, i0 = i1;
29919   }
29920
29921   return rows;
29922 }
29923
29924 var squarify = ((function custom(ratio) {
29925
29926   function squarify(parent, x0, y0, x1, y1) {
29927     squarifyRatio(ratio, parent, x0, y0, x1, y1);
29928   }
29929
29930   squarify.ratio = function(x) {
29931     return custom((x = +x) > 1 ? x : 1);
29932   };
29933
29934   return squarify;
29935 }))(phi);
29936
29937 var index$6 = function() {
29938   var tile = squarify,
29939       round = false,
29940       dx = 1,
29941       dy = 1,
29942       paddingStack = [0],
29943       paddingInner = constantZero,
29944       paddingTop = constantZero,
29945       paddingRight = constantZero,
29946       paddingBottom = constantZero,
29947       paddingLeft = constantZero;
29948
29949   function treemap(root) {
29950     root.x0 =
29951     root.y0 = 0;
29952     root.x1 = dx;
29953     root.y1 = dy;
29954     root.eachBefore(positionNode);
29955     paddingStack = [0];
29956     if (round) root.eachBefore(roundNode);
29957     return root;
29958   }
29959
29960   function positionNode(node) {
29961     var p = paddingStack[node.depth],
29962         x0 = node.x0 + p,
29963         y0 = node.y0 + p,
29964         x1 = node.x1 - p,
29965         y1 = node.y1 - p;
29966     if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29967     if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29968     node.x0 = x0;
29969     node.y0 = y0;
29970     node.x1 = x1;
29971     node.y1 = y1;
29972     if (node.children) {
29973       p = paddingStack[node.depth + 1] = paddingInner(node) / 2;
29974       x0 += paddingLeft(node) - p;
29975       y0 += paddingTop(node) - p;
29976       x1 -= paddingRight(node) - p;
29977       y1 -= paddingBottom(node) - p;
29978       if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29979       if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29980       tile(node, x0, y0, x1, y1);
29981     }
29982   }
29983
29984   treemap.round = function(x) {
29985     return arguments.length ? (round = !!x, treemap) : round;
29986   };
29987
29988   treemap.size = function(x) {
29989     return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy];
29990   };
29991
29992   treemap.tile = function(x) {
29993     return arguments.length ? (tile = required(x), treemap) : tile;
29994   };
29995
29996   treemap.padding = function(x) {
29997     return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner();
29998   };
29999
30000   treemap.paddingInner = function(x) {
30001     return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$8(+x), treemap) : paddingInner;
30002   };
30003
30004   treemap.paddingOuter = function(x) {
30005     return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop();
30006   };
30007
30008   treemap.paddingTop = function(x) {
30009     return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$8(+x), treemap) : paddingTop;
30010   };
30011
30012   treemap.paddingRight = function(x) {
30013     return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$8(+x), treemap) : paddingRight;
30014   };
30015
30016   treemap.paddingBottom = function(x) {
30017     return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$8(+x), treemap) : paddingBottom;
30018   };
30019
30020   treemap.paddingLeft = function(x) {
30021     return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$8(+x), treemap) : paddingLeft;
30022   };
30023
30024   return treemap;
30025 };
30026
30027 var binary = function(parent, x0, y0, x1, y1) {
30028   var nodes = parent.children,
30029       i, n = nodes.length,
30030       sum, sums = new Array(n + 1);
30031
30032   for (sums[0] = sum = i = 0; i < n; ++i) {
30033     sums[i + 1] = sum += nodes[i].value;
30034   }
30035
30036   partition(0, n, parent.value, x0, y0, x1, y1);
30037
30038   function partition(i, j, value, x0, y0, x1, y1) {
30039     if (i >= j - 1) {
30040       var node = nodes[i];
30041       node.x0 = x0, node.y0 = y0;
30042       node.x1 = x1, node.y1 = y1;
30043       return;
30044     }
30045
30046     var valueOffset = sums[i],
30047         valueTarget = (value / 2) + valueOffset,
30048         k = i + 1,
30049         hi = j - 1;
30050
30051     while (k < hi) {
30052       var mid = k + hi >>> 1;
30053       if (sums[mid] < valueTarget) k = mid + 1;
30054       else hi = mid;
30055     }
30056
30057     if ((valueTarget - sums[k - 1]) < (sums[k] - valueTarget) && i + 1 < k) --k;
30058
30059     var valueLeft = sums[k] - valueOffset,
30060         valueRight = value - valueLeft;
30061
30062     if ((x1 - x0) > (y1 - y0)) {
30063       var xk = (x0 * valueRight + x1 * valueLeft) / value;
30064       partition(i, k, valueLeft, x0, y0, xk, y1);
30065       partition(k, j, valueRight, xk, y0, x1, y1);
30066     } else {
30067       var yk = (y0 * valueRight + y1 * valueLeft) / value;
30068       partition(i, k, valueLeft, x0, y0, x1, yk);
30069       partition(k, j, valueRight, x0, yk, x1, y1);
30070     }
30071   }
30072 };
30073
30074 var sliceDice = function(parent, x0, y0, x1, y1) {
30075   (parent.depth & 1 ? treemapSlice : treemapDice)(parent, x0, y0, x1, y1);
30076 };
30077
30078 var resquarify = ((function custom(ratio) {
30079
30080   function resquarify(parent, x0, y0, x1, y1) {
30081     if ((rows = parent._squarify) && (rows.ratio === ratio)) {
30082       var rows,
30083           row,
30084           nodes,
30085           i,
30086           j = -1,
30087           n,
30088           m = rows.length,
30089           value = parent.value;
30090
30091       while (++j < m) {
30092         row = rows[j], nodes = row.children;
30093         for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value;
30094         if (row.dice) treemapDice(row, x0, y0, x1, y0 += (y1 - y0) * row.value / value);
30095         else treemapSlice(row, x0, y0, x0 += (x1 - x0) * row.value / value, y1);
30096         value -= row.value;
30097       }
30098     } else {
30099       parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1);
30100       rows.ratio = ratio;
30101     }
30102   }
30103
30104   resquarify.ratio = function(x) {
30105     return custom((x = +x) > 1 ? x : 1);
30106   };
30107
30108   return resquarify;
30109 }))(phi);
30110
30111 var d3polygonArea = function(polygon) {
30112   var i = -1,
30113       n = polygon.length,
30114       a,
30115       b = polygon[n - 1],
30116       area = 0;
30117
30118   while (++i < n) {
30119     a = b;
30120     b = polygon[i];
30121     area += a[1] * b[0] - a[0] * b[1];
30122   }
30123
30124   return area / 2;
30125 };
30126
30127 var d3polygonCentroid = function(polygon) {
30128   var i = -1,
30129       n = polygon.length,
30130       x = 0,
30131       y = 0,
30132       a,
30133       b = polygon[n - 1],
30134       c,
30135       k = 0;
30136
30137   while (++i < n) {
30138     a = b;
30139     b = polygon[i];
30140     k += c = a[0] * b[1] - b[0] * a[1];
30141     x += (a[0] + b[0]) * c;
30142     y += (a[1] + b[1]) * c;
30143   }
30144
30145   return k *= 3, [x / k, y / k];
30146 };
30147
30148 // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
30149 // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
30150 // right, +y is up). Returns a positive value if ABC is counter-clockwise,
30151 // negative if clockwise, and zero if the points are collinear.
30152 var cross$1 = function(a, b, c) {
30153   return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
30154 };
30155
30156 function lexicographicOrder(a, b) {
30157   return a[0] - b[0] || a[1] - b[1];
30158 }
30159
30160 // Computes the upper convex hull per the monotone chain algorithm.
30161 // Assumes points.length >= 3, is sorted by x, unique in y.
30162 // Returns an array of indices into points in left-to-right order.
30163 function computeUpperHullIndexes(points) {
30164   var n = points.length,
30165       indexes = [0, 1],
30166       size = 2;
30167
30168   for (var i = 2; i < n; ++i) {
30169     while (size > 1 && cross$1(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size;
30170     indexes[size++] = i;
30171   }
30172
30173   return indexes.slice(0, size); // remove popped points
30174 }
30175
30176 var d3polygonHull = function(points) {
30177   if ((n = points.length) < 3) return null;
30178
30179   var i,
30180       n,
30181       sortedPoints = new Array(n),
30182       flippedPoints = new Array(n);
30183
30184   for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i];
30185   sortedPoints.sort(lexicographicOrder);
30186   for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
30187
30188   var upperIndexes = computeUpperHullIndexes(sortedPoints),
30189       lowerIndexes = computeUpperHullIndexes(flippedPoints);
30190
30191   // Construct the hull polygon, removing possible duplicate endpoints.
30192   var skipLeft = lowerIndexes[0] === upperIndexes[0],
30193       skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
30194       hull = [];
30195
30196   // Add upper hull in right-to-l order.
30197   // Then add lower hull in left-to-right order.
30198   for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]);
30199   for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
30200
30201   return hull;
30202 };
30203
30204 var contains$1 = function(polygon, point) {
30205   var n = polygon.length,
30206       p = polygon[n - 1],
30207       x = point[0], y = point[1],
30208       x0 = p[0], y0 = p[1],
30209       x1, y1,
30210       inside = false;
30211
30212   for (var i = 0; i < n; ++i) {
30213     p = polygon[i], x1 = p[0], y1 = p[1];
30214     if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside;
30215     x0 = x1, y0 = y1;
30216   }
30217
30218   return inside;
30219 };
30220
30221 var length$1 = function(polygon) {
30222   var i = -1,
30223       n = polygon.length,
30224       b = polygon[n - 1],
30225       xa,
30226       ya,
30227       xb = b[0],
30228       yb = b[1],
30229       perimeter = 0;
30230
30231   while (++i < n) {
30232     xa = xb;
30233     ya = yb;
30234     b = polygon[i];
30235     xb = b[0];
30236     yb = b[1];
30237     xa -= xb;
30238     ya -= yb;
30239     perimeter += Math.sqrt(xa * xa + ya * ya);
30240   }
30241
30242   return perimeter;
30243 };
30244
30245 var slice$3 = [].slice;
30246
30247 var noabort = {};
30248
30249 function Queue(size) {
30250   this._size = size;
30251   this._call =
30252   this._error = null;
30253   this._tasks = [];
30254   this._data = [];
30255   this._waiting =
30256   this._active =
30257   this._ended =
30258   this._start = 0; // inside a synchronous task callback?
30259 }
30260
30261 Queue.prototype = queue.prototype = {
30262   constructor: Queue,
30263   defer: function(callback) {
30264     if (typeof callback !== "function") throw new Error("invalid callback");
30265     if (this._call) throw new Error("defer after await");
30266     if (this._error != null) return this;
30267     var t = slice$3.call(arguments, 1);
30268     t.push(callback);
30269     ++this._waiting, this._tasks.push(t);
30270     poke$1(this);
30271     return this;
30272   },
30273   abort: function() {
30274     if (this._error == null) abort(this, new Error("abort"));
30275     return this;
30276   },
30277   await: function(callback) {
30278     if (typeof callback !== "function") throw new Error("invalid callback");
30279     if (this._call) throw new Error("multiple await");
30280     this._call = function(error, results) { callback.apply(null, [error].concat(results)); };
30281     maybeNotify(this);
30282     return this;
30283   },
30284   awaitAll: function(callback) {
30285     if (typeof callback !== "function") throw new Error("invalid callback");
30286     if (this._call) throw new Error("multiple await");
30287     this._call = callback;
30288     maybeNotify(this);
30289     return this;
30290   }
30291 };
30292
30293 function poke$1(q) {
30294   if (!q._start) {
30295     try { start$1(q); } // let the current task complete
30296     catch (e) {
30297       if (q._tasks[q._ended + q._active - 1]) abort(q, e); // task errored synchronously
30298       else if (!q._data) throw e; // await callback errored synchronously
30299     }
30300   }
30301 }
30302
30303 function start$1(q) {
30304   while (q._start = q._waiting && q._active < q._size) {
30305     var i = q._ended + q._active,
30306         t = q._tasks[i],
30307         j = t.length - 1,
30308         c = t[j];
30309     t[j] = end(q, i);
30310     --q._waiting, ++q._active;
30311     t = c.apply(null, t);
30312     if (!q._tasks[i]) continue; // task finished synchronously
30313     q._tasks[i] = t || noabort;
30314   }
30315 }
30316
30317 function end(q, i) {
30318   return function(e, r) {
30319     if (!q._tasks[i]) return; // ignore multiple callbacks
30320     --q._active, ++q._ended;
30321     q._tasks[i] = null;
30322     if (q._error != null) return; // ignore secondary errors
30323     if (e != null) {
30324       abort(q, e);
30325     } else {
30326       q._data[i] = r;
30327       if (q._waiting) poke$1(q);
30328       else maybeNotify(q);
30329     }
30330   };
30331 }
30332
30333 function abort(q, e) {
30334   var i = q._tasks.length, t;
30335   q._error = e; // ignore active callbacks
30336   q._data = undefined; // allow gc
30337   q._waiting = NaN; // prevent starting
30338
30339   while (--i >= 0) {
30340     if (t = q._tasks[i]) {
30341       q._tasks[i] = null;
30342       if (t.abort) {
30343         try { t.abort(); }
30344         catch (e) { /* ignore */ }
30345       }
30346     }
30347   }
30348
30349   q._active = NaN; // allow notification
30350   maybeNotify(q);
30351 }
30352
30353 function maybeNotify(q) {
30354   if (!q._active && q._call) {
30355     var d = q._data;
30356     q._data = undefined; // allow gc
30357     q._call(q._error, d);
30358   }
30359 }
30360
30361 function queue(concurrency) {
30362   if (concurrency == null) concurrency = Infinity;
30363   else if (!((concurrency = +concurrency) >= 1)) throw new Error("invalid concurrency");
30364   return new Queue(concurrency);
30365 }
30366
30367 var defaultSource$1 = function() {
30368   return Math.random();
30369 };
30370
30371 var uniform = ((function sourceRandomUniform(source) {
30372   function randomUniform(min, max) {
30373     min = min == null ? 0 : +min;
30374     max = max == null ? 1 : +max;
30375     if (arguments.length === 1) max = min, min = 0;
30376     else max -= min;
30377     return function() {
30378       return source() * max + min;
30379     };
30380   }
30381
30382   randomUniform.source = sourceRandomUniform;
30383
30384   return randomUniform;
30385 }))(defaultSource$1);
30386
30387 var normal = ((function sourceRandomNormal(source) {
30388   function randomNormal(mu, sigma) {
30389     var x, r;
30390     mu = mu == null ? 0 : +mu;
30391     sigma = sigma == null ? 1 : +sigma;
30392     return function() {
30393       var y;
30394
30395       // If available, use the second previously-generated uniform random.
30396       if (x != null) y = x, x = null;
30397
30398       // Otherwise, generate a new x and y.
30399       else do {
30400         x = source() * 2 - 1;
30401         y = source() * 2 - 1;
30402         r = x * x + y * y;
30403       } while (!r || r > 1);
30404
30405       return mu + sigma * y * Math.sqrt(-2 * Math.log(r) / r);
30406     };
30407   }
30408
30409   randomNormal.source = sourceRandomNormal;
30410
30411   return randomNormal;
30412 }))(defaultSource$1);
30413
30414 var logNormal = ((function sourceRandomLogNormal(source) {
30415   function randomLogNormal() {
30416     var randomNormal = normal.source(source).apply(this, arguments);
30417     return function() {
30418       return Math.exp(randomNormal());
30419     };
30420   }
30421
30422   randomLogNormal.source = sourceRandomLogNormal;
30423
30424   return randomLogNormal;
30425 }))(defaultSource$1);
30426
30427 var irwinHall = ((function sourceRandomIrwinHall(source) {
30428   function randomIrwinHall(n) {
30429     return function() {
30430       for (var sum = 0, i = 0; i < n; ++i) sum += source();
30431       return sum;
30432     };
30433   }
30434
30435   randomIrwinHall.source = sourceRandomIrwinHall;
30436
30437   return randomIrwinHall;
30438 }))(defaultSource$1);
30439
30440 var bates = ((function sourceRandomBates(source) {
30441   function randomBates(n) {
30442     var randomIrwinHall = irwinHall.source(source)(n);
30443     return function() {
30444       return randomIrwinHall() / n;
30445     };
30446   }
30447
30448   randomBates.source = sourceRandomBates;
30449
30450   return randomBates;
30451 }))(defaultSource$1);
30452
30453 var exponential$1 = ((function sourceRandomExponential(source) {
30454   function randomExponential(lambda) {
30455     return function() {
30456       return -Math.log(1 - source()) / lambda;
30457     };
30458   }
30459
30460   randomExponential.source = sourceRandomExponential;
30461
30462   return randomExponential;
30463 }))(defaultSource$1);
30464
30465 var request = function(url, callback) {
30466   var request,
30467       event = dispatch("beforesend", "progress", "load", "error"),
30468       mimeType,
30469       headers = map$1(),
30470       xhr = new XMLHttpRequest,
30471       user = null,
30472       password = null,
30473       response,
30474       responseType,
30475       timeout = 0;
30476
30477   // If IE does not support CORS, use XDomainRequest.
30478   if (typeof XDomainRequest !== "undefined"
30479       && !("withCredentials" in xhr)
30480       && /^(http(s)?:)?\/\//.test(url)) xhr = new XDomainRequest;
30481
30482   "onload" in xhr
30483       ? xhr.onload = xhr.onerror = xhr.ontimeout = respond
30484       : xhr.onreadystatechange = function(o) { xhr.readyState > 3 && respond(o); };
30485
30486   function respond(o) {
30487     var status = xhr.status, result;
30488     if (!status && hasResponse(xhr)
30489         || status >= 200 && status < 300
30490         || status === 304) {
30491       if (response) {
30492         try {
30493           result = response.call(request, xhr);
30494         } catch (e) {
30495           event.call("error", request, e);
30496           return;
30497         }
30498       } else {
30499         result = xhr;
30500       }
30501       event.call("load", request, result);
30502     } else {
30503       event.call("error", request, o);
30504     }
30505   }
30506
30507   xhr.onprogress = function(e) {
30508     event.call("progress", request, e);
30509   };
30510
30511   request = {
30512     header: function(name, value) {
30513       name = (name + "").toLowerCase();
30514       if (arguments.length < 2) return headers.get(name);
30515       if (value == null) headers.remove(name);
30516       else headers.set(name, value + "");
30517       return request;
30518     },
30519
30520     // If mimeType is non-null and no Accept header is set, a default is used.
30521     mimeType: function(value) {
30522       if (!arguments.length) return mimeType;
30523       mimeType = value == null ? null : value + "";
30524       return request;
30525     },
30526
30527     // Specifies what type the response value should take;
30528     // for instance, arraybuffer, blob, document, or text.
30529     responseType: function(value) {
30530       if (!arguments.length) return responseType;
30531       responseType = value;
30532       return request;
30533     },
30534
30535     timeout: function(value) {
30536       if (!arguments.length) return timeout;
30537       timeout = +value;
30538       return request;
30539     },
30540
30541     user: function(value) {
30542       return arguments.length < 1 ? user : (user = value == null ? null : value + "", request);
30543     },
30544
30545     password: function(value) {
30546       return arguments.length < 1 ? password : (password = value == null ? null : value + "", request);
30547     },
30548
30549     // Specify how to convert the response content to a specific type;
30550     // changes the callback value on "load" events.
30551     response: function(value) {
30552       response = value;
30553       return request;
30554     },
30555
30556     // Alias for send("GET", …).
30557     get: function(data, callback) {
30558       return request.send("GET", data, callback);
30559     },
30560
30561     // Alias for send("POST", …).
30562     post: function(data, callback) {
30563       return request.send("POST", data, callback);
30564     },
30565
30566     // If callback is non-null, it will be used for error and load events.
30567     send: function(method, data, callback) {
30568       xhr.open(method, url, true, user, password);
30569       if (mimeType != null && !headers.has("accept")) headers.set("accept", mimeType + ",*/*");
30570       if (xhr.setRequestHeader) headers.each(function(value, name) { xhr.setRequestHeader(name, value); });
30571       if (mimeType != null && xhr.overrideMimeType) xhr.overrideMimeType(mimeType);
30572       if (responseType != null) xhr.responseType = responseType;
30573       if (timeout > 0) xhr.timeout = timeout;
30574       if (callback == null && typeof data === "function") callback = data, data = null;
30575       if (callback != null && callback.length === 1) callback = fixCallback(callback);
30576       if (callback != null) request.on("error", callback).on("load", function(xhr) { callback(null, xhr); });
30577       event.call("beforesend", request, xhr);
30578       xhr.send(data == null ? null : data);
30579       return request;
30580     },
30581
30582     abort: function() {
30583       xhr.abort();
30584       return request;
30585     },
30586
30587     on: function() {
30588       var value = event.on.apply(event, arguments);
30589       return value === event ? request : value;
30590     }
30591   };
30592
30593   if (callback != null) {
30594     if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
30595     return request.get(callback);
30596   }
30597
30598   return request;
30599 };
30600
30601 function fixCallback(callback) {
30602   return function(error, xhr) {
30603     callback(error == null ? xhr : null);
30604   };
30605 }
30606
30607 function hasResponse(xhr) {
30608   var type = xhr.responseType;
30609   return type && type !== "text"
30610       ? xhr.response // null on error
30611       : xhr.responseText; // "" on error
30612 }
30613
30614 var type$3 = function(defaultMimeType, response) {
30615   return function(url, callback) {
30616     var r = request(url).mimeType(defaultMimeType).response(response);
30617     if (callback != null) {
30618       if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
30619       return r.get(callback);
30620     }
30621     return r;
30622   };
30623 };
30624
30625 var html = type$3("text/html", function(xhr) {
30626   return document.createRange().createContextualFragment(xhr.responseText);
30627 });
30628
30629 var json = type$3("application/json", function(xhr) {
30630   return JSON.parse(xhr.responseText);
30631 });
30632
30633 var text = type$3("text/plain", function(xhr) {
30634   return xhr.responseText;
30635 });
30636
30637 var xml = type$3("application/xml", function(xhr) {
30638   var xml = xhr.responseXML;
30639   if (!xml) throw new Error("parse error");
30640   return xml;
30641 });
30642
30643 var dsv$1 = function(defaultMimeType, parse) {
30644   return function(url, row, callback) {
30645     if (arguments.length < 3) callback = row, row = null;
30646     var r = request(url).mimeType(defaultMimeType);
30647     r.row = function(_) { return arguments.length ? r.response(responseOf(parse, row = _)) : row; };
30648     r.row(row);
30649     return callback ? r.get(callback) : r;
30650   };
30651 };
30652
30653 function responseOf(parse, row) {
30654   return function(request$$1) {
30655     return parse(request$$1.responseText, row);
30656   };
30657 }
30658
30659 var csv$1 = dsv$1("text/csv", csvParse);
30660
30661 var tsv$1 = dsv$1("text/tab-separated-values", tsvParse);
30662
30663 var array$2 = Array.prototype;
30664
30665 var map$3 = array$2.map;
30666 var slice$4 = array$2.slice;
30667
30668 var implicit = {name: "implicit"};
30669
30670 function ordinal(range) {
30671   var index = map$1(),
30672       domain = [],
30673       unknown = implicit;
30674
30675   range = range == null ? [] : slice$4.call(range);
30676
30677   function scale(d) {
30678     var key = d + "", i = index.get(key);
30679     if (!i) {
30680       if (unknown !== implicit) return unknown;
30681       index.set(key, i = domain.push(d));
30682     }
30683     return range[(i - 1) % range.length];
30684   }
30685
30686   scale.domain = function(_) {
30687     if (!arguments.length) return domain.slice();
30688     domain = [], index = map$1();
30689     var i = -1, n = _.length, d, key;
30690     while (++i < n) if (!index.has(key = (d = _[i]) + "")) index.set(key, domain.push(d));
30691     return scale;
30692   };
30693
30694   scale.range = function(_) {
30695     return arguments.length ? (range = slice$4.call(_), scale) : range.slice();
30696   };
30697
30698   scale.unknown = function(_) {
30699     return arguments.length ? (unknown = _, scale) : unknown;
30700   };
30701
30702   scale.copy = function() {
30703     return ordinal()
30704         .domain(domain)
30705         .range(range)
30706         .unknown(unknown);
30707   };
30708
30709   return scale;
30710 }
30711
30712 function band() {
30713   var scale = ordinal().unknown(undefined),
30714       domain = scale.domain,
30715       ordinalRange = scale.range,
30716       range = [0, 1],
30717       step,
30718       bandwidth,
30719       round = false,
30720       paddingInner = 0,
30721       paddingOuter = 0,
30722       align = 0.5;
30723
30724   delete scale.unknown;
30725
30726   function rescale() {
30727     var n = domain().length,
30728         reverse = range[1] < range[0],
30729         start = range[reverse - 0],
30730         stop = range[1 - reverse];
30731     step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);
30732     if (round) step = Math.floor(step);
30733     start += (stop - start - step * (n - paddingInner)) * align;
30734     bandwidth = step * (1 - paddingInner);
30735     if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);
30736     var values = sequence(n).map(function(i) { return start + step * i; });
30737     return ordinalRange(reverse ? values.reverse() : values);
30738   }
30739
30740   scale.domain = function(_) {
30741     return arguments.length ? (domain(_), rescale()) : domain();
30742   };
30743
30744   scale.range = function(_) {
30745     return arguments.length ? (range = [+_[0], +_[1]], rescale()) : range.slice();
30746   };
30747
30748   scale.rangeRound = function(_) {
30749     return range = [+_[0], +_[1]], round = true, rescale();
30750   };
30751
30752   scale.bandwidth = function() {
30753     return bandwidth;
30754   };
30755
30756   scale.step = function() {
30757     return step;
30758   };
30759
30760   scale.round = function(_) {
30761     return arguments.length ? (round = !!_, rescale()) : round;
30762   };
30763
30764   scale.padding = function(_) {
30765     return arguments.length ? (paddingInner = paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
30766   };
30767
30768   scale.paddingInner = function(_) {
30769     return arguments.length ? (paddingInner = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
30770   };
30771
30772   scale.paddingOuter = function(_) {
30773     return arguments.length ? (paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingOuter;
30774   };
30775
30776   scale.align = function(_) {
30777     return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;
30778   };
30779
30780   scale.copy = function() {
30781     return band()
30782         .domain(domain())
30783         .range(range)
30784         .round(round)
30785         .paddingInner(paddingInner)
30786         .paddingOuter(paddingOuter)
30787         .align(align);
30788   };
30789
30790   return rescale();
30791 }
30792
30793 function pointish(scale) {
30794   var copy = scale.copy;
30795
30796   scale.padding = scale.paddingOuter;
30797   delete scale.paddingInner;
30798   delete scale.paddingOuter;
30799
30800   scale.copy = function() {
30801     return pointish(copy());
30802   };
30803
30804   return scale;
30805 }
30806
30807 function point$1() {
30808   return pointish(band().paddingInner(1));
30809 }
30810
30811 var constant$9 = function(x) {
30812   return function() {
30813     return x;
30814   };
30815 };
30816
30817 var number$1 = function(x) {
30818   return +x;
30819 };
30820
30821 var unit = [0, 1];
30822
30823 function deinterpolateLinear(a, b) {
30824   return (b -= (a = +a))
30825       ? function(x) { return (x - a) / b; }
30826       : constant$9(b);
30827 }
30828
30829 function deinterpolateClamp(deinterpolate) {
30830   return function(a, b) {
30831     var d = deinterpolate(a = +a, b = +b);
30832     return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
30833   };
30834 }
30835
30836 function reinterpolateClamp(reinterpolate$$1) {
30837   return function(a, b) {
30838     var r = reinterpolate$$1(a = +a, b = +b);
30839     return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
30840   };
30841 }
30842
30843 function bimap(domain, range, deinterpolate, reinterpolate$$1) {
30844   var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];
30845   if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate$$1(r1, r0);
30846   else d0 = deinterpolate(d0, d1), r0 = reinterpolate$$1(r0, r1);
30847   return function(x) { return r0(d0(x)); };
30848 }
30849
30850 function polymap(domain, range, deinterpolate, reinterpolate$$1) {
30851   var j = Math.min(domain.length, range.length) - 1,
30852       d = new Array(j),
30853       r = new Array(j),
30854       i = -1;
30855
30856   // Reverse descending domains.
30857   if (domain[j] < domain[0]) {
30858     domain = domain.slice().reverse();
30859     range = range.slice().reverse();
30860   }
30861
30862   while (++i < j) {
30863     d[i] = deinterpolate(domain[i], domain[i + 1]);
30864     r[i] = reinterpolate$$1(range[i], range[i + 1]);
30865   }
30866
30867   return function(x) {
30868     var i = bisectRight(domain, x, 1, j) - 1;
30869     return r[i](d[i](x));
30870   };
30871 }
30872
30873 function copy(source, target) {
30874   return target
30875       .domain(source.domain())
30876       .range(source.range())
30877       .interpolate(source.interpolate())
30878       .clamp(source.clamp());
30879 }
30880
30881 // deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
30882 // reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
30883 function continuous(deinterpolate, reinterpolate$$1) {
30884   var domain = unit,
30885       range = unit,
30886       interpolate = interpolateValue,
30887       clamp = false,
30888       piecewise,
30889       output,
30890       input;
30891
30892   function rescale() {
30893     piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap;
30894     output = input = null;
30895     return scale;
30896   }
30897
30898   function scale(x) {
30899     return (output || (output = piecewise(domain, range, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate)))(+x);
30900   }
30901
30902   scale.invert = function(y) {
30903     return (input || (input = piecewise(range, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate$$1) : reinterpolate$$1)))(+y);
30904   };
30905
30906   scale.domain = function(_) {
30907     return arguments.length ? (domain = map$3.call(_, number$1), rescale()) : domain.slice();
30908   };
30909
30910   scale.range = function(_) {
30911     return arguments.length ? (range = slice$4.call(_), rescale()) : range.slice();
30912   };
30913
30914   scale.rangeRound = function(_) {
30915     return range = slice$4.call(_), interpolate = interpolateRound, rescale();
30916   };
30917
30918   scale.clamp = function(_) {
30919     return arguments.length ? (clamp = !!_, rescale()) : clamp;
30920   };
30921
30922   scale.interpolate = function(_) {
30923     return arguments.length ? (interpolate = _, rescale()) : interpolate;
30924   };
30925
30926   return rescale();
30927 }
30928
30929 var tickFormat = function(domain, count, specifier) {
30930   var start = domain[0],
30931       stop = domain[domain.length - 1],
30932       step = tickStep(start, stop, count == null ? 10 : count),
30933       precision;
30934   specifier = formatSpecifier(specifier == null ? ",f" : specifier);
30935   switch (specifier.type) {
30936     case "s": {
30937       var value = Math.max(Math.abs(start), Math.abs(stop));
30938       if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
30939       return formatPrefix(specifier, value);
30940     }
30941     case "":
30942     case "e":
30943     case "g":
30944     case "p":
30945     case "r": {
30946       if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
30947       break;
30948     }
30949     case "f":
30950     case "%": {
30951       if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
30952       break;
30953     }
30954   }
30955   return format(specifier);
30956 };
30957
30958 function linearish(scale) {
30959   var domain = scale.domain;
30960
30961   scale.ticks = function(count) {
30962     var d = domain();
30963     return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
30964   };
30965
30966   scale.tickFormat = function(count, specifier) {
30967     return tickFormat(domain(), count, specifier);
30968   };
30969
30970   scale.nice = function(count) {
30971     if (count == null) count = 10;
30972
30973     var d = domain(),
30974         i0 = 0,
30975         i1 = d.length - 1,
30976         start = d[i0],
30977         stop = d[i1],
30978         step;
30979
30980     if (stop < start) {
30981       step = start, start = stop, stop = step;
30982       step = i0, i0 = i1, i1 = step;
30983     }
30984
30985     step = tickIncrement(start, stop, count);
30986
30987     if (step > 0) {
30988       start = Math.floor(start / step) * step;
30989       stop = Math.ceil(stop / step) * step;
30990       step = tickIncrement(start, stop, count);
30991     } else if (step < 0) {
30992       start = Math.ceil(start * step) / step;
30993       stop = Math.floor(stop * step) / step;
30994       step = tickIncrement(start, stop, count);
30995     }
30996
30997     if (step > 0) {
30998       d[i0] = Math.floor(start / step) * step;
30999       d[i1] = Math.ceil(stop / step) * step;
31000       domain(d);
31001     } else if (step < 0) {
31002       d[i0] = Math.ceil(start * step) / step;
31003       d[i1] = Math.floor(stop * step) / step;
31004       domain(d);
31005     }
31006
31007     return scale;
31008   };
31009
31010   return scale;
31011 }
31012
31013 function linear$2() {
31014   var scale = continuous(deinterpolateLinear, reinterpolate);
31015
31016   scale.copy = function() {
31017     return copy(scale, linear$2());
31018   };
31019
31020   return linearish(scale);
31021 }
31022
31023 function identity$6() {
31024   var domain = [0, 1];
31025
31026   function scale(x) {
31027     return +x;
31028   }
31029
31030   scale.invert = scale;
31031
31032   scale.domain = scale.range = function(_) {
31033     return arguments.length ? (domain = map$3.call(_, number$1), scale) : domain.slice();
31034   };
31035
31036   scale.copy = function() {
31037     return identity$6().domain(domain);
31038   };
31039
31040   return linearish(scale);
31041 }
31042
31043 var nice = function(domain, interval) {
31044   domain = domain.slice();
31045
31046   var i0 = 0,
31047       i1 = domain.length - 1,
31048       x0 = domain[i0],
31049       x1 = domain[i1],
31050       t;
31051
31052   if (x1 < x0) {
31053     t = i0, i0 = i1, i1 = t;
31054     t = x0, x0 = x1, x1 = t;
31055   }
31056
31057   domain[i0] = interval.floor(x0);
31058   domain[i1] = interval.ceil(x1);
31059   return domain;
31060 };
31061
31062 function deinterpolate(a, b) {
31063   return (b = Math.log(b / a))
31064       ? function(x) { return Math.log(x / a) / b; }
31065       : constant$9(b);
31066 }
31067
31068 function reinterpolate$1(a, b) {
31069   return a < 0
31070       ? function(t) { return -Math.pow(-b, t) * Math.pow(-a, 1 - t); }
31071       : function(t) { return Math.pow(b, t) * Math.pow(a, 1 - t); };
31072 }
31073
31074 function pow10(x) {
31075   return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x;
31076 }
31077
31078 function powp(base) {
31079   return base === 10 ? pow10
31080       : base === Math.E ? Math.exp
31081       : function(x) { return Math.pow(base, x); };
31082 }
31083
31084 function logp(base) {
31085   return base === Math.E ? Math.log
31086       : base === 10 && Math.log10
31087       || base === 2 && Math.log2
31088       || (base = Math.log(base), function(x) { return Math.log(x) / base; });
31089 }
31090
31091 function reflect(f) {
31092   return function(x) {
31093     return -f(-x);
31094   };
31095 }
31096
31097 function log$1() {
31098   var scale = continuous(deinterpolate, reinterpolate$1).domain([1, 10]),
31099       domain = scale.domain,
31100       base = 10,
31101       logs = logp(10),
31102       pows = powp(10);
31103
31104   function rescale() {
31105     logs = logp(base), pows = powp(base);
31106     if (domain()[0] < 0) logs = reflect(logs), pows = reflect(pows);
31107     return scale;
31108   }
31109
31110   scale.base = function(_) {
31111     return arguments.length ? (base = +_, rescale()) : base;
31112   };
31113
31114   scale.domain = function(_) {
31115     return arguments.length ? (domain(_), rescale()) : domain();
31116   };
31117
31118   scale.ticks = function(count) {
31119     var d = domain(),
31120         u = d[0],
31121         v = d[d.length - 1],
31122         r;
31123
31124     if (r = v < u) i = u, u = v, v = i;
31125
31126     var i = logs(u),
31127         j = logs(v),
31128         p,
31129         k,
31130         t,
31131         n = count == null ? 10 : +count,
31132         z = [];
31133
31134     if (!(base % 1) && j - i < n) {
31135       i = Math.round(i) - 1, j = Math.round(j) + 1;
31136       if (u > 0) for (; i < j; ++i) {
31137         for (k = 1, p = pows(i); k < base; ++k) {
31138           t = p * k;
31139           if (t < u) continue;
31140           if (t > v) break;
31141           z.push(t);
31142         }
31143       } else for (; i < j; ++i) {
31144         for (k = base - 1, p = pows(i); k >= 1; --k) {
31145           t = p * k;
31146           if (t < u) continue;
31147           if (t > v) break;
31148           z.push(t);
31149         }
31150       }
31151     } else {
31152       z = ticks(i, j, Math.min(j - i, n)).map(pows);
31153     }
31154
31155     return r ? z.reverse() : z;
31156   };
31157
31158   scale.tickFormat = function(count, specifier) {
31159     if (specifier == null) specifier = base === 10 ? ".0e" : ",";
31160     if (typeof specifier !== "function") specifier = format(specifier);
31161     if (count === Infinity) return specifier;
31162     if (count == null) count = 10;
31163     var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
31164     return function(d) {
31165       var i = d / pows(Math.round(logs(d)));
31166       if (i * base < base - 0.5) i *= base;
31167       return i <= k ? specifier(d) : "";
31168     };
31169   };
31170
31171   scale.nice = function() {
31172     return domain(nice(domain(), {
31173       floor: function(x) { return pows(Math.floor(logs(x))); },
31174       ceil: function(x) { return pows(Math.ceil(logs(x))); }
31175     }));
31176   };
31177
31178   scale.copy = function() {
31179     return copy(scale, log$1().base(base));
31180   };
31181
31182   return scale;
31183 }
31184
31185 function raise$1(x, exponent) {
31186   return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
31187 }
31188
31189 function pow$1() {
31190   var exponent = 1,
31191       scale = continuous(deinterpolate, reinterpolate),
31192       domain = scale.domain;
31193
31194   function deinterpolate(a, b) {
31195     return (b = raise$1(b, exponent) - (a = raise$1(a, exponent)))
31196         ? function(x) { return (raise$1(x, exponent) - a) / b; }
31197         : constant$9(b);
31198   }
31199
31200   function reinterpolate(a, b) {
31201     b = raise$1(b, exponent) - (a = raise$1(a, exponent));
31202     return function(t) { return raise$1(a + b * t, 1 / exponent); };
31203   }
31204
31205   scale.exponent = function(_) {
31206     return arguments.length ? (exponent = +_, domain(domain())) : exponent;
31207   };
31208
31209   scale.copy = function() {
31210     return copy(scale, pow$1().exponent(exponent));
31211   };
31212
31213   return linearish(scale);
31214 }
31215
31216 function sqrt$1() {
31217   return pow$1().exponent(0.5);
31218 }
31219
31220 function quantile() {
31221   var domain = [],
31222       range = [],
31223       thresholds = [];
31224
31225   function rescale() {
31226     var i = 0, n = Math.max(1, range.length);
31227     thresholds = new Array(n - 1);
31228     while (++i < n) thresholds[i - 1] = threshold(domain, i / n);
31229     return scale;
31230   }
31231
31232   function scale(x) {
31233     if (!isNaN(x = +x)) return range[bisectRight(thresholds, x)];
31234   }
31235
31236   scale.invertExtent = function(y) {
31237     var i = range.indexOf(y);
31238     return i < 0 ? [NaN, NaN] : [
31239       i > 0 ? thresholds[i - 1] : domain[0],
31240       i < thresholds.length ? thresholds[i] : domain[domain.length - 1]
31241     ];
31242   };
31243
31244   scale.domain = function(_) {
31245     if (!arguments.length) return domain.slice();
31246     domain = [];
31247     for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d);
31248     domain.sort(ascending);
31249     return rescale();
31250   };
31251
31252   scale.range = function(_) {
31253     return arguments.length ? (range = slice$4.call(_), rescale()) : range.slice();
31254   };
31255
31256   scale.quantiles = function() {
31257     return thresholds.slice();
31258   };
31259
31260   scale.copy = function() {
31261     return quantile()
31262         .domain(domain)
31263         .range(range);
31264   };
31265
31266   return scale;
31267 }
31268
31269 function quantize$1() {
31270   var x0 = 0,
31271       x1 = 1,
31272       n = 1,
31273       domain = [0.5],
31274       range = [0, 1];
31275
31276   function scale(x) {
31277     if (x <= x) return range[bisectRight(domain, x, 0, n)];
31278   }
31279
31280   function rescale() {
31281     var i = -1;
31282     domain = new Array(n);
31283     while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
31284     return scale;
31285   }
31286
31287   scale.domain = function(_) {
31288     return arguments.length ? (x0 = +_[0], x1 = +_[1], rescale()) : [x0, x1];
31289   };
31290
31291   scale.range = function(_) {
31292     return arguments.length ? (n = (range = slice$4.call(_)).length - 1, rescale()) : range.slice();
31293   };
31294
31295   scale.invertExtent = function(y) {
31296     var i = range.indexOf(y);
31297     return i < 0 ? [NaN, NaN]
31298         : i < 1 ? [x0, domain[0]]
31299         : i >= n ? [domain[n - 1], x1]
31300         : [domain[i - 1], domain[i]];
31301   };
31302
31303   scale.copy = function() {
31304     return quantize$1()
31305         .domain([x0, x1])
31306         .range(range);
31307   };
31308
31309   return linearish(scale);
31310 }
31311
31312 function threshold$1() {
31313   var domain = [0.5],
31314       range = [0, 1],
31315       n = 1;
31316
31317   function scale(x) {
31318     if (x <= x) return range[bisectRight(domain, x, 0, n)];
31319   }
31320
31321   scale.domain = function(_) {
31322     return arguments.length ? (domain = slice$4.call(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();
31323   };
31324
31325   scale.range = function(_) {
31326     return arguments.length ? (range = slice$4.call(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice();
31327   };
31328
31329   scale.invertExtent = function(y) {
31330     var i = range.indexOf(y);
31331     return [domain[i - 1], domain[i]];
31332   };
31333
31334   scale.copy = function() {
31335     return threshold$1()
31336         .domain(domain)
31337         .range(range);
31338   };
31339
31340   return scale;
31341 }
31342
31343 var t0$1 = new Date;
31344 var t1$1 = new Date;
31345
31346 function newInterval(floori, offseti, count, field) {
31347
31348   function interval(date) {
31349     return floori(date = new Date(+date)), date;
31350   }
31351
31352   interval.floor = interval;
31353
31354   interval.ceil = function(date) {
31355     return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;
31356   };
31357
31358   interval.round = function(date) {
31359     var d0 = interval(date),
31360         d1 = interval.ceil(date);
31361     return date - d0 < d1 - date ? d0 : d1;
31362   };
31363
31364   interval.offset = function(date, step) {
31365     return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
31366   };
31367
31368   interval.range = function(start, stop, step) {
31369     var range = [];
31370     start = interval.ceil(start);
31371     step = step == null ? 1 : Math.floor(step);
31372     if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
31373     do range.push(new Date(+start)); while (offseti(start, step), floori(start), start < stop)
31374     return range;
31375   };
31376
31377   interval.filter = function(test) {
31378     return newInterval(function(date) {
31379       if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);
31380     }, function(date, step) {
31381       if (date >= date) while (--step >= 0) while (offseti(date, 1), !test(date)) {} // eslint-disable-line no-empty
31382     });
31383   };
31384
31385   if (count) {
31386     interval.count = function(start, end) {
31387       t0$1.setTime(+start), t1$1.setTime(+end);
31388       floori(t0$1), floori(t1$1);
31389       return Math.floor(count(t0$1, t1$1));
31390     };
31391
31392     interval.every = function(step) {
31393       step = Math.floor(step);
31394       return !isFinite(step) || !(step > 0) ? null
31395           : !(step > 1) ? interval
31396           : interval.filter(field
31397               ? function(d) { return field(d) % step === 0; }
31398               : function(d) { return interval.count(0, d) % step === 0; });
31399     };
31400   }
31401
31402   return interval;
31403 }
31404
31405 var millisecond = newInterval(function() {
31406   // noop
31407 }, function(date, step) {
31408   date.setTime(+date + step);
31409 }, function(start, end) {
31410   return end - start;
31411 });
31412
31413 // An optimized implementation for this simple case.
31414 millisecond.every = function(k) {
31415   k = Math.floor(k);
31416   if (!isFinite(k) || !(k > 0)) return null;
31417   if (!(k > 1)) return millisecond;
31418   return newInterval(function(date) {
31419     date.setTime(Math.floor(date / k) * k);
31420   }, function(date, step) {
31421     date.setTime(+date + step * k);
31422   }, function(start, end) {
31423     return (end - start) / k;
31424   });
31425 };
31426
31427 var milliseconds = millisecond.range;
31428
31429 var durationSecond$1 = 1e3;
31430 var durationMinute$1 = 6e4;
31431 var durationHour$1 = 36e5;
31432 var durationDay$1 = 864e5;
31433 var durationWeek$1 = 6048e5;
31434
31435 var second = newInterval(function(date) {
31436   date.setTime(Math.floor(date / durationSecond$1) * durationSecond$1);
31437 }, function(date, step) {
31438   date.setTime(+date + step * durationSecond$1);
31439 }, function(start, end) {
31440   return (end - start) / durationSecond$1;
31441 }, function(date) {
31442   return date.getUTCSeconds();
31443 });
31444
31445 var seconds = second.range;
31446
31447 var minute = newInterval(function(date) {
31448   date.setTime(Math.floor(date / durationMinute$1) * durationMinute$1);
31449 }, function(date, step) {
31450   date.setTime(+date + step * durationMinute$1);
31451 }, function(start, end) {
31452   return (end - start) / durationMinute$1;
31453 }, function(date) {
31454   return date.getMinutes();
31455 });
31456
31457 var minutes = minute.range;
31458
31459 var hour = newInterval(function(date) {
31460   var offset = date.getTimezoneOffset() * durationMinute$1 % durationHour$1;
31461   if (offset < 0) offset += durationHour$1;
31462   date.setTime(Math.floor((+date - offset) / durationHour$1) * durationHour$1 + offset);
31463 }, function(date, step) {
31464   date.setTime(+date + step * durationHour$1);
31465 }, function(start, end) {
31466   return (end - start) / durationHour$1;
31467 }, function(date) {
31468   return date.getHours();
31469 });
31470
31471 var hours = hour.range;
31472
31473 var day = newInterval(function(date) {
31474   date.setHours(0, 0, 0, 0);
31475 }, function(date, step) {
31476   date.setDate(date.getDate() + step);
31477 }, function(start, end) {
31478   return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute$1) / durationDay$1;
31479 }, function(date) {
31480   return date.getDate() - 1;
31481 });
31482
31483 var days = day.range;
31484
31485 function weekday(i) {
31486   return newInterval(function(date) {
31487     date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
31488     date.setHours(0, 0, 0, 0);
31489   }, function(date, step) {
31490     date.setDate(date.getDate() + step * 7);
31491   }, function(start, end) {
31492     return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute$1) / durationWeek$1;
31493   });
31494 }
31495
31496 var sunday = weekday(0);
31497 var monday = weekday(1);
31498 var tuesday = weekday(2);
31499 var wednesday = weekday(3);
31500 var thursday = weekday(4);
31501 var friday = weekday(5);
31502 var saturday = weekday(6);
31503
31504 var sundays = sunday.range;
31505 var mondays = monday.range;
31506 var tuesdays = tuesday.range;
31507 var wednesdays = wednesday.range;
31508 var thursdays = thursday.range;
31509 var fridays = friday.range;
31510 var saturdays = saturday.range;
31511
31512 var month = newInterval(function(date) {
31513   date.setDate(1);
31514   date.setHours(0, 0, 0, 0);
31515 }, function(date, step) {
31516   date.setMonth(date.getMonth() + step);
31517 }, function(start, end) {
31518   return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
31519 }, function(date) {
31520   return date.getMonth();
31521 });
31522
31523 var months = month.range;
31524
31525 var year = newInterval(function(date) {
31526   date.setMonth(0, 1);
31527   date.setHours(0, 0, 0, 0);
31528 }, function(date, step) {
31529   date.setFullYear(date.getFullYear() + step);
31530 }, function(start, end) {
31531   return end.getFullYear() - start.getFullYear();
31532 }, function(date) {
31533   return date.getFullYear();
31534 });
31535
31536 // An optimized implementation for this simple case.
31537 year.every = function(k) {
31538   return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
31539     date.setFullYear(Math.floor(date.getFullYear() / k) * k);
31540     date.setMonth(0, 1);
31541     date.setHours(0, 0, 0, 0);
31542   }, function(date, step) {
31543     date.setFullYear(date.getFullYear() + step * k);
31544   });
31545 };
31546
31547 var years = year.range;
31548
31549 var utcMinute = newInterval(function(date) {
31550   date.setUTCSeconds(0, 0);
31551 }, function(date, step) {
31552   date.setTime(+date + step * durationMinute$1);
31553 }, function(start, end) {
31554   return (end - start) / durationMinute$1;
31555 }, function(date) {
31556   return date.getUTCMinutes();
31557 });
31558
31559 var utcMinutes = utcMinute.range;
31560
31561 var utcHour = newInterval(function(date) {
31562   date.setUTCMinutes(0, 0, 0);
31563 }, function(date, step) {
31564   date.setTime(+date + step * durationHour$1);
31565 }, function(start, end) {
31566   return (end - start) / durationHour$1;
31567 }, function(date) {
31568   return date.getUTCHours();
31569 });
31570
31571 var utcHours = utcHour.range;
31572
31573 var utcDay = newInterval(function(date) {
31574   date.setUTCHours(0, 0, 0, 0);
31575 }, function(date, step) {
31576   date.setUTCDate(date.getUTCDate() + step);
31577 }, function(start, end) {
31578   return (end - start) / durationDay$1;
31579 }, function(date) {
31580   return date.getUTCDate() - 1;
31581 });
31582
31583 var utcDays = utcDay.range;
31584
31585 function utcWeekday(i) {
31586   return newInterval(function(date) {
31587     date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
31588     date.setUTCHours(0, 0, 0, 0);
31589   }, function(date, step) {
31590     date.setUTCDate(date.getUTCDate() + step * 7);
31591   }, function(start, end) {
31592     return (end - start) / durationWeek$1;
31593   });
31594 }
31595
31596 var utcSunday = utcWeekday(0);
31597 var utcMonday = utcWeekday(1);
31598 var utcTuesday = utcWeekday(2);
31599 var utcWednesday = utcWeekday(3);
31600 var utcThursday = utcWeekday(4);
31601 var utcFriday = utcWeekday(5);
31602 var utcSaturday = utcWeekday(6);
31603
31604 var utcSundays = utcSunday.range;
31605 var utcMondays = utcMonday.range;
31606 var utcTuesdays = utcTuesday.range;
31607 var utcWednesdays = utcWednesday.range;
31608 var utcThursdays = utcThursday.range;
31609 var utcFridays = utcFriday.range;
31610 var utcSaturdays = utcSaturday.range;
31611
31612 var utcMonth = newInterval(function(date) {
31613   date.setUTCDate(1);
31614   date.setUTCHours(0, 0, 0, 0);
31615 }, function(date, step) {
31616   date.setUTCMonth(date.getUTCMonth() + step);
31617 }, function(start, end) {
31618   return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
31619 }, function(date) {
31620   return date.getUTCMonth();
31621 });
31622
31623 var utcMonths = utcMonth.range;
31624
31625 var utcYear = newInterval(function(date) {
31626   date.setUTCMonth(0, 1);
31627   date.setUTCHours(0, 0, 0, 0);
31628 }, function(date, step) {
31629   date.setUTCFullYear(date.getUTCFullYear() + step);
31630 }, function(start, end) {
31631   return end.getUTCFullYear() - start.getUTCFullYear();
31632 }, function(date) {
31633   return date.getUTCFullYear();
31634 });
31635
31636 // An optimized implementation for this simple case.
31637 utcYear.every = function(k) {
31638   return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
31639     date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
31640     date.setUTCMonth(0, 1);
31641     date.setUTCHours(0, 0, 0, 0);
31642   }, function(date, step) {
31643     date.setUTCFullYear(date.getUTCFullYear() + step * k);
31644   });
31645 };
31646
31647 var utcYears = utcYear.range;
31648
31649 function localDate(d) {
31650   if (0 <= d.y && d.y < 100) {
31651     var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);
31652     date.setFullYear(d.y);
31653     return date;
31654   }
31655   return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);
31656 }
31657
31658 function utcDate(d) {
31659   if (0 <= d.y && d.y < 100) {
31660     var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));
31661     date.setUTCFullYear(d.y);
31662     return date;
31663   }
31664   return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));
31665 }
31666
31667 function newYear(y) {
31668   return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0};
31669 }
31670
31671 function formatLocale$1(locale) {
31672   var locale_dateTime = locale.dateTime,
31673       locale_date = locale.date,
31674       locale_time = locale.time,
31675       locale_periods = locale.periods,
31676       locale_weekdays = locale.days,
31677       locale_shortWeekdays = locale.shortDays,
31678       locale_months = locale.months,
31679       locale_shortMonths = locale.shortMonths;
31680
31681   var periodRe = formatRe(locale_periods),
31682       periodLookup = formatLookup(locale_periods),
31683       weekdayRe = formatRe(locale_weekdays),
31684       weekdayLookup = formatLookup(locale_weekdays),
31685       shortWeekdayRe = formatRe(locale_shortWeekdays),
31686       shortWeekdayLookup = formatLookup(locale_shortWeekdays),
31687       monthRe = formatRe(locale_months),
31688       monthLookup = formatLookup(locale_months),
31689       shortMonthRe = formatRe(locale_shortMonths),
31690       shortMonthLookup = formatLookup(locale_shortMonths);
31691
31692   var formats = {
31693     "a": formatShortWeekday,
31694     "A": formatWeekday,
31695     "b": formatShortMonth,
31696     "B": formatMonth,
31697     "c": null,
31698     "d": formatDayOfMonth,
31699     "e": formatDayOfMonth,
31700     "H": formatHour24,
31701     "I": formatHour12,
31702     "j": formatDayOfYear,
31703     "L": formatMilliseconds,
31704     "m": formatMonthNumber,
31705     "M": formatMinutes,
31706     "p": formatPeriod,
31707     "S": formatSeconds,
31708     "U": formatWeekNumberSunday,
31709     "w": formatWeekdayNumber,
31710     "W": formatWeekNumberMonday,
31711     "x": null,
31712     "X": null,
31713     "y": formatYear,
31714     "Y": formatFullYear,
31715     "Z": formatZone,
31716     "%": formatLiteralPercent
31717   };
31718
31719   var utcFormats = {
31720     "a": formatUTCShortWeekday,
31721     "A": formatUTCWeekday,
31722     "b": formatUTCShortMonth,
31723     "B": formatUTCMonth,
31724     "c": null,
31725     "d": formatUTCDayOfMonth,
31726     "e": formatUTCDayOfMonth,
31727     "H": formatUTCHour24,
31728     "I": formatUTCHour12,
31729     "j": formatUTCDayOfYear,
31730     "L": formatUTCMilliseconds,
31731     "m": formatUTCMonthNumber,
31732     "M": formatUTCMinutes,
31733     "p": formatUTCPeriod,
31734     "S": formatUTCSeconds,
31735     "U": formatUTCWeekNumberSunday,
31736     "w": formatUTCWeekdayNumber,
31737     "W": formatUTCWeekNumberMonday,
31738     "x": null,
31739     "X": null,
31740     "y": formatUTCYear,
31741     "Y": formatUTCFullYear,
31742     "Z": formatUTCZone,
31743     "%": formatLiteralPercent
31744   };
31745
31746   var parses = {
31747     "a": parseShortWeekday,
31748     "A": parseWeekday,
31749     "b": parseShortMonth,
31750     "B": parseMonth,
31751     "c": parseLocaleDateTime,
31752     "d": parseDayOfMonth,
31753     "e": parseDayOfMonth,
31754     "H": parseHour24,
31755     "I": parseHour24,
31756     "j": parseDayOfYear,
31757     "L": parseMilliseconds,
31758     "m": parseMonthNumber,
31759     "M": parseMinutes,
31760     "p": parsePeriod,
31761     "S": parseSeconds,
31762     "U": parseWeekNumberSunday,
31763     "w": parseWeekdayNumber,
31764     "W": parseWeekNumberMonday,
31765     "x": parseLocaleDate,
31766     "X": parseLocaleTime,
31767     "y": parseYear,
31768     "Y": parseFullYear,
31769     "Z": parseZone,
31770     "%": parseLiteralPercent
31771   };
31772
31773   // These recursive directive definitions must be deferred.
31774   formats.x = newFormat(locale_date, formats);
31775   formats.X = newFormat(locale_time, formats);
31776   formats.c = newFormat(locale_dateTime, formats);
31777   utcFormats.x = newFormat(locale_date, utcFormats);
31778   utcFormats.X = newFormat(locale_time, utcFormats);
31779   utcFormats.c = newFormat(locale_dateTime, utcFormats);
31780
31781   function newFormat(specifier, formats) {
31782     return function(date) {
31783       var string = [],
31784           i = -1,
31785           j = 0,
31786           n = specifier.length,
31787           c,
31788           pad,
31789           format;
31790
31791       if (!(date instanceof Date)) date = new Date(+date);
31792
31793       while (++i < n) {
31794         if (specifier.charCodeAt(i) === 37) {
31795           string.push(specifier.slice(j, i));
31796           if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);
31797           else pad = c === "e" ? " " : "0";
31798           if (format = formats[c]) c = format(date, pad);
31799           string.push(c);
31800           j = i + 1;
31801         }
31802       }
31803
31804       string.push(specifier.slice(j, i));
31805       return string.join("");
31806     };
31807   }
31808
31809   function newParse(specifier, newDate) {
31810     return function(string) {
31811       var d = newYear(1900),
31812           i = parseSpecifier(d, specifier, string += "", 0);
31813       if (i != string.length) return null;
31814
31815       // The am-pm flag is 0 for AM, and 1 for PM.
31816       if ("p" in d) d.H = d.H % 12 + d.p * 12;
31817
31818       // Convert day-of-week and week-of-year to day-of-year.
31819       if ("W" in d || "U" in d) {
31820         if (!("w" in d)) d.w = "W" in d ? 1 : 0;
31821         var day$$1 = "Z" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).getDay();
31822         d.m = 0;
31823         d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day$$1 + 5) % 7 : d.w + d.U * 7 - (day$$1 + 6) % 7;
31824       }
31825
31826       // If a time zone is specified, all fields are interpreted as UTC and then
31827       // offset according to the specified time zone.
31828       if ("Z" in d) {
31829         d.H += d.Z / 100 | 0;
31830         d.M += d.Z % 100;
31831         return utcDate(d);
31832       }
31833
31834       // Otherwise, all fields are in local time.
31835       return newDate(d);
31836     };
31837   }
31838
31839   function parseSpecifier(d, specifier, string, j) {
31840     var i = 0,
31841         n = specifier.length,
31842         m = string.length,
31843         c,
31844         parse;
31845
31846     while (i < n) {
31847       if (j >= m) return -1;
31848       c = specifier.charCodeAt(i++);
31849       if (c === 37) {
31850         c = specifier.charAt(i++);
31851         parse = parses[c in pads ? specifier.charAt(i++) : c];
31852         if (!parse || ((j = parse(d, string, j)) < 0)) return -1;
31853       } else if (c != string.charCodeAt(j++)) {
31854         return -1;
31855       }
31856     }
31857
31858     return j;
31859   }
31860
31861   function parsePeriod(d, string, i) {
31862     var n = periodRe.exec(string.slice(i));
31863     return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31864   }
31865
31866   function parseShortWeekday(d, string, i) {
31867     var n = shortWeekdayRe.exec(string.slice(i));
31868     return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31869   }
31870
31871   function parseWeekday(d, string, i) {
31872     var n = weekdayRe.exec(string.slice(i));
31873     return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31874   }
31875
31876   function parseShortMonth(d, string, i) {
31877     var n = shortMonthRe.exec(string.slice(i));
31878     return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31879   }
31880
31881   function parseMonth(d, string, i) {
31882     var n = monthRe.exec(string.slice(i));
31883     return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31884   }
31885
31886   function parseLocaleDateTime(d, string, i) {
31887     return parseSpecifier(d, locale_dateTime, string, i);
31888   }
31889
31890   function parseLocaleDate(d, string, i) {
31891     return parseSpecifier(d, locale_date, string, i);
31892   }
31893
31894   function parseLocaleTime(d, string, i) {
31895     return parseSpecifier(d, locale_time, string, i);
31896   }
31897
31898   function formatShortWeekday(d) {
31899     return locale_shortWeekdays[d.getDay()];
31900   }
31901
31902   function formatWeekday(d) {
31903     return locale_weekdays[d.getDay()];
31904   }
31905
31906   function formatShortMonth(d) {
31907     return locale_shortMonths[d.getMonth()];
31908   }
31909
31910   function formatMonth(d) {
31911     return locale_months[d.getMonth()];
31912   }
31913
31914   function formatPeriod(d) {
31915     return locale_periods[+(d.getHours() >= 12)];
31916   }
31917
31918   function formatUTCShortWeekday(d) {
31919     return locale_shortWeekdays[d.getUTCDay()];
31920   }
31921
31922   function formatUTCWeekday(d) {
31923     return locale_weekdays[d.getUTCDay()];
31924   }
31925
31926   function formatUTCShortMonth(d) {
31927     return locale_shortMonths[d.getUTCMonth()];
31928   }
31929
31930   function formatUTCMonth(d) {
31931     return locale_months[d.getUTCMonth()];
31932   }
31933
31934   function formatUTCPeriod(d) {
31935     return locale_periods[+(d.getUTCHours() >= 12)];
31936   }
31937
31938   return {
31939     format: function(specifier) {
31940       var f = newFormat(specifier += "", formats);
31941       f.toString = function() { return specifier; };
31942       return f;
31943     },
31944     parse: function(specifier) {
31945       var p = newParse(specifier += "", localDate);
31946       p.toString = function() { return specifier; };
31947       return p;
31948     },
31949     utcFormat: function(specifier) {
31950       var f = newFormat(specifier += "", utcFormats);
31951       f.toString = function() { return specifier; };
31952       return f;
31953     },
31954     utcParse: function(specifier) {
31955       var p = newParse(specifier, utcDate);
31956       p.toString = function() { return specifier; };
31957       return p;
31958     }
31959   };
31960 }
31961
31962 var pads = {"-": "", "_": " ", "0": "0"};
31963 var numberRe = /^\s*\d+/;
31964 var percentRe = /^%/;
31965 var requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
31966
31967 function pad(value, fill, width) {
31968   var sign = value < 0 ? "-" : "",
31969       string = (sign ? -value : value) + "",
31970       length = string.length;
31971   return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
31972 }
31973
31974 function requote(s) {
31975   return s.replace(requoteRe, "\\$&");
31976 }
31977
31978 function formatRe(names) {
31979   return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
31980 }
31981
31982 function formatLookup(names) {
31983   var map = {}, i = -1, n = names.length;
31984   while (++i < n) map[names[i].toLowerCase()] = i;
31985   return map;
31986 }
31987
31988 function parseWeekdayNumber(d, string, i) {
31989   var n = numberRe.exec(string.slice(i, i + 1));
31990   return n ? (d.w = +n[0], i + n[0].length) : -1;
31991 }
31992
31993 function parseWeekNumberSunday(d, string, i) {
31994   var n = numberRe.exec(string.slice(i));
31995   return n ? (d.U = +n[0], i + n[0].length) : -1;
31996 }
31997
31998 function parseWeekNumberMonday(d, string, i) {
31999   var n = numberRe.exec(string.slice(i));
32000   return n ? (d.W = +n[0], i + n[0].length) : -1;
32001 }
32002
32003 function parseFullYear(d, string, i) {
32004   var n = numberRe.exec(string.slice(i, i + 4));
32005   return n ? (d.y = +n[0], i + n[0].length) : -1;
32006 }
32007
32008 function parseYear(d, string, i) {
32009   var n = numberRe.exec(string.slice(i, i + 2));
32010   return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;
32011 }
32012
32013 function parseZone(d, string, i) {
32014   var n = /^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(string.slice(i, i + 6));
32015   return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1;
32016 }
32017
32018 function parseMonthNumber(d, string, i) {
32019   var n = numberRe.exec(string.slice(i, i + 2));
32020   return n ? (d.m = n[0] - 1, i + n[0].length) : -1;
32021 }
32022
32023 function parseDayOfMonth(d, string, i) {
32024   var n = numberRe.exec(string.slice(i, i + 2));
32025   return n ? (d.d = +n[0], i + n[0].length) : -1;
32026 }
32027
32028 function parseDayOfYear(d, string, i) {
32029   var n = numberRe.exec(string.slice(i, i + 3));
32030   return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;
32031 }
32032
32033 function parseHour24(d, string, i) {
32034   var n = numberRe.exec(string.slice(i, i + 2));
32035   return n ? (d.H = +n[0], i + n[0].length) : -1;
32036 }
32037
32038 function parseMinutes(d, string, i) {
32039   var n = numberRe.exec(string.slice(i, i + 2));
32040   return n ? (d.M = +n[0], i + n[0].length) : -1;
32041 }
32042
32043 function parseSeconds(d, string, i) {
32044   var n = numberRe.exec(string.slice(i, i + 2));
32045   return n ? (d.S = +n[0], i + n[0].length) : -1;
32046 }
32047
32048 function parseMilliseconds(d, string, i) {
32049   var n = numberRe.exec(string.slice(i, i + 3));
32050   return n ? (d.L = +n[0], i + n[0].length) : -1;
32051 }
32052
32053 function parseLiteralPercent(d, string, i) {
32054   var n = percentRe.exec(string.slice(i, i + 1));
32055   return n ? i + n[0].length : -1;
32056 }
32057
32058 function formatDayOfMonth(d, p) {
32059   return pad(d.getDate(), p, 2);
32060 }
32061
32062 function formatHour24(d, p) {
32063   return pad(d.getHours(), p, 2);
32064 }
32065
32066 function formatHour12(d, p) {
32067   return pad(d.getHours() % 12 || 12, p, 2);
32068 }
32069
32070 function formatDayOfYear(d, p) {
32071   return pad(1 + day.count(year(d), d), p, 3);
32072 }
32073
32074 function formatMilliseconds(d, p) {
32075   return pad(d.getMilliseconds(), p, 3);
32076 }
32077
32078 function formatMonthNumber(d, p) {
32079   return pad(d.getMonth() + 1, p, 2);
32080 }
32081
32082 function formatMinutes(d, p) {
32083   return pad(d.getMinutes(), p, 2);
32084 }
32085
32086 function formatSeconds(d, p) {
32087   return pad(d.getSeconds(), p, 2);
32088 }
32089
32090 function formatWeekNumberSunday(d, p) {
32091   return pad(sunday.count(year(d), d), p, 2);
32092 }
32093
32094 function formatWeekdayNumber(d) {
32095   return d.getDay();
32096 }
32097
32098 function formatWeekNumberMonday(d, p) {
32099   return pad(monday.count(year(d), d), p, 2);
32100 }
32101
32102 function formatYear(d, p) {
32103   return pad(d.getFullYear() % 100, p, 2);
32104 }
32105
32106 function formatFullYear(d, p) {
32107   return pad(d.getFullYear() % 10000, p, 4);
32108 }
32109
32110 function formatZone(d) {
32111   var z = d.getTimezoneOffset();
32112   return (z > 0 ? "-" : (z *= -1, "+"))
32113       + pad(z / 60 | 0, "0", 2)
32114       + pad(z % 60, "0", 2);
32115 }
32116
32117 function formatUTCDayOfMonth(d, p) {
32118   return pad(d.getUTCDate(), p, 2);
32119 }
32120
32121 function formatUTCHour24(d, p) {
32122   return pad(d.getUTCHours(), p, 2);
32123 }
32124
32125 function formatUTCHour12(d, p) {
32126   return pad(d.getUTCHours() % 12 || 12, p, 2);
32127 }
32128
32129 function formatUTCDayOfYear(d, p) {
32130   return pad(1 + utcDay.count(utcYear(d), d), p, 3);
32131 }
32132
32133 function formatUTCMilliseconds(d, p) {
32134   return pad(d.getUTCMilliseconds(), p, 3);
32135 }
32136
32137 function formatUTCMonthNumber(d, p) {
32138   return pad(d.getUTCMonth() + 1, p, 2);
32139 }
32140
32141 function formatUTCMinutes(d, p) {
32142   return pad(d.getUTCMinutes(), p, 2);
32143 }
32144
32145 function formatUTCSeconds(d, p) {
32146   return pad(d.getUTCSeconds(), p, 2);
32147 }
32148
32149 function formatUTCWeekNumberSunday(d, p) {
32150   return pad(utcSunday.count(utcYear(d), d), p, 2);
32151 }
32152
32153 function formatUTCWeekdayNumber(d) {
32154   return d.getUTCDay();
32155 }
32156
32157 function formatUTCWeekNumberMonday(d, p) {
32158   return pad(utcMonday.count(utcYear(d), d), p, 2);
32159 }
32160
32161 function formatUTCYear(d, p) {
32162   return pad(d.getUTCFullYear() % 100, p, 2);
32163 }
32164
32165 function formatUTCFullYear(d, p) {
32166   return pad(d.getUTCFullYear() % 10000, p, 4);
32167 }
32168
32169 function formatUTCZone() {
32170   return "+0000";
32171 }
32172
32173 function formatLiteralPercent() {
32174   return "%";
32175 }
32176
32177 var locale$2;
32178 var timeFormat;
32179 var timeParse;
32180 var utcFormat;
32181 var utcParse;
32182
32183 defaultLocale$1({
32184   dateTime: "%x, %X",
32185   date: "%-m/%-d/%Y",
32186   time: "%-I:%M:%S %p",
32187   periods: ["AM", "PM"],
32188   days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
32189   shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
32190   months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
32191   shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
32192 });
32193
32194 function defaultLocale$1(definition) {
32195   locale$2 = formatLocale$1(definition);
32196   timeFormat = locale$2.format;
32197   timeParse = locale$2.parse;
32198   utcFormat = locale$2.utcFormat;
32199   utcParse = locale$2.utcParse;
32200   return locale$2;
32201 }
32202
32203 var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ";
32204
32205 function formatIsoNative(date) {
32206   return date.toISOString();
32207 }
32208
32209 var formatIso = Date.prototype.toISOString
32210     ? formatIsoNative
32211     : utcFormat(isoSpecifier);
32212
32213 function parseIsoNative(string) {
32214   var date = new Date(string);
32215   return isNaN(date) ? null : date;
32216 }
32217
32218 var parseIso = +new Date("2000-01-01T00:00:00.000Z")
32219     ? parseIsoNative
32220     : utcParse(isoSpecifier);
32221
32222 var durationSecond = 1000;
32223 var durationMinute = durationSecond * 60;
32224 var durationHour = durationMinute * 60;
32225 var durationDay = durationHour * 24;
32226 var durationWeek = durationDay * 7;
32227 var durationMonth = durationDay * 30;
32228 var durationYear = durationDay * 365;
32229
32230 function date$1(t) {
32231   return new Date(t);
32232 }
32233
32234 function number$2(t) {
32235   return t instanceof Date ? +t : +new Date(+t);
32236 }
32237
32238 function calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format) {
32239   var scale = continuous(deinterpolateLinear, reinterpolate),
32240       invert = scale.invert,
32241       domain = scale.domain;
32242
32243   var formatMillisecond = format(".%L"),
32244       formatSecond = format(":%S"),
32245       formatMinute = format("%I:%M"),
32246       formatHour = format("%I %p"),
32247       formatDay = format("%a %d"),
32248       formatWeek = format("%b %d"),
32249       formatMonth = format("%B"),
32250       formatYear = format("%Y");
32251
32252   var tickIntervals = [
32253     [second$$1,  1,      durationSecond],
32254     [second$$1,  5,  5 * durationSecond],
32255     [second$$1, 15, 15 * durationSecond],
32256     [second$$1, 30, 30 * durationSecond],
32257     [minute$$1,  1,      durationMinute],
32258     [minute$$1,  5,  5 * durationMinute],
32259     [minute$$1, 15, 15 * durationMinute],
32260     [minute$$1, 30, 30 * durationMinute],
32261     [  hour$$1,  1,      durationHour  ],
32262     [  hour$$1,  3,  3 * durationHour  ],
32263     [  hour$$1,  6,  6 * durationHour  ],
32264     [  hour$$1, 12, 12 * durationHour  ],
32265     [   day$$1,  1,      durationDay   ],
32266     [   day$$1,  2,  2 * durationDay   ],
32267     [  week,  1,      durationWeek  ],
32268     [ month$$1,  1,      durationMonth ],
32269     [ month$$1,  3,  3 * durationMonth ],
32270     [  year$$1,  1,      durationYear  ]
32271   ];
32272
32273   function tickFormat(date$$1) {
32274     return (second$$1(date$$1) < date$$1 ? formatMillisecond
32275         : minute$$1(date$$1) < date$$1 ? formatSecond
32276         : hour$$1(date$$1) < date$$1 ? formatMinute
32277         : day$$1(date$$1) < date$$1 ? formatHour
32278         : month$$1(date$$1) < date$$1 ? (week(date$$1) < date$$1 ? formatDay : formatWeek)
32279         : year$$1(date$$1) < date$$1 ? formatMonth
32280         : formatYear)(date$$1);
32281   }
32282
32283   function tickInterval(interval$$1, start, stop, step) {
32284     if (interval$$1 == null) interval$$1 = 10;
32285
32286     // If a desired tick count is specified, pick a reasonable tick interval
32287     // based on the extent of the domain and a rough estimate of tick size.
32288     // Otherwise, assume interval is already a time interval and use it.
32289     if (typeof interval$$1 === "number") {
32290       var target = Math.abs(stop - start) / interval$$1,
32291           i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
32292       if (i === tickIntervals.length) {
32293         step = tickStep(start / durationYear, stop / durationYear, interval$$1);
32294         interval$$1 = year$$1;
32295       } else if (i) {
32296         i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
32297         step = i[1];
32298         interval$$1 = i[0];
32299       } else {
32300         step = tickStep(start, stop, interval$$1);
32301         interval$$1 = millisecond$$1;
32302       }
32303     }
32304
32305     return step == null ? interval$$1 : interval$$1.every(step);
32306   }
32307
32308   scale.invert = function(y) {
32309     return new Date(invert(y));
32310   };
32311
32312   scale.domain = function(_) {
32313     return arguments.length ? domain(map$3.call(_, number$2)) : domain().map(date$1);
32314   };
32315
32316   scale.ticks = function(interval$$1, step) {
32317     var d = domain(),
32318         t0 = d[0],
32319         t1 = d[d.length - 1],
32320         r = t1 < t0,
32321         t;
32322     if (r) t = t0, t0 = t1, t1 = t;
32323     t = tickInterval(interval$$1, t0, t1, step);
32324     t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
32325     return r ? t.reverse() : t;
32326   };
32327
32328   scale.tickFormat = function(count, specifier) {
32329     return specifier == null ? tickFormat : format(specifier);
32330   };
32331
32332   scale.nice = function(interval$$1, step) {
32333     var d = domain();
32334     return (interval$$1 = tickInterval(interval$$1, d[0], d[d.length - 1], step))
32335         ? domain(nice(d, interval$$1))
32336         : scale;
32337   };
32338
32339   scale.copy = function() {
32340     return copy(scale, calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format));
32341   };
32342
32343   return scale;
32344 }
32345
32346 var time = function() {
32347   return calendar(year, month, sunday, day, hour, minute, second, millisecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);
32348 };
32349
32350 var utcTime = function() {
32351   return calendar(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, millisecond, utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]);
32352 };
32353
32354 var colors = function(s) {
32355   return s.match(/.{6}/g).map(function(x) {
32356     return "#" + x;
32357   });
32358 };
32359
32360 var category10 = colors("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf");
32361
32362 var category20b = colors("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6");
32363
32364 var category20c = colors("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9");
32365
32366 var category20 = colors("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5");
32367
32368 var cubehelix$3 = cubehelixLong(cubehelix(300, 0.5, 0.0), cubehelix(-240, 0.5, 1.0));
32369
32370 var warm = cubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
32371
32372 var cool = cubehelixLong(cubehelix(260, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
32373
32374 var rainbow = cubehelix();
32375
32376 var rainbow$1 = function(t) {
32377   if (t < 0 || t > 1) t -= Math.floor(t);
32378   var ts = Math.abs(t - 0.5);
32379   rainbow.h = 360 * t - 100;
32380   rainbow.s = 1.5 - 1.5 * ts;
32381   rainbow.l = 0.8 - 0.9 * ts;
32382   return rainbow + "";
32383 };
32384
32385 function ramp(range) {
32386   var n = range.length;
32387   return function(t) {
32388     return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
32389   };
32390 }
32391
32392 var viridis = ramp(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
32393
32394 var magma = ramp(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
32395
32396 var inferno = ramp(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
32397
32398 var plasma = ramp(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));
32399
32400 function sequential(interpolator) {
32401   var x0 = 0,
32402       x1 = 1,
32403       clamp = false;
32404
32405   function scale(x) {
32406     var t = (x - x0) / (x1 - x0);
32407     return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);
32408   }
32409
32410   scale.domain = function(_) {
32411     return arguments.length ? (x0 = +_[0], x1 = +_[1], scale) : [x0, x1];
32412   };
32413
32414   scale.clamp = function(_) {
32415     return arguments.length ? (clamp = !!_, scale) : clamp;
32416   };
32417
32418   scale.interpolator = function(_) {
32419     return arguments.length ? (interpolator = _, scale) : interpolator;
32420   };
32421
32422   scale.copy = function() {
32423     return sequential(interpolator).domain([x0, x1]).clamp(clamp);
32424   };
32425
32426   return linearish(scale);
32427 }
32428
32429 var constant$10 = function(x) {
32430   return function constant() {
32431     return x;
32432   };
32433 };
32434
32435 var abs$1 = Math.abs;
32436 var atan2$1 = Math.atan2;
32437 var cos$2 = Math.cos;
32438 var max$2 = Math.max;
32439 var min$1 = Math.min;
32440 var sin$2 = Math.sin;
32441 var sqrt$2 = Math.sqrt;
32442
32443 var epsilon$3 = 1e-12;
32444 var pi$4 = Math.PI;
32445 var halfPi$3 = pi$4 / 2;
32446 var tau$4 = 2 * pi$4;
32447
32448 function acos$1(x) {
32449   return x > 1 ? 0 : x < -1 ? pi$4 : Math.acos(x);
32450 }
32451
32452 function asin$1(x) {
32453   return x >= 1 ? halfPi$3 : x <= -1 ? -halfPi$3 : Math.asin(x);
32454 }
32455
32456 function arcInnerRadius(d) {
32457   return d.innerRadius;
32458 }
32459
32460 function arcOuterRadius(d) {
32461   return d.outerRadius;
32462 }
32463
32464 function arcStartAngle(d) {
32465   return d.startAngle;
32466 }
32467
32468 function arcEndAngle(d) {
32469   return d.endAngle;
32470 }
32471
32472 function arcPadAngle(d) {
32473   return d && d.padAngle; // Note: optional!
32474 }
32475
32476 function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
32477   var x10 = x1 - x0, y10 = y1 - y0,
32478       x32 = x3 - x2, y32 = y3 - y2,
32479       t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / (y32 * x10 - x32 * y10);
32480   return [x0 + t * x10, y0 + t * y10];
32481 }
32482
32483 // Compute perpendicular offset line of length rc.
32484 // http://mathworld.wolfram.com/Circle-LineIntersection.html
32485 function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
32486   var x01 = x0 - x1,
32487       y01 = y0 - y1,
32488       lo = (cw ? rc : -rc) / sqrt$2(x01 * x01 + y01 * y01),
32489       ox = lo * y01,
32490       oy = -lo * x01,
32491       x11 = x0 + ox,
32492       y11 = y0 + oy,
32493       x10 = x1 + ox,
32494       y10 = y1 + oy,
32495       x00 = (x11 + x10) / 2,
32496       y00 = (y11 + y10) / 2,
32497       dx = x10 - x11,
32498       dy = y10 - y11,
32499       d2 = dx * dx + dy * dy,
32500       r = r1 - rc,
32501       D = x11 * y10 - x10 * y11,
32502       d = (dy < 0 ? -1 : 1) * sqrt$2(max$2(0, r * r * d2 - D * D)),
32503       cx0 = (D * dy - dx * d) / d2,
32504       cy0 = (-D * dx - dy * d) / d2,
32505       cx1 = (D * dy + dx * d) / d2,
32506       cy1 = (-D * dx + dy * d) / d2,
32507       dx0 = cx0 - x00,
32508       dy0 = cy0 - y00,
32509       dx1 = cx1 - x00,
32510       dy1 = cy1 - y00;
32511
32512   // Pick the closer of the two intersection points.
32513   // TODO Is there a faster way to determine which intersection to use?
32514   if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
32515
32516   return {
32517     cx: cx0,
32518     cy: cy0,
32519     x01: -ox,
32520     y01: -oy,
32521     x11: cx0 * (r1 / r - 1),
32522     y11: cy0 * (r1 / r - 1)
32523   };
32524 }
32525
32526 var arc = function() {
32527   var innerRadius = arcInnerRadius,
32528       outerRadius = arcOuterRadius,
32529       cornerRadius = constant$10(0),
32530       padRadius = null,
32531       startAngle = arcStartAngle,
32532       endAngle = arcEndAngle,
32533       padAngle = arcPadAngle,
32534       context = null;
32535
32536   function arc() {
32537     var buffer,
32538         r,
32539         r0 = +innerRadius.apply(this, arguments),
32540         r1 = +outerRadius.apply(this, arguments),
32541         a0 = startAngle.apply(this, arguments) - halfPi$3,
32542         a1 = endAngle.apply(this, arguments) - halfPi$3,
32543         da = abs$1(a1 - a0),
32544         cw = a1 > a0;
32545
32546     if (!context) context = buffer = path();
32547
32548     // Ensure that the outer radius is always larger than the inner radius.
32549     if (r1 < r0) r = r1, r1 = r0, r0 = r;
32550
32551     // Is it a point?
32552     if (!(r1 > epsilon$3)) context.moveTo(0, 0);
32553
32554     // Or is it a circle or annulus?
32555     else if (da > tau$4 - epsilon$3) {
32556       context.moveTo(r1 * cos$2(a0), r1 * sin$2(a0));
32557       context.arc(0, 0, r1, a0, a1, !cw);
32558       if (r0 > epsilon$3) {
32559         context.moveTo(r0 * cos$2(a1), r0 * sin$2(a1));
32560         context.arc(0, 0, r0, a1, a0, cw);
32561       }
32562     }
32563
32564     // Or is it a circular or annular sector?
32565     else {
32566       var a01 = a0,
32567           a11 = a1,
32568           a00 = a0,
32569           a10 = a1,
32570           da0 = da,
32571           da1 = da,
32572           ap = padAngle.apply(this, arguments) / 2,
32573           rp = (ap > epsilon$3) && (padRadius ? +padRadius.apply(this, arguments) : sqrt$2(r0 * r0 + r1 * r1)),
32574           rc = min$1(abs$1(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
32575           rc0 = rc,
32576           rc1 = rc,
32577           t0,
32578           t1;
32579
32580       // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
32581       if (rp > epsilon$3) {
32582         var p0 = asin$1(rp / r0 * sin$2(ap)),
32583             p1 = asin$1(rp / r1 * sin$2(ap));
32584         if ((da0 -= p0 * 2) > epsilon$3) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
32585         else da0 = 0, a00 = a10 = (a0 + a1) / 2;
32586         if ((da1 -= p1 * 2) > epsilon$3) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
32587         else da1 = 0, a01 = a11 = (a0 + a1) / 2;
32588       }
32589
32590       var x01 = r1 * cos$2(a01),
32591           y01 = r1 * sin$2(a01),
32592           x10 = r0 * cos$2(a10),
32593           y10 = r0 * sin$2(a10);
32594
32595       // Apply rounded corners?
32596       if (rc > epsilon$3) {
32597         var x11 = r1 * cos$2(a11),
32598             y11 = r1 * sin$2(a11),
32599             x00 = r0 * cos$2(a00),
32600             y00 = r0 * sin$2(a00);
32601
32602         // Restrict the corner radius according to the sector angle.
32603         if (da < pi$4) {
32604           var oc = da0 > epsilon$3 ? intersect(x01, y01, x00, y00, x11, y11, x10, y10) : [x10, y10],
32605               ax = x01 - oc[0],
32606               ay = y01 - oc[1],
32607               bx = x11 - oc[0],
32608               by = y11 - oc[1],
32609               kc = 1 / sin$2(acos$1((ax * bx + ay * by) / (sqrt$2(ax * ax + ay * ay) * sqrt$2(bx * bx + by * by))) / 2),
32610               lc = sqrt$2(oc[0] * oc[0] + oc[1] * oc[1]);
32611           rc0 = min$1(rc, (r0 - lc) / (kc - 1));
32612           rc1 = min$1(rc, (r1 - lc) / (kc + 1));
32613         }
32614       }
32615
32616       // Is the sector collapsed to a line?
32617       if (!(da1 > epsilon$3)) context.moveTo(x01, y01);
32618
32619       // Does the sector’s outer ring have rounded corners?
32620       else if (rc1 > epsilon$3) {
32621         t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
32622         t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
32623
32624         context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
32625
32626         // Have the corners merged?
32627         if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
32628
32629         // Otherwise, draw the two corners and the ring.
32630         else {
32631           context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
32632           context.arc(0, 0, r1, atan2$1(t0.cy + t0.y11, t0.cx + t0.x11), atan2$1(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
32633           context.arc(t1.cx, t1.cy, rc1, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
32634         }
32635       }
32636
32637       // Or is the outer ring just a circular arc?
32638       else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
32639
32640       // Is there no inner ring, and it’s a circular sector?
32641       // Or perhaps it’s an annular sector collapsed due to padding?
32642       if (!(r0 > epsilon$3) || !(da0 > epsilon$3)) context.lineTo(x10, y10);
32643
32644       // Does the sector’s inner ring (or point) have rounded corners?
32645       else if (rc0 > epsilon$3) {
32646         t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
32647         t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
32648
32649         context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
32650
32651         // Have the corners merged?
32652         if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
32653
32654         // Otherwise, draw the two corners and the ring.
32655         else {
32656           context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
32657           context.arc(0, 0, r0, atan2$1(t0.cy + t0.y11, t0.cx + t0.x11), atan2$1(t1.cy + t1.y11, t1.cx + t1.x11), cw);
32658           context.arc(t1.cx, t1.cy, rc0, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
32659         }
32660       }
32661
32662       // Or is the inner ring just a circular arc?
32663       else context.arc(0, 0, r0, a10, a00, cw);
32664     }
32665
32666     context.closePath();
32667
32668     if (buffer) return context = null, buffer + "" || null;
32669   }
32670
32671   arc.centroid = function() {
32672     var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
32673         a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi$4 / 2;
32674     return [cos$2(a) * r, sin$2(a) * r];
32675   };
32676
32677   arc.innerRadius = function(_) {
32678     return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : innerRadius;
32679   };
32680
32681   arc.outerRadius = function(_) {
32682     return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : outerRadius;
32683   };
32684
32685   arc.cornerRadius = function(_) {
32686     return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : cornerRadius;
32687   };
32688
32689   arc.padRadius = function(_) {
32690     return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), arc) : padRadius;
32691   };
32692
32693   arc.startAngle = function(_) {
32694     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : startAngle;
32695   };
32696
32697   arc.endAngle = function(_) {
32698     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : endAngle;
32699   };
32700
32701   arc.padAngle = function(_) {
32702     return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : padAngle;
32703   };
32704
32705   arc.context = function(_) {
32706     return arguments.length ? ((context = _ == null ? null : _), arc) : context;
32707   };
32708
32709   return arc;
32710 };
32711
32712 function Linear(context) {
32713   this._context = context;
32714 }
32715
32716 Linear.prototype = {
32717   areaStart: function() {
32718     this._line = 0;
32719   },
32720   areaEnd: function() {
32721     this._line = NaN;
32722   },
32723   lineStart: function() {
32724     this._point = 0;
32725   },
32726   lineEnd: function() {
32727     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
32728     this._line = 1 - this._line;
32729   },
32730   point: function(x, y) {
32731     x = +x, y = +y;
32732     switch (this._point) {
32733       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
32734       case 1: this._point = 2; // proceed
32735       default: this._context.lineTo(x, y); break;
32736     }
32737   }
32738 };
32739
32740 var curveLinear = function(context) {
32741   return new Linear(context);
32742 };
32743
32744 function x$3(p) {
32745   return p[0];
32746 }
32747
32748 function y$3(p) {
32749   return p[1];
32750 }
32751
32752 var line = function() {
32753   var x = x$3,
32754       y = y$3,
32755       defined = constant$10(true),
32756       context = null,
32757       curve = curveLinear,
32758       output = null;
32759
32760   function line(data) {
32761     var i,
32762         n = data.length,
32763         d,
32764         defined0 = false,
32765         buffer;
32766
32767     if (context == null) output = curve(buffer = path());
32768
32769     for (i = 0; i <= n; ++i) {
32770       if (!(i < n && defined(d = data[i], i, data)) === defined0) {
32771         if (defined0 = !defined0) output.lineStart();
32772         else output.lineEnd();
32773       }
32774       if (defined0) output.point(+x(d, i, data), +y(d, i, data));
32775     }
32776
32777     if (buffer) return output = null, buffer + "" || null;
32778   }
32779
32780   line.x = function(_) {
32781     return arguments.length ? (x = typeof _ === "function" ? _ : constant$10(+_), line) : x;
32782   };
32783
32784   line.y = function(_) {
32785     return arguments.length ? (y = typeof _ === "function" ? _ : constant$10(+_), line) : y;
32786   };
32787
32788   line.defined = function(_) {
32789     return arguments.length ? (defined = typeof _ === "function" ? _ : constant$10(!!_), line) : defined;
32790   };
32791
32792   line.curve = function(_) {
32793     return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
32794   };
32795
32796   line.context = function(_) {
32797     return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
32798   };
32799
32800   return line;
32801 };
32802
32803 var area$1 = function() {
32804   var x0 = x$3,
32805       x1 = null,
32806       y0 = constant$10(0),
32807       y1 = y$3,
32808       defined = constant$10(true),
32809       context = null,
32810       curve = curveLinear,
32811       output = null;
32812
32813   function area(data) {
32814     var i,
32815         j,
32816         k,
32817         n = data.length,
32818         d,
32819         defined0 = false,
32820         buffer,
32821         x0z = new Array(n),
32822         y0z = new Array(n);
32823
32824     if (context == null) output = curve(buffer = path());
32825
32826     for (i = 0; i <= n; ++i) {
32827       if (!(i < n && defined(d = data[i], i, data)) === defined0) {
32828         if (defined0 = !defined0) {
32829           j = i;
32830           output.areaStart();
32831           output.lineStart();
32832         } else {
32833           output.lineEnd();
32834           output.lineStart();
32835           for (k = i - 1; k >= j; --k) {
32836             output.point(x0z[k], y0z[k]);
32837           }
32838           output.lineEnd();
32839           output.areaEnd();
32840         }
32841       }
32842       if (defined0) {
32843         x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
32844         output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
32845       }
32846     }
32847
32848     if (buffer) return output = null, buffer + "" || null;
32849   }
32850
32851   function arealine() {
32852     return line().defined(defined).curve(curve).context(context);
32853   }
32854
32855   area.x = function(_) {
32856     return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$10(+_), x1 = null, area) : x0;
32857   };
32858
32859   area.x0 = function(_) {
32860     return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$10(+_), area) : x0;
32861   };
32862
32863   area.x1 = function(_) {
32864     return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), area) : x1;
32865   };
32866
32867   area.y = function(_) {
32868     return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$10(+_), y1 = null, area) : y0;
32869   };
32870
32871   area.y0 = function(_) {
32872     return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$10(+_), area) : y0;
32873   };
32874
32875   area.y1 = function(_) {
32876     return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), area) : y1;
32877   };
32878
32879   area.lineX0 =
32880   area.lineY0 = function() {
32881     return arealine().x(x0).y(y0);
32882   };
32883
32884   area.lineY1 = function() {
32885     return arealine().x(x0).y(y1);
32886   };
32887
32888   area.lineX1 = function() {
32889     return arealine().x(x1).y(y0);
32890   };
32891
32892   area.defined = function(_) {
32893     return arguments.length ? (defined = typeof _ === "function" ? _ : constant$10(!!_), area) : defined;
32894   };
32895
32896   area.curve = function(_) {
32897     return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;
32898   };
32899
32900   area.context = function(_) {
32901     return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
32902   };
32903
32904   return area;
32905 };
32906
32907 var descending$1 = function(a, b) {
32908   return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
32909 };
32910
32911 var identity$7 = function(d) {
32912   return d;
32913 };
32914
32915 var pie = function() {
32916   var value = identity$7,
32917       sortValues = descending$1,
32918       sort = null,
32919       startAngle = constant$10(0),
32920       endAngle = constant$10(tau$4),
32921       padAngle = constant$10(0);
32922
32923   function pie(data) {
32924     var i,
32925         n = data.length,
32926         j,
32927         k,
32928         sum = 0,
32929         index = new Array(n),
32930         arcs = new Array(n),
32931         a0 = +startAngle.apply(this, arguments),
32932         da = Math.min(tau$4, Math.max(-tau$4, endAngle.apply(this, arguments) - a0)),
32933         a1,
32934         p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
32935         pa = p * (da < 0 ? -1 : 1),
32936         v;
32937
32938     for (i = 0; i < n; ++i) {
32939       if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
32940         sum += v;
32941       }
32942     }
32943
32944     // Optionally sort the arcs by previously-computed values or by data.
32945     if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
32946     else if (sort != null) index.sort(function(i, j) { return sort(data[i], data[j]); });
32947
32948     // Compute the arcs! They are stored in the original data's order.
32949     for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
32950       j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
32951         data: data[j],
32952         index: i,
32953         value: v,
32954         startAngle: a0,
32955         endAngle: a1,
32956         padAngle: p
32957       };
32958     }
32959
32960     return arcs;
32961   }
32962
32963   pie.value = function(_) {
32964     return arguments.length ? (value = typeof _ === "function" ? _ : constant$10(+_), pie) : value;
32965   };
32966
32967   pie.sortValues = function(_) {
32968     return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
32969   };
32970
32971   pie.sort = function(_) {
32972     return arguments.length ? (sort = _, sortValues = null, pie) : sort;
32973   };
32974
32975   pie.startAngle = function(_) {
32976     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : startAngle;
32977   };
32978
32979   pie.endAngle = function(_) {
32980     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : endAngle;
32981   };
32982
32983   pie.padAngle = function(_) {
32984     return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : padAngle;
32985   };
32986
32987   return pie;
32988 };
32989
32990 var curveRadialLinear = curveRadial(curveLinear);
32991
32992 function Radial(curve) {
32993   this._curve = curve;
32994 }
32995
32996 Radial.prototype = {
32997   areaStart: function() {
32998     this._curve.areaStart();
32999   },
33000   areaEnd: function() {
33001     this._curve.areaEnd();
33002   },
33003   lineStart: function() {
33004     this._curve.lineStart();
33005   },
33006   lineEnd: function() {
33007     this._curve.lineEnd();
33008   },
33009   point: function(a, r) {
33010     this._curve.point(r * Math.sin(a), r * -Math.cos(a));
33011   }
33012 };
33013
33014 function curveRadial(curve) {
33015
33016   function radial(context) {
33017     return new Radial(curve(context));
33018   }
33019
33020   radial._curve = curve;
33021
33022   return radial;
33023 }
33024
33025 function radialLine(l) {
33026   var c = l.curve;
33027
33028   l.angle = l.x, delete l.x;
33029   l.radius = l.y, delete l.y;
33030
33031   l.curve = function(_) {
33032     return arguments.length ? c(curveRadial(_)) : c()._curve;
33033   };
33034
33035   return l;
33036 }
33037
33038 var radialLine$1 = function() {
33039   return radialLine(line().curve(curveRadialLinear));
33040 };
33041
33042 var radialArea = function() {
33043   var a = area$1().curve(curveRadialLinear),
33044       c = a.curve,
33045       x0 = a.lineX0,
33046       x1 = a.lineX1,
33047       y0 = a.lineY0,
33048       y1 = a.lineY1;
33049
33050   a.angle = a.x, delete a.x;
33051   a.startAngle = a.x0, delete a.x0;
33052   a.endAngle = a.x1, delete a.x1;
33053   a.radius = a.y, delete a.y;
33054   a.innerRadius = a.y0, delete a.y0;
33055   a.outerRadius = a.y1, delete a.y1;
33056   a.lineStartAngle = function() { return radialLine(x0()); }, delete a.lineX0;
33057   a.lineEndAngle = function() { return radialLine(x1()); }, delete a.lineX1;
33058   a.lineInnerRadius = function() { return radialLine(y0()); }, delete a.lineY0;
33059   a.lineOuterRadius = function() { return radialLine(y1()); }, delete a.lineY1;
33060
33061   a.curve = function(_) {
33062     return arguments.length ? c(curveRadial(_)) : c()._curve;
33063   };
33064
33065   return a;
33066 };
33067
33068 var slice$5 = Array.prototype.slice;
33069
33070 var radialPoint = function(x, y) {
33071   return [(y = +y) * Math.cos(x -= Math.PI / 2), y * Math.sin(x)];
33072 };
33073
33074 function linkSource(d) {
33075   return d.source;
33076 }
33077
33078 function linkTarget(d) {
33079   return d.target;
33080 }
33081
33082 function link$2(curve) {
33083   var source = linkSource,
33084       target = linkTarget,
33085       x = x$3,
33086       y = y$3,
33087       context = null;
33088
33089   function link() {
33090     var buffer, argv = slice$5.call(arguments), s = source.apply(this, argv), t = target.apply(this, argv);
33091     if (!context) context = buffer = path();
33092     curve(context, +x.apply(this, (argv[0] = s, argv)), +y.apply(this, argv), +x.apply(this, (argv[0] = t, argv)), +y.apply(this, argv));
33093     if (buffer) return context = null, buffer + "" || null;
33094   }
33095
33096   link.source = function(_) {
33097     return arguments.length ? (source = _, link) : source;
33098   };
33099
33100   link.target = function(_) {
33101     return arguments.length ? (target = _, link) : target;
33102   };
33103
33104   link.x = function(_) {
33105     return arguments.length ? (x = typeof _ === "function" ? _ : constant$10(+_), link) : x;
33106   };
33107
33108   link.y = function(_) {
33109     return arguments.length ? (y = typeof _ === "function" ? _ : constant$10(+_), link) : y;
33110   };
33111
33112   link.context = function(_) {
33113     return arguments.length ? ((context = _ == null ? null : _), link) : context;
33114   };
33115
33116   return link;
33117 }
33118
33119 function curveHorizontal(context, x0, y0, x1, y1) {
33120   context.moveTo(x0, y0);
33121   context.bezierCurveTo(x0 = (x0 + x1) / 2, y0, x0, y1, x1, y1);
33122 }
33123
33124 function curveVertical(context, x0, y0, x1, y1) {
33125   context.moveTo(x0, y0);
33126   context.bezierCurveTo(x0, y0 = (y0 + y1) / 2, x1, y0, x1, y1);
33127 }
33128
33129 function curveRadial$1(context, x0, y0, x1, y1) {
33130   var p0 = radialPoint(x0, y0),
33131       p1 = radialPoint(x0, y0 = (y0 + y1) / 2),
33132       p2 = radialPoint(x1, y0),
33133       p3 = radialPoint(x1, y1);
33134   context.moveTo(p0[0], p0[1]);
33135   context.bezierCurveTo(p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);
33136 }
33137
33138 function linkHorizontal() {
33139   return link$2(curveHorizontal);
33140 }
33141
33142 function linkVertical() {
33143   return link$2(curveVertical);
33144 }
33145
33146 function linkRadial() {
33147   var l = link$2(curveRadial$1);
33148   l.angle = l.x, delete l.x;
33149   l.radius = l.y, delete l.y;
33150   return l;
33151 }
33152
33153 var circle$2 = {
33154   draw: function(context, size) {
33155     var r = Math.sqrt(size / pi$4);
33156     context.moveTo(r, 0);
33157     context.arc(0, 0, r, 0, tau$4);
33158   }
33159 };
33160
33161 var cross$2 = {
33162   draw: function(context, size) {
33163     var r = Math.sqrt(size / 5) / 2;
33164     context.moveTo(-3 * r, -r);
33165     context.lineTo(-r, -r);
33166     context.lineTo(-r, -3 * r);
33167     context.lineTo(r, -3 * r);
33168     context.lineTo(r, -r);
33169     context.lineTo(3 * r, -r);
33170     context.lineTo(3 * r, r);
33171     context.lineTo(r, r);
33172     context.lineTo(r, 3 * r);
33173     context.lineTo(-r, 3 * r);
33174     context.lineTo(-r, r);
33175     context.lineTo(-3 * r, r);
33176     context.closePath();
33177   }
33178 };
33179
33180 var tan30 = Math.sqrt(1 / 3);
33181 var tan30_2 = tan30 * 2;
33182
33183 var diamond = {
33184   draw: function(context, size) {
33185     var y = Math.sqrt(size / tan30_2),
33186         x = y * tan30;
33187     context.moveTo(0, -y);
33188     context.lineTo(x, 0);
33189     context.lineTo(0, y);
33190     context.lineTo(-x, 0);
33191     context.closePath();
33192   }
33193 };
33194
33195 var ka = 0.89081309152928522810;
33196 var kr = Math.sin(pi$4 / 10) / Math.sin(7 * pi$4 / 10);
33197 var kx = Math.sin(tau$4 / 10) * kr;
33198 var ky = -Math.cos(tau$4 / 10) * kr;
33199
33200 var star = {
33201   draw: function(context, size) {
33202     var r = Math.sqrt(size * ka),
33203         x = kx * r,
33204         y = ky * r;
33205     context.moveTo(0, -r);
33206     context.lineTo(x, y);
33207     for (var i = 1; i < 5; ++i) {
33208       var a = tau$4 * i / 5,
33209           c = Math.cos(a),
33210           s = Math.sin(a);
33211       context.lineTo(s * r, -c * r);
33212       context.lineTo(c * x - s * y, s * x + c * y);
33213     }
33214     context.closePath();
33215   }
33216 };
33217
33218 var square = {
33219   draw: function(context, size) {
33220     var w = Math.sqrt(size),
33221         x = -w / 2;
33222     context.rect(x, x, w, w);
33223   }
33224 };
33225
33226 var sqrt3 = Math.sqrt(3);
33227
33228 var triangle = {
33229   draw: function(context, size) {
33230     var y = -Math.sqrt(size / (sqrt3 * 3));
33231     context.moveTo(0, y * 2);
33232     context.lineTo(-sqrt3 * y, -y);
33233     context.lineTo(sqrt3 * y, -y);
33234     context.closePath();
33235   }
33236 };
33237
33238 var c = -0.5;
33239 var s = Math.sqrt(3) / 2;
33240 var k = 1 / Math.sqrt(12);
33241 var a = (k / 2 + 1) * 3;
33242
33243 var wye = {
33244   draw: function(context, size) {
33245     var r = Math.sqrt(size / a),
33246         x0 = r / 2,
33247         y0 = r * k,
33248         x1 = x0,
33249         y1 = r * k + r,
33250         x2 = -x1,
33251         y2 = y1;
33252     context.moveTo(x0, y0);
33253     context.lineTo(x1, y1);
33254     context.lineTo(x2, y2);
33255     context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
33256     context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
33257     context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
33258     context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
33259     context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
33260     context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
33261     context.closePath();
33262   }
33263 };
33264
33265 var symbols = [
33266   circle$2,
33267   cross$2,
33268   diamond,
33269   square,
33270   star,
33271   triangle,
33272   wye
33273 ];
33274
33275 var symbol = function() {
33276   var type = constant$10(circle$2),
33277       size = constant$10(64),
33278       context = null;
33279
33280   function symbol() {
33281     var buffer;
33282     if (!context) context = buffer = path();
33283     type.apply(this, arguments).draw(context, +size.apply(this, arguments));
33284     if (buffer) return context = null, buffer + "" || null;
33285   }
33286
33287   symbol.type = function(_) {
33288     return arguments.length ? (type = typeof _ === "function" ? _ : constant$10(_), symbol) : type;
33289   };
33290
33291   symbol.size = function(_) {
33292     return arguments.length ? (size = typeof _ === "function" ? _ : constant$10(+_), symbol) : size;
33293   };
33294
33295   symbol.context = function(_) {
33296     return arguments.length ? (context = _ == null ? null : _, symbol) : context;
33297   };
33298
33299   return symbol;
33300 };
33301
33302 var noop$2 = function() {};
33303
33304 function point$2(that, x, y) {
33305   that._context.bezierCurveTo(
33306     (2 * that._x0 + that._x1) / 3,
33307     (2 * that._y0 + that._y1) / 3,
33308     (that._x0 + 2 * that._x1) / 3,
33309     (that._y0 + 2 * that._y1) / 3,
33310     (that._x0 + 4 * that._x1 + x) / 6,
33311     (that._y0 + 4 * that._y1 + y) / 6
33312   );
33313 }
33314
33315 function Basis(context) {
33316   this._context = context;
33317 }
33318
33319 Basis.prototype = {
33320   areaStart: function() {
33321     this._line = 0;
33322   },
33323   areaEnd: function() {
33324     this._line = NaN;
33325   },
33326   lineStart: function() {
33327     this._x0 = this._x1 =
33328     this._y0 = this._y1 = NaN;
33329     this._point = 0;
33330   },
33331   lineEnd: function() {
33332     switch (this._point) {
33333       case 3: point$2(this, this._x1, this._y1); // proceed
33334       case 2: this._context.lineTo(this._x1, this._y1); break;
33335     }
33336     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33337     this._line = 1 - this._line;
33338   },
33339   point: function(x, y) {
33340     x = +x, y = +y;
33341     switch (this._point) {
33342       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33343       case 1: this._point = 2; break;
33344       case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed
33345       default: point$2(this, x, y); break;
33346     }
33347     this._x0 = this._x1, this._x1 = x;
33348     this._y0 = this._y1, this._y1 = y;
33349   }
33350 };
33351
33352 var basis$2 = function(context) {
33353   return new Basis(context);
33354 };
33355
33356 function BasisClosed(context) {
33357   this._context = context;
33358 }
33359
33360 BasisClosed.prototype = {
33361   areaStart: noop$2,
33362   areaEnd: noop$2,
33363   lineStart: function() {
33364     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
33365     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
33366     this._point = 0;
33367   },
33368   lineEnd: function() {
33369     switch (this._point) {
33370       case 1: {
33371         this._context.moveTo(this._x2, this._y2);
33372         this._context.closePath();
33373         break;
33374       }
33375       case 2: {
33376         this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);
33377         this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);
33378         this._context.closePath();
33379         break;
33380       }
33381       case 3: {
33382         this.point(this._x2, this._y2);
33383         this.point(this._x3, this._y3);
33384         this.point(this._x4, this._y4);
33385         break;
33386       }
33387     }
33388   },
33389   point: function(x, y) {
33390     x = +x, y = +y;
33391     switch (this._point) {
33392       case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
33393       case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
33394       case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;
33395       default: point$2(this, x, y); break;
33396     }
33397     this._x0 = this._x1, this._x1 = x;
33398     this._y0 = this._y1, this._y1 = y;
33399   }
33400 };
33401
33402 var basisClosed$1 = function(context) {
33403   return new BasisClosed(context);
33404 };
33405
33406 function BasisOpen(context) {
33407   this._context = context;
33408 }
33409
33410 BasisOpen.prototype = {
33411   areaStart: function() {
33412     this._line = 0;
33413   },
33414   areaEnd: function() {
33415     this._line = NaN;
33416   },
33417   lineStart: function() {
33418     this._x0 = this._x1 =
33419     this._y0 = this._y1 = NaN;
33420     this._point = 0;
33421   },
33422   lineEnd: function() {
33423     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33424     this._line = 1 - this._line;
33425   },
33426   point: function(x, y) {
33427     x = +x, y = +y;
33428     switch (this._point) {
33429       case 0: this._point = 1; break;
33430       case 1: this._point = 2; break;
33431       case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;
33432       case 3: this._point = 4; // proceed
33433       default: point$2(this, x, y); break;
33434     }
33435     this._x0 = this._x1, this._x1 = x;
33436     this._y0 = this._y1, this._y1 = y;
33437   }
33438 };
33439
33440 var basisOpen = function(context) {
33441   return new BasisOpen(context);
33442 };
33443
33444 function Bundle(context, beta) {
33445   this._basis = new Basis(context);
33446   this._beta = beta;
33447 }
33448
33449 Bundle.prototype = {
33450   lineStart: function() {
33451     this._x = [];
33452     this._y = [];
33453     this._basis.lineStart();
33454   },
33455   lineEnd: function() {
33456     var x = this._x,
33457         y = this._y,
33458         j = x.length - 1;
33459
33460     if (j > 0) {
33461       var x0 = x[0],
33462           y0 = y[0],
33463           dx = x[j] - x0,
33464           dy = y[j] - y0,
33465           i = -1,
33466           t;
33467
33468       while (++i <= j) {
33469         t = i / j;
33470         this._basis.point(
33471           this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
33472           this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
33473         );
33474       }
33475     }
33476
33477     this._x = this._y = null;
33478     this._basis.lineEnd();
33479   },
33480   point: function(x, y) {
33481     this._x.push(+x);
33482     this._y.push(+y);
33483   }
33484 };
33485
33486 var bundle = ((function custom(beta) {
33487
33488   function bundle(context) {
33489     return beta === 1 ? new Basis(context) : new Bundle(context, beta);
33490   }
33491
33492   bundle.beta = function(beta) {
33493     return custom(+beta);
33494   };
33495
33496   return bundle;
33497 }))(0.85);
33498
33499 function point$3(that, x, y) {
33500   that._context.bezierCurveTo(
33501     that._x1 + that._k * (that._x2 - that._x0),
33502     that._y1 + that._k * (that._y2 - that._y0),
33503     that._x2 + that._k * (that._x1 - x),
33504     that._y2 + that._k * (that._y1 - y),
33505     that._x2,
33506     that._y2
33507   );
33508 }
33509
33510 function Cardinal(context, tension) {
33511   this._context = context;
33512   this._k = (1 - tension) / 6;
33513 }
33514
33515 Cardinal.prototype = {
33516   areaStart: function() {
33517     this._line = 0;
33518   },
33519   areaEnd: function() {
33520     this._line = NaN;
33521   },
33522   lineStart: function() {
33523     this._x0 = this._x1 = this._x2 =
33524     this._y0 = this._y1 = this._y2 = NaN;
33525     this._point = 0;
33526   },
33527   lineEnd: function() {
33528     switch (this._point) {
33529       case 2: this._context.lineTo(this._x2, this._y2); break;
33530       case 3: point$3(this, this._x1, this._y1); break;
33531     }
33532     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33533     this._line = 1 - this._line;
33534   },
33535   point: function(x, y) {
33536     x = +x, y = +y;
33537     switch (this._point) {
33538       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33539       case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
33540       case 2: this._point = 3; // proceed
33541       default: point$3(this, x, y); break;
33542     }
33543     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33544     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33545   }
33546 };
33547
33548 var cardinal = ((function custom(tension) {
33549
33550   function cardinal(context) {
33551     return new Cardinal(context, tension);
33552   }
33553
33554   cardinal.tension = function(tension) {
33555     return custom(+tension);
33556   };
33557
33558   return cardinal;
33559 }))(0);
33560
33561 function CardinalClosed(context, tension) {
33562   this._context = context;
33563   this._k = (1 - tension) / 6;
33564 }
33565
33566 CardinalClosed.prototype = {
33567   areaStart: noop$2,
33568   areaEnd: noop$2,
33569   lineStart: function() {
33570     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
33571     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
33572     this._point = 0;
33573   },
33574   lineEnd: function() {
33575     switch (this._point) {
33576       case 1: {
33577         this._context.moveTo(this._x3, this._y3);
33578         this._context.closePath();
33579         break;
33580       }
33581       case 2: {
33582         this._context.lineTo(this._x3, this._y3);
33583         this._context.closePath();
33584         break;
33585       }
33586       case 3: {
33587         this.point(this._x3, this._y3);
33588         this.point(this._x4, this._y4);
33589         this.point(this._x5, this._y5);
33590         break;
33591       }
33592     }
33593   },
33594   point: function(x, y) {
33595     x = +x, y = +y;
33596     switch (this._point) {
33597       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
33598       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
33599       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
33600       default: point$3(this, x, y); break;
33601     }
33602     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33603     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33604   }
33605 };
33606
33607 var cardinalClosed = ((function custom(tension) {
33608
33609   function cardinal$$1(context) {
33610     return new CardinalClosed(context, tension);
33611   }
33612
33613   cardinal$$1.tension = function(tension) {
33614     return custom(+tension);
33615   };
33616
33617   return cardinal$$1;
33618 }))(0);
33619
33620 function CardinalOpen(context, tension) {
33621   this._context = context;
33622   this._k = (1 - tension) / 6;
33623 }
33624
33625 CardinalOpen.prototype = {
33626   areaStart: function() {
33627     this._line = 0;
33628   },
33629   areaEnd: function() {
33630     this._line = NaN;
33631   },
33632   lineStart: function() {
33633     this._x0 = this._x1 = this._x2 =
33634     this._y0 = this._y1 = this._y2 = NaN;
33635     this._point = 0;
33636   },
33637   lineEnd: function() {
33638     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33639     this._line = 1 - this._line;
33640   },
33641   point: function(x, y) {
33642     x = +x, y = +y;
33643     switch (this._point) {
33644       case 0: this._point = 1; break;
33645       case 1: this._point = 2; break;
33646       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
33647       case 3: this._point = 4; // proceed
33648       default: point$3(this, x, y); break;
33649     }
33650     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33651     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33652   }
33653 };
33654
33655 var cardinalOpen = ((function custom(tension) {
33656
33657   function cardinal$$1(context) {
33658     return new CardinalOpen(context, tension);
33659   }
33660
33661   cardinal$$1.tension = function(tension) {
33662     return custom(+tension);
33663   };
33664
33665   return cardinal$$1;
33666 }))(0);
33667
33668 function point$4(that, x, y) {
33669   var x1 = that._x1,
33670       y1 = that._y1,
33671       x2 = that._x2,
33672       y2 = that._y2;
33673
33674   if (that._l01_a > epsilon$3) {
33675     var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
33676         n = 3 * that._l01_a * (that._l01_a + that._l12_a);
33677     x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
33678     y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
33679   }
33680
33681   if (that._l23_a > epsilon$3) {
33682     var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
33683         m = 3 * that._l23_a * (that._l23_a + that._l12_a);
33684     x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
33685     y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;
33686   }
33687
33688   that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);
33689 }
33690
33691 function CatmullRom(context, alpha) {
33692   this._context = context;
33693   this._alpha = alpha;
33694 }
33695
33696 CatmullRom.prototype = {
33697   areaStart: function() {
33698     this._line = 0;
33699   },
33700   areaEnd: function() {
33701     this._line = NaN;
33702   },
33703   lineStart: function() {
33704     this._x0 = this._x1 = this._x2 =
33705     this._y0 = this._y1 = this._y2 = NaN;
33706     this._l01_a = this._l12_a = this._l23_a =
33707     this._l01_2a = this._l12_2a = this._l23_2a =
33708     this._point = 0;
33709   },
33710   lineEnd: function() {
33711     switch (this._point) {
33712       case 2: this._context.lineTo(this._x2, this._y2); break;
33713       case 3: this.point(this._x2, this._y2); break;
33714     }
33715     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33716     this._line = 1 - this._line;
33717   },
33718   point: function(x, y) {
33719     x = +x, y = +y;
33720
33721     if (this._point) {
33722       var x23 = this._x2 - x,
33723           y23 = this._y2 - y;
33724       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33725     }
33726
33727     switch (this._point) {
33728       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33729       case 1: this._point = 2; break;
33730       case 2: this._point = 3; // proceed
33731       default: point$4(this, x, y); break;
33732     }
33733
33734     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33735     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33736     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33737     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33738   }
33739 };
33740
33741 var catmullRom = ((function custom(alpha) {
33742
33743   function catmullRom(context) {
33744     return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);
33745   }
33746
33747   catmullRom.alpha = function(alpha) {
33748     return custom(+alpha);
33749   };
33750
33751   return catmullRom;
33752 }))(0.5);
33753
33754 function CatmullRomClosed(context, alpha) {
33755   this._context = context;
33756   this._alpha = alpha;
33757 }
33758
33759 CatmullRomClosed.prototype = {
33760   areaStart: noop$2,
33761   areaEnd: noop$2,
33762   lineStart: function() {
33763     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
33764     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
33765     this._l01_a = this._l12_a = this._l23_a =
33766     this._l01_2a = this._l12_2a = this._l23_2a =
33767     this._point = 0;
33768   },
33769   lineEnd: function() {
33770     switch (this._point) {
33771       case 1: {
33772         this._context.moveTo(this._x3, this._y3);
33773         this._context.closePath();
33774         break;
33775       }
33776       case 2: {
33777         this._context.lineTo(this._x3, this._y3);
33778         this._context.closePath();
33779         break;
33780       }
33781       case 3: {
33782         this.point(this._x3, this._y3);
33783         this.point(this._x4, this._y4);
33784         this.point(this._x5, this._y5);
33785         break;
33786       }
33787     }
33788   },
33789   point: function(x, y) {
33790     x = +x, y = +y;
33791
33792     if (this._point) {
33793       var x23 = this._x2 - x,
33794           y23 = this._y2 - y;
33795       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33796     }
33797
33798     switch (this._point) {
33799       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
33800       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
33801       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
33802       default: point$4(this, x, y); break;
33803     }
33804
33805     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33806     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33807     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33808     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33809   }
33810 };
33811
33812 var catmullRomClosed = ((function custom(alpha) {
33813
33814   function catmullRom$$1(context) {
33815     return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);
33816   }
33817
33818   catmullRom$$1.alpha = function(alpha) {
33819     return custom(+alpha);
33820   };
33821
33822   return catmullRom$$1;
33823 }))(0.5);
33824
33825 function CatmullRomOpen(context, alpha) {
33826   this._context = context;
33827   this._alpha = alpha;
33828 }
33829
33830 CatmullRomOpen.prototype = {
33831   areaStart: function() {
33832     this._line = 0;
33833   },
33834   areaEnd: function() {
33835     this._line = NaN;
33836   },
33837   lineStart: function() {
33838     this._x0 = this._x1 = this._x2 =
33839     this._y0 = this._y1 = this._y2 = NaN;
33840     this._l01_a = this._l12_a = this._l23_a =
33841     this._l01_2a = this._l12_2a = this._l23_2a =
33842     this._point = 0;
33843   },
33844   lineEnd: function() {
33845     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33846     this._line = 1 - this._line;
33847   },
33848   point: function(x, y) {
33849     x = +x, y = +y;
33850
33851     if (this._point) {
33852       var x23 = this._x2 - x,
33853           y23 = this._y2 - y;
33854       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33855     }
33856
33857     switch (this._point) {
33858       case 0: this._point = 1; break;
33859       case 1: this._point = 2; break;
33860       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
33861       case 3: this._point = 4; // proceed
33862       default: point$4(this, x, y); break;
33863     }
33864
33865     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33866     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33867     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33868     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33869   }
33870 };
33871
33872 var catmullRomOpen = ((function custom(alpha) {
33873
33874   function catmullRom$$1(context) {
33875     return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);
33876   }
33877
33878   catmullRom$$1.alpha = function(alpha) {
33879     return custom(+alpha);
33880   };
33881
33882   return catmullRom$$1;
33883 }))(0.5);
33884
33885 function LinearClosed(context) {
33886   this._context = context;
33887 }
33888
33889 LinearClosed.prototype = {
33890   areaStart: noop$2,
33891   areaEnd: noop$2,
33892   lineStart: function() {
33893     this._point = 0;
33894   },
33895   lineEnd: function() {
33896     if (this._point) this._context.closePath();
33897   },
33898   point: function(x, y) {
33899     x = +x, y = +y;
33900     if (this._point) this._context.lineTo(x, y);
33901     else this._point = 1, this._context.moveTo(x, y);
33902   }
33903 };
33904
33905 var linearClosed = function(context) {
33906   return new LinearClosed(context);
33907 };
33908
33909 function sign$1(x) {
33910   return x < 0 ? -1 : 1;
33911 }
33912
33913 // Calculate the slopes of the tangents (Hermite-type interpolation) based on
33914 // the following paper: Steffen, M. 1990. A Simple Method for Monotonic
33915 // Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.
33916 // NOV(II), P. 443, 1990.
33917 function slope3(that, x2, y2) {
33918   var h0 = that._x1 - that._x0,
33919       h1 = x2 - that._x1,
33920       s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),
33921       s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),
33922       p = (s0 * h1 + s1 * h0) / (h0 + h1);
33923   return (sign$1(s0) + sign$1(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
33924 }
33925
33926 // Calculate a one-sided slope.
33927 function slope2(that, t) {
33928   var h = that._x1 - that._x0;
33929   return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
33930 }
33931
33932 // According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
33933 // "you can express cubic Hermite interpolation in terms of cubic Bézier curves
33934 // with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
33935 function point$5(that, t0, t1) {
33936   var x0 = that._x0,
33937       y0 = that._y0,
33938       x1 = that._x1,
33939       y1 = that._y1,
33940       dx = (x1 - x0) / 3;
33941   that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
33942 }
33943
33944 function MonotoneX(context) {
33945   this._context = context;
33946 }
33947
33948 MonotoneX.prototype = {
33949   areaStart: function() {
33950     this._line = 0;
33951   },
33952   areaEnd: function() {
33953     this._line = NaN;
33954   },
33955   lineStart: function() {
33956     this._x0 = this._x1 =
33957     this._y0 = this._y1 =
33958     this._t0 = NaN;
33959     this._point = 0;
33960   },
33961   lineEnd: function() {
33962     switch (this._point) {
33963       case 2: this._context.lineTo(this._x1, this._y1); break;
33964       case 3: point$5(this, this._t0, slope2(this, this._t0)); break;
33965     }
33966     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33967     this._line = 1 - this._line;
33968   },
33969   point: function(x, y) {
33970     var t1 = NaN;
33971
33972     x = +x, y = +y;
33973     if (x === this._x1 && y === this._y1) return; // Ignore coincident points.
33974     switch (this._point) {
33975       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33976       case 1: this._point = 2; break;
33977       case 2: this._point = 3; point$5(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
33978       default: point$5(this, this._t0, t1 = slope3(this, x, y)); break;
33979     }
33980
33981     this._x0 = this._x1, this._x1 = x;
33982     this._y0 = this._y1, this._y1 = y;
33983     this._t0 = t1;
33984   }
33985 };
33986
33987 function MonotoneY(context) {
33988   this._context = new ReflectContext(context);
33989 }
33990
33991 (MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {
33992   MonotoneX.prototype.point.call(this, y, x);
33993 };
33994
33995 function ReflectContext(context) {
33996   this._context = context;
33997 }
33998
33999 ReflectContext.prototype = {
34000   moveTo: function(x, y) { this._context.moveTo(y, x); },
34001   closePath: function() { this._context.closePath(); },
34002   lineTo: function(x, y) { this._context.lineTo(y, x); },
34003   bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }
34004 };
34005
34006 function monotoneX(context) {
34007   return new MonotoneX(context);
34008 }
34009
34010 function monotoneY(context) {
34011   return new MonotoneY(context);
34012 }
34013
34014 function Natural(context) {
34015   this._context = context;
34016 }
34017
34018 Natural.prototype = {
34019   areaStart: function() {
34020     this._line = 0;
34021   },
34022   areaEnd: function() {
34023     this._line = NaN;
34024   },
34025   lineStart: function() {
34026     this._x = [];
34027     this._y = [];
34028   },
34029   lineEnd: function() {
34030     var x = this._x,
34031         y = this._y,
34032         n = x.length;
34033
34034     if (n) {
34035       this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);
34036       if (n === 2) {
34037         this._context.lineTo(x[1], y[1]);
34038       } else {
34039         var px = controlPoints(x),
34040             py = controlPoints(y);
34041         for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
34042           this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);
34043         }
34044       }
34045     }
34046
34047     if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();
34048     this._line = 1 - this._line;
34049     this._x = this._y = null;
34050   },
34051   point: function(x, y) {
34052     this._x.push(+x);
34053     this._y.push(+y);
34054   }
34055 };
34056
34057 // See https://www.particleincell.com/2012/bezier-splines/ for derivation.
34058 function controlPoints(x) {
34059   var i,
34060       n = x.length - 1,
34061       m,
34062       a = new Array(n),
34063       b = new Array(n),
34064       r = new Array(n);
34065   a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];
34066   for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];
34067   a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];
34068   for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
34069   a[n - 1] = r[n - 1] / b[n - 1];
34070   for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
34071   b[n - 1] = (x[n] + a[n - 1]) / 2;
34072   for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
34073   return [a, b];
34074 }
34075
34076 var natural = function(context) {
34077   return new Natural(context);
34078 };
34079
34080 function Step(context, t) {
34081   this._context = context;
34082   this._t = t;
34083 }
34084
34085 Step.prototype = {
34086   areaStart: function() {
34087     this._line = 0;
34088   },
34089   areaEnd: function() {
34090     this._line = NaN;
34091   },
34092   lineStart: function() {
34093     this._x = this._y = NaN;
34094     this._point = 0;
34095   },
34096   lineEnd: function() {
34097     if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
34098     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
34099     if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
34100   },
34101   point: function(x, y) {
34102     x = +x, y = +y;
34103     switch (this._point) {
34104       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
34105       case 1: this._point = 2; // proceed
34106       default: {
34107         if (this._t <= 0) {
34108           this._context.lineTo(this._x, y);
34109           this._context.lineTo(x, y);
34110         } else {
34111           var x1 = this._x * (1 - this._t) + x * this._t;
34112           this._context.lineTo(x1, this._y);
34113           this._context.lineTo(x1, y);
34114         }
34115         break;
34116       }
34117     }
34118     this._x = x, this._y = y;
34119   }
34120 };
34121
34122 var step = function(context) {
34123   return new Step(context, 0.5);
34124 };
34125
34126 function stepBefore(context) {
34127   return new Step(context, 0);
34128 }
34129
34130 function stepAfter(context) {
34131   return new Step(context, 1);
34132 }
34133
34134 var none$1 = function(series, order) {
34135   if (!((n = series.length) > 1)) return;
34136   for (var i = 1, j, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
34137     s0 = s1, s1 = series[order[i]];
34138     for (j = 0; j < m; ++j) {
34139       s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];
34140     }
34141   }
34142 };
34143
34144 var none$2 = function(series) {
34145   var n = series.length, o = new Array(n);
34146   while (--n >= 0) o[n] = n;
34147   return o;
34148 };
34149
34150 function stackValue(d, key) {
34151   return d[key];
34152 }
34153
34154 var stack = function() {
34155   var keys = constant$10([]),
34156       order = none$2,
34157       offset = none$1,
34158       value = stackValue;
34159
34160   function stack(data) {
34161     var kz = keys.apply(this, arguments),
34162         i,
34163         m = data.length,
34164         n = kz.length,
34165         sz = new Array(n),
34166         oz;
34167
34168     for (i = 0; i < n; ++i) {
34169       for (var ki = kz[i], si = sz[i] = new Array(m), j = 0, sij; j < m; ++j) {
34170         si[j] = sij = [0, +value(data[j], ki, j, data)];
34171         sij.data = data[j];
34172       }
34173       si.key = ki;
34174     }
34175
34176     for (i = 0, oz = order(sz); i < n; ++i) {
34177       sz[oz[i]].index = i;
34178     }
34179
34180     offset(sz, oz);
34181     return sz;
34182   }
34183
34184   stack.keys = function(_) {
34185     return arguments.length ? (keys = typeof _ === "function" ? _ : constant$10(slice$5.call(_)), stack) : keys;
34186   };
34187
34188   stack.value = function(_) {
34189     return arguments.length ? (value = typeof _ === "function" ? _ : constant$10(+_), stack) : value;
34190   };
34191
34192   stack.order = function(_) {
34193     return arguments.length ? (order = _ == null ? none$2 : typeof _ === "function" ? _ : constant$10(slice$5.call(_)), stack) : order;
34194   };
34195
34196   stack.offset = function(_) {
34197     return arguments.length ? (offset = _ == null ? none$1 : _, stack) : offset;
34198   };
34199
34200   return stack;
34201 };
34202
34203 var expand = function(series, order) {
34204   if (!((n = series.length) > 0)) return;
34205   for (var i, n, j = 0, m = series[0].length, y; j < m; ++j) {
34206     for (y = i = 0; i < n; ++i) y += series[i][j][1] || 0;
34207     if (y) for (i = 0; i < n; ++i) series[i][j][1] /= y;
34208   }
34209   none$1(series, order);
34210 };
34211
34212 var diverging = function(series, order) {
34213   if (!((n = series.length) > 1)) return;
34214   for (var i, j = 0, d, dy, yp, yn, n, m = series[order[0]].length; j < m; ++j) {
34215     for (yp = yn = 0, i = 0; i < n; ++i) {
34216       if ((dy = (d = series[order[i]][j])[1] - d[0]) >= 0) {
34217         d[0] = yp, d[1] = yp += dy;
34218       } else if (dy < 0) {
34219         d[1] = yn, d[0] = yn += dy;
34220       } else {
34221         d[0] = yp;
34222       }
34223     }
34224   }
34225 };
34226
34227 var silhouette = function(series, order) {
34228   if (!((n = series.length) > 0)) return;
34229   for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {
34230     for (var i = 0, y = 0; i < n; ++i) y += series[i][j][1] || 0;
34231     s0[j][1] += s0[j][0] = -y / 2;
34232   }
34233   none$1(series, order);
34234 };
34235
34236 var wiggle = function(series, order) {
34237   if (!((n = series.length) > 0) || !((m = (s0 = series[order[0]]).length) > 0)) return;
34238   for (var y = 0, j = 1, s0, m, n; j < m; ++j) {
34239     for (var i = 0, s1 = 0, s2 = 0; i < n; ++i) {
34240       var si = series[order[i]],
34241           sij0 = si[j][1] || 0,
34242           sij1 = si[j - 1][1] || 0,
34243           s3 = (sij0 - sij1) / 2;
34244       for (var k = 0; k < i; ++k) {
34245         var sk = series[order[k]],
34246             skj0 = sk[j][1] || 0,
34247             skj1 = sk[j - 1][1] || 0;
34248         s3 += skj0 - skj1;
34249       }
34250       s1 += sij0, s2 += s3 * sij0;
34251     }
34252     s0[j - 1][1] += s0[j - 1][0] = y;
34253     if (s1) y -= s2 / s1;
34254   }
34255   s0[j - 1][1] += s0[j - 1][0] = y;
34256   none$1(series, order);
34257 };
34258
34259 var ascending$2 = function(series) {
34260   var sums = series.map(sum$2);
34261   return none$2(series).sort(function(a, b) { return sums[a] - sums[b]; });
34262 };
34263
34264 function sum$2(series) {
34265   var s = 0, i = -1, n = series.length, v;
34266   while (++i < n) if (v = +series[i][1]) s += v;
34267   return s;
34268 }
34269
34270 var descending$2 = function(series) {
34271   return ascending$2(series).reverse();
34272 };
34273
34274 var insideOut = function(series) {
34275   var n = series.length,
34276       i,
34277       j,
34278       sums = series.map(sum$2),
34279       order = none$2(series).sort(function(a, b) { return sums[b] - sums[a]; }),
34280       top = 0,
34281       bottom = 0,
34282       tops = [],
34283       bottoms = [];
34284
34285   for (i = 0; i < n; ++i) {
34286     j = order[i];
34287     if (top < bottom) {
34288       top += sums[j];
34289       tops.push(j);
34290     } else {
34291       bottom += sums[j];
34292       bottoms.push(j);
34293     }
34294   }
34295
34296   return bottoms.reverse().concat(tops);
34297 };
34298
34299 var reverse = function(series) {
34300   return none$2(series).reverse();
34301 };
34302
34303 var constant$11 = function(x) {
34304   return function() {
34305     return x;
34306   };
34307 };
34308
34309 function x$4(d) {
34310   return d[0];
34311 }
34312
34313 function y$4(d) {
34314   return d[1];
34315 }
34316
34317 function RedBlackTree() {
34318   this._ = null; // root node
34319 }
34320
34321 function RedBlackNode(node) {
34322   node.U = // parent node
34323   node.C = // color - true for red, false for black
34324   node.L = // left node
34325   node.R = // right node
34326   node.P = // previous node
34327   node.N = null; // next node
34328 }
34329
34330 RedBlackTree.prototype = {
34331   constructor: RedBlackTree,
34332
34333   insert: function(after, node) {
34334     var parent, grandpa, uncle;
34335
34336     if (after) {
34337       node.P = after;
34338       node.N = after.N;
34339       if (after.N) after.N.P = node;
34340       after.N = node;
34341       if (after.R) {
34342         after = after.R;
34343         while (after.L) after = after.L;
34344         after.L = node;
34345       } else {
34346         after.R = node;
34347       }
34348       parent = after;
34349     } else if (this._) {
34350       after = RedBlackFirst(this._);
34351       node.P = null;
34352       node.N = after;
34353       after.P = after.L = node;
34354       parent = after;
34355     } else {
34356       node.P = node.N = null;
34357       this._ = node;
34358       parent = null;
34359     }
34360     node.L = node.R = null;
34361     node.U = parent;
34362     node.C = true;
34363
34364     after = node;
34365     while (parent && parent.C) {
34366       grandpa = parent.U;
34367       if (parent === grandpa.L) {
34368         uncle = grandpa.R;
34369         if (uncle && uncle.C) {
34370           parent.C = uncle.C = false;
34371           grandpa.C = true;
34372           after = grandpa;
34373         } else {
34374           if (after === parent.R) {
34375             RedBlackRotateLeft(this, parent);
34376             after = parent;
34377             parent = after.U;
34378           }
34379           parent.C = false;
34380           grandpa.C = true;
34381           RedBlackRotateRight(this, grandpa);
34382         }
34383       } else {
34384         uncle = grandpa.L;
34385         if (uncle && uncle.C) {
34386           parent.C = uncle.C = false;
34387           grandpa.C = true;
34388           after = grandpa;
34389         } else {
34390           if (after === parent.L) {
34391             RedBlackRotateRight(this, parent);
34392             after = parent;
34393             parent = after.U;
34394           }
34395           parent.C = false;
34396           grandpa.C = true;
34397           RedBlackRotateLeft(this, grandpa);
34398         }
34399       }
34400       parent = after.U;
34401     }
34402     this._.C = false;
34403   },
34404
34405   remove: function(node) {
34406     if (node.N) node.N.P = node.P;
34407     if (node.P) node.P.N = node.N;
34408     node.N = node.P = null;
34409
34410     var parent = node.U,
34411         sibling,
34412         left = node.L,
34413         right = node.R,
34414         next,
34415         red;
34416
34417     if (!left) next = right;
34418     else if (!right) next = left;
34419     else next = RedBlackFirst(right);
34420
34421     if (parent) {
34422       if (parent.L === node) parent.L = next;
34423       else parent.R = next;
34424     } else {
34425       this._ = next;
34426     }
34427
34428     if (left && right) {
34429       red = next.C;
34430       next.C = node.C;
34431       next.L = left;
34432       left.U = next;
34433       if (next !== right) {
34434         parent = next.U;
34435         next.U = node.U;
34436         node = next.R;
34437         parent.L = node;
34438         next.R = right;
34439         right.U = next;
34440       } else {
34441         next.U = parent;
34442         parent = next;
34443         node = next.R;
34444       }
34445     } else {
34446       red = node.C;
34447       node = next;
34448     }
34449
34450     if (node) node.U = parent;
34451     if (red) return;
34452     if (node && node.C) { node.C = false; return; }
34453
34454     do {
34455       if (node === this._) break;
34456       if (node === parent.L) {
34457         sibling = parent.R;
34458         if (sibling.C) {
34459           sibling.C = false;
34460           parent.C = true;
34461           RedBlackRotateLeft(this, parent);
34462           sibling = parent.R;
34463         }
34464         if ((sibling.L && sibling.L.C)
34465             || (sibling.R && sibling.R.C)) {
34466           if (!sibling.R || !sibling.R.C) {
34467             sibling.L.C = false;
34468             sibling.C = true;
34469             RedBlackRotateRight(this, sibling);
34470             sibling = parent.R;
34471           }
34472           sibling.C = parent.C;
34473           parent.C = sibling.R.C = false;
34474           RedBlackRotateLeft(this, parent);
34475           node = this._;
34476           break;
34477         }
34478       } else {
34479         sibling = parent.L;
34480         if (sibling.C) {
34481           sibling.C = false;
34482           parent.C = true;
34483           RedBlackRotateRight(this, parent);
34484           sibling = parent.L;
34485         }
34486         if ((sibling.L && sibling.L.C)
34487           || (sibling.R && sibling.R.C)) {
34488           if (!sibling.L || !sibling.L.C) {
34489             sibling.R.C = false;
34490             sibling.C = true;
34491             RedBlackRotateLeft(this, sibling);
34492             sibling = parent.L;
34493           }
34494           sibling.C = parent.C;
34495           parent.C = sibling.L.C = false;
34496           RedBlackRotateRight(this, parent);
34497           node = this._;
34498           break;
34499         }
34500       }
34501       sibling.C = true;
34502       node = parent;
34503       parent = parent.U;
34504     } while (!node.C);
34505
34506     if (node) node.C = false;
34507   }
34508 };
34509
34510 function RedBlackRotateLeft(tree, node) {
34511   var p = node,
34512       q = node.R,
34513       parent = p.U;
34514
34515   if (parent) {
34516     if (parent.L === p) parent.L = q;
34517     else parent.R = q;
34518   } else {
34519     tree._ = q;
34520   }
34521
34522   q.U = parent;
34523   p.U = q;
34524   p.R = q.L;
34525   if (p.R) p.R.U = p;
34526   q.L = p;
34527 }
34528
34529 function RedBlackRotateRight(tree, node) {
34530   var p = node,
34531       q = node.L,
34532       parent = p.U;
34533
34534   if (parent) {
34535     if (parent.L === p) parent.L = q;
34536     else parent.R = q;
34537   } else {
34538     tree._ = q;
34539   }
34540
34541   q.U = parent;
34542   p.U = q;
34543   p.L = q.R;
34544   if (p.L) p.L.U = p;
34545   q.R = p;
34546 }
34547
34548 function RedBlackFirst(node) {
34549   while (node.L) node = node.L;
34550   return node;
34551 }
34552
34553 function createEdge(left, right, v0, v1) {
34554   var edge = [null, null],
34555       index = edges.push(edge) - 1;
34556   edge.left = left;
34557   edge.right = right;
34558   if (v0) setEdgeEnd(edge, left, right, v0);
34559   if (v1) setEdgeEnd(edge, right, left, v1);
34560   cells[left.index].halfedges.push(index);
34561   cells[right.index].halfedges.push(index);
34562   return edge;
34563 }
34564
34565 function createBorderEdge(left, v0, v1) {
34566   var edge = [v0, v1];
34567   edge.left = left;
34568   return edge;
34569 }
34570
34571 function setEdgeEnd(edge, left, right, vertex) {
34572   if (!edge[0] && !edge[1]) {
34573     edge[0] = vertex;
34574     edge.left = left;
34575     edge.right = right;
34576   } else if (edge.left === right) {
34577     edge[1] = vertex;
34578   } else {
34579     edge[0] = vertex;
34580   }
34581 }
34582
34583 // Liang–Barsky line clipping.
34584 function clipEdge(edge, x0, y0, x1, y1) {
34585   var a = edge[0],
34586       b = edge[1],
34587       ax = a[0],
34588       ay = a[1],
34589       bx = b[0],
34590       by = b[1],
34591       t0 = 0,
34592       t1 = 1,
34593       dx = bx - ax,
34594       dy = by - ay,
34595       r;
34596
34597   r = x0 - ax;
34598   if (!dx && r > 0) return;
34599   r /= dx;
34600   if (dx < 0) {
34601     if (r < t0) return;
34602     if (r < t1) t1 = r;
34603   } else if (dx > 0) {
34604     if (r > t1) return;
34605     if (r > t0) t0 = r;
34606   }
34607
34608   r = x1 - ax;
34609   if (!dx && r < 0) return;
34610   r /= dx;
34611   if (dx < 0) {
34612     if (r > t1) return;
34613     if (r > t0) t0 = r;
34614   } else if (dx > 0) {
34615     if (r < t0) return;
34616     if (r < t1) t1 = r;
34617   }
34618
34619   r = y0 - ay;
34620   if (!dy && r > 0) return;
34621   r /= dy;
34622   if (dy < 0) {
34623     if (r < t0) return;
34624     if (r < t1) t1 = r;
34625   } else if (dy > 0) {
34626     if (r > t1) return;
34627     if (r > t0) t0 = r;
34628   }
34629
34630   r = y1 - ay;
34631   if (!dy && r < 0) return;
34632   r /= dy;
34633   if (dy < 0) {
34634     if (r > t1) return;
34635     if (r > t0) t0 = r;
34636   } else if (dy > 0) {
34637     if (r < t0) return;
34638     if (r < t1) t1 = r;
34639   }
34640
34641   if (!(t0 > 0) && !(t1 < 1)) return true; // TODO Better check?
34642
34643   if (t0 > 0) edge[0] = [ax + t0 * dx, ay + t0 * dy];
34644   if (t1 < 1) edge[1] = [ax + t1 * dx, ay + t1 * dy];
34645   return true;
34646 }
34647
34648 function connectEdge(edge, x0, y0, x1, y1) {
34649   var v1 = edge[1];
34650   if (v1) return true;
34651
34652   var v0 = edge[0],
34653       left = edge.left,
34654       right = edge.right,
34655       lx = left[0],
34656       ly = left[1],
34657       rx = right[0],
34658       ry = right[1],
34659       fx = (lx + rx) / 2,
34660       fy = (ly + ry) / 2,
34661       fm,
34662       fb;
34663
34664   if (ry === ly) {
34665     if (fx < x0 || fx >= x1) return;
34666     if (lx > rx) {
34667       if (!v0) v0 = [fx, y0];
34668       else if (v0[1] >= y1) return;
34669       v1 = [fx, y1];
34670     } else {
34671       if (!v0) v0 = [fx, y1];
34672       else if (v0[1] < y0) return;
34673       v1 = [fx, y0];
34674     }
34675   } else {
34676     fm = (lx - rx) / (ry - ly);
34677     fb = fy - fm * fx;
34678     if (fm < -1 || fm > 1) {
34679       if (lx > rx) {
34680         if (!v0) v0 = [(y0 - fb) / fm, y0];
34681         else if (v0[1] >= y1) return;
34682         v1 = [(y1 - fb) / fm, y1];
34683       } else {
34684         if (!v0) v0 = [(y1 - fb) / fm, y1];
34685         else if (v0[1] < y0) return;
34686         v1 = [(y0 - fb) / fm, y0];
34687       }
34688     } else {
34689       if (ly < ry) {
34690         if (!v0) v0 = [x0, fm * x0 + fb];
34691         else if (v0[0] >= x1) return;
34692         v1 = [x1, fm * x1 + fb];
34693       } else {
34694         if (!v0) v0 = [x1, fm * x1 + fb];
34695         else if (v0[0] < x0) return;
34696         v1 = [x0, fm * x0 + fb];
34697       }
34698     }
34699   }
34700
34701   edge[0] = v0;
34702   edge[1] = v1;
34703   return true;
34704 }
34705
34706 function clipEdges(x0, y0, x1, y1) {
34707   var i = edges.length,
34708       edge;
34709
34710   while (i--) {
34711     if (!connectEdge(edge = edges[i], x0, y0, x1, y1)
34712         || !clipEdge(edge, x0, y0, x1, y1)
34713         || !(Math.abs(edge[0][0] - edge[1][0]) > epsilon$4
34714             || Math.abs(edge[0][1] - edge[1][1]) > epsilon$4)) {
34715       delete edges[i];
34716     }
34717   }
34718 }
34719
34720 function createCell(site) {
34721   return cells[site.index] = {
34722     site: site,
34723     halfedges: []
34724   };
34725 }
34726
34727 function cellHalfedgeAngle(cell, edge) {
34728   var site = cell.site,
34729       va = edge.left,
34730       vb = edge.right;
34731   if (site === vb) vb = va, va = site;
34732   if (vb) return Math.atan2(vb[1] - va[1], vb[0] - va[0]);
34733   if (site === va) va = edge[1], vb = edge[0];
34734   else va = edge[0], vb = edge[1];
34735   return Math.atan2(va[0] - vb[0], vb[1] - va[1]);
34736 }
34737
34738 function cellHalfedgeStart(cell, edge) {
34739   return edge[+(edge.left !== cell.site)];
34740 }
34741
34742 function cellHalfedgeEnd(cell, edge) {
34743   return edge[+(edge.left === cell.site)];
34744 }
34745
34746 function sortCellHalfedges() {
34747   for (var i = 0, n = cells.length, cell, halfedges, j, m; i < n; ++i) {
34748     if ((cell = cells[i]) && (m = (halfedges = cell.halfedges).length)) {
34749       var index = new Array(m),
34750           array = new Array(m);
34751       for (j = 0; j < m; ++j) index[j] = j, array[j] = cellHalfedgeAngle(cell, edges[halfedges[j]]);
34752       index.sort(function(i, j) { return array[j] - array[i]; });
34753       for (j = 0; j < m; ++j) array[j] = halfedges[index[j]];
34754       for (j = 0; j < m; ++j) halfedges[j] = array[j];
34755     }
34756   }
34757 }
34758
34759 function clipCells(x0, y0, x1, y1) {
34760   var nCells = cells.length,
34761       iCell,
34762       cell,
34763       site,
34764       iHalfedge,
34765       halfedges,
34766       nHalfedges,
34767       start,
34768       startX,
34769       startY,
34770       end,
34771       endX,
34772       endY,
34773       cover = true;
34774
34775   for (iCell = 0; iCell < nCells; ++iCell) {
34776     if (cell = cells[iCell]) {
34777       site = cell.site;
34778       halfedges = cell.halfedges;
34779       iHalfedge = halfedges.length;
34780
34781       // Remove any dangling clipped edges.
34782       while (iHalfedge--) {
34783         if (!edges[halfedges[iHalfedge]]) {
34784           halfedges.splice(iHalfedge, 1);
34785         }
34786       }
34787
34788       // Insert any border edges as necessary.
34789       iHalfedge = 0, nHalfedges = halfedges.length;
34790       while (iHalfedge < nHalfedges) {
34791         end = cellHalfedgeEnd(cell, edges[halfedges[iHalfedge]]), endX = end[0], endY = end[1];
34792         start = cellHalfedgeStart(cell, edges[halfedges[++iHalfedge % nHalfedges]]), startX = start[0], startY = start[1];
34793         if (Math.abs(endX - startX) > epsilon$4 || Math.abs(endY - startY) > epsilon$4) {
34794           halfedges.splice(iHalfedge, 0, edges.push(createBorderEdge(site, end,
34795               Math.abs(endX - x0) < epsilon$4 && y1 - endY > epsilon$4 ? [x0, Math.abs(startX - x0) < epsilon$4 ? startY : y1]
34796               : Math.abs(endY - y1) < epsilon$4 && x1 - endX > epsilon$4 ? [Math.abs(startY - y1) < epsilon$4 ? startX : x1, y1]
34797               : Math.abs(endX - x1) < epsilon$4 && endY - y0 > epsilon$4 ? [x1, Math.abs(startX - x1) < epsilon$4 ? startY : y0]
34798               : Math.abs(endY - y0) < epsilon$4 && endX - x0 > epsilon$4 ? [Math.abs(startY - y0) < epsilon$4 ? startX : x0, y0]
34799               : null)) - 1);
34800           ++nHalfedges;
34801         }
34802       }
34803
34804       if (nHalfedges) cover = false;
34805     }
34806   }
34807
34808   // If there weren’t any edges, have the closest site cover the extent.
34809   // It doesn’t matter which corner of the extent we measure!
34810   if (cover) {
34811     var dx, dy, d2, dc = Infinity;
34812
34813     for (iCell = 0, cover = null; iCell < nCells; ++iCell) {
34814       if (cell = cells[iCell]) {
34815         site = cell.site;
34816         dx = site[0] - x0;
34817         dy = site[1] - y0;
34818         d2 = dx * dx + dy * dy;
34819         if (d2 < dc) dc = d2, cover = cell;
34820       }
34821     }
34822
34823     if (cover) {
34824       var v00 = [x0, y0], v01 = [x0, y1], v11 = [x1, y1], v10 = [x1, y0];
34825       cover.halfedges.push(
34826         edges.push(createBorderEdge(site = cover.site, v00, v01)) - 1,
34827         edges.push(createBorderEdge(site, v01, v11)) - 1,
34828         edges.push(createBorderEdge(site, v11, v10)) - 1,
34829         edges.push(createBorderEdge(site, v10, v00)) - 1
34830       );
34831     }
34832   }
34833
34834   // Lastly delete any cells with no edges; these were entirely clipped.
34835   for (iCell = 0; iCell < nCells; ++iCell) {
34836     if (cell = cells[iCell]) {
34837       if (!cell.halfedges.length) {
34838         delete cells[iCell];
34839       }
34840     }
34841   }
34842 }
34843
34844 var circlePool = [];
34845
34846 var firstCircle;
34847
34848 function Circle() {
34849   RedBlackNode(this);
34850   this.x =
34851   this.y =
34852   this.arc =
34853   this.site =
34854   this.cy = null;
34855 }
34856
34857 function attachCircle(arc) {
34858   var lArc = arc.P,
34859       rArc = arc.N;
34860
34861   if (!lArc || !rArc) return;
34862
34863   var lSite = lArc.site,
34864       cSite = arc.site,
34865       rSite = rArc.site;
34866
34867   if (lSite === rSite) return;
34868
34869   var bx = cSite[0],
34870       by = cSite[1],
34871       ax = lSite[0] - bx,
34872       ay = lSite[1] - by,
34873       cx = rSite[0] - bx,
34874       cy = rSite[1] - by;
34875
34876   var d = 2 * (ax * cy - ay * cx);
34877   if (d >= -epsilon2$2) return;
34878
34879   var ha = ax * ax + ay * ay,
34880       hc = cx * cx + cy * cy,
34881       x = (cy * ha - ay * hc) / d,
34882       y = (ax * hc - cx * ha) / d;
34883
34884   var circle = circlePool.pop() || new Circle;
34885   circle.arc = arc;
34886   circle.site = cSite;
34887   circle.x = x + bx;
34888   circle.y = (circle.cy = y + by) + Math.sqrt(x * x + y * y); // y bottom
34889
34890   arc.circle = circle;
34891
34892   var before = null,
34893       node = circles._;
34894
34895   while (node) {
34896     if (circle.y < node.y || (circle.y === node.y && circle.x <= node.x)) {
34897       if (node.L) node = node.L;
34898       else { before = node.P; break; }
34899     } else {
34900       if (node.R) node = node.R;
34901       else { before = node; break; }
34902     }
34903   }
34904
34905   circles.insert(before, circle);
34906   if (!before) firstCircle = circle;
34907 }
34908
34909 function detachCircle(arc) {
34910   var circle = arc.circle;
34911   if (circle) {
34912     if (!circle.P) firstCircle = circle.N;
34913     circles.remove(circle);
34914     circlePool.push(circle);
34915     RedBlackNode(circle);
34916     arc.circle = null;
34917   }
34918 }
34919
34920 var beachPool = [];
34921
34922 function Beach() {
34923   RedBlackNode(this);
34924   this.edge =
34925   this.site =
34926   this.circle = null;
34927 }
34928
34929 function createBeach(site) {
34930   var beach = beachPool.pop() || new Beach;
34931   beach.site = site;
34932   return beach;
34933 }
34934
34935 function detachBeach(beach) {
34936   detachCircle(beach);
34937   beaches.remove(beach);
34938   beachPool.push(beach);
34939   RedBlackNode(beach);
34940 }
34941
34942 function removeBeach(beach) {
34943   var circle = beach.circle,
34944       x = circle.x,
34945       y = circle.cy,
34946       vertex = [x, y],
34947       previous = beach.P,
34948       next = beach.N,
34949       disappearing = [beach];
34950
34951   detachBeach(beach);
34952
34953   var lArc = previous;
34954   while (lArc.circle
34955       && Math.abs(x - lArc.circle.x) < epsilon$4
34956       && Math.abs(y - lArc.circle.cy) < epsilon$4) {
34957     previous = lArc.P;
34958     disappearing.unshift(lArc);
34959     detachBeach(lArc);
34960     lArc = previous;
34961   }
34962
34963   disappearing.unshift(lArc);
34964   detachCircle(lArc);
34965
34966   var rArc = next;
34967   while (rArc.circle
34968       && Math.abs(x - rArc.circle.x) < epsilon$4
34969       && Math.abs(y - rArc.circle.cy) < epsilon$4) {
34970     next = rArc.N;
34971     disappearing.push(rArc);
34972     detachBeach(rArc);
34973     rArc = next;
34974   }
34975
34976   disappearing.push(rArc);
34977   detachCircle(rArc);
34978
34979   var nArcs = disappearing.length,
34980       iArc;
34981   for (iArc = 1; iArc < nArcs; ++iArc) {
34982     rArc = disappearing[iArc];
34983     lArc = disappearing[iArc - 1];
34984     setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
34985   }
34986
34987   lArc = disappearing[0];
34988   rArc = disappearing[nArcs - 1];
34989   rArc.edge = createEdge(lArc.site, rArc.site, null, vertex);
34990
34991   attachCircle(lArc);
34992   attachCircle(rArc);
34993 }
34994
34995 function addBeach(site) {
34996   var x = site[0],
34997       directrix = site[1],
34998       lArc,
34999       rArc,
35000       dxl,
35001       dxr,
35002       node = beaches._;
35003
35004   while (node) {
35005     dxl = leftBreakPoint(node, directrix) - x;
35006     if (dxl > epsilon$4) node = node.L; else {
35007       dxr = x - rightBreakPoint(node, directrix);
35008       if (dxr > epsilon$4) {
35009         if (!node.R) {
35010           lArc = node;
35011           break;
35012         }
35013         node = node.R;
35014       } else {
35015         if (dxl > -epsilon$4) {
35016           lArc = node.P;
35017           rArc = node;
35018         } else if (dxr > -epsilon$4) {
35019           lArc = node;
35020           rArc = node.N;
35021         } else {
35022           lArc = rArc = node;
35023         }
35024         break;
35025       }
35026     }
35027   }
35028
35029   createCell(site);
35030   var newArc = createBeach(site);
35031   beaches.insert(lArc, newArc);
35032
35033   if (!lArc && !rArc) return;
35034
35035   if (lArc === rArc) {
35036     detachCircle(lArc);
35037     rArc = createBeach(lArc.site);
35038     beaches.insert(newArc, rArc);
35039     newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site);
35040     attachCircle(lArc);
35041     attachCircle(rArc);
35042     return;
35043   }
35044
35045   if (!rArc) { // && lArc
35046     newArc.edge = createEdge(lArc.site, newArc.site);
35047     return;
35048   }
35049
35050   // else lArc !== rArc
35051   detachCircle(lArc);
35052   detachCircle(rArc);
35053
35054   var lSite = lArc.site,
35055       ax = lSite[0],
35056       ay = lSite[1],
35057       bx = site[0] - ax,
35058       by = site[1] - ay,
35059       rSite = rArc.site,
35060       cx = rSite[0] - ax,
35061       cy = rSite[1] - ay,
35062       d = 2 * (bx * cy - by * cx),
35063       hb = bx * bx + by * by,
35064       hc = cx * cx + cy * cy,
35065       vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay];
35066
35067   setEdgeEnd(rArc.edge, lSite, rSite, vertex);
35068   newArc.edge = createEdge(lSite, site, null, vertex);
35069   rArc.edge = createEdge(site, rSite, null, vertex);
35070   attachCircle(lArc);
35071   attachCircle(rArc);
35072 }
35073
35074 function leftBreakPoint(arc, directrix) {
35075   var site = arc.site,
35076       rfocx = site[0],
35077       rfocy = site[1],
35078       pby2 = rfocy - directrix;
35079
35080   if (!pby2) return rfocx;
35081
35082   var lArc = arc.P;
35083   if (!lArc) return -Infinity;
35084
35085   site = lArc.site;
35086   var lfocx = site[0],
35087       lfocy = site[1],
35088       plby2 = lfocy - directrix;
35089
35090   if (!plby2) return lfocx;
35091
35092   var hl = lfocx - rfocx,
35093       aby2 = 1 / pby2 - 1 / plby2,
35094       b = hl / plby2;
35095
35096   if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
35097
35098   return (rfocx + lfocx) / 2;
35099 }
35100
35101 function rightBreakPoint(arc, directrix) {
35102   var rArc = arc.N;
35103   if (rArc) return leftBreakPoint(rArc, directrix);
35104   var site = arc.site;
35105   return site[1] === directrix ? site[0] : Infinity;
35106 }
35107
35108 var epsilon$4 = 1e-6;
35109 var epsilon2$2 = 1e-12;
35110 var beaches;
35111 var cells;
35112 var circles;
35113 var edges;
35114
35115 function triangleArea(a, b, c) {
35116   return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]);
35117 }
35118
35119 function lexicographic(a, b) {
35120   return b[1] - a[1]
35121       || b[0] - a[0];
35122 }
35123
35124 function Diagram(sites, extent) {
35125   var site = sites.sort(lexicographic).pop(),
35126       x,
35127       y,
35128       circle;
35129
35130   edges = [];
35131   cells = new Array(sites.length);
35132   beaches = new RedBlackTree;
35133   circles = new RedBlackTree;
35134
35135   while (true) {
35136     circle = firstCircle;
35137     if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) {
35138       if (site[0] !== x || site[1] !== y) {
35139         addBeach(site);
35140         x = site[0], y = site[1];
35141       }
35142       site = sites.pop();
35143     } else if (circle) {
35144       removeBeach(circle.arc);
35145     } else {
35146       break;
35147     }
35148   }
35149
35150   sortCellHalfedges();
35151
35152   if (extent) {
35153     var x0 = +extent[0][0],
35154         y0 = +extent[0][1],
35155         x1 = +extent[1][0],
35156         y1 = +extent[1][1];
35157     clipEdges(x0, y0, x1, y1);
35158     clipCells(x0, y0, x1, y1);
35159   }
35160
35161   this.edges = edges;
35162   this.cells = cells;
35163
35164   beaches =
35165   circles =
35166   edges =
35167   cells = null;
35168 }
35169
35170 Diagram.prototype = {
35171   constructor: Diagram,
35172
35173   polygons: function() {
35174     var edges = this.edges;
35175
35176     return this.cells.map(function(cell) {
35177       var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); });
35178       polygon.data = cell.site.data;
35179       return polygon;
35180     });
35181   },
35182
35183   triangles: function() {
35184     var triangles = [],
35185         edges = this.edges;
35186
35187     this.cells.forEach(function(cell, i) {
35188       if (!(m = (halfedges = cell.halfedges).length)) return;
35189       var site = cell.site,
35190           halfedges,
35191           j = -1,
35192           m,
35193           s0,
35194           e1 = edges[halfedges[m - 1]],
35195           s1 = e1.left === site ? e1.right : e1.left;
35196
35197       while (++j < m) {
35198         s0 = s1;
35199         e1 = edges[halfedges[j]];
35200         s1 = e1.left === site ? e1.right : e1.left;
35201         if (s0 && s1 && i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) {
35202           triangles.push([site.data, s0.data, s1.data]);
35203         }
35204       }
35205     });
35206
35207     return triangles;
35208   },
35209
35210   links: function() {
35211     return this.edges.filter(function(edge) {
35212       return edge.right;
35213     }).map(function(edge) {
35214       return {
35215         source: edge.left.data,
35216         target: edge.right.data
35217       };
35218     });
35219   },
35220
35221   find: function(x, y, radius) {
35222     var that = this, i0, i1 = that._found || 0, n = that.cells.length, cell;
35223
35224     // Use the previously-found cell, or start with an arbitrary one.
35225     while (!(cell = that.cells[i1])) if (++i1 >= n) return null;
35226     var dx = x - cell.site[0], dy = y - cell.site[1], d2 = dx * dx + dy * dy;
35227
35228     // Traverse the half-edges to find a closer cell, if any.
35229     do {
35230       cell = that.cells[i0 = i1], i1 = null;
35231       cell.halfedges.forEach(function(e) {
35232         var edge = that.edges[e], v = edge.left;
35233         if ((v === cell.site || !v) && !(v = edge.right)) return;
35234         var vx = x - v[0], vy = y - v[1], v2 = vx * vx + vy * vy;
35235         if (v2 < d2) d2 = v2, i1 = v.index;
35236       });
35237     } while (i1 !== null);
35238
35239     that._found = i0;
35240
35241     return radius == null || d2 <= radius * radius ? cell.site : null;
35242   }
35243 };
35244
35245 var voronoi = function() {
35246   var x = x$4,
35247       y = y$4,
35248       extent = null;
35249
35250   function voronoi(data) {
35251     return new Diagram(data.map(function(d, i) {
35252       var s = [Math.round(x(d, i, data) / epsilon$4) * epsilon$4, Math.round(y(d, i, data) / epsilon$4) * epsilon$4];
35253       s.index = i;
35254       s.data = d;
35255       return s;
35256     }), extent);
35257   }
35258
35259   voronoi.polygons = function(data) {
35260     return voronoi(data).polygons();
35261   };
35262
35263   voronoi.links = function(data) {
35264     return voronoi(data).links();
35265   };
35266
35267   voronoi.triangles = function(data) {
35268     return voronoi(data).triangles();
35269   };
35270
35271   voronoi.x = function(_) {
35272     return arguments.length ? (x = typeof _ === "function" ? _ : constant$11(+_), voronoi) : x;
35273   };
35274
35275   voronoi.y = function(_) {
35276     return arguments.length ? (y = typeof _ === "function" ? _ : constant$11(+_), voronoi) : y;
35277   };
35278
35279   voronoi.extent = function(_) {
35280     return arguments.length ? (extent = _ == null ? null : [[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]], voronoi) : extent && [[extent[0][0], extent[0][1]], [extent[1][0], extent[1][1]]];
35281   };
35282
35283   voronoi.size = function(_) {
35284     return arguments.length ? (extent = _ == null ? null : [[0, 0], [+_[0], +_[1]]], voronoi) : extent && [extent[1][0] - extent[0][0], extent[1][1] - extent[0][1]];
35285   };
35286
35287   return voronoi;
35288 };
35289
35290 var constant$12 = function(x) {
35291   return function() {
35292     return x;
35293   };
35294 };
35295
35296 function ZoomEvent(target, type, transform) {
35297   this.target = target;
35298   this.type = type;
35299   this.transform = transform;
35300 }
35301
35302 function Transform(k, x, y) {
35303   this.k = k;
35304   this.x = x;
35305   this.y = y;
35306 }
35307
35308 Transform.prototype = {
35309   constructor: Transform,
35310   scale: function(k) {
35311     return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
35312   },
35313   translate: function(x, y) {
35314     return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
35315   },
35316   apply: function(point) {
35317     return [point[0] * this.k + this.x, point[1] * this.k + this.y];
35318   },
35319   applyX: function(x) {
35320     return x * this.k + this.x;
35321   },
35322   applyY: function(y) {
35323     return y * this.k + this.y;
35324   },
35325   invert: function(location) {
35326     return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
35327   },
35328   invertX: function(x) {
35329     return (x - this.x) / this.k;
35330   },
35331   invertY: function(y) {
35332     return (y - this.y) / this.k;
35333   },
35334   rescaleX: function(x) {
35335     return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
35336   },
35337   rescaleY: function(y) {
35338     return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
35339   },
35340   toString: function() {
35341     return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
35342   }
35343 };
35344
35345 var identity$8 = new Transform(1, 0, 0);
35346
35347 transform$1.prototype = Transform.prototype;
35348
35349 function transform$1(node) {
35350   return node.__zoom || identity$8;
35351 }
35352
35353 function nopropagation$2() {
35354   event.stopImmediatePropagation();
35355 }
35356
35357 var noevent$2 = function() {
35358   event.preventDefault();
35359   event.stopImmediatePropagation();
35360 };
35361
35362 // Ignore right-click, since that should open the context menu.
35363 function defaultFilter$2() {
35364   return !event.button;
35365 }
35366
35367 function defaultExtent$1() {
35368   var e = this, w, h;
35369   if (e instanceof SVGElement) {
35370     e = e.ownerSVGElement || e;
35371     w = e.width.baseVal.value;
35372     h = e.height.baseVal.value;
35373   } else {
35374     w = e.clientWidth;
35375     h = e.clientHeight;
35376   }
35377   return [[0, 0], [w, h]];
35378 }
35379
35380 function defaultTransform() {
35381   return this.__zoom || identity$8;
35382 }
35383
35384 var zoom = function() {
35385   var filter = defaultFilter$2,
35386       extent = defaultExtent$1,
35387       k0 = 0,
35388       k1 = Infinity,
35389       x0 = -k1,
35390       x1 = k1,
35391       y0 = x0,
35392       y1 = x1,
35393       duration = 250,
35394       interpolate = interpolateZoom,
35395       gestures = [],
35396       listeners = dispatch("start", "zoom", "end"),
35397       touchstarting,
35398       touchending,
35399       touchDelay = 500,
35400       wheelDelay = 150,
35401       clickDistance2 = 0;
35402
35403   function zoom(selection$$1) {
35404     selection$$1
35405         .on("wheel.zoom", wheeled)
35406         .on("mousedown.zoom", mousedowned)
35407         .on("dblclick.zoom", dblclicked)
35408         .on("touchstart.zoom", touchstarted)
35409         .on("touchmove.zoom", touchmoved)
35410         .on("touchend.zoom touchcancel.zoom", touchended)
35411         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
35412         .property("__zoom", defaultTransform);
35413   }
35414
35415   zoom.transform = function(collection, transform$$1) {
35416     var selection$$1 = collection.selection ? collection.selection() : collection;
35417     selection$$1.property("__zoom", defaultTransform);
35418     if (collection !== selection$$1) {
35419       schedule(collection, transform$$1);
35420     } else {
35421       selection$$1.interrupt().each(function() {
35422         gesture(this, arguments)
35423             .start()
35424             .zoom(null, typeof transform$$1 === "function" ? transform$$1.apply(this, arguments) : transform$$1)
35425             .end();
35426       });
35427     }
35428   };
35429
35430   zoom.scaleBy = function(selection$$1, k) {
35431     zoom.scaleTo(selection$$1, function() {
35432       var k0 = this.__zoom.k,
35433           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
35434       return k0 * k1;
35435     });
35436   };
35437
35438   zoom.scaleTo = function(selection$$1, k) {
35439     zoom.transform(selection$$1, function() {
35440       var e = extent.apply(this, arguments),
35441           t0 = this.__zoom,
35442           p0 = centroid(e),
35443           p1 = t0.invert(p0),
35444           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
35445       return constrain(translate(scale(t0, k1), p0, p1), e);
35446     });
35447   };
35448
35449   zoom.translateBy = function(selection$$1, x, y) {
35450     zoom.transform(selection$$1, function() {
35451       return constrain(this.__zoom.translate(
35452         typeof x === "function" ? x.apply(this, arguments) : x,
35453         typeof y === "function" ? y.apply(this, arguments) : y
35454       ), extent.apply(this, arguments));
35455     });
35456   };
35457
35458   function scale(transform$$1, k) {
35459     k = Math.max(k0, Math.min(k1, k));
35460     return k === transform$$1.k ? transform$$1 : new Transform(k, transform$$1.x, transform$$1.y);
35461   }
35462
35463   function translate(transform$$1, p0, p1) {
35464     var x = p0[0] - p1[0] * transform$$1.k, y = p0[1] - p1[1] * transform$$1.k;
35465     return x === transform$$1.x && y === transform$$1.y ? transform$$1 : new Transform(transform$$1.k, x, y);
35466   }
35467
35468   function constrain(transform$$1, extent) {
35469     var dx0 = transform$$1.invertX(extent[0][0]) - x0,
35470         dx1 = transform$$1.invertX(extent[1][0]) - x1,
35471         dy0 = transform$$1.invertY(extent[0][1]) - y0,
35472         dy1 = transform$$1.invertY(extent[1][1]) - y1;
35473     return transform$$1.translate(
35474       dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
35475       dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
35476     );
35477   }
35478
35479   function centroid(extent) {
35480     return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
35481   }
35482
35483   function schedule(transition$$1, transform$$1, center) {
35484     transition$$1
35485         .on("start.zoom", function() { gesture(this, arguments).start(); })
35486         .on("interrupt.zoom end.zoom", function() { gesture(this, arguments).end(); })
35487         .tween("zoom", function() {
35488           var that = this,
35489               args = arguments,
35490               g = gesture(that, args),
35491               e = extent.apply(that, args),
35492               p = center || centroid(e),
35493               w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
35494               a = that.__zoom,
35495               b = typeof transform$$1 === "function" ? transform$$1.apply(that, args) : transform$$1,
35496               i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
35497           return function(t) {
35498             if (t === 1) t = b; // Avoid rounding error on end.
35499             else { var l = i(t), k = w / l[2]; t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k); }
35500             g.zoom(null, t);
35501           };
35502         });
35503   }
35504
35505   function gesture(that, args) {
35506     for (var i = 0, n = gestures.length, g; i < n; ++i) {
35507       if ((g = gestures[i]).that === that) {
35508         return g;
35509       }
35510     }
35511     return new Gesture(that, args);
35512   }
35513
35514   function Gesture(that, args) {
35515     this.that = that;
35516     this.args = args;
35517     this.index = -1;
35518     this.active = 0;
35519     this.extent = extent.apply(that, args);
35520   }
35521
35522   Gesture.prototype = {
35523     start: function() {
35524       if (++this.active === 1) {
35525         this.index = gestures.push(this) - 1;
35526         this.emit("start");
35527       }
35528       return this;
35529     },
35530     zoom: function(key, transform$$1) {
35531       if (this.mouse && key !== "mouse") this.mouse[1] = transform$$1.invert(this.mouse[0]);
35532       if (this.touch0 && key !== "touch") this.touch0[1] = transform$$1.invert(this.touch0[0]);
35533       if (this.touch1 && key !== "touch") this.touch1[1] = transform$$1.invert(this.touch1[0]);
35534       this.that.__zoom = transform$$1;
35535       this.emit("zoom");
35536       return this;
35537     },
35538     end: function() {
35539       if (--this.active === 0) {
35540         gestures.splice(this.index, 1);
35541         this.index = -1;
35542         this.emit("end");
35543       }
35544       return this;
35545     },
35546     emit: function(type) {
35547       customEvent(new ZoomEvent(zoom, type, this.that.__zoom), listeners.apply, listeners, [type, this.that, this.args]);
35548     }
35549   };
35550
35551   function wheeled() {
35552     if (!filter.apply(this, arguments)) return;
35553     var g = gesture(this, arguments),
35554         t = this.__zoom,
35555         k = Math.max(k0, Math.min(k1, t.k * Math.pow(2, -event.deltaY * (event.deltaMode ? 120 : 1) / 500))),
35556         p = mouse(this);
35557
35558     // If the mouse is in the same location as before, reuse it.
35559     // If there were recent wheel events, reset the wheel idle timeout.
35560     if (g.wheel) {
35561       if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
35562         g.mouse[1] = t.invert(g.mouse[0] = p);
35563       }
35564       clearTimeout(g.wheel);
35565     }
35566
35567     // If this wheel event won’t trigger a transform change, ignore it.
35568     else if (t.k === k) return;
35569
35570     // Otherwise, capture the mouse point and location at the start.
35571     else {
35572       g.mouse = [p, t.invert(p)];
35573       interrupt(this);
35574       g.start();
35575     }
35576
35577     noevent$2();
35578     g.wheel = setTimeout(wheelidled, wheelDelay);
35579     g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent));
35580
35581     function wheelidled() {
35582       g.wheel = null;
35583       g.end();
35584     }
35585   }
35586
35587   function mousedowned() {
35588     if (touchending || !filter.apply(this, arguments)) return;
35589     var g = gesture(this, arguments),
35590         v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
35591         p = mouse(this),
35592         x0 = event.clientX,
35593         y0 = event.clientY;
35594
35595     dragDisable(event.view);
35596     nopropagation$2();
35597     g.mouse = [p, this.__zoom.invert(p)];
35598     interrupt(this);
35599     g.start();
35600
35601     function mousemoved() {
35602       noevent$2();
35603       if (!g.moved) {
35604         var dx = event.clientX - x0, dy = event.clientY - y0;
35605         g.moved = dx * dx + dy * dy > clickDistance2;
35606       }
35607       g.zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = mouse(g.that), g.mouse[1]), g.extent));
35608     }
35609
35610     function mouseupped() {
35611       v.on("mousemove.zoom mouseup.zoom", null);
35612       yesdrag(event.view, g.moved);
35613       noevent$2();
35614       g.end();
35615     }
35616   }
35617
35618   function dblclicked() {
35619     if (!filter.apply(this, arguments)) return;
35620     var t0 = this.__zoom,
35621         p0 = mouse(this),
35622         p1 = t0.invert(p0),
35623         k1 = t0.k * (event.shiftKey ? 0.5 : 2),
35624         t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, arguments));
35625
35626     noevent$2();
35627     if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0);
35628     else select(this).call(zoom.transform, t1);
35629   }
35630
35631   function touchstarted() {
35632     if (!filter.apply(this, arguments)) return;
35633     var g = gesture(this, arguments),
35634         touches$$1 = event.changedTouches,
35635         started,
35636         n = touches$$1.length, i, t, p;
35637
35638     nopropagation$2();
35639     for (i = 0; i < n; ++i) {
35640       t = touches$$1[i], p = touch(this, touches$$1, t.identifier);
35641       p = [p, this.__zoom.invert(p), t.identifier];
35642       if (!g.touch0) g.touch0 = p, started = true;
35643       else if (!g.touch1) g.touch1 = p;
35644     }
35645
35646     // If this is a dbltap, reroute to the (optional) dblclick.zoom handler.
35647     if (touchstarting) {
35648       touchstarting = clearTimeout(touchstarting);
35649       if (!g.touch1) {
35650         g.end();
35651         p = select(this).on("dblclick.zoom");
35652         if (p) p.apply(this, arguments);
35653         return;
35654       }
35655     }
35656
35657     if (started) {
35658       touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay);
35659       interrupt(this);
35660       g.start();
35661     }
35662   }
35663
35664   function touchmoved() {
35665     var g = gesture(this, arguments),
35666         touches$$1 = event.changedTouches,
35667         n = touches$$1.length, i, t, p, l;
35668
35669     noevent$2();
35670     if (touchstarting) touchstarting = clearTimeout(touchstarting);
35671     for (i = 0; i < n; ++i) {
35672       t = touches$$1[i], p = touch(this, touches$$1, t.identifier);
35673       if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;
35674       else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;
35675     }
35676     t = g.that.__zoom;
35677     if (g.touch1) {
35678       var p0 = g.touch0[0], l0 = g.touch0[1],
35679           p1 = g.touch1[0], l1 = g.touch1[1],
35680           dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
35681           dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
35682       t = scale(t, Math.sqrt(dp / dl));
35683       p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
35684       l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
35685     }
35686     else if (g.touch0) p = g.touch0[0], l = g.touch0[1];
35687     else return;
35688     g.zoom("touch", constrain(translate(t, p, l), g.extent));
35689   }
35690
35691   function touchended() {
35692     var g = gesture(this, arguments),
35693         touches$$1 = event.changedTouches,
35694         n = touches$$1.length, i, t;
35695
35696     nopropagation$2();
35697     if (touchending) clearTimeout(touchending);
35698     touchending = setTimeout(function() { touchending = null; }, touchDelay);
35699     for (i = 0; i < n; ++i) {
35700       t = touches$$1[i];
35701       if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;
35702       else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
35703     }
35704     if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
35705     if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);
35706     else g.end();
35707   }
35708
35709   zoom.filter = function(_) {
35710     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$12(!!_), zoom) : filter;
35711   };
35712
35713   zoom.extent = function(_) {
35714     return arguments.length ? (extent = typeof _ === "function" ? _ : constant$12([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
35715   };
35716
35717   zoom.scaleExtent = function(_) {
35718     return arguments.length ? (k0 = +_[0], k1 = +_[1], zoom) : [k0, k1];
35719   };
35720
35721   zoom.translateExtent = function(_) {
35722     return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], zoom) : [[x0, y0], [x1, y1]];
35723   };
35724
35725   zoom.duration = function(_) {
35726     return arguments.length ? (duration = +_, zoom) : duration;
35727   };
35728
35729   zoom.interpolate = function(_) {
35730     return arguments.length ? (interpolate = _, zoom) : interpolate;
35731   };
35732
35733   zoom.on = function() {
35734     var value = listeners.on.apply(listeners, arguments);
35735     return value === listeners ? zoom : value;
35736   };
35737
35738   zoom.clickDistance = function(_) {
35739     return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
35740   };
35741     
35742   return zoom;
35743 };
35744
35745
35746
35747 var index$2 = Object.freeze({
35748         version: version,
35749         bisect: bisectRight,
35750         bisectRight: bisectRight,
35751         bisectLeft: bisectLeft,
35752         ascending: ascending,
35753         bisector: bisector,
35754         cross: cross,
35755         descending: descending,
35756         deviation: deviation,
35757         extent: extent,
35758         histogram: histogram,
35759         thresholdFreedmanDiaconis: freedmanDiaconis,
35760         thresholdScott: scott,
35761         thresholdSturges: sturges,
35762         max: max,
35763         mean: mean,
35764         median: median,
35765         merge: merge,
35766         min: min,
35767         pairs: pairs,
35768         permute: permute,
35769         quantile: threshold,
35770         range: sequence,
35771         scan: scan,
35772         shuffle: shuffle,
35773         sum: sum,
35774         ticks: ticks,
35775         tickIncrement: tickIncrement,
35776         tickStep: tickStep,
35777         transpose: transpose,
35778         variance: variance,
35779         zip: zip,
35780         axisTop: axisTop,
35781         axisRight: axisRight,
35782         axisBottom: axisBottom,
35783         axisLeft: axisLeft,
35784         brush: brush,
35785         brushX: brushX,
35786         brushY: brushY,
35787         brushSelection: brushSelection,
35788         chord: chord,
35789         ribbon: ribbon,
35790         nest: nest,
35791         set: set$2,
35792         map: map$1,
35793         keys: keys,
35794         values: values,
35795         entries: entries,
35796         color: color,
35797         rgb: rgb,
35798         hsl: hsl,
35799         lab: lab,
35800         hcl: hcl,
35801         cubehelix: cubehelix,
35802         dispatch: dispatch,
35803         drag: drag,
35804         dragDisable: dragDisable,
35805         dragEnable: yesdrag,
35806         dsvFormat: dsv,
35807         csvParse: csvParse,
35808         csvParseRows: csvParseRows,
35809         csvFormat: csvFormat,
35810         csvFormatRows: csvFormatRows,
35811         tsvParse: tsvParse,
35812         tsvParseRows: tsvParseRows,
35813         tsvFormat: tsvFormat,
35814         tsvFormatRows: tsvFormatRows,
35815         easeLinear: linear$1,
35816         easeQuad: quadInOut,
35817         easeQuadIn: quadIn,
35818         easeQuadOut: quadOut,
35819         easeQuadInOut: quadInOut,
35820         easeCubic: cubicInOut,
35821         easeCubicIn: cubicIn,
35822         easeCubicOut: cubicOut,
35823         easeCubicInOut: cubicInOut,
35824         easePoly: polyInOut,
35825         easePolyIn: polyIn,
35826         easePolyOut: polyOut,
35827         easePolyInOut: polyInOut,
35828         easeSin: sinInOut,
35829         easeSinIn: sinIn,
35830         easeSinOut: sinOut,
35831         easeSinInOut: sinInOut,
35832         easeExp: expInOut,
35833         easeExpIn: expIn,
35834         easeExpOut: expOut,
35835         easeExpInOut: expInOut,
35836         easeCircle: circleInOut,
35837         easeCircleIn: circleIn,
35838         easeCircleOut: circleOut,
35839         easeCircleInOut: circleInOut,
35840         easeBounce: bounceOut,
35841         easeBounceIn: bounceIn,
35842         easeBounceOut: bounceOut,
35843         easeBounceInOut: bounceInOut,
35844         easeBack: backInOut,
35845         easeBackIn: backIn,
35846         easeBackOut: backOut,
35847         easeBackInOut: backInOut,
35848         easeElastic: elasticOut,
35849         easeElasticIn: elasticIn,
35850         easeElasticOut: elasticOut,
35851         easeElasticInOut: elasticInOut,
35852         forceCenter: center$1,
35853         forceCollide: collide,
35854         forceLink: link,
35855         forceManyBody: manyBody,
35856         forceSimulation: simulation,
35857         forceX: x$2,
35858         forceY: y$2,
35859         formatDefaultLocale: defaultLocale,
35860         get format () { return format; },
35861         get formatPrefix () { return formatPrefix; },
35862         formatLocale: formatLocale,
35863         formatSpecifier: formatSpecifier,
35864         precisionFixed: precisionFixed,
35865         precisionPrefix: precisionPrefix,
35866         precisionRound: precisionRound,
35867         geoArea: area,
35868         geoBounds: bounds,
35869         geoCentroid: d3GeoCentroid,
35870         geoCircle: circle,
35871         geoClipExtent: extent$1,
35872         geoContains: contains,
35873         geoDistance: distance,
35874         geoGraticule: graticule,
35875         geoGraticule10: graticule10,
35876         geoInterpolate: interpolate$1,
35877         geoLength: d3GeoLength,
35878         geoPath: index$4,
35879         geoAlbers: albers,
35880         geoAlbersUsa: albersUsa,
35881         geoAzimuthalEqualArea: azimuthalEqualArea,
35882         geoAzimuthalEqualAreaRaw: azimuthalEqualAreaRaw,
35883         geoAzimuthalEquidistant: azimuthalEquidistant,
35884         geoAzimuthalEquidistantRaw: azimuthalEquidistantRaw,
35885         geoConicConformal: conicConformal,
35886         geoConicConformalRaw: conicConformalRaw,
35887         geoConicEqualArea: conicEqualArea,
35888         geoConicEqualAreaRaw: conicEqualAreaRaw,
35889         geoConicEquidistant: conicEquidistant,
35890         geoConicEquidistantRaw: conicEquidistantRaw,
35891         geoEquirectangular: equirectangular,
35892         geoEquirectangularRaw: equirectangularRaw,
35893         geoGnomonic: gnomonic,
35894         geoGnomonicRaw: gnomonicRaw,
35895         geoIdentity: identity$5,
35896         geoProjection: projection,
35897         geoProjectionMutator: projectionMutator,
35898         geoMercator: mercator,
35899         geoMercatorRaw: mercatorRaw,
35900         geoOrthographic: orthographic,
35901         geoOrthographicRaw: orthographicRaw,
35902         geoStereographic: stereographic,
35903         geoStereographicRaw: stereographicRaw,
35904         geoTransverseMercator: transverseMercator,
35905         geoTransverseMercatorRaw: transverseMercatorRaw,
35906         geoRotation: rotation,
35907         geoStream: geoStream,
35908         geoTransform: transform,
35909         cluster: cluster,
35910         hierarchy: hierarchy,
35911         pack: index$5,
35912         packSiblings: siblings,
35913         packEnclose: enclose,
35914         partition: partition,
35915         stratify: stratify,
35916         tree: tree,
35917         treemap: index$6,
35918         treemapBinary: binary,
35919         treemapDice: treemapDice,
35920         treemapSlice: treemapSlice,
35921         treemapSliceDice: sliceDice,
35922         treemapSquarify: squarify,
35923         treemapResquarify: resquarify,
35924         interpolate: interpolateValue,
35925         interpolateArray: array$1,
35926         interpolateBasis: basis$1,
35927         interpolateBasisClosed: basisClosed,
35928         interpolateDate: date,
35929         interpolateNumber: reinterpolate,
35930         interpolateObject: object,
35931         interpolateRound: interpolateRound,
35932         interpolateString: interpolateString,
35933         interpolateTransformCss: interpolateTransformCss,
35934         interpolateTransformSvg: interpolateTransformSvg,
35935         interpolateZoom: interpolateZoom,
35936         interpolateRgb: interpolateRgb,
35937         interpolateRgbBasis: rgbBasis,
35938         interpolateRgbBasisClosed: rgbBasisClosed,
35939         interpolateHsl: hsl$2,
35940         interpolateHslLong: hslLong,
35941         interpolateLab: lab$1,
35942         interpolateHcl: hcl$2,
35943         interpolateHclLong: hclLong,
35944         interpolateCubehelix: cubehelix$2,
35945         interpolateCubehelixLong: cubehelixLong,
35946         quantize: quantize,
35947         path: path,
35948         polygonArea: d3polygonArea,
35949         polygonCentroid: d3polygonCentroid,
35950         polygonHull: d3polygonHull,
35951         polygonContains: contains$1,
35952         polygonLength: length$1,
35953         quadtree: quadtree,
35954         queue: queue,
35955         randomUniform: uniform,
35956         randomNormal: normal,
35957         randomLogNormal: logNormal,
35958         randomBates: bates,
35959         randomIrwinHall: irwinHall,
35960         randomExponential: exponential$1,
35961         request: request,
35962         html: html,
35963         json: json,
35964         text: text,
35965         xml: xml,
35966         csv: csv$1,
35967         tsv: tsv$1,
35968         scaleBand: band,
35969         scalePoint: point$1,
35970         scaleIdentity: identity$6,
35971         scaleLinear: linear$2,
35972         scaleLog: log$1,
35973         scaleOrdinal: ordinal,
35974         scaleImplicit: implicit,
35975         scalePow: pow$1,
35976         scaleSqrt: sqrt$1,
35977         scaleQuantile: quantile,
35978         scaleQuantize: quantize$1,
35979         scaleThreshold: threshold$1,
35980         scaleTime: time,
35981         scaleUtc: utcTime,
35982         schemeCategory10: category10,
35983         schemeCategory20b: category20b,
35984         schemeCategory20c: category20c,
35985         schemeCategory20: category20,
35986         interpolateCubehelixDefault: cubehelix$3,
35987         interpolateRainbow: rainbow$1,
35988         interpolateWarm: warm,
35989         interpolateCool: cool,
35990         interpolateViridis: viridis,
35991         interpolateMagma: magma,
35992         interpolateInferno: inferno,
35993         interpolatePlasma: plasma,
35994         scaleSequential: sequential,
35995         creator: creator,
35996         local: local$1,
35997         matcher: matcher$1,
35998         mouse: mouse,
35999         namespace: namespace,
36000         namespaces: namespaces,
36001         select: select,
36002         selectAll: selectAll,
36003         selection: selection,
36004         selector: selector,
36005         selectorAll: selectorAll,
36006         style: styleValue,
36007         touch: touch,
36008         touches: touches,
36009         window: defaultView,
36010         get event () { return event; },
36011         customEvent: customEvent,
36012         arc: arc,
36013         area: area$1,
36014         line: line,
36015         pie: pie,
36016         radialArea: radialArea,
36017         radialLine: radialLine$1,
36018         linkHorizontal: linkHorizontal,
36019         linkVertical: linkVertical,
36020         linkRadial: linkRadial,
36021         symbol: symbol,
36022         symbols: symbols,
36023         symbolCircle: circle$2,
36024         symbolCross: cross$2,
36025         symbolDiamond: diamond,
36026         symbolSquare: square,
36027         symbolStar: star,
36028         symbolTriangle: triangle,
36029         symbolWye: wye,
36030         curveBasisClosed: basisClosed$1,
36031         curveBasisOpen: basisOpen,
36032         curveBasis: basis$2,
36033         curveBundle: bundle,
36034         curveCardinalClosed: cardinalClosed,
36035         curveCardinalOpen: cardinalOpen,
36036         curveCardinal: cardinal,
36037         curveCatmullRomClosed: catmullRomClosed,
36038         curveCatmullRomOpen: catmullRomOpen,
36039         curveCatmullRom: catmullRom,
36040         curveLinearClosed: linearClosed,
36041         curveLinear: curveLinear,
36042         curveMonotoneX: monotoneX,
36043         curveMonotoneY: monotoneY,
36044         curveNatural: natural,
36045         curveStep: step,
36046         curveStepAfter: stepAfter,
36047         curveStepBefore: stepBefore,
36048         stack: stack,
36049         stackOffsetExpand: expand,
36050         stackOffsetDiverging: diverging,
36051         stackOffsetNone: none$1,
36052         stackOffsetSilhouette: silhouette,
36053         stackOffsetWiggle: wiggle,
36054         stackOrderAscending: ascending$2,
36055         stackOrderDescending: descending$2,
36056         stackOrderInsideOut: insideOut,
36057         stackOrderNone: none$2,
36058         stackOrderReverse: reverse,
36059         timeInterval: newInterval,
36060         timeMillisecond: millisecond,
36061         timeMilliseconds: milliseconds,
36062         utcMillisecond: millisecond,
36063         utcMilliseconds: milliseconds,
36064         timeSecond: second,
36065         timeSeconds: seconds,
36066         utcSecond: second,
36067         utcSeconds: seconds,
36068         timeMinute: minute,
36069         timeMinutes: minutes,
36070         timeHour: hour,
36071         timeHours: hours,
36072         timeDay: day,
36073         timeDays: days,
36074         timeWeek: sunday,
36075         timeWeeks: sundays,
36076         timeSunday: sunday,
36077         timeSundays: sundays,
36078         timeMonday: monday,
36079         timeMondays: mondays,
36080         timeTuesday: tuesday,
36081         timeTuesdays: tuesdays,
36082         timeWednesday: wednesday,
36083         timeWednesdays: wednesdays,
36084         timeThursday: thursday,
36085         timeThursdays: thursdays,
36086         timeFriday: friday,
36087         timeFridays: fridays,
36088         timeSaturday: saturday,
36089         timeSaturdays: saturdays,
36090         timeMonth: month,
36091         timeMonths: months,
36092         timeYear: year,
36093         timeYears: years,
36094         utcMinute: utcMinute,
36095         utcMinutes: utcMinutes,
36096         utcHour: utcHour,
36097         utcHours: utcHours,
36098         utcDay: utcDay,
36099         utcDays: utcDays,
36100         utcWeek: utcSunday,
36101         utcWeeks: utcSundays,
36102         utcSunday: utcSunday,
36103         utcSundays: utcSundays,
36104         utcMonday: utcMonday,
36105         utcMondays: utcMondays,
36106         utcTuesday: utcTuesday,
36107         utcTuesdays: utcTuesdays,
36108         utcWednesday: utcWednesday,
36109         utcWednesdays: utcWednesdays,
36110         utcThursday: utcThursday,
36111         utcThursdays: utcThursdays,
36112         utcFriday: utcFriday,
36113         utcFridays: utcFridays,
36114         utcSaturday: utcSaturday,
36115         utcSaturdays: utcSaturdays,
36116         utcMonth: utcMonth,
36117         utcMonths: utcMonths,
36118         utcYear: utcYear,
36119         utcYears: utcYears,
36120         timeFormatDefaultLocale: defaultLocale$1,
36121         get timeFormat () { return timeFormat; },
36122         get timeParse () { return timeParse; },
36123         get utcFormat () { return utcFormat; },
36124         get utcParse () { return utcParse; },
36125         timeFormatLocale: formatLocale$1,
36126         isoFormat: formatIso,
36127         isoParse: parseIso,
36128         now: now,
36129         timer: timer,
36130         timerFlush: timerFlush,
36131         timeout: timeout$1,
36132         interval: interval$1,
36133         transition: transition,
36134         active: active,
36135         interrupt: interrupt,
36136         voronoi: voronoi,
36137         zoom: zoom,
36138         zoomTransform: transform$1,
36139         zoomIdentity: identity$8
36140 });
36141
36142 /*
36143     Bypasses features of D3's default projection stream pipeline that are unnecessary:
36144     * Antimeridian clipping
36145     * Spherical rotation
36146     * Resampling
36147 */
36148 function geoRawMercator() {
36149     var project = mercatorRaw,
36150         k = 512 / Math.PI, // scale
36151         x = 0, y = 0, // translate
36152         clipExtent = [[0, 0], [0, 0]];
36153
36154
36155     function projection$$1(point) {
36156         point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
36157         return [point[0] * k + x, y - point[1] * k];
36158     }
36159
36160
36161     projection$$1.invert = function(point) {
36162         point = project.invert((point[0] - x) / k, (y - point[1]) / k);
36163         return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
36164     };
36165
36166
36167     projection$$1.scale = function(_) {
36168         if (!arguments.length) return k;
36169         k = +_;
36170         return projection$$1;
36171     };
36172
36173
36174     projection$$1.translate = function(_) {
36175         if (!arguments.length) return [x, y];
36176         x = +_[0];
36177         y = +_[1];
36178         return projection$$1;
36179     };
36180
36181
36182     projection$$1.clipExtent = function(_) {
36183         if (!arguments.length) return clipExtent;
36184         clipExtent = _;
36185         return projection$$1;
36186     };
36187
36188
36189     projection$$1.transform = function(_) {
36190         if (!arguments.length) return identity$8.translate(x, y).scale(k);
36191         x = +_.x;
36192         y = +_.y;
36193         k = +_.k;
36194         return projection$$1;
36195     };
36196
36197
36198     projection$$1.stream = transform({
36199         point: function(x, y) {
36200             x = projection$$1([x, y]);
36201             this.stream.point(x[0], x[1]);
36202         }
36203     }).stream;
36204
36205
36206     return projection$$1;
36207 }
36208
36209 function osmChangeset() {
36210     if (!(this instanceof osmChangeset)) {
36211         return (new osmChangeset()).initialize(arguments);
36212     } else if (arguments.length) {
36213         this.initialize(arguments);
36214     }
36215 }
36216
36217
36218 osmEntity$$1.changeset = osmChangeset;
36219
36220 osmChangeset.prototype = Object.create(osmEntity$$1.prototype);
36221
36222 lodash.extend(osmChangeset.prototype, {
36223
36224     type: 'changeset',
36225
36226
36227     extent: function() {
36228         return new geoExtent$$1();
36229     },
36230
36231
36232     geometry: function() {
36233         return 'changeset';
36234     },
36235
36236
36237     asJXON: function() {
36238         return {
36239             osm: {
36240                 changeset: {
36241                     tag: lodash.map(this.tags, function(value, key) {
36242                         return { '@k': key, '@v': value };
36243                     }),
36244                     '@version': 0.6,
36245                     '@generator': 'iD'
36246                 }
36247             }
36248         };
36249     },
36250
36251
36252     // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
36253     // XML. Returns a string.
36254     osmChangeJXON: function(changes) {
36255         var changeset_id = this.id;
36256
36257         function nest(x, order) {
36258             var groups = {};
36259             for (var i = 0; i < x.length; i++) {
36260                 var tagName = Object.keys(x[i])[0];
36261                 if (!groups[tagName]) groups[tagName] = [];
36262                 groups[tagName].push(x[i][tagName]);
36263             }
36264             var ordered = {};
36265             order.forEach(function(o) {
36266                 if (groups[o]) ordered[o] = groups[o];
36267             });
36268             return ordered;
36269         }
36270
36271
36272         // sort relations in a changeset by dependencies
36273         function sort(changes) {
36274
36275             // find a referenced relation in the current changeset
36276             function resolve(item) {
36277                 return lodash.find(relations, function(relation) {
36278                     return item.keyAttributes.type === 'relation'
36279                         && item.keyAttributes.ref === relation['@id'];
36280                 });
36281             }
36282
36283             // a new item is an item that has not been already processed
36284             function isNew(item) {
36285                 return !sorted[ item['@id'] ] && !lodash.find(processing, function(proc) {
36286                     return proc['@id'] === item['@id'];
36287                 });
36288             }
36289
36290             var processing = [],
36291                 sorted = {},
36292                 relations = changes.relation;
36293
36294             if (!relations) return changes;
36295
36296             for (var i = 0; i < relations.length; i++) {
36297                 var relation = relations[i];
36298
36299                 // skip relation if already sorted
36300                 if (!sorted[relation['@id']]) {
36301                     processing.push(relation);
36302                 }
36303
36304                 while (processing.length > 0) {
36305                     var next = processing[0],
36306                     deps = lodash.filter(lodash.compact(next.member.map(resolve)), isNew);
36307                     if (deps.length === 0) {
36308                         sorted[next['@id']] = next;
36309                         processing.shift();
36310                     } else {
36311                         processing = deps.concat(processing);
36312                     }
36313                 }
36314             }
36315
36316             changes.relation = lodash.values(sorted);
36317             return changes;
36318         }
36319
36320         function rep(entity) {
36321             return entity.asJXON(changeset_id);
36322         }
36323
36324         return {
36325             osmChange: {
36326                 '@version': 0.6,
36327                 '@generator': 'iD',
36328                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
36329                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
36330                 'delete': lodash.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), { '@if-unused': true })
36331             }
36332         };
36333     },
36334
36335
36336     asGeoJSON: function() {
36337         return {};
36338     }
36339
36340 });
36341
36342 function osmNode() {
36343     if (!(this instanceof osmNode)) {
36344         return (new osmNode()).initialize(arguments);
36345     } else if (arguments.length) {
36346         this.initialize(arguments);
36347     }
36348 }
36349
36350 osmEntity$$1.node = osmNode;
36351
36352 osmNode.prototype = Object.create(osmEntity$$1.prototype);
36353
36354 lodash.extend(osmNode.prototype, {
36355
36356     type: 'node',
36357
36358
36359     extent: function() {
36360         return new geoExtent$$1(this.loc);
36361     },
36362
36363
36364     geometry: function(graph) {
36365         return graph.transient(this, 'geometry', function() {
36366             return graph.isPoi(this) ? 'point' : 'vertex';
36367         });
36368     },
36369
36370
36371     move: function(loc) {
36372         return this.update({loc: loc});
36373     },
36374
36375
36376     isDegenerate: function() {
36377         return !(
36378             Array.isArray(this.loc) && this.loc.length === 2 &&
36379             this.loc[0] >= -180 && this.loc[0] <= 180 &&
36380             this.loc[1] >= -90 && this.loc[1] <= 90
36381         );
36382     },
36383
36384
36385     isEndpoint: function(resolver) {
36386         return resolver.transient(this, 'isEndpoint', function() {
36387             var id = this.id;
36388             return resolver.parentWays(this).filter(function(parent) {
36389                 return !parent.isClosed() && !!parent.affix(id);
36390             }).length > 0;
36391         });
36392     },
36393
36394
36395     isConnected: function(resolver) {
36396         return resolver.transient(this, 'isConnected', function() {
36397             var parents = resolver.parentWays(this);
36398
36399             function isLine(entity) {
36400                 return entity.geometry(resolver) === 'line' &&
36401                     entity.hasInterestingTags();
36402             }
36403
36404             // vertex is connected to multiple parent lines
36405             if (parents.length > 1 && lodash.some(parents, isLine)) {
36406                 return true;
36407
36408             } else if (parents.length === 1) {
36409                 var way = parents[0],
36410                     nodes = way.nodes.slice();
36411                 if (way.isClosed()) { nodes.pop(); }  // ignore connecting node if closed
36412
36413                 // return true if vertex appears multiple times (way is self intersecting)
36414                 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
36415             }
36416
36417             return false;
36418         });
36419     },
36420
36421
36422     isIntersection: function(resolver) {
36423         return resolver.transient(this, 'isIntersection', function() {
36424             return resolver.parentWays(this).filter(function(parent) {
36425                 return (parent.tags.highway ||
36426                     parent.tags.waterway ||
36427                     parent.tags.railway ||
36428                     parent.tags.aeroway) &&
36429                     parent.geometry(resolver) === 'line';
36430             }).length > 1;
36431         });
36432     },
36433
36434
36435     isHighwayIntersection: function(resolver) {
36436         return resolver.transient(this, 'isHighwayIntersection', function() {
36437             return resolver.parentWays(this).filter(function(parent) {
36438                 return parent.tags.highway && parent.geometry(resolver) === 'line';
36439             }).length > 1;
36440         });
36441     },
36442
36443
36444     isOnAddressLine: function(resolver) {
36445         return resolver.transient(this, 'isOnAddressLine', function() {
36446             return resolver.parentWays(this).filter(function(parent) {
36447                 return parent.tags.hasOwnProperty('addr:interpolation') &&
36448                     parent.geometry(resolver) === 'line';
36449             }).length > 0;
36450         });
36451     },
36452
36453
36454     asJXON: function(changeset_id) {
36455         var r = {
36456             node: {
36457                 '@id': this.osmId(),
36458                 '@lon': this.loc[0],
36459                 '@lat': this.loc[1],
36460                 '@version': (this.version || 0),
36461                 tag: lodash.map(this.tags, function(v, k) {
36462                     return { keyAttributes: { k: k, v: v } };
36463                 })
36464             }
36465         };
36466         if (changeset_id) r.node['@changeset'] = changeset_id;
36467         return r;
36468     },
36469
36470
36471     asGeoJSON: function() {
36472         return {
36473             type: 'Point',
36474             coordinates: this.loc
36475         };
36476     }
36477 });
36478
36479 /*
36480   Order the nodes of a way in reverse order and reverse any direction dependent tags
36481   other than `oneway`. (We assume that correcting a backwards oneway is the primary
36482   reason for reversing a way.)
36483
36484   The following transforms are performed:
36485
36486     Keys:
36487           *:right=* ⟺ *:left=*
36488         *:forward=* ⟺ *:backward=*
36489        direction=up ⟺ direction=down
36490          incline=up ⟺ incline=down
36491             *=right ⟺ *=left
36492
36493     Relation members:
36494        role=forward ⟺ role=backward
36495          role=north ⟺ role=south
36496           role=east ⟺ role=west
36497
36498    In addition, numeric-valued `incline` tags are negated.
36499
36500    The JOSM implementation was used as a guide, but transformations that were of unclear benefit
36501    or adjusted tags that don't seem to be used in practice were omitted.
36502
36503    Also, each node on the way is examined for its own tags and the following transformations are performed
36504    in order to ensure associated nodes (eg a Stop Sign) is also reversed
36505
36506     Node Keys:
36507         direction=forward ⟺ direction=backward
36508         direction=left ⟺ direction=right
36509         *:forward=* ⟺ *:backward=*
36510         *:left=* ⟺ *:right=*
36511
36512    References:
36513       http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
36514       http://wiki.openstreetmap.org/wiki/Key:direction#Steps
36515       http://wiki.openstreetmap.org/wiki/Key:incline
36516       http://wiki.openstreetmap.org/wiki/Route#Members
36517       http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
36518       http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
36519       http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
36520  */
36521 function actionReverse(wayId, options) {
36522     var replacements = [
36523             [/:right$/, ':left'], [/:left$/, ':right'],
36524             [/:forward$/, ':backward'], [/:backward$/, ':forward']
36525         ],
36526         numeric = /^([+\-]?)(?=[\d.])/,
36527         roleReversals = {
36528             forward: 'backward',
36529             backward: 'forward',
36530             north: 'south',
36531             south: 'north',
36532             east: 'west',
36533             west: 'east'
36534         };
36535
36536
36537     function reverseKey(key) {
36538         for (var i = 0; i < replacements.length; ++i) {
36539             var replacement = replacements[i];
36540             if (replacement[0].test(key)) {
36541                 return key.replace(replacement[0], replacement[1]);
36542             }
36543         }
36544         return key;
36545     }
36546
36547
36548     function reverseValue(key, value) {
36549         if (key === 'incline' && numeric.test(value)) {
36550             return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
36551         } else if (key === 'incline' || key === 'direction') {
36552             return {up: 'down', down: 'up'}[value] || value;
36553         } else if (options && options.reverseOneway && key === 'oneway') {
36554             return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
36555         } else {
36556             return {left: 'right', right: 'left'}[value] || value;
36557         }
36558     }
36559
36560
36561     function reverseDirectionTags(node) {
36562         // Update the direction based tags as appropriate then return an updated node
36563         return node.update({tags: lodash.transform(node.tags, function(acc, tagValue, tagKey) {
36564             // See if this is a direction tag and reverse (or use existing value if not recognised)
36565             if (tagKey === 'direction') {
36566                 acc[tagKey] = {forward: 'backward', backward: 'forward', left: 'right', right: 'left'}[tagValue] || tagValue;
36567             } else {
36568                 // Use the reverseKey method to cater for situations such as traffic_sign:forward=stop
36569                 // This will pass through other tags unchanged
36570                 acc[reverseKey(tagKey)] = tagValue;
36571             }
36572             return acc;
36573         }, {})});
36574     }
36575
36576
36577     function reverseTagsOnNodes(graph, nodeIds) {
36578         // Reverse the direction of appropriate tags attached to the nodes (#3076)
36579         return lodash(nodeIds)
36580             // Get each node from the graph
36581             .map(function(nodeId) { return graph.entity(nodeId);})
36582             // Check tags on the node, if there aren't any, we can skip
36583             .filter(function(existingNode) { return existingNode.tags !== undefined;})
36584             // Get a new version of each node with the appropriate tags reversed
36585             .map(function(existingNode) { return reverseDirectionTags(existingNode);})
36586             // Chain together consecutive updates to the graph for each updated node and return
36587             .reduce(function (accGraph, value) { return accGraph.replace(value); }, graph);
36588     }
36589
36590
36591     return function(graph) {
36592         var way = graph.entity(wayId),
36593             nodes = way.nodes.slice().reverse(),
36594             tags = {}, key, role;
36595
36596         for (key in way.tags) {
36597             tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
36598         }
36599
36600         graph.parentRelations(way).forEach(function(relation) {
36601             relation.members.forEach(function(member, index) {
36602                 if (member.id === way.id && (role = roleReversals[member.role])) {
36603                     relation = relation.updateMember({role: role}, index);
36604                     graph = graph.replace(relation);
36605                 }
36606             });
36607         });
36608
36609         // Reverse any associated directions on nodes on the way and then replace
36610         // the way itself with the reversed node ids and updated way tags
36611         return reverseTagsOnNodes(graph, nodes).replace(way.update({nodes: nodes, tags: tags}));
36612     };
36613 }
36614
36615 // For fixing up rendering of multipolygons with tags on the outer member.
36616 // https://github.com/openstreetmap/iD/issues/613
36617 function osmIsSimpleMultipolygonOuterMember(entity, graph) {
36618     if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0)
36619         return false;
36620
36621     var parents = graph.parentRelations(entity);
36622     if (parents.length !== 1)
36623         return false;
36624
36625     var parent = parents[0];
36626     if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1)
36627         return false;
36628
36629     var members = parent.members, member;
36630     for (var i = 0; i < members.length; i++) {
36631         member = members[i];
36632         if (member.id === entity.id && member.role && member.role !== 'outer')
36633             return false; // Not outer member
36634         if (member.id !== entity.id && (!member.role || member.role === 'outer'))
36635             return false; // Not a simple multipolygon
36636     }
36637
36638     return parent;
36639 }
36640
36641
36642 function osmSimpleMultipolygonOuterMember(entity, graph) {
36643     if (entity.type !== 'way')
36644         return false;
36645
36646     var parents = graph.parentRelations(entity);
36647     if (parents.length !== 1)
36648         return false;
36649
36650     var parent = parents[0];
36651     if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1)
36652         return false;
36653
36654     var members = parent.members, member, outerMember;
36655     for (var i = 0; i < members.length; i++) {
36656         member = members[i];
36657         if (!member.role || member.role === 'outer') {
36658             if (outerMember)
36659                 return false; // Not a simple multipolygon
36660             outerMember = member;
36661         }
36662     }
36663
36664     if (!outerMember)
36665         return false;
36666
36667     var outerEntity = graph.hasEntity(outerMember.id);
36668     if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length)
36669         return false;
36670
36671     return outerEntity;
36672 }
36673
36674
36675 // Join `array` into sequences of connecting ways.
36676 //
36677 // Segments which share identical start/end nodes will, as much as possible,
36678 // be connected with each other.
36679 //
36680 // The return value is a nested array. Each constituent array contains elements
36681 // of `array` which have been determined to connect. Each consitituent array
36682 // also has a `nodes` property whose value is an ordered array of member nodes,
36683 // with appropriate order reversal and start/end coordinate de-duplication.
36684 //
36685 // Members of `array` must have, at minimum, `type` and `id` properties.
36686 // Thus either an array of `osmWay`s or a relation member array may be
36687 // used.
36688 //
36689 // If an member has a `tags` property, its tags will be reversed via
36690 // `actionReverse` in the output.
36691 //
36692 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
36693 // false) and non-way members are ignored.
36694 //
36695 function osmJoinWays(array, graph) {
36696     var joined = [], member, current, nodes, first, last, i, how, what;
36697
36698     array = array.filter(function(member) {
36699         return member.type === 'way' && graph.hasEntity(member.id);
36700     });
36701
36702     function resolve(member) {
36703         return graph.childNodes(graph.entity(member.id));
36704     }
36705
36706     function reverse(member) {
36707         return member.tags ? actionReverse(member.id, { reverseOneway: true })(graph).entity(member.id) : member;
36708     }
36709
36710     while (array.length) {
36711         member = array.shift();
36712         current = [member];
36713         current.nodes = nodes = resolve(member).slice();
36714         joined.push(current);
36715
36716         while (array.length && lodash.first(nodes) !== lodash.last(nodes)) {
36717             first = lodash.first(nodes);
36718             last  = lodash.last(nodes);
36719
36720             for (i = 0; i < array.length; i++) {
36721                 member = array[i];
36722                 what = resolve(member);
36723
36724                 if (last === lodash.first(what)) {
36725                     how  = nodes.push;
36726                     what = what.slice(1);
36727                     break;
36728                 } else if (last === lodash.last(what)) {
36729                     how  = nodes.push;
36730                     what = what.slice(0, -1).reverse();
36731                     member = reverse(member);
36732                     break;
36733                 } else if (first === lodash.last(what)) {
36734                     how  = nodes.unshift;
36735                     what = what.slice(0, -1);
36736                     break;
36737                 } else if (first === lodash.first(what)) {
36738                     how  = nodes.unshift;
36739                     what = what.slice(1).reverse();
36740                     member = reverse(member);
36741                     break;
36742                 } else {
36743                     what = how = null;
36744                 }
36745             }
36746
36747             if (!what)
36748                 break; // No more joinable ways.
36749
36750             how.apply(current, [member]);
36751             how.apply(nodes, what);
36752
36753             array.splice(i, 1);
36754         }
36755     }
36756
36757     return joined;
36758 }
36759
36760 function osmRelation() {
36761     if (!(this instanceof osmRelation)) {
36762         return (new osmRelation()).initialize(arguments);
36763     } else if (arguments.length) {
36764         this.initialize(arguments);
36765     }
36766 }
36767
36768
36769 osmEntity$$1.relation = osmRelation;
36770
36771 osmRelation.prototype = Object.create(osmEntity$$1.prototype);
36772
36773
36774 osmRelation.creationOrder = function(a, b) {
36775     var aId = parseInt(osmEntity$$1.id.toOSM(a.id), 10);
36776     var bId = parseInt(osmEntity$$1.id.toOSM(b.id), 10);
36777
36778     if (aId < 0 || bId < 0) return aId - bId;
36779     return bId - aId;
36780 };
36781
36782
36783 lodash.extend(osmRelation.prototype, {
36784     type: 'relation',
36785     members: [],
36786
36787
36788     copy: function(resolver, copies) {
36789         if (copies[this.id])
36790             return copies[this.id];
36791
36792         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
36793
36794         var members = this.members.map(function(member) {
36795             return lodash.extend({}, member, { id: resolver.entity(member.id).copy(resolver, copies).id });
36796         });
36797
36798         copy = copy.update({members: members});
36799         copies[this.id] = copy;
36800
36801         return copy;
36802     },
36803
36804
36805     extent: function(resolver, memo) {
36806         return resolver.transient(this, 'extent', function() {
36807             if (memo && memo[this.id]) return geoExtent$$1();
36808             memo = memo || {};
36809             memo[this.id] = true;
36810
36811             var extent$$1 = geoExtent$$1();
36812             for (var i = 0; i < this.members.length; i++) {
36813                 var member = resolver.hasEntity(this.members[i].id);
36814                 if (member) {
36815                     extent$$1._extend(member.extent(resolver, memo));
36816                 }
36817             }
36818             return extent$$1;
36819         });
36820     },
36821
36822
36823     geometry: function(graph) {
36824         return graph.transient(this, 'geometry', function() {
36825             return this.isMultipolygon() ? 'area' : 'relation';
36826         });
36827     },
36828
36829
36830     isDegenerate: function() {
36831         return this.members.length === 0;
36832     },
36833
36834
36835     // Return an array of members, each extended with an 'index' property whose value
36836     // is the member index.
36837     indexedMembers: function() {
36838         var result = new Array(this.members.length);
36839         for (var i = 0; i < this.members.length; i++) {
36840             result[i] = lodash.extend({}, this.members[i], {index: i});
36841         }
36842         return result;
36843     },
36844
36845
36846     // Return the first member with the given role. A copy of the member object
36847     // is returned, extended with an 'index' property whose value is the member index.
36848     memberByRole: function(role) {
36849         for (var i = 0; i < this.members.length; i++) {
36850             if (this.members[i].role === role) {
36851                 return lodash.extend({}, this.members[i], {index: i});
36852             }
36853         }
36854     },
36855
36856
36857     // Return the first member with the given id. A copy of the member object
36858     // is returned, extended with an 'index' property whose value is the member index.
36859     memberById: function(id) {
36860         for (var i = 0; i < this.members.length; i++) {
36861             if (this.members[i].id === id) {
36862                 return lodash.extend({}, this.members[i], {index: i});
36863             }
36864         }
36865     },
36866
36867
36868     // Return the first member with the given id and role. A copy of the member object
36869     // is returned, extended with an 'index' property whose value is the member index.
36870     memberByIdAndRole: function(id, role) {
36871         for (var i = 0; i < this.members.length; i++) {
36872             if (this.members[i].id === id && this.members[i].role === role) {
36873                 return lodash.extend({}, this.members[i], {index: i});
36874             }
36875         }
36876     },
36877
36878
36879     addMember: function(member, index) {
36880         var members = this.members.slice();
36881         members.splice(index === undefined ? members.length : index, 0, member);
36882         return this.update({members: members});
36883     },
36884
36885
36886     updateMember: function(member, index) {
36887         var members = this.members.slice();
36888         members.splice(index, 1, lodash.extend({}, members[index], member));
36889         return this.update({members: members});
36890     },
36891
36892
36893     removeMember: function(index) {
36894         var members = this.members.slice();
36895         members.splice(index, 1);
36896         return this.update({members: members});
36897     },
36898
36899
36900     removeMembersWithID: function(id) {
36901         var members = lodash.reject(this.members, function(m) { return m.id === id; });
36902         return this.update({members: members});
36903     },
36904
36905
36906     // Wherever a member appears with id `needle.id`, replace it with a member
36907     // with id `replacement.id`, type `replacement.type`, and the original role,
36908     // unless a member already exists with that id and role. Return an updated
36909     // relation.
36910     replaceMember: function(needle, replacement) {
36911         if (!this.memberById(needle.id))
36912             return this;
36913
36914         var members = [];
36915
36916         for (var i = 0; i < this.members.length; i++) {
36917             var member = this.members[i];
36918             if (member.id !== needle.id) {
36919                 members.push(member);
36920             } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
36921                 members.push({id: replacement.id, type: replacement.type, role: member.role});
36922             }
36923         }
36924
36925         return this.update({members: members});
36926     },
36927
36928
36929     asJXON: function(changeset_id) {
36930         var r = {
36931             relation: {
36932                 '@id': this.osmId(),
36933                 '@version': this.version || 0,
36934                 member: lodash.map(this.members, function(member) {
36935                     return {
36936                         keyAttributes: {
36937                             type: member.type,
36938                             role: member.role,
36939                             ref: osmEntity$$1.id.toOSM(member.id)
36940                         }
36941                     };
36942                 }),
36943                 tag: lodash.map(this.tags, function(v, k) {
36944                     return { keyAttributes: { k: k, v: v } };
36945                 })
36946             }
36947         };
36948         if (changeset_id) r.relation['@changeset'] = changeset_id;
36949         return r;
36950     },
36951
36952
36953     asGeoJSON: function(resolver) {
36954         return resolver.transient(this, 'GeoJSON', function () {
36955             if (this.isMultipolygon()) {
36956                 return {
36957                     type: 'MultiPolygon',
36958                     coordinates: this.multipolygon(resolver)
36959                 };
36960             } else {
36961                 return {
36962                     type: 'FeatureCollection',
36963                     properties: this.tags,
36964                     features: this.members.map(function (member) {
36965                         return lodash.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
36966                     })
36967                 };
36968             }
36969         });
36970     },
36971
36972
36973     area: function(resolver) {
36974         return resolver.transient(this, 'area', function() {
36975             return area(this.asGeoJSON(resolver));
36976         });
36977     },
36978
36979
36980     isMultipolygon: function() {
36981         return this.tags.type === 'multipolygon';
36982     },
36983
36984
36985     isComplete: function(resolver) {
36986         for (var i = 0; i < this.members.length; i++) {
36987             if (!resolver.hasEntity(this.members[i].id)) {
36988                 return false;
36989             }
36990         }
36991         return true;
36992     },
36993
36994
36995     isRestriction: function() {
36996         return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
36997     },
36998
36999
37000     // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
37001     // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
37002     //
37003     // This corresponds to the structure needed for rendering a multipolygon path using a
37004     // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
37005     //
37006     // In the case of invalid geometries, this function will still return a result which
37007     // includes the nodes of all way members, but some Nds may be unclosed and some inner
37008     // rings not matched with the intended outer ring.
37009     //
37010     multipolygon: function(resolver) {
37011         var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
37012             inners = this.members.filter(function(m) { return 'inner' === m.role; });
37013
37014         outers = osmJoinWays(outers, resolver);
37015         inners = osmJoinWays(inners, resolver);
37016
37017         outers = outers.map(function(outer) { return lodash.map(outer.nodes, 'loc'); });
37018         inners = inners.map(function(inner) { return lodash.map(inner.nodes, 'loc'); });
37019
37020         var result = outers.map(function(o) {
37021             // Heuristic for detecting counterclockwise winding order. Assumes
37022             // that OpenStreetMap polygons are not hemisphere-spanning.
37023             return [area({ type: 'Polygon', coordinates: [o] }) > 2 * Math.PI ? o.reverse() : o];
37024         });
37025
37026         function findOuter(inner) {
37027             var o, outer;
37028
37029             for (o = 0; o < outers.length; o++) {
37030                 outer = outers[o];
37031                 if (geoPolygonContainsPolygon(outer, inner))
37032                     return o;
37033             }
37034
37035             for (o = 0; o < outers.length; o++) {
37036                 outer = outers[o];
37037                 if (geoPolygonIntersectsPolygon(outer, inner, false))
37038                     return o;
37039             }
37040         }
37041
37042         for (var i = 0; i < inners.length; i++) {
37043             var inner = inners[i];
37044
37045             if (area({ type: 'Polygon', coordinates: [inner] }) < 2 * Math.PI) {
37046                 inner = inner.reverse();
37047             }
37048
37049             var o = findOuter(inners[i]);
37050             if (o !== undefined)
37051                 result[o].push(inners[i]);
37052             else
37053                 result.push([inners[i]]); // Invalid geometry
37054         }
37055
37056         return result;
37057     }
37058 });
37059
37060 function osmLanes(entity) {
37061     if (entity.type !== 'way') return null;
37062     if (!entity.tags.highway) return null;
37063
37064     var tags = entity.tags;
37065     var isOneWay = entity.isOneWay();
37066     var laneCount = getLaneCount(tags, isOneWay);
37067     var maxspeed = parseMaxspeed(tags);
37068
37069     var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
37070     var forward = laneDirections.forward;
37071     var backward = laneDirections.backward;
37072     var bothways = laneDirections.bothways;
37073
37074     // parse the piped string 'x|y|z' format
37075     var turnLanes = {};
37076     turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
37077     turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
37078     turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
37079
37080     var maxspeedLanes = {};
37081     maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
37082     maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
37083     maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
37084
37085     var psvLanes = {};
37086     psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
37087     psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
37088     psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
37089
37090     var busLanes = {};
37091     busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
37092     busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
37093     busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
37094
37095     var taxiLanes = {};
37096     taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
37097     taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
37098     taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
37099
37100     var hovLanes = {};
37101     hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
37102     hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
37103     hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
37104
37105     var hgvLanes = {};
37106     hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
37107     hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
37108     hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
37109
37110     var bicyclewayLanes = {};
37111     bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
37112     bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
37113     bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
37114
37115     var lanesObj = {
37116         forward: [],
37117         backward: [],
37118         unspecified: []
37119     };
37120
37121     // map forward/backward/unspecified of each lane type to lanesObj
37122     mapToLanesObj(lanesObj, turnLanes, 'turnLane');
37123     mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
37124     mapToLanesObj(lanesObj, psvLanes, 'psv');
37125     mapToLanesObj(lanesObj, busLanes, 'bus');
37126     mapToLanesObj(lanesObj, taxiLanes, 'taxi');
37127     mapToLanesObj(lanesObj, hovLanes, 'hov');
37128     mapToLanesObj(lanesObj, hgvLanes, 'hgv');
37129     mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
37130
37131     return {
37132         metadata: {
37133             count: laneCount,
37134             oneway: isOneWay,
37135             forward: forward,
37136             backward: backward,
37137             bothways: bothways,
37138             turnLanes: turnLanes,
37139             maxspeed: maxspeed,
37140             maxspeedLanes: maxspeedLanes,
37141             psvLanes: psvLanes,
37142             busLanes: busLanes,
37143             taxiLanes: taxiLanes,
37144             hovLanes: hovLanes,
37145             hgvLanes: hgvLanes,
37146             bicyclewayLanes: bicyclewayLanes
37147         },
37148         lanes: lanesObj
37149     };
37150 }
37151
37152
37153 function getLaneCount(tags, isOneWay) {
37154     var count;
37155     if (tags.lanes) {
37156         count = parseInt(tags.lanes, 10);
37157         if (count > 0) {
37158             return count;
37159         }
37160     }
37161
37162
37163     switch (tags.highway) {
37164         case 'trunk':
37165         case 'motorway':
37166             count = isOneWay ? 2 : 4;
37167             break;
37168         default:
37169             count = isOneWay ? 1 : 2;
37170             break;
37171     }
37172
37173     return count;
37174 }
37175
37176
37177 function parseMaxspeed(tags) {
37178     var maxspeed = tags.maxspeed;
37179     if (lodash.isNumber(maxspeed)) return maxspeed;
37180     if (lodash.isString(maxspeed)) {
37181         maxspeed = maxspeed.match(/^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/g);
37182         if (!maxspeed) return;
37183         return parseInt(maxspeed, 10);
37184     }
37185 }
37186
37187
37188 function parseLaneDirections(tags, isOneWay, laneCount) {
37189     var forward = parseInt(tags['lanes:forward'], 10);
37190     var backward = parseInt(tags['lanes:backward'], 10);
37191     var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
37192
37193     if (parseInt(tags.oneway, 10) === -1) {
37194         forward = 0;
37195         bothways = 0;
37196         backward = laneCount;
37197     }
37198     else if (isOneWay) {
37199         forward = laneCount;
37200         bothways = 0;
37201         backward = 0;
37202     }
37203     else if (lodash.isNaN(forward) && lodash.isNaN(backward)) {
37204         backward = Math.floor((laneCount - bothways) / 2);
37205         forward = laneCount - bothways - backward;
37206     }
37207     else if (lodash.isNaN(forward)) {
37208         if (backward > laneCount - bothways) {
37209             backward = laneCount - bothways;
37210         }
37211         forward = laneCount - bothways - backward;
37212     }
37213     else if (lodash.isNaN(backward)) {
37214         if (forward > laneCount - bothways) {
37215             forward = laneCount - bothways;
37216         }
37217         backward = laneCount - bothways - forward;
37218     }
37219     return {
37220         forward: forward,
37221         backward: backward,
37222         bothways: bothways
37223     };
37224 }
37225
37226
37227 function parseTurnLanes(tag){
37228     if (!tag) return;
37229
37230     var validValues = [
37231         'left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right',
37232         'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'
37233     ];
37234
37235     return tag.split('|')
37236         .map(function (s) {
37237             if (s === '') s = 'none';
37238             return s.split(';')
37239                 .map(function (d) {
37240                     return validValues.indexOf(d) === -1 ? 'unknown': d;
37241                 });
37242         });
37243 }
37244
37245
37246 function parseMaxspeedLanes(tag, maxspeed) {
37247     if (!tag) return;
37248
37249     return tag.split('|')
37250         .map(function (s) {
37251             if (s === 'none') return s;
37252             var m = parseInt(s, 10);
37253             if (s === '' || m === maxspeed) return null;
37254             return lodash.isNaN(m) ? 'unknown': m;
37255         });
37256 }
37257
37258
37259 function parseMiscLanes(tag) {
37260     if (!tag) return;
37261
37262     var validValues = [
37263         'yes', 'no', 'designated'
37264     ];
37265
37266     return tag.split('|')
37267         .map(function (s) {
37268             if (s === '') s = 'no';
37269             return validValues.indexOf(s) === -1 ? 'unknown': s;
37270         });
37271 }
37272
37273
37274 function parseBicycleWay(tag) {
37275     if (!tag) return;
37276
37277     var validValues = [
37278         'yes', 'no', 'designated', 'lane'
37279     ];
37280
37281     return tag.split('|')
37282         .map(function (s) {
37283             if (s === '') s = 'no';
37284             return validValues.indexOf(s) === -1 ? 'unknown': s;
37285         });
37286 }
37287
37288
37289 function mapToLanesObj(lanesObj, data, key) {
37290     if (data.forward) data.forward.forEach(function(l, i) {
37291         if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
37292         lanesObj.forward[i][key] = l;
37293     });
37294     if (data.backward) data.backward.forEach(function(l, i) {
37295         if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
37296         lanesObj.backward[i][key] = l;
37297     });
37298     if (data.unspecified) data.unspecified.forEach(function(l, i) {
37299         if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
37300         lanesObj.unspecified[i][key] = l;
37301     });
37302 }
37303
37304 var translations = Object.create(null);
37305
37306 var currentLocale = 'en';
37307 var textDirection = 'ltr';
37308
37309 function setLocale(_) {
37310     if (translations[_] !== undefined) {
37311         currentLocale = _;
37312     } else if (translations[_.split('-')[0]]) {
37313         currentLocale = _.split('-')[0];
37314     }
37315 }
37316
37317 function addTranslation(id, value) {
37318     translations[id] = value;
37319 }
37320
37321 /**
37322  * Given a string identifier, try to find that string in the current
37323  * language, and return it.
37324  *
37325  * @param {string} s string identifier
37326  * @returns {string?} locale string
37327  */
37328 function t(s, o, loc) {
37329     loc = loc || currentLocale;
37330
37331     var path = s
37332         .split('.')
37333         .map(function(s) { return s.replace('<TX_DOT>', '.'); })
37334         .reverse();
37335
37336     var rep = translations[loc];
37337
37338     while (rep !== undefined && path.length) rep = rep[path.pop()];
37339
37340     if (rep !== undefined) {
37341         if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
37342         return rep;
37343     }
37344
37345     if (loc !== 'en') {
37346         return t(s, o, 'en');
37347     }
37348
37349     if (o && 'default' in o) {
37350         return o.default;
37351     }
37352
37353     var missing = 'Missing ' + loc + ' translation: ' + s;
37354     if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
37355
37356     return missing;
37357 }
37358
37359 /**
37360  * Given string 'ltr' or 'rtl', save that setting
37361  *
37362  * @param {string} s ltr or rtl
37363  */
37364
37365 function setTextDirection(dir) {
37366     textDirection = dir;
37367 }
37368
37369 var detected;
37370
37371 function utilDetect(force) {
37372     if (detected && !force) return detected;
37373     detected = {};
37374
37375     var ua = navigator.userAgent,
37376         m = null;
37377
37378     m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i);   // Edge
37379     if (m !== null) {
37380         detected.browser = m[1];
37381         detected.version = m[2];
37382     }
37383     if (!detected.browser) {
37384         m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i);   // IE11
37385         if (m !== null) {
37386             detected.browser = 'msie';
37387             detected.version = m[1];
37388         }
37389     }
37390     if (!detected.browser) {
37391         m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i);   // Opera 15+
37392         if (m !== null) {
37393             detected.browser = 'Opera';
37394             detected.version = m[2];
37395         }
37396     }
37397     if (!detected.browser) {
37398         m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
37399         if (m !== null) {
37400             detected.browser = m[1];
37401             detected.version = m[2];
37402             m = ua.match(/version\/([\.\d]+)/i);
37403             if (m !== null) detected.version = m[1];
37404         }
37405     }
37406     if (!detected.browser) {
37407         detected.browser = navigator.appName;
37408         detected.version = navigator.appVersion;
37409     }
37410
37411     // keep major.minor version only..
37412     detected.version = detected.version.split(/\W/).slice(0,2).join('.');
37413
37414     if (detected.browser.toLowerCase() === 'msie') {
37415         detected.ie = true;
37416         detected.browser = 'Internet Explorer';
37417         detected.support = parseFloat(detected.version) >= 11;
37418     } else {
37419         detected.ie = false;
37420         detected.support = true;
37421     }
37422
37423     // Added due to incomplete svg style support. See #715
37424     detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 );
37425
37426     detected.locale = (navigator.language || navigator.userLanguage || 'en-US');
37427     detected.language = detected.locale.split('-')[0];
37428
37429     // Search `navigator.languages` for a better locale.. Prefer the first language,
37430     // unless the second language is a culture-specific version of the first one, see #3842
37431     if (navigator.languages && navigator.languages.length > 0) {
37432         var code0 = navigator.languages[0],
37433             parts0 = code0.split('-');
37434
37435         detected.locale = code0;
37436         detected.language = parts0[0];
37437
37438         if (navigator.languages.length > 1 && parts0.length === 1) {
37439             var code1 = navigator.languages[1],
37440                 parts1 = code1.split('-');
37441
37442             if (parts1[0] === parts0[0]) {
37443                 detected.locale = code1;
37444             }
37445         }
37446     }
37447
37448     // Loaded locale is stored in currentLocale
37449     // return that instead (except in the situation where 'en' might override 'en-US')
37450     var loadedLocale = currentLocale || 'en';
37451     if (loadedLocale !== 'en') {
37452         detected.locale = loadedLocale;
37453         detected.language = detected.locale.split('-')[0];
37454     }
37455
37456     // detect text direction
37457     var q = utilStringQs(window.location.hash.substring(1));
37458     var lang = dataLocales[detected.locale];
37459     if ((lang && lang.rtl) || q.hasOwnProperty('rtl')) {
37460         detected.textDirection = 'rtl';
37461     } else {
37462         detected.textDirection = 'ltr';
37463     }
37464     setTextDirection(detected.textDirection);
37465
37466     // detect host
37467     var loc = window.top.location;
37468     var origin = loc.origin;
37469     if (!origin) {  // for unpatched IE11
37470         origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port: '');
37471     }
37472
37473     detected.host = origin + loc.pathname;
37474
37475     detected.filedrop = (window.FileReader && 'ondrop' in window);
37476
37477     function nav(x) {
37478         return navigator.userAgent.indexOf(x) !== -1;
37479     }
37480
37481     if (nav('Win')) {
37482         detected.os = 'win';
37483         detected.platform = 'Windows';
37484     }
37485     else if (nav('Mac')) {
37486         detected.os = 'mac';
37487         detected.platform = 'Macintosh';
37488     }
37489     else if (nav('X11') || nav('Linux')) {
37490         detected.os = 'linux';
37491         detected.platform = 'Linux';
37492     }
37493     else {
37494         detected.os = 'win';
37495         detected.platform = 'Unknown';
37496     }
37497
37498     return detected;
37499 }
37500
37501 var remove$1 = removeDiacritics;
37502
37503 var replacementList = [
37504   {
37505     base: ' ',
37506     chars: "\u00A0",
37507   }, {
37508     base: '0',
37509     chars: "\u07C0",
37510   }, {
37511     base: 'A',
37512     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",
37513   }, {
37514     base: 'AA',
37515     chars: "\uA732",
37516   }, {
37517     base: 'AE',
37518     chars: "\u00C6\u01FC\u01E2",
37519   }, {
37520     base: 'AO',
37521     chars: "\uA734",
37522   }, {
37523     base: 'AU',
37524     chars: "\uA736",
37525   }, {
37526     base: 'AV',
37527     chars: "\uA738\uA73A",
37528   }, {
37529     base: 'AY',
37530     chars: "\uA73C",
37531   }, {
37532     base: 'B',
37533     chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181",
37534   }, {
37535     base: 'C',
37536     chars: "\u24b8\uff23\uA73E\u1E08\u0106\u0043\u0108\u010A\u010C\u00C7\u0187\u023B",
37537   }, {
37538     base: 'D',
37539     chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779",
37540   }, {
37541     base: 'Dh',
37542     chars: "\u00D0",
37543   }, {
37544     base: 'DZ',
37545     chars: "\u01F1\u01C4",
37546   }, {
37547     base: 'Dz',
37548     chars: "\u01F2\u01C5",
37549   }, {
37550     base: 'E',
37551     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",
37552   }, {
37553     base: 'F',
37554     chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B",
37555   }, {
37556     base: 'G',
37557     chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262",
37558   }, {
37559     base: 'H',
37560     chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D",
37561   }, {
37562     base: 'I',
37563     chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197",
37564   }, {
37565     base: 'J',
37566     chars: "\u24BF\uFF2A\u0134\u0248\u0237",
37567   }, {
37568     base: 'K',
37569     chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2",
37570   }, {
37571     base: 'L',
37572     chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780",
37573   }, {
37574     base: 'LJ',
37575     chars: "\u01C7",
37576   }, {
37577     base: 'Lj',
37578     chars: "\u01C8",
37579   }, {
37580     base: 'M',
37581     chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB",
37582   }, {
37583     base: 'N',
37584     chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E",
37585   }, {
37586     base: 'NJ',
37587     chars: "\u01CA",
37588   }, {
37589     base: 'Nj',
37590     chars: "\u01CB",
37591   }, {
37592     base: 'O',
37593     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",
37594   }, {
37595     base: 'OE',
37596     chars: "\u0152",
37597   }, {
37598     base: 'OI',
37599     chars: "\u01A2",
37600   }, {
37601     base: 'OO',
37602     chars: "\uA74E",
37603   }, {
37604     base: 'OU',
37605     chars: "\u0222",
37606   }, {
37607     base: 'P',
37608     chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754",
37609   }, {
37610     base: 'Q',
37611     chars: "\u24C6\uFF31\uA756\uA758\u024A",
37612   }, {
37613     base: 'R',
37614     chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782",
37615   }, {
37616     base: 'S',
37617     chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784",
37618   }, {
37619     base: 'T',
37620     chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786",
37621   }, {
37622     base: 'Th',
37623     chars: "\u00DE",
37624   }, {
37625     base: 'TZ',
37626     chars: "\uA728",
37627   }, {
37628     base: 'U',
37629     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",
37630   }, {
37631     base: 'V',
37632     chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245",
37633   }, {
37634     base: 'VY',
37635     chars: "\uA760",
37636   }, {
37637     base: 'W',
37638     chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72",
37639   }, {
37640     base: 'X',
37641     chars: "\u24CD\uFF38\u1E8A\u1E8C",
37642   }, {
37643     base: 'Y',
37644     chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE",
37645   }, {
37646     base: 'Z',
37647     chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762",
37648   }, {
37649     base: 'a',
37650     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",
37651   }, {
37652     base: 'aa',
37653     chars: "\uA733",
37654   }, {
37655     base: 'ae',
37656     chars: "\u00E6\u01FD\u01E3",
37657   }, {
37658     base: 'ao',
37659     chars: "\uA735",
37660   }, {
37661     base: 'au',
37662     chars: "\uA737",
37663   }, {
37664     base: 'av',
37665     chars: "\uA739\uA73B",
37666   }, {
37667     base: 'ay',
37668     chars: "\uA73D",
37669   }, {
37670     base: 'b',
37671     chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182",
37672   }, {
37673     base: 'c',
37674     chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184",
37675   }, {
37676     base: 'd',
37677     chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA",
37678   }, {
37679     base: 'dh',
37680     chars: "\u00F0",
37681   }, {
37682     base: 'dz',
37683     chars: "\u01F3\u01C6",
37684   }, {
37685     base: 'e',
37686     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",
37687   }, {
37688     base: 'f',
37689     chars: "\u24D5\uFF46\u1E1F\u0192",
37690   }, {
37691     base: 'ff',
37692     chars: "\uFB00",
37693   }, {
37694     base: 'fi',
37695     chars: "\uFB01",
37696   }, {
37697     base: 'fl',
37698     chars: "\uFB02",
37699   }, {
37700     base: 'ffi',
37701     chars: "\uFB03",
37702   }, {
37703     base: 'ffl',
37704     chars: "\uFB04",
37705   }, {
37706     base: 'g',
37707     chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79",
37708   }, {
37709     base: 'h',
37710     chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265",
37711   }, {
37712     base: 'hv',
37713     chars: "\u0195",
37714   }, {
37715     base: 'i',
37716     chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131",
37717   }, {
37718     base: 'j',
37719     chars: "\u24D9\uFF4A\u0135\u01F0\u0249",
37720   }, {
37721     base: 'k',
37722     chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3",
37723   }, {
37724     base: 'l',
37725     chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D",
37726   }, {
37727     base: 'lj',
37728     chars: "\u01C9",
37729   }, {
37730     base: 'm',
37731     chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F",
37732   }, {
37733     base: 'n',
37734     chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509",
37735   }, {
37736     base: 'nj',
37737     chars: "\u01CC",
37738   }, {
37739     base: 'o',
37740     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",
37741   }, {
37742     base: 'oe',
37743     chars: "\u0153",
37744   }, {
37745     base: 'oi',
37746     chars: "\u01A3",
37747   }, {
37748     base: 'oo',
37749     chars: "\uA74F",
37750   }, {
37751     base: 'ou',
37752     chars: "\u0223",
37753   }, {
37754     base: 'p',
37755     chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1",
37756   }, {
37757     base: 'q',
37758     chars: "\u24E0\uFF51\u024B\uA757\uA759",
37759   }, {
37760     base: 'r',
37761     chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783",
37762   }, {
37763     base: 's',
37764     chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282",
37765   }, {
37766     base: 'ss',
37767     chars: "\xDF",
37768   }, {
37769     base: 't',
37770     chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787",
37771   }, {
37772     base: 'th',
37773     chars: "\u00FE",
37774   }, {
37775     base: 'tz',
37776     chars: "\uA729",
37777   }, {
37778     base: 'u',
37779     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",
37780   }, {
37781     base: 'v',
37782     chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C",
37783   }, {
37784     base: 'vy',
37785     chars: "\uA761",
37786   }, {
37787     base: 'w',
37788     chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73",
37789   }, {
37790     base: 'x',
37791     chars: "\u24E7\uFF58\u1E8B\u1E8D",
37792   }, {
37793     base: 'y',
37794     chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF",
37795   }, {
37796     base: 'z',
37797     chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763",
37798   }
37799 ];
37800
37801 var diacriticsMap = {};
37802 for (var i = 0; i < replacementList.length; i += 1) {
37803   var chars = replacementList[i].chars;
37804   for (var j = 0; j < chars.length; j += 1) {
37805     diacriticsMap[chars[j]] = replacementList[i].base;
37806   }
37807 }
37808
37809 function removeDiacritics(str) {
37810   return str.replace(/[^\u0000-\u007e]/g, function(c) {
37811     return diacriticsMap[c] || c;
37812   });
37813 }
37814
37815 // see https://github.com/openstreetmap/iD/pull/3707
37816 // https://gist.github.com/mapmeld/556b09ddec07a2044c76e1ef45f01c60
37817
37818 var chars$1 = {
37819     // madda above alef
37820     1570: { initial: 'آ‎', isolated: 'ﺁ', medial: 'ﺁ', final: 'ﺂ' },
37821
37822     // hamza above and below alef
37823     1571: { initial: 'أ', isolated: 'ﺃ', medial: '', final: 'ﺄ' },
37824     // 1572 is ؤ
37825     1573: { initial: 'إ', isolated: 'ﺇ', medial: '', final: 'ﺈ' },
37826     // 1574 is ئ
37827     1575: { initial: 'ا', isolated: 'ا', medial: '', final: 'ﺎ' },
37828     1576: { initial: 'ﺑ', isolated: 'ﺏ', medial: 'ﺒ', final: 'ﺐ' },
37829
37830     // 1577 ة
37831     1577: { initial: '', isolated: 'ة', medial: '', final: 'ﺔ' },
37832
37833     1578: { initial: 'ﺗ', isolated: 'ﺕ', medial: 'ﺘ', final: 'ﺖ' },
37834     1579: { initial: 'ﺛ', isolated: 'ﺙ', medial: 'ﺜ', final: 'ﺚ' },
37835     1580: { initial: 'ﺟ', isolated: 'ﺝ', medial: 'ﺠ', final: 'ﺞ' },
37836     1581: { initial: 'ﺣ', isolated: 'ﺡ', medial: 'ﺤ', final: 'ﺢ' },
37837     1582: { initial: 'ﺧ', isolated: 'ﺥ', medial: 'ﺨ', final: 'ﺦ' },
37838     1583: { initial: 'ﺩ', isolated: 'ﺩ', medial: '', final: 'ﺪ' },
37839     1584: { initial: 'ﺫ', isolated: 'ﺫ', medial: '', final: 'ﺬ' },
37840     1585: { initial: 'ﺭ', isolated: 'ﺭ', medial: '', final: 'ﺮ' },
37841     1586: { initial: 'ﺯ', isolated: 'ﺯ', medial: '', final: 'ﺰ' },
37842     1688: { initial: 'ﮊ', isolated: 'ﮊ', medial: '', final: 'ﮋ' },
37843     1587: { initial: 'ﺳ', isolated: 'ﺱ', medial: 'ﺴ', final: 'ﺲ' },
37844     1588: { initial: 'ﺷ', isolated: 'ﺵ', medial: 'ﺸ', final: 'ﺶ' },
37845     1589: { initial: 'ﺻ', isolated: 'ﺹ', medial: 'ﺼ', final: 'ﺺ' },
37846     1590: { initial: 'ﺿ', isolated: 'ﺽ', medial: 'ﻀ', final: 'ﺾ' },
37847     1591: { initial: 'ﻃ', isolated: 'ﻁ', medial: 'ﻄ', final: 'ﻂ' },
37848     1592: { initial: 'ﻇ', isolated: 'ﻅ', medial: 'ﻈ', final: 'ﻆ' },
37849     1593: { initial: 'ﻋ', isolated: 'ﻉ', medial: 'ﻌ', final: 'ﻊ' },
37850     1594: { initial: 'ﻏ', isolated: 'ﻍ', medial: 'ﻐ', final: 'ﻎ' },
37851
37852     // 1595 ػ - may be very rare
37853
37854     1601: { initial: 'ﻓ', isolated: 'ﻑ', medial: 'ﻔ', final: 'ﻒ' },
37855     1602: { initial: 'ﻗ', isolated: 'ﻕ', medial: 'ﻘ', final: 'ﻖ' },
37856     1604: { initial: 'ﻟ', isolated: 'ﻝ', medial: 'ﻠ', final: 'ﻞ' },
37857     1605: { initial: 'ﻣ', isolated: 'ﻡ', medial: 'ﻤ', final: 'ﻢ' },
37858     1606: { initial: 'ﻧ', isolated: 'ﻥ', medial: 'ﻨ', final: 'ﻦ' },
37859     1607: { initial: 'ﻫ', isolated: 'ﻩ', medial: 'ﻬ', final: 'ﻪ' },
37860     1608: { initial: 'ﻭ', isolated: 'ﻭ', medial: '', final: 'ﻮ' },
37861
37862     // 1609 ى
37863     1609: { initial: 'ﯨ', isolated: 'ﻯ', medial: 'ﯩ', final: 'ﻰ' },
37864     // 1610 ي
37865     1610: { initial: 'ﻳ', isolated: 'ﻱ', medial: 'ﻴ', final: 'ﻲ' },
37866
37867     // short vowel sounds / tashkil markings
37868
37869     1662: { initial: 'ﭘ', isolated: 'ﭖ', medial: 'ﭙ', final: 'ﭗ' },
37870
37871     1670: { initial: 'ﭼ', isolated: 'ﭺ', medial: 'ﭽ', final: 'ﭻ' },
37872     1603: { initial: 'ﻛ', isolated: 'ﻙ', medial: 'ﻜ', final: 'ﻚ' },
37873     1705: { initial: 'ﻛ', isolated: 'ﮎ', medial: 'ﻜ', final: 'ﮏ' },
37874     1711: { initial: 'ﮔ', isolated: 'ﮒ', medial: 'ﮕ', final: 'ﮓ' },
37875     1740: { initial: 'ﻳ', isolated: 'ﻯ', medial: 'ﻴ', final: 'ﻰ' },
37876     5000: { initial: 'ﻻ', isolated: 'ﻻ', medial: '', final: 'ﻼ' }
37877 };
37878
37879 var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0780-\u07BF]/;
37880
37881 function fixRTLTextForSvg(inputText) {
37882     var context = true;
37883     var ret = '';
37884     var rtlBuffer = [];
37885     var arabicRegex = /[\u0600-\u06FF]/g;
37886     var arabicTashkil = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED]/;
37887     var thaanaVowel = /[\u07A6-\u07B0]/;
37888     var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/;
37889
37890     if (!arabicRegex.test(inputText)) {
37891         // Hebrew or Thaana RTL script
37892         for (var n = 0; n < inputText.length; n++) {
37893             var c = inputText[n];
37894             if ((thaanaVowel.test(c) || hebrewSign.test(c)) && rtlBuffer.length) {
37895                 rtlBuffer[rtlBuffer.length - 1] += c;
37896             } else if (rtlRegex.test(c)) {
37897                 rtlBuffer.push(c);
37898             } else if (c === ' ' && rtlBuffer.length) {
37899                 // whitespace within RTL text
37900                 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
37901             } else {
37902                 // non-RTL character
37903                 ret += rtlBuffer.reverse().join('') + c;
37904                 rtlBuffer = [];
37905             }
37906         }
37907     } else {
37908         for (var i = 0, l = inputText.length; i < l; i++) {
37909             var code = inputText[i].charCodeAt(0);
37910             var nextCode = inputText[i + 1] ? inputText[i + 1].charCodeAt(0) : 0;
37911
37912             if (!chars$1[code]) {
37913                 if (code === 32 && rtlBuffer.length) {
37914                     // whitespace
37915                     rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
37916                 } else if (arabicTashkil.test(inputText[i]) && rtlBuffer.length) {
37917                     // tashkil mark
37918                     rtlBuffer[rtlBuffer.length - 1] += inputText[i];
37919                 } else {
37920                     // non-RTL character
37921                     ret += rtlBuffer.reverse().join('') + inputText[i];
37922                     rtlBuffer = [];
37923                 }
37924                 continue;
37925             }
37926             if (context) {
37927                 if (i === l - 1 || nextCode === 32) {
37928                     rtlBuffer.push(chars$1[code].isolated);
37929                 } else {
37930                     // special case for لا
37931                     if (code === 1604 && nextCode === 1575) {
37932                         rtlBuffer.push(chars$1[5000].initial);
37933                         i++;
37934                         context = true;
37935                         continue;
37936                     }
37937                     rtlBuffer.push(chars$1[code].initial);
37938                 }
37939             } else {
37940                 if (i === l - 1 || nextCode === 32){
37941                     rtlBuffer.push(chars$1[code].final);
37942                 } else {
37943                     // special case for ﻼ
37944                     if (code === 1604 && nextCode === 1575){
37945                         rtlBuffer.push(chars$1[5000].final);
37946                         i++;
37947                         context = true;
37948                         continue;
37949                     }
37950                     if (chars$1[code].medial === ''){
37951                         rtlBuffer.push(chars$1[code].final);
37952                     } else {
37953                         rtlBuffer.push(chars$1[code].medial);
37954                     }
37955                 }
37956             }
37957             context = (chars$1[code].medial === '') || nextCode === 32;
37958         }
37959     }
37960     ret += rtlBuffer.reverse().join('');
37961     return ret;
37962 }
37963
37964 function utilTagText(entity) {
37965     return entries(entity.tags).map(function(e) {
37966         return e.key + '=' + e.value;
37967     }).join(', ');
37968 }
37969
37970
37971 function utilEntitySelector(ids) {
37972     return ids.length ? '.' + ids.join(',.') : 'nothing';
37973 }
37974
37975
37976 function utilEntityOrMemberSelector(ids, graph) {
37977     var s = utilEntitySelector(ids);
37978
37979     ids.forEach(function(id) {
37980         var entity = graph.hasEntity(id);
37981         if (entity && entity.type === 'relation') {
37982             entity.members.forEach(function(member) {
37983                 s += ',.' + member.id;
37984             });
37985         }
37986     });
37987
37988     return s;
37989 }
37990
37991
37992 function utilGetAllNodes(ids, graph) {
37993     var seen = {};
37994     var nodes = [];
37995     ids.forEach(getNodes);
37996     return nodes;
37997
37998     function getNodes(id) {
37999         if (seen[id]) return;
38000         seen[id] = true;
38001
38002         var entity = graph.hasEntity(id);
38003         if (!entity) return;
38004
38005         if (entity.type === 'node') {
38006             nodes.push(entity);
38007         } else if (entity.type === 'way') {
38008             entity.nodes.forEach(getNodes);
38009         } else {
38010             entity.members.map(function(member) { return member.id; }).forEach(getNodes);
38011         }
38012     }
38013 }
38014
38015
38016 function utilDisplayName(entity) {
38017     var localizedNameKey = 'name:' + utilDetect().locale.toLowerCase().split('-')[0],
38018         name = entity.tags[localizedNameKey] || entity.tags.name || '',
38019         network = entity.tags.cycle_network || entity.tags.network;
38020
38021     if (!name && entity.tags.ref) {
38022         name = entity.tags.ref;
38023         if (network) {
38024             name = network + ' ' + name;
38025         }
38026     }
38027
38028     return name;
38029 }
38030
38031
38032 function utilDisplayNameForPath(entity) {
38033     var name = utilDisplayName(entity);
38034     var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
38035
38036     if (!isFirefox && name && rtlRegex.test(name)) {
38037         name = fixRTLTextForSvg(name);
38038     }
38039
38040     return name;
38041 }
38042
38043
38044 function utilDisplayType(id) {
38045     return {
38046         n: t('inspector.node'),
38047         w: t('inspector.way'),
38048         r: t('inspector.relation')
38049     }[id.charAt(0)];
38050 }
38051
38052
38053 function utilStringQs(str) {
38054     return str.split('&').reduce(function(obj, pair){
38055         var parts = pair.split('=');
38056         if (parts.length === 2) {
38057             obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
38058         }
38059         return obj;
38060     }, {});
38061 }
38062
38063
38064 function utilQsString(obj, noencode) {
38065     function softEncode(s) {
38066       // encode everything except special characters used in certain hash parameters:
38067       // "/" in map states, ":", ",", {" and "}" in background
38068       return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
38069     }
38070     return Object.keys(obj).sort().map(function(key) {
38071         return encodeURIComponent(key) + '=' + (
38072             noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
38073     }).join('&');
38074 }
38075
38076
38077 function utilPrefixDOMProperty(property) {
38078     var prefixes = ['webkit', 'ms', 'moz', 'o'],
38079         i = -1,
38080         n = prefixes.length,
38081         s = document.body;
38082
38083     if (property in s)
38084         return property;
38085
38086     property = property.substr(0, 1).toUpperCase() + property.substr(1);
38087
38088     while (++i < n)
38089         if (prefixes[i] + property in s)
38090             return prefixes[i] + property;
38091
38092     return false;
38093 }
38094
38095
38096 function utilPrefixCSSProperty(property) {
38097     var prefixes = ['webkit', 'ms', 'Moz', 'O'],
38098         i = -1,
38099         n = prefixes.length,
38100         s = document.body.style;
38101
38102     if (property.toLowerCase() in s)
38103         return property.toLowerCase();
38104
38105     while (++i < n)
38106         if (prefixes[i] + property in s)
38107             return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
38108
38109     return false;
38110 }
38111
38112
38113 var transformProperty;
38114 function utilSetTransform(el, x, y, scale) {
38115     var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform'),
38116         translate = utilDetect().opera ?
38117             'translate('   + x + 'px,' + y + 'px)' :
38118             'translate3d(' + x + 'px,' + y + 'px,0)';
38119     return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
38120 }
38121
38122
38123 // Calculates Levenshtein distance between two strings
38124 // see:  https://en.wikipedia.org/wiki/Levenshtein_distance
38125 // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
38126 function utilEditDistance(a, b) {
38127     a = remove$1(a.toLowerCase());
38128     b = remove$1(b.toLowerCase());
38129     if (a.length === 0) return b.length;
38130     if (b.length === 0) return a.length;
38131     var matrix = [];
38132     for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
38133     for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
38134     for (i = 1; i <= b.length; i++) {
38135         for (j = 1; j <= a.length; j++) {
38136             if (b.charAt(i-1) === a.charAt(j-1)) {
38137                 matrix[i][j] = matrix[i-1][j-1];
38138             } else {
38139                 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
38140                     Math.min(matrix[i][j-1] + 1, // insertion
38141                     matrix[i-1][j] + 1)); // deletion
38142             }
38143         }
38144     }
38145     return matrix[b.length][a.length];
38146 }
38147
38148
38149 // a d3.mouse-alike which
38150 // 1. Only works on HTML elements, not SVG
38151 // 2. Does not cause style recalculation
38152 function utilFastMouse(container) {
38153     var rect = container.getBoundingClientRect(),
38154         rectLeft = rect.left,
38155         rectTop = rect.top,
38156         clientLeft = +container.clientLeft,
38157         clientTop = +container.clientTop;
38158     if (textDirection === 'rtl') {
38159         rectLeft = 0;
38160     }
38161     return function(e) {
38162         return [
38163             e.clientX - rectLeft - clientLeft,
38164             e.clientY - rectTop - clientTop];
38165     };
38166 }
38167
38168
38169 /* eslint-disable no-proto */
38170 var utilGetPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
38171 /* eslint-enable no-proto */
38172
38173
38174 function utilAsyncMap(inputs, func, callback) {
38175     var remaining = inputs.length,
38176         results = [],
38177         errors = [];
38178
38179     inputs.forEach(function(d, i) {
38180         func(d, function done(err, data) {
38181             errors[i] = err;
38182             results[i] = data;
38183             remaining--;
38184             if (!remaining) callback(errors, results);
38185         });
38186     });
38187 }
38188
38189
38190 // wraps an index to an interval [0..length-1]
38191 function utilWrap(index, length) {
38192     if (index < 0)
38193         index += Math.ceil(-index/length)*length;
38194     return index % length;
38195 }
38196
38197
38198 /**
38199  * a replacement for functor
38200  *
38201  * @param {*} value any value
38202  * @returns {Function} a function that returns that value or the value if it's a function
38203  */
38204 function utilFunctor(value) {
38205     if (typeof value === 'function') return value;
38206     return function() {
38207         return value;
38208     };
38209 }
38210
38211
38212 function utilNoAuto(selection$$1) {
38213     return selection$$1
38214         .attr('autocomplete', 'off')
38215         .attr('autocorrect', 'off')
38216         .attr('autocapitalize', 'off')
38217         .attr('spellcheck', 'false');
38218 }
38219
38220 // Like selection.property('value', ...), but avoids no-op value sets,
38221 // which can result in layout/repaint thrashing in some situations.
38222 function utilGetSetValue(selection, value) {
38223     function d3_selection_value(value) {
38224         function valueNull() {
38225             delete this.value;
38226         }
38227
38228         function valueConstant() {
38229             if (this.value !== value) {
38230                 this.value = value;
38231             }
38232         }
38233
38234         function valueFunction() {
38235             var x = value.apply(this, arguments);
38236             if (x == null) {
38237                 delete this.value;
38238             } else if (this.value !== x) {
38239                 this.value = x;
38240             }
38241         }
38242
38243         return value == null
38244             ? valueNull : (typeof value === 'function'
38245             ? valueFunction : valueConstant);
38246     }
38247
38248     if (arguments.length === 1) {
38249         return selection.property('value');
38250     }
38251
38252     return selection.each(d3_selection_value(value));
38253 }
38254
38255 // Copies a variable number of methods from source to target.
38256 function utilRebind(target, source) {
38257     var i = 1, n = arguments.length, method;
38258     while (++i < n) {
38259         target[method = arguments[i]] = d3_rebind(target, source, source[method]);
38260     }
38261     return target;
38262 }
38263
38264 // Method is assumed to be a standard D3 getter-setter:
38265 // If passed with no arguments, gets the value.
38266 // If passed with arguments, sets the value and returns the target.
38267 function d3_rebind(target, source, method) {
38268     return function() {
38269         var value = method.apply(source, arguments);
38270         return value === source ? target : value;
38271     };
38272 }
38273
38274 // A per-domain session mutex backed by a cookie and dead man's
38275 // switch. If the session crashes, the mutex will auto-release
38276 // after 5 seconds.
38277
38278 function utilSessionMutex(name) {
38279     var mutex = {},
38280         intervalID;
38281
38282     function renew() {
38283         var expires = new Date();
38284         expires.setSeconds(expires.getSeconds() + 5);
38285         document.cookie = name + '=1; expires=' + expires.toUTCString();
38286     }
38287
38288     mutex.lock = function() {
38289         if (intervalID) return true;
38290         var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
38291         if (cookie) return false;
38292         renew();
38293         intervalID = window.setInterval(renew, 4000);
38294         return true;
38295     };
38296
38297     mutex.unlock = function() {
38298         if (!intervalID) return;
38299         document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
38300         clearInterval(intervalID);
38301         intervalID = null;
38302     };
38303
38304     mutex.locked = function() {
38305         return !!intervalID;
38306     };
38307
38308     return mutex;
38309 }
38310
38311 function utilSuggestNames(preset, suggestions) {
38312     preset = preset.id.split('/', 2);
38313     var k = preset[0],
38314         v = preset[1];
38315
38316     return function(value, callback) {
38317         var result = [];
38318         if (value && value.length > 2) {
38319             if (suggestions[k] && suggestions[k][v]) {
38320                 for (var sugg in suggestions[k][v]) {
38321                     var dist = utilEditDistance(value, sugg.substring(0, value.length));
38322                     if (dist < 3) {
38323                         result.push({
38324                             title: sugg,
38325                             value: sugg,
38326                             dist: dist
38327                         });
38328                     }
38329                 }
38330             }
38331             result.sort(function(a, b) {
38332                 return a.dist - b.dist;
38333             });
38334         }
38335         result = result.slice(0,3);
38336         callback(result);
38337     };
38338 }
38339
38340 function utilTriggerEvent(target, type) {
38341     target.each(function() {
38342         var evt = document.createEvent('HTMLEvents');
38343         evt.initEvent(type, true, true);
38344         this.dispatchEvent(evt);
38345     });
38346 }
38347
38348 function validationDeprecatedTag() {
38349
38350     var validation = function(changes) {
38351         var warnings = [];
38352         for (var i = 0; i < changes.created.length; i++) {
38353             var change = changes.created[i],
38354                 deprecatedTags = change.deprecatedTags();
38355
38356             if (!lodash.isEmpty(deprecatedTags)) {
38357                 var tags = utilTagText({ tags: deprecatedTags });
38358                 warnings.push({
38359                     id: 'deprecated_tags',
38360                     message: t('validations.deprecated_tags', { tags: tags }),
38361                     entity: change
38362                 });
38363             }
38364         }
38365
38366         return warnings;
38367     };
38368
38369
38370     return validation;
38371 }
38372
38373 function validationDisconnectedHighway() {
38374
38375
38376     function isDisconnectedHighway(entity, graph) {
38377         if (!entity.tags.highway) return false;
38378         if (entity.geometry(graph) !== 'line') return false;
38379
38380         return graph.childNodes(entity)
38381             .every(function(vertex) {
38382                 var parents = graph.parentWays(vertex);
38383                 if (parents.length === 1) {  // standalone vertex
38384                     return true;
38385                 } else {                     // shared vertex
38386                     return !vertex.tags.entrance &&
38387                         parents.filter(function(parent) {
38388                             return parent.tags.highway && parent !== entity;
38389                         }).length === 0;
38390                 }
38391             });
38392     }
38393
38394
38395     var validation = function(changes, graph) {
38396         var warnings = [];
38397         for (var i = 0; i < changes.created.length; i++) {
38398             var entity = changes.created[i];
38399
38400             if (isDisconnectedHighway(entity, graph)) {
38401                 warnings.push({
38402                     id: 'disconnected_highway',
38403                     message: t('validations.disconnected_highway'),
38404                     tooltip: t('validations.disconnected_highway_tooltip'),
38405                     entity: entity
38406                 });
38407             }
38408         }
38409
38410         return warnings;
38411     };
38412
38413
38414     return validation;
38415 }
38416
38417 function validationManyDeletions() {
38418     var threshold = 100;
38419
38420     var validation = function(changes) {
38421         var warnings = [];
38422         if (changes.deleted.length > threshold) {
38423             warnings.push({
38424                 id: 'many_deletions',
38425                 message: t('validations.many_deletions', { n: changes.deleted.length })
38426             });
38427         }
38428
38429         return warnings;
38430     };
38431
38432
38433     return validation;
38434 }
38435
38436 function validationMissingTag() {
38437
38438     // Slightly stricter check than Entity#isUsed (#3091)
38439     function hasTags(entity, graph) {
38440         return lodash.without(Object.keys(entity.tags), 'area', 'name').length > 0 ||
38441             graph.parentRelations(entity).length > 0;
38442     }
38443
38444     var validation = function(changes, graph) {
38445         var types = ['point', 'line', 'area', 'relation'],
38446             warnings = [];
38447
38448         for (var i = 0; i < changes.created.length; i++) {
38449             var change = changes.created[i],
38450                 geometry = change.geometry(graph);
38451
38452             if (types.indexOf(geometry) !== -1 && !hasTags(change, graph)) {
38453                 warnings.push({
38454                     id: 'missing_tag',
38455                     message: t('validations.untagged_' + geometry),
38456                     tooltip: t('validations.untagged_' + geometry + '_tooltip'),
38457                     entity: change
38458                 });
38459             }
38460         }
38461
38462         return warnings;
38463     };
38464
38465
38466     return validation;
38467 }
38468
38469 function validationOldMultipolygon() {
38470
38471
38472     return function validation(changes, graph) {
38473         var warnings = [];
38474         for (var i = 0; i < changes.created.length; i++) {
38475             var entity = changes.created[i];
38476             var parent = osmIsSimpleMultipolygonOuterMember(entity, graph);
38477             if (parent) {
38478                 warnings.push({
38479                     id: 'old_multipolygon',
38480                     message: t('validations.old_multipolygon'),
38481                     tooltip: t('validations.old_multipolygon_tooltip'),
38482                     entity: parent
38483                 });
38484             }
38485         }
38486         return warnings;
38487     };
38488 }
38489
38490 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
38491 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
38492 function validationTagSuggestsArea() {
38493
38494     function tagSuggestsArea(tags) {
38495         if (lodash.isEmpty(tags)) return false;
38496
38497         var presence = ['landuse', 'amenities', 'tourism', 'shop'];
38498         for (var i = 0; i < presence.length; i++) {
38499             if (tags[presence[i]] !== undefined) {
38500                 return presence[i] + '=' + tags[presence[i]];
38501             }
38502         }
38503
38504         if (tags.building && tags.building === 'yes') return 'building=yes';
38505     }
38506
38507
38508     var validation = function(changes, graph) {
38509         var warnings = [];
38510         for (var i = 0; i < changes.created.length; i++) {
38511             var change = changes.created[i],
38512                 geometry = change.geometry(graph),
38513                 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
38514
38515             if (suggestion) {
38516                 warnings.push({
38517                     id: 'tag_suggests_area',
38518                     message: t('validations.tag_suggests_area', { tag: suggestion }),
38519                     entity: change
38520                 });
38521             }
38522         }
38523
38524         return warnings;
38525     };
38526
38527
38528     return validation;
38529 }
38530
38531
38532
38533 var Validations = Object.freeze({
38534         validationDeprecatedTag: validationDeprecatedTag,
38535         validationDisconnectedHighway: validationDisconnectedHighway,
38536         validationManyDeletions: validationManyDeletions,
38537         validationMissingTag: validationMissingTag,
38538         validationOldMultipolygon: validationOldMultipolygon,
38539         validationTagSuggestsArea: validationTagSuggestsArea
38540 });
38541
38542 /*
38543     iD.Difference represents the difference between two graphs.
38544     It knows how to calculate the set of entities that were
38545     created, modified, or deleted, and also contains the logic
38546     for recursively extending a difference to the complete set
38547     of entities that will require a redraw, taking into account
38548     child and parent relationships.
38549  */
38550 function coreDifference(base, head) {
38551     var changes = {},
38552         difference = {},
38553         length = 0;
38554
38555
38556     function changed(h, b) {
38557         return h !== b && !lodash.isEqual(lodash.omit(h, 'v'), lodash.omit(b, 'v'));
38558     }
38559
38560
38561     lodash.each(head.entities, function(h, id) {
38562         var b = base.entities[id];
38563         if (changed(h, b)) {
38564             changes[id] = {base: b, head: h};
38565             length++;
38566         }
38567     });
38568
38569
38570     lodash.each(base.entities, function(b, id) {
38571         var h = head.entities[id];
38572         if (!changes[id] && changed(h, b)) {
38573             changes[id] = {base: b, head: h};
38574             length++;
38575         }
38576     });
38577
38578
38579     function addParents(parents, result) {
38580         for (var i = 0; i < parents.length; i++) {
38581             var parent = parents[i];
38582
38583             if (parent.id in result)
38584                 continue;
38585
38586             result[parent.id] = parent;
38587             addParents(head.parentRelations(parent), result);
38588         }
38589     }
38590
38591
38592     difference.length = function() {
38593         return length;
38594     };
38595
38596
38597     difference.changes = function() {
38598         return changes;
38599     };
38600
38601
38602     difference.extantIDs = function() {
38603         var result = [];
38604         lodash.each(changes, function(change, id) {
38605             if (change.head) result.push(id);
38606         });
38607         return result;
38608     };
38609
38610
38611     difference.modified = function() {
38612         var result = [];
38613         lodash.each(changes, function(change) {
38614             if (change.base && change.head) result.push(change.head);
38615         });
38616         return result;
38617     };
38618
38619
38620     difference.created = function() {
38621         var result = [];
38622         lodash.each(changes, function(change) {
38623             if (!change.base && change.head) result.push(change.head);
38624         });
38625         return result;
38626     };
38627
38628
38629     difference.deleted = function() {
38630         var result = [];
38631         lodash.each(changes, function(change) {
38632             if (change.base && !change.head) result.push(change.base);
38633         });
38634         return result;
38635     };
38636
38637
38638     difference.summary = function() {
38639         var relevant = {};
38640
38641         function addEntity(entity, graph, changeType) {
38642             relevant[entity.id] = {
38643                 entity: entity,
38644                 graph: graph,
38645                 changeType: changeType
38646             };
38647         }
38648
38649         function addParents(entity) {
38650             var parents = head.parentWays(entity);
38651             for (var j = parents.length - 1; j >= 0; j--) {
38652                 var parent = parents[j];
38653                 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
38654             }
38655         }
38656
38657         lodash.each(changes, function(change) {
38658             if (change.head && change.head.geometry(head) !== 'vertex') {
38659                 addEntity(change.head, head, change.base ? 'modified' : 'created');
38660
38661             } else if (change.base && change.base.geometry(base) !== 'vertex') {
38662                 addEntity(change.base, base, 'deleted');
38663
38664             } else if (change.base && change.head) { // modified vertex
38665                 var moved    = !lodash.isEqual(change.base.loc,  change.head.loc),
38666                     retagged = !lodash.isEqual(change.base.tags, change.head.tags);
38667
38668                 if (moved) {
38669                     addParents(change.head);
38670                 }
38671
38672                 if (retagged || (moved && change.head.hasInterestingTags())) {
38673                     addEntity(change.head, head, 'modified');
38674                 }
38675
38676             } else if (change.head && change.head.hasInterestingTags()) { // created vertex
38677                 addEntity(change.head, head, 'created');
38678
38679             } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
38680                 addEntity(change.base, base, 'deleted');
38681             }
38682         });
38683
38684         return values(relevant);
38685     };
38686
38687
38688     difference.complete = function(extent$$1) {
38689         var result = {}, id, change;
38690
38691         for (id in changes) {
38692             change = changes[id];
38693
38694             var h = change.head,
38695                 b = change.base,
38696                 entity = h || b;
38697
38698             if (extent$$1 &&
38699                 (!h || !h.intersects(extent$$1, head)) &&
38700                 (!b || !b.intersects(extent$$1, base)))
38701                 continue;
38702
38703             result[id] = h;
38704
38705             if (entity.type === 'way') {
38706                 var nh = h ? h.nodes : [],
38707                     nb = b ? b.nodes : [],
38708                     diff, i;
38709
38710                 diff = lodash.difference(nh, nb);
38711                 for (i = 0; i < diff.length; i++) {
38712                     result[diff[i]] = head.hasEntity(diff[i]);
38713                 }
38714
38715                 diff = lodash.difference(nb, nh);
38716                 for (i = 0; i < diff.length; i++) {
38717                     result[diff[i]] = head.hasEntity(diff[i]);
38718                 }
38719             }
38720
38721             addParents(head.parentWays(entity), result);
38722             addParents(head.parentRelations(entity), result);
38723         }
38724
38725         return result;
38726     };
38727
38728
38729     return difference;
38730 }
38731
38732 function coreGraph$$1(other, mutable) {
38733     if (!(this instanceof coreGraph$$1)) return new coreGraph$$1(other, mutable);
38734
38735     if (other instanceof coreGraph$$1) {
38736         var base = other.base();
38737         this.entities = lodash.assign(Object.create(base.entities), other.entities);
38738         this._parentWays = lodash.assign(Object.create(base.parentWays), other._parentWays);
38739         this._parentRels = lodash.assign(Object.create(base.parentRels), other._parentRels);
38740
38741     } else {
38742         this.entities = Object.create({});
38743         this._parentWays = Object.create({});
38744         this._parentRels = Object.create({});
38745         this.rebase(other || [], [this]);
38746     }
38747
38748     this.transients = {};
38749     this._childNodes = {};
38750     this.frozen = !mutable;
38751 }
38752
38753
38754 coreGraph$$1.prototype = {
38755
38756     hasEntity: function(id) {
38757         return this.entities[id];
38758     },
38759
38760
38761     entity: function(id) {
38762         var entity = this.entities[id];
38763
38764         //https://github.com/openstreetmap/iD/issues/3973#issuecomment-307052376
38765         if (!entity) {
38766             entity = this.entities.__proto__[id];  // eslint-disable-line no-proto
38767         }
38768
38769         if (!entity) {
38770             throw new Error('entity ' + id + ' not found');
38771         }
38772         return entity;
38773     },
38774
38775
38776     transient: function(entity, key, fn) {
38777         var id = entity.id,
38778             transients = this.transients[id] ||
38779             (this.transients[id] = {});
38780
38781         if (transients[key] !== undefined) {
38782             return transients[key];
38783         }
38784
38785         transients[key] = fn.call(entity);
38786
38787         return transients[key];
38788     },
38789
38790
38791     parentWays: function(entity) {
38792         var parents = this._parentWays[entity.id],
38793             result = [];
38794
38795         if (parents) {
38796             for (var i = 0; i < parents.length; i++) {
38797                 result.push(this.entity(parents[i]));
38798             }
38799         }
38800         return result;
38801     },
38802
38803
38804     isPoi: function(entity) {
38805         var parentWays = this._parentWays[entity.id];
38806         return !parentWays || parentWays.length === 0;
38807     },
38808
38809
38810     isShared: function(entity) {
38811         var parentWays = this._parentWays[entity.id];
38812         return parentWays && parentWays.length > 1;
38813     },
38814
38815
38816     parentRelations: function(entity) {
38817         var parents = this._parentRels[entity.id],
38818             result = [];
38819
38820         if (parents) {
38821             for (var i = 0; i < parents.length; i++) {
38822                 result.push(this.entity(parents[i]));
38823             }
38824         }
38825         return result;
38826     },
38827
38828
38829     childNodes: function(entity) {
38830         if (this._childNodes[entity.id]) return this._childNodes[entity.id];
38831         if (!entity.nodes) return [];
38832
38833         var nodes = [];
38834         for (var i = 0; i < entity.nodes.length; i++) {
38835             nodes[i] = this.entity(entity.nodes[i]);
38836         }
38837
38838         if (debug) Object.freeze(nodes);
38839
38840         this._childNodes[entity.id] = nodes;
38841         return this._childNodes[entity.id];
38842     },
38843
38844
38845     base: function() {
38846         return {
38847             'entities': utilGetPrototypeOf(this.entities),
38848             'parentWays': utilGetPrototypeOf(this._parentWays),
38849             'parentRels': utilGetPrototypeOf(this._parentRels)
38850         };
38851     },
38852
38853
38854     // Unlike other graph methods, rebase mutates in place. This is because it
38855     // is used only during the history operation that merges newly downloaded
38856     // data into each state. To external consumers, it should appear as if the
38857     // graph always contained the newly downloaded data.
38858     rebase: function(entities, stack, force) {
38859         var base = this.base(),
38860             i, j, k, id;
38861
38862         for (i = 0; i < entities.length; i++) {
38863             var entity = entities[i];
38864
38865             if (!entity.visible || (!force && base.entities[entity.id]))
38866                 continue;
38867
38868             // Merging data into the base graph
38869             base.entities[entity.id] = entity;
38870             this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
38871
38872             // Restore provisionally-deleted nodes that are discovered to have an extant parent
38873             if (entity.type === 'way') {
38874                 for (j = 0; j < entity.nodes.length; j++) {
38875                     id = entity.nodes[j];
38876                     for (k = 1; k < stack.length; k++) {
38877                         var ents = stack[k].entities;
38878                         if (ents.hasOwnProperty(id) && ents[id] === undefined) {
38879                             delete ents[id];
38880                         }
38881                     }
38882                 }
38883             }
38884         }
38885
38886         for (i = 0; i < stack.length; i++) {
38887             stack[i]._updateRebased();
38888         }
38889     },
38890
38891
38892     _updateRebased: function() {
38893         var base = this.base(),
38894             i, k, child, id, keys;
38895
38896         keys = Object.keys(this._parentWays);
38897         for (i = 0; i < keys.length; i++) {
38898             child = keys[i];
38899             if (base.parentWays[child]) {
38900                 for (k = 0; k < base.parentWays[child].length; k++) {
38901                     id = base.parentWays[child][k];
38902                     if (!this.entities.hasOwnProperty(id) && !lodash.includes(this._parentWays[child], id)) {
38903                         this._parentWays[child].push(id);
38904                     }
38905                 }
38906             }
38907         }
38908
38909         keys = Object.keys(this._parentRels);
38910         for (i = 0; i < keys.length; i++) {
38911             child = keys[i];
38912             if (base.parentRels[child]) {
38913                 for (k = 0; k < base.parentRels[child].length; k++) {
38914                     id = base.parentRels[child][k];
38915                     if (!this.entities.hasOwnProperty(id) && !lodash.includes(this._parentRels[child], id)) {
38916                         this._parentRels[child].push(id);
38917                     }
38918                 }
38919             }
38920         }
38921
38922         this.transients = {};
38923
38924         // this._childNodes is not updated, under the assumption that
38925         // ways are always downloaded with their child nodes.
38926     },
38927
38928
38929     // Updates calculated properties (parentWays, parentRels) for the specified change
38930     _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
38931
38932         parentWays = parentWays || this._parentWays;
38933         parentRels = parentRels || this._parentRels;
38934
38935         var type = entity && entity.type || oldentity && oldentity.type,
38936             removed, added, ways, rels, i;
38937
38938
38939         if (type === 'way') {
38940
38941             // Update parentWays
38942             if (oldentity && entity) {
38943                 removed = lodash.difference(oldentity.nodes, entity.nodes);
38944                 added = lodash.difference(entity.nodes, oldentity.nodes);
38945             } else if (oldentity) {
38946                 removed = oldentity.nodes;
38947                 added = [];
38948             } else if (entity) {
38949                 removed = [];
38950                 added = entity.nodes;
38951             }
38952             for (i = 0; i < removed.length; i++) {
38953                 parentWays[removed[i]] = lodash.without(parentWays[removed[i]], oldentity.id);
38954             }
38955             for (i = 0; i < added.length; i++) {
38956                 ways = lodash.without(parentWays[added[i]], entity.id);
38957                 ways.push(entity.id);
38958                 parentWays[added[i]] = ways;
38959             }
38960
38961         } else if (type === 'relation') {
38962
38963             // Update parentRels
38964             if (oldentity && entity) {
38965                 removed = lodash.difference(oldentity.members, entity.members);
38966                 added = lodash.difference(entity.members, oldentity);
38967             } else if (oldentity) {
38968                 removed = oldentity.members;
38969                 added = [];
38970             } else if (entity) {
38971                 removed = [];
38972                 added = entity.members;
38973             }
38974             for (i = 0; i < removed.length; i++) {
38975                 parentRels[removed[i].id] = lodash.without(parentRels[removed[i].id], oldentity.id);
38976             }
38977             for (i = 0; i < added.length; i++) {
38978                 rels = lodash.without(parentRels[added[i].id], entity.id);
38979                 rels.push(entity.id);
38980                 parentRels[added[i].id] = rels;
38981             }
38982         }
38983     },
38984
38985
38986     replace: function(entity) {
38987         if (this.entities[entity.id] === entity)
38988             return this;
38989
38990         return this.update(function() {
38991             this._updateCalculated(this.entities[entity.id], entity);
38992             this.entities[entity.id] = entity;
38993         });
38994     },
38995
38996
38997     remove: function(entity) {
38998         return this.update(function() {
38999             this._updateCalculated(entity, undefined);
39000             this.entities[entity.id] = undefined;
39001         });
39002     },
39003
39004
39005     revert: function(id) {
39006         var baseEntity = this.base().entities[id],
39007             headEntity = this.entities[id];
39008
39009         if (headEntity === baseEntity)
39010             return this;
39011
39012         return this.update(function() {
39013             this._updateCalculated(headEntity, baseEntity);
39014             delete this.entities[id];
39015         });
39016     },
39017
39018
39019     update: function() {
39020         var graph = this.frozen ? coreGraph$$1(this, true) : this;
39021
39022         for (var i = 0; i < arguments.length; i++) {
39023             arguments[i].call(graph, graph);
39024         }
39025
39026         if (this.frozen) graph.frozen = true;
39027
39028         return graph;
39029     },
39030
39031
39032     // Obliterates any existing entities
39033     load: function(entities) {
39034         var base = this.base();
39035         this.entities = Object.create(base.entities);
39036
39037         for (var i in entities) {
39038             this.entities[i] = entities[i];
39039             this._updateCalculated(base.entities[i], this.entities[i]);
39040         }
39041
39042         return this;
39043     }
39044 };
39045
39046 var index$10 = partialSort;
39047
39048 // Floyd-Rivest selection algorithm:
39049 // Rearrange items so that all items in the [left, k] range are smaller than all items in (k, right];
39050 // The k-th element will have the (k - left + 1)th smallest value in [left, right]
39051
39052 function partialSort(arr, k, left, right, compare) {
39053     left = left || 0;
39054     right = right || (arr.length - 1);
39055     compare = compare || defaultCompare;
39056
39057     while (right > left) {
39058         if (right - left > 600) {
39059             var n = right - left + 1;
39060             var m = k - left + 1;
39061             var z = Math.log(n);
39062             var s = 0.5 * Math.exp(2 * z / 3);
39063             var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
39064             var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
39065             var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
39066             partialSort(arr, k, newLeft, newRight, compare);
39067         }
39068
39069         var t = arr[k];
39070         var i = left;
39071         var j = right;
39072
39073         swap(arr, left, k);
39074         if (compare(arr[right], t) > 0) swap(arr, left, right);
39075
39076         while (i < j) {
39077             swap(arr, i, j);
39078             i++;
39079             j--;
39080             while (compare(arr[i], t) < 0) i++;
39081             while (compare(arr[j], t) > 0) j--;
39082         }
39083
39084         if (compare(arr[left], t) === 0) swap(arr, left, j);
39085         else {
39086             j++;
39087             swap(arr, j, right);
39088         }
39089
39090         if (j <= k) left = j + 1;
39091         if (k <= j) right = j - 1;
39092     }
39093 }
39094
39095 function swap(arr, i, j) {
39096     var tmp = arr[i];
39097     arr[i] = arr[j];
39098     arr[j] = tmp;
39099 }
39100
39101 function defaultCompare(a, b) {
39102     return a < b ? -1 : a > b ? 1 : 0;
39103 }
39104
39105 var index$9 = rbush;
39106
39107
39108
39109 function rbush(maxEntries, format) {
39110     if (!(this instanceof rbush)) return new rbush(maxEntries, format);
39111
39112     // max entries in a node is 9 by default; min node fill is 40% for best performance
39113     this._maxEntries = Math.max(4, maxEntries || 9);
39114     this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
39115
39116     if (format) {
39117         this._initFormat(format);
39118     }
39119
39120     this.clear();
39121 }
39122
39123 rbush.prototype = {
39124
39125     all: function () {
39126         return this._all(this.data, []);
39127     },
39128
39129     search: function (bbox) {
39130
39131         var node = this.data,
39132             result = [],
39133             toBBox = this.toBBox;
39134
39135         if (!intersects$1(bbox, node)) return result;
39136
39137         var nodesToSearch = [],
39138             i, len, child, childBBox;
39139
39140         while (node) {
39141             for (i = 0, len = node.children.length; i < len; i++) {
39142
39143                 child = node.children[i];
39144                 childBBox = node.leaf ? toBBox(child) : child;
39145
39146                 if (intersects$1(bbox, childBBox)) {
39147                     if (node.leaf) result.push(child);
39148                     else if (contains$2(bbox, childBBox)) this._all(child, result);
39149                     else nodesToSearch.push(child);
39150                 }
39151             }
39152             node = nodesToSearch.pop();
39153         }
39154
39155         return result;
39156     },
39157
39158     collides: function (bbox) {
39159
39160         var node = this.data,
39161             toBBox = this.toBBox;
39162
39163         if (!intersects$1(bbox, node)) return false;
39164
39165         var nodesToSearch = [],
39166             i, len, child, childBBox;
39167
39168         while (node) {
39169             for (i = 0, len = node.children.length; i < len; i++) {
39170
39171                 child = node.children[i];
39172                 childBBox = node.leaf ? toBBox(child) : child;
39173
39174                 if (intersects$1(bbox, childBBox)) {
39175                     if (node.leaf || contains$2(bbox, childBBox)) return true;
39176                     nodesToSearch.push(child);
39177                 }
39178             }
39179             node = nodesToSearch.pop();
39180         }
39181
39182         return false;
39183     },
39184
39185     load: function (data) {
39186         if (!(data && data.length)) return this;
39187
39188         if (data.length < this._minEntries) {
39189             for (var i = 0, len = data.length; i < len; i++) {
39190                 this.insert(data[i]);
39191             }
39192             return this;
39193         }
39194
39195         // recursively build the tree with the given data from stratch using OMT algorithm
39196         var node = this._build(data.slice(), 0, data.length - 1, 0);
39197
39198         if (!this.data.children.length) {
39199             // save as is if tree is empty
39200             this.data = node;
39201
39202         } else if (this.data.height === node.height) {
39203             // split root if trees have the same height
39204             this._splitRoot(this.data, node);
39205
39206         } else {
39207             if (this.data.height < node.height) {
39208                 // swap trees if inserted one is bigger
39209                 var tmpNode = this.data;
39210                 this.data = node;
39211                 node = tmpNode;
39212             }
39213
39214             // insert the small tree into the large tree at appropriate level
39215             this._insert(node, this.data.height - node.height - 1, true);
39216         }
39217
39218         return this;
39219     },
39220
39221     insert: function (item) {
39222         if (item) this._insert(item, this.data.height - 1);
39223         return this;
39224     },
39225
39226     clear: function () {
39227         this.data = createNode([]);
39228         return this;
39229     },
39230
39231     remove: function (item, equalsFn) {
39232         if (!item) return this;
39233
39234         var node = this.data,
39235             bbox = this.toBBox(item),
39236             path = [],
39237             indexes = [],
39238             i, parent, index, goingUp;
39239
39240         // depth-first iterative tree traversal
39241         while (node || path.length) {
39242
39243             if (!node) { // go up
39244                 node = path.pop();
39245                 parent = path[path.length - 1];
39246                 i = indexes.pop();
39247                 goingUp = true;
39248             }
39249
39250             if (node.leaf) { // check current node
39251                 index = findItem(item, node.children, equalsFn);
39252
39253                 if (index !== -1) {
39254                     // item found, remove the item and condense tree upwards
39255                     node.children.splice(index, 1);
39256                     path.push(node);
39257                     this._condense(path);
39258                     return this;
39259                 }
39260             }
39261
39262             if (!goingUp && !node.leaf && contains$2(node, bbox)) { // go down
39263                 path.push(node);
39264                 indexes.push(i);
39265                 i = 0;
39266                 parent = node;
39267                 node = node.children[0];
39268
39269             } else if (parent) { // go right
39270                 i++;
39271                 node = parent.children[i];
39272                 goingUp = false;
39273
39274             } else node = null; // nothing found
39275         }
39276
39277         return this;
39278     },
39279
39280     toBBox: function (item) { return item; },
39281
39282     compareMinX: compareNodeMinX,
39283     compareMinY: compareNodeMinY,
39284
39285     toJSON: function () { return this.data; },
39286
39287     fromJSON: function (data) {
39288         this.data = data;
39289         return this;
39290     },
39291
39292     _all: function (node, result) {
39293         var nodesToSearch = [];
39294         while (node) {
39295             if (node.leaf) result.push.apply(result, node.children);
39296             else nodesToSearch.push.apply(nodesToSearch, node.children);
39297
39298             node = nodesToSearch.pop();
39299         }
39300         return result;
39301     },
39302
39303     _build: function (items, left, right, height) {
39304
39305         var N = right - left + 1,
39306             M = this._maxEntries,
39307             node;
39308
39309         if (N <= M) {
39310             // reached leaf level; return leaf
39311             node = createNode(items.slice(left, right + 1));
39312             calcBBox(node, this.toBBox);
39313             return node;
39314         }
39315
39316         if (!height) {
39317             // target height of the bulk-loaded tree
39318             height = Math.ceil(Math.log(N) / Math.log(M));
39319
39320             // target number of root entries to maximize storage utilization
39321             M = Math.ceil(N / Math.pow(M, height - 1));
39322         }
39323
39324         node = createNode([]);
39325         node.leaf = false;
39326         node.height = height;
39327
39328         // split the items into M mostly square tiles
39329
39330         var N2 = Math.ceil(N / M),
39331             N1 = N2 * Math.ceil(Math.sqrt(M)),
39332             i, j, right2, right3;
39333
39334         multiSelect(items, left, right, N1, this.compareMinX);
39335
39336         for (i = left; i <= right; i += N1) {
39337
39338             right2 = Math.min(i + N1 - 1, right);
39339
39340             multiSelect(items, i, right2, N2, this.compareMinY);
39341
39342             for (j = i; j <= right2; j += N2) {
39343
39344                 right3 = Math.min(j + N2 - 1, right2);
39345
39346                 // pack each entry recursively
39347                 node.children.push(this._build(items, j, right3, height - 1));
39348             }
39349         }
39350
39351         calcBBox(node, this.toBBox);
39352
39353         return node;
39354     },
39355
39356     _chooseSubtree: function (bbox, node, level, path) {
39357
39358         var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
39359
39360         while (true) {
39361             path.push(node);
39362
39363             if (node.leaf || path.length - 1 === level) break;
39364
39365             minArea = minEnlargement = Infinity;
39366
39367             for (i = 0, len = node.children.length; i < len; i++) {
39368                 child = node.children[i];
39369                 area = bboxArea(child);
39370                 enlargement = enlargedArea(bbox, child) - area;
39371
39372                 // choose entry with the least area enlargement
39373                 if (enlargement < minEnlargement) {
39374                     minEnlargement = enlargement;
39375                     minArea = area < minArea ? area : minArea;
39376                     targetNode = child;
39377
39378                 } else if (enlargement === minEnlargement) {
39379                     // otherwise choose one with the smallest area
39380                     if (area < minArea) {
39381                         minArea = area;
39382                         targetNode = child;
39383                     }
39384                 }
39385             }
39386
39387             node = targetNode || node.children[0];
39388         }
39389
39390         return node;
39391     },
39392
39393     _insert: function (item, level, isNode) {
39394
39395         var toBBox = this.toBBox,
39396             bbox = isNode ? item : toBBox(item),
39397             insertPath = [];
39398
39399         // find the best node for accommodating the item, saving all nodes along the path too
39400         var node = this._chooseSubtree(bbox, this.data, level, insertPath);
39401
39402         // put the item into the node
39403         node.children.push(item);
39404         extend$1(node, bbox);
39405
39406         // split on node overflow; propagate upwards if necessary
39407         while (level >= 0) {
39408             if (insertPath[level].children.length > this._maxEntries) {
39409                 this._split(insertPath, level);
39410                 level--;
39411             } else break;
39412         }
39413
39414         // adjust bboxes along the insertion path
39415         this._adjustParentBBoxes(bbox, insertPath, level);
39416     },
39417
39418     // split overflowed node into two
39419     _split: function (insertPath, level) {
39420
39421         var node = insertPath[level],
39422             M = node.children.length,
39423             m = this._minEntries;
39424
39425         this._chooseSplitAxis(node, m, M);
39426
39427         var splitIndex = this._chooseSplitIndex(node, m, M);
39428
39429         var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
39430         newNode.height = node.height;
39431         newNode.leaf = node.leaf;
39432
39433         calcBBox(node, this.toBBox);
39434         calcBBox(newNode, this.toBBox);
39435
39436         if (level) insertPath[level - 1].children.push(newNode);
39437         else this._splitRoot(node, newNode);
39438     },
39439
39440     _splitRoot: function (node, newNode) {
39441         // split root node
39442         this.data = createNode([node, newNode]);
39443         this.data.height = node.height + 1;
39444         this.data.leaf = false;
39445         calcBBox(this.data, this.toBBox);
39446     },
39447
39448     _chooseSplitIndex: function (node, m, M) {
39449
39450         var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
39451
39452         minOverlap = minArea = Infinity;
39453
39454         for (i = m; i <= M - m; i++) {
39455             bbox1 = distBBox(node, 0, i, this.toBBox);
39456             bbox2 = distBBox(node, i, M, this.toBBox);
39457
39458             overlap = intersectionArea(bbox1, bbox2);
39459             area = bboxArea(bbox1) + bboxArea(bbox2);
39460
39461             // choose distribution with minimum overlap
39462             if (overlap < minOverlap) {
39463                 minOverlap = overlap;
39464                 index = i;
39465
39466                 minArea = area < minArea ? area : minArea;
39467
39468             } else if (overlap === minOverlap) {
39469                 // otherwise choose distribution with minimum area
39470                 if (area < minArea) {
39471                     minArea = area;
39472                     index = i;
39473                 }
39474             }
39475         }
39476
39477         return index;
39478     },
39479
39480     // sorts node children by the best axis for split
39481     _chooseSplitAxis: function (node, m, M) {
39482
39483         var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
39484             compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
39485             xMargin = this._allDistMargin(node, m, M, compareMinX),
39486             yMargin = this._allDistMargin(node, m, M, compareMinY);
39487
39488         // if total distributions margin value is minimal for x, sort by minX,
39489         // otherwise it's already sorted by minY
39490         if (xMargin < yMargin) node.children.sort(compareMinX);
39491     },
39492
39493     // total margin of all possible split distributions where each node is at least m full
39494     _allDistMargin: function (node, m, M, compare) {
39495
39496         node.children.sort(compare);
39497
39498         var toBBox = this.toBBox,
39499             leftBBox = distBBox(node, 0, m, toBBox),
39500             rightBBox = distBBox(node, M - m, M, toBBox),
39501             margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
39502             i, child;
39503
39504         for (i = m; i < M - m; i++) {
39505             child = node.children[i];
39506             extend$1(leftBBox, node.leaf ? toBBox(child) : child);
39507             margin += bboxMargin(leftBBox);
39508         }
39509
39510         for (i = M - m - 1; i >= m; i--) {
39511             child = node.children[i];
39512             extend$1(rightBBox, node.leaf ? toBBox(child) : child);
39513             margin += bboxMargin(rightBBox);
39514         }
39515
39516         return margin;
39517     },
39518
39519     _adjustParentBBoxes: function (bbox, path, level) {
39520         // adjust bboxes along the given tree path
39521         for (var i = level; i >= 0; i--) {
39522             extend$1(path[i], bbox);
39523         }
39524     },
39525
39526     _condense: function (path) {
39527         // go through the path, removing empty nodes and updating bboxes
39528         for (var i = path.length - 1, siblings; i >= 0; i--) {
39529             if (path[i].children.length === 0) {
39530                 if (i > 0) {
39531                     siblings = path[i - 1].children;
39532                     siblings.splice(siblings.indexOf(path[i]), 1);
39533
39534                 } else this.clear();
39535
39536             } else calcBBox(path[i], this.toBBox);
39537         }
39538     },
39539
39540     _initFormat: function (format) {
39541         // data format (minX, minY, maxX, maxY accessors)
39542
39543         // uses eval-type function compilation instead of just accepting a toBBox function
39544         // because the algorithms are very sensitive to sorting functions performance,
39545         // so they should be dead simple and without inner calls
39546
39547         var compareArr = ['return a', ' - b', ';'];
39548
39549         this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
39550         this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
39551
39552         this.toBBox = new Function('a',
39553             'return {minX: a' + format[0] +
39554             ', minY: a' + format[1] +
39555             ', maxX: a' + format[2] +
39556             ', maxY: a' + format[3] + '};');
39557     }
39558 };
39559
39560 function findItem(item, items, equalsFn) {
39561     if (!equalsFn) return items.indexOf(item);
39562
39563     for (var i = 0; i < items.length; i++) {
39564         if (equalsFn(item, items[i])) return i;
39565     }
39566     return -1;
39567 }
39568
39569 // calculate node's bbox from bboxes of its children
39570 function calcBBox(node, toBBox) {
39571     distBBox(node, 0, node.children.length, toBBox, node);
39572 }
39573
39574 // min bounding rectangle of node children from k to p-1
39575 function distBBox(node, k, p, toBBox, destNode) {
39576     if (!destNode) destNode = createNode(null);
39577     destNode.minX = Infinity;
39578     destNode.minY = Infinity;
39579     destNode.maxX = -Infinity;
39580     destNode.maxY = -Infinity;
39581
39582     for (var i = k, child; i < p; i++) {
39583         child = node.children[i];
39584         extend$1(destNode, node.leaf ? toBBox(child) : child);
39585     }
39586
39587     return destNode;
39588 }
39589
39590 function extend$1(a, b) {
39591     a.minX = Math.min(a.minX, b.minX);
39592     a.minY = Math.min(a.minY, b.minY);
39593     a.maxX = Math.max(a.maxX, b.maxX);
39594     a.maxY = Math.max(a.maxY, b.maxY);
39595     return a;
39596 }
39597
39598 function compareNodeMinX(a, b) { return a.minX - b.minX; }
39599 function compareNodeMinY(a, b) { return a.minY - b.minY; }
39600
39601 function bboxArea(a)   { return (a.maxX - a.minX) * (a.maxY - a.minY); }
39602 function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
39603
39604 function enlargedArea(a, b) {
39605     return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
39606            (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
39607 }
39608
39609 function intersectionArea(a, b) {
39610     var minX = Math.max(a.minX, b.minX),
39611         minY = Math.max(a.minY, b.minY),
39612         maxX = Math.min(a.maxX, b.maxX),
39613         maxY = Math.min(a.maxY, b.maxY);
39614
39615     return Math.max(0, maxX - minX) *
39616            Math.max(0, maxY - minY);
39617 }
39618
39619 function contains$2(a, b) {
39620     return a.minX <= b.minX &&
39621            a.minY <= b.minY &&
39622            b.maxX <= a.maxX &&
39623            b.maxY <= a.maxY;
39624 }
39625
39626 function intersects$1(a, b) {
39627     return b.minX <= a.maxX &&
39628            b.minY <= a.maxY &&
39629            b.maxX >= a.minX &&
39630            b.maxY >= a.minY;
39631 }
39632
39633 function createNode(children) {
39634     return {
39635         children: children,
39636         height: 1,
39637         leaf: true,
39638         minX: Infinity,
39639         minY: Infinity,
39640         maxX: -Infinity,
39641         maxY: -Infinity
39642     };
39643 }
39644
39645 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
39646 // combines selection algorithm with binary divide & conquer approach
39647
39648 function multiSelect(arr, left, right, n, compare) {
39649     var stack = [left, right],
39650         mid;
39651
39652     while (stack.length) {
39653         right = stack.pop();
39654         left = stack.pop();
39655
39656         if (right - left <= n) continue;
39657
39658         mid = left + Math.ceil((right - left) / n / 2) * n;
39659         index$10(arr, mid, left, right, compare);
39660
39661         stack.push(left, mid, mid, right);
39662     }
39663 }
39664
39665 function coreTree(head) {
39666     var rtree = index$9(),
39667         bboxes = {},
39668         tree = {};
39669
39670
39671     function entityBBox(entity) {
39672         var bbox = entity.extent(head).bbox();
39673         bbox.id = entity.id;
39674         bboxes[entity.id] = bbox;
39675         return bbox;
39676     }
39677
39678
39679     function updateParents(entity, insertions, memo) {
39680         head.parentWays(entity).forEach(function(way) {
39681             if (bboxes[way.id]) {
39682                 rtree.remove(bboxes[way.id]);
39683                 insertions[way.id] = way;
39684             }
39685             updateParents(way, insertions, memo);
39686         });
39687
39688         head.parentRelations(entity).forEach(function(relation) {
39689             if (memo[entity.id]) return;
39690             memo[entity.id] = true;
39691             if (bboxes[relation.id]) {
39692                 rtree.remove(bboxes[relation.id]);
39693                 insertions[relation.id] = relation;
39694             }
39695             updateParents(relation, insertions, memo);
39696         });
39697     }
39698
39699
39700     tree.rebase = function(entities, force) {
39701         var insertions = {};
39702
39703         for (var i = 0; i < entities.length; i++) {
39704             var entity = entities[i];
39705
39706             if (!entity.visible)
39707                 continue;
39708
39709             if (head.entities.hasOwnProperty(entity.id) || bboxes[entity.id]) {
39710                 if (!force) {
39711                     continue;
39712                 } else if (bboxes[entity.id]) {
39713                     rtree.remove(bboxes[entity.id]);
39714                 }
39715             }
39716
39717             insertions[entity.id] = entity;
39718             updateParents(entity, insertions, {});
39719         }
39720
39721         rtree.load(lodash.map(insertions, entityBBox));
39722
39723         return tree;
39724     };
39725
39726
39727     tree.intersects = function(extent, graph) {
39728         if (graph !== head) {
39729             var diff = coreDifference(head, graph),
39730                 insertions = {};
39731
39732             head = graph;
39733
39734             diff.deleted().forEach(function(entity) {
39735                 rtree.remove(bboxes[entity.id]);
39736                 delete bboxes[entity.id];
39737             });
39738
39739             diff.modified().forEach(function(entity) {
39740                 rtree.remove(bboxes[entity.id]);
39741                 insertions[entity.id] = entity;
39742                 updateParents(entity, insertions, {});
39743             });
39744
39745             diff.created().forEach(function(entity) {
39746                 insertions[entity.id] = entity;
39747             });
39748
39749             rtree.load(lodash.map(insertions, entityBBox));
39750         }
39751
39752         return rtree.search(extent.bbox()).map(function(bbox) {
39753             return head.entity(bbox.id);
39754         });
39755     };
39756
39757
39758     return tree;
39759 }
39760
39761 /*
39762  * This code is licensed under the MIT license.
39763  *
39764  * Copyright © 2013, iD authors.
39765  *
39766  * Portions copyright © 2011, Keith Cirkel
39767  * See https://github.com/keithamus/jwerty
39768  *
39769  */
39770 function d3keybinding(namespace$$1) {
39771     var bindings = [];
39772
39773
39774     function testBindings(isCapturing) {
39775         var didMatch = false,
39776             i, binding;
39777
39778         // Most key shortcuts will accept either lower or uppercase ('h' or 'H'),
39779         // so we don't strictly match on the shift key, but we prioritize
39780         // shifted bindings first, and fallback to unshifted only if no match.
39781         // (This lets us differentiate between '←'/'⇧←' or '⌘Z'/'⌘⇧Z')
39782
39783         // priority match shifted bindings first
39784         for (i = 0; i < bindings.length; i++) {
39785             binding = bindings[i];
39786             if (!binding.event.modifiers.shiftKey) continue;  // no shift
39787             if (!!binding.capture !== isCapturing) continue;
39788             if (matches(binding, true)) {
39789                 binding.callback();
39790                 didMatch = true;
39791             }
39792         }
39793
39794         // then unshifted bindings
39795         if (didMatch) return;
39796         for (i = 0; i < bindings.length; i++) {
39797             binding = bindings[i];
39798             if (binding.event.modifiers.shiftKey) continue;   // shift
39799             if (!!binding.capture !== isCapturing) continue;
39800             if (matches(binding, false)) {
39801                 binding.callback();
39802             }
39803         }
39804
39805
39806         function matches(binding, testShift) {
39807             var event$$1 = event;
39808             if (event$$1.key !== undefined) {
39809                 if (binding.event.key === undefined) {
39810                     return false;
39811                 } else if (lodash.isArray(binding.event.key)) {
39812                     if (binding.event.key.map(function(s) { return s.toLowerCase(); }).indexOf(event$$1.key.toLowerCase()) === -1)
39813                         return false;
39814                 } else {
39815                     if (event$$1.key.toLowerCase() !== binding.event.key.toLowerCase())
39816                         return false;
39817                 }
39818             } else {
39819                 // check keycodes if browser doesn't support KeyboardEvent.key
39820                 if (event$$1.keyCode !== binding.event.keyCode)
39821                     return false;
39822             }
39823
39824             // test modifier keys
39825             if (!(event$$1.ctrlKey && event$$1.altKey)) {  // if both are set, assume AltGr and skip it - #4096
39826                 if (event$$1.ctrlKey !== binding.event.modifiers.ctrlKey) return false;
39827                 if (event$$1.altKey !== binding.event.modifiers.altKey) return false;
39828             }
39829             if (event$$1.metaKey !== binding.event.modifiers.metaKey) return false;
39830             if (testShift && event$$1.shiftKey !== binding.event.modifiers.shiftKey) return false;
39831
39832             return true;
39833         }
39834     }
39835
39836
39837     function capture() {
39838         testBindings(true);
39839     }
39840
39841
39842     function bubble() {
39843         var tagName = select(event.target).node().tagName;
39844         if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
39845             return;
39846         }
39847         testBindings(false);
39848     }
39849
39850
39851     function keybinding(selection$$1) {
39852         selection$$1 = selection$$1 || select(document);
39853         selection$$1.on('keydown.capture' + namespace$$1, capture, true);
39854         selection$$1.on('keydown.bubble' + namespace$$1, bubble, false);
39855         return keybinding;
39856     }
39857
39858
39859     keybinding.off = function(selection$$1) {
39860         bindings = [];
39861         selection$$1 = selection$$1 || select(document);
39862         selection$$1.on('keydown.capture' + namespace$$1, null);
39863         selection$$1.on('keydown.bubble' + namespace$$1, null);
39864         return keybinding;
39865     };
39866
39867
39868     keybinding.on = function(codes, callback, capture) {
39869         var arr = [].concat(codes);
39870         for (var i = 0; i < arr.length; i++) {
39871             var code = arr[i];
39872             var binding = {
39873                 event: {
39874                     key: undefined,
39875                     keyCode: 0, // only for browsers that don't support KeyboardEvent.key
39876                     modifiers: {
39877                         shiftKey: false,
39878                         ctrlKey: false,
39879                         altKey: false,
39880                         metaKey: false
39881                     }
39882                 },
39883                 capture: capture,
39884                 callback: callback
39885             };
39886
39887             code = code.toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
39888
39889             for (var j = 0; j < code.length; j++) {
39890                 // Normalise matching errors
39891                 if (code[j] === '++') code[j] = '+';
39892
39893                 if (code[j] in d3keybinding.modifierCodes) {
39894                     binding.event.modifiers[d3keybinding.modifierProperties[d3keybinding.modifierCodes[code[j]]]] = true;
39895                 } else {
39896                     binding.event.key = d3keybinding.keys[code[j]] || code[j];
39897                     if (code[j] in d3keybinding.keyCodes) {
39898                         binding.event.keyCode = d3keybinding.keyCodes[code[j]];
39899                     }
39900                 }
39901             }
39902
39903             bindings.push(binding);
39904         }
39905
39906         return keybinding;
39907     };
39908
39909     return keybinding;
39910 }
39911
39912
39913 d3keybinding.modifierCodes = {
39914     // Shift key, ⇧
39915     '⇧': 16, shift: 16,
39916     // CTRL key, on Mac: ⌃
39917     '⌃': 17, ctrl: 17,
39918     // ALT key, on Mac: ⌥ (Alt)
39919     '⌥': 18, alt: 18, option: 18,
39920     // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
39921     '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
39922 };
39923
39924 d3keybinding.modifierProperties = {
39925     16: 'shiftKey',
39926     17: 'ctrlKey',
39927     18: 'altKey',
39928     91: 'metaKey'
39929 };
39930
39931 d3keybinding.keys = {
39932     // Backspace key, on Mac: ⌫ (Backspace)
39933     '⌫': 'Backspace', backspace: 'Backspace',
39934     // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
39935     '⇥': 'Tab', '⇆': 'Tab', tab: 'Tab',
39936     // Return key, ↩
39937     '↩': 'Enter', 'return': 'Enter', enter: 'Enter', '⌅': 'Enter',
39938     // Pause/Break key
39939     'pause': 'Pause', 'pause-break': 'Pause',
39940     // Caps Lock key, ⇪
39941     '⇪': 'CapsLock', caps: 'CapsLock', 'caps-lock': 'CapsLock',
39942     // Escape key, on Mac: ⎋, on Windows: Esc
39943     '⎋': ['Escape', 'Esc'], escape: ['Escape', 'Esc'], esc: ['Escape', 'Esc'],
39944     // Space key
39945     space: [' ', 'Spacebar'],
39946     // Page-Up key, or pgup, on Mac: ↖
39947     '↖': 'PageUp', pgup: 'PageUp', 'page-up': 'PageUp',
39948     // Page-Down key, or pgdown, on Mac: ↘
39949     '↘': 'PageDown', pgdown: 'PageDown', 'page-down': 'PageDown',
39950     // END key, on Mac: ⇟
39951     '⇟': 'End', end: 'End',
39952     // HOME key, on Mac: ⇞
39953     '⇞': 'Home', home: 'Home',
39954     // Insert key, or ins
39955     ins: 'Insert', insert: 'Insert',
39956     // Delete key, on Mac: ⌦ (Delete)
39957     '⌦': ['Delete', 'Del'], del: ['Delete', 'Del'], 'delete': ['Delete', 'Del'],
39958     // Left Arrow Key, or ←
39959     '←': ['ArrowLeft', 'Left'], left: ['ArrowLeft', 'Left'], 'arrow-left': ['ArrowLeft', 'Left'],
39960     // Up Arrow Key, or ↑
39961     '↑': ['ArrowUp', 'Up'], up: ['ArrowUp', 'Up'], 'arrow-up': ['ArrowUp', 'Up'],
39962     // Right Arrow Key, or →
39963     '→': ['ArrowRight', 'Right'], right: ['ArrowRight', 'Right'], 'arrow-right': ['ArrowRight', 'Right'],
39964     // Up Arrow Key, or ↓
39965     '↓': ['ArrowDown', 'Down'], down: ['ArrowDown', 'Down'], 'arrow-down': ['ArrowDown', 'Down'],
39966     // odities, stuff for backward compatibility (browsers and code):
39967     // Num-Multiply, or *
39968     '*': ['*', 'Multiply'], star: ['*', 'Multiply'], asterisk: ['*', 'Multiply'], multiply: ['*', 'Multiply'],
39969     // Num-Plus or +
39970     '+': ['+', 'Add'], 'plus': ['+', 'Add'],
39971     // Num-Subtract, or -
39972     '-': ['-', 'Subtract'], subtract: ['-', 'Subtract'], 'dash': ['-', 'Subtract'],
39973     // Semicolon
39974     semicolon: ';',
39975     // = or equals
39976     equals: '=',
39977     // Comma, or ,
39978     comma: ',',
39979     // Period, or ., or full-stop
39980     period: '.', 'full-stop': '.',
39981     // Slash, or /, or forward-slash
39982     slash: '/', 'forward-slash': '/',
39983     // Tick, or `, or back-quote
39984     tick: '`', 'back-quote': '`',
39985     // Open bracket, or [
39986     'open-bracket': '[',
39987     // Back slash, or \
39988     'back-slash': '\\',
39989     // Close backet, or ]
39990     'close-bracket': ']',
39991     // Apostrophe, or Quote, or '
39992     quote: '\'', apostrophe: '\'',
39993     // NUMPAD 0-9
39994     'num-0': '0',
39995     'num-1': '1',
39996     'num-2': '2',
39997     'num-3': '3',
39998     'num-4': '4',
39999     'num-5': '5',
40000     'num-6': '6',
40001     'num-7': '7',
40002     'num-8': '8',
40003     'num-9': '9',
40004     // F1-F25
40005     f1: 'F1',
40006     f2: 'F2',
40007     f3: 'F3',
40008     f4: 'F4',
40009     f5: 'F5',
40010     f6: 'F6',
40011     f7: 'F7',
40012     f8: 'F8',
40013     f9: 'F9',
40014     f10: 'F10',
40015     f11: 'F11',
40016     f12: 'F12',
40017     f13: 'F13',
40018     f14: 'F14',
40019     f15: 'F15',
40020     f16: 'F16',
40021     f17: 'F17',
40022     f18: 'F18',
40023     f19: 'F19',
40024     f20: 'F20',
40025     f21: 'F21',
40026     f22: 'F22',
40027     f23: 'F23',
40028     f24: 'F24',
40029     f25: 'F25'
40030 };
40031
40032 d3keybinding.keyCodes = {
40033     // Backspace key, on Mac: ⌫ (Backspace)
40034     '⌫': 8, backspace: 8,
40035     // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
40036     '⇥': 9, '⇆': 9, tab: 9,
40037     // Return key, ↩
40038     '↩': 13, 'return': 13, enter: 13, '⌅': 13,
40039     // Pause/Break key
40040     'pause': 19, 'pause-break': 19,
40041     // Caps Lock key, ⇪
40042     '⇪': 20, caps: 20, 'caps-lock': 20,
40043     // Escape key, on Mac: ⎋, on Windows: Esc
40044     '⎋': 27, escape: 27, esc: 27,
40045     // Space key
40046     space: 32,
40047     // Page-Up key, or pgup, on Mac: ↖
40048     '↖': 33, pgup: 33, 'page-up': 33,
40049     // Page-Down key, or pgdown, on Mac: ↘
40050     '↘': 34, pgdown: 34, 'page-down': 34,
40051     // END key, on Mac: ⇟
40052     '⇟': 35, end: 35,
40053     // HOME key, on Mac: ⇞
40054     '⇞': 36, home: 36,
40055     // Insert key, or ins
40056     ins: 45, insert: 45,
40057     // Delete key, on Mac: ⌦ (Delete)
40058     '⌦': 46, del: 46, 'delete': 46,
40059     // Left Arrow Key, or ←
40060     '←': 37, left: 37, 'arrow-left': 37,
40061     // Up Arrow Key, or ↑
40062     '↑': 38, up: 38, 'arrow-up': 38,
40063     // Right Arrow Key, or →
40064     '→': 39, right: 39, 'arrow-right': 39,
40065     // Up Arrow Key, or ↓
40066     '↓': 40, down: 40, 'arrow-down': 40,
40067     // odities, printing characters that come out wrong:
40068     // Firefox Equals
40069     'ffequals': 61,
40070     // Num-Multiply, or *
40071     '*': 106, star: 106, asterisk: 106, multiply: 106,
40072     // Num-Plus or +
40073     '+': 107, 'plus': 107,
40074     // Num-Subtract, or -
40075     '-': 109, subtract: 109,
40076     // Firefox Plus
40077     'ffplus': 171,
40078     // Firefox Minus
40079     'ffminus': 173,
40080     // Semicolon
40081     ';': 186, semicolon: 186,
40082     // = or equals
40083     '=': 187, 'equals': 187,
40084     // Comma, or ,
40085     ',': 188, comma: 188,
40086     // Dash / Underscore key
40087     'dash': 189,
40088     // Period, or ., or full-stop
40089     '.': 190, period: 190, 'full-stop': 190,
40090     // Slash, or /, or forward-slash
40091     '/': 191, slash: 191, 'forward-slash': 191,
40092     // Tick, or `, or back-quote
40093     '`': 192, tick: 192, 'back-quote': 192,
40094     // Open bracket, or [
40095     '[': 219, 'open-bracket': 219,
40096     // Back slash, or \
40097     '\\': 220, 'back-slash': 220,
40098     // Close backet, or ]
40099     ']': 221, 'close-bracket': 221,
40100     // Apostrophe, or Quote, or '
40101     '\'': 222, quote: 222, apostrophe: 222
40102 };
40103
40104 // NUMPAD 0-9
40105 var i$1 = 95;
40106 var n = 0;
40107 while (++i$1 < 106) {
40108     d3keybinding.keyCodes['num-' + n] = i$1;
40109     ++n;
40110 }
40111
40112 // 0-9
40113 i$1 = 47; n = 0;
40114 while (++i$1 < 58) {
40115     d3keybinding.keyCodes[n] = i$1;
40116     ++n;
40117 }
40118
40119 // F1-F25
40120 i$1 = 111; n = 1;
40121 while (++i$1 < 136) {
40122     d3keybinding.keyCodes['f' + n] = i$1;
40123     ++n;
40124 }
40125
40126 // a-z
40127 i$1 = 64;
40128 while (++i$1 < 91) {
40129     d3keybinding.keyCodes[String.fromCharCode(i$1).toLowerCase()] = i$1;
40130 }
40131
40132 function tooltip() {
40133   var tooltip = function(selection$$1) {
40134       selection$$1.each(setup);
40135     },
40136     animation = utilFunctor(false),
40137     html$$1 = utilFunctor(false),
40138     title = function() {
40139       var title = this.getAttribute('data-original-title');
40140       if (title) {
40141         return title;
40142       } else {
40143         title = this.getAttribute('title');
40144         this.removeAttribute('title');
40145         this.setAttribute('data-original-title', title);
40146       }
40147       return title;
40148     },
40149     over = 'mouseenter.tooltip',
40150     out = 'mouseleave.tooltip',
40151     placement = utilFunctor('top');
40152
40153
40154   tooltip.title = function(_) {
40155     if (arguments.length) {
40156       title = utilFunctor(_);
40157       return tooltip;
40158     } else {
40159       return title;
40160     }
40161   };
40162
40163
40164   tooltip.html = function(_) {
40165     if (arguments.length) {
40166       html$$1 = utilFunctor(_);
40167       return tooltip;
40168     } else {
40169       return html$$1;
40170     }
40171   };
40172
40173
40174   tooltip.placement = function(_) {
40175     if (arguments.length) {
40176       placement = utilFunctor(_);
40177       return tooltip;
40178     } else {
40179       return placement;
40180     }
40181   };
40182
40183
40184   tooltip.show = function(selection$$1) {
40185     selection$$1.each(show);
40186   };
40187
40188
40189   tooltip.hide = function(selection$$1) {
40190     selection$$1.each(hide);
40191   };
40192
40193
40194   tooltip.toggle = function(selection$$1) {
40195     selection$$1.each(toggle);
40196   };
40197
40198
40199   tooltip.destroy = function(selection$$1) {
40200     selection$$1
40201       .on(over, null)
40202       .on(out, null)
40203       .attr('title', function() {
40204         return this.getAttribute('data-original-title') || this.getAttribute('title');
40205       })
40206       .attr('data-original-title', null)
40207       .selectAll('.tooltip')
40208       .remove();
40209   };
40210
40211
40212   function setup() {
40213     var root = select(this),
40214         animate = animation.apply(this, arguments),
40215         tip = root.selectAll('.tooltip').data([0]);
40216
40217     var enter = tip.enter()
40218       .append('div')
40219       .attr('class', 'tooltip');
40220
40221     enter
40222       .append('div')
40223       .attr('class', 'tooltip-arrow');
40224
40225     enter
40226       .append('div')
40227       .attr('class', 'tooltip-inner');
40228
40229     tip = enter
40230       .merge(tip);
40231
40232     if (animate) {
40233       tip.classed('fade', true);
40234     }
40235
40236     var place = placement.apply(this, arguments);
40237     tip.classed(place, true);
40238
40239     root.on(over, show);
40240     root.on(out, hide);
40241   }
40242
40243
40244   function show() {
40245     var root = select(this),
40246       content = title.apply(this, arguments),
40247       tip = root.selectAll('.tooltip')
40248         .classed('in', true),
40249       markup = html$$1.apply(this, arguments);
40250
40251     tip.selectAll('.tooltip-inner')[markup ? 'html' : 'text'](content);
40252     var place = placement.apply(this, arguments),
40253       outer = getPosition(root.node()),
40254       inner = getPosition(tip.node()),
40255       pos;
40256
40257     switch (place) {
40258       case 'top':
40259         pos = {x: outer.x + (outer.w - inner.w) / 2, y: outer.y - inner.h};
40260         break;
40261       case 'right':
40262         pos = {x: outer.x + outer.w, y: outer.y + (outer.h - inner.h) / 2};
40263         break;
40264       case 'left':
40265         pos = {x: outer.x - inner.w, y: outer.y + (outer.h - inner.h) / 2};
40266         break;
40267       case 'bottom':
40268         pos = {x: Math.max(0, outer.x + (outer.w - inner.w) / 2), y: outer.y + outer.h};
40269         break;
40270     }
40271
40272     if (pos) {
40273       tip.style('left', ~~pos.x + 'px').style('top', ~~pos.y + 'px');
40274     } else {
40275       tip.style('left', null).style('top', null);
40276     }
40277
40278     this.tooltipVisible = true;
40279   }
40280
40281
40282   function hide() {
40283     select(this).selectAll('.tooltip')
40284       .classed('in', false);
40285
40286     this.tooltipVisible = false;
40287   }
40288
40289
40290   function toggle() {
40291     if (this.tooltipVisible) {
40292       hide.apply(this, arguments);
40293     } else {
40294       show.apply(this, arguments);
40295     }
40296   }
40297
40298   return tooltip;
40299 }
40300
40301
40302 function getPosition(node) {
40303   var mode = select(node).style('position');
40304   if (mode === 'absolute' || mode === 'static') {
40305     return {
40306       x: node.offsetLeft,
40307       y: node.offsetTop,
40308       w: node.offsetWidth,
40309       h: node.offsetHeight
40310     };
40311   } else {
40312     return {
40313       x: 0,
40314       y: 0,
40315       w: node.offsetWidth,
40316       h: node.offsetHeight
40317     };
40318   }
40319 }
40320
40321 function svgAreas$$1(projection$$1, context) {
40322     // Patterns only work in Firefox when set directly on element.
40323     // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
40324     var patterns = {
40325         beach: 'beach',
40326         cemetery: 'cemetery',
40327         construction: 'construction',
40328         farm: 'farmland',
40329         farmland: 'farmland',
40330         grave_yard: 'cemetery',
40331         meadow: 'meadow',
40332         military: 'construction',
40333         orchard: 'orchard',
40334         sand: 'beach',
40335         scrub: 'scrub',
40336         wetland: 'wetland',
40337     };
40338
40339     var patternKeys = ['landuse', 'natural', 'amenity'];
40340
40341
40342     function setPattern(d) {
40343         for (var i = 0; i < patternKeys.length; i++) {
40344             if (d.tags.building && d.tags.building !== 'no') continue;
40345
40346             if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
40347                 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
40348                 return;
40349             }
40350         }
40351         this.style.fill = this.style.stroke = '';
40352     }
40353
40354
40355     return function drawAreas(selection$$1, graph, entities, filter) {
40356         var path$$1 = svgPath(projection$$1, graph, true),
40357             areas = {},
40358             multipolygon;
40359
40360         for (var i = 0; i < entities.length; i++) {
40361             var entity = entities[i];
40362             if (entity.geometry(graph) !== 'area') continue;
40363
40364             multipolygon = osmIsSimpleMultipolygonOuterMember(entity, graph);
40365             if (multipolygon) {
40366                 areas[multipolygon.id] = {
40367                     entity: multipolygon.mergeTags(entity.tags),
40368                     area: Math.abs(entity.area(graph))
40369                 };
40370             } else if (!areas[entity.id]) {
40371                 areas[entity.id] = {
40372                     entity: entity,
40373                     area: Math.abs(entity.area(graph))
40374                 };
40375             }
40376         }
40377
40378         areas = values(areas).filter(function hasPath(a) { return path$$1(a.entity); });
40379         areas.sort(function areaSort(a, b) { return b.area - a.area; });
40380         areas = lodash.map(areas, 'entity');
40381
40382         var strokes = areas.filter(function(area$$1) {
40383             return area$$1.type === 'way';
40384         });
40385
40386         var data = {
40387             clip: areas,
40388             shadow: strokes,
40389             stroke: strokes,
40390             fill: areas
40391         };
40392
40393         var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath')
40394            .filter(filter)
40395            .data(data.clip, osmEntity$$1.key);
40396
40397         clipPaths.exit()
40398            .remove();
40399
40400         var clipPathsEnter = clipPaths.enter()
40401            .append('clipPath')
40402            .attr('class', 'clipPath')
40403            .attr('id', function(entity) { return entity.id + '-clippath'; });
40404
40405         clipPathsEnter
40406            .append('path');
40407
40408         clipPaths.merge(clipPathsEnter)
40409            .selectAll('path')
40410            .attr('d', path$$1);
40411
40412
40413         var layer = selection$$1.selectAll('.layer-areas');
40414
40415         var areagroup = layer
40416             .selectAll('g.areagroup')
40417             .data(['fill', 'shadow', 'stroke']);
40418
40419         areagroup = areagroup.enter()
40420             .append('g')
40421             .attr('class', function(d) { return 'areagroup area-' + d; })
40422             .merge(areagroup);
40423
40424         var paths = areagroup
40425             .selectAll('path')
40426             .filter(filter)
40427             .data(function(layer) { return data[layer]; }, osmEntity$$1.key);
40428
40429         paths.exit()
40430             .remove();
40431
40432         var fills = selection$$1.selectAll('.area-fill path.area').nodes();
40433
40434         var bisect = bisector(function(node) {
40435             return -node.__data__.area(graph);
40436         }).left;
40437
40438         function sortedByArea(entity) {
40439             if (this._parent.__data__ === 'fill') {
40440                 return fills[bisect(fills, -entity.area(graph))];
40441             }
40442         }
40443
40444         paths = paths.enter()
40445             .insert('path', sortedByArea)
40446             .merge(paths)
40447             .each(function(entity) {
40448                 var layer = this.parentNode.__data__;
40449
40450                 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
40451
40452                 if (layer === 'fill') {
40453                     this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
40454                     setPattern.apply(this, arguments);
40455                 }
40456             })
40457             .call(svgTagClasses())
40458             .attr('d', path$$1);
40459     };
40460 }
40461
40462 function svgDebug(projection$$1, context) {
40463
40464     function multipolygons(imagery) {
40465         return imagery.map(function(data$$1) {
40466             return {
40467                 type: 'MultiPolygon',
40468                 coordinates: [ data$$1.polygon ]
40469             };
40470         });
40471     }
40472
40473     function drawDebug(selection$$1) {
40474         var showsTile = context.getDebug('tile'),
40475             showsCollision = context.getDebug('collision'),
40476             showsImagery = context.getDebug('imagery'),
40477             showsImperial = context.getDebug('imperial'),
40478             showsDriveLeft = context.getDebug('driveLeft'),
40479             path$$1 = index$4(projection$$1);
40480
40481
40482         var debugData = [];
40483         if (showsTile) {
40484             debugData.push({ class: 'red', label: 'tile' });
40485         }
40486         if (showsCollision) {
40487             debugData.push({ class: 'yellow', label: 'collision' });
40488         }
40489         if (showsImagery) {
40490             debugData.push({ class: 'orange', label: 'imagery' });
40491         }
40492         if (showsImperial) {
40493             debugData.push({ class: 'cyan', label: 'imperial' });
40494         }
40495         if (showsDriveLeft) {
40496             debugData.push({ class: 'green', label: 'driveLeft' });
40497         }
40498
40499
40500         var legend = select('#content')
40501             .selectAll('.debug-legend')
40502             .data(debugData.length ? [0] : []);
40503
40504         legend.exit()
40505             .remove();
40506
40507         legend = legend.enter()
40508             .append('div')
40509             .attr('class', 'fillD debug-legend')
40510             .merge(legend);
40511
40512
40513         var legendItems = legend.selectAll('.debug-legend-item')
40514             .data(debugData, function(d) { return d.label; });
40515
40516         legendItems.exit()
40517             .remove();
40518
40519         legendItems.enter()
40520             .append('span')
40521             .attr('class', function(d) { return 'debug-legend-item ' + d.class; })
40522             .text(function(d) { return d.label; });
40523
40524
40525         var layer = selection$$1.selectAll('.layer-debug')
40526             .data(showsImagery || showsImperial || showsDriveLeft ? [0] : []);
40527
40528         layer.exit()
40529             .remove();
40530
40531         layer = layer.enter()
40532             .append('g')
40533             .attr('class', 'layer-debug')
40534             .merge(layer);
40535
40536
40537         var extent$$1 = context.map().extent(),
40538             dataImagery = data.imagery || [],
40539             availableImagery = showsImagery && multipolygons(dataImagery.filter(function(source) {
40540                 if (!source.polygon) return false;
40541                 return source.polygon.some(function(polygon) {
40542                     return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
40543                 });
40544             }));
40545
40546         var imagery = layer.selectAll('path.debug-imagery')
40547             .data(showsImagery ? availableImagery : []);
40548
40549         imagery.exit()
40550             .remove();
40551
40552         imagery.enter()
40553             .append('path')
40554             .attr('class', 'debug-imagery debug orange');
40555
40556
40557         var imperial = layer
40558             .selectAll('path.debug-imperial')
40559             .data(showsImperial ? [dataImperial] : []);
40560
40561         imperial.exit()
40562             .remove();
40563
40564         imperial.enter()
40565             .append('path')
40566             .attr('class', 'debug-imperial debug cyan');
40567
40568
40569         var driveLeft = layer
40570             .selectAll('path.debug-drive-left')
40571             .data(showsDriveLeft ? [dataDriveLeft] : []);
40572
40573         driveLeft.exit()
40574             .remove();
40575
40576         driveLeft.enter()
40577             .append('path')
40578             .attr('class', 'debug-drive-left debug green');
40579
40580
40581         // update
40582         layer.selectAll('path')
40583             .attr('d', path$$1);
40584     }
40585
40586
40587     // This looks strange because `enabled` methods on other layers are
40588     // chainable getter/setters, and this one is just a getter.
40589     drawDebug.enabled = function() {
40590         if (!arguments.length) {
40591             return context.getDebug('tile') ||
40592                 context.getDebug('collision') ||
40593                 context.getDebug('imagery') ||
40594                 context.getDebug('imperial') ||
40595                 context.getDebug('driveLeft');
40596         } else {
40597             return this;
40598         }
40599     };
40600
40601
40602     return drawDebug;
40603 }
40604
40605 /*
40606     A standalone SVG element that contains only a `defs` sub-element. To be
40607     used once globally, since defs IDs must be unique within a document.
40608 */
40609 function svgDefs(context) {
40610
40611     function SVGSpriteDefinition(id, href) {
40612         return function(defs) {
40613             request(href)
40614                 .mimeType('image/svg+xml')
40615                 .response(function(xhr) { return xhr.responseXML; })
40616                 .get(function(err, svg) {
40617                     if (err) return;
40618                     defs.node().appendChild(
40619                         select(svg.documentElement).attr('id', id).node()
40620                     );
40621                 });
40622         };
40623     }
40624
40625
40626     return function drawDefs(selection$$1) {
40627         var defs = selection$$1.append('defs');
40628
40629         // marker
40630         defs.append('marker')
40631             .attr('id', 'oneway-marker')
40632             .attr('viewBox', '0 0 10 10')
40633             .attr('refY', 2.5)
40634             .attr('refX', 5)
40635             .attr('markerWidth', 2)
40636             .attr('markerHeight', 2)
40637             .attr('markerUnits', 'strokeWidth')
40638             .attr('orient', 'auto')
40639
40640             .append('path')
40641             .attr('class', 'oneway')
40642             .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')
40643             .attr('stroke', 'none')
40644             .attr('fill', '#000')
40645             .attr('opacity', '0.75');
40646
40647         // patterns
40648         var patterns = defs.selectAll('pattern')
40649             .data([
40650                 // pattern name, pattern image name
40651                 ['wetland', 'wetland'],
40652                 ['construction', 'construction'],
40653                 ['cemetery', 'cemetery'],
40654                 ['orchard', 'orchard'],
40655                 ['farmland', 'farmland'],
40656                 ['beach', 'dots'],
40657                 ['scrub', 'dots'],
40658                 ['meadow', 'dots']
40659             ])
40660             .enter()
40661             .append('pattern')
40662             .attr('id', function (d) {
40663                 return 'pattern-' + d[0];
40664             })
40665             .attr('width', 32)
40666             .attr('height', 32)
40667             .attr('patternUnits', 'userSpaceOnUse');
40668
40669         patterns.append('rect')
40670             .attr('x', 0)
40671             .attr('y', 0)
40672             .attr('width', 32)
40673             .attr('height', 32)
40674             .attr('class', function (d) {
40675                     return 'pattern-color-' + d[0];
40676             });
40677
40678         patterns.append('image')
40679             .attr('x', 0)
40680             .attr('y', 0)
40681             .attr('width', 32)
40682             .attr('height', 32)
40683             .attr('xlink:href', function (d) {
40684                 return context.imagePath('pattern/' + d[1] + '.png');
40685             });
40686
40687         // clip paths
40688         defs.selectAll()
40689             .data([12, 18, 20, 32, 45])
40690             .enter()
40691             .append('clipPath')
40692             .attr('id', function (d) {
40693                 return 'clip-square-' + d;
40694             })
40695             .append('rect')
40696             .attr('x', 0)
40697             .attr('y', 0)
40698             .attr('width', function (d) {
40699                 return d;
40700             })
40701             .attr('height', function (d) {
40702                 return d;
40703             });
40704
40705         defs.call(SVGSpriteDefinition(
40706             'iD-sprite',
40707             context.imagePath('iD-sprite.svg')));
40708
40709         defs.call(SVGSpriteDefinition(
40710             'maki-sprite',
40711             context.imagePath('maki-sprite.svg')));
40712     };
40713 }
40714
40715 //[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]
40716 //[4a]          NameChar           ::=          NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
40717 //[5]           Name       ::=          NameStartChar (NameChar)*
40718 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
40719 var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
40720 var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
40721 //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
40722 //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(',')
40723
40724 //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
40725 //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
40726 var S_TAG = 0;//tag name offerring
40727 var S_ATTR = 1;//attr name offerring 
40728 var S_ATTR_SPACE=2;//attr name end and space offer
40729 var S_EQ = 3;//=space?
40730 var S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only)
40731 var S_ATTR_END = 5;//attr value end and no space(quot end)
40732 var S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer)
40733 var S_TAG_CLOSE = 7;//closed el<el />
40734
40735 function XMLReader(){
40736         
40737 }
40738
40739 XMLReader.prototype = {
40740         parse:function(source,defaultNSMap,entityMap){
40741                 var domBuilder = this.domBuilder;
40742                 domBuilder.startDocument();
40743                 _copy(defaultNSMap ,defaultNSMap = {});
40744                 parse(source,defaultNSMap,entityMap,
40745                                 domBuilder,this.errorHandler);
40746                 domBuilder.endDocument();
40747         }
40748 };
40749 function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
40750         function fixedFromCharCode(code) {
40751                 // String.prototype.fromCharCode does not supports
40752                 // > 2 bytes unicode chars directly
40753                 if (code > 0xffff) {
40754                         code -= 0x10000;
40755                         var surrogate1 = 0xd800 + (code >> 10)
40756                                 , surrogate2 = 0xdc00 + (code & 0x3ff);
40757
40758                         return String.fromCharCode(surrogate1, surrogate2);
40759                 } else {
40760                         return String.fromCharCode(code);
40761                 }
40762         }
40763         function entityReplacer(a){
40764                 var k = a.slice(1,-1);
40765                 if(k in entityMap){
40766                         return entityMap[k]; 
40767                 }else if(k.charAt(0) === '#'){
40768                         return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))
40769                 }else{
40770                         errorHandler.error('entity not found:'+a);
40771                         return a;
40772                 }
40773         }
40774         function appendText(end){//has some bugs
40775                 if(end>start){
40776                         var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer);
40777                         locator&&position(start);
40778                         domBuilder.characters(xt,0,end-start);
40779                         start = end;
40780                 }
40781         }
40782         function position(p,m){
40783                 while(p>=lineEnd && (m = linePattern.exec(source))){
40784                         lineStart = m.index;
40785                         lineEnd = lineStart + m[0].length;
40786                         locator.lineNumber++;
40787                         //console.log('line++:',locator,startPos,endPos)
40788                 }
40789                 locator.columnNumber = p-lineStart+1;
40790         }
40791         var lineStart = 0;
40792         var lineEnd = 0;
40793         var linePattern = /.*(?:\r\n?|\n)|.*$/g;
40794         var locator = domBuilder.locator;
40795         
40796         var parseStack = [{currentNSMap:defaultNSMapCopy}];
40797         var closeMap = {};
40798         var start = 0;
40799         while(true){
40800                 try{
40801                         var tagStart = source.indexOf('<',start);
40802                         if(tagStart<0){
40803                                 if(!source.substr(start).match(/^\s*$/)){
40804                                         var doc = domBuilder.doc;
40805                                 var text = doc.createTextNode(source.substr(start));
40806                                 doc.appendChild(text);
40807                                 domBuilder.currentElement = text;
40808                                 }
40809                                 return;
40810                         }
40811                         if(tagStart>start){
40812                                 appendText(tagStart);
40813                         }
40814                         switch(source.charAt(tagStart+1)){
40815                         case '/':
40816                                 var end = source.indexOf('>',tagStart+3);
40817                                 var tagName = source.substring(tagStart+2,end);
40818                                 var config = parseStack.pop();
40819                                 if(end<0){
40820                                         
40821                                 tagName = source.substring(tagStart+2).replace(/[\s<].*/,'');
40822                                 //console.error('#@@@@@@'+tagName)
40823                                 errorHandler.error("end tag name: "+tagName+' is not complete:'+config.tagName);
40824                                 end = tagStart+1+tagName.length;
40825                         }else if(tagName.match(/\s</)){
40826                                 tagName = tagName.replace(/[\s<].*/,'');
40827                                 errorHandler.error("end tag name: "+tagName+' maybe not complete');
40828                                 end = tagStart+1+tagName.length;
40829                                 }
40830                                 //console.error(parseStack.length,parseStack)
40831                                 //console.error(config);
40832                                 var localNSMap = config.localNSMap;
40833                                 var endMatch = config.tagName == tagName;
40834                                 var endIgnoreCaseMach = endMatch || config.tagName&&config.tagName.toLowerCase() == tagName.toLowerCase();
40835                         if(endIgnoreCaseMach){
40836                                 domBuilder.endElement(config.uri,config.localName,tagName);
40837                                         if(localNSMap){
40838                                                 for(var prefix in localNSMap){
40839                                                         domBuilder.endPrefixMapping(prefix) ;
40840                                                 }
40841                                         }
40842                                         if(!endMatch){
40843                                 errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName );
40844                                         }
40845                         }else{
40846                                 parseStack.push(config);
40847                         }
40848                                 
40849                                 end++;
40850                                 break;
40851                                 // end elment
40852                         case '?':// <?...?>
40853                                 locator&&position(tagStart);
40854                                 end = parseInstruction(source,tagStart,domBuilder);
40855                                 break;
40856                         case '!':// <!doctype,<![CDATA,<!--
40857                                 locator&&position(tagStart);
40858                                 end = parseDCC(source,tagStart,domBuilder,errorHandler);
40859                                 break;
40860                         default:
40861                                 locator&&position(tagStart);
40862                                 var el = new ElementAttributes();
40863                                 var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
40864                                 //elStartEnd
40865                                 var end = parseElementStartPart(source,tagStart,el,currentNSMap,entityReplacer,errorHandler);
40866                                 var len = el.length;
40867                                 
40868                                 
40869                                 if(!el.closed && fixSelfClosed(source,end,el.tagName,closeMap)){
40870                                         el.closed = true;
40871                                         if(!entityMap.nbsp){
40872                                                 errorHandler.warning('unclosed xml attribute');
40873                                         }
40874                                 }
40875                                 if(locator && len){
40876                                         var locator2 = copyLocator(locator,{});
40877                                         //try{//attribute position fixed
40878                                         for(var i = 0;i<len;i++){
40879                                                 var a = el[i];
40880                                                 position(a.offset);
40881                                                 a.locator = copyLocator(locator,{});
40882                                         }
40883                                         //}catch(e){console.error('@@@@@'+e)}
40884                                         domBuilder.locator = locator2;
40885                                         if(appendElement(el,domBuilder,currentNSMap)){
40886                                                 parseStack.push(el);
40887                                         }
40888                                         domBuilder.locator = locator;
40889                                 }else{
40890                                         if(appendElement(el,domBuilder,currentNSMap)){
40891                                                 parseStack.push(el);
40892                                         }
40893                                 }
40894                                 
40895                                 
40896                                 
40897                                 if(el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed){
40898                                         end = parseHtmlSpecialContent(source,end,el.tagName,entityReplacer,domBuilder);
40899                                 }else{
40900                                         end++;
40901                                 }
40902                         }
40903                 }catch(e){
40904                         errorHandler.error('element parse error: '+e);
40905                         //errorHandler.error('element parse error: '+e);
40906                         end = -1;
40907                         //throw e;
40908                 }
40909                 if(end>start){
40910                         start = end;
40911                 }else{
40912                         //TODO: 这里有可能sax回退,有位置错误风险
40913                         appendText(Math.max(tagStart,start)+1);
40914                 }
40915         }
40916 }
40917 function copyLocator(f,t){
40918         t.lineNumber = f.lineNumber;
40919         t.columnNumber = f.columnNumber;
40920         return t;
40921 }
40922
40923 /**
40924  * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
40925  * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
40926  */
40927 function parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){
40928         var attrName;
40929         var value;
40930         var p = ++start;
40931         var s = S_TAG;//status
40932         while(true){
40933                 var c = source.charAt(p);
40934                 switch(c){
40935                 case '=':
40936                         if(s === S_ATTR){//attrName
40937                                 attrName = source.slice(start,p);
40938                                 s = S_EQ;
40939                         }else if(s === S_ATTR_SPACE){
40940                                 s = S_EQ;
40941                         }else{
40942                                 //fatalError: equal must after attrName or space after attrName
40943                                 throw new Error('attribute equal must after attrName');
40944                         }
40945                         break;
40946                 case '\'':
40947                 case '"':
40948                         if(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
40949                                 ){//equal
40950                                 if(s === S_ATTR){
40951                                         errorHandler.warning('attribute value must after "="');
40952                                         attrName = source.slice(start,p);
40953                                 }
40954                                 start = p+1;
40955                                 p = source.indexOf(c,start);
40956                                 if(p>0){
40957                                         value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
40958                                         el.add(attrName,value,start-1);
40959                                         s = S_ATTR_END;
40960                                 }else{
40961                                         //fatalError: no end quot match
40962                                         throw new Error('attribute value no end \''+c+'\' match');
40963                                 }
40964                         }else if(s == S_ATTR_NOQUOT_VALUE){
40965                                 value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
40966                                 //console.log(attrName,value,start,p)
40967                                 el.add(attrName,value,start);
40968                                 //console.dir(el)
40969                                 errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!');
40970                                 start = p+1;
40971                                 s = S_ATTR_END;
40972                         }else{
40973                                 //fatalError: no equal before
40974                                 throw new Error('attribute value must after "="');
40975                         }
40976                         break;
40977                 case '/':
40978                         switch(s){
40979                         case S_TAG:
40980                                 el.setTagName(source.slice(start,p));
40981                         case S_ATTR_END:
40982                         case S_TAG_SPACE:
40983                         case S_TAG_CLOSE:
40984                                 s =S_TAG_CLOSE;
40985                                 el.closed = true;
40986                         case S_ATTR_NOQUOT_VALUE:
40987                         case S_ATTR:
40988                         case S_ATTR_SPACE:
40989                                 break;
40990                         //case S_EQ:
40991                         default:
40992                                 throw new Error("attribute invalid close char('/')")
40993                         }
40994                         break;
40995                 case ''://end document
40996                         //throw new Error('unexpected end of input')
40997                         errorHandler.error('unexpected end of input');
40998                         if(s == S_TAG){
40999                                 el.setTagName(source.slice(start,p));
41000                         }
41001                         return p;
41002                 case '>':
41003                         switch(s){
41004                         case S_TAG:
41005                                 el.setTagName(source.slice(start,p));
41006                         case S_ATTR_END:
41007                         case S_TAG_SPACE:
41008                         case S_TAG_CLOSE:
41009                                 break;//normal
41010                         case S_ATTR_NOQUOT_VALUE://Compatible state
41011                         case S_ATTR:
41012                                 value = source.slice(start,p);
41013                                 if(value.slice(-1) === '/'){
41014                                         el.closed  = true;
41015                                         value = value.slice(0,-1);
41016                                 }
41017                         case S_ATTR_SPACE:
41018                                 if(s === S_ATTR_SPACE){
41019                                         value = attrName;
41020                                 }
41021                                 if(s == S_ATTR_NOQUOT_VALUE){
41022                                         errorHandler.warning('attribute "'+value+'" missed quot(")!!');
41023                                         el.add(attrName,value.replace(/&#?\w+;/g,entityReplacer),start);
41024                                 }else{
41025                                         if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)){
41026                                                 errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!');
41027                                         }
41028                                         el.add(value,value,start);
41029                                 }
41030                                 break;
41031                         case S_EQ:
41032                                 throw new Error('attribute value missed!!');
41033                         }
41034 //                      console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
41035                         return p;
41036                 /*xml space '\x20' | #x9 | #xD | #xA; */
41037                 case '\u0080':
41038                         c = ' ';
41039                 default:
41040                         if(c<= ' '){//space
41041                                 switch(s){
41042                                 case S_TAG:
41043                                         el.setTagName(source.slice(start,p));//tagName
41044                                         s = S_TAG_SPACE;
41045                                         break;
41046                                 case S_ATTR:
41047                                         attrName = source.slice(start,p);
41048                                         s = S_ATTR_SPACE;
41049                                         break;
41050                                 case S_ATTR_NOQUOT_VALUE:
41051                                         var value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
41052                                         errorHandler.warning('attribute "'+value+'" missed quot(")!!');
41053                                         el.add(attrName,value,start);
41054                                 case S_ATTR_END:
41055                                         s = S_TAG_SPACE;
41056                                         break;
41057                                 //case S_TAG_SPACE:
41058                                 //case S_EQ:
41059                                 //case S_ATTR_SPACE:
41060                                 //      void();break;
41061                                 //case S_TAG_CLOSE:
41062                                         //ignore warning
41063                                 }
41064                         }else{//not space
41065 //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
41066 //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
41067                                 switch(s){
41068                                 //case S_TAG:void();break;
41069                                 //case S_ATTR:void();break;
41070                                 //case S_ATTR_NOQUOT_VALUE:void();break;
41071                                 case S_ATTR_SPACE:
41072                                         var tagName =  el.tagName;
41073                                         if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)){
41074                                                 errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead2!!');
41075                                         }
41076                                         el.add(attrName,attrName,start);
41077                                         start = p;
41078                                         s = S_ATTR;
41079                                         break;
41080                                 case S_ATTR_END:
41081                                         errorHandler.warning('attribute space is required"'+attrName+'"!!');
41082                                 case S_TAG_SPACE:
41083                                         s = S_ATTR;
41084                                         start = p;
41085                                         break;
41086                                 case S_EQ:
41087                                         s = S_ATTR_NOQUOT_VALUE;
41088                                         start = p;
41089                                         break;
41090                                 case S_TAG_CLOSE:
41091                                         throw new Error("elements closed character '/' and '>' must be connected to");
41092                                 }
41093                         }
41094                 }//end outer switch
41095                 //console.log('p++',p)
41096                 p++;
41097         }
41098 }
41099 /**
41100  * @return true if has new namespace define
41101  */
41102 function appendElement(el,domBuilder,currentNSMap){
41103         var tagName = el.tagName;
41104         var localNSMap = null;
41105         //var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
41106         var i = el.length;
41107         while(i--){
41108                 var a = el[i];
41109                 var qName = a.qName;
41110                 var value = a.value;
41111                 var nsp = qName.indexOf(':');
41112                 if(nsp>0){
41113                         var prefix = a.prefix = qName.slice(0,nsp);
41114                         var localName = qName.slice(nsp+1);
41115                         var nsPrefix = prefix === 'xmlns' && localName;
41116                 }else{
41117                         localName = qName;
41118                         prefix = null;
41119                         nsPrefix = qName === 'xmlns' && '';
41120                 }
41121                 //can not set prefix,because prefix !== ''
41122                 a.localName = localName ;
41123                 //prefix == null for no ns prefix attribute 
41124                 if(nsPrefix !== false){//hack!!
41125                         if(localNSMap == null){
41126                                 localNSMap = {};
41127                                 //console.log(currentNSMap,0)
41128                                 _copy(currentNSMap,currentNSMap={});
41129                                 //console.log(currentNSMap,1)
41130                         }
41131                         currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
41132                         a.uri = 'http://www.w3.org/2000/xmlns/';
41133                         domBuilder.startPrefixMapping(nsPrefix, value); 
41134                 }
41135         }
41136         var i = el.length;
41137         while(i--){
41138                 a = el[i];
41139                 var prefix = a.prefix;
41140                 if(prefix){//no prefix attribute has no namespace
41141                         if(prefix === 'xml'){
41142                                 a.uri = 'http://www.w3.org/XML/1998/namespace';
41143                         }if(prefix !== 'xmlns'){
41144                                 a.uri = currentNSMap[prefix || ''];
41145                                 
41146                                 //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
41147                         }
41148                 }
41149         }
41150         var nsp = tagName.indexOf(':');
41151         if(nsp>0){
41152                 prefix = el.prefix = tagName.slice(0,nsp);
41153                 localName = el.localName = tagName.slice(nsp+1);
41154         }else{
41155                 prefix = null;//important!!
41156                 localName = el.localName = tagName;
41157         }
41158         //no prefix element has default namespace
41159         var ns = el.uri = currentNSMap[prefix || ''];
41160         domBuilder.startElement(ns,localName,tagName,el);
41161         //endPrefixMapping and startPrefixMapping have not any help for dom builder
41162         //localNSMap = null
41163         if(el.closed){
41164                 domBuilder.endElement(ns,localName,tagName);
41165                 if(localNSMap){
41166                         for(prefix in localNSMap){
41167                                 domBuilder.endPrefixMapping(prefix); 
41168                         }
41169                 }
41170         }else{
41171                 el.currentNSMap = currentNSMap;
41172                 el.localNSMap = localNSMap;
41173                 //parseStack.push(el);
41174                 return true;
41175         }
41176 }
41177 function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){
41178         if(/^(?:script|textarea)$/i.test(tagName)){
41179                 var elEndStart =  source.indexOf('</'+tagName+'>',elStartEnd);
41180                 var text = source.substring(elStartEnd+1,elEndStart);
41181                 if(/[&<]/.test(text)){
41182                         if(/^script$/i.test(tagName)){
41183                                 //if(!/\]\]>/.test(text)){
41184                                         //lexHandler.startCDATA();
41185                                         domBuilder.characters(text,0,text.length);
41186                                         //lexHandler.endCDATA();
41187                                         return elEndStart;
41188                                 //}
41189                         }//}else{//text area
41190                                 text = text.replace(/&#?\w+;/g,entityReplacer);
41191                                 domBuilder.characters(text,0,text.length);
41192                                 return elEndStart;
41193                         //}
41194                         
41195                 }
41196         }
41197         return elStartEnd+1;
41198 }
41199 function fixSelfClosed(source,elStartEnd,tagName,closeMap){
41200         //if(tagName in closeMap){
41201         var pos = closeMap[tagName];
41202         if(pos == null){
41203                 //console.log(tagName)
41204                 pos =  source.lastIndexOf('</'+tagName+'>');
41205                 if(pos<elStartEnd){//忘记闭合
41206                         pos = source.lastIndexOf('</'+tagName);
41207                 }
41208                 closeMap[tagName] =pos;
41209         }
41210         return pos<elStartEnd;
41211         //} 
41212 }
41213 function _copy(source,target){
41214         for(var n in source){target[n] = source[n];}
41215 }
41216 function parseDCC(source,start,domBuilder,errorHandler){//sure start with '<!'
41217         var next= source.charAt(start+2);
41218         switch(next){
41219         case '-':
41220                 if(source.charAt(start + 3) === '-'){
41221                         var end = source.indexOf('-->',start+4);
41222                         //append comment source.substring(4,end)//<!--
41223                         if(end>start){
41224                                 domBuilder.comment(source,start+4,end-start-4);
41225                                 return end+3;
41226                         }else{
41227                                 errorHandler.error("Unclosed comment");
41228                                 return -1;
41229                         }
41230                 }else{
41231                         //error
41232                         return -1;
41233                 }
41234         default:
41235                 if(source.substr(start+3,6) == 'CDATA['){
41236                         var end = source.indexOf(']]>',start+9);
41237                         domBuilder.startCDATA();
41238                         domBuilder.characters(source,start+9,end-start-9);
41239                         domBuilder.endCDATA(); 
41240                         return end+3;
41241                 }
41242                 //<!DOCTYPE
41243                 //startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) 
41244                 var matchs = split(source,start);
41245                 var len = matchs.length;
41246                 if(len>1 && /!doctype/i.test(matchs[0][0])){
41247                         var name = matchs[1][0];
41248                         var pubid = len>3 && /^public$/i.test(matchs[2][0]) && matchs[3][0];
41249                         var sysid = len>4 && matchs[4][0];
41250                         var lastMatch = matchs[len-1];
41251                         domBuilder.startDTD(name,pubid && pubid.replace(/^(['"])(.*?)\1$/,'$2'),
41252                                         sysid && sysid.replace(/^(['"])(.*?)\1$/,'$2'));
41253                         domBuilder.endDTD();
41254                         
41255                         return lastMatch.index+lastMatch[0].length
41256                 }
41257         }
41258         return -1;
41259 }
41260
41261
41262
41263 function parseInstruction(source,start,domBuilder){
41264         var end = source.indexOf('?>',start);
41265         if(end){
41266                 var match = source.substring(start,end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
41267                 if(match){
41268                         var len = match[0].length;
41269                         domBuilder.processingInstruction(match[1], match[2]) ;
41270                         return end+2;
41271                 }else{//error
41272                         return -1;
41273                 }
41274         }
41275         return -1;
41276 }
41277
41278 /**
41279  * @param source
41280  */
41281 function ElementAttributes(source){
41282         
41283 }
41284 ElementAttributes.prototype = {
41285         setTagName:function(tagName){
41286                 if(!tagNamePattern.test(tagName)){
41287                         throw new Error('invalid tagName:'+tagName)
41288                 }
41289                 this.tagName = tagName;
41290         },
41291         add:function(qName,value,offset){
41292                 if(!tagNamePattern.test(qName)){
41293                         throw new Error('invalid attribute:'+qName)
41294                 }
41295                 this[this.length++] = {qName:qName,value:value,offset:offset};
41296         },
41297         length:0,
41298         getLocalName:function(i){return this[i].localName},
41299         getLocator:function(i){return this[i].locator},
41300         getQName:function(i){return this[i].qName},
41301         getURI:function(i){return this[i].uri},
41302         getValue:function(i){return this[i].value}
41303 //      ,getIndex:function(uri, localName)){
41304 //              if(localName){
41305 //                      
41306 //              }else{
41307 //                      var qName = uri
41308 //              }
41309 //      },
41310 //      getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
41311 //      getType:function(uri,localName){}
41312 //      getType:function(i){},
41313 };
41314
41315
41316
41317
41318 function _set_proto_(thiz,parent){
41319         thiz.__proto__ = parent;
41320         return thiz;
41321 }
41322 if(!(_set_proto_({},_set_proto_.prototype) instanceof _set_proto_)){
41323         _set_proto_ = function(thiz,parent){
41324                 function p(){}
41325                 p.prototype = parent;
41326                 p = new p();
41327                 for(parent in thiz){
41328                         p[parent] = thiz[parent];
41329                 }
41330                 return p;
41331         };
41332 }
41333
41334 function split(source,start){
41335         var match;
41336         var buf = [];
41337         var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
41338         reg.lastIndex = start;
41339         reg.exec(source);//skip <
41340         while(match = reg.exec(source)){
41341                 buf.push(match);
41342                 if(match[1])return buf;
41343         }
41344 }
41345
41346 var XMLReader_1 = XMLReader;
41347
41348 var sax = {
41349         XMLReader: XMLReader_1
41350 };
41351
41352 /*
41353  * DOM Level 2
41354  * Object DOMException
41355  * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
41356  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
41357  */
41358
41359 function copy$1(src,dest){
41360         for(var p in src){
41361                 dest[p] = src[p];
41362         }
41363 }
41364 /**
41365 ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
41366 ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
41367  */
41368 function _extends(Class,Super){
41369         var pt = Class.prototype;
41370         if(Object.create){
41371                 var ppt = Object.create(Super.prototype);
41372                 pt.__proto__ = ppt;
41373         }
41374         if(!(pt instanceof Super)){
41375                 function t(){}
41376                 t.prototype = Super.prototype;
41377                 t = new t();
41378                 copy$1(pt,t);
41379                 Class.prototype = pt = t;
41380         }
41381         if(pt.constructor != Class){
41382                 if(typeof Class != 'function'){
41383                         console.error("unknow Class:"+Class);
41384                 }
41385                 pt.constructor = Class;
41386         }
41387 }
41388 var htmlns = 'http://www.w3.org/1999/xhtml';
41389 // Node Types
41390 var NodeType = {};
41391 var ELEMENT_NODE                = NodeType.ELEMENT_NODE                = 1;
41392 var ATTRIBUTE_NODE              = NodeType.ATTRIBUTE_NODE              = 2;
41393 var TEXT_NODE                   = NodeType.TEXT_NODE                   = 3;
41394 var CDATA_SECTION_NODE          = NodeType.CDATA_SECTION_NODE          = 4;
41395 var ENTITY_REFERENCE_NODE       = NodeType.ENTITY_REFERENCE_NODE       = 5;
41396 var ENTITY_NODE                 = NodeType.ENTITY_NODE                 = 6;
41397 var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
41398 var COMMENT_NODE                = NodeType.COMMENT_NODE                = 8;
41399 var DOCUMENT_NODE               = NodeType.DOCUMENT_NODE               = 9;
41400 var DOCUMENT_TYPE_NODE          = NodeType.DOCUMENT_TYPE_NODE          = 10;
41401 var DOCUMENT_FRAGMENT_NODE      = NodeType.DOCUMENT_FRAGMENT_NODE      = 11;
41402 var NOTATION_NODE               = NodeType.NOTATION_NODE               = 12;
41403
41404 // ExceptionCode
41405 var ExceptionCode = {};
41406 var ExceptionMessage = {};
41407 var INDEX_SIZE_ERR              = ExceptionCode.INDEX_SIZE_ERR              = ((ExceptionMessage[1]="Index size error"),1);
41408 var DOMSTRING_SIZE_ERR          = ExceptionCode.DOMSTRING_SIZE_ERR          = ((ExceptionMessage[2]="DOMString size error"),2);
41409 var HIERARCHY_REQUEST_ERR       = ExceptionCode.HIERARCHY_REQUEST_ERR       = ((ExceptionMessage[3]="Hierarchy request error"),3);
41410 var WRONG_DOCUMENT_ERR          = ExceptionCode.WRONG_DOCUMENT_ERR          = ((ExceptionMessage[4]="Wrong document"),4);
41411 var INVALID_CHARACTER_ERR       = ExceptionCode.INVALID_CHARACTER_ERR       = ((ExceptionMessage[5]="Invalid character"),5);
41412 var NO_DATA_ALLOWED_ERR         = ExceptionCode.NO_DATA_ALLOWED_ERR         = ((ExceptionMessage[6]="No data allowed"),6);
41413 var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]="No modification allowed"),7);
41414 var NOT_FOUND_ERR               = ExceptionCode.NOT_FOUND_ERR               = ((ExceptionMessage[8]="Not found"),8);
41415 var NOT_SUPPORTED_ERR           = ExceptionCode.NOT_SUPPORTED_ERR           = ((ExceptionMessage[9]="Not supported"),9);
41416 var INUSE_ATTRIBUTE_ERR         = ExceptionCode.INUSE_ATTRIBUTE_ERR         = ((ExceptionMessage[10]="Attribute in use"),10);
41417 //level2
41418 var INVALID_STATE_ERR           = ExceptionCode.INVALID_STATE_ERR               = ((ExceptionMessage[11]="Invalid state"),11);
41419 var SYNTAX_ERR                  = ExceptionCode.SYNTAX_ERR                      = ((ExceptionMessage[12]="Syntax error"),12);
41420 var INVALID_MODIFICATION_ERR    = ExceptionCode.INVALID_MODIFICATION_ERR        = ((ExceptionMessage[13]="Invalid modification"),13);
41421 var NAMESPACE_ERR               = ExceptionCode.NAMESPACE_ERR                   = ((ExceptionMessage[14]="Invalid namespace"),14);
41422 var INVALID_ACCESS_ERR          = ExceptionCode.INVALID_ACCESS_ERR              = ((ExceptionMessage[15]="Invalid access"),15);
41423
41424
41425 function DOMException(code, message) {
41426         if(message instanceof Error){
41427                 var error = message;
41428         }else{
41429                 error = this;
41430                 Error.call(this, ExceptionMessage[code]);
41431                 this.message = ExceptionMessage[code];
41432                 if(Error.captureStackTrace) Error.captureStackTrace(this, DOMException);
41433         }
41434         error.code = code;
41435         if(message) this.message = this.message + ": " + message;
41436         return error;
41437 }
41438 DOMException.prototype = Error.prototype;
41439 copy$1(ExceptionCode,DOMException);
41440 /**
41441  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
41442  * 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.
41443  * The items in the NodeList are accessible via an integral index, starting from 0.
41444  */
41445 function NodeList() {
41446 }
41447 NodeList.prototype = {
41448         /**
41449          * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
41450          * @standard level1
41451          */
41452         length:0, 
41453         /**
41454          * 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.
41455          * @standard level1
41456          * @param index  unsigned long 
41457          *   Index into the collection.
41458          * @return Node
41459          *      The node at the indexth position in the NodeList, or null if that is not a valid index. 
41460          */
41461         item: function(index) {
41462                 return this[index] || null;
41463         },
41464         toString:function(isHTML,nodeFilter){
41465                 for(var buf = [], i = 0;i<this.length;i++){
41466                         serializeToString(this[i],buf,isHTML,nodeFilter);
41467                 }
41468                 return buf.join('');
41469         }
41470 };
41471 function LiveNodeList(node,refresh){
41472         this._node = node;
41473         this._refresh = refresh;
41474         _updateLiveList(this);
41475 }
41476 function _updateLiveList(list){
41477         var inc = list._node._inc || list._node.ownerDocument._inc;
41478         if(list._inc != inc){
41479                 var ls = list._refresh(list._node);
41480                 //console.log(ls.length)
41481                 __set__(list,'length',ls.length);
41482                 copy$1(ls,list);
41483                 list._inc = inc;
41484         }
41485 }
41486 LiveNodeList.prototype.item = function(i){
41487         _updateLiveList(this);
41488         return this[i];
41489 };
41490
41491 _extends(LiveNodeList,NodeList);
41492 /**
41493  * 
41494  * 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.
41495  * NamedNodeMap objects in the DOM are live.
41496  * used for attributes or DocumentType entities 
41497  */
41498 function NamedNodeMap() {
41499 }
41500
41501 function _findNodeIndex(list,node){
41502         var i = list.length;
41503         while(i--){
41504                 if(list[i] === node){return i}
41505         }
41506 }
41507
41508 function _addNamedNode(el,list,newAttr,oldAttr){
41509         if(oldAttr){
41510                 list[_findNodeIndex(list,oldAttr)] = newAttr;
41511         }else{
41512                 list[list.length++] = newAttr;
41513         }
41514         if(el){
41515                 newAttr.ownerElement = el;
41516                 var doc = el.ownerDocument;
41517                 if(doc){
41518                         oldAttr && _onRemoveAttribute(doc,el,oldAttr);
41519                         _onAddAttribute(doc,el,newAttr);
41520                 }
41521         }
41522 }
41523 function _removeNamedNode(el,list,attr){
41524         //console.log('remove attr:'+attr)
41525         var i = _findNodeIndex(list,attr);
41526         if(i>=0){
41527                 var lastIndex = list.length-1;
41528                 while(i<lastIndex){
41529                         list[i] = list[++i];
41530                 }
41531                 list.length = lastIndex;
41532                 if(el){
41533                         var doc = el.ownerDocument;
41534                         if(doc){
41535                                 _onRemoveAttribute(doc,el,attr);
41536                                 attr.ownerElement = null;
41537                         }
41538                 }
41539         }else{
41540                 throw DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))
41541         }
41542 }
41543 NamedNodeMap.prototype = {
41544         length:0,
41545         item:NodeList.prototype.item,
41546         getNamedItem: function(key) {
41547 //              if(key.indexOf(':')>0 || key == 'xmlns'){
41548 //                      return null;
41549 //              }
41550                 //console.log()
41551                 var i = this.length;
41552                 while(i--){
41553                         var attr = this[i];
41554                         //console.log(attr.nodeName,key)
41555                         if(attr.nodeName == key){
41556                                 return attr;
41557                         }
41558                 }
41559         },
41560         setNamedItem: function(attr) {
41561                 var el = attr.ownerElement;
41562                 if(el && el!=this._ownerElement){
41563                         throw new DOMException(INUSE_ATTRIBUTE_ERR);
41564                 }
41565                 var oldAttr = this.getNamedItem(attr.nodeName);
41566                 _addNamedNode(this._ownerElement,this,attr,oldAttr);
41567                 return oldAttr;
41568         },
41569         /* returns Node */
41570         setNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
41571                 var el = attr.ownerElement, oldAttr;
41572                 if(el && el!=this._ownerElement){
41573                         throw new DOMException(INUSE_ATTRIBUTE_ERR);
41574                 }
41575                 oldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName);
41576                 _addNamedNode(this._ownerElement,this,attr,oldAttr);
41577                 return oldAttr;
41578         },
41579
41580         /* returns Node */
41581         removeNamedItem: function(key) {
41582                 var attr = this.getNamedItem(key);
41583                 _removeNamedNode(this._ownerElement,this,attr);
41584                 return attr;
41585                 
41586                 
41587         },// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
41588         
41589         //for level2
41590         removeNamedItemNS:function(namespaceURI,localName){
41591                 var attr = this.getNamedItemNS(namespaceURI,localName);
41592                 _removeNamedNode(this._ownerElement,this,attr);
41593                 return attr;
41594         },
41595         getNamedItemNS: function(namespaceURI, localName) {
41596                 var i = this.length;
41597                 while(i--){
41598                         var node = this[i];
41599                         if(node.localName == localName && node.namespaceURI == namespaceURI){
41600                                 return node;
41601                         }
41602                 }
41603                 return null;
41604         }
41605 };
41606 /**
41607  * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
41608  */
41609 function DOMImplementation(/* Object */ features) {
41610         this._features = {};
41611         if (features) {
41612                 for (var feature in features) {
41613                          this._features = features[feature];
41614                 }
41615         }
41616 }
41617
41618 DOMImplementation.prototype = {
41619         hasFeature: function(/* string */ feature, /* string */ version) {
41620                 var versions = this._features[feature.toLowerCase()];
41621                 if (versions && (!version || version in versions)) {
41622                         return true;
41623                 } else {
41624                         return false;
41625                 }
41626         },
41627         // Introduced in DOM Level 2:
41628         createDocument:function(namespaceURI,  qualifiedName, doctype){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR
41629                 var doc = new Document();
41630                 doc.implementation = this;
41631                 doc.childNodes = new NodeList();
41632                 doc.doctype = doctype;
41633                 if(doctype){
41634                         doc.appendChild(doctype);
41635                 }
41636                 if(qualifiedName){
41637                         var root = doc.createElementNS(namespaceURI,qualifiedName);
41638                         doc.appendChild(root);
41639                 }
41640                 return doc;
41641         },
41642         // Introduced in DOM Level 2:
41643         createDocumentType:function(qualifiedName, publicId, systemId){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR
41644                 var node = new DocumentType();
41645                 node.name = qualifiedName;
41646                 node.nodeName = qualifiedName;
41647                 node.publicId = publicId;
41648                 node.systemId = systemId;
41649                 // Introduced in DOM Level 2:
41650                 //readonly attribute DOMString        internalSubset;
41651                 
41652                 //TODO:..
41653                 //  readonly attribute NamedNodeMap     entities;
41654                 //  readonly attribute NamedNodeMap     notations;
41655                 return node;
41656         }
41657 };
41658
41659
41660 /**
41661  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
41662  */
41663
41664 function Node$3() {
41665 }
41666
41667 Node$3.prototype = {
41668         firstChild : null,
41669         lastChild : null,
41670         previousSibling : null,
41671         nextSibling : null,
41672         attributes : null,
41673         parentNode : null,
41674         childNodes : null,
41675         ownerDocument : null,
41676         nodeValue : null,
41677         namespaceURI : null,
41678         prefix : null,
41679         localName : null,
41680         // Modified in DOM Level 2:
41681         insertBefore:function(newChild, refChild){//raises 
41682                 return _insertBefore(this,newChild,refChild);
41683         },
41684         replaceChild:function(newChild, oldChild){//raises 
41685                 this.insertBefore(newChild,oldChild);
41686                 if(oldChild){
41687                         this.removeChild(oldChild);
41688                 }
41689         },
41690         removeChild:function(oldChild){
41691                 return _removeChild(this,oldChild);
41692         },
41693         appendChild:function(newChild){
41694                 return this.insertBefore(newChild,null);
41695         },
41696         hasChildNodes:function(){
41697                 return this.firstChild != null;
41698         },
41699         cloneNode:function(deep){
41700                 return cloneNode(this.ownerDocument||this,this,deep);
41701         },
41702         // Modified in DOM Level 2:
41703         normalize:function(){
41704                 var child = this.firstChild;
41705                 while(child){
41706                         var next = child.nextSibling;
41707                         if(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){
41708                                 this.removeChild(next);
41709                                 child.appendData(next.data);
41710                         }else{
41711                                 child.normalize();
41712                                 child = next;
41713                         }
41714                 }
41715         },
41716         // Introduced in DOM Level 2:
41717         isSupported:function(feature, version){
41718                 return this.ownerDocument.implementation.hasFeature(feature,version);
41719         },
41720     // Introduced in DOM Level 2:
41721     hasAttributes:function(){
41722         return this.attributes.length>0;
41723     },
41724     lookupPrefix:function(namespaceURI){
41725         var el = this;
41726         while(el){
41727                 var map = el._nsMap;
41728                 //console.dir(map)
41729                 if(map){
41730                         for(var n in map){
41731                                 if(map[n] == namespaceURI){
41732                                         return n;
41733                                 }
41734                         }
41735                 }
41736                 el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
41737         }
41738         return null;
41739     },
41740     // Introduced in DOM Level 3:
41741     lookupNamespaceURI:function(prefix){
41742         var el = this;
41743         while(el){
41744                 var map = el._nsMap;
41745                 //console.dir(map)
41746                 if(map){
41747                         if(prefix in map){
41748                                 return map[prefix] ;
41749                         }
41750                 }
41751                 el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
41752         }
41753         return null;
41754     },
41755     // Introduced in DOM Level 3:
41756     isDefaultNamespace:function(namespaceURI){
41757         var prefix = this.lookupPrefix(namespaceURI);
41758         return prefix == null;
41759     }
41760 };
41761
41762
41763 function _xmlEncoder(c){
41764         return c == '<' && '&lt;' ||
41765          c == '>' && '&gt;' ||
41766          c == '&' && '&amp;' ||
41767          c == '"' && '&quot;' ||
41768          '&#'+c.charCodeAt()+';'
41769 }
41770
41771
41772 copy$1(NodeType,Node$3);
41773 copy$1(NodeType,Node$3.prototype);
41774
41775 /**
41776  * @param callback return true for continue,false for break
41777  * @return boolean true: break visit;
41778  */
41779 function _visitNode(node,callback){
41780         if(callback(node)){
41781                 return true;
41782         }
41783         if(node = node.firstChild){
41784                 do{
41785                         if(_visitNode(node,callback)){return true}
41786         }while(node=node.nextSibling)
41787     }
41788 }
41789
41790
41791
41792 function Document(){
41793 }
41794 function _onAddAttribute(doc,el,newAttr){
41795         doc && doc._inc++;
41796         var ns = newAttr.namespaceURI;
41797         if(ns == 'http://www.w3.org/2000/xmlns/'){
41798                 //update namespace
41799                 el._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value;
41800         }
41801 }
41802 function _onRemoveAttribute(doc,el,newAttr,remove){
41803         doc && doc._inc++;
41804         var ns = newAttr.namespaceURI;
41805         if(ns == 'http://www.w3.org/2000/xmlns/'){
41806                 //update namespace
41807                 delete el._nsMap[newAttr.prefix?newAttr.localName:''];
41808         }
41809 }
41810 function _onUpdateChild(doc,el,newChild){
41811         if(doc && doc._inc){
41812                 doc._inc++;
41813                 //update childNodes
41814                 var cs = el.childNodes;
41815                 if(newChild){
41816                         cs[cs.length++] = newChild;
41817                 }else{
41818                         //console.log(1)
41819                         var child = el.firstChild;
41820                         var i = 0;
41821                         while(child){
41822                                 cs[i++] = child;
41823                                 child =child.nextSibling;
41824                         }
41825                         cs.length = i;
41826                 }
41827         }
41828 }
41829
41830 /**
41831  * attributes;
41832  * children;
41833  * 
41834  * writeable properties:
41835  * nodeValue,Attr:value,CharacterData:data
41836  * prefix
41837  */
41838 function _removeChild(parentNode,child){
41839         var previous = child.previousSibling;
41840         var next = child.nextSibling;
41841         if(previous){
41842                 previous.nextSibling = next;
41843         }else{
41844                 parentNode.firstChild = next;
41845         }
41846         if(next){
41847                 next.previousSibling = previous;
41848         }else{
41849                 parentNode.lastChild = previous;
41850         }
41851         _onUpdateChild(parentNode.ownerDocument,parentNode);
41852         return child;
41853 }
41854 /**
41855  * preformance key(refChild == null)
41856  */
41857 function _insertBefore(parentNode,newChild,nextChild){
41858         var cp = newChild.parentNode;
41859         if(cp){
41860                 cp.removeChild(newChild);//remove and update
41861         }
41862         if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
41863                 var newFirst = newChild.firstChild;
41864                 if (newFirst == null) {
41865                         return newChild;
41866                 }
41867                 var newLast = newChild.lastChild;
41868         }else{
41869                 newFirst = newLast = newChild;
41870         }
41871         var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
41872
41873         newFirst.previousSibling = pre;
41874         newLast.nextSibling = nextChild;
41875         
41876         
41877         if(pre){
41878                 pre.nextSibling = newFirst;
41879         }else{
41880                 parentNode.firstChild = newFirst;
41881         }
41882         if(nextChild == null){
41883                 parentNode.lastChild = newLast;
41884         }else{
41885                 nextChild.previousSibling = newLast;
41886         }
41887         do{
41888                 newFirst.parentNode = parentNode;
41889         }while(newFirst !== newLast && (newFirst= newFirst.nextSibling))
41890         _onUpdateChild(parentNode.ownerDocument||parentNode,parentNode);
41891         //console.log(parentNode.lastChild.nextSibling == null)
41892         if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
41893                 newChild.firstChild = newChild.lastChild = null;
41894         }
41895         return newChild;
41896 }
41897 function _appendSingleChild(parentNode,newChild){
41898         var cp = newChild.parentNode;
41899         if(cp){
41900                 var pre = parentNode.lastChild;
41901                 cp.removeChild(newChild);//remove and update
41902                 var pre = parentNode.lastChild;
41903         }
41904         var pre = parentNode.lastChild;
41905         newChild.parentNode = parentNode;
41906         newChild.previousSibling = pre;
41907         newChild.nextSibling = null;
41908         if(pre){
41909                 pre.nextSibling = newChild;
41910         }else{
41911                 parentNode.firstChild = newChild;
41912         }
41913         parentNode.lastChild = newChild;
41914         _onUpdateChild(parentNode.ownerDocument,parentNode,newChild);
41915         return newChild;
41916         //console.log("__aa",parentNode.lastChild.nextSibling == null)
41917 }
41918 Document.prototype = {
41919         //implementation : null,
41920         nodeName :  '#document',
41921         nodeType :  DOCUMENT_NODE,
41922         doctype :  null,
41923         documentElement :  null,
41924         _inc : 1,
41925         
41926         insertBefore :  function(newChild, refChild){//raises 
41927                 if(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){
41928                         var child = newChild.firstChild;
41929                         while(child){
41930                                 var next = child.nextSibling;
41931                                 this.insertBefore(child,refChild);
41932                                 child = next;
41933                         }
41934                         return newChild;
41935                 }
41936                 if(this.documentElement == null && newChild.nodeType == ELEMENT_NODE){
41937                         this.documentElement = newChild;
41938                 }
41939                 
41940                 return _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild;
41941         },
41942         removeChild :  function(oldChild){
41943                 if(this.documentElement == oldChild){
41944                         this.documentElement = null;
41945                 }
41946                 return _removeChild(this,oldChild);
41947         },
41948         // Introduced in DOM Level 2:
41949         importNode : function(importedNode,deep){
41950                 return importNode(this,importedNode,deep);
41951         },
41952         // Introduced in DOM Level 2:
41953         getElementById :        function(id){
41954                 var rtv = null;
41955                 _visitNode(this.documentElement,function(node){
41956                         if(node.nodeType == ELEMENT_NODE){
41957                                 if(node.getAttribute('id') == id){
41958                                         rtv = node;
41959                                         return true;
41960                                 }
41961                         }
41962                 });
41963                 return rtv;
41964         },
41965         
41966         //document factory method:
41967         createElement : function(tagName){
41968                 var node = new Element();
41969                 node.ownerDocument = this;
41970                 node.nodeName = tagName;
41971                 node.tagName = tagName;
41972                 node.childNodes = new NodeList();
41973                 var attrs       = node.attributes = new NamedNodeMap();
41974                 attrs._ownerElement = node;
41975                 return node;
41976         },
41977         createDocumentFragment :        function(){
41978                 var node = new DocumentFragment();
41979                 node.ownerDocument = this;
41980                 node.childNodes = new NodeList();
41981                 return node;
41982         },
41983         createTextNode :        function(data){
41984                 var node = new Text();
41985                 node.ownerDocument = this;
41986                 node.appendData(data);
41987                 return node;
41988         },
41989         createComment : function(data){
41990                 var node = new Comment();
41991                 node.ownerDocument = this;
41992                 node.appendData(data);
41993                 return node;
41994         },
41995         createCDATASection :    function(data){
41996                 var node = new CDATASection();
41997                 node.ownerDocument = this;
41998                 node.appendData(data);
41999                 return node;
42000         },
42001         createProcessingInstruction :   function(target,data){
42002                 var node = new ProcessingInstruction();
42003                 node.ownerDocument = this;
42004                 node.tagName = node.target = target;
42005                 node.nodeValue= node.data = data;
42006                 return node;
42007         },
42008         createAttribute :       function(name){
42009                 var node = new Attr();
42010                 node.ownerDocument      = this;
42011                 node.name = name;
42012                 node.nodeName   = name;
42013                 node.localName = name;
42014                 node.specified = true;
42015                 return node;
42016         },
42017         createEntityReference : function(name){
42018                 var node = new EntityReference();
42019                 node.ownerDocument      = this;
42020                 node.nodeName   = name;
42021                 return node;
42022         },
42023         // Introduced in DOM Level 2:
42024         createElementNS :       function(namespaceURI,qualifiedName){
42025                 var node = new Element();
42026                 var pl = qualifiedName.split(':');
42027                 var attrs       = node.attributes = new NamedNodeMap();
42028                 node.childNodes = new NodeList();
42029                 node.ownerDocument = this;
42030                 node.nodeName = qualifiedName;
42031                 node.tagName = qualifiedName;
42032                 node.namespaceURI = namespaceURI;
42033                 if(pl.length == 2){
42034                         node.prefix = pl[0];
42035                         node.localName = pl[1];
42036                 }else{
42037                         //el.prefix = null;
42038                         node.localName = qualifiedName;
42039                 }
42040                 attrs._ownerElement = node;
42041                 return node;
42042         },
42043         // Introduced in DOM Level 2:
42044         createAttributeNS :     function(namespaceURI,qualifiedName){
42045                 var node = new Attr();
42046                 var pl = qualifiedName.split(':');
42047                 node.ownerDocument = this;
42048                 node.nodeName = qualifiedName;
42049                 node.name = qualifiedName;
42050                 node.namespaceURI = namespaceURI;
42051                 node.specified = true;
42052                 if(pl.length == 2){
42053                         node.prefix = pl[0];
42054                         node.localName = pl[1];
42055                 }else{
42056                         //el.prefix = null;
42057                         node.localName = qualifiedName;
42058                 }
42059                 return node;
42060         }
42061 };
42062 _extends(Document,Node$3);
42063
42064
42065 function Element() {
42066         this._nsMap = {};
42067 }
42068 Element.prototype = {
42069         nodeType : ELEMENT_NODE,
42070         hasAttribute : function(name){
42071                 return this.getAttributeNode(name)!=null;
42072         },
42073         getAttribute : function(name){
42074                 var attr = this.getAttributeNode(name);
42075                 return attr && attr.value || '';
42076         },
42077         getAttributeNode : function(name){
42078                 return this.attributes.getNamedItem(name);
42079         },
42080         setAttribute : function(name, value){
42081                 var attr = this.ownerDocument.createAttribute(name);
42082                 attr.value = attr.nodeValue = "" + value;
42083                 this.setAttributeNode(attr);
42084         },
42085         removeAttribute : function(name){
42086                 var attr = this.getAttributeNode(name);
42087                 attr && this.removeAttributeNode(attr);
42088         },
42089         
42090         //four real opeartion method
42091         appendChild:function(newChild){
42092                 if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
42093                         return this.insertBefore(newChild,null);
42094                 }else{
42095                         return _appendSingleChild(this,newChild);
42096                 }
42097         },
42098         setAttributeNode : function(newAttr){
42099                 return this.attributes.setNamedItem(newAttr);
42100         },
42101         setAttributeNodeNS : function(newAttr){
42102                 return this.attributes.setNamedItemNS(newAttr);
42103         },
42104         removeAttributeNode : function(oldAttr){
42105                 //console.log(this == oldAttr.ownerElement)
42106                 return this.attributes.removeNamedItem(oldAttr.nodeName);
42107         },
42108         //get real attribute name,and remove it by removeAttributeNode
42109         removeAttributeNS : function(namespaceURI, localName){
42110                 var old = this.getAttributeNodeNS(namespaceURI, localName);
42111                 old && this.removeAttributeNode(old);
42112         },
42113         
42114         hasAttributeNS : function(namespaceURI, localName){
42115                 return this.getAttributeNodeNS(namespaceURI, localName)!=null;
42116         },
42117         getAttributeNS : function(namespaceURI, localName){
42118                 var attr = this.getAttributeNodeNS(namespaceURI, localName);
42119                 return attr && attr.value || '';
42120         },
42121         setAttributeNS : function(namespaceURI, qualifiedName, value){
42122                 var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
42123                 attr.value = attr.nodeValue = "" + value;
42124                 this.setAttributeNode(attr);
42125         },
42126         getAttributeNodeNS : function(namespaceURI, localName){
42127                 return this.attributes.getNamedItemNS(namespaceURI, localName);
42128         },
42129         
42130         getElementsByTagName : function(tagName){
42131                 return new LiveNodeList(this,function(base){
42132                         var ls = [];
42133                         _visitNode(base,function(node){
42134                                 if(node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)){
42135                                         ls.push(node);
42136                                 }
42137                         });
42138                         return ls;
42139                 });
42140         },
42141         getElementsByTagNameNS : function(namespaceURI, localName){
42142                 return new LiveNodeList(this,function(base){
42143                         var ls = [];
42144                         _visitNode(base,function(node){
42145                                 if(node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)){
42146                                         ls.push(node);
42147                                 }
42148                         });
42149                         return ls;
42150                         
42151                 });
42152         }
42153 };
42154 Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
42155 Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
42156
42157
42158 _extends(Element,Node$3);
42159 function Attr() {
42160 }
42161 Attr.prototype.nodeType = ATTRIBUTE_NODE;
42162 _extends(Attr,Node$3);
42163
42164
42165 function CharacterData() {
42166 }
42167 CharacterData.prototype = {
42168         data : '',
42169         substringData : function(offset, count) {
42170                 return this.data.substring(offset, offset+count);
42171         },
42172         appendData: function(text) {
42173                 text = this.data+text;
42174                 this.nodeValue = this.data = text;
42175                 this.length = text.length;
42176         },
42177         insertData: function(offset,text) {
42178                 this.replaceData(offset,0,text);
42179         
42180         },
42181         appendChild:function(newChild){
42182                 throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR])
42183         },
42184         deleteData: function(offset, count) {
42185                 this.replaceData(offset,count,"");
42186         },
42187         replaceData: function(offset, count, text) {
42188                 var start = this.data.substring(0,offset);
42189                 var end = this.data.substring(offset+count);
42190                 text = start + text + end;
42191                 this.nodeValue = this.data = text;
42192                 this.length = text.length;
42193         }
42194 };
42195 _extends(CharacterData,Node$3);
42196 function Text() {
42197 }
42198 Text.prototype = {
42199         nodeName : "#text",
42200         nodeType : TEXT_NODE,
42201         splitText : function(offset) {
42202                 var text = this.data;
42203                 var newText = text.substring(offset);
42204                 text = text.substring(0, offset);
42205                 this.data = this.nodeValue = text;
42206                 this.length = text.length;
42207                 var newNode = this.ownerDocument.createTextNode(newText);
42208                 if(this.parentNode){
42209                         this.parentNode.insertBefore(newNode, this.nextSibling);
42210                 }
42211                 return newNode;
42212         }
42213 };
42214 _extends(Text,CharacterData);
42215 function Comment() {
42216 }
42217 Comment.prototype = {
42218         nodeName : "#comment",
42219         nodeType : COMMENT_NODE
42220 };
42221 _extends(Comment,CharacterData);
42222
42223 function CDATASection() {
42224 }
42225 CDATASection.prototype = {
42226         nodeName : "#cdata-section",
42227         nodeType : CDATA_SECTION_NODE
42228 };
42229 _extends(CDATASection,CharacterData);
42230
42231
42232 function DocumentType() {
42233 }
42234 DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
42235 _extends(DocumentType,Node$3);
42236
42237 function Notation() {
42238 }
42239 Notation.prototype.nodeType = NOTATION_NODE;
42240 _extends(Notation,Node$3);
42241
42242 function Entity() {
42243 }
42244 Entity.prototype.nodeType = ENTITY_NODE;
42245 _extends(Entity,Node$3);
42246
42247 function EntityReference() {
42248 }
42249 EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
42250 _extends(EntityReference,Node$3);
42251
42252 function DocumentFragment() {
42253 }
42254 DocumentFragment.prototype.nodeName =   "#document-fragment";
42255 DocumentFragment.prototype.nodeType =   DOCUMENT_FRAGMENT_NODE;
42256 _extends(DocumentFragment,Node$3);
42257
42258
42259 function ProcessingInstruction() {
42260 }
42261 ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
42262 _extends(ProcessingInstruction,Node$3);
42263 function XMLSerializer$1(){}
42264 XMLSerializer$1.prototype.serializeToString = function(node,isHtml,nodeFilter){
42265         return nodeSerializeToString.call(node,isHtml,nodeFilter);
42266 };
42267 Node$3.prototype.toString = nodeSerializeToString;
42268 function nodeSerializeToString(isHtml,nodeFilter){
42269         var buf = [];
42270         var refNode = this.nodeType == 9?this.documentElement:this;
42271         var prefix = refNode.prefix;
42272         var uri = refNode.namespaceURI;
42273         
42274         if(uri && prefix == null){
42275                 //console.log(prefix)
42276                 var prefix = refNode.lookupPrefix(uri);
42277                 if(prefix == null){
42278                         //isHTML = true;
42279                         var visibleNamespaces=[
42280                         {namespace:uri,prefix:null}
42281                         //{namespace:uri,prefix:''}
42282                         ];
42283                 }
42284         }
42285         serializeToString(this,buf,isHtml,nodeFilter,visibleNamespaces);
42286         //console.log('###',this.nodeType,uri,prefix,buf.join(''))
42287         return buf.join('');
42288 }
42289 function needNamespaceDefine(node,isHTML, visibleNamespaces) {
42290         var prefix = node.prefix||'';
42291         var uri = node.namespaceURI;
42292         if (!prefix && !uri){
42293                 return false;
42294         }
42295         if (prefix === "xml" && uri === "http://www.w3.org/XML/1998/namespace" 
42296                 || uri == 'http://www.w3.org/2000/xmlns/'){
42297                 return false;
42298         }
42299         
42300         var i = visibleNamespaces.length; 
42301         //console.log('@@@@',node.tagName,prefix,uri,visibleNamespaces)
42302         while (i--) {
42303                 var ns = visibleNamespaces[i];
42304                 // get namespace prefix
42305                 //console.log(node.nodeType,node.tagName,ns.prefix,prefix)
42306                 if (ns.prefix == prefix){
42307                         return ns.namespace != uri;
42308                 }
42309         }
42310         //console.log(isHTML,uri,prefix=='')
42311         //if(isHTML && prefix ==null && uri == 'http://www.w3.org/1999/xhtml'){
42312         //      return false;
42313         //}
42314         //node.flag = '11111'
42315         //console.error(3,true,node.flag,node.prefix,node.namespaceURI)
42316         return true;
42317 }
42318 function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
42319         if(nodeFilter){
42320                 node = nodeFilter(node);
42321                 if(node){
42322                         if(typeof node == 'string'){
42323                                 buf.push(node);
42324                                 return;
42325                         }
42326                 }else{
42327                         return;
42328                 }
42329                 //buf.sort.apply(attrs, attributeSorter);
42330         }
42331         switch(node.nodeType){
42332         case ELEMENT_NODE:
42333                 if (!visibleNamespaces) visibleNamespaces = [];
42334                 var startVisibleNamespaces = visibleNamespaces.length;
42335                 var attrs = node.attributes;
42336                 var len = attrs.length;
42337                 var child = node.firstChild;
42338                 var nodeName = node.tagName;
42339                 
42340                 isHTML =  (htmlns === node.namespaceURI) ||isHTML; 
42341                 buf.push('<',nodeName);
42342                 
42343                 
42344                 
42345                 for(var i=0;i<len;i++){
42346                         // add namespaces for attributes
42347                         var attr = attrs.item(i);
42348                         if (attr.prefix == 'xmlns') {
42349                                 visibleNamespaces.push({ prefix: attr.localName, namespace: attr.value });
42350                         }else if(attr.nodeName == 'xmlns'){
42351                                 visibleNamespaces.push({ prefix: '', namespace: attr.value });
42352                         }
42353                 }
42354                 for(var i=0;i<len;i++){
42355                         var attr = attrs.item(i);
42356                         if (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {
42357                                 var prefix = attr.prefix||'';
42358                                 var uri = attr.namespaceURI;
42359                                 var ns = prefix ? ' xmlns:' + prefix : " xmlns";
42360                                 buf.push(ns, '="' , uri , '"');
42361                                 visibleNamespaces.push({ prefix: prefix, namespace:uri });
42362                         }
42363                         serializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);
42364                 }
42365                 // add namespace for current node               
42366                 if (needNamespaceDefine(node,isHTML, visibleNamespaces)) {
42367                         var prefix = node.prefix||'';
42368                         var uri = node.namespaceURI;
42369                         var ns = prefix ? ' xmlns:' + prefix : " xmlns";
42370                         buf.push(ns, '="' , uri , '"');
42371                         visibleNamespaces.push({ prefix: prefix, namespace:uri });
42372                 }
42373                 
42374                 if(child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)){
42375                         buf.push('>');
42376                         //if is cdata child node
42377                         if(isHTML && /^script$/i.test(nodeName)){
42378                                 while(child){
42379                                         if(child.data){
42380                                                 buf.push(child.data);
42381                                         }else{
42382                                                 serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42383                                         }
42384                                         child = child.nextSibling;
42385                                 }
42386                         }else
42387                         {
42388                                 while(child){
42389                                         serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42390                                         child = child.nextSibling;
42391                                 }
42392                         }
42393                         buf.push('</',nodeName,'>');
42394                 }else{
42395                         buf.push('/>');
42396                 }
42397                 // remove added visible namespaces
42398                 //visibleNamespaces.length = startVisibleNamespaces;
42399                 return;
42400         case DOCUMENT_NODE:
42401         case DOCUMENT_FRAGMENT_NODE:
42402                 var child = node.firstChild;
42403                 while(child){
42404                         serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42405                         child = child.nextSibling;
42406                 }
42407                 return;
42408         case ATTRIBUTE_NODE:
42409                 return buf.push(' ',node.name,'="',node.value.replace(/[<&"]/g,_xmlEncoder),'"');
42410         case TEXT_NODE:
42411                 return buf.push(node.data.replace(/[<&]/g,_xmlEncoder));
42412         case CDATA_SECTION_NODE:
42413                 return buf.push( '<![CDATA[',node.data,']]>');
42414         case COMMENT_NODE:
42415                 return buf.push( "<!--",node.data,"-->");
42416         case DOCUMENT_TYPE_NODE:
42417                 var pubid = node.publicId;
42418                 var sysid = node.systemId;
42419                 buf.push('<!DOCTYPE ',node.name);
42420                 if(pubid){
42421                         buf.push(' PUBLIC "',pubid);
42422                         if (sysid && sysid!='.') {
42423                                 buf.push( '" "',sysid);
42424                         }
42425                         buf.push('">');
42426                 }else if(sysid && sysid!='.'){
42427                         buf.push(' SYSTEM "',sysid,'">');
42428                 }else{
42429                         var sub = node.internalSubset;
42430                         if(sub){
42431                                 buf.push(" [",sub,"]");
42432                         }
42433                         buf.push(">");
42434                 }
42435                 return;
42436         case PROCESSING_INSTRUCTION_NODE:
42437                 return buf.push( "<?",node.target," ",node.data,"?>");
42438         case ENTITY_REFERENCE_NODE:
42439                 return buf.push( '&',node.nodeName,';');
42440         //case ENTITY_NODE:
42441         //case NOTATION_NODE:
42442         default:
42443                 buf.push('??',node.nodeName);
42444         }
42445 }
42446 function importNode(doc,node,deep){
42447         var node2;
42448         switch (node.nodeType) {
42449         case ELEMENT_NODE:
42450                 node2 = node.cloneNode(false);
42451                 node2.ownerDocument = doc;
42452                 //var attrs = node2.attributes;
42453                 //var len = attrs.length;
42454                 //for(var i=0;i<len;i++){
42455                         //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
42456                 //}
42457         case DOCUMENT_FRAGMENT_NODE:
42458                 break;
42459         case ATTRIBUTE_NODE:
42460                 deep = true;
42461                 break;
42462         //case ENTITY_REFERENCE_NODE:
42463         //case PROCESSING_INSTRUCTION_NODE:
42464         ////case TEXT_NODE:
42465         //case CDATA_SECTION_NODE:
42466         //case COMMENT_NODE:
42467         //      deep = false;
42468         //      break;
42469         //case DOCUMENT_NODE:
42470         //case DOCUMENT_TYPE_NODE:
42471         //cannot be imported.
42472         //case ENTITY_NODE:
42473         //case NOTATION_NODE:
42474         //can not hit in level3
42475         //default:throw e;
42476         }
42477         if(!node2){
42478                 node2 = node.cloneNode(false);//false
42479         }
42480         node2.ownerDocument = doc;
42481         node2.parentNode = null;
42482         if(deep){
42483                 var child = node.firstChild;
42484                 while(child){
42485                         node2.appendChild(importNode(doc,child,deep));
42486                         child = child.nextSibling;
42487                 }
42488         }
42489         return node2;
42490 }
42491 //
42492 //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
42493 //                                      attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
42494 function cloneNode(doc,node,deep){
42495         var node2 = new node.constructor();
42496         for(var n in node){
42497                 var v = node[n];
42498                 if(typeof v != 'object' ){
42499                         if(v != node2[n]){
42500                                 node2[n] = v;
42501                         }
42502                 }
42503         }
42504         if(node.childNodes){
42505                 node2.childNodes = new NodeList();
42506         }
42507         node2.ownerDocument = doc;
42508         switch (node2.nodeType) {
42509         case ELEMENT_NODE:
42510                 var attrs       = node.attributes;
42511                 var attrs2      = node2.attributes = new NamedNodeMap();
42512                 var len = attrs.length;
42513                 attrs2._ownerElement = node2;
42514                 for(var i=0;i<len;i++){
42515                         node2.setAttributeNode(cloneNode(doc,attrs.item(i),true));
42516                 }
42517                 break;;
42518         case ATTRIBUTE_NODE:
42519                 deep = true;
42520         }
42521         if(deep){
42522                 var child = node.firstChild;
42523                 while(child){
42524                         node2.appendChild(cloneNode(doc,child,deep));
42525                         child = child.nextSibling;
42526                 }
42527         }
42528         return node2;
42529 }
42530
42531 function __set__(object,key,value){
42532         object[key] = value;
42533 }
42534 //do dynamic
42535 try{
42536         if(Object.defineProperty){
42537                 Object.defineProperty(LiveNodeList.prototype,'length',{
42538                         get:function(){
42539                                 _updateLiveList(this);
42540                                 return this.$$length;
42541                         }
42542                 });
42543                 Object.defineProperty(Node$3.prototype,'textContent',{
42544                         get:function(){
42545                                 return getTextContent(this);
42546                         },
42547                         set:function(data){
42548                                 switch(this.nodeType){
42549                                 case ELEMENT_NODE:
42550                                 case DOCUMENT_FRAGMENT_NODE:
42551                                         while(this.firstChild){
42552                                                 this.removeChild(this.firstChild);
42553                                         }
42554                                         if(data || String(data)){
42555                                                 this.appendChild(this.ownerDocument.createTextNode(data));
42556                                         }
42557                                         break;
42558                                 default:
42559                                         //TODO:
42560                                         this.data = data;
42561                                         this.value = data;
42562                                         this.nodeValue = data;
42563                                 }
42564                         }
42565                 });
42566                 
42567                 function getTextContent(node){
42568                         switch(node.nodeType){
42569                         case ELEMENT_NODE:
42570                         case DOCUMENT_FRAGMENT_NODE:
42571                                 var buf = [];
42572                                 node = node.firstChild;
42573                                 while(node){
42574                                         if(node.nodeType!==7 && node.nodeType !==8){
42575                                                 buf.push(getTextContent(node));
42576                                         }
42577                                         node = node.nextSibling;
42578                                 }
42579                                 return buf.join('');
42580                         default:
42581                                 return node.nodeValue;
42582                         }
42583                 }
42584                 __set__ = function(object,key,value){
42585                         //console.log(value)
42586                         object['$$'+key] = value;
42587                 };
42588         }
42589 }catch(e){//ie8
42590 }
42591
42592 //if(typeof require == 'function'){
42593         var DOMImplementation_1 = DOMImplementation;
42594         var XMLSerializer_1 = XMLSerializer$1;
42595 //}
42596
42597 var dom = {
42598         DOMImplementation: DOMImplementation_1,
42599         XMLSerializer: XMLSerializer_1
42600 };
42601
42602 var domParser = createCommonjsModule(function (module, exports) {
42603 function DOMParser(options){
42604         this.options = options ||{locator:{}};
42605         
42606 }
42607 DOMParser.prototype.parseFromString = function(source,mimeType){
42608         var options = this.options;
42609         var sax$$1 =  new XMLReader();
42610         var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
42611         var errorHandler = options.errorHandler;
42612         var locator = options.locator;
42613         var defaultNSMap = options.xmlns||{};
42614         var entityMap = {'lt':'<','gt':'>','amp':'&','quot':'"','apos':"'"};
42615         if(locator){
42616                 domBuilder.setDocumentLocator(locator);
42617         }
42618         
42619         sax$$1.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator);
42620         sax$$1.domBuilder = options.domBuilder || domBuilder;
42621         if(/\/x?html?$/.test(mimeType)){
42622                 entityMap.nbsp = '\xa0';
42623                 entityMap.copy = '\xa9';
42624                 defaultNSMap['']= 'http://www.w3.org/1999/xhtml';
42625         }
42626         defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
42627         if(source){
42628                 sax$$1.parse(source,defaultNSMap,entityMap);
42629         }else{
42630                 sax$$1.errorHandler.error("invalid doc source");
42631         }
42632         return domBuilder.doc;
42633 };
42634 function buildErrorHandler(errorImpl,domBuilder,locator){
42635         if(!errorImpl){
42636                 if(domBuilder instanceof DOMHandler){
42637                         return domBuilder;
42638                 }
42639                 errorImpl = domBuilder ;
42640         }
42641         var errorHandler = {};
42642         var isCallback = errorImpl instanceof Function;
42643         locator = locator||{};
42644         function build(key){
42645                 var fn = errorImpl[key];
42646                 if(!fn && isCallback){
42647                         fn = errorImpl.length == 2?function(msg){errorImpl(key,msg);}:errorImpl;
42648                 }
42649                 errorHandler[key] = fn && function(msg){
42650                         fn('[xmldom '+key+']\t'+msg+_locator(locator));
42651                 }||function(){};
42652         }
42653         build('warning');
42654         build('error');
42655         build('fatalError');
42656         return errorHandler;
42657 }
42658
42659 //console.log('#\n\n\n\n\n\n\n####')
42660 /**
42661  * +ContentHandler+ErrorHandler
42662  * +LexicalHandler+EntityResolver2
42663  * -DeclHandler-DTDHandler 
42664  * 
42665  * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
42666  * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
42667  * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
42668  */
42669 function DOMHandler() {
42670     this.cdata = false;
42671 }
42672 function position(locator,node){
42673         node.lineNumber = locator.lineNumber;
42674         node.columnNumber = locator.columnNumber;
42675 }
42676 /**
42677  * @see org.xml.sax.ContentHandler#startDocument
42678  * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
42679  */ 
42680 DOMHandler.prototype = {
42681         startDocument : function() {
42682         this.doc = new DOMImplementation().createDocument(null, null, null);
42683         if (this.locator) {
42684                 this.doc.documentURI = this.locator.systemId;
42685         }
42686         },
42687         startElement:function(namespaceURI, localName, qName, attrs) {
42688                 var doc = this.doc;
42689             var el = doc.createElementNS(namespaceURI, qName||localName);
42690             var len = attrs.length;
42691             appendElement(this, el);
42692             this.currentElement = el;
42693             
42694                 this.locator && position(this.locator,el);
42695             for (var i = 0 ; i < len; i++) {
42696                 var namespaceURI = attrs.getURI(i);
42697                 var value = attrs.getValue(i);
42698                 var qName = attrs.getQName(i);
42699                         var attr = doc.createAttributeNS(namespaceURI, qName);
42700                         this.locator &&position(attrs.getLocator(i),attr);
42701                         attr.value = attr.nodeValue = value;
42702                         el.setAttributeNode(attr);
42703             }
42704         },
42705         endElement:function(namespaceURI, localName, qName) {
42706                 var current = this.currentElement;
42707                 var tagName = current.tagName;
42708                 this.currentElement = current.parentNode;
42709         },
42710         startPrefixMapping:function(prefix, uri) {
42711         },
42712         endPrefixMapping:function(prefix) {
42713         },
42714         processingInstruction:function(target, data) {
42715             var ins = this.doc.createProcessingInstruction(target, data);
42716             this.locator && position(this.locator,ins);
42717             appendElement(this, ins);
42718         },
42719         ignorableWhitespace:function(ch, start, length) {
42720         },
42721         characters:function(chars, start, length) {
42722                 chars = _toString.apply(this,arguments);
42723                 //console.log(chars)
42724                 if(chars){
42725                         if (this.cdata) {
42726                                 var charNode = this.doc.createCDATASection(chars);
42727                         } else {
42728                                 var charNode = this.doc.createTextNode(chars);
42729                         }
42730                         if(this.currentElement){
42731                                 this.currentElement.appendChild(charNode);
42732                         }else if(/^\s*$/.test(chars)){
42733                                 this.doc.appendChild(charNode);
42734                                 //process xml
42735                         }
42736                         this.locator && position(this.locator,charNode);
42737                 }
42738         },
42739         skippedEntity:function(name) {
42740         },
42741         endDocument:function() {
42742                 this.doc.normalize();
42743         },
42744         setDocumentLocator:function (locator) {
42745             if(this.locator = locator){// && !('lineNumber' in locator)){
42746                 locator.lineNumber = 0;
42747             }
42748         },
42749         //LexicalHandler
42750         comment:function(chars, start, length) {
42751                 chars = _toString.apply(this,arguments);
42752             var comm = this.doc.createComment(chars);
42753             this.locator && position(this.locator,comm);
42754             appendElement(this, comm);
42755         },
42756         
42757         startCDATA:function() {
42758             //used in characters() methods
42759             this.cdata = true;
42760         },
42761         endCDATA:function() {
42762             this.cdata = false;
42763         },
42764         
42765         startDTD:function(name, publicId, systemId) {
42766                 var impl = this.doc.implementation;
42767             if (impl && impl.createDocumentType) {
42768                 var dt = impl.createDocumentType(name, publicId, systemId);
42769                 this.locator && position(this.locator,dt);
42770                 appendElement(this, dt);
42771             }
42772         },
42773         /**
42774          * @see org.xml.sax.ErrorHandler
42775          * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
42776          */
42777         warning:function(error) {
42778                 console.warn('[xmldom warning]\t'+error,_locator(this.locator));
42779         },
42780         error:function(error) {
42781                 console.error('[xmldom error]\t'+error,_locator(this.locator));
42782         },
42783         fatalError:function(error) {
42784                 console.error('[xmldom fatalError]\t'+error,_locator(this.locator));
42785             throw error;
42786         }
42787 };
42788 function _locator(l){
42789         if(l){
42790                 return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']'
42791         }
42792 }
42793 function _toString(chars,start,length){
42794         if(typeof chars == 'string'){
42795                 return chars.substr(start,length)
42796         }else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
42797                 if(chars.length >= start+length || start){
42798                         return new java.lang.String(chars,start,length)+'';
42799                 }
42800                 return chars;
42801         }
42802 }
42803
42804 /*
42805  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
42806  * used method of org.xml.sax.ext.LexicalHandler:
42807  *  #comment(chars, start, length)
42808  *  #startCDATA()
42809  *  #endCDATA()
42810  *  #startDTD(name, publicId, systemId)
42811  *
42812  *
42813  * IGNORED method of org.xml.sax.ext.LexicalHandler:
42814  *  #endDTD()
42815  *  #startEntity(name)
42816  *  #endEntity(name)
42817  *
42818  *
42819  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
42820  * IGNORED method of org.xml.sax.ext.DeclHandler
42821  *      #attributeDecl(eName, aName, type, mode, value)
42822  *  #elementDecl(name, model)
42823  *  #externalEntityDecl(name, publicId, systemId)
42824  *  #internalEntityDecl(name, value)
42825  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
42826  * IGNORED method of org.xml.sax.EntityResolver2
42827  *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
42828  *  #resolveEntity(publicId, systemId)
42829  *  #getExternalSubset(name, baseURI)
42830  * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
42831  * IGNORED method of org.xml.sax.DTDHandler
42832  *  #notationDecl(name, publicId, systemId) {};
42833  *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
42834  */
42835 "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){
42836         DOMHandler.prototype[key] = function(){return null};
42837 });
42838
42839 /* 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 */
42840 function appendElement (hander,node) {
42841     if (!hander.currentElement) {
42842         hander.doc.appendChild(node);
42843     } else {
42844         hander.currentElement.appendChild(node);
42845     }
42846 }//appendChild and setAttributeNS are preformance key
42847
42848 //if(typeof require == 'function'){
42849         var XMLReader = sax.XMLReader;
42850         var DOMImplementation = exports.DOMImplementation = dom.DOMImplementation;
42851         exports.XMLSerializer = dom.XMLSerializer ;
42852         exports.DOMParser = DOMParser;
42853 //}
42854 });
42855
42856 var togeojson = createCommonjsModule(function (module, exports) {
42857 var toGeoJSON = (function() {
42858     'use strict';
42859
42860     var removeSpace = /\s*/g,
42861         trimSpace = /^\s*|\s*$/g,
42862         splitSpace = /\s+/;
42863     // generate a short, numeric hash of a string
42864     function okhash(x) {
42865         if (!x || !x.length) return 0;
42866         for (var i = 0, h = 0; i < x.length; i++) {
42867             h = ((h << 5) - h) + x.charCodeAt(i) | 0;
42868         } return h;
42869     }
42870     // all Y children of X
42871     function get(x, y) { return x.getElementsByTagName(y); }
42872     function attr(x, y) { return x.getAttribute(y); }
42873     function attrf(x, y) { return parseFloat(attr(x, y)); }
42874     // one Y child of X, if any, otherwise null
42875     function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
42876     // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
42877     function norm(el) { if (el.normalize) { el.normalize(); } return el; }
42878     // cast array x into numbers
42879     function numarray(x) {
42880         for (var j = 0, o = []; j < x.length; j++) { o[j] = parseFloat(x[j]); }
42881         return o;
42882     }
42883     // get the content of a text node, if any
42884     function nodeVal(x) {
42885         if (x) { norm(x); }
42886         return (x && x.textContent) || '';
42887     }
42888     // get the contents of multiple text nodes, if present
42889     function getMulti(x, ys) {
42890         var o = {}, n, k;
42891         for (k = 0; k < ys.length; k++) {
42892             n = get1(x, ys[k]);
42893             if (n) o[ys[k]] = nodeVal(n);
42894         }
42895         return o;
42896     }
42897     // add properties of Y to X, overwriting if present in both
42898     function extend(x, y) { for (var k in y) x[k] = y[k]; }
42899     // get one coordinate from a coordinate array, if any
42900     function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
42901     // get all coordinates from a coordinate array as [[],[]]
42902     function coord(v) {
42903         var coords = v.replace(trimSpace, '').split(splitSpace),
42904             o = [];
42905         for (var i = 0; i < coords.length; i++) {
42906             o.push(coord1(coords[i]));
42907         }
42908         return o;
42909     }
42910     function coordPair(x) {
42911         var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
42912             ele = get1(x, 'ele'),
42913             // handle namespaced attribute in browser
42914             heartRate = get1(x, 'gpxtpx:hr') || get1(x, 'hr'),
42915             time = get1(x, 'time'),
42916             e;
42917         if (ele) {
42918             e = parseFloat(nodeVal(ele));
42919             if (!isNaN(e)) {
42920                 ll.push(e);
42921             }
42922         }
42923         return {
42924             coordinates: ll,
42925             time: time ? nodeVal(time) : null,
42926             heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
42927         };
42928     }
42929
42930     // create a new feature collection parent object
42931     function fc() {
42932         return {
42933             type: 'FeatureCollection',
42934             features: []
42935         };
42936     }
42937
42938     var serializer;
42939     if (typeof XMLSerializer !== 'undefined') {
42940         /* istanbul ignore next */
42941         serializer = new XMLSerializer();
42942     // only require xmldom in a node environment
42943     } else if ('object' === 'object' && typeof process === 'object' && !process.browser) {
42944         serializer = new (domParser.XMLSerializer)();
42945     }
42946     function xml2str(str) {
42947         // IE9 will create a new XMLSerializer but it'll crash immediately.
42948         // This line is ignored because we don't run coverage tests in IE9
42949         /* istanbul ignore next */
42950         if (str.xml !== undefined) return str.xml;
42951         return serializer.serializeToString(str);
42952     }
42953
42954     var t = {
42955         kml: function(doc) {
42956
42957             var gj = fc(),
42958                 // styleindex keeps track of hashed styles in order to match features
42959                 styleIndex = {}, styleByHash = {},
42960                 // stylemapindex keeps track of style maps to expose in properties
42961                 styleMapIndex = {},
42962                 // atomic geospatial types supported by KML - MultiGeometry is
42963                 // handled separately
42964                 geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'],
42965                 // all root placemarks in the file
42966                 placemarks = get(doc, 'Placemark'),
42967                 styles = get(doc, 'Style'),
42968                 styleMaps = get(doc, 'StyleMap');
42969
42970             for (var k = 0; k < styles.length; k++) {
42971                 var hash = okhash(xml2str(styles[k])).toString(16);
42972                 styleIndex['#' + attr(styles[k], 'id')] = hash;
42973                 styleByHash[hash] = styles[k];
42974             }
42975             for (var l = 0; l < styleMaps.length; l++) {
42976                 styleIndex['#' + attr(styleMaps[l], 'id')] = okhash(xml2str(styleMaps[l])).toString(16);
42977                 var pairs = get(styleMaps[l], 'Pair');
42978                 var pairsMap = {};
42979                 for (var m = 0; m < pairs.length; m++) {
42980                     pairsMap[nodeVal(get1(pairs[m], 'key'))] = nodeVal(get1(pairs[m], 'styleUrl'));
42981                 }
42982                 styleMapIndex['#' + attr(styleMaps[l], 'id')] = pairsMap;
42983
42984             }
42985             for (var j = 0; j < placemarks.length; j++) {
42986                 gj.features = gj.features.concat(getPlacemark(placemarks[j]));
42987             }
42988             function kmlColor(v) {
42989                 var color, opacity;
42990                 v = v || '';
42991                 if (v.substr(0, 1) === '#') { v = v.substr(1); }
42992                 if (v.length === 6 || v.length === 3) { color = v; }
42993                 if (v.length === 8) {
42994                     opacity = parseInt(v.substr(0, 2), 16) / 255;
42995                     color = '#' + v.substr(6, 2) +
42996                         v.substr(4, 2) +
42997                         v.substr(2, 2);
42998                 }
42999                 return [color, isNaN(opacity) ? undefined : opacity];
43000             }
43001             function gxCoord(v) { return numarray(v.split(' ')); }
43002             function gxCoords(root) {
43003                 var elems = get(root, 'coord', 'gx'), coords = [], times = [];
43004                 if (elems.length === 0) elems = get(root, 'gx:coord');
43005                 for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
43006                 var timeElems = get(root, 'when');
43007                 for (var j = 0; j < timeElems.length; j++) times.push(nodeVal(timeElems[j]));
43008                 return {
43009                     coords: coords,
43010                     times: times
43011                 };
43012             }
43013             function getGeometry(root) {
43014                 var geomNode, geomNodes, i, j, k, geoms = [], coordTimes = [];
43015                 if (get1(root, 'MultiGeometry')) { return getGeometry(get1(root, 'MultiGeometry')); }
43016                 if (get1(root, 'MultiTrack')) { return getGeometry(get1(root, 'MultiTrack')); }
43017                 if (get1(root, 'gx:MultiTrack')) { return getGeometry(get1(root, 'gx:MultiTrack')); }
43018                 for (i = 0; i < geotypes.length; i++) {
43019                     geomNodes = get(root, geotypes[i]);
43020                     if (geomNodes) {
43021                         for (j = 0; j < geomNodes.length; j++) {
43022                             geomNode = geomNodes[j];
43023                             if (geotypes[i] === 'Point') {
43024                                 geoms.push({
43025                                     type: 'Point',
43026                                     coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
43027                                 });
43028                             } else if (geotypes[i] === 'LineString') {
43029                                 geoms.push({
43030                                     type: 'LineString',
43031                                     coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
43032                                 });
43033                             } else if (geotypes[i] === 'Polygon') {
43034                                 var rings = get(geomNode, 'LinearRing'),
43035                                     coords = [];
43036                                 for (k = 0; k < rings.length; k++) {
43037                                     coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
43038                                 }
43039                                 geoms.push({
43040                                     type: 'Polygon',
43041                                     coordinates: coords
43042                                 });
43043                             } else if (geotypes[i] === 'Track' ||
43044                                 geotypes[i] === 'gx:Track') {
43045                                 var track = gxCoords(geomNode);
43046                                 geoms.push({
43047                                     type: 'LineString',
43048                                     coordinates: track.coords
43049                                 });
43050                                 if (track.times.length) coordTimes.push(track.times);
43051                             }
43052                         }
43053                     }
43054                 }
43055                 return {
43056                     geoms: geoms,
43057                     coordTimes: coordTimes
43058                 };
43059             }
43060             function getPlacemark(root) {
43061                 var geomsAndTimes = getGeometry(root), i, properties = {},
43062                     name = nodeVal(get1(root, 'name')),
43063                     address = nodeVal(get1(root, 'address')),
43064                     styleUrl = nodeVal(get1(root, 'styleUrl')),
43065                     description = nodeVal(get1(root, 'description')),
43066                     timeSpan = get1(root, 'TimeSpan'),
43067                     timeStamp = get1(root, 'TimeStamp'),
43068                     extendedData = get1(root, 'ExtendedData'),
43069                     lineStyle = get1(root, 'LineStyle'),
43070                     polyStyle = get1(root, 'PolyStyle'),
43071                     visibility = get1(root, 'visibility');
43072
43073                 if (!geomsAndTimes.geoms.length) return [];
43074                 if (name) properties.name = name;
43075                 if (address) properties.address = address;
43076                 if (styleUrl) {
43077                     if (styleUrl[0] !== '#') {
43078                         styleUrl = '#' + styleUrl;
43079                     }
43080
43081                     properties.styleUrl = styleUrl;
43082                     if (styleIndex[styleUrl]) {
43083                         properties.styleHash = styleIndex[styleUrl];
43084                     }
43085                     if (styleMapIndex[styleUrl]) {
43086                         properties.styleMapHash = styleMapIndex[styleUrl];
43087                         properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
43088                     }
43089                     // Try to populate the lineStyle or polyStyle since we got the style hash
43090                     var style = styleByHash[properties.styleHash];
43091                     if (style) {
43092                         if (!lineStyle) lineStyle = get1(style, 'LineStyle');
43093                         if (!polyStyle) polyStyle = get1(style, 'PolyStyle');
43094                     }
43095                 }
43096                 if (description) properties.description = description;
43097                 if (timeSpan) {
43098                     var begin = nodeVal(get1(timeSpan, 'begin'));
43099                     var end = nodeVal(get1(timeSpan, 'end'));
43100                     properties.timespan = { begin: begin, end: end };
43101                 }
43102                 if (timeStamp) {
43103                     properties.timestamp = nodeVal(get1(timeStamp, 'when'));
43104                 }
43105                 if (lineStyle) {
43106                     var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))),
43107                         color = linestyles[0],
43108                         opacity = linestyles[1],
43109                         width = parseFloat(nodeVal(get1(lineStyle, 'width')));
43110                     if (color) properties.stroke = color;
43111                     if (!isNaN(opacity)) properties['stroke-opacity'] = opacity;
43112                     if (!isNaN(width)) properties['stroke-width'] = width;
43113                 }
43114                 if (polyStyle) {
43115                     var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))),
43116                         pcolor = polystyles[0],
43117                         popacity = polystyles[1],
43118                         fill = nodeVal(get1(polyStyle, 'fill')),
43119                         outline = nodeVal(get1(polyStyle, 'outline'));
43120                     if (pcolor) properties.fill = pcolor;
43121                     if (!isNaN(popacity)) properties['fill-opacity'] = popacity;
43122                     if (fill) properties['fill-opacity'] = fill === '1' ? properties['fill-opacity'] || 1 : 0;
43123                     if (outline) properties['stroke-opacity'] = outline === '1' ? properties['stroke-opacity'] || 1 : 0;
43124                 }
43125                 if (extendedData) {
43126                     var datas = get(extendedData, 'Data'),
43127                         simpleDatas = get(extendedData, 'SimpleData');
43128
43129                     for (i = 0; i < datas.length; i++) {
43130                         properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
43131                     }
43132                     for (i = 0; i < simpleDatas.length; i++) {
43133                         properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
43134                     }
43135                 }
43136                 if (visibility) {
43137                     properties.visibility = nodeVal(visibility);
43138                 }
43139                 if (geomsAndTimes.coordTimes.length) {
43140                     properties.coordTimes = (geomsAndTimes.coordTimes.length === 1) ?
43141                         geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes;
43142                 }
43143                 var feature = {
43144                     type: 'Feature',
43145                     geometry: (geomsAndTimes.geoms.length === 1) ? geomsAndTimes.geoms[0] : {
43146                         type: 'GeometryCollection',
43147                         geometries: geomsAndTimes.geoms
43148                     },
43149                     properties: properties
43150                 };
43151                 if (attr(root, 'id')) feature.id = attr(root, 'id');
43152                 return [feature];
43153             }
43154             return gj;
43155         },
43156         gpx: function(doc) {
43157             var i,
43158                 tracks = get(doc, 'trk'),
43159                 routes = get(doc, 'rte'),
43160                 waypoints = get(doc, 'wpt'),
43161                 // a feature collection
43162                 gj = fc(),
43163                 feature;
43164             for (i = 0; i < tracks.length; i++) {
43165                 feature = getTrack(tracks[i]);
43166                 if (feature) gj.features.push(feature);
43167             }
43168             for (i = 0; i < routes.length; i++) {
43169                 feature = getRoute(routes[i]);
43170                 if (feature) gj.features.push(feature);
43171             }
43172             for (i = 0; i < waypoints.length; i++) {
43173                 gj.features.push(getPoint(waypoints[i]));
43174             }
43175             function getPoints(node, pointname) {
43176                 var pts = get(node, pointname),
43177                     line = [],
43178                     times = [],
43179                     heartRates = [],
43180                     l = pts.length;
43181                 if (l < 2) return {};  // Invalid line in GeoJSON
43182                 for (var i = 0; i < l; i++) {
43183                     var c = coordPair(pts[i]);
43184                     line.push(c.coordinates);
43185                     if (c.time) times.push(c.time);
43186                     if (c.heartRate) heartRates.push(c.heartRate);
43187                 }
43188                 return {
43189                     line: line,
43190                     times: times,
43191                     heartRates: heartRates
43192                 };
43193             }
43194             function getTrack(node) {
43195                 var segments = get(node, 'trkseg'),
43196                     track = [],
43197                     times = [],
43198                     heartRates = [],
43199                     line;
43200                 for (var i = 0; i < segments.length; i++) {
43201                     line = getPoints(segments[i], 'trkpt');
43202                     if (line) {
43203                         if (line.line) track.push(line.line);
43204                         if (line.times && line.times.length) times.push(line.times);
43205                         if (line.heartRates && line.heartRates.length) heartRates.push(line.heartRates);
43206                     }
43207                 }
43208                 if (track.length === 0) return;
43209                 var properties = getProperties(node);
43210                 extend(properties, getLineStyle(get1(node, 'extensions')));
43211                 if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
43212                 if (heartRates.length) properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
43213                 return {
43214                     type: 'Feature',
43215                     properties: properties,
43216                     geometry: {
43217                         type: track.length === 1 ? 'LineString' : 'MultiLineString',
43218                         coordinates: track.length === 1 ? track[0] : track
43219                     }
43220                 };
43221             }
43222             function getRoute(node) {
43223                 var line = getPoints(node, 'rtept');
43224                 if (!line.line) return;
43225                 var prop = getProperties(node);
43226                 extend(prop, getLineStyle(get1(node, 'extensions')));
43227                 var routeObj = {
43228                     type: 'Feature',
43229                     properties: prop,
43230                     geometry: {
43231                         type: 'LineString',
43232                         coordinates: line.line
43233                     }
43234                 };
43235                 return routeObj;
43236             }
43237             function getPoint(node) {
43238                 var prop = getProperties(node);
43239                 extend(prop, getMulti(node, ['sym']));
43240                 return {
43241                     type: 'Feature',
43242                     properties: prop,
43243                     geometry: {
43244                         type: 'Point',
43245                         coordinates: coordPair(node).coordinates
43246                     }
43247                 };
43248             }
43249             function getLineStyle(extensions) {
43250                 var style = {};
43251                 if (extensions) {
43252                     var lineStyle = get1(extensions, 'line');
43253                     if (lineStyle) {
43254                         var color = nodeVal(get1(lineStyle, 'color')),
43255                             opacity = parseFloat(nodeVal(get1(lineStyle, 'opacity'))),
43256                             width = parseFloat(nodeVal(get1(lineStyle, 'width')));
43257                         if (color) style.stroke = color;
43258                         if (!isNaN(opacity)) style['stroke-opacity'] = opacity;
43259                         // GPX width is in mm, convert to px with 96 px per inch
43260                         if (!isNaN(width)) style['stroke-width'] = width * 96 / 25.4;
43261                     }
43262                 }
43263                 return style;
43264             }
43265             function getProperties(node) {
43266                 var prop = getMulti(node, ['name', 'cmt', 'desc', 'type', 'time', 'keywords']),
43267                     links = get(node, 'link');
43268                 if (links.length) prop.links = [];
43269                 for (var i = 0, link; i < links.length; i++) {
43270                     link = { href: attr(links[i], 'href') };
43271                     extend(link, getMulti(links[i], ['text', 'type']));
43272                     prop.links.push(link);
43273                 }
43274                 return prop;
43275             }
43276             return gj;
43277         }
43278     };
43279     return t;
43280 })();
43281
43282 module.exports = toGeoJSON;
43283 });
43284
43285 function svgGpx(projection$$1, context, dispatch$$1) {
43286     var showLabels = true,
43287         detected = utilDetect(),
43288         layer;
43289
43290
43291     function init() {
43292         if (svgGpx.initialized) return;  // run once
43293
43294         svgGpx.geojson = {};
43295         svgGpx.enabled = true;
43296
43297         function over() {
43298             event.stopPropagation();
43299             event.preventDefault();
43300             event.dataTransfer.dropEffect = 'copy';
43301         }
43302
43303         select('body')
43304             .attr('dropzone', 'copy')
43305             .on('drop.localgpx', function() {
43306                 event.stopPropagation();
43307                 event.preventDefault();
43308                 if (!detected.filedrop) return;
43309                 drawGpx.files(event.dataTransfer.files);
43310             })
43311             .on('dragenter.localgpx', over)
43312             .on('dragexit.localgpx', over)
43313             .on('dragover.localgpx', over);
43314
43315         svgGpx.initialized = true;
43316     }
43317
43318
43319     function drawGpx(selection$$1) {
43320         var geojson = svgGpx.geojson,
43321             enabled = svgGpx.enabled;
43322
43323         layer = selection$$1.selectAll('.layer-gpx')
43324             .data(enabled ? [0] : []);
43325
43326         layer.exit()
43327             .remove();
43328
43329         layer = layer.enter()
43330             .append('g')
43331             .attr('class', 'layer-gpx')
43332             .merge(layer);
43333
43334
43335         var paths = layer
43336             .selectAll('path')
43337             .data([geojson]);
43338
43339         paths.exit()
43340             .remove();
43341
43342         paths = paths.enter()
43343             .append('path')
43344             .attr('class', 'gpx')
43345             .merge(paths);
43346
43347
43348         var path$$1 = index$4(projection$$1);
43349
43350         paths
43351             .attr('d', path$$1);
43352
43353
43354         var labels = layer.selectAll('text')
43355             .data(showLabels && geojson.features ? geojson.features : []);
43356
43357         labels.exit()
43358             .remove();
43359
43360         labels = labels.enter()
43361             .append('text')
43362             .attr('class', 'gpx')
43363             .merge(labels);
43364
43365         labels
43366             .text(function(d) {
43367                 return d.properties.desc || d.properties.name;
43368             })
43369             .attr('x', function(d) {
43370                 var centroid = path$$1.centroid(d);
43371                 return centroid[0] + 7;
43372             })
43373             .attr('y', function(d) {
43374                 var centroid = path$$1.centroid(d);
43375                 return centroid[1];
43376             });
43377
43378     }
43379
43380
43381     function toDom(x) {
43382         return (new DOMParser()).parseFromString(x, 'text/xml');
43383     }
43384
43385
43386     function getExtension(fileName) {
43387         if (lodash.isUndefined(fileName)) {
43388             return '';
43389         }
43390
43391         var lastDotIndex = fileName.lastIndexOf('.');
43392         if (lastDotIndex < 0) {
43393             return '';
43394         }
43395
43396         return fileName.substr(lastDotIndex);
43397     }
43398
43399
43400     function parseSaveAndZoom(extension, data) {
43401         switch (extension) {
43402             default:
43403                 drawGpx.geojson(togeojson.gpx(toDom(data))).fitZoom();
43404                 break;
43405             case '.kml':
43406                 drawGpx.geojson(togeojson.kml(toDom(data))).fitZoom();
43407                 break;
43408             case '.geojson':
43409             case '.json':
43410                 drawGpx.geojson(JSON.parse(data)).fitZoom();
43411                 break;
43412         }
43413     }
43414
43415
43416     drawGpx.showLabels = function(_) {
43417         if (!arguments.length) return showLabels;
43418         showLabels = _;
43419         return this;
43420     };
43421
43422
43423     drawGpx.enabled = function(_) {
43424         if (!arguments.length) return svgGpx.enabled;
43425         svgGpx.enabled = _;
43426         dispatch$$1.call('change');
43427         return this;
43428     };
43429
43430
43431     drawGpx.hasGpx = function() {
43432         var geojson = svgGpx.geojson;
43433         return (!(lodash.isEmpty(geojson) || lodash.isEmpty(geojson.features)));
43434     };
43435
43436
43437     drawGpx.geojson = function(gj) {
43438         if (!arguments.length) return svgGpx.geojson;
43439         if (lodash.isEmpty(gj) || lodash.isEmpty(gj.features)) return this;
43440         svgGpx.geojson = gj;
43441         dispatch$$1.call('change');
43442         return this;
43443     };
43444
43445
43446     drawGpx.url = function(url) {
43447         text(url, function(err, data) {
43448             if (!err) {
43449                 var extension = getExtension(url);
43450                 parseSaveAndZoom(extension, data);
43451             }
43452         });
43453         return this;
43454     };
43455
43456
43457     drawGpx.files = function(fileList) {
43458         if (!fileList.length) return this;
43459         var f = fileList[0],
43460             reader = new FileReader();
43461
43462         reader.onload = (function(file) {
43463             var extension = getExtension(file.name);
43464
43465             return function (e) {
43466                 parseSaveAndZoom(extension, e.target.result);
43467             };
43468         })(f);
43469
43470         reader.readAsText(f);
43471         return this;
43472     };
43473
43474
43475     drawGpx.fitZoom = function() {
43476         if (!this.hasGpx()) return this;
43477         var geojson = svgGpx.geojson;
43478
43479         var map = context.map(),
43480             viewport = map.trimmedExtent().polygon(),
43481             coords = lodash.reduce(geojson.features, function(coords, feature) {
43482                 var c = feature.geometry.coordinates;
43483
43484                 /* eslint-disable no-fallthrough */
43485                 switch (feature.geometry.type) {
43486                     case 'Point':
43487                         c = [c];
43488                     case 'MultiPoint':
43489                     case 'LineString':
43490                         break;
43491
43492                     case 'MultiPolygon':
43493                         c = lodash.flatten(c);
43494                     case 'Polygon':
43495                     case 'MultiLineString':
43496                         c = lodash.flatten(c);
43497                         break;
43498                 }
43499                 /* eslint-enable no-fallthrough */
43500
43501                 return lodash.union(coords, c);
43502             }, []);
43503
43504         if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
43505             var extent$$1 = geoExtent$$1(bounds({ type: 'LineString', coordinates: coords }));
43506             map.centerZoom(extent$$1.center(), map.trimmedExtentZoom(extent$$1));
43507         }
43508
43509         return this;
43510     };
43511
43512
43513     init();
43514     return drawGpx;
43515 }
43516
43517 function svgIcon(name, svgklass, useklass) {
43518     return function drawIcon(selection) {
43519         selection.selectAll('svg')
43520             .data([0])
43521             .enter()
43522             .append('svg')
43523             .attr('class', 'icon ' + (svgklass || ''))
43524             .append('use')
43525             .attr('xlink:href', name)
43526             .attr('class', useklass);
43527     };
43528 }
43529
43530 function svgLabels(projection$$1, context) {
43531     var path$$1 = index$4(projection$$1),
43532         detected = utilDetect(),
43533         baselineHack = (detected.ie || detected.browser.toLowerCase() === 'edge'),
43534         rdrawn = index$9(),
43535         rskipped = index$9(),
43536         textWidthCache = {},
43537         entitybboxes = {};
43538
43539     // Listed from highest to lowest priority
43540     var labelStack = [
43541         ['line', 'aeroway', '*', 12],
43542         ['line', 'highway', 'motorway', 12],
43543         ['line', 'highway', 'trunk', 12],
43544         ['line', 'highway', 'primary', 12],
43545         ['line', 'highway', 'secondary', 12],
43546         ['line', 'highway', 'tertiary', 12],
43547         ['line', 'highway', '*', 12],
43548         ['line', 'railway', '*', 12],
43549         ['line', 'waterway', '*', 12],
43550         ['area', 'aeroway', '*', 12],
43551         ['area', 'amenity', '*', 12],
43552         ['area', 'building', '*', 12],
43553         ['area', 'historic', '*', 12],
43554         ['area', 'leisure', '*', 12],
43555         ['area', 'man_made', '*', 12],
43556         ['area', 'natural', '*', 12],
43557         ['area', 'shop', '*', 12],
43558         ['area', 'tourism', '*', 12],
43559         ['area', 'camp_site', '*', 12],
43560         ['point', 'aeroway', '*', 10],
43561         ['point', 'amenity', '*', 10],
43562         ['point', 'building', '*', 10],
43563         ['point', 'historic', '*', 10],
43564         ['point', 'leisure', '*', 10],
43565         ['point', 'man_made', '*', 10],
43566         ['point', 'natural', '*', 10],
43567         ['point', 'shop', '*', 10],
43568         ['point', 'tourism', '*', 10],
43569         ['point', 'camp_site', '*', 10],
43570         ['line', 'name', '*', 12],
43571         ['area', 'name', '*', 12],
43572         ['point', 'name', '*', 10]
43573     ];
43574
43575
43576     function blacklisted(preset) {
43577         var noIcons = ['building', 'landuse', 'natural'];
43578         return lodash.some(noIcons, function(s) {
43579             return preset.id.indexOf(s) >= 0;
43580         });
43581     }
43582
43583
43584     function get(array, prop) {
43585         return function(d, i) { return array[i][prop]; };
43586     }
43587
43588
43589     function textWidth(text$$1, size, elem) {
43590         var c = textWidthCache[size];
43591         if (!c) c = textWidthCache[size] = {};
43592
43593         if (c[text$$1]) {
43594             return c[text$$1];
43595
43596         } else if (elem) {
43597             c[text$$1] = elem.getComputedTextLength();
43598             return c[text$$1];
43599
43600         } else {
43601             var str = encodeURIComponent(text$$1).match(/%[CDEFcdef]/g);
43602             if (str === null) {
43603                 return size / 3 * 2 * text$$1.length;
43604             } else {
43605                 return size / 3 * (2 * text$$1.length + str.length);
43606             }
43607         }
43608     }
43609
43610
43611     function drawLinePaths(selection$$1, entities, filter, classes, labels) {
43612         var paths = selection$$1.selectAll('path')
43613             .filter(filter)
43614             .data(entities, osmEntity$$1.key);
43615
43616         paths.exit()
43617             .remove();
43618
43619         paths.enter()
43620             .append('path')
43621             .style('stroke-width', get(labels, 'font-size'))
43622             .attr('id', function(d) { return 'labelpath-' + d.id; })
43623             .attr('class', classes)
43624             .merge(paths)
43625             .attr('d', get(labels, 'lineString'));
43626     }
43627
43628
43629     function drawLineLabels(selection$$1, entities, filter, classes, labels) {
43630         var texts = selection$$1.selectAll('text.' + classes)
43631             .filter(filter)
43632             .data(entities, osmEntity$$1.key);
43633
43634         texts.exit()
43635             .remove();
43636
43637         texts.enter()
43638             .append('text')
43639             .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
43640             .attr('dy', baselineHack ? '0.35em' : null)
43641             .append('textPath')
43642             .attr('class', 'textpath');
43643
43644         texts = selection$$1.selectAll('text.' + classes);
43645
43646         texts.selectAll('.textpath')
43647             .filter(filter)
43648             .data(entities, osmEntity$$1.key)
43649             .attr('startOffset', '50%')
43650             .attr('xlink:href', function(d) { return '#labelpath-' + d.id; })
43651             .text(utilDisplayNameForPath);
43652     }
43653
43654
43655     function drawPointLabels(selection$$1, entities, filter, classes, labels) {
43656         var texts = selection$$1.selectAll('text.' + classes)
43657             .filter(filter)
43658             .data(entities, osmEntity$$1.key);
43659
43660         texts.exit()
43661             .remove();
43662
43663         texts = texts.enter()
43664             .append('text')
43665             .attr('class', function(d, i) {
43666                 return classes + ' ' + labels[i].classes + ' ' + d.id;
43667             })
43668             .merge(texts);
43669
43670         texts
43671             .attr('x', get(labels, 'x'))
43672             .attr('y', get(labels, 'y'))
43673             .style('text-anchor', get(labels, 'textAnchor'))
43674             .text(utilDisplayName)
43675             .each(function(d, i) {
43676                 textWidth(utilDisplayName(d), labels[i].height, this);
43677             });
43678     }
43679
43680
43681     function drawAreaLabels(selection$$1, entities, filter, classes, labels) {
43682         entities = entities.filter(hasText);
43683         labels = labels.filter(hasText);
43684         drawPointLabels(selection$$1, entities, filter, classes, labels);
43685
43686         function hasText(d, i) {
43687             return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
43688         }
43689     }
43690
43691
43692     function drawAreaIcons(selection$$1, entities, filter, classes, labels) {
43693         var icons = selection$$1.selectAll('use.' + classes)
43694             .filter(filter)
43695             .data(entities, osmEntity$$1.key);
43696
43697         icons.exit()
43698             .remove();
43699
43700         icons = icons.enter()
43701             .append('use')
43702             .attr('class', 'icon ' + classes)
43703             .attr('width', '17px')
43704             .attr('height', '17px')
43705             .merge(icons);
43706
43707         icons
43708             .attr('transform', get(labels, 'transform'))
43709             .attr('xlink:href', function(d) {
43710                 var preset = context.presets().match(d, context.graph()),
43711                     picon = preset && preset.icon;
43712
43713                 if (!picon)
43714                     return '';
43715                 else {
43716                     var isMaki = dataFeatureIcons.indexOf(picon) !== -1;
43717                     return '#' + picon + (isMaki ? '-15' : '');
43718                 }
43719             });
43720     }
43721
43722
43723     function drawCollisionBoxes(selection$$1, rtree, which) {
43724         var showDebug = context.getDebug('collision'),
43725             classes = 'debug ' + which + ' ' +
43726                 (which === 'debug-skipped' ? 'orange' : 'yellow');
43727
43728         var debug = selection$$1.selectAll('.layer-label-debug')
43729                 .data(showDebug ? [true] : []);
43730
43731         debug.exit()
43732             .remove();
43733
43734         debug = debug.enter()
43735             .append('g')
43736             .attr('class', 'layer-label-debug')
43737             .merge(debug);
43738
43739         if (showDebug) {
43740             var gj = rtree.all().map(function(d) {
43741                 return { type: 'Polygon', coordinates: [[
43742                     [d.minX, d.minY],
43743                     [d.maxX, d.minY],
43744                     [d.maxX, d.maxY],
43745                     [d.minX, d.maxY],
43746                     [d.minX, d.minY]
43747                 ]]};
43748             });
43749
43750             var debugboxes = debug.selectAll('.' + which)
43751                 .data(gj);
43752
43753             debugboxes.exit()
43754                 .remove();
43755
43756             debugboxes = debugboxes.enter()
43757                 .append('path')
43758                 .attr('class', classes)
43759                 .merge(debugboxes);
43760
43761             debugboxes
43762                 .attr('d', index$4());
43763         }
43764     }
43765
43766
43767     function drawLabels(selection$$1, graph, entities, filter, dimensions, fullRedraw) {
43768         var lowZoom = context.surface().classed('low-zoom');
43769
43770         var labelable = [], i, j, k, entity, geometry;
43771         for (i = 0; i < labelStack.length; i++) {
43772             labelable.push([]);
43773         }
43774
43775         if (fullRedraw) {
43776             rdrawn.clear();
43777             rskipped.clear();
43778             entitybboxes = {};
43779         } else {
43780             for (i = 0; i < entities.length; i++) {
43781                 entity = entities[i];
43782                 var toRemove = []
43783                     .concat(entitybboxes[entity.id] || [])
43784                     .concat(entitybboxes[entity.id + 'I'] || []);
43785
43786                 for (j = 0; j < toRemove.length; j++) {
43787                     rdrawn.remove(toRemove[j]);
43788                     rskipped.remove(toRemove[j]);
43789                 }
43790             }
43791         }
43792
43793         // Split entities into groups specified by labelStack
43794         for (i = 0; i < entities.length; i++) {
43795             entity = entities[i];
43796             geometry = entity.geometry(graph);
43797             if (geometry === 'vertex') { geometry = 'point'; }  // treat vertex like point
43798
43799             var preset = geometry === 'area' && context.presets().match(entity, graph),
43800                 icon = preset && !blacklisted(preset) && preset.icon;
43801
43802             if (!icon && !utilDisplayName(entity))
43803                 continue;
43804
43805             for (k = 0; k < labelStack.length; k++) {
43806                 var matchGeom = labelStack[k][0],
43807                     matchKey = labelStack[k][1],
43808                     matchVal = labelStack[k][2],
43809                     hasVal = entity.tags[matchKey];
43810
43811                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
43812                     labelable[k].push(entity);
43813                     break;
43814                 }
43815             }
43816         }
43817
43818         var positions = {
43819             point: [],
43820             line: [],
43821             area: []
43822         };
43823
43824         var labelled = {
43825             point: [],
43826             line: [],
43827             area: []
43828         };
43829
43830         // Try and find a valid label for labellable entities
43831         for (k = 0; k < labelable.length; k++) {
43832             var fontSize = labelStack[k][3];
43833             for (i = 0; i < labelable[k].length; i++) {
43834                 entity = labelable[k][i];
43835                 geometry = entity.geometry(graph);
43836
43837                 var getName = (geometry === 'line') ? utilDisplayNameForPath : utilDisplayName,
43838                     name = getName(entity),
43839                     width = name && textWidth(name, fontSize),
43840                     p;
43841
43842                 if (geometry === 'point') {
43843                     p = getPointLabel(entity, width, fontSize, geometry);
43844                 } else if (geometry === 'vertex' && !lowZoom) {
43845                     // don't label vertices at low zoom because they don't have icons
43846                     p = getPointLabel(entity, width, fontSize, geometry);
43847                 } else if (geometry === 'line') {
43848                     p = getLineLabel(entity, width, fontSize);
43849                 } else if (geometry === 'area') {
43850                     p = getAreaLabel(entity, width, fontSize);
43851                 }
43852
43853                 if (p) {
43854                     if (geometry === 'vertex') { geometry = 'point'; }  // treat vertex like point
43855                     p.classes = geometry + ' tag-' + labelStack[k][1];
43856                     positions[geometry].push(p);
43857                     labelled[geometry].push(entity);
43858                 }
43859             }
43860         }
43861
43862
43863         function getPointLabel(entity, width, height, geometry) {
43864             var y = (geometry === 'point' ? -12 : 0),
43865                 pointOffsets = {
43866                     ltr: [15, y, 'start'],
43867                     rtl: [-15, y, 'end']
43868                 };
43869
43870             var coord = projection$$1(entity.loc),
43871                 margin = 2,
43872                 offset = pointOffsets[textDirection],
43873                 p = {
43874                     height: height,
43875                     width: width,
43876                     x: coord[0] + offset[0],
43877                     y: coord[1] + offset[1],
43878                     textAnchor: offset[2]
43879                 },
43880                 bbox;
43881
43882             if (textDirection === 'rtl') {
43883                 bbox = {
43884                     minX: p.x - width - margin,
43885                     minY: p.y - (height / 2) - margin,
43886                     maxX: p.x + margin,
43887                     maxY: p.y + (height / 2) + margin
43888                 };
43889             } else {
43890                 bbox = {
43891                     minX: p.x - margin,
43892                     minY: p.y - (height / 2) - margin,
43893                     maxX: p.x + width + margin,
43894                     maxY: p.y + (height / 2) + margin
43895                 };
43896             }
43897
43898             if (tryInsert([bbox], entity.id, true)) {
43899                 return p;
43900             }
43901         }
43902
43903
43904         function getLineLabel(entity, width, height) {
43905             var viewport = geoExtent$$1(context.projection.clipExtent()).polygon(),
43906                 nodes = lodash.map(graph.childNodes(entity), 'loc').map(projection$$1),
43907                 length = geoPathLength(nodes);
43908
43909             if (length < width + 20) return;
43910
43911             // % along the line to attempt to place the label
43912             var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70,
43913                                25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
43914             var margin = 3;
43915
43916             for (var i = 0; i < lineOffsets.length; i++) {
43917                 var offset = lineOffsets[i],
43918                     middle = offset / 100 * length,
43919                     start = middle - width / 2;
43920
43921                 if (start < 0 || start + width > length) continue;
43922
43923                 // generate subpath and ignore paths that are invalid or don't cross viewport.
43924                 var sub = subpath(nodes, start, start + width);
43925                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
43926                     continue;
43927                 }
43928
43929                 var isReverse = reverse$$1(sub);
43930                 if (isReverse) {
43931                     sub = sub.reverse();
43932                 }
43933
43934                 var bboxes = [],
43935                     boxsize = (height + 2) / 2;
43936
43937                 for (var j = 0; j < sub.length - 1; j++) {
43938                     var a = sub[j];
43939                     var b = sub[j + 1];
43940                     var num = Math.max(1, Math.floor(geoEuclideanDistance(a, b) / boxsize / 2));
43941
43942                     for (var box = 0; box < num; box++) {
43943                         var p = geoInterp(a, b, box / num);
43944                         var x0 = p[0] - boxsize - margin;
43945                         var y0 = p[1] - boxsize - margin;
43946                         var x1 = p[0] + boxsize + margin;
43947                         var y1 = p[1] + boxsize + margin;
43948
43949                         bboxes.push({
43950                             minX: Math.min(x0, x1),
43951                             minY: Math.min(y0, y1),
43952                             maxX: Math.max(x0, x1),
43953                             maxY: Math.max(y0, y1)
43954                         });
43955                     }
43956                 }
43957
43958                 if (tryInsert(bboxes, entity.id, false)) {
43959                     return {
43960                         'font-size': height + 2,
43961                         lineString: lineString(sub),
43962                         startOffset: offset + '%'
43963                     };
43964                 }
43965             }
43966
43967             function reverse$$1(p) {
43968                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
43969                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
43970             }
43971
43972             function lineString(nodes) {
43973                 return 'M' + nodes.join('L');
43974             }
43975
43976             function subpath(nodes, from, to) {
43977                 var sofar = 0,
43978                     start, end, i0, i1;
43979
43980                 for (var i = 0; i < nodes.length - 1; i++) {
43981                     var a = nodes[i],
43982                         b = nodes[i + 1];
43983                     var current = geoEuclideanDistance(a, b);
43984                     var portion;
43985                     if (!start && sofar + current >= from) {
43986                         portion = (from - sofar) / current;
43987                         start = [
43988                             a[0] + portion * (b[0] - a[0]),
43989                             a[1] + portion * (b[1] - a[1])
43990                         ];
43991                         i0 = i + 1;
43992                     }
43993                     if (!end && sofar + current >= to) {
43994                         portion = (to - sofar) / current;
43995                         end = [
43996                             a[0] + portion * (b[0] - a[0]),
43997                             a[1] + portion * (b[1] - a[1])
43998                         ];
43999                         i1 = i + 1;
44000                     }
44001                     sofar += current;
44002                 }
44003
44004                 var ret = nodes.slice(i0, i1);
44005                 ret.unshift(start);
44006                 ret.push(end);
44007                 return ret;
44008             }
44009         }
44010
44011
44012         function getAreaLabel(entity, width, height) {
44013             var centroid = path$$1.centroid(entity.asGeoJSON(graph, true)),
44014                 extent$$1 = entity.extent(graph),
44015                 entitywidth = projection$$1(extent$$1[1])[0] - projection$$1(extent$$1[0])[0];
44016
44017             if (isNaN(centroid[0]) || entitywidth < 20) return;
44018
44019             var iconSize = 20,
44020                 iconX = centroid[0] - (iconSize / 2),
44021                 iconY = centroid[1] - (iconSize / 2),
44022                 margin = 2,
44023                 textOffset = iconSize + margin,
44024                 p = { transform: 'translate(' + iconX + ',' + iconY + ')' };
44025
44026             var bbox = {
44027                 minX: iconX,
44028                 minY: iconY,
44029                 maxX: iconX + iconSize,
44030                 maxY: iconY + iconSize
44031             };
44032
44033             // try to add icon
44034             if (tryInsert([bbox], entity.id + 'I', true)) {
44035                 if (width && entitywidth >= width + 20) {
44036                     var labelX = centroid[0],
44037                         labelY = centroid[1] + textOffset;
44038
44039                     bbox = {
44040                         minX: labelX - (width / 2) - margin,
44041                         minY: labelY - (height / 2) - margin,
44042                         maxX: labelX + (width / 2) + margin,
44043                         maxY: labelY + (height / 2) + margin
44044                     };
44045
44046                     // try to add label
44047                     if (tryInsert([bbox], entity.id, true)) {
44048                         p.x = labelX;
44049                         p.y = labelY;
44050                         p.textAnchor = 'middle';
44051                         p.height = height;
44052                     }
44053                 }
44054
44055                 return p;
44056             }
44057         }
44058
44059
44060         function tryInsert(bboxes, id, saveSkipped) {
44061             var skipped = false,
44062                 bbox;
44063
44064             for (var i = 0; i < bboxes.length; i++) {
44065                 bbox = bboxes[i];
44066                 bbox.id = id;
44067
44068                 // Check that label is visible
44069                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
44070                     skipped = true;
44071                     break;
44072                 }
44073                 if (rdrawn.collides(bbox)) {
44074                     skipped = true;
44075                     break;
44076                 }
44077             }
44078
44079             entitybboxes[id] = bboxes;
44080
44081             if (skipped) {
44082                 if (saveSkipped) {
44083                     rskipped.load(bboxes);
44084                 }
44085             } else {
44086                 rdrawn.load(bboxes);
44087             }
44088
44089             return !skipped;
44090         }
44091
44092
44093         var label = selection$$1.selectAll('.layer-label'),
44094             halo = selection$$1.selectAll('.layer-halo');
44095
44096         // points
44097         drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
44098         drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
44099
44100         // lines
44101         drawLinePaths(halo, labelled.line, filter, '', positions.line);
44102         drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
44103         drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
44104
44105         // areas
44106         drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
44107         drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
44108         drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
44109         drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area);
44110
44111         // debug
44112         drawCollisionBoxes(label, rskipped, 'debug-skipped');
44113         drawCollisionBoxes(label, rdrawn, 'debug-drawn');
44114
44115         selection$$1.call(filterLabels);
44116     }
44117
44118
44119     function filterLabels(selection$$1) {
44120         var layers = selection$$1
44121             .selectAll('.layer-label, .layer-halo');
44122
44123         layers.selectAll('.proximate')
44124             .classed('proximate', false);
44125
44126         var mouse$$1 = context.mouse(),
44127             graph = context.graph(),
44128             selectedIDs = context.selectedIDs(),
44129             ids = [],
44130             pad, bbox;
44131
44132         // hide labels near the mouse
44133         if (mouse$$1) {
44134             pad = 20;
44135             bbox = { minX: mouse$$1[0] - pad, minY: mouse$$1[1] - pad, maxX: mouse$$1[0] + pad, maxY: mouse$$1[1] + pad };
44136             ids.push.apply(ids, lodash.map(rdrawn.search(bbox), 'id'));
44137         }
44138
44139         // hide labels along selected ways, or near selected vertices
44140         for (var i = 0; i < selectedIDs.length; i++) {
44141             var entity = graph.hasEntity(selectedIDs[i]);
44142             if (!entity) continue;
44143             var geometry = entity.geometry(graph);
44144
44145             if (geometry === 'line') {
44146                 ids.push(selectedIDs[i]);
44147             } else if (geometry === 'vertex') {
44148                 var point = context.projection(entity.loc);
44149                 pad = 10;
44150                 bbox = { minX: point[0] - pad, minY: point[1] - pad, maxX: point[0] + pad, maxY: point[1] + pad };
44151                 ids.push.apply(ids, lodash.map(rdrawn.search(bbox), 'id'));
44152             }
44153         }
44154
44155         layers.selectAll(utilEntitySelector(ids))
44156             .classed('proximate', true);
44157     }
44158
44159
44160     var throttleFilterLabels = lodash.throttle(filterLabels, 100);
44161
44162
44163     drawLabels.observe = function(selection$$1) {
44164         var listener = function() { throttleFilterLabels(selection$$1); };
44165         selection$$1.on('mousemove.hidelabels', listener);
44166         context.on('enter.hidelabels', listener);
44167     };
44168
44169
44170     drawLabels.off = function(selection$$1) {
44171         throttleFilterLabels.cancel();
44172         selection$$1.on('mousemove.hidelabels', null);
44173         context.on('enter.hidelabels', null);
44174     };
44175
44176
44177     return drawLabels;
44178 }
44179
44180 function refresh(selection, node) {
44181     var cr = node.getBoundingClientRect();
44182     var prop = [cr.width, cr.height];
44183     selection.property('__dimensions__', prop);
44184     return prop;
44185 }
44186
44187 function utilGetDimensions(selection, force) {
44188     if (!selection || selection.empty()) {
44189         return [0, 0];
44190     }
44191     var node = selection.node(),
44192         cached = selection.property('__dimensions__');
44193     return (!cached || force) ? refresh(selection, node) : cached;
44194 }
44195
44196
44197 function utilSetDimensions(selection, dimensions) {
44198     if (!selection || selection.empty()) {
44199         return selection;
44200     }
44201     var node = selection.node();
44202     if (dimensions === null) {
44203         refresh(selection, node);
44204         return selection;
44205     }
44206     return selection
44207         .property('__dimensions__', [dimensions[0], dimensions[1]])
44208         .attr('width', dimensions[0])
44209         .attr('height', dimensions[1]);
44210 }
44211
44212 function svgPointTransform(projection) {
44213     return function(entity) {
44214         // http://jsperf.com/short-array-join
44215         var pt = projection(entity.loc);
44216         return 'translate(' + pt[0] + ',' + pt[1] + ')';
44217     };
44218 }
44219
44220 function d3geoTile() {
44221   var size = [960, 500],
44222       scale = 256,
44223       scaleExtent = [0, 20],
44224       translate = [size[0] / 2, size[1] / 2],
44225       zoomDelta = 0;
44226
44227   function bound(_) {
44228       return Math.min(scaleExtent[1], Math.max(scaleExtent[0], _));
44229   }
44230
44231   function tile() {
44232     var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
44233         z0 = bound(Math.round(z + zoomDelta)),
44234         k = Math.pow(2, z - z0 + 8),
44235         origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
44236         tiles = [],
44237         cols = sequence(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
44238         rows = sequence(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
44239
44240     rows.forEach(function(y) {
44241       cols.forEach(function(x) {
44242         tiles.push([x, y, z0]);
44243       });
44244     });
44245
44246     tiles.translate = origin;
44247     tiles.scale = k;
44248
44249     return tiles;
44250   }
44251
44252   tile.scaleExtent = function(_) {
44253     if (!arguments.length) return scaleExtent;
44254     scaleExtent = _;
44255     return tile;
44256   };
44257
44258   tile.size = function(_) {
44259     if (!arguments.length) return size;
44260     size = _;
44261     return tile;
44262   };
44263
44264   tile.scale = function(_) {
44265     if (!arguments.length) return scale;
44266     scale = _;
44267     return tile;
44268   };
44269
44270   tile.translate = function(_) {
44271     if (!arguments.length) return translate;
44272     translate = _;
44273     return tile;
44274   };
44275
44276   tile.zoomDelta = function(_) {
44277     if (!arguments.length) return zoomDelta;
44278     zoomDelta = +_;
44279     return tile;
44280   };
44281
44282   return tile;
44283 }
44284
44285 /* global Mapillary:false */
44286 var apibase = 'https://a.mapillary.com/v3/';
44287 var viewercss = 'mapillary-js/mapillary.min.css';
44288 var viewerjs = 'mapillary-js/mapillary.min.js';
44289 var clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi';
44290 var maxResults = 1000;
44291 var tileZoom = 14;
44292 var dispatch$2 = dispatch('loadedImages', 'loadedSigns');
44293 var mapillaryCache;
44294 var mapillaryClicks;
44295 var mapillaryImage;
44296 var mapillarySignDefs;
44297 var mapillarySignSprite;
44298 var mapillaryViewer;
44299
44300
44301 function abortRequest(i) {
44302     i.abort();
44303 }
44304
44305
44306 function nearNullIsland(x, y, z) {
44307     if (z >= 7) {
44308         var center = Math.pow(2, z - 1),
44309             width = Math.pow(2, z - 6),
44310             min$$1 = center - (width / 2),
44311             max$$1 = center + (width / 2) - 1;
44312         return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
44313     }
44314     return false;
44315 }
44316
44317
44318 function maxPageAtZoom(z) {
44319     if (z < 15)   return 2;
44320     if (z === 15) return 5;
44321     if (z === 16) return 10;
44322     if (z === 17) return 20;
44323     if (z === 18) return 40;
44324     if (z > 18)   return 80;
44325 }
44326
44327
44328 function getTiles(projection$$1) {
44329     var s = projection$$1.scale() * 2 * Math.PI,
44330         z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
44331         ts = 256 * Math.pow(2, z - tileZoom),
44332         origin = [
44333             s / 2 - projection$$1.translate()[0],
44334             s / 2 - projection$$1.translate()[1]];
44335
44336     return d3geoTile()
44337         .scaleExtent([tileZoom, tileZoom])
44338         .scale(s)
44339         .size(projection$$1.clipExtent()[1])
44340         .translate(projection$$1.translate())()
44341         .map(function(tile) {
44342             var x = tile[0] * ts - origin[0],
44343                 y = tile[1] * ts - origin[1];
44344
44345             return {
44346                 id: tile.toString(),
44347                 xyz: tile,
44348                 extent: geoExtent$$1(
44349                     projection$$1.invert([x, y + ts]),
44350                     projection$$1.invert([x + ts, y])
44351                 )
44352             };
44353         });
44354 }
44355
44356
44357 function loadTiles(which, url, projection$$1) {
44358     var s = projection$$1.scale() * 2 * Math.PI,
44359         currZoom = Math.floor(Math.max(Math.log(s) / Math.log(2) - 8, 0));
44360
44361     var tiles = getTiles(projection$$1).filter(function(t) {
44362             return !nearNullIsland(t.xyz[0], t.xyz[1], t.xyz[2]);
44363         });
44364
44365     lodash.filter(which.inflight, function(v, k) {
44366         var wanted = lodash.find(tiles, function(tile) { return k === (tile.id + ',0'); });
44367         if (!wanted) delete which.inflight[k];
44368         return !wanted;
44369     }).map(abortRequest);
44370
44371     tiles.forEach(function(tile) {
44372         loadNextTilePage(which, currZoom, url, tile);
44373     });
44374 }
44375
44376
44377 function loadNextTilePage(which, currZoom, url, tile) {
44378     var cache = mapillaryCache[which],
44379         rect = tile.extent.rectangle(),
44380         maxPages = maxPageAtZoom(currZoom),
44381         nextPage = cache.nextPage[tile.id] || 0,
44382         nextURL = cache.nextURL[tile.id] || url +
44383             utilQsString({
44384                 per_page: maxResults,
44385                 page: nextPage,
44386                 client_id: clientId,
44387                 bbox: [rect[0], rect[1], rect[2], rect[3]].join(','),
44388             });
44389
44390     if (nextPage > maxPages) return;
44391
44392     var id = tile.id + ',' + String(nextPage);
44393     if (cache.loaded[id] || cache.inflight[id]) return;
44394     cache.inflight[id] = request(nextURL)
44395         .mimeType('application/json')
44396         .response(function(xhr) {
44397             var linkHeader = xhr.getResponseHeader('Link');
44398             if (linkHeader) {
44399                 var pagination = parsePagination(xhr.getResponseHeader('Link'));
44400                 if (pagination.next) {
44401                     cache.nextURL[tile.id] = pagination.next;
44402                 }
44403             }
44404
44405             return JSON.parse(xhr.responseText); })
44406         .get(function(err, data) {
44407             cache.loaded[id] = true;
44408             delete cache.inflight[id];
44409             if (err || !data.features || !data.features.length) return;
44410
44411             var features = [],
44412                 feature, loc, d;
44413
44414             for (var i = 0; i < data.features.length; i++) {
44415                 feature = data.features[i];
44416                 loc = feature.geometry.coordinates;
44417                 d = { key: feature.properties.key, loc: loc };
44418                 if (which === 'images') d = { ca: feature.properties.ca, key: feature.properties.key, loc: loc };
44419                 if (which === 'signs') d = { key: feature.properties.detections[0].image_key, loc: loc, value: feature.properties.value };
44420
44421                 features.push({minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1], data: d});
44422             }
44423
44424             cache.rtree.load(features);
44425
44426             if (which === 'images') dispatch$2.call('loadedImages');
44427             if (which === 'signs') dispatch$2.call('loadedSigns');
44428             if (data.features.length === maxResults) {  // more pages to load
44429                 cache.nextPage[tile.id] = nextPage + 1;
44430                 loadNextTilePage(which, currZoom, url, tile);
44431             } else {
44432                 cache.nextPage[tile.id] = Infinity;     // no more pages to load
44433             }
44434         });
44435 }
44436
44437 // extract links to pages of API results
44438 function parsePagination(links) {
44439     return links.split(',').map(function(rel) {
44440         var elements = rel.split(';');
44441         if (elements.length === 2) {
44442             return [
44443                 /<(.+)>/.exec(elements[0])[1],
44444                 /rel="(.+)"/.exec(elements[1])[1]
44445                 ];
44446         } else {
44447             return ['',''];
44448         }
44449     }).reduce(function(pagination, val) {
44450         pagination[val[1]] = val[0];
44451         return pagination;
44452     }, {});
44453 }
44454
44455
44456 // partition viewport into `psize` x `psize` regions
44457 function partitionViewport(psize, projection$$1) {
44458     var dimensions = projection$$1.clipExtent()[1];
44459     psize = psize || 16;
44460     var cols = sequence(0, dimensions[0], psize),
44461         rows = sequence(0, dimensions[1], psize),
44462         partitions = [];
44463
44464     rows.forEach(function(y) {
44465         cols.forEach(function(x) {
44466             var min$$1 = [x, y + psize],
44467                 max$$1 = [x + psize, y];
44468             partitions.push(
44469                 geoExtent$$1(projection$$1.invert(min$$1), projection$$1.invert(max$$1)));
44470         });
44471     });
44472
44473     return partitions;
44474 }
44475
44476
44477 // no more than `limit` results per partition.
44478 function searchLimited(psize, limit, projection$$1, rtree) {
44479     limit = limit || 3;
44480
44481     var partitions = partitionViewport(psize, projection$$1);
44482     return lodash.flatten(lodash.compact(lodash.map(partitions, function(extent$$1) {
44483         return rtree.search(extent$$1.bbox())
44484             .slice(0, limit)
44485             .map(function(d) { return d.data; });
44486     })));
44487 }
44488
44489
44490
44491 var serviceMapillary = {
44492
44493     init: function() {
44494         if (!mapillaryCache) {
44495             this.reset();
44496         }
44497
44498         this.event = utilRebind(this, dispatch$2, 'on');
44499     },
44500
44501     reset: function() {
44502         var cache = mapillaryCache;
44503
44504         if (cache) {
44505             if (cache.images && cache.images.inflight) {
44506                 lodash.forEach(cache.images.inflight, abortRequest);
44507             }
44508             if (cache.signs && cache.signs.inflight) {
44509                 lodash.forEach(cache.signs.inflight, abortRequest);
44510             }
44511         }
44512
44513         mapillaryCache = {
44514             images: { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: index$9() },
44515             signs:  { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: index$9() }
44516         };
44517
44518         mapillaryImage = null;
44519         mapillaryClicks = [];
44520     },
44521
44522
44523     images: function(projection$$1) {
44524         var psize = 16, limit = 3;
44525         return searchLimited(psize, limit, projection$$1, mapillaryCache.images.rtree);
44526     },
44527
44528
44529     signs: function(projection$$1) {
44530         var psize = 32, limit = 3;
44531         return searchLimited(psize, limit, projection$$1, mapillaryCache.signs.rtree);
44532     },
44533
44534
44535     signsSupported: function() {
44536         var detected = utilDetect();
44537         if (detected.ie) return false;
44538         if ((detected.browser.toLowerCase() === 'safari') && (parseFloat(detected.version) < 10)) return false;
44539         return true;
44540     },
44541
44542
44543     signHTML: function(d) {
44544         if (!mapillarySignDefs || !mapillarySignSprite) return;
44545         var position = mapillarySignDefs[d.value];
44546         if (!position) return '<div></div>';
44547         var iconStyle = [
44548             'background-image:url(' + mapillarySignSprite + ')',
44549             'background-repeat:no-repeat',
44550             'height:' + position.height + 'px',
44551             'width:' + position.width + 'px',
44552             'background-position-x:-' + position.x + 'px',
44553             'background-position-y:-' + position.y + 'px',
44554         ];
44555
44556         return '<div style="' + iconStyle.join(';') +'"></div>';
44557     },
44558
44559
44560     loadImages: function(projection$$1) {
44561         var url = apibase + 'images?';
44562         loadTiles('images', url, projection$$1);
44563     },
44564
44565
44566     loadSigns: function(context, projection$$1) {
44567         var url = apibase + 'objects?';
44568         loadTiles('signs', url, projection$$1);
44569
44570         // load traffic sign defs
44571         if (!mapillarySignDefs) {
44572             mapillarySignSprite = context.asset('img/traffic-signs/traffic-signs.png');
44573             mapillarySignDefs = {};
44574             json(context.asset('img/traffic-signs/traffic-signs.json'), function(err, data) {
44575                 if (err) return;
44576                 mapillarySignDefs = data;
44577             });
44578         }
44579     },
44580
44581
44582     loadViewer: function(context) {
44583         var that = this;
44584         var wrap = select('#content').selectAll('.mapillary-wrap')
44585             .data([0]);
44586
44587         var enter = wrap.enter()
44588             .append('div')
44589             .attr('class', 'mapillary-wrap')
44590             .classed('al', true)       // 'al'=left,  'ar'=right
44591             .classed('hidden', true);
44592
44593         enter
44594             .append('button')
44595             .attr('class', 'thumb-hide')
44596             .on('click', function () { that.hideViewer(); })
44597             .append('div')
44598             .call(svgIcon('#icon-close'));
44599
44600         enter
44601             .append('div')
44602             .attr('id', 'mly')
44603             .attr('class', 'mly-wrapper')
44604             .classed('active', false);
44605
44606         // load mapillary-viewercss
44607         select('head').selectAll('#mapillary-viewercss')
44608             .data([0])
44609             .enter()
44610             .append('link')
44611             .attr('id', 'mapillary-viewercss')
44612             .attr('rel', 'stylesheet')
44613             .attr('href', context.asset(viewercss));
44614
44615         // load mapillary-viewerjs
44616         select('head').selectAll('#mapillary-viewerjs')
44617             .data([0])
44618             .enter()
44619             .append('script')
44620             .attr('id', 'mapillary-viewerjs')
44621             .attr('src', context.asset(viewerjs));
44622     },
44623
44624
44625     showViewer: function() {
44626         select('#content')
44627             .selectAll('.mapillary-wrap')
44628             .classed('hidden', false)
44629             .selectAll('.mly-wrapper')
44630             .classed('active', true);
44631
44632         return this;
44633     },
44634
44635
44636     hideViewer: function() {
44637         select('#content')
44638             .selectAll('.mapillary-wrap')
44639             .classed('hidden', true)
44640             .selectAll('.mly-wrapper')
44641             .classed('active', false);
44642
44643         selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
44644             .classed('selected', false);
44645
44646         mapillaryImage = null;
44647         return this;
44648     },
44649
44650
44651     parsePagination: parsePagination,
44652
44653
44654     updateViewer: function(imageKey, context) {
44655         if (!imageKey) return;
44656
44657         if (!mapillaryViewer) {
44658             this.initViewer(imageKey, context);
44659         } else {
44660             mapillaryViewer.moveToKey(imageKey);
44661         }
44662
44663         return this;
44664     },
44665
44666
44667     initViewer: function(imageKey, context) {
44668         var that = this;
44669         if (Mapillary && imageKey) {
44670             var opts = {
44671                 baseImageSize: 320,
44672                 component: {
44673                     cover: false,
44674                     keyboard: false
44675                 }
44676             };
44677
44678             mapillaryViewer = new Mapillary.Viewer('mly', clientId, imageKey, opts);
44679             mapillaryViewer.on('nodechanged', nodeChanged);
44680         }
44681
44682         function nodeChanged(node) {
44683             var clicks = mapillaryClicks;
44684             var index = clicks.indexOf(node.key);
44685             if (index > -1) {    // nodechange initiated from clicking on a marker..
44686                 clicks.splice(index, 1);
44687             } else {             // nodechange initiated from the Mapillary viewer controls..
44688                 var loc = node.computedLatLon ? [node.computedLatLon.lon, node.computedLatLon.lat] : [node.latLon.lon, node.latLon.lat];
44689                 context.map().centerEase(loc);
44690                 that.selectedImage(node.key, false);
44691             }
44692         }
44693     },
44694
44695
44696     selectedImage: function(imageKey, fromClick) {
44697         if (!arguments.length) return mapillaryImage;
44698
44699         mapillaryImage = imageKey;
44700         if (fromClick) {
44701             mapillaryClicks.push(imageKey);
44702         }
44703
44704         selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
44705             .classed('selected', function(d) { return d.key === imageKey; });
44706
44707         return this;
44708     },
44709
44710
44711     cache: function(_) {
44712         if (!arguments.length) return mapillaryCache;
44713         mapillaryCache = _;
44714         return this;
44715     },
44716
44717
44718     signDefs: function(_) {
44719         if (!arguments.length) return mapillarySignDefs;
44720         mapillarySignDefs = _;
44721         return this;
44722     }
44723
44724 };
44725
44726 var apibase$1 = 'https://nominatim.openstreetmap.org/';
44727 var inflight = {};
44728 var nominatimCache;
44729
44730
44731 var serviceNominatim = {
44732
44733     init: function() {
44734         inflight = {};
44735         nominatimCache = index$9();
44736     },
44737
44738     reset: function() {
44739         lodash.forEach(inflight, function(req) { req.abort(); });
44740         inflight = {};
44741         nominatimCache = index$9();
44742     },
44743
44744
44745     countryCode: function (location, callback) {
44746         this.reverse(location, function(err, result) {
44747             if (err) {
44748                 return callback(err);
44749             } else if (result.address) {
44750                 return callback(null, result.address.country_code);
44751             } else {
44752                 return callback('Unable to geocode', null);
44753             }
44754         });
44755     },
44756
44757
44758     reverse: function (location, callback) {
44759         var cached = nominatimCache.search(
44760             { minX: location[0], minY: location[1], maxX: location[0], maxY: location[1] }
44761         );
44762
44763         if (cached.length > 0) {
44764             return callback(null, cached[0].data);
44765         }
44766
44767         var params = { zoom: 13, format: 'json', addressdetails: 1, lat: location[1], lon: location[0] };
44768         var url = apibase$1 + 'reverse?' + utilQsString(params);
44769         if (inflight[url]) return;
44770
44771         inflight[url] = json(url, function(err, result) {
44772             delete inflight[url];
44773
44774             if (err) {
44775                 return callback(err);
44776             } else if (result && result.error) {
44777                 return callback(result.error);
44778             }
44779
44780             var extent$$1 = geoExtent$$1(location).padByMeters(200);
44781             nominatimCache.insert(lodash.assign(extent$$1.bbox(), {data: result}));
44782
44783             callback(null, result);
44784         });
44785     },
44786
44787
44788     search: function (val, callback) {
44789         var searchVal = encodeURIComponent(val);
44790         var url = apibase$1 + 'search/' + searchVal + '?limit=10&format=json';
44791         if (inflight[url]) return;
44792
44793         inflight[url] = json(url, function(err, result) {
44794             delete inflight[url];
44795             callback(err, result);
44796         });
44797     }
44798
44799 };
44800
44801 var hashes = createCommonjsModule(function (module, exports) {
44802 /**
44803  * jshashes - https://github.com/h2non/jshashes
44804  * Released under the "New BSD" license
44805  *
44806  * Algorithms specification:
44807  *
44808  * MD5 - http://www.ietf.org/rfc/rfc1321.txt
44809  * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
44810  * SHA1   - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44811  * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44812  * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44813  * HMAC - http://www.ietf.org/rfc/rfc2104.txt
44814  */
44815 (function() {
44816   var Hashes;
44817
44818   function utf8Encode(str) {
44819     var x, y, output = '',
44820       i = -1,
44821       l;
44822
44823     if (str && str.length) {
44824       l = str.length;
44825       while ((i += 1) < l) {
44826         /* Decode utf-16 surrogate pairs */
44827         x = str.charCodeAt(i);
44828         y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
44829         if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
44830           x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
44831           i += 1;
44832         }
44833         /* Encode output as utf-8 */
44834         if (x <= 0x7F) {
44835           output += String.fromCharCode(x);
44836         } else if (x <= 0x7FF) {
44837           output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F),
44838             0x80 | (x & 0x3F));
44839         } else if (x <= 0xFFFF) {
44840           output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
44841             0x80 | ((x >>> 6) & 0x3F),
44842             0x80 | (x & 0x3F));
44843         } else if (x <= 0x1FFFFF) {
44844           output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
44845             0x80 | ((x >>> 12) & 0x3F),
44846             0x80 | ((x >>> 6) & 0x3F),
44847             0x80 | (x & 0x3F));
44848         }
44849       }
44850     }
44851     return output;
44852   }
44853
44854   function utf8Decode(str) {
44855     var i, ac, c1, c2, c3, arr = [],
44856       l;
44857     i = ac = c1 = c2 = c3 = 0;
44858
44859     if (str && str.length) {
44860       l = str.length;
44861       str += '';
44862
44863       while (i < l) {
44864         c1 = str.charCodeAt(i);
44865         ac += 1;
44866         if (c1 < 128) {
44867           arr[ac] = String.fromCharCode(c1);
44868           i += 1;
44869         } else if (c1 > 191 && c1 < 224) {
44870           c2 = str.charCodeAt(i + 1);
44871           arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
44872           i += 2;
44873         } else {
44874           c2 = str.charCodeAt(i + 1);
44875           c3 = str.charCodeAt(i + 2);
44876           arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
44877           i += 3;
44878         }
44879       }
44880     }
44881     return arr.join('');
44882   }
44883
44884   /**
44885    * Add integers, wrapping at 2^32. This uses 16-bit operations internally
44886    * to work around bugs in some JS interpreters.
44887    */
44888
44889   function safe_add(x, y) {
44890     var lsw = (x & 0xFFFF) + (y & 0xFFFF),
44891       msw = (x >> 16) + (y >> 16) + (lsw >> 16);
44892     return (msw << 16) | (lsw & 0xFFFF);
44893   }
44894
44895   /**
44896    * Bitwise rotate a 32-bit number to the left.
44897    */
44898
44899   function bit_rol(num, cnt) {
44900     return (num << cnt) | (num >>> (32 - cnt));
44901   }
44902
44903   /**
44904    * Convert a raw string to a hex string
44905    */
44906
44907   function rstr2hex(input, hexcase) {
44908     var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
44909       output = '',
44910       x, i = 0,
44911       l = input.length;
44912     for (; i < l; i += 1) {
44913       x = input.charCodeAt(i);
44914       output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F);
44915     }
44916     return output;
44917   }
44918
44919   /**
44920    * Encode a string as utf-16
44921    */
44922
44923   function binb2rstr(input) {
44924     var i, l = input.length * 32,
44925       output = '';
44926     for (i = 0; i < l; i += 8) {
44927       output += String.fromCharCode((input[i >> 5] >>> (24 - i % 32)) & 0xFF);
44928     }
44929     return output;
44930   }
44931
44932   /**
44933    * Convert an array of little-endian words to a string
44934    */
44935
44936   function binl2rstr(input) {
44937     var i, l = input.length * 32,
44938       output = '';
44939     for (i = 0; i < l; i += 8) {
44940       output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
44941     }
44942     return output;
44943   }
44944
44945   /**
44946    * Convert a raw string to an array of little-endian words
44947    * Characters >255 have their high-byte silently ignored.
44948    */
44949
44950   function rstr2binl(input) {
44951     var i, l = input.length * 8,
44952       output = Array(input.length >> 2),
44953       lo = output.length;
44954     for (i = 0; i < lo; i += 1) {
44955       output[i] = 0;
44956     }
44957     for (i = 0; i < l; i += 8) {
44958       output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
44959     }
44960     return output;
44961   }
44962
44963   /**
44964    * Convert a raw string to an array of big-endian words
44965    * Characters >255 have their high-byte silently ignored.
44966    */
44967
44968   function rstr2binb(input) {
44969     var i, l = input.length * 8,
44970       output = Array(input.length >> 2),
44971       lo = output.length;
44972     for (i = 0; i < lo; i += 1) {
44973       output[i] = 0;
44974     }
44975     for (i = 0; i < l; i += 8) {
44976       output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
44977     }
44978     return output;
44979   }
44980
44981   /**
44982    * Convert a raw string to an arbitrary string encoding
44983    */
44984
44985   function rstr2any(input, encoding) {
44986     var divisor = encoding.length,
44987       remainders = Array(),
44988       i, q, x, ld, quotient, dividend, output, full_length;
44989
44990     /* Convert to an array of 16-bit big-endian values, forming the dividend */
44991     dividend = Array(Math.ceil(input.length / 2));
44992     ld = dividend.length;
44993     for (i = 0; i < ld; i += 1) {
44994       dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
44995     }
44996
44997     /**
44998      * Repeatedly perform a long division. The binary array forms the dividend,
44999      * the length of the encoding is the divisor. Once computed, the quotient
45000      * forms the dividend for the next step. We stop when the dividend is zerHashes.
45001      * All remainders are stored for later use.
45002      */
45003     while (dividend.length > 0) {
45004       quotient = Array();
45005       x = 0;
45006       for (i = 0; i < dividend.length; i += 1) {
45007         x = (x << 16) + dividend[i];
45008         q = Math.floor(x / divisor);
45009         x -= q * divisor;
45010         if (quotient.length > 0 || q > 0) {
45011           quotient[quotient.length] = q;
45012         }
45013       }
45014       remainders[remainders.length] = x;
45015       dividend = quotient;
45016     }
45017
45018     /* Convert the remainders to the output string */
45019     output = '';
45020     for (i = remainders.length - 1; i >= 0; i--) {
45021       output += encoding.charAt(remainders[i]);
45022     }
45023
45024     /* Append leading zero equivalents */
45025     full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
45026     for (i = output.length; i < full_length; i += 1) {
45027       output = encoding[0] + output;
45028     }
45029     return output;
45030   }
45031
45032   /**
45033    * Convert a raw string to a base-64 string
45034    */
45035
45036   function rstr2b64(input, b64pad) {
45037     var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
45038       output = '',
45039       len = input.length,
45040       i, j, triplet;
45041     b64pad = b64pad || '=';
45042     for (i = 0; i < len; i += 3) {
45043       triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
45044       for (j = 0; j < 4; j += 1) {
45045         if (i * 8 + j * 6 > input.length * 8) {
45046           output += b64pad;
45047         } else {
45048           output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
45049         }
45050       }
45051     }
45052     return output;
45053   }
45054
45055   Hashes = {
45056     /**
45057      * @property {String} version
45058      * @readonly
45059      */
45060     VERSION: '1.0.6',
45061     /**
45062      * @member Hashes
45063      * @class Base64
45064      * @constructor
45065      */
45066     Base64: function() {
45067       // private properties
45068       var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
45069         pad = '=', // default pad according with the RFC standard
45070         url = false, // URL encoding support @todo
45071         utf8 = true; // by default enable UTF-8 support encoding
45072
45073       // public method for encoding
45074       this.encode = function(input) {
45075         var i, j, triplet,
45076           output = '',
45077           len = input.length;
45078
45079         pad = pad || '=';
45080         input = (utf8) ? utf8Encode(input) : input;
45081
45082         for (i = 0; i < len; i += 3) {
45083           triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
45084           for (j = 0; j < 4; j += 1) {
45085             if (i * 8 + j * 6 > len * 8) {
45086               output += pad;
45087             } else {
45088               output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
45089             }
45090           }
45091         }
45092         return output;
45093       };
45094
45095       // public method for decoding
45096       this.decode = function(input) {
45097         // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
45098         var i, o1, o2, o3, h1, h2, h3, h4, bits, ac,
45099           dec = '',
45100           arr = [];
45101         if (!input) {
45102           return input;
45103         }
45104
45105         i = ac = 0;
45106         input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
45107         //input += '';
45108
45109         do { // unpack four hexets into three octets using index points in b64
45110           h1 = tab.indexOf(input.charAt(i += 1));
45111           h2 = tab.indexOf(input.charAt(i += 1));
45112           h3 = tab.indexOf(input.charAt(i += 1));
45113           h4 = tab.indexOf(input.charAt(i += 1));
45114
45115           bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
45116
45117           o1 = bits >> 16 & 0xff;
45118           o2 = bits >> 8 & 0xff;
45119           o3 = bits & 0xff;
45120           ac += 1;
45121
45122           if (h3 === 64) {
45123             arr[ac] = String.fromCharCode(o1);
45124           } else if (h4 === 64) {
45125             arr[ac] = String.fromCharCode(o1, o2);
45126           } else {
45127             arr[ac] = String.fromCharCode(o1, o2, o3);
45128           }
45129         } while (i < input.length);
45130
45131         dec = arr.join('');
45132         dec = (utf8) ? utf8Decode(dec) : dec;
45133
45134         return dec;
45135       };
45136
45137       // set custom pad string
45138       this.setPad = function(str) {
45139         pad = str || pad;
45140         return this;
45141       };
45142       // set custom tab string characters
45143       this.setTab = function(str) {
45144         tab = str || tab;
45145         return this;
45146       };
45147       this.setUTF8 = function(bool) {
45148         if (typeof bool === 'boolean') {
45149           utf8 = bool;
45150         }
45151         return this;
45152       };
45153     },
45154
45155     /**
45156      * CRC-32 calculation
45157      * @member Hashes
45158      * @method CRC32
45159      * @static
45160      * @param {String} str Input String
45161      * @return {String}
45162      */
45163     CRC32: function(str) {
45164       var crc = 0,
45165         x = 0,
45166         y = 0,
45167         table, i, iTop;
45168       str = utf8Encode(str);
45169
45170       table = [
45171         '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ',
45172         '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ',
45173         '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ',
45174         '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ',
45175         'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ',
45176         '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ',
45177         'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ',
45178         '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ',
45179         'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ',
45180         '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ',
45181         'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ',
45182         '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ',
45183         'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ',
45184         '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ',
45185         '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ',
45186         '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ',
45187         '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ',
45188         'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ',
45189         '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ',
45190         'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ',
45191         '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ',
45192         'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ',
45193         '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ',
45194         'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ',
45195         '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ',
45196         'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'
45197       ].join('');
45198
45199       crc = crc ^ (-1);
45200       for (i = 0, iTop = str.length; i < iTop; i += 1) {
45201         y = (crc ^ str.charCodeAt(i)) & 0xFF;
45202         x = '0x' + table.substr(y * 9, 8);
45203         crc = (crc >>> 8) ^ x;
45204       }
45205       // always return a positive number (that's what >>> 0 does)
45206       return (crc ^ (-1)) >>> 0;
45207     },
45208     /**
45209      * @member Hashes
45210      * @class MD5
45211      * @constructor
45212      * @param {Object} [config]
45213      *
45214      * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
45215      * Digest Algorithm, as defined in RFC 1321.
45216      * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
45217      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45218      * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
45219      */
45220     MD5: function(options) {
45221       /**
45222        * Private config properties. You may need to tweak these to be compatible with
45223        * the server-side, but the defaults work in most cases.
45224        * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
45225        */
45226       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
45227         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
45228         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
45229
45230       // privileged (public) methods
45231       this.hex = function(s) {
45232         return rstr2hex(rstr(s, utf8), hexcase);
45233       };
45234       this.b64 = function(s) {
45235         return rstr2b64(rstr(s), b64pad);
45236       };
45237       this.any = function(s, e) {
45238         return rstr2any(rstr(s, utf8), e);
45239       };
45240       this.raw = function(s) {
45241         return rstr(s, utf8);
45242       };
45243       this.hex_hmac = function(k, d) {
45244         return rstr2hex(rstr_hmac(k, d), hexcase);
45245       };
45246       this.b64_hmac = function(k, d) {
45247         return rstr2b64(rstr_hmac(k, d), b64pad);
45248       };
45249       this.any_hmac = function(k, d, e) {
45250         return rstr2any(rstr_hmac(k, d), e);
45251       };
45252       /**
45253        * Perform a simple self-test to see if the VM is working
45254        * @return {String} Hexadecimal hash sample
45255        */
45256       this.vm_test = function() {
45257         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45258       };
45259       /**
45260        * Enable/disable uppercase hexadecimal returned string
45261        * @param {Boolean}
45262        * @return {Object} this
45263        */
45264       this.setUpperCase = function(a) {
45265         if (typeof a === 'boolean') {
45266           hexcase = a;
45267         }
45268         return this;
45269       };
45270       /**
45271        * Defines a base64 pad string
45272        * @param {String} Pad
45273        * @return {Object} this
45274        */
45275       this.setPad = function(a) {
45276         b64pad = a || b64pad;
45277         return this;
45278       };
45279       /**
45280        * Defines a base64 pad string
45281        * @param {Boolean}
45282        * @return {Object} [this]
45283        */
45284       this.setUTF8 = function(a) {
45285         if (typeof a === 'boolean') {
45286           utf8 = a;
45287         }
45288         return this;
45289       };
45290
45291       // private methods
45292
45293       /**
45294        * Calculate the MD5 of a raw string
45295        */
45296
45297       function rstr(s) {
45298         s = (utf8) ? utf8Encode(s) : s;
45299         return binl2rstr(binl(rstr2binl(s), s.length * 8));
45300       }
45301
45302       /**
45303        * Calculate the HMAC-MD5, of a key and some data (raw strings)
45304        */
45305
45306       function rstr_hmac(key, data) {
45307         var bkey, ipad, opad, hash, i;
45308
45309         key = (utf8) ? utf8Encode(key) : key;
45310         data = (utf8) ? utf8Encode(data) : data;
45311         bkey = rstr2binl(key);
45312         if (bkey.length > 16) {
45313           bkey = binl(bkey, key.length * 8);
45314         }
45315
45316         ipad = Array(16), opad = Array(16);
45317         for (i = 0; i < 16; i += 1) {
45318           ipad[i] = bkey[i] ^ 0x36363636;
45319           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45320         }
45321         hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
45322         return binl2rstr(binl(opad.concat(hash), 512 + 128));
45323       }
45324
45325       /**
45326        * Calculate the MD5 of an array of little-endian words, and a bit length.
45327        */
45328
45329       function binl(x, len) {
45330         var i, olda, oldb, oldc, oldd,
45331           a = 1732584193,
45332           b = -271733879,
45333           c = -1732584194,
45334           d = 271733878;
45335
45336         /* append padding */
45337         x[len >> 5] |= 0x80 << ((len) % 32);
45338         x[(((len + 64) >>> 9) << 4) + 14] = len;
45339
45340         for (i = 0; i < x.length; i += 16) {
45341           olda = a;
45342           oldb = b;
45343           oldc = c;
45344           oldd = d;
45345
45346           a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
45347           d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
45348           c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
45349           b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
45350           a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
45351           d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
45352           c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
45353           b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
45354           a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
45355           d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
45356           c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
45357           b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
45358           a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
45359           d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
45360           c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
45361           b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
45362
45363           a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
45364           d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
45365           c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
45366           b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
45367           a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
45368           d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
45369           c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
45370           b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
45371           a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
45372           d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
45373           c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
45374           b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
45375           a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
45376           d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
45377           c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
45378           b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
45379
45380           a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
45381           d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
45382           c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
45383           b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
45384           a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
45385           d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
45386           c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
45387           b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
45388           a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
45389           d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
45390           c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
45391           b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
45392           a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
45393           d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
45394           c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
45395           b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
45396
45397           a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
45398           d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
45399           c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
45400           b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
45401           a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
45402           d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
45403           c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
45404           b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
45405           a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
45406           d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
45407           c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
45408           b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
45409           a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
45410           d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
45411           c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
45412           b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
45413
45414           a = safe_add(a, olda);
45415           b = safe_add(b, oldb);
45416           c = safe_add(c, oldc);
45417           d = safe_add(d, oldd);
45418         }
45419         return Array(a, b, c, d);
45420       }
45421
45422       /**
45423        * These functions implement the four basic operations the algorithm uses.
45424        */
45425
45426       function md5_cmn(q, a, b, x, s, t) {
45427         return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
45428       }
45429
45430       function md5_ff(a, b, c, d, x, s, t) {
45431         return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
45432       }
45433
45434       function md5_gg(a, b, c, d, x, s, t) {
45435         return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
45436       }
45437
45438       function md5_hh(a, b, c, d, x, s, t) {
45439         return md5_cmn(b ^ c ^ d, a, b, x, s, t);
45440       }
45441
45442       function md5_ii(a, b, c, d, x, s, t) {
45443         return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
45444       }
45445     },
45446     /**
45447      * @member Hashes
45448      * @class Hashes.SHA1
45449      * @param {Object} [config]
45450      * @constructor
45451      *
45452      * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
45453      * Version 2.2 Copyright Paul Johnston 2000 - 2009.
45454      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45455      * See http://pajhome.org.uk/crypt/md5 for details.
45456      */
45457     SHA1: function(options) {
45458       /**
45459        * Private config properties. You may need to tweak these to be compatible with
45460        * the server-side, but the defaults work in most cases.
45461        * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
45462        */
45463       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
45464         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
45465         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
45466
45467       // public methods
45468       this.hex = function(s) {
45469         return rstr2hex(rstr(s, utf8), hexcase);
45470       };
45471       this.b64 = function(s) {
45472         return rstr2b64(rstr(s, utf8), b64pad);
45473       };
45474       this.any = function(s, e) {
45475         return rstr2any(rstr(s, utf8), e);
45476       };
45477       this.raw = function(s) {
45478         return rstr(s, utf8);
45479       };
45480       this.hex_hmac = function(k, d) {
45481         return rstr2hex(rstr_hmac(k, d));
45482       };
45483       this.b64_hmac = function(k, d) {
45484         return rstr2b64(rstr_hmac(k, d), b64pad);
45485       };
45486       this.any_hmac = function(k, d, e) {
45487         return rstr2any(rstr_hmac(k, d), e);
45488       };
45489       /**
45490        * Perform a simple self-test to see if the VM is working
45491        * @return {String} Hexadecimal hash sample
45492        * @public
45493        */
45494       this.vm_test = function() {
45495         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45496       };
45497       /**
45498        * @description Enable/disable uppercase hexadecimal returned string
45499        * @param {boolean}
45500        * @return {Object} this
45501        * @public
45502        */
45503       this.setUpperCase = function(a) {
45504         if (typeof a === 'boolean') {
45505           hexcase = a;
45506         }
45507         return this;
45508       };
45509       /**
45510        * @description Defines a base64 pad string
45511        * @param {string} Pad
45512        * @return {Object} this
45513        * @public
45514        */
45515       this.setPad = function(a) {
45516         b64pad = a || b64pad;
45517         return this;
45518       };
45519       /**
45520        * @description Defines a base64 pad string
45521        * @param {boolean}
45522        * @return {Object} this
45523        * @public
45524        */
45525       this.setUTF8 = function(a) {
45526         if (typeof a === 'boolean') {
45527           utf8 = a;
45528         }
45529         return this;
45530       };
45531
45532       // private methods
45533
45534       /**
45535        * Calculate the SHA-512 of a raw string
45536        */
45537
45538       function rstr(s) {
45539         s = (utf8) ? utf8Encode(s) : s;
45540         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45541       }
45542
45543       /**
45544        * Calculate the HMAC-SHA1 of a key and some data (raw strings)
45545        */
45546
45547       function rstr_hmac(key, data) {
45548         var bkey, ipad, opad, i, hash;
45549         key = (utf8) ? utf8Encode(key) : key;
45550         data = (utf8) ? utf8Encode(data) : data;
45551         bkey = rstr2binb(key);
45552
45553         if (bkey.length > 16) {
45554           bkey = binb(bkey, key.length * 8);
45555         }
45556         ipad = Array(16), opad = Array(16);
45557         for (i = 0; i < 16; i += 1) {
45558           ipad[i] = bkey[i] ^ 0x36363636;
45559           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45560         }
45561         hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
45562         return binb2rstr(binb(opad.concat(hash), 512 + 160));
45563       }
45564
45565       /**
45566        * Calculate the SHA-1 of an array of big-endian words, and a bit length
45567        */
45568
45569       function binb(x, len) {
45570         var i, j, t, olda, oldb, oldc, oldd, olde,
45571           w = Array(80),
45572           a = 1732584193,
45573           b = -271733879,
45574           c = -1732584194,
45575           d = 271733878,
45576           e = -1009589776;
45577
45578         /* append padding */
45579         x[len >> 5] |= 0x80 << (24 - len % 32);
45580         x[((len + 64 >> 9) << 4) + 15] = len;
45581
45582         for (i = 0; i < x.length; i += 16) {
45583           olda = a,
45584           oldb = b;
45585           oldc = c;
45586           oldd = d;
45587           olde = e;
45588
45589           for (j = 0; j < 80; j += 1) {
45590             if (j < 16) {
45591               w[j] = x[i + j];
45592             } else {
45593               w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
45594             }
45595             t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
45596               safe_add(safe_add(e, w[j]), sha1_kt(j)));
45597             e = d;
45598             d = c;
45599             c = bit_rol(b, 30);
45600             b = a;
45601             a = t;
45602           }
45603
45604           a = safe_add(a, olda);
45605           b = safe_add(b, oldb);
45606           c = safe_add(c, oldc);
45607           d = safe_add(d, oldd);
45608           e = safe_add(e, olde);
45609         }
45610         return Array(a, b, c, d, e);
45611       }
45612
45613       /**
45614        * Perform the appropriate triplet combination function for the current
45615        * iteration
45616        */
45617
45618       function sha1_ft(t, b, c, d) {
45619         if (t < 20) {
45620           return (b & c) | ((~b) & d);
45621         }
45622         if (t < 40) {
45623           return b ^ c ^ d;
45624         }
45625         if (t < 60) {
45626           return (b & c) | (b & d) | (c & d);
45627         }
45628         return b ^ c ^ d;
45629       }
45630
45631       /**
45632        * Determine the appropriate additive constant for the current iteration
45633        */
45634
45635       function sha1_kt(t) {
45636         return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
45637           (t < 60) ? -1894007588 : -899497514;
45638       }
45639     },
45640     /**
45641      * @class Hashes.SHA256
45642      * @param {config}
45643      *
45644      * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
45645      * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
45646      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45647      * See http://pajhome.org.uk/crypt/md5 for details.
45648      * Also http://anmar.eu.org/projects/jssha2/
45649      */
45650     SHA256: function(options) {
45651       /**
45652        * Private properties configuration variables. You may need to tweak these to be compatible with
45653        * the server-side, but the defaults work in most cases.
45654        * @see this.setUpperCase() method
45655        * @see this.setPad() method
45656        */
45657       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase  */
45658         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=',
45659         /* base-64 pad character. Default '=' for strict RFC compliance   */
45660         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45661         /* enable/disable utf8 encoding */
45662         sha256_K;
45663
45664       /* privileged (public) methods */
45665       this.hex = function(s) {
45666         return rstr2hex(rstr(s, utf8));
45667       };
45668       this.b64 = function(s) {
45669         return rstr2b64(rstr(s, utf8), b64pad);
45670       };
45671       this.any = function(s, e) {
45672         return rstr2any(rstr(s, utf8), e);
45673       };
45674       this.raw = function(s) {
45675         return rstr(s, utf8);
45676       };
45677       this.hex_hmac = function(k, d) {
45678         return rstr2hex(rstr_hmac(k, d));
45679       };
45680       this.b64_hmac = function(k, d) {
45681         return rstr2b64(rstr_hmac(k, d), b64pad);
45682       };
45683       this.any_hmac = function(k, d, e) {
45684         return rstr2any(rstr_hmac(k, d), e);
45685       };
45686       /**
45687        * Perform a simple self-test to see if the VM is working
45688        * @return {String} Hexadecimal hash sample
45689        * @public
45690        */
45691       this.vm_test = function() {
45692         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45693       };
45694       /**
45695        * Enable/disable uppercase hexadecimal returned string
45696        * @param {boolean}
45697        * @return {Object} this
45698        * @public
45699        */
45700       this.setUpperCase = function(a) {
45701         if (typeof a === 'boolean') {
45702           hexcase = a;
45703         }
45704         return this;
45705       };
45706       /**
45707        * @description Defines a base64 pad string
45708        * @param {string} Pad
45709        * @return {Object} this
45710        * @public
45711        */
45712       this.setPad = function(a) {
45713         b64pad = a || b64pad;
45714         return this;
45715       };
45716       /**
45717        * Defines a base64 pad string
45718        * @param {boolean}
45719        * @return {Object} this
45720        * @public
45721        */
45722       this.setUTF8 = function(a) {
45723         if (typeof a === 'boolean') {
45724           utf8 = a;
45725         }
45726         return this;
45727       };
45728
45729       // private methods
45730
45731       /**
45732        * Calculate the SHA-512 of a raw string
45733        */
45734
45735       function rstr(s, utf8) {
45736         s = (utf8) ? utf8Encode(s) : s;
45737         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45738       }
45739
45740       /**
45741        * Calculate the HMAC-sha256 of a key and some data (raw strings)
45742        */
45743
45744       function rstr_hmac(key, data) {
45745         key = (utf8) ? utf8Encode(key) : key;
45746         data = (utf8) ? utf8Encode(data) : data;
45747         var hash, i = 0,
45748           bkey = rstr2binb(key),
45749           ipad = Array(16),
45750           opad = Array(16);
45751
45752         if (bkey.length > 16) {
45753           bkey = binb(bkey, key.length * 8);
45754         }
45755
45756         for (; i < 16; i += 1) {
45757           ipad[i] = bkey[i] ^ 0x36363636;
45758           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45759         }
45760
45761         hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
45762         return binb2rstr(binb(opad.concat(hash), 512 + 256));
45763       }
45764
45765       /*
45766        * Main sha256 function, with its support functions
45767        */
45768
45769       function sha256_S(X, n) {
45770         return (X >>> n) | (X << (32 - n));
45771       }
45772
45773       function sha256_R(X, n) {
45774         return (X >>> n);
45775       }
45776
45777       function sha256_Ch(x, y, z) {
45778         return ((x & y) ^ ((~x) & z));
45779       }
45780
45781       function sha256_Maj(x, y, z) {
45782         return ((x & y) ^ (x & z) ^ (y & z));
45783       }
45784
45785       function sha256_Sigma0256(x) {
45786         return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));
45787       }
45788
45789       function sha256_Sigma1256(x) {
45790         return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));
45791       }
45792
45793       function sha256_Gamma0256(x) {
45794         return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));
45795       }
45796
45797       function sha256_Gamma1256(x) {
45798         return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));
45799       }
45800
45801       sha256_K = [
45802         1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
45803         1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
45804         264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
45805         113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
45806         1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
45807         430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
45808         1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998
45809       ];
45810
45811       function binb(m, l) {
45812         var HASH = [1779033703, -1150833019, 1013904242, -1521486534,
45813           1359893119, -1694144372, 528734635, 1541459225
45814         ];
45815         var W = new Array(64);
45816         var a, b, c, d, e, f, g, h;
45817         var i, j, T1, T2;
45818
45819         /* append padding */
45820         m[l >> 5] |= 0x80 << (24 - l % 32);
45821         m[((l + 64 >> 9) << 4) + 15] = l;
45822
45823         for (i = 0; i < m.length; i += 16) {
45824           a = HASH[0];
45825           b = HASH[1];
45826           c = HASH[2];
45827           d = HASH[3];
45828           e = HASH[4];
45829           f = HASH[5];
45830           g = HASH[6];
45831           h = HASH[7];
45832
45833           for (j = 0; j < 64; j += 1) {
45834             if (j < 16) {
45835               W[j] = m[j + i];
45836             } else {
45837               W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
45838                 sha256_Gamma0256(W[j - 15])), W[j - 16]);
45839             }
45840
45841             T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
45842               sha256_K[j]), W[j]);
45843             T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
45844             h = g;
45845             g = f;
45846             f = e;
45847             e = safe_add(d, T1);
45848             d = c;
45849             c = b;
45850             b = a;
45851             a = safe_add(T1, T2);
45852           }
45853
45854           HASH[0] = safe_add(a, HASH[0]);
45855           HASH[1] = safe_add(b, HASH[1]);
45856           HASH[2] = safe_add(c, HASH[2]);
45857           HASH[3] = safe_add(d, HASH[3]);
45858           HASH[4] = safe_add(e, HASH[4]);
45859           HASH[5] = safe_add(f, HASH[5]);
45860           HASH[6] = safe_add(g, HASH[6]);
45861           HASH[7] = safe_add(h, HASH[7]);
45862         }
45863         return HASH;
45864       }
45865
45866     },
45867
45868     /**
45869      * @class Hashes.SHA512
45870      * @param {config}
45871      *
45872      * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
45873      * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
45874      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45875      * See http://pajhome.org.uk/crypt/md5 for details.
45876      */
45877     SHA512: function(options) {
45878       /**
45879        * Private properties configuration variables. You may need to tweak these to be compatible with
45880        * the server-side, but the defaults work in most cases.
45881        * @see this.setUpperCase() method
45882        * @see this.setPad() method
45883        */
45884       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false,
45885         /* hexadecimal output case format. false - lowercase; true - uppercase  */
45886         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=',
45887         /* base-64 pad character. Default '=' for strict RFC compliance   */
45888         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45889         /* enable/disable utf8 encoding */
45890         sha512_k;
45891
45892       /* privileged (public) methods */
45893       this.hex = function(s) {
45894         return rstr2hex(rstr(s));
45895       };
45896       this.b64 = function(s) {
45897         return rstr2b64(rstr(s), b64pad);
45898       };
45899       this.any = function(s, e) {
45900         return rstr2any(rstr(s), e);
45901       };
45902       this.raw = function(s) {
45903         return rstr(s, utf8);
45904       };
45905       this.hex_hmac = function(k, d) {
45906         return rstr2hex(rstr_hmac(k, d));
45907       };
45908       this.b64_hmac = function(k, d) {
45909         return rstr2b64(rstr_hmac(k, d), b64pad);
45910       };
45911       this.any_hmac = function(k, d, e) {
45912         return rstr2any(rstr_hmac(k, d), e);
45913       };
45914       /**
45915        * Perform a simple self-test to see if the VM is working
45916        * @return {String} Hexadecimal hash sample
45917        * @public
45918        */
45919       this.vm_test = function() {
45920         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45921       };
45922       /**
45923        * @description Enable/disable uppercase hexadecimal returned string
45924        * @param {boolean}
45925        * @return {Object} this
45926        * @public
45927        */
45928       this.setUpperCase = function(a) {
45929         if (typeof a === 'boolean') {
45930           hexcase = a;
45931         }
45932         return this;
45933       };
45934       /**
45935        * @description Defines a base64 pad string
45936        * @param {string} Pad
45937        * @return {Object} this
45938        * @public
45939        */
45940       this.setPad = function(a) {
45941         b64pad = a || b64pad;
45942         return this;
45943       };
45944       /**
45945        * @description Defines a base64 pad string
45946        * @param {boolean}
45947        * @return {Object} this
45948        * @public
45949        */
45950       this.setUTF8 = function(a) {
45951         if (typeof a === 'boolean') {
45952           utf8 = a;
45953         }
45954         return this;
45955       };
45956
45957       /* private methods */
45958
45959       /**
45960        * Calculate the SHA-512 of a raw string
45961        */
45962
45963       function rstr(s) {
45964         s = (utf8) ? utf8Encode(s) : s;
45965         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45966       }
45967       /*
45968        * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
45969        */
45970
45971       function rstr_hmac(key, data) {
45972         key = (utf8) ? utf8Encode(key) : key;
45973         data = (utf8) ? utf8Encode(data) : data;
45974
45975         var hash, i = 0,
45976           bkey = rstr2binb(key),
45977           ipad = Array(32),
45978           opad = Array(32);
45979
45980         if (bkey.length > 32) {
45981           bkey = binb(bkey, key.length * 8);
45982         }
45983
45984         for (; i < 32; i += 1) {
45985           ipad[i] = bkey[i] ^ 0x36363636;
45986           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45987         }
45988
45989         hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
45990         return binb2rstr(binb(opad.concat(hash), 1024 + 512));
45991       }
45992
45993       /**
45994        * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
45995        */
45996
45997       function binb(x, len) {
45998         var j, i, l,
45999           W = new Array(80),
46000           hash = new Array(16),
46001           //Initial hash values
46002           H = [
46003             new int64(0x6a09e667, -205731576),
46004             new int64(-1150833019, -2067093701),
46005             new int64(0x3c6ef372, -23791573),
46006             new int64(-1521486534, 0x5f1d36f1),
46007             new int64(0x510e527f, -1377402159),
46008             new int64(-1694144372, 0x2b3e6c1f),
46009             new int64(0x1f83d9ab, -79577749),
46010             new int64(0x5be0cd19, 0x137e2179)
46011           ],
46012           T1 = new int64(0, 0),
46013           T2 = new int64(0, 0),
46014           a = new int64(0, 0),
46015           b = new int64(0, 0),
46016           c = new int64(0, 0),
46017           d = new int64(0, 0),
46018           e = new int64(0, 0),
46019           f = new int64(0, 0),
46020           g = new int64(0, 0),
46021           h = new int64(0, 0),
46022           //Temporary variables not specified by the document
46023           s0 = new int64(0, 0),
46024           s1 = new int64(0, 0),
46025           Ch = new int64(0, 0),
46026           Maj = new int64(0, 0),
46027           r1 = new int64(0, 0),
46028           r2 = new int64(0, 0),
46029           r3 = new int64(0, 0);
46030
46031         if (sha512_k === undefined) {
46032           //SHA512 constants
46033           sha512_k = [
46034             new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
46035             new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
46036             new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
46037             new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
46038             new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
46039             new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
46040             new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
46041             new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
46042             new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
46043             new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
46044             new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
46045             new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
46046             new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
46047             new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
46048             new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
46049             new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
46050             new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
46051             new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
46052             new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
46053             new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
46054             new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
46055             new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
46056             new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
46057             new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
46058             new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
46059             new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
46060             new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
46061             new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
46062             new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
46063             new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
46064             new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
46065             new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
46066             new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
46067             new int64(-354779690, -840897762), new int64(-176337025, -294727304),
46068             new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
46069             new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
46070             new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
46071             new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
46072             new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
46073             new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)
46074           ];
46075         }
46076
46077         for (i = 0; i < 80; i += 1) {
46078           W[i] = new int64(0, 0);
46079         }
46080
46081         // append padding to the source string. The format is described in the FIPS.
46082         x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
46083         x[((len + 128 >> 10) << 5) + 31] = len;
46084         l = x.length;
46085         for (i = 0; i < l; i += 32) { //32 dwords is the block size
46086           int64copy(a, H[0]);
46087           int64copy(b, H[1]);
46088           int64copy(c, H[2]);
46089           int64copy(d, H[3]);
46090           int64copy(e, H[4]);
46091           int64copy(f, H[5]);
46092           int64copy(g, H[6]);
46093           int64copy(h, H[7]);
46094
46095           for (j = 0; j < 16; j += 1) {
46096             W[j].h = x[i + 2 * j];
46097             W[j].l = x[i + 2 * j + 1];
46098           }
46099
46100           for (j = 16; j < 80; j += 1) {
46101             //sigma1
46102             int64rrot(r1, W[j - 2], 19);
46103             int64revrrot(r2, W[j - 2], 29);
46104             int64shr(r3, W[j - 2], 6);
46105             s1.l = r1.l ^ r2.l ^ r3.l;
46106             s1.h = r1.h ^ r2.h ^ r3.h;
46107             //sigma0
46108             int64rrot(r1, W[j - 15], 1);
46109             int64rrot(r2, W[j - 15], 8);
46110             int64shr(r3, W[j - 15], 7);
46111             s0.l = r1.l ^ r2.l ^ r3.l;
46112             s0.h = r1.h ^ r2.h ^ r3.h;
46113
46114             int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
46115           }
46116
46117           for (j = 0; j < 80; j += 1) {
46118             //Ch
46119             Ch.l = (e.l & f.l) ^ (~e.l & g.l);
46120             Ch.h = (e.h & f.h) ^ (~e.h & g.h);
46121
46122             //Sigma1
46123             int64rrot(r1, e, 14);
46124             int64rrot(r2, e, 18);
46125             int64revrrot(r3, e, 9);
46126             s1.l = r1.l ^ r2.l ^ r3.l;
46127             s1.h = r1.h ^ r2.h ^ r3.h;
46128
46129             //Sigma0
46130             int64rrot(r1, a, 28);
46131             int64revrrot(r2, a, 2);
46132             int64revrrot(r3, a, 7);
46133             s0.l = r1.l ^ r2.l ^ r3.l;
46134             s0.h = r1.h ^ r2.h ^ r3.h;
46135
46136             //Maj
46137             Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
46138             Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
46139
46140             int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
46141             int64add(T2, s0, Maj);
46142
46143             int64copy(h, g);
46144             int64copy(g, f);
46145             int64copy(f, e);
46146             int64add(e, d, T1);
46147             int64copy(d, c);
46148             int64copy(c, b);
46149             int64copy(b, a);
46150             int64add(a, T1, T2);
46151           }
46152           int64add(H[0], H[0], a);
46153           int64add(H[1], H[1], b);
46154           int64add(H[2], H[2], c);
46155           int64add(H[3], H[3], d);
46156           int64add(H[4], H[4], e);
46157           int64add(H[5], H[5], f);
46158           int64add(H[6], H[6], g);
46159           int64add(H[7], H[7], h);
46160         }
46161
46162         //represent the hash as an array of 32-bit dwords
46163         for (i = 0; i < 8; i += 1) {
46164           hash[2 * i] = H[i].h;
46165           hash[2 * i + 1] = H[i].l;
46166         }
46167         return hash;
46168       }
46169
46170       //A constructor for 64-bit numbers
46171
46172       function int64(h, l) {
46173         this.h = h;
46174         this.l = l;
46175         //this.toString = int64toString;
46176       }
46177
46178       //Copies src into dst, assuming both are 64-bit numbers
46179
46180       function int64copy(dst, src) {
46181         dst.h = src.h;
46182         dst.l = src.l;
46183       }
46184
46185       //Right-rotates a 64-bit number by shift
46186       //Won't handle cases of shift>=32
46187       //The function revrrot() is for that
46188
46189       function int64rrot(dst, x, shift) {
46190         dst.l = (x.l >>> shift) | (x.h << (32 - shift));
46191         dst.h = (x.h >>> shift) | (x.l << (32 - shift));
46192       }
46193
46194       //Reverses the dwords of the source and then rotates right by shift.
46195       //This is equivalent to rotation by 32+shift
46196
46197       function int64revrrot(dst, x, shift) {
46198         dst.l = (x.h >>> shift) | (x.l << (32 - shift));
46199         dst.h = (x.l >>> shift) | (x.h << (32 - shift));
46200       }
46201
46202       //Bitwise-shifts right a 64-bit number by shift
46203       //Won't handle shift>=32, but it's never needed in SHA512
46204
46205       function int64shr(dst, x, shift) {
46206         dst.l = (x.l >>> shift) | (x.h << (32 - shift));
46207         dst.h = (x.h >>> shift);
46208       }
46209
46210       //Adds two 64-bit numbers
46211       //Like the original implementation, does not rely on 32-bit operations
46212
46213       function int64add(dst, x, y) {
46214         var w0 = (x.l & 0xffff) + (y.l & 0xffff);
46215         var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
46216         var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
46217         var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
46218         dst.l = (w0 & 0xffff) | (w1 << 16);
46219         dst.h = (w2 & 0xffff) | (w3 << 16);
46220       }
46221
46222       //Same, except with 4 addends. Works faster than adding them one by one.
46223
46224       function int64add4(dst, a, b, c, d) {
46225         var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
46226         var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
46227         var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
46228         var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
46229         dst.l = (w0 & 0xffff) | (w1 << 16);
46230         dst.h = (w2 & 0xffff) | (w3 << 16);
46231       }
46232
46233       //Same, except with 5 addends
46234
46235       function int64add5(dst, a, b, c, d, e) {
46236         var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
46237           w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
46238           w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
46239           w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
46240         dst.l = (w0 & 0xffff) | (w1 << 16);
46241         dst.h = (w2 & 0xffff) | (w3 << 16);
46242       }
46243     },
46244     /**
46245      * @class Hashes.RMD160
46246      * @constructor
46247      * @param {Object} [config]
46248      *
46249      * A JavaScript implementation of the RIPEMD-160 Algorithm
46250      * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
46251      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
46252      * See http://pajhome.org.uk/crypt/md5 for details.
46253      * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
46254      */
46255     RMD160: function(options) {
46256       /**
46257        * Private properties configuration variables. You may need to tweak these to be compatible with
46258        * the server-side, but the defaults work in most cases.
46259        * @see this.setUpperCase() method
46260        * @see this.setPad() method
46261        */
46262       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false,
46263         /* hexadecimal output case format. false - lowercase; true - uppercase  */
46264         b64pad = (options && typeof options.pad === 'string') ? options.pa : '=',
46265         /* base-64 pad character. Default '=' for strict RFC compliance   */
46266         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
46267         /* enable/disable utf8 encoding */
46268         rmd160_r1 = [
46269           0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
46270           7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
46271           3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
46272           1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
46273           4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
46274         ],
46275         rmd160_r2 = [
46276           5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
46277           6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
46278           15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
46279           8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
46280           12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
46281         ],
46282         rmd160_s1 = [
46283           11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
46284           7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
46285           11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
46286           11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
46287           9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
46288         ],
46289         rmd160_s2 = [
46290           8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
46291           9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
46292           9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
46293           15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
46294           8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
46295         ];
46296
46297       /* privileged (public) methods */
46298       this.hex = function(s) {
46299         return rstr2hex(rstr(s, utf8));
46300       };
46301       this.b64 = function(s) {
46302         return rstr2b64(rstr(s, utf8), b64pad);
46303       };
46304       this.any = function(s, e) {
46305         return rstr2any(rstr(s, utf8), e);
46306       };
46307       this.raw = function(s) {
46308         return rstr(s, utf8);
46309       };
46310       this.hex_hmac = function(k, d) {
46311         return rstr2hex(rstr_hmac(k, d));
46312       };
46313       this.b64_hmac = function(k, d) {
46314         return rstr2b64(rstr_hmac(k, d), b64pad);
46315       };
46316       this.any_hmac = function(k, d, e) {
46317         return rstr2any(rstr_hmac(k, d), e);
46318       };
46319       /**
46320        * Perform a simple self-test to see if the VM is working
46321        * @return {String} Hexadecimal hash sample
46322        * @public
46323        */
46324       this.vm_test = function() {
46325         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
46326       };
46327       /**
46328        * @description Enable/disable uppercase hexadecimal returned string
46329        * @param {boolean}
46330        * @return {Object} this
46331        * @public
46332        */
46333       this.setUpperCase = function(a) {
46334         if (typeof a === 'boolean') {
46335           hexcase = a;
46336         }
46337         return this;
46338       };
46339       /**
46340        * @description Defines a base64 pad string
46341        * @param {string} Pad
46342        * @return {Object} this
46343        * @public
46344        */
46345       this.setPad = function(a) {
46346         if (typeof a !== 'undefined') {
46347           b64pad = a;
46348         }
46349         return this;
46350       };
46351       /**
46352        * @description Defines a base64 pad string
46353        * @param {boolean}
46354        * @return {Object} this
46355        * @public
46356        */
46357       this.setUTF8 = function(a) {
46358         if (typeof a === 'boolean') {
46359           utf8 = a;
46360         }
46361         return this;
46362       };
46363
46364       /* private methods */
46365
46366       /**
46367        * Calculate the rmd160 of a raw string
46368        */
46369
46370       function rstr(s) {
46371         s = (utf8) ? utf8Encode(s) : s;
46372         return binl2rstr(binl(rstr2binl(s), s.length * 8));
46373       }
46374
46375       /**
46376        * Calculate the HMAC-rmd160 of a key and some data (raw strings)
46377        */
46378
46379       function rstr_hmac(key, data) {
46380         key = (utf8) ? utf8Encode(key) : key;
46381         data = (utf8) ? utf8Encode(data) : data;
46382         var i, hash,
46383           bkey = rstr2binl(key),
46384           ipad = Array(16),
46385           opad = Array(16);
46386
46387         if (bkey.length > 16) {
46388           bkey = binl(bkey, key.length * 8);
46389         }
46390
46391         for (i = 0; i < 16; i += 1) {
46392           ipad[i] = bkey[i] ^ 0x36363636;
46393           opad[i] = bkey[i] ^ 0x5C5C5C5C;
46394         }
46395         hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
46396         return binl2rstr(binl(opad.concat(hash), 512 + 160));
46397       }
46398
46399       /**
46400        * Convert an array of little-endian words to a string
46401        */
46402
46403       function binl2rstr(input) {
46404         var i, output = '',
46405           l = input.length * 32;
46406         for (i = 0; i < l; i += 8) {
46407           output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
46408         }
46409         return output;
46410       }
46411
46412       /**
46413        * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
46414        */
46415
46416       function binl(x, len) {
46417         var T, j, i, l,
46418           h0 = 0x67452301,
46419           h1 = 0xefcdab89,
46420           h2 = 0x98badcfe,
46421           h3 = 0x10325476,
46422           h4 = 0xc3d2e1f0,
46423           A1, B1, C1, D1, E1,
46424           A2, B2, C2, D2, E2;
46425
46426         /* append padding */
46427         x[len >> 5] |= 0x80 << (len % 32);
46428         x[(((len + 64) >>> 9) << 4) + 14] = len;
46429         l = x.length;
46430
46431         for (i = 0; i < l; i += 16) {
46432           A1 = A2 = h0;
46433           B1 = B2 = h1;
46434           C1 = C2 = h2;
46435           D1 = D2 = h3;
46436           E1 = E2 = h4;
46437           for (j = 0; j <= 79; j += 1) {
46438             T = safe_add(A1, rmd160_f(j, B1, C1, D1));
46439             T = safe_add(T, x[i + rmd160_r1[j]]);
46440             T = safe_add(T, rmd160_K1(j));
46441             T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
46442             A1 = E1;
46443             E1 = D1;
46444             D1 = bit_rol(C1, 10);
46445             C1 = B1;
46446             B1 = T;
46447             T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
46448             T = safe_add(T, x[i + rmd160_r2[j]]);
46449             T = safe_add(T, rmd160_K2(j));
46450             T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
46451             A2 = E2;
46452             E2 = D2;
46453             D2 = bit_rol(C2, 10);
46454             C2 = B2;
46455             B2 = T;
46456           }
46457
46458           T = safe_add(h1, safe_add(C1, D2));
46459           h1 = safe_add(h2, safe_add(D1, E2));
46460           h2 = safe_add(h3, safe_add(E1, A2));
46461           h3 = safe_add(h4, safe_add(A1, B2));
46462           h4 = safe_add(h0, safe_add(B1, C2));
46463           h0 = T;
46464         }
46465         return [h0, h1, h2, h3, h4];
46466       }
46467
46468       // specific algorithm methods
46469
46470       function rmd160_f(j, x, y, z) {
46471         return (0 <= j && j <= 15) ? (x ^ y ^ z) :
46472           (16 <= j && j <= 31) ? (x & y) | (~x & z) :
46473           (32 <= j && j <= 47) ? (x | ~y) ^ z :
46474           (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
46475           (64 <= j && j <= 79) ? x ^ (y | ~z) :
46476           'rmd160_f: j out of range';
46477       }
46478
46479       function rmd160_K1(j) {
46480         return (0 <= j && j <= 15) ? 0x00000000 :
46481           (16 <= j && j <= 31) ? 0x5a827999 :
46482           (32 <= j && j <= 47) ? 0x6ed9eba1 :
46483           (48 <= j && j <= 63) ? 0x8f1bbcdc :
46484           (64 <= j && j <= 79) ? 0xa953fd4e :
46485           'rmd160_K1: j out of range';
46486       }
46487
46488       function rmd160_K2(j) {
46489         return (0 <= j && j <= 15) ? 0x50a28be6 :
46490           (16 <= j && j <= 31) ? 0x5c4dd124 :
46491           (32 <= j && j <= 47) ? 0x6d703ef3 :
46492           (48 <= j && j <= 63) ? 0x7a6d76e9 :
46493           (64 <= j && j <= 79) ? 0x00000000 :
46494           'rmd160_K2: j out of range';
46495       }
46496     }
46497   };
46498
46499   // exposes Hashes
46500   (function(window, undefined) {
46501     var freeExports = false;
46502     {
46503       freeExports = exports;
46504       if (exports && typeof commonjsGlobal === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
46505         window = commonjsGlobal;
46506       }
46507     }
46508
46509     if (typeof undefined === 'function' && typeof undefined.amd === 'object' && undefined.amd) {
46510       // define as an anonymous module, so, through path mapping, it can be aliased
46511       undefined(function() {
46512         return Hashes;
46513       });
46514     } else if (freeExports) {
46515       // in Node.js or RingoJS v0.8.0+
46516       if ('object' === 'object' && module && module.exports === freeExports) {
46517         module.exports = Hashes;
46518       }
46519       // in Narwhal or RingoJS v0.7.0-
46520       else {
46521         freeExports.Hashes = Hashes;
46522       }
46523     } else {
46524       // in a browser or Rhino
46525       window.Hashes = Hashes;
46526     }
46527   }(this));
46528 }()); // IIFE
46529 });
46530
46531 var immutable = extend$2;
46532
46533 var hasOwnProperty = Object.prototype.hasOwnProperty;
46534
46535 function extend$2() {
46536     var target = {};
46537
46538     for (var i = 0; i < arguments.length; i++) {
46539         var source = arguments[i];
46540
46541         for (var key in source) {
46542             if (hasOwnProperty.call(source, key)) {
46543                 target[key] = source[key];
46544             }
46545         }
46546     }
46547
46548     return target
46549 }
46550
46551 var sha1 = new hashes.SHA1();
46552
46553 var ohauth = {};
46554
46555 ohauth.qsString = function(obj) {
46556     return Object.keys(obj).sort().map(function(key) {
46557         return ohauth.percentEncode(key) + '=' +
46558             ohauth.percentEncode(obj[key]);
46559     }).join('&');
46560 };
46561
46562 ohauth.stringQs = function(str) {
46563     return str.split('&').filter(function (pair) {
46564         return pair !== '';
46565     }).reduce(function(obj, pair){
46566         var parts = pair.split('=');
46567         obj[decodeURIComponent(parts[0])] = (null === parts[1]) ?
46568             '' : decodeURIComponent(parts[1]);
46569         return obj;
46570     }, {});
46571 };
46572
46573 ohauth.rawxhr = function(method, url, data, headers, callback) {
46574     var xhr = new XMLHttpRequest(),
46575         twoHundred = /^20\d$/;
46576     xhr.onreadystatechange = function() {
46577         if (4 === xhr.readyState && 0 !== xhr.status) {
46578             if (twoHundred.test(xhr.status)) callback(null, xhr);
46579             else return callback(xhr, null);
46580         }
46581     };
46582     xhr.onerror = function(e) { return callback(e, null); };
46583     xhr.open(method, url, true);
46584     for (var h in headers) xhr.setRequestHeader(h, headers[h]);
46585     xhr.send(data);
46586     return xhr;
46587 };
46588
46589 ohauth.xhr = function(method, url, auth, data, options, callback) {
46590     var headers = (options && options.header) || {
46591         'Content-Type': 'application/x-www-form-urlencoded'
46592     };
46593     headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
46594     return ohauth.rawxhr(method, url, data, headers, callback);
46595 };
46596
46597 ohauth.nonce = function() {
46598     for (var o = ''; o.length < 6;) {
46599         o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
46600     }
46601     return o;
46602 };
46603
46604 ohauth.authHeader = function(obj) {
46605     return Object.keys(obj).sort().map(function(key) {
46606         return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
46607     }).join(', ');
46608 };
46609
46610 ohauth.timestamp = function() { return ~~((+new Date()) / 1000); };
46611
46612 ohauth.percentEncode = function(s) {
46613     return encodeURIComponent(s)
46614         .replace(/\!/g, '%21').replace(/\'/g, '%27')
46615         .replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
46616 };
46617
46618 ohauth.baseString = function(method, url, params) {
46619     if (params.oauth_signature) delete params.oauth_signature;
46620     return [
46621         method,
46622         ohauth.percentEncode(url),
46623         ohauth.percentEncode(ohauth.qsString(params))].join('&');
46624 };
46625
46626 ohauth.signature = function(oauth_secret, token_secret, baseString) {
46627     return sha1.b64_hmac(
46628         ohauth.percentEncode(oauth_secret) + '&' +
46629         ohauth.percentEncode(token_secret),
46630         baseString);
46631 };
46632
46633 /**
46634  * Takes an options object for configuration (consumer_key,
46635  * consumer_secret, version, signature_method, token, token_secret)
46636  * and returns a function that generates the Authorization header
46637  * for given data.
46638  *
46639  * The returned function takes these parameters:
46640  * - method: GET/POST/...
46641  * - uri: full URI with protocol, port, path and query string
46642  * - extra_params: any extra parameters (that are passed in the POST data),
46643  *   can be an object or a from-urlencoded string.
46644  *
46645  * Returned function returns full OAuth header with "OAuth" string in it.
46646  */
46647
46648 ohauth.headerGenerator = function(options) {
46649     options = options || {};
46650     var consumer_key = options.consumer_key || '',
46651         consumer_secret = options.consumer_secret || '',
46652         signature_method = options.signature_method || 'HMAC-SHA1',
46653         version = options.version || '1.0',
46654         token = options.token || '',
46655         token_secret = options.token_secret || '';
46656
46657     return function(method, uri, extra_params) {
46658         method = method.toUpperCase();
46659         if (typeof extra_params === 'string' && extra_params.length > 0) {
46660             extra_params = ohauth.stringQs(extra_params);
46661         }
46662
46663         var uri_parts = uri.split('?', 2),
46664         base_uri = uri_parts[0];
46665
46666         var query_params = uri_parts.length === 2 ?
46667             ohauth.stringQs(uri_parts[1]) : {};
46668
46669         var oauth_params = {
46670             oauth_consumer_key: consumer_key,
46671             oauth_signature_method: signature_method,
46672             oauth_version: version,
46673             oauth_timestamp: ohauth.timestamp(),
46674             oauth_nonce: ohauth.nonce()
46675         };
46676
46677         if (token) oauth_params.oauth_token = token;
46678
46679         var all_params = immutable({}, oauth_params, query_params, extra_params),
46680             base_str = ohauth.baseString(method, base_uri, all_params);
46681
46682         oauth_params.oauth_signature = ohauth.signature(consumer_secret, token_secret, base_str);
46683
46684         return 'OAuth ' + ohauth.authHeader(oauth_params);
46685     };
46686 };
46687
46688 var index$13 = ohauth;
46689
46690 var resolveUrl = createCommonjsModule(function (module, exports) {
46691 // Copyright 2014 Simon Lydell
46692 // X11 (“MIT”) Licensed. (See LICENSE.)
46693
46694 void (function(root, factory) {
46695   if (typeof undefined === "function" && undefined.amd) {
46696     undefined(factory);
46697   } else {
46698     module.exports = factory();
46699   }
46700 }(commonjsGlobal, function() {
46701
46702   function resolveUrl(/* ...urls */) {
46703     var numUrls = arguments.length;
46704
46705     if (numUrls === 0) {
46706       throw new Error("resolveUrl requires at least one argument; got none.")
46707     }
46708
46709     var base = document.createElement("base");
46710     base.href = arguments[0];
46711
46712     if (numUrls === 1) {
46713       return base.href
46714     }
46715
46716     var head = document.getElementsByTagName("head")[0];
46717     head.insertBefore(base, head.firstChild);
46718
46719     var a = document.createElement("a");
46720     var resolved;
46721
46722     for (var index = 1; index < numUrls; index++) {
46723       a.href = arguments[index];
46724       resolved = a.href;
46725       base.href = resolved;
46726     }
46727
46728     head.removeChild(base);
46729
46730     return resolved
46731   }
46732
46733   return resolveUrl
46734
46735 }));
46736 });
46737
46738 var assign = make_assign();
46739 var create$2 = make_create();
46740 var trim = make_trim();
46741 var Global = (typeof window !== 'undefined' ? window : commonjsGlobal);
46742
46743 var util = {
46744         assign: assign,
46745         create: create$2,
46746         trim: trim,
46747         bind: bind$1,
46748         slice: slice$7,
46749         each: each$1,
46750         map: map$4,
46751         pluck: pluck$1,
46752         isList: isList$1,
46753         isFunction: isFunction$1,
46754         isObject: isObject$1,
46755         Global: Global
46756 };
46757
46758 function make_assign() {
46759         if (Object.assign) {
46760                 return Object.assign
46761         } else {
46762                 return function shimAssign(obj, props1, props2, etc) {
46763                         for (var i = 1; i < arguments.length; i++) {
46764                                 each$1(Object(arguments[i]), function(val, key) {
46765                                         obj[key] = val;
46766                                 });
46767                         }                       
46768                         return obj
46769                 }
46770         }
46771 }
46772
46773 function make_create() {
46774         if (Object.create) {
46775                 return function create(obj, assignProps1, assignProps2, etc) {
46776                         var assignArgsList = slice$7(arguments, 1);
46777                         return assign.apply(this, [Object.create(obj)].concat(assignArgsList))
46778                 }
46779         } else {
46780                 function F() {} // eslint-disable-line no-inner-declarations
46781                 return function create(obj, assignProps1, assignProps2, etc) {
46782                         var assignArgsList = slice$7(arguments, 1);
46783                         F.prototype = obj;
46784                         return assign.apply(this, [new F()].concat(assignArgsList))
46785                 }
46786         }
46787 }
46788
46789 function make_trim() {
46790         if (String.prototype.trim) {
46791                 return function trim(str) {
46792                         return String.prototype.trim.call(str)
46793                 }
46794         } else {
46795                 return function trim(str) {
46796                         return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
46797                 }
46798         }
46799 }
46800
46801 function bind$1(obj, fn) {
46802         return function() {
46803                 return fn.apply(obj, Array.prototype.slice.call(arguments, 0))
46804         }
46805 }
46806
46807 function slice$7(arr, index) {
46808         return Array.prototype.slice.call(arr, index || 0)
46809 }
46810
46811 function each$1(obj, fn) {
46812         pluck$1(obj, function(val, key) {
46813                 fn(val, key);
46814                 return false
46815         });
46816 }
46817
46818 function map$4(obj, fn) {
46819         var res = (isList$1(obj) ? [] : {});
46820         pluck$1(obj, function(v, k) {
46821                 res[k] = fn(v, k);
46822                 return false
46823         });
46824         return res
46825 }
46826
46827 function pluck$1(obj, fn) {
46828         if (isList$1(obj)) {
46829                 for (var i=0; i<obj.length; i++) {
46830                         if (fn(obj[i], i)) {
46831                                 return obj[i]
46832                         }
46833                 }
46834         } else {
46835                 for (var key in obj) {
46836                         if (obj.hasOwnProperty(key)) {
46837                                 if (fn(obj[key], key)) {
46838                                         return obj[key]
46839                                 }
46840                         }
46841                 }
46842         }
46843 }
46844
46845 function isList$1(val) {
46846         return (val != null && typeof val != 'function' && typeof val.length == 'number')
46847 }
46848
46849 function isFunction$1(val) {
46850         return val && {}.toString.call(val) === '[object Function]'
46851 }
46852
46853 function isObject$1(val) {
46854         return val && {}.toString.call(val) === '[object Object]'
46855 }
46856
46857 var slice$6 = util.slice;
46858 var pluck = util.pluck;
46859 var each = util.each;
46860 var bind = util.bind;
46861 var create$1 = util.create;
46862 var isList = util.isList;
46863 var isFunction = util.isFunction;
46864 var isObject = util.isObject;
46865
46866 var storeEngine = {
46867         createStore: createStore
46868 };
46869
46870 var storeAPI = {
46871         version: '2.0.12',
46872         enabled: false,
46873         
46874         // get returns the value of the given key. If that value
46875         // is undefined, it returns optionalDefaultValue instead.
46876         get: function(key, optionalDefaultValue) {
46877                 var data = this.storage.read(this._namespacePrefix + key);
46878                 return this._deserialize(data, optionalDefaultValue)
46879         },
46880
46881         // set will store the given value at key and returns value.
46882         // Calling set with value === undefined is equivalent to calling remove.
46883         set: function(key, value) {
46884                 if (value === undefined) {
46885                         return this.remove(key)
46886                 }
46887                 this.storage.write(this._namespacePrefix + key, this._serialize(value));
46888                 return value
46889         },
46890
46891         // remove deletes the key and value stored at the given key.
46892         remove: function(key) {
46893                 this.storage.remove(this._namespacePrefix + key);
46894         },
46895
46896         // each will call the given callback once for each key-value pair
46897         // in this store.
46898         each: function(callback) {
46899                 var self = this;
46900                 this.storage.each(function(val, namespacedKey) {
46901                         callback.call(self, self._deserialize(val), (namespacedKey || '').replace(self._namespaceRegexp, ''));
46902                 });
46903         },
46904
46905         // clearAll will remove all the stored key-value pairs in this store.
46906         clearAll: function() {
46907                 this.storage.clearAll();
46908         },
46909
46910         // additional functionality that can't live in plugins
46911         // ---------------------------------------------------
46912
46913         // hasNamespace returns true if this store instance has the given namespace.
46914         hasNamespace: function(namespace) {
46915                 return (this._namespacePrefix == '__storejs_'+namespace+'_')
46916         },
46917
46918         // createStore creates a store.js instance with the first
46919         // functioning storage in the list of storage candidates,
46920         // and applies the the given mixins to the instance.
46921         createStore: function() {
46922                 return createStore.apply(this, arguments)
46923         },
46924         
46925         addPlugin: function(plugin) {
46926                 this._addPlugin(plugin);
46927         },
46928         
46929         namespace: function(namespace) {
46930                 return createStore(this.storage, this.plugins, namespace)
46931         }
46932 };
46933
46934 function _warn() {
46935         var _console = (typeof console == 'undefined' ? null : console);
46936         if (!_console) { return }
46937         var fn = (_console.warn ? _console.warn : _console.log);
46938         fn.apply(_console, arguments);
46939 }
46940
46941 function createStore(storages, plugins, namespace) {
46942         if (!namespace) {
46943                 namespace = '';
46944         }
46945         if (storages && !isList(storages)) {
46946                 storages = [storages];
46947         }
46948         if (plugins && !isList(plugins)) {
46949                 plugins = [plugins];
46950         }
46951
46952         var namespacePrefix = (namespace ? '__storejs_'+namespace+'_' : '');
46953         var namespaceRegexp = (namespace ? new RegExp('^'+namespacePrefix) : null);
46954         var legalNamespaces = /^[a-zA-Z0-9_\-]*$/; // alpha-numeric + underscore and dash
46955         if (!legalNamespaces.test(namespace)) {
46956                 throw new Error('store.js namespaces can only have alphanumerics + underscores and dashes')
46957         }
46958         
46959         var _privateStoreProps = {
46960                 _namespacePrefix: namespacePrefix,
46961                 _namespaceRegexp: namespaceRegexp,
46962
46963                 _testStorage: function(storage) {
46964                         try {
46965                                 var testStr = '__storejs__test__';
46966                                 storage.write(testStr, testStr);
46967                                 var ok = (storage.read(testStr) === testStr);
46968                                 storage.remove(testStr);
46969                                 return ok
46970                         } catch(e) {
46971                                 return false
46972                         }
46973                 },
46974
46975                 _assignPluginFnProp: function(pluginFnProp, propName) {
46976                         var oldFn = this[propName];
46977                         this[propName] = function pluginFn() {
46978                                 var args = slice$6(arguments, 0);
46979                                 var self = this;
46980
46981                                 // super_fn calls the old function which was overwritten by
46982                                 // this mixin.
46983                                 function super_fn() {
46984                                         if (!oldFn) { return }
46985                                         each(arguments, function(arg, i) {
46986                                                 args[i] = arg;
46987                                         });
46988                                         return oldFn.apply(self, args)
46989                                 }
46990
46991                                 // Give mixing function access to super_fn by prefixing all mixin function
46992                                 // arguments with super_fn.
46993                                 var newFnArgs = [super_fn].concat(args);
46994
46995                                 return pluginFnProp.apply(self, newFnArgs)
46996                         };
46997                 },
46998
46999                 _serialize: function(obj) {
47000                         return JSON.stringify(obj)
47001                 },
47002
47003                 _deserialize: function(strVal, defaultVal) {
47004                         if (!strVal) { return defaultVal }
47005                         // It is possible that a raw string value has been previously stored
47006                         // in a storage without using store.js, meaning it will be a raw
47007                         // string value instead of a JSON serialized string. By defaulting
47008                         // to the raw string value in case of a JSON parse error, we allow
47009                         // for past stored values to be forwards-compatible with store.js
47010                         var val = '';
47011                         try { val = JSON.parse(strVal); }
47012                         catch(e) { val = strVal; }
47013
47014                         return (val !== undefined ? val : defaultVal)
47015                 },
47016                 
47017                 _addStorage: function(storage) {
47018                         if (this.enabled) { return }
47019                         if (this._testStorage(storage)) {
47020                                 this.storage = storage;
47021                                 this.enabled = true;
47022                         }
47023                 },
47024
47025                 _addPlugin: function(plugin) {
47026                         var self = this;
47027
47028                         // If the plugin is an array, then add all plugins in the array.
47029                         // This allows for a plugin to depend on other plugins.
47030                         if (isList(plugin)) {
47031                                 each(plugin, function(plugin) {
47032                                         self._addPlugin(plugin);
47033                                 });
47034                                 return
47035                         }
47036
47037                         // Keep track of all plugins we've seen so far, so that we
47038                         // don't add any of them twice.
47039                         var seenPlugin = pluck(this.plugins, function(seenPlugin) {
47040                                 return (plugin === seenPlugin)
47041                         });
47042                         if (seenPlugin) {
47043                                 return
47044                         }
47045                         this.plugins.push(plugin);
47046
47047                         // Check that the plugin is properly formed
47048                         if (!isFunction(plugin)) {
47049                                 throw new Error('Plugins must be function values that return objects')
47050                         }
47051
47052                         var pluginProperties = plugin.call(this);
47053                         if (!isObject(pluginProperties)) {
47054                                 throw new Error('Plugins must return an object of function properties')
47055                         }
47056
47057                         // Add the plugin function properties to this store instance.
47058                         each(pluginProperties, function(pluginFnProp, propName) {
47059                                 if (!isFunction(pluginFnProp)) {
47060                                         throw new Error('Bad plugin property: '+propName+' from plugin '+plugin.name+'. Plugins should only return functions.')
47061                                 }
47062                                 self._assignPluginFnProp(pluginFnProp, propName);
47063                         });
47064                 },
47065                 
47066                 // Put deprecated properties in the private API, so as to not expose it to accidential
47067                 // discovery through inspection of the store object.
47068                 
47069                 // Deprecated: addStorage
47070                 addStorage: function(storage) {
47071                         _warn('store.addStorage(storage) is deprecated. Use createStore([storages])');
47072                         this._addStorage(storage);
47073                 }
47074         };
47075
47076         var store = create$1(_privateStoreProps, storeAPI, {
47077                 plugins: []
47078         });
47079         store.raw = {};
47080         each(store, function(prop, propName) {
47081                 if (isFunction(prop)) {
47082                         store.raw[propName] = bind(store, prop);                        
47083                 }
47084         });
47085         each(storages, function(storage) {
47086                 store._addStorage(storage);
47087         });
47088         each(plugins, function(plugin) {
47089                 store._addPlugin(plugin);
47090         });
47091         return store
47092 }
47093
47094 var Global$1 = util.Global;
47095
47096 var localStorage_1 = {
47097         name: 'localStorage',
47098         read: read,
47099         write: write,
47100         each: each$2,
47101         remove: remove$2,
47102         clearAll: clearAll,
47103 };
47104
47105 function localStorage$1() {
47106         return Global$1.localStorage
47107 }
47108
47109 function read(key) {
47110         return localStorage$1().getItem(key)
47111 }
47112
47113 function write(key, data) {
47114         return localStorage$1().setItem(key, data)
47115 }
47116
47117 function each$2(fn) {
47118         for (var i = localStorage$1().length - 1; i >= 0; i--) {
47119                 var key = localStorage$1().key(i);
47120                 fn(read(key), key);
47121         }
47122 }
47123
47124 function remove$2(key) {
47125         return localStorage$1().removeItem(key)
47126 }
47127
47128 function clearAll() {
47129         return localStorage$1().clear()
47130 }
47131
47132 // oldFF-globalStorage provides storage for Firefox
47133 // versions 6 and 7, where no localStorage, etc
47134 // is available.
47135
47136
47137 var Global$2 = util.Global;
47138
47139 var oldFFGlobalStorage = {
47140         name: 'oldFF-globalStorage',
47141         read: read$1,
47142         write: write$1,
47143         each: each$3,
47144         remove: remove$3,
47145         clearAll: clearAll$1,
47146 };
47147
47148 var globalStorage = Global$2.globalStorage;
47149
47150 function read$1(key) {
47151         return globalStorage[key]
47152 }
47153
47154 function write$1(key, data) {
47155         globalStorage[key] = data;
47156 }
47157
47158 function each$3(fn) {
47159         for (var i = globalStorage.length - 1; i >= 0; i--) {
47160                 var key = globalStorage.key(i);
47161                 fn(globalStorage[key], key);
47162         }
47163 }
47164
47165 function remove$3(key) {
47166         return globalStorage.removeItem(key)
47167 }
47168
47169 function clearAll$1() {
47170         each$3(function(key, _) {
47171                 delete globalStorage[key];
47172         });
47173 }
47174
47175 // oldIE-userDataStorage provides storage for Internet Explorer
47176 // versions 6 and 7, where no localStorage, sessionStorage, etc
47177 // is available.
47178
47179
47180 var Global$3 = util.Global;
47181
47182 var oldIEUserDataStorage = {
47183         name: 'oldIE-userDataStorage',
47184         write: write$2,
47185         read: read$2,
47186         each: each$4,
47187         remove: remove$4,
47188         clearAll: clearAll$2,
47189 };
47190
47191 var storageName = 'storejs';
47192 var doc = Global$3.document;
47193 var _withStorageEl = _makeIEStorageElFunction();
47194 var disable = (Global$3.navigator ? Global$3.navigator.userAgent : '').match(/ (MSIE 8|MSIE 9|MSIE 10)\./); // MSIE 9.x, MSIE 10.x
47195
47196 function write$2(unfixedKey, data) {
47197         if (disable) { return }
47198         var fixedKey = fixKey(unfixedKey);
47199         _withStorageEl(function(storageEl) {
47200                 storageEl.setAttribute(fixedKey, data);
47201                 storageEl.save(storageName);
47202         });
47203 }
47204
47205 function read$2(unfixedKey) {
47206         if (disable) { return }
47207         var fixedKey = fixKey(unfixedKey);
47208         var res = null;
47209         _withStorageEl(function(storageEl) {
47210                 res = storageEl.getAttribute(fixedKey);
47211         });
47212         return res
47213 }
47214
47215 function each$4(callback) {
47216         _withStorageEl(function(storageEl) {
47217                 var attributes = storageEl.XMLDocument.documentElement.attributes;
47218                 for (var i=attributes.length-1; i>=0; i--) {
47219                         var attr = attributes[i];
47220                         callback(storageEl.getAttribute(attr.name), attr.name);
47221                 }
47222         });
47223 }
47224
47225 function remove$4(unfixedKey) {
47226         var fixedKey = fixKey(unfixedKey);
47227         _withStorageEl(function(storageEl) {
47228                 storageEl.removeAttribute(fixedKey);
47229                 storageEl.save(storageName);
47230         });
47231 }
47232
47233 function clearAll$2() {
47234         _withStorageEl(function(storageEl) {
47235                 var attributes = storageEl.XMLDocument.documentElement.attributes;
47236                 storageEl.load(storageName);
47237                 for (var i=attributes.length-1; i>=0; i--) {
47238                         storageEl.removeAttribute(attributes[i].name);
47239                 }
47240                 storageEl.save(storageName);
47241         });
47242 }
47243
47244 // Helpers
47245 //////////
47246
47247 // In IE7, keys cannot start with a digit or contain certain chars.
47248 // See https://github.com/marcuswestin/store.js/issues/40
47249 // See https://github.com/marcuswestin/store.js/issues/83
47250 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
47251 function fixKey(key) {
47252         return key.replace(/^\d/, '___$&').replace(forbiddenCharsRegex, '___')
47253 }
47254
47255 function _makeIEStorageElFunction() {
47256         if (!doc || !doc.documentElement || !doc.documentElement.addBehavior) {
47257                 return null
47258         }
47259         var scriptTag = 'script',
47260                 storageOwner,
47261                 storageContainer,
47262                 storageEl;
47263
47264         // Since #userData storage applies only to specific paths, we need to
47265         // somehow link our data to a specific path.  We choose /favicon.ico
47266         // as a pretty safe option, since all browsers already make a request to
47267         // this URL anyway and being a 404 will not hurt us here.  We wrap an
47268         // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
47269         // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
47270         // since the iframe access rules appear to allow direct access and
47271         // manipulation of the document element, even for a 404 page.  This
47272         // document can be used instead of the current document (which would
47273         // have been limited to the current path) to perform #userData storage.
47274         try {
47275                 /* global ActiveXObject */
47276                 storageContainer = new ActiveXObject('htmlfile');
47277                 storageContainer.open();
47278                 storageContainer.write('<'+scriptTag+'>document.w=window</'+scriptTag+'><iframe src="/favicon.ico"></iframe>');
47279                 storageContainer.close();
47280                 storageOwner = storageContainer.w.frames[0].document;
47281                 storageEl = storageOwner.createElement('div');
47282         } catch(e) {
47283                 // somehow ActiveXObject instantiation failed (perhaps some special
47284                 // security settings or otherwse), fall back to per-path storage
47285                 storageEl = doc.createElement('div');
47286                 storageOwner = doc.body;
47287         }
47288
47289         return function(storeFunction) {
47290                 var args = [].slice.call(arguments, 0);
47291                 args.unshift(storageEl);
47292                 // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
47293                 // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
47294                 storageOwner.appendChild(storageEl);
47295                 storageEl.addBehavior('#default#userData');
47296                 storageEl.load(storageName);
47297                 storeFunction.apply(this, args);
47298                 storageOwner.removeChild(storageEl);
47299                 return
47300         }
47301 }
47302
47303 // cookieStorage is useful Safari private browser mode, where localStorage
47304 // doesn't work but cookies do. This implementation is adopted from
47305 // https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage
47306
47307
47308 var Global$4 = util.Global;
47309 var trim$1 = util.trim;
47310
47311 var cookieStorage = {
47312         name: 'cookieStorage',
47313         read: read$3,
47314         write: write$3,
47315         each: each$5,
47316         remove: remove$5,
47317         clearAll: clearAll$3,
47318 };
47319
47320 var doc$1 = Global$4.document;
47321
47322 function read$3(key) {
47323         if (!key || !_has(key)) { return null }
47324         var regexpStr = "(?:^|.*;\\s*)" +
47325                 escape(key).replace(/[\-\.\+\*]/g, "\\$&") +
47326                 "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";
47327         return unescape(doc$1.cookie.replace(new RegExp(regexpStr), "$1"))
47328 }
47329
47330 function each$5(callback) {
47331         var cookies = doc$1.cookie.split(/; ?/g);
47332         for (var i = cookies.length - 1; i >= 0; i--) {
47333                 if (!trim$1(cookies[i])) {
47334                         continue
47335                 }
47336                 var kvp = cookies[i].split('=');
47337                 var key = unescape(kvp[0]);
47338                 var val = unescape(kvp[1]);
47339                 callback(val, key);
47340         }
47341 }
47342
47343 function write$3(key, data) {
47344         if(!key) { return }
47345         doc$1.cookie = escape(key) + "=" + escape(data) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
47346 }
47347
47348 function remove$5(key) {
47349         if (!key || !_has(key)) {
47350                 return
47351         }
47352         doc$1.cookie = escape(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
47353 }
47354
47355 function clearAll$3() {
47356         each$5(function(_, key) {
47357                 remove$5(key);
47358         });
47359 }
47360
47361 function _has(key) {
47362         return (new RegExp("(?:^|;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(doc$1.cookie)
47363 }
47364
47365 var Global$5 = util.Global;
47366
47367 var sessionStorage_1 = {
47368         name: 'sessionStorage',
47369         read: read$4,
47370         write: write$4,
47371         each: each$6,
47372         remove: remove$6,
47373         clearAll: clearAll$4
47374 };
47375
47376 function sessionStorage() {
47377         return Global$5.sessionStorage
47378 }
47379
47380 function read$4(key) {
47381         return sessionStorage().getItem(key)
47382 }
47383
47384 function write$4(key, data) {
47385         return sessionStorage().setItem(key, data)
47386 }
47387
47388 function each$6(fn) {
47389         for (var i = sessionStorage().length - 1; i >= 0; i--) {
47390                 var key = sessionStorage().key(i);
47391                 fn(read$4(key), key);
47392         }
47393 }
47394
47395 function remove$6(key) {
47396         return sessionStorage().removeItem(key)
47397 }
47398
47399 function clearAll$4() {
47400         return sessionStorage().clear()
47401 }
47402
47403 // memoryStorage is a useful last fallback to ensure that the store
47404 // is functions (meaning store.get(), store.set(), etc will all function).
47405 // However, stored values will not persist when the browser navigates to
47406 // a new page or reloads the current page.
47407
47408 var memoryStorage_1 = {
47409         name: 'memoryStorage',
47410         read: read$5,
47411         write: write$5,
47412         each: each$7,
47413         remove: remove$7,
47414         clearAll: clearAll$5,
47415 };
47416
47417 var memoryStorage = {};
47418
47419 function read$5(key) {
47420         return memoryStorage[key]
47421 }
47422
47423 function write$5(key, data) {
47424         memoryStorage[key] = data;
47425 }
47426
47427 function each$7(callback) {
47428         for (var key in memoryStorage) {
47429                 if (memoryStorage.hasOwnProperty(key)) {
47430                         callback(memoryStorage[key], key);
47431                 }
47432         }
47433 }
47434
47435 function remove$7(key) {
47436         delete memoryStorage[key];
47437 }
47438
47439 function clearAll$5(key) {
47440         memoryStorage = {};
47441 }
47442
47443 var all$3 = [
47444         // Listed in order of usage preference
47445         localStorage_1,
47446         oldFFGlobalStorage,
47447         oldIEUserDataStorage,
47448         cookieStorage,
47449         sessionStorage_1,
47450         memoryStorage_1
47451 ];
47452
47453 /* eslint-disable */
47454
47455 //  json2.js
47456 //  2016-10-28
47457 //  Public Domain.
47458 //  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
47459 //  See http://www.JSON.org/js.html
47460 //  This code should be minified before deployment.
47461 //  See http://javascript.crockford.com/jsmin.html
47462
47463 //  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
47464 //  NOT CONTROL.
47465
47466 //  This file creates a global JSON object containing two methods: stringify
47467 //  and parse. This file provides the ES5 JSON capability to ES3 systems.
47468 //  If a project might run on IE8 or earlier, then this file should be included.
47469 //  This file does nothing on ES5 systems.
47470
47471 //      JSON.stringify(value, replacer, space)
47472 //          value       any JavaScript value, usually an object or array.
47473 //          replacer    an optional parameter that determines how object
47474 //                      values are stringified for objects. It can be a
47475 //                      function or an array of strings.
47476 //          space       an optional parameter that specifies the indentation
47477 //                      of nested structures. If it is omitted, the text will
47478 //                      be packed without extra whitespace. If it is a number,
47479 //                      it will specify the number of spaces to indent at each
47480 //                      level. If it is a string (such as "\t" or "&nbsp;"),
47481 //                      it contains the characters used to indent at each level.
47482 //          This method produces a JSON text from a JavaScript value.
47483 //          When an object value is found, if the object contains a toJSON
47484 //          method, its toJSON method will be called and the result will be
47485 //          stringified. A toJSON method does not serialize: it returns the
47486 //          value represented by the name/value pair that should be serialized,
47487 //          or undefined if nothing should be serialized. The toJSON method
47488 //          will be passed the key associated with the value, and this will be
47489 //          bound to the value.
47490
47491 //          For example, this would serialize Dates as ISO strings.
47492
47493 //              Date.prototype.toJSON = function (key) {
47494 //                  function f(n) {
47495 //                      // Format integers to have at least two digits.
47496 //                      return (n < 10)
47497 //                          ? "0" + n
47498 //                          : n;
47499 //                  }
47500 //                  return this.getUTCFullYear()   + "-" +
47501 //                       f(this.getUTCMonth() + 1) + "-" +
47502 //                       f(this.getUTCDate())      + "T" +
47503 //                       f(this.getUTCHours())     + ":" +
47504 //                       f(this.getUTCMinutes())   + ":" +
47505 //                       f(this.getUTCSeconds())   + "Z";
47506 //              };
47507
47508 //          You can provide an optional replacer method. It will be passed the
47509 //          key and value of each member, with this bound to the containing
47510 //          object. The value that is returned from your method will be
47511 //          serialized. If your method returns undefined, then the member will
47512 //          be excluded from the serialization.
47513
47514 //          If the replacer parameter is an array of strings, then it will be
47515 //          used to select the members to be serialized. It filters the results
47516 //          such that only members with keys listed in the replacer array are
47517 //          stringified.
47518
47519 //          Values that do not have JSON representations, such as undefined or
47520 //          functions, will not be serialized. Such values in objects will be
47521 //          dropped; in arrays they will be replaced with null. You can use
47522 //          a replacer function to replace those with JSON values.
47523
47524 //          JSON.stringify(undefined) returns undefined.
47525
47526 //          The optional space parameter produces a stringification of the
47527 //          value that is filled with line breaks and indentation to make it
47528 //          easier to read.
47529
47530 //          If the space parameter is a non-empty string, then that string will
47531 //          be used for indentation. If the space parameter is a number, then
47532 //          the indentation will be that many spaces.
47533
47534 //          Example:
47535
47536 //          text = JSON.stringify(["e", {pluribus: "unum"}]);
47537 //          // text is '["e",{"pluribus":"unum"}]'
47538
47539 //          text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
47540 //          // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
47541
47542 //          text = JSON.stringify([new Date()], function (key, value) {
47543 //              return this[key] instanceof Date
47544 //                  ? "Date(" + this[key] + ")"
47545 //                  : value;
47546 //          });
47547 //          // text is '["Date(---current time---)"]'
47548
47549 //      JSON.parse(text, reviver)
47550 //          This method parses a JSON text to produce an object or array.
47551 //          It can throw a SyntaxError exception.
47552
47553 //          The optional reviver parameter is a function that can filter and
47554 //          transform the results. It receives each of the keys and values,
47555 //          and its return value is used instead of the original value.
47556 //          If it returns what it received, then the structure is not modified.
47557 //          If it returns undefined then the member is deleted.
47558
47559 //          Example:
47560
47561 //          // Parse the text. Values that look like ISO date strings will
47562 //          // be converted to Date objects.
47563
47564 //          myData = JSON.parse(text, function (key, value) {
47565 //              var a;
47566 //              if (typeof value === "string") {
47567 //                  a =
47568 //   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
47569 //                  if (a) {
47570 //                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
47571 //                          +a[5], +a[6]));
47572 //                  }
47573 //              }
47574 //              return value;
47575 //          });
47576
47577 //          myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
47578 //              var d;
47579 //              if (typeof value === "string" &&
47580 //                      value.slice(0, 5) === "Date(" &&
47581 //                      value.slice(-1) === ")") {
47582 //                  d = new Date(value.slice(5, -1));
47583 //                  if (d) {
47584 //                      return d;
47585 //                  }
47586 //              }
47587 //              return value;
47588 //          });
47589
47590 //  This is a reference implementation. You are free to copy, modify, or
47591 //  redistribute.
47592
47593 /*jslint
47594     eval, for, this
47595 */
47596
47597 /*property
47598     JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
47599     getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
47600     lastIndex, length, parse, prototype, push, replace, slice, stringify,
47601     test, toJSON, toString, valueOf
47602 */
47603
47604
47605 // Create a JSON object only if one does not already exist. We create the
47606 // methods in a closure to avoid creating global variables.
47607
47608 if (typeof JSON !== "object") {
47609     JSON = {};
47610 }
47611
47612 (function () {
47613     "use strict";
47614
47615     var rx_one = /^[\],:{}\s]*$/;
47616     var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
47617     var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
47618     var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
47619     var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
47620     var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
47621
47622     function f(n) {
47623         // Format integers to have at least two digits.
47624         return n < 10
47625             ? "0" + n
47626             : n;
47627     }
47628
47629     function this_value() {
47630         return this.valueOf();
47631     }
47632
47633     if (typeof Date.prototype.toJSON !== "function") {
47634
47635         Date.prototype.toJSON = function () {
47636
47637             return isFinite(this.valueOf())
47638                 ? this.getUTCFullYear() + "-" +
47639                         f(this.getUTCMonth() + 1) + "-" +
47640                         f(this.getUTCDate()) + "T" +
47641                         f(this.getUTCHours()) + ":" +
47642                         f(this.getUTCMinutes()) + ":" +
47643                         f(this.getUTCSeconds()) + "Z"
47644                 : null;
47645         };
47646
47647         Boolean.prototype.toJSON = this_value;
47648         Number.prototype.toJSON = this_value;
47649         String.prototype.toJSON = this_value;
47650     }
47651
47652     var gap;
47653     var indent;
47654     var meta;
47655     var rep;
47656
47657
47658     function quote(string) {
47659
47660 // If the string contains no control characters, no quote characters, and no
47661 // backslash characters, then we can safely slap some quotes around it.
47662 // Otherwise we must also replace the offending characters with safe escape
47663 // sequences.
47664
47665         rx_escapable.lastIndex = 0;
47666         return rx_escapable.test(string)
47667             ? "\"" + string.replace(rx_escapable, function (a) {
47668                 var c = meta[a];
47669                 return typeof c === "string"
47670                     ? c
47671                     : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
47672             }) + "\""
47673             : "\"" + string + "\"";
47674     }
47675
47676
47677     function str(key, holder) {
47678
47679 // Produce a string from holder[key].
47680
47681         var i;          // The loop counter.
47682         var k;          // The member key.
47683         var v;          // The member value.
47684         var length;
47685         var mind = gap;
47686         var partial;
47687         var value = holder[key];
47688
47689 // If the value has a toJSON method, call it to obtain a replacement value.
47690
47691         if (value && typeof value === "object" &&
47692                 typeof value.toJSON === "function") {
47693             value = value.toJSON(key);
47694         }
47695
47696 // If we were called with a replacer function, then call the replacer to
47697 // obtain a replacement value.
47698
47699         if (typeof rep === "function") {
47700             value = rep.call(holder, key, value);
47701         }
47702
47703 // What happens next depends on the value's type.
47704
47705         switch (typeof value) {
47706         case "string":
47707             return quote(value);
47708
47709         case "number":
47710
47711 // JSON numbers must be finite. Encode non-finite numbers as null.
47712
47713             return isFinite(value)
47714                 ? String(value)
47715                 : "null";
47716
47717         case "boolean":
47718         case "null":
47719
47720 // If the value is a boolean or null, convert it to a string. Note:
47721 // typeof null does not produce "null". The case is included here in
47722 // the remote chance that this gets fixed someday.
47723
47724             return String(value);
47725
47726 // If the type is "object", we might be dealing with an object or an array or
47727 // null.
47728
47729         case "object":
47730
47731 // Due to a specification blunder in ECMAScript, typeof null is "object",
47732 // so watch out for that case.
47733
47734             if (!value) {
47735                 return "null";
47736             }
47737
47738 // Make an array to hold the partial results of stringifying this object value.
47739
47740             gap += indent;
47741             partial = [];
47742
47743 // Is the value an array?
47744
47745             if (Object.prototype.toString.apply(value) === "[object Array]") {
47746
47747 // The value is an array. Stringify every element. Use null as a placeholder
47748 // for non-JSON values.
47749
47750                 length = value.length;
47751                 for (i = 0; i < length; i += 1) {
47752                     partial[i] = str(i, value) || "null";
47753                 }
47754
47755 // Join all of the elements together, separated with commas, and wrap them in
47756 // brackets.
47757
47758                 v = partial.length === 0
47759                     ? "[]"
47760                     : gap
47761                         ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]"
47762                         : "[" + partial.join(",") + "]";
47763                 gap = mind;
47764                 return v;
47765             }
47766
47767 // If the replacer is an array, use it to select the members to be stringified.
47768
47769             if (rep && typeof rep === "object") {
47770                 length = rep.length;
47771                 for (i = 0; i < length; i += 1) {
47772                     if (typeof rep[i] === "string") {
47773                         k = rep[i];
47774                         v = str(k, value);
47775                         if (v) {
47776                             partial.push(quote(k) + (
47777                                 gap
47778                                     ? ": "
47779                                     : ":"
47780                             ) + v);
47781                         }
47782                     }
47783                 }
47784             } else {
47785
47786 // Otherwise, iterate through all of the keys in the object.
47787
47788                 for (k in value) {
47789                     if (Object.prototype.hasOwnProperty.call(value, k)) {
47790                         v = str(k, value);
47791                         if (v) {
47792                             partial.push(quote(k) + (
47793                                 gap
47794                                     ? ": "
47795                                     : ":"
47796                             ) + v);
47797                         }
47798                     }
47799                 }
47800             }
47801
47802 // Join all of the member texts together, separated with commas,
47803 // and wrap them in braces.
47804
47805             v = partial.length === 0
47806                 ? "{}"
47807                 : gap
47808                     ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}"
47809                     : "{" + partial.join(",") + "}";
47810             gap = mind;
47811             return v;
47812         }
47813     }
47814
47815 // If the JSON object does not yet have a stringify method, give it one.
47816
47817     if (typeof JSON.stringify !== "function") {
47818         meta = {    // table of character substitutions
47819             "\b": "\\b",
47820             "\t": "\\t",
47821             "\n": "\\n",
47822             "\f": "\\f",
47823             "\r": "\\r",
47824             "\"": "\\\"",
47825             "\\": "\\\\"
47826         };
47827         JSON.stringify = function (value, replacer, space) {
47828
47829 // The stringify method takes a value and an optional replacer, and an optional
47830 // space parameter, and returns a JSON text. The replacer can be a function
47831 // that can replace values, or an array of strings that will select the keys.
47832 // A default replacer method can be provided. Use of the space parameter can
47833 // produce text that is more easily readable.
47834
47835             var i;
47836             gap = "";
47837             indent = "";
47838
47839 // If the space parameter is a number, make an indent string containing that
47840 // many spaces.
47841
47842             if (typeof space === "number") {
47843                 for (i = 0; i < space; i += 1) {
47844                     indent += " ";
47845                 }
47846
47847 // If the space parameter is a string, it will be used as the indent string.
47848
47849             } else if (typeof space === "string") {
47850                 indent = space;
47851             }
47852
47853 // If there is a replacer, it must be a function or an array.
47854 // Otherwise, throw an error.
47855
47856             rep = replacer;
47857             if (replacer && typeof replacer !== "function" &&
47858                     (typeof replacer !== "object" ||
47859                     typeof replacer.length !== "number")) {
47860                 throw new Error("JSON.stringify");
47861             }
47862
47863 // Make a fake root object containing our value under the key of "".
47864 // Return the result of stringifying the value.
47865
47866             return str("", {"": value});
47867         };
47868     }
47869
47870
47871 // If the JSON object does not yet have a parse method, give it one.
47872
47873     if (typeof JSON.parse !== "function") {
47874         JSON.parse = function (text, reviver) {
47875
47876 // The parse method takes a text and an optional reviver function, and returns
47877 // a JavaScript value if the text is a valid JSON text.
47878
47879             var j;
47880
47881             function walk(holder, key) {
47882
47883 // The walk method is used to recursively walk the resulting structure so
47884 // that modifications can be made.
47885
47886                 var k;
47887                 var v;
47888                 var value = holder[key];
47889                 if (value && typeof value === "object") {
47890                     for (k in value) {
47891                         if (Object.prototype.hasOwnProperty.call(value, k)) {
47892                             v = walk(value, k);
47893                             if (v !== undefined) {
47894                                 value[k] = v;
47895                             } else {
47896                                 delete value[k];
47897                             }
47898                         }
47899                     }
47900                 }
47901                 return reviver.call(holder, key, value);
47902             }
47903
47904
47905 // Parsing happens in four stages. In the first stage, we replace certain
47906 // Unicode characters with escape sequences. JavaScript handles many characters
47907 // incorrectly, either silently deleting them, or treating them as line endings.
47908
47909             text = String(text);
47910             rx_dangerous.lastIndex = 0;
47911             if (rx_dangerous.test(text)) {
47912                 text = text.replace(rx_dangerous, function (a) {
47913                     return "\\u" +
47914                             ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
47915                 });
47916             }
47917
47918 // In the second stage, we run the text against regular expressions that look
47919 // for non-JSON patterns. We are especially concerned with "()" and "new"
47920 // because they can cause invocation, and "=" because it can cause mutation.
47921 // But just to be safe, we want to reject all unexpected forms.
47922
47923 // We split the second stage into 4 regexp operations in order to work around
47924 // crippling inefficiencies in IE's and Safari's regexp engines. First we
47925 // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
47926 // replace all simple value tokens with "]" characters. Third, we delete all
47927 // open brackets that follow a colon or comma or that begin the text. Finally,
47928 // we look to see that the remaining characters are only whitespace or "]" or
47929 // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
47930
47931             if (
47932                 rx_one.test(
47933                     text
47934                         .replace(rx_two, "@")
47935                         .replace(rx_three, "]")
47936                         .replace(rx_four, "")
47937                 )
47938             ) {
47939
47940 // In the third stage we use the eval function to compile the text into a
47941 // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
47942 // in JavaScript: it can begin a block or an object literal. We wrap the text
47943 // in parens to eliminate the ambiguity.
47944
47945                 j = eval("(" + text + ")");
47946
47947 // In the optional fourth stage, we recursively walk the new structure, passing
47948 // each name/value pair to a reviver function for possible transformation.
47949
47950                 return (typeof reviver === "function")
47951                     ? walk({"": j}, "")
47952                     : j;
47953             }
47954
47955 // If the text is not JSON parseable, then a SyntaxError is thrown.
47956
47957             throw new SyntaxError("JSON.parse");
47958         };
47959     }
47960 }());
47961
47962 var json2 = json2Plugin;
47963
47964 function json2Plugin() {
47965         
47966         return {}
47967 }
47968
47969 var plugins = [json2];
47970
47971 var store_legacy = storeEngine.createStore(all$3, plugins);
47972
47973 // # osm-auth
47974 //
47975 // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
47976 // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
47977 // does not support custom headers, which this uses everywhere.
47978 var index$12 = function(o) {
47979
47980     var oauth = {};
47981
47982     // authenticated users will also have a request token secret, but it's
47983     // not used in transactions with the server
47984     oauth.authenticated = function() {
47985         return !!(token('oauth_token') && token('oauth_token_secret'));
47986     };
47987
47988     oauth.logout = function() {
47989         token('oauth_token', '');
47990         token('oauth_token_secret', '');
47991         token('oauth_request_token_secret', '');
47992         return oauth;
47993     };
47994
47995     // TODO: detect lack of click event
47996     oauth.authenticate = function(callback) {
47997         if (oauth.authenticated()) return callback();
47998
47999         oauth.logout();
48000
48001         // ## Getting a request token
48002         var params = timenonce(getAuth(o)),
48003             url = o.url + '/oauth/request_token';
48004
48005         params.oauth_signature = index$13.signature(
48006             o.oauth_secret, '',
48007             index$13.baseString('POST', url, params));
48008
48009         if (!o.singlepage) {
48010             // Create a 600x550 popup window in the center of the screen
48011             var w = 600, h = 550,
48012                 settings = [
48013                     ['width', w], ['height', h],
48014                     ['left', screen.width / 2 - w / 2],
48015                     ['top', screen.height / 2 - h / 2]].map(function(x) {
48016                         return x.join('=');
48017                     }).join(','),
48018                 popup = window.open('about:blank', 'oauth_window', settings);
48019         }
48020
48021         // Request a request token. When this is complete, the popup
48022         // window is redirected to OSM's authorization page.
48023         index$13.xhr('POST', url, params, null, {}, reqTokenDone);
48024         o.loading();
48025
48026         function reqTokenDone(err, xhr) {
48027             o.done();
48028             if (err) return callback(err);
48029             var resp = index$13.stringQs(xhr.response);
48030             token('oauth_request_token_secret', resp.oauth_token_secret);
48031             var authorize_url = o.url + '/oauth/authorize?' + index$13.qsString({
48032                 oauth_token: resp.oauth_token,
48033                 oauth_callback: resolveUrl(o.landing)
48034             });
48035
48036             if (o.singlepage) {
48037                 location.href = authorize_url;
48038             } else {
48039                 popup.location = authorize_url;
48040             }
48041         }
48042
48043         // Called by a function in a landing page, in the popup window. The
48044         // window closes itself.
48045         window.authComplete = function(token) {
48046             var oauth_token = index$13.stringQs(token.split('?')[1]);
48047             get_access_token(oauth_token.oauth_token);
48048             delete window.authComplete;
48049         };
48050
48051         // ## Getting an request token
48052         //
48053         // At this point we have an `oauth_token`, brought in from a function
48054         // call on a landing page popup.
48055         function get_access_token(oauth_token) {
48056             var url = o.url + '/oauth/access_token',
48057                 params = timenonce(getAuth(o)),
48058                 request_token_secret = token('oauth_request_token_secret');
48059             params.oauth_token = oauth_token;
48060             params.oauth_signature = index$13.signature(
48061                 o.oauth_secret,
48062                 request_token_secret,
48063                 index$13.baseString('POST', url, params));
48064
48065             // ## Getting an access token
48066             //
48067             // The final token required for authentication. At this point
48068             // we have a `request token secret`
48069             index$13.xhr('POST', url, params, null, {}, accessTokenDone);
48070             o.loading();
48071         }
48072
48073         function accessTokenDone(err, xhr) {
48074             o.done();
48075             if (err) return callback(err);
48076             var access_token = index$13.stringQs(xhr.response);
48077             token('oauth_token', access_token.oauth_token);
48078             token('oauth_token_secret', access_token.oauth_token_secret);
48079             callback(null, oauth);
48080         }
48081     };
48082
48083     oauth.bootstrapToken = function(oauth_token, callback) {
48084         // ## Getting an request token
48085         // At this point we have an `oauth_token`, brought in from a function
48086         // call on a landing page popup.
48087         function get_access_token(oauth_token) {
48088             var url = o.url + '/oauth/access_token',
48089                 params = timenonce(getAuth(o)),
48090                 request_token_secret = token('oauth_request_token_secret');
48091             params.oauth_token = oauth_token;
48092             params.oauth_signature = index$13.signature(
48093                 o.oauth_secret,
48094                 request_token_secret,
48095                 index$13.baseString('POST', url, params));
48096
48097             // ## Getting an access token
48098             // The final token required for authentication. At this point
48099             // we have a `request token secret`
48100             index$13.xhr('POST', url, params, null, {}, accessTokenDone);
48101             o.loading();
48102         }
48103
48104         function accessTokenDone(err, xhr) {
48105             o.done();
48106             if (err) return callback(err);
48107             var access_token = index$13.stringQs(xhr.response);
48108             token('oauth_token', access_token.oauth_token);
48109             token('oauth_token_secret', access_token.oauth_token_secret);
48110             callback(null, oauth);
48111         }
48112
48113         get_access_token(oauth_token);
48114     };
48115
48116     // # xhr
48117     //
48118     // A single XMLHttpRequest wrapper that does authenticated calls if the
48119     // user has logged in.
48120     oauth.xhr = function(options, callback) {
48121         if (!oauth.authenticated()) {
48122             if (o.auto) {
48123                 return oauth.authenticate(run);
48124             } else {
48125                 callback('not authenticated', null);
48126                 return;
48127             }
48128         } else {
48129             return run();
48130         }
48131
48132         function run() {
48133             var params = timenonce(getAuth(o)),
48134                 oauth_token_secret = token('oauth_token_secret'),
48135                 url = (options.prefix !== false) ? o.url + options.path : options.path,
48136                 url_parts = url.replace(/#.*$/, '').split('?', 2),
48137                 base_url = url_parts[0],
48138                 query = (url_parts.length === 2) ? url_parts[1] : '';
48139
48140             // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
48141             if ((!options.options || !options.options.header ||
48142                 options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') &&
48143                 options.content) {
48144                 params = immutable(params, index$13.stringQs(options.content));
48145             }
48146
48147             params.oauth_token = token('oauth_token');
48148             params.oauth_signature = index$13.signature(
48149                 o.oauth_secret,
48150                 oauth_token_secret,
48151                 index$13.baseString(options.method, base_url, immutable(params, index$13.stringQs(query)))
48152             );
48153
48154             return index$13.xhr(options.method, url, params, options.content, options.options, done);
48155         }
48156
48157         function done(err, xhr) {
48158             if (err) return callback(err);
48159             else if (xhr.responseXML) return callback(err, xhr.responseXML);
48160             else return callback(err, xhr.response);
48161         }
48162     };
48163
48164     // pre-authorize this object, if we can just get a token and token_secret
48165     // from the start
48166     oauth.preauth = function(c) {
48167         if (!c) return;
48168         if (c.oauth_token) token('oauth_token', c.oauth_token);
48169         if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
48170         return oauth;
48171     };
48172
48173     oauth.options = function(_) {
48174         if (!arguments.length) return o;
48175
48176         o = _;
48177         o.url = o.url || 'https://www.openstreetmap.org';
48178         o.landing = o.landing || 'land.html';
48179         o.singlepage = o.singlepage || false;
48180
48181         // Optional loading and loading-done functions for nice UI feedback.
48182         // by default, no-ops
48183         o.loading = o.loading || function() {};
48184         o.done = o.done || function() {};
48185
48186         return oauth.preauth(o);
48187     };
48188
48189     // 'stamp' an authentication object from `getAuth()`
48190     // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
48191     // and timestamp
48192     function timenonce(o) {
48193         o.oauth_timestamp = index$13.timestamp();
48194         o.oauth_nonce = index$13.nonce();
48195         return o;
48196     }
48197
48198     // get/set tokens. These are prefixed with the base URL so that `osm-auth`
48199     // can be used with multiple APIs and the keys in `localStorage`
48200     // will not clash
48201     var token;
48202
48203     if (store_legacy.enabled) {
48204         token = function (x, y) {
48205             if (arguments.length === 1) return store_legacy.get(o.url + x);
48206             else if (arguments.length === 2) return store_legacy.set(o.url + x, y);
48207         };
48208     } else {
48209         var storage = {};
48210         token = function (x, y) {
48211             if (arguments.length === 1) return storage[o.url + x];
48212             else if (arguments.length === 2) return storage[o.url + x] = y;
48213         };
48214     }
48215
48216     // Get an authentication object. If you just add and remove properties
48217     // from a single object, you'll need to use `delete` to make sure that
48218     // it doesn't contain undesired properties for authentication
48219     function getAuth(o) {
48220         return {
48221             oauth_consumer_key: o.oauth_consumer_key,
48222             oauth_signature_method: 'HMAC-SHA1'
48223         };
48224     }
48225
48226     // potentially pre-authorize
48227     oauth.options(o);
48228
48229     return oauth;
48230 };
48231
48232 var JXON = new (function () {
48233   var
48234     sValueProp = 'keyValue', sAttributesProp = 'keyAttributes', sAttrPref = '@', /* you can customize these values */
48235     aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
48236
48237   function parseText (sValue) {
48238     if (rIsNull.test(sValue)) { return null; }
48239     if (rIsBool.test(sValue)) { return sValue.toLowerCase() === 'true'; }
48240     if (isFinite(sValue)) { return parseFloat(sValue); }
48241     if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
48242     return sValue;
48243   }
48244
48245   function EmptyTree () { }
48246   EmptyTree.prototype.toString = function () { return 'null'; };
48247   EmptyTree.prototype.valueOf = function () { return null; };
48248
48249   function objectify (vValue) {
48250     return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
48251   }
48252
48253   function createObjTree (oParentNode, nVerb, bFreeze, bNesteAttr) {
48254     var
48255       nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(),
48256       bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
48257
48258     var
48259       sProp, vContent, nLength = 0, sCollectedTxt = '',
48260       vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
48261
48262     if (bChildren) {
48263       for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
48264         oNode = oParentNode.childNodes.item(nItem);
48265         if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is 'CDATASection' (4) */
48266         else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is 'Text' (3) */
48267         else if (oNode.nodeType === 1 && !oNode.prefix) { aCache.push(oNode); } /* nodeType is 'Element' (1) */
48268       }
48269     }
48270
48271     var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
48272
48273     if (!bHighVerb && (bChildren || bAttributes)) { vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; }
48274
48275     for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
48276       sProp = aCache[nElId].nodeName.toLowerCase();
48277       vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
48278       if (vResult.hasOwnProperty(sProp)) {
48279         if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; }
48280         vResult[sProp].push(vContent);
48281       } else {
48282         vResult[sProp] = vContent;
48283         nLength++;
48284       }
48285     }
48286
48287     if (bAttributes) {
48288       var
48289         nAttrLen = oParentNode.attributes.length,
48290         sAPrefix = bNesteAttr ? '' : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
48291
48292       for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
48293         oAttrib = oParentNode.attributes.item(nAttrib);
48294         oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
48295       }
48296
48297       if (bNesteAttr) {
48298         if (bFreeze) { Object.freeze(oAttrParent); }
48299         vResult[sAttributesProp] = oAttrParent;
48300         nLength -= nAttrLen - 1;
48301       }
48302     }
48303
48304     if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
48305       vResult[sValueProp] = vBuiltVal;
48306     } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
48307       vResult = vBuiltVal;
48308     }
48309
48310     if (bFreeze && (bHighVerb || nLength > 0)) { Object.freeze(vResult); }
48311
48312     aCache.length = nLevelStart;
48313
48314     return vResult;
48315   }
48316
48317   function loadObjTree (oXMLDoc, oParentEl, oParentObj) {
48318     var vValue, oChild;
48319
48320     if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
48321       oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
48322     } else if (oParentObj.constructor === Date) {
48323       oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));    
48324     }
48325
48326     for (var sName in oParentObj) {
48327       vValue = oParentObj[sName];
48328       if (isFinite(sName) || vValue instanceof Function) { continue; } /* verbosity level is 0 */
48329       if (sName === sValueProp) {
48330         if (vValue !== null && vValue !== true) { oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); }
48331       } else if (sName === sAttributesProp) { /* verbosity level is 3 */
48332         for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); }
48333       } else if (sName.charAt(0) === sAttrPref) {
48334         oParentEl.setAttribute(sName.slice(1), vValue);
48335       } else if (vValue.constructor === Array) {
48336         for (var nItem = 0; nItem < vValue.length; nItem++) {
48337           oChild = oXMLDoc.createElement(sName);
48338           loadObjTree(oXMLDoc, oChild, vValue[nItem]);
48339           oParentEl.appendChild(oChild);
48340         }
48341       } else {
48342         oChild = oXMLDoc.createElement(sName);
48343         if (vValue instanceof Object) {
48344           loadObjTree(oXMLDoc, oChild, vValue);
48345         } else if (vValue !== null && vValue !== true) {
48346           oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
48347         }
48348         oParentEl.appendChild(oChild);
48349      }
48350    }
48351   }
48352
48353   this.build = function (oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
48354     var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 : /* put here the default verbosity level: */ 1;
48355     return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);    
48356   };
48357
48358   this.unbuild = function (oObjTree) {    
48359     var oNewDoc = document.implementation.createDocument('', '', null);
48360     loadObjTree(oNewDoc, oNewDoc, oObjTree);
48361     return oNewDoc;
48362   };
48363
48364   this.stringify = function (oObjTree) {
48365     return (new XMLSerializer()).serializeToString(JXON.unbuild(oObjTree));
48366   };
48367 })();
48368
48369 // var myObject = JXON.build(doc);
48370 // we got our javascript object! try: alert(JSON.stringify(myObject));
48371
48372 // var newDoc = JXON.unbuild(myObject);
48373 // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
48374
48375 var dispatch$3 = dispatch('authLoading', 'authDone', 'change', 'loading', 'loaded');
48376 var urlroot = 'https://www.openstreetmap.org';
48377 var blacklists = ['.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*'];
48378 var inflight$1 = {};
48379 var loadedTiles = {};
48380 var tileZoom$1 = 16;
48381 var oauth = index$12({
48382         url: urlroot,
48383         oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
48384         oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
48385         loading: authLoading,
48386         done: authDone
48387     });
48388 var rateLimitError;
48389 var userChangesets;
48390 var userDetails;
48391 var off;
48392
48393
48394 function authLoading() {
48395     dispatch$3.call('authLoading');
48396 }
48397
48398
48399 function authDone() {
48400     dispatch$3.call('authDone');
48401 }
48402
48403
48404 function abortRequest$1(i) {
48405     if (i) {
48406         i.abort();
48407     }
48408 }
48409
48410
48411 function getLoc(attrs) {
48412     var lon = attrs.lon && attrs.lon.value,
48413         lat = attrs.lat && attrs.lat.value;
48414     return [parseFloat(lon), parseFloat(lat)];
48415 }
48416
48417
48418 function getNodes(obj) {
48419     var elems = obj.getElementsByTagName('nd'),
48420         nodes = new Array(elems.length);
48421     for (var i = 0, l = elems.length; i < l; i++) {
48422         nodes[i] = 'n' + elems[i].attributes.ref.value;
48423     }
48424     return nodes;
48425 }
48426
48427
48428 function getTags(obj) {
48429     var elems = obj.getElementsByTagName('tag'),
48430         tags = {};
48431     for (var i = 0, l = elems.length; i < l; i++) {
48432         var attrs = elems[i].attributes;
48433         tags[attrs.k.value] = attrs.v.value;
48434     }
48435
48436     return tags;
48437 }
48438
48439
48440 function getMembers(obj) {
48441     var elems = obj.getElementsByTagName('member'),
48442         members = new Array(elems.length);
48443     for (var i = 0, l = elems.length; i < l; i++) {
48444         var attrs = elems[i].attributes;
48445         members[i] = {
48446             id: attrs.type.value[0] + attrs.ref.value,
48447             type: attrs.type.value,
48448             role: attrs.role.value
48449         };
48450     }
48451     return members;
48452 }
48453
48454
48455 function getVisible(attrs) {
48456     return (!attrs.visible || attrs.visible.value !== 'false');
48457 }
48458
48459
48460 var parsers = {
48461     node: function nodeData(obj) {
48462         var attrs = obj.attributes;
48463         return new osmNode({
48464             id: osmEntity$$1.id.fromOSM('node', attrs.id.value),
48465             visible: getVisible(attrs),
48466             version: attrs.version.value,
48467             changeset: attrs.changeset && attrs.changeset.value,
48468             timestamp: attrs.timestamp && attrs.timestamp.value,
48469             user: attrs.user && attrs.user.value,
48470             uid: attrs.uid && attrs.uid.value,
48471             loc: getLoc(attrs),
48472             tags: getTags(obj)
48473         });
48474     },
48475
48476     way: function wayData(obj) {
48477         var attrs = obj.attributes;
48478         return new osmWay({
48479             id: osmEntity$$1.id.fromOSM('way', attrs.id.value),
48480             visible: getVisible(attrs),
48481             version: attrs.version.value,
48482             changeset: attrs.changeset && attrs.changeset.value,
48483             timestamp: attrs.timestamp && attrs.timestamp.value,
48484             user: attrs.user && attrs.user.value,
48485             uid: attrs.uid && attrs.uid.value,
48486             tags: getTags(obj),
48487             nodes: getNodes(obj),
48488         });
48489     },
48490
48491     relation: function relationData(obj) {
48492         var attrs = obj.attributes;
48493         return new osmRelation({
48494             id: osmEntity$$1.id.fromOSM('relation', attrs.id.value),
48495             visible: getVisible(attrs),
48496             version: attrs.version.value,
48497             changeset: attrs.changeset && attrs.changeset.value,
48498             timestamp: attrs.timestamp && attrs.timestamp.value,
48499             user: attrs.user && attrs.user.value,
48500             uid: attrs.uid && attrs.uid.value,
48501             tags: getTags(obj),
48502             members: getMembers(obj)
48503         });
48504     }
48505 };
48506
48507
48508 function parse$1(xml$$1) {
48509     if (!xml$$1 || !xml$$1.childNodes) return;
48510
48511     var root = xml$$1.childNodes[0],
48512         children = root.childNodes,
48513         entities = [];
48514
48515     for (var i = 0, l = children.length; i < l; i++) {
48516         var child = children[i],
48517             parser = parsers[child.nodeName];
48518         if (parser) {
48519             entities.push(parser(child));
48520         }
48521     }
48522
48523     return entities;
48524 }
48525
48526
48527 var serviceOsm = {
48528
48529     init: function() {
48530         utilRebind(this, dispatch$3, 'on');
48531     },
48532
48533
48534     reset: function() {
48535         userChangesets = undefined;
48536         userDetails = undefined;
48537         rateLimitError = undefined;
48538         lodash.forEach(inflight$1, abortRequest$1);
48539         loadedTiles = {};
48540         inflight$1 = {};
48541         return this;
48542     },
48543
48544
48545     changesetURL: function(changesetId) {
48546         return urlroot + '/changeset/' + changesetId;
48547     },
48548
48549
48550     changesetsURL: function(center, zoom$$1) {
48551         var precision = Math.max(0, Math.ceil(Math.log(zoom$$1) / Math.LN2));
48552         return urlroot + '/history#map=' +
48553             Math.floor(zoom$$1) + '/' +
48554             center[1].toFixed(precision) + '/' +
48555             center[0].toFixed(precision);
48556     },
48557
48558
48559     entityURL: function(entity) {
48560         return urlroot + '/' + entity.type + '/' + entity.osmId();
48561     },
48562
48563
48564     historyURL: function(entity) {
48565         return urlroot + '/' + entity.type + '/' + entity.osmId() + '/history';
48566     },
48567
48568
48569     userURL: function(username) {
48570         return urlroot + '/user/' + username;
48571     },
48572
48573
48574     loadFromAPI: function(path$$1, callback) {
48575         var that = this;
48576
48577         function done(err, xml$$1) {
48578             var isAuthenticated = that.authenticated();
48579
48580             // 400 Bad Request, 401 Unauthorized, 403 Forbidden
48581             // Logout and retry the request..
48582             if (isAuthenticated && err &&
48583                     (err.status === 400 || err.status === 401 || err.status === 403)) {
48584                 that.logout();
48585                 that.loadFromAPI(path$$1, callback);
48586
48587             // else, no retry..
48588             } else {
48589                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
48590                 // Set the rateLimitError flag and trigger a warning..
48591                 if (!isAuthenticated && !rateLimitError && err &&
48592                         (err.status === 509 || err.status === 429)) {
48593                     rateLimitError = err;
48594                     dispatch$3.call('change');
48595                 }
48596
48597                 if (callback) {
48598                     callback(err, parse$1(xml$$1));
48599                 }
48600             }
48601         }
48602
48603         if (this.authenticated()) {
48604             return oauth.xhr({ method: 'GET', path: path$$1 }, done);
48605         } else {
48606             var url = urlroot + path$$1;
48607             return xml(url).get(done);
48608         }
48609     },
48610
48611
48612     loadEntity: function(id, callback) {
48613         var type = osmEntity$$1.id.type(id),
48614             osmID = osmEntity$$1.id.toOSM(id);
48615
48616         this.loadFromAPI(
48617             '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
48618             function(err, entities) {
48619                 if (callback) callback(err, { data: entities });
48620             }
48621         );
48622     },
48623
48624
48625     loadEntityVersion: function(id, version$$1, callback) {
48626         var type = osmEntity$$1.id.type(id),
48627             osmID = osmEntity$$1.id.toOSM(id);
48628
48629         this.loadFromAPI(
48630             '/api/0.6/' + type + '/' + osmID + '/' + version$$1,
48631             function(err, entities) {
48632                 if (callback) callback(err, { data: entities });
48633             }
48634         );
48635     },
48636
48637
48638     loadMultiple: function(ids, callback) {
48639         var that = this;
48640         lodash.each(lodash.groupBy(lodash.uniq(ids), osmEntity$$1.id.type), function(v, k) {
48641             var type = k + 's',
48642                 osmIDs = lodash.map(v, osmEntity$$1.id.toOSM);
48643
48644             lodash.each(lodash.chunk(osmIDs, 150), function(arr) {
48645                 that.loadFromAPI(
48646                     '/api/0.6/' + type + '?' + type + '=' + arr.join(),
48647                     function(err, entities) {
48648                         if (callback) callback(err, { data: entities });
48649                     }
48650                 );
48651             });
48652         });
48653     },
48654
48655
48656     authenticated: function() {
48657         return oauth.authenticated();
48658     },
48659
48660
48661     putChangeset: function(changeset, changes, callback) {
48662
48663         // Create the changeset..
48664         oauth.xhr({
48665             method: 'PUT',
48666             path: '/api/0.6/changeset/create',
48667             options: { header: { 'Content-Type': 'text/xml' } },
48668             content: JXON.stringify(changeset.asJXON())
48669         }, createdChangeset);
48670
48671
48672         function createdChangeset(err, changeset_id) {
48673             if (err) return callback(err);
48674             changeset = changeset.update({ id: changeset_id });
48675
48676             // Upload the changeset..
48677             oauth.xhr({
48678                 method: 'POST',
48679                 path: '/api/0.6/changeset/' + changeset_id + '/upload',
48680                 options: { header: { 'Content-Type': 'text/xml' } },
48681                 content: JXON.stringify(changeset.osmChangeJXON(changes))
48682             }, uploadedChangeset);
48683         }
48684
48685
48686         function uploadedChangeset(err) {
48687             if (err) return callback(err);
48688
48689             // Upload was successful, safe to call the callback.
48690             // Add delay to allow for postgres replication #1646 #2678
48691             window.setTimeout(function() {
48692                 callback(null, changeset);
48693             }, 2500);
48694
48695             // Still attempt to close changeset, but ignore response because #2667
48696             oauth.xhr({
48697                 method: 'PUT',
48698                 path: '/api/0.6/changeset/' + changeset.id + '/close',
48699                 options: { header: { 'Content-Type': 'text/xml' } }
48700             }, function() { return true; });
48701         }
48702     },
48703
48704
48705     userDetails: function(callback) {
48706         if (userDetails) {
48707             callback(undefined, userDetails);
48708             return;
48709         }
48710
48711         function done(err, user_details) {
48712             if (err) return callback(err);
48713
48714             var u = user_details.getElementsByTagName('user')[0],
48715                 img = u.getElementsByTagName('img'),
48716                 image_url = '';
48717
48718             if (img && img[0] && img[0].getAttribute('href')) {
48719                 image_url = img[0].getAttribute('href');
48720             }
48721
48722             var changesets = u.getElementsByTagName('changesets'),
48723                 changesets_count = 0;
48724
48725             if (changesets && changesets[0] && changesets[0].getAttribute('count')) {
48726                 changesets_count = changesets[0].getAttribute('count');
48727             }
48728
48729             userDetails = {
48730                 id: u.attributes.id.value,
48731                 display_name: u.attributes.display_name.value,
48732                 image_url: image_url,
48733                 changesets_count: changesets_count
48734             };
48735
48736             callback(undefined, userDetails);
48737         }
48738
48739         oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
48740     },
48741
48742
48743     userChangesets: function(callback) {
48744         if (userChangesets) {
48745             callback(undefined, userChangesets);
48746             return;
48747         }
48748
48749         this.userDetails(function(err, user) {
48750             if (err) {
48751                 callback(err);
48752                 return;
48753             }
48754
48755             function done(err, changesets) {
48756                 if (err) {
48757                     callback(err);
48758                 } else {
48759                     userChangesets = Array.prototype.map.call(
48760                         changesets.getElementsByTagName('changeset'),
48761                         function (changeset) {
48762                             return { tags: getTags(changeset) };
48763                         }
48764                     ).filter(function (changeset) {
48765                         var comment = changeset.tags.comment;
48766                         return comment && comment !== '';
48767                     });
48768                     callback(undefined, userChangesets);
48769                 }
48770             }
48771
48772             oauth.xhr({ method: 'GET', path: '/api/0.6/changesets?user=' + user.id }, done);
48773         });
48774     },
48775
48776
48777     status: function(callback) {
48778         function done(xml$$1) {
48779             // update blacklists
48780             var elements = xml$$1.getElementsByTagName('blacklist'),
48781                 regexes = [];
48782             for (var i = 0; i < elements.length; i++) {
48783                 var regex = elements[i].getAttribute('regex');  // needs unencode?
48784                 if (regex) {
48785                     regexes.push(regex);
48786                 }
48787             }
48788             if (regexes.length) {
48789                 blacklists = regexes;
48790             }
48791
48792
48793             if (rateLimitError) {
48794                 callback(rateLimitError, 'rateLimited');
48795             } else {
48796                 var apiStatus = xml$$1.getElementsByTagName('status'),
48797                     val = apiStatus[0].getAttribute('api');
48798
48799                 callback(undefined, val);
48800             }
48801         }
48802
48803         xml(urlroot + '/api/capabilities').get()
48804             .on('load', done)
48805             .on('error', callback);
48806     },
48807
48808
48809     imageryBlacklists: function() {
48810         return blacklists;
48811     },
48812
48813
48814     tileZoom: function(_) {
48815         if (!arguments.length) return tileZoom$1;
48816         tileZoom$1 = _;
48817         return this;
48818     },
48819
48820
48821     loadTiles: function(projection$$1, dimensions, callback) {
48822         if (off) return;
48823
48824         var that = this,
48825             s = projection$$1.scale() * 2 * Math.PI,
48826             z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
48827             ts = 256 * Math.pow(2, z - tileZoom$1),
48828             origin = [
48829                 s / 2 - projection$$1.translate()[0],
48830                 s / 2 - projection$$1.translate()[1]
48831             ];
48832
48833         var tiles = d3geoTile()
48834             .scaleExtent([tileZoom$1, tileZoom$1])
48835             .scale(s)
48836             .size(dimensions)
48837             .translate(projection$$1.translate())()
48838             .map(function(tile) {
48839                 var x = tile[0] * ts - origin[0],
48840                     y = tile[1] * ts - origin[1];
48841
48842                 return {
48843                     id: tile.toString(),
48844                     extent: geoExtent$$1(
48845                         projection$$1.invert([x, y + ts]),
48846                         projection$$1.invert([x + ts, y]))
48847                 };
48848             });
48849
48850         lodash.filter(inflight$1, function(v, i) {
48851             var wanted = lodash.find(tiles, function(tile) {
48852                 return i === tile.id;
48853             });
48854             if (!wanted) delete inflight$1[i];
48855             return !wanted;
48856         }).map(abortRequest$1);
48857
48858         tiles.forEach(function(tile) {
48859             var id = tile.id;
48860
48861             if (loadedTiles[id] || inflight$1[id]) return;
48862
48863             if (lodash.isEmpty(inflight$1)) {
48864                 dispatch$3.call('loading');
48865             }
48866
48867             inflight$1[id] = that.loadFromAPI(
48868                 '/api/0.6/map?bbox=' + tile.extent.toParam(),
48869                 function(err, parsed) {
48870                     delete inflight$1[id];
48871                     if (!err) {
48872                         loadedTiles[id] = true;
48873                     }
48874
48875                     if (callback) {
48876                         callback(err, lodash.extend({ data: parsed }, tile));
48877                     }
48878
48879                     if (lodash.isEmpty(inflight$1)) {
48880                         dispatch$3.call('loaded');
48881                     }
48882                 }
48883             );
48884         });
48885     },
48886
48887
48888     switch: function(options) {
48889         urlroot = options.urlroot;
48890
48891         oauth.options(lodash.extend({
48892             url: urlroot,
48893             loading: authLoading,
48894             done: authDone
48895         }, options));
48896
48897         dispatch$3.call('change');
48898         this.reset();
48899         this.userChangesets(function() {});  // eagerly load user details/changesets
48900         return this;
48901     },
48902
48903
48904     toggle: function(_) {
48905         off = !_;
48906         return this;
48907     },
48908
48909
48910     loadedTiles: function(_) {
48911         if (!arguments.length) return loadedTiles;
48912         loadedTiles = _;
48913         return this;
48914     },
48915
48916
48917     logout: function() {
48918         userChangesets = undefined;
48919         userDetails = undefined;
48920         oauth.logout();
48921         dispatch$3.call('change');
48922         return this;
48923     },
48924
48925
48926     authenticate: function(callback) {
48927         var that = this;
48928         userChangesets = undefined;
48929         userDetails = undefined;
48930
48931         function done(err, res) {
48932             rateLimitError = undefined;
48933             dispatch$3.call('change');
48934             if (callback) callback(err, res);
48935             that.userChangesets(function() {});  // eagerly load user details/changesets
48936         }
48937
48938         return oauth.authenticate(done);
48939     }
48940 };
48941
48942 var apibase$2 = 'https://taginfo.openstreetmap.org/api/4/';
48943 var inflight$2 = {};
48944 var popularKeys = {};
48945 var taginfoCache = {};
48946 var tag_sorts = {
48947         point: 'count_nodes',
48948         vertex: 'count_nodes',
48949         area: 'count_ways',
48950         line: 'count_ways'
48951     };
48952 var tag_sort_members = {
48953         point: 'count_node_members',
48954         vertex: 'count_node_members',
48955         area: 'count_way_members',
48956         line: 'count_way_members',
48957         relation: 'count_relation_members'
48958     };
48959 var tag_filters = {
48960         point: 'nodes',
48961         vertex: 'nodes',
48962         area: 'ways',
48963         line: 'ways'
48964     };
48965 var tag_members_fractions = {
48966         point: 'count_node_members_fraction',
48967         vertex: 'count_node_members_fraction',
48968         area: 'count_way_members_fraction',
48969         line: 'count_way_members_fraction',
48970         relation: 'count_relation_members_fraction'
48971     };
48972
48973
48974 function sets(params, n, o) {
48975     if (params.geometry && o[params.geometry]) {
48976         params[n] = o[params.geometry];
48977     }
48978     return params;
48979 }
48980
48981
48982 function setFilter(params) {
48983     return sets(params, 'filter', tag_filters);
48984 }
48985
48986
48987 function setSort(params) {
48988     return sets(params, 'sortname', tag_sorts);
48989 }
48990
48991
48992 function setSortMembers(params) {
48993     return sets(params, 'sortname', tag_sort_members);
48994 }
48995
48996
48997 function clean(params) {
48998     return lodash.omit(params, ['geometry', 'debounce']);
48999 }
49000
49001
49002 function filterKeys(type) {
49003     var count_type = type ? 'count_' + type : 'count_all';
49004     return function(d) {
49005         return parseFloat(d[count_type]) > 2500 || d.in_wiki;
49006     };
49007 }
49008
49009
49010 function filterMultikeys(prefix) {
49011     return function(d) {
49012         // d.key begins with prefix, and d.key contains no additional ':'s
49013         var re = new RegExp('^' + prefix + '(.*)$');
49014         var matches = d.key.match(re) || [];
49015         return (matches.length === 2 && matches[1].indexOf(':') === -1);
49016     };
49017 }
49018
49019
49020 function filterValues(allowUpperCase) {
49021     return function(d) {
49022         if (d.value.match(/[;,]/) !== null) return false;  // exclude some punctuation
49023         if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false;  // exclude uppercase letters
49024         return parseFloat(d.fraction) > 0.0 || d.in_wiki;
49025     };
49026 }
49027
49028
49029 function filterRoles(geometry) {
49030     return function(d) {
49031         if (d.role === '') return false; // exclude empty role
49032         if (d.role.match(/[A-Z*;,]/) !== null) return false;  // exclude uppercase letters and some punctuation
49033         return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
49034     };
49035 }
49036
49037
49038 function valKey(d) {
49039     return {
49040         value: d.key,
49041         title: d.key
49042     };
49043 }
49044
49045
49046 function valKeyDescription(d) {
49047     return {
49048         value: d.value,
49049         title: d.description || d.value
49050     };
49051 }
49052
49053
49054 function roleKey(d) {
49055     return {
49056         value: d.role,
49057         title: d.role
49058     };
49059 }
49060
49061
49062 // sort keys with ':' lower than keys without ':'
49063 function sortKeys(a, b) {
49064     return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
49065         : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
49066         : 0;
49067 }
49068
49069
49070 var debouncedRequest = lodash.debounce(request$1, 500, { leading: false });
49071
49072 function request$1(url, params, exactMatch, callback, loaded) {
49073     if (inflight$2[url]) return;
49074
49075     if (checkCache(url, params, exactMatch, callback)) return;
49076
49077     inflight$2[url] = json(url, function (err, data) {
49078         delete inflight$2[url];
49079         loaded(err, data);
49080     });
49081 }
49082
49083
49084 function checkCache(url, params, exactMatch, callback) {
49085     var rp = params.rp || 25,
49086         testQuery = params.query || '',
49087         testUrl = url;
49088
49089     do {
49090         var hit = taginfoCache[testUrl];
49091
49092         // exact match, or shorter match yielding fewer than max results (rp)
49093         if (hit && (url === testUrl || hit.length < rp)) {
49094             callback(null, hit);
49095             return true;
49096         }
49097
49098         // don't try to shorten the query
49099         if (exactMatch || !testQuery.length) return false;
49100
49101         // do shorten the query to see if we already have a cached result
49102         // that has returned fewer than max results (rp)
49103         testQuery = testQuery.slice(0, -1);
49104         testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
49105     } while (testQuery.length >= 0);
49106
49107     return false;
49108 }
49109
49110
49111 var serviceTaginfo = {
49112
49113     init: function() {
49114         inflight$2 = {};
49115         taginfoCache = {};
49116         popularKeys = {};
49117
49118         // Fetch popular keys.  We'll exclude these from `values`
49119         // lookups because they stress taginfo, and they aren't likely
49120         // to yield meaningful autocomplete results.. see #3955
49121         var params = { rp: 100, sortname: 'values_all', sortorder: 'desc', page: 1, debounce: false };
49122         this.keys(params, function(err, data) {
49123             if (err) return;
49124             data.forEach(function(d) {
49125                 if (d.value === 'opening_hours') return;  // exception
49126                 popularKeys[d.value] = true;
49127             });
49128         });
49129     },
49130
49131
49132     reset: function() {
49133         lodash.forEach(inflight$2, function(req) { req.abort(); });
49134         inflight$2 = {};
49135     },
49136
49137
49138     keys: function(params, callback) {
49139         var doRequest = params.debounce ? debouncedRequest : request$1;
49140         params = clean(setSort(params));
49141         params = lodash.extend({ rp: 10, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
49142
49143         var url = apibase$2 + 'keys/all?' + utilQsString(params);
49144         doRequest(url, params, false, callback, function(err, d) {
49145             if (err) {
49146                 callback(err);
49147             } else {
49148                 var f = filterKeys(params.filter);
49149                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
49150                 taginfoCache[url] = result;
49151                 callback(null, result);
49152             }
49153         });
49154     },
49155
49156
49157     multikeys: function(params, callback) {
49158         var doRequest = params.debounce ? debouncedRequest : request$1;
49159         params = clean(setSort(params));
49160         params = lodash.extend({ rp: 25, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
49161         var prefix = params.query;
49162
49163         var url = apibase$2 + 'keys/all?' + utilQsString(params);
49164         doRequest(url, params, true, callback, function(err, d) {
49165             if (err) {
49166                 callback(err);
49167             } else {
49168                 var f = filterMultikeys(prefix);
49169                 var result = d.data.filter(f).map(valKey);
49170                 taginfoCache[url] = result;
49171                 callback(null, result);
49172             }
49173         });
49174     },
49175
49176
49177     values: function(params, callback) {
49178         // Exclude popular keys from values lookups.. see #3955
49179         var key = params.key;
49180         if (key && popularKeys[key]) {
49181             callback(null, []);
49182             return;
49183         }
49184
49185         var doRequest = params.debounce ? debouncedRequest : request$1;
49186         params = clean(setSort(setFilter(params)));
49187         params = lodash.extend({ rp: 25, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
49188
49189         var url = apibase$2 + 'key/values?' + utilQsString(params);
49190         doRequest(url, params, false, callback, function(err, d) {
49191             if (err) {
49192                 callback(err);
49193             } else {
49194                 // In most cases we prefer taginfo value results with lowercase letters.
49195                 // A few OSM keys expect values to contain uppercase values (see #3377).
49196                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
49197                 // but these are the fields where taginfo value lookup is most useful.
49198                 var re = /network|taxon|genus|species|brand|grape_variety|_hours|_times/;
49199                 var allowUpperCase = (params.key.match(re) !== null);
49200                 var f = filterValues(allowUpperCase);
49201
49202                 var result = d.data.filter(f).map(valKeyDescription);
49203                 taginfoCache[url] = result;
49204                 callback(null, result);
49205             }
49206         });
49207     },
49208
49209
49210     roles: function(params, callback) {
49211         var doRequest = params.debounce ? debouncedRequest : request$1;
49212         var geometry = params.geometry;
49213         params = clean(setSortMembers(params));
49214         params = lodash.extend({ rp: 25, sortname: 'count_all_members', sortorder: 'desc', page: 1 }, params);
49215
49216         var url = apibase$2 + 'relation/roles?' + utilQsString(params);
49217         doRequest(url, params, true, callback, function(err, d) {
49218             if (err) {
49219                 callback(err);
49220             } else {
49221                 var f = filterRoles(geometry);
49222                 var result = d.data.filter(f).map(roleKey);
49223                 taginfoCache[url] = result;
49224                 callback(null, result);
49225             }
49226         });
49227     },
49228
49229
49230     docs: function(params, callback) {
49231         var doRequest = params.debounce ? debouncedRequest : request$1;
49232         params = clean(setSort(params));
49233
49234         var path$$1 = 'key/wiki_pages?';
49235         if (params.value) path$$1 = 'tag/wiki_pages?';
49236         else if (params.rtype) path$$1 = 'relation/wiki_pages?';
49237
49238         var url = apibase$2 + path$$1 + utilQsString(params);
49239         doRequest(url, params, true, callback, function(err, d) {
49240             if (err) {
49241                 callback(err);
49242             } else {
49243                 taginfoCache[url] = d.data;
49244                 callback(null, d.data);
49245             }
49246         });
49247     },
49248
49249
49250     apibase: function(_) {
49251         if (!arguments.length) return apibase$2;
49252         apibase$2 = _;
49253         return this;
49254     }
49255
49256 };
49257
49258 var jsonpCache = {};
49259 window.jsonpCache = jsonpCache;
49260
49261 function jsonpRequest(url, callback) {
49262
49263   if (window.JSONP_FIX) {
49264     if (window.JSONP_DELAY === 0) {
49265       callback(window.JSONP_FIX);
49266     } else {
49267       setTimeout(function() {
49268         callback(window.JSONP_FIX);
49269       }, window.JSONP_DELAY || 0);
49270     }
49271     return;
49272   }
49273
49274   function rand() {
49275     var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
49276       c = '', i = -1;
49277     while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
49278     return c;
49279   }
49280
49281   function create(url) {
49282     var e = url.match(/callback=(\w+)/),
49283       c = e ? e[1] : rand();
49284     jsonpCache[c] = function(data) {
49285       callback(data);
49286       delete jsonpCache[c];
49287       script.remove();
49288     };
49289     return 'jsonpCache.' + c;
49290   }
49291
49292   var cb = create(url),
49293     script = select('head')
49294     .append('script')
49295     .attr('type', 'text/javascript')
49296     .attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
49297 }
49298
49299 var endpoint = 'https://www.wikidata.org/w/api.php?';
49300
49301 var serviceWikidata = {
49302
49303     init: function() {},
49304     reset: function() {},
49305
49306
49307     // Given a Wikipedia language and article title, return an array of
49308     // corresponding Wikidata entities.
49309     itemsByTitle: function(lang, title, callback) {
49310         if (!title) {
49311             callback('', {});
49312             return;
49313         }
49314
49315         lang = lang || 'en';
49316         jsonpRequest(endpoint + utilQsString({
49317             action: 'wbgetentities',
49318             format: 'json',
49319             sites: lang.replace(/-/g, '_') + 'wiki',
49320             titles: title,
49321             languages: 'en', // shrink response by filtering to one language
49322             callback: '{callback}'
49323         }), function(data) {
49324             if (!data || data.error) {
49325                 callback('', {});
49326             } else {
49327                 callback(title, data.entities || {});
49328             }
49329         });
49330     }
49331
49332 };
49333
49334 var endpoint$1 = 'https://en.wikipedia.org/w/api.php?';
49335
49336 var serviceWikipedia = {
49337
49338     init: function() {},
49339     reset: function() {},
49340
49341
49342     search: function(lang, query, callback) {
49343         if (!query) {
49344             callback('', []);
49345             return;
49346         }
49347
49348         lang = lang || 'en';
49349         jsonpRequest(endpoint$1.replace('en', lang) +
49350             utilQsString({
49351                 action: 'query',
49352                 list: 'search',
49353                 srlimit: '10',
49354                 srinfo: 'suggestion',
49355                 format: 'json',
49356                 callback: '{callback}',
49357                 srsearch: query
49358             }), function(data) {
49359                 if (!data || !data.query || !data.query.search || data.error) {
49360                     callback('', []);
49361                 } else {
49362                     var results = data.query.search.map(function(d) { return d.title; });
49363                     callback(query, results);
49364                 }
49365             }
49366         );
49367     },
49368
49369
49370     suggestions: function(lang, query, callback) {
49371         if (!query) {
49372             callback('', []);
49373             return;
49374         }
49375
49376         lang = lang || 'en';
49377         jsonpRequest(endpoint$1.replace('en', lang) +
49378             utilQsString({
49379                 action: 'opensearch',
49380                 namespace: 0,
49381                 suggest: '',
49382                 format: 'json',
49383                 callback: '{callback}',
49384                 search: query
49385             }), function(data) {
49386                 if (!data || data.error) {
49387                     callback('', []);
49388                 } else {
49389                     callback(data[0], data[1] || []);
49390                 }
49391             }
49392         );
49393     },
49394
49395
49396     translations: function(lang, title, callback) {
49397         if (!title) {
49398             callback({});
49399             return;
49400         }
49401
49402         jsonpRequest(endpoint$1.replace('en', lang) +
49403             utilQsString({
49404                 action: 'query',
49405                 prop: 'langlinks',
49406                 format: 'json',
49407                 callback: '{callback}',
49408                 lllimit: 500,
49409                 titles: title
49410             }), function(data) {
49411                 if (!data || !data.query || !data.query.pages || data.error) {
49412                     callback({});
49413                 } else {
49414                     var list = data.query.pages[Object.keys(data.query.pages)[0]],
49415                         translations = {};
49416                     if (list && list.langlinks) {
49417                         list.langlinks.forEach(function(d) {
49418                             translations[d.lang] = d['*'];
49419                         });
49420                     }
49421                     callback(translations);
49422                 }
49423             }
49424         );
49425     }
49426
49427 };
49428
49429 var services = {
49430     mapillary: serviceMapillary,
49431     geocoder: serviceNominatim,
49432     osm: serviceOsm,
49433     taginfo: serviceTaginfo,
49434     wikidata: serviceWikidata,
49435     wikipedia: serviceWikipedia
49436 };
49437
49438 function svgMapillaryImages(projection$$1, context, dispatch$$1) {
49439     var throttledRedraw = lodash.throttle(function () { dispatch$$1.call('change'); }, 1000),
49440         minZoom = 12,
49441         minViewfieldZoom = 17,
49442         layer = select(null),
49443         _mapillary;
49444
49445
49446     function init() {
49447         if (svgMapillaryImages.initialized) return;  // run once
49448         svgMapillaryImages.enabled = false;
49449         svgMapillaryImages.initialized = true;
49450     }
49451
49452
49453     function getMapillary() {
49454         if (services.mapillary && !_mapillary) {
49455             _mapillary = services.mapillary;
49456             _mapillary.event.on('loadedImages', throttledRedraw);
49457         } else if (!services.mapillary && _mapillary) {
49458             _mapillary = null;
49459         }
49460
49461         return _mapillary;
49462     }
49463
49464
49465     function showLayer() {
49466         var mapillary = getMapillary();
49467         if (!mapillary) return;
49468
49469         mapillary.loadViewer(context);
49470         editOn();
49471
49472         layer
49473             .style('opacity', 0)
49474             .transition()
49475             .duration(500)
49476             .style('opacity', 1)
49477             .on('end', function () { dispatch$$1.call('change'); });
49478     }
49479
49480
49481     function hideLayer() {
49482         var mapillary = getMapillary();
49483         if (mapillary) {
49484             mapillary.hideViewer();
49485         }
49486
49487         throttledRedraw.cancel();
49488
49489         layer
49490             .transition()
49491             .duration(500)
49492             .style('opacity', 0)
49493             .on('end', editOff);
49494     }
49495
49496
49497     function editOn() {
49498         layer.style('display', 'block');
49499     }
49500
49501
49502     function editOff() {
49503         layer.selectAll('.viewfield-group').remove();
49504         layer.style('display', 'none');
49505     }
49506
49507
49508     function click(d) {
49509         var mapillary = getMapillary();
49510         if (!mapillary) return;
49511
49512         context.map().centerEase(d.loc);
49513
49514         mapillary
49515             .selectedImage(d.key, true)
49516             .updateViewer(d.key, context)
49517             .showViewer();
49518     }
49519
49520
49521     function transform$$1(d) {
49522         var t = svgPointTransform(projection$$1)(d);
49523         if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
49524         return t;
49525     }
49526
49527
49528     function update() {
49529         var mapillary = getMapillary(),
49530             data = (mapillary ? mapillary.images(projection$$1) : []),
49531             imageKey = mapillary ? mapillary.selectedImage() : null;
49532
49533         var markers = layer.selectAll('.viewfield-group')
49534             .data(data, function(d) { return d.key; });
49535
49536         markers.exit()
49537             .remove();
49538
49539         var enter = markers.enter()
49540             .append('g')
49541             .attr('class', 'viewfield-group')
49542             .classed('selected', function(d) { return d.key === imageKey; })
49543             .on('click', click);
49544
49545         markers = markers
49546             .merge(enter)
49547             .attr('transform', transform$$1);
49548
49549
49550        var viewfields = markers.selectAll('.viewfield')
49551             .data(~~context.map().zoom() >= minViewfieldZoom ? [0] : []);
49552
49553         viewfields.exit()
49554             .remove();
49555
49556         viewfields.enter()
49557             .append('path')
49558             .attr('class', 'viewfield')
49559             .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
49560             .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');
49561
49562         markers.selectAll('circle')
49563             .data([0])
49564             .enter()
49565             .append('circle')
49566             .attr('dx', '0')
49567             .attr('dy', '0')
49568             .attr('r', '6');
49569     }
49570
49571
49572     function drawImages(selection$$1) {
49573         var enabled = svgMapillaryImages.enabled,
49574             mapillary = getMapillary();
49575
49576         layer = selection$$1.selectAll('.layer-mapillary-images')
49577             .data(mapillary ? [0] : []);
49578
49579         layer.exit()
49580             .remove();
49581
49582         layer = layer.enter()
49583             .append('g')
49584             .attr('class', 'layer-mapillary-images')
49585             .style('display', enabled ? 'block' : 'none')
49586             .merge(layer);
49587
49588         if (enabled) {
49589             if (mapillary && ~~context.map().zoom() >= minZoom) {
49590                 editOn();
49591                 update();
49592                 mapillary.loadImages(projection$$1);
49593             } else {
49594                 editOff();
49595             }
49596         }
49597     }
49598
49599
49600     drawImages.enabled = function(_) {
49601         if (!arguments.length) return svgMapillaryImages.enabled;
49602         svgMapillaryImages.enabled = _;
49603         if (svgMapillaryImages.enabled) {
49604             showLayer();
49605         } else {
49606             hideLayer();
49607         }
49608         dispatch$$1.call('change');
49609         return this;
49610     };
49611
49612
49613     drawImages.supported = function() {
49614         return !!getMapillary();
49615     };
49616
49617
49618     init();
49619     return drawImages;
49620 }
49621
49622 function svgMapillarySigns(projection$$1, context, dispatch$$1) {
49623     var throttledRedraw = lodash.throttle(function () { dispatch$$1.call('change'); }, 1000),
49624         minZoom = 12,
49625         layer = select(null),
49626         _mapillary;
49627
49628
49629     function init() {
49630         if (svgMapillarySigns.initialized) return;  // run once
49631         svgMapillarySigns.enabled = false;
49632         svgMapillarySigns.initialized = true;
49633     }
49634
49635
49636     function getMapillary() {
49637         if (services.mapillary && !_mapillary) {
49638             _mapillary = services.mapillary;
49639             _mapillary.event.on('loadedSigns', throttledRedraw);
49640         } else if (!services.mapillary && _mapillary) {
49641             _mapillary = null;
49642         }
49643         return _mapillary;
49644     }
49645
49646
49647     function showLayer() {
49648         editOn();
49649     }
49650
49651
49652     function hideLayer() {
49653         throttledRedraw.cancel();
49654         editOff();
49655     }
49656
49657
49658     function editOn() {
49659         layer.style('display', 'block');
49660     }
49661
49662
49663     function editOff() {
49664         layer.selectAll('.icon-sign').remove();
49665         layer.style('display', 'none');
49666     }
49667
49668
49669     function click(d) {
49670         var mapillary = getMapillary();
49671         if (!mapillary) return;
49672
49673         context.map().centerEase(d.loc);
49674
49675         mapillary
49676             .selectedImage(d.key, true)
49677             .updateViewer(d.key, context)
49678             .showViewer();
49679     }
49680
49681
49682     function update() {
49683         var mapillary = getMapillary(),
49684             data = (mapillary ? mapillary.signs(projection$$1) : []),
49685             imageKey = mapillary ? mapillary.selectedImage() : null;
49686
49687         var signs = layer.selectAll('.icon-sign')
49688             .data(data, function(d) { return d.key; });
49689
49690         signs.exit()
49691             .remove();
49692
49693         var enter = signs.enter()
49694             .append('foreignObject')
49695             .attr('class', 'icon-sign')
49696             .attr('width', '32px')      // for Firefox
49697             .attr('height', '32px')     // for Firefox
49698             .classed('selected', function(d) { return d.key === imageKey; })
49699             .on('click', click);
49700
49701         enter
49702             .append('xhtml:body')
49703             .attr('class', 'icon-sign-body')
49704             .html(mapillary.signHTML);
49705
49706         signs
49707             .merge(enter)
49708             .attr('x', function(d) { return projection$$1(d.loc)[0] - 16; })   // offset by -16px to
49709             .attr('y', function(d) { return projection$$1(d.loc)[1] - 16; });  // center signs on loc
49710     }
49711
49712
49713     function drawSigns(selection$$1) {
49714         var enabled = svgMapillarySigns.enabled,
49715             mapillary = getMapillary();
49716
49717         layer = selection$$1.selectAll('.layer-mapillary-signs')
49718             .data(mapillary ? [0] : []);
49719
49720         layer.exit()
49721             .remove();
49722
49723         layer = layer.enter()
49724             .append('g')
49725             .attr('class', 'layer-mapillary-signs')
49726             .style('display', enabled ? 'block' : 'none')
49727             .merge(layer);
49728
49729         if (enabled) {
49730             if (mapillary && ~~context.map().zoom() >= minZoom) {
49731                 editOn();
49732                 update();
49733                 mapillary.loadSigns(context, projection$$1);
49734             } else {
49735                 editOff();
49736             }
49737         }
49738     }
49739
49740
49741     drawSigns.enabled = function(_) {
49742         if (!arguments.length) return svgMapillarySigns.enabled;
49743         svgMapillarySigns.enabled = _;
49744         if (svgMapillarySigns.enabled) {
49745             showLayer();
49746         } else {
49747             hideLayer();
49748         }
49749         dispatch$$1.call('change');
49750         return this;
49751     };
49752
49753
49754     drawSigns.supported = function() {
49755         var mapillary = getMapillary();
49756         return (mapillary && mapillary.signsSupported());
49757     };
49758
49759
49760     init();
49761     return drawSigns;
49762 }
49763
49764 function svgOsm() {
49765     return function drawOsm(selection) {
49766         var layers = selection.selectAll('.layer-osm')
49767             .data(['areas', 'lines', 'hit', 'halo', 'label']);
49768
49769         layers.enter()
49770             .append('g')
49771             .attr('class', function(d) { return 'layer-osm layer-' + d; });
49772     };
49773 }
49774
49775 function svgLayers(projection$$1, context) {
49776     var dispatch$$1 = dispatch('change'),
49777         svg = select(null),
49778         layers = [
49779             { id: 'osm', layer: svgOsm(projection$$1, context, dispatch$$1) },
49780             { id: 'gpx', layer: svgGpx(projection$$1, context, dispatch$$1) },
49781             { id: 'mapillary-images', layer: svgMapillaryImages(projection$$1, context, dispatch$$1) },
49782             { id: 'mapillary-signs',  layer: svgMapillarySigns(projection$$1, context, dispatch$$1) },
49783             { id: 'debug', layer: svgDebug(projection$$1, context, dispatch$$1) }
49784         ];
49785
49786
49787     function drawLayers(selection$$1) {
49788         svg = selection$$1.selectAll('.surface')
49789             .data([0]);
49790
49791         svg = svg.enter()
49792             .append('svg')
49793             .attr('class', 'surface')
49794             .merge(svg);
49795
49796         var defs = svg.selectAll('.surface-defs')
49797             .data([0]);
49798
49799         defs.enter()
49800             .append('defs')
49801             .attr('class', 'surface-defs');
49802
49803         var groups = svg.selectAll('.data-layer')
49804             .data(layers);
49805
49806         groups.exit()
49807             .remove();
49808
49809         groups.enter()
49810             .append('g')
49811             .attr('class', function(d) { return 'data-layer data-layer-' + d.id; })
49812             .merge(groups)
49813             .each(function(d) { select(this).call(d.layer); });
49814     }
49815
49816
49817     drawLayers.all = function() {
49818         return layers;
49819     };
49820
49821
49822     drawLayers.layer = function(id) {
49823         var obj = lodash.find(layers, function(o) {return o.id === id;});
49824         return obj && obj.layer;
49825     };
49826
49827
49828     drawLayers.only = function(what) {
49829         var arr = [].concat(what);
49830         drawLayers.remove(lodash.difference(lodash.map(layers, 'id'), arr));
49831         return this;
49832     };
49833
49834
49835     drawLayers.remove = function(what) {
49836         var arr = [].concat(what);
49837         arr.forEach(function(id) {
49838             layers = lodash.reject(layers, function(o) {return o.id === id;});
49839         });
49840         dispatch$$1.call('change');
49841         return this;
49842     };
49843
49844
49845     drawLayers.add = function(what) {
49846         var arr = [].concat(what);
49847         arr.forEach(function(obj) {
49848             if ('id' in obj && 'layer' in obj) {
49849                 layers.push(obj);
49850             }
49851         });
49852         dispatch$$1.call('change');
49853         return this;
49854     };
49855
49856
49857     drawLayers.dimensions = function(_) {
49858         if (!arguments.length) return utilGetDimensions(svg);
49859         utilSetDimensions(svg, _);
49860         return this;
49861     };
49862
49863
49864     return utilRebind(drawLayers, dispatch$$1, 'on');
49865 }
49866
49867 function svgLines$$1(projection$$1, context) {
49868     var detected = utilDetect();
49869
49870     var highway_stack = {
49871         motorway: 0,
49872         motorway_link: 1,
49873         trunk: 2,
49874         trunk_link: 3,
49875         primary: 4,
49876         primary_link: 5,
49877         secondary: 6,
49878         tertiary: 7,
49879         unclassified: 8,
49880         residential: 9,
49881         service: 10,
49882         footway: 11
49883     };
49884
49885
49886     function drawLines(selection$$1, graph, entities, filter) {
49887
49888
49889         function waystack(a, b) {
49890             var selected = context.selectedIDs(),
49891                 scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0,
49892                 scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
49893
49894             if (a.tags.highway) { scoreA -= highway_stack[a.tags.highway]; }
49895             if (b.tags.highway) { scoreB -= highway_stack[b.tags.highway]; }
49896             return scoreA - scoreB;
49897         }
49898
49899
49900         function drawLineGroup(selection$$1, klass, isSelected) {
49901             var lines = selection$$1
49902                 .selectAll('path')
49903                 .filter(filter)
49904                 .data(getPathData(isSelected), osmEntity$$1.key);
49905
49906             lines.exit()
49907                 .remove();
49908
49909             // Optimization: call simple TagClasses only on enter selection. This
49910             // works because osmEntity.key is defined to include the entity v attribute.
49911             lines.enter()
49912                 .append('path')
49913                 .attr('class', function(d) {
49914                     return 'way line ' + klass + ' ' + d.id + (isSelected ? ' selected' : '') +
49915                         (oldMultiPolygonOuters[d.id] ? ' old-multipolygon' : '');
49916                 })
49917                 .call(svgTagClasses())
49918                 .merge(lines)
49919                 .sort(waystack)
49920                 .attr('d', getPath)
49921                 .call(svgTagClasses().tags(svgRelationMemberTags(graph)));
49922
49923             return selection$$1;
49924         }
49925
49926
49927         function getPathData(isSelected) {
49928             return function() {
49929                 var layer = this.parentNode.__data__;
49930                 var data = pathdata[layer] || [];
49931                 return data.filter(function(d) {
49932                     if (isSelected)
49933                         return context.selectedIDs().indexOf(d.id) !== -1;
49934                     else
49935                         return context.selectedIDs().indexOf(d.id) === -1;
49936                 });
49937             };
49938         }
49939
49940
49941         var getPath = svgPath(projection$$1, graph),
49942             ways = [],
49943             pathdata = {},
49944             onewaydata = {},
49945             oldMultiPolygonOuters = {};
49946
49947         for (var i = 0; i < entities.length; i++) {
49948             var entity = entities[i],
49949                 outer = osmSimpleMultipolygonOuterMember(entity, graph);
49950             if (outer) {
49951                 ways.push(entity.mergeTags(outer.tags));
49952                 oldMultiPolygonOuters[outer.id] = true;
49953             } else if (entity.geometry(graph) === 'line') {
49954                 ways.push(entity);
49955             }
49956         }
49957
49958         ways = ways.filter(getPath);
49959         pathdata = lodash.groupBy(ways, function(way) { return way.layer(); });
49960
49961         lodash.forOwn(pathdata, function(v, k) {
49962             onewaydata[k] = lodash(v)
49963                 .filter(function(d) { return d.isOneWay(); })
49964                 .map(svgOneWaySegments(projection$$1, graph, 35))
49965                 .flatten()
49966                 .valueOf();
49967         });
49968
49969
49970         var layer = selection$$1.selectAll('.layer-lines');
49971
49972         var layergroup = layer
49973             .selectAll('g.layergroup')
49974             .data(sequence(-10, 11));
49975
49976         layergroup = layergroup.enter()
49977             .append('g')
49978             .attr('class', function(d) { return 'layergroup layer' + String(d); })
49979             .merge(layergroup);
49980
49981         layergroup
49982             .selectAll('g.linegroup')
49983             .data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted'])
49984             .enter()
49985             .append('g')
49986             .attr('class', function(d) { return 'linegroup line-' + d; });
49987
49988
49989         layergroup.selectAll('g.line-shadow')
49990             .call(drawLineGroup, 'shadow', false);
49991         layergroup.selectAll('g.line-casing')
49992             .call(drawLineGroup, 'casing', false);
49993         layergroup.selectAll('g.line-stroke')
49994             .call(drawLineGroup, 'stroke', false);
49995
49996         layergroup.selectAll('g.line-shadow-highlighted')
49997             .call(drawLineGroup, 'shadow', true);
49998         layergroup.selectAll('g.line-casing-highlighted')
49999             .call(drawLineGroup, 'casing', true);
50000         layergroup.selectAll('g.line-stroke-highlighted')
50001             .call(drawLineGroup, 'stroke', true);
50002
50003
50004         var onewaygroup = layergroup
50005             .selectAll('g.onewaygroup')
50006             .data(['oneway']);
50007
50008         onewaygroup = onewaygroup.enter()
50009             .append('g')
50010             .attr('class', 'onewaygroup')
50011             .merge(onewaygroup);
50012
50013         var oneways = onewaygroup
50014             .selectAll('path')
50015             .filter(filter)
50016             .data(
50017                 function() { return onewaydata[this.parentNode.__data__] || []; },
50018                 function(d) { return [d.id, d.index]; }
50019             );
50020
50021         oneways.exit()
50022             .remove();
50023
50024         oneways = oneways.enter()
50025             .append('path')
50026             .attr('class', 'oneway')
50027             .attr('marker-mid', 'url(#oneway-marker)')
50028             .merge(oneways)
50029             .attr('d', function(d) { return d.d; });
50030
50031         if (detected.ie) {
50032             oneways.each(function() { this.parentNode.insertBefore(this, this); });
50033         }
50034     }
50035
50036
50037     return drawLines;
50038 }
50039
50040 function svgMidpoints$$1(projection, context) {
50041
50042     return function drawMidpoints(selection, graph, entities, filter, extent) {
50043         var layer = selection.selectAll('.layer-hit');
50044
50045         var mode = context.mode();
50046         if (mode && mode.id !== 'select') {
50047             layer.selectAll('g.midpoint').remove();
50048             return;
50049         }
50050
50051         var poly = extent.polygon(),
50052             midpoints = {};
50053
50054         for (var i = 0; i < entities.length; i++) {
50055             var entity = entities[i];
50056
50057             if (entity.type !== 'way')
50058                 continue;
50059             if (!filter(entity))
50060                 continue;
50061             if (context.selectedIDs().indexOf(entity.id) < 0)
50062                 continue;
50063
50064             var nodes = graph.childNodes(entity);
50065             for (var j = 0; j < nodes.length - 1; j++) {
50066
50067                 var a = nodes[j],
50068                     b = nodes[j + 1],
50069                     id = [a.id, b.id].sort().join('-');
50070
50071                 if (midpoints[id]) {
50072                     midpoints[id].parents.push(entity);
50073                 } else {
50074                     if (geoEuclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
50075                         var point = geoInterp(a.loc, b.loc, 0.5),
50076                             loc = null;
50077
50078                         if (extent.intersects(point)) {
50079                             loc = point;
50080                         } else {
50081                             for (var k = 0; k < 4; k++) {
50082                                 point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
50083                                 if (point &&
50084                                     geoEuclideanDistance(projection(a.loc), projection(point)) > 20 &&
50085                                     geoEuclideanDistance(projection(b.loc), projection(point)) > 20)
50086                                 {
50087                                     loc = point;
50088                                     break;
50089                                 }
50090                             }
50091                         }
50092
50093                         if (loc) {
50094                             midpoints[id] = {
50095                                 type: 'midpoint',
50096                                 id: id,
50097                                 loc: loc,
50098                                 edge: [a.id, b.id],
50099                                 parents: [entity]
50100                             };
50101                         }
50102                     }
50103                 }
50104             }
50105         }
50106
50107
50108         function midpointFilter(d) {
50109             if (midpoints[d.id])
50110                 return true;
50111
50112             for (var i = 0; i < d.parents.length; i++) {
50113                 if (filter(d.parents[i])) {
50114                     return true;
50115                 }
50116             }
50117
50118             return false;
50119         }
50120
50121
50122         var groups = layer
50123             .selectAll('g.midpoint')
50124             .filter(midpointFilter)
50125             .data(lodash.values(midpoints), function(d) { return d.id; });
50126
50127         groups.exit()
50128             .remove();
50129
50130         var enter = groups.enter()
50131             .insert('g', ':first-child')
50132             .attr('class', 'midpoint');
50133
50134         enter.append('polygon')
50135             .attr('points', '-6,8 10,0 -6,-8')
50136             .attr('class', 'shadow');
50137
50138         enter.append('polygon')
50139             .attr('points', '-3,4 5,0 -3,-4')
50140             .attr('class', 'fill');
50141
50142         groups = groups
50143             .merge(enter)
50144             .attr('transform', function(d) {
50145                 var translate = svgPointTransform(projection),
50146                     a = graph.entity(d.edge[0]),
50147                     b = graph.entity(d.edge[1]),
50148                     angleVal = Math.round(geoAngle(a, b, projection) * (180 / Math.PI));
50149                 return translate(d) + ' rotate(' + angleVal + ')';
50150             })
50151             .call(svgTagClasses().tags(
50152                 function(d) { return d.parents[0].tags; }
50153             ));
50154
50155         // Propagate data bindings.
50156         groups.select('polygon.shadow');
50157         groups.select('polygon.fill');
50158
50159     };
50160 }
50161
50162 function svgOneWaySegments(projection$$1, graph, dt) {
50163     return function(entity) {
50164         var a,
50165             b,
50166             i = 0,
50167             offset = dt,
50168             segments = [],
50169             clip = identity$5().clipExtent(projection$$1.clipExtent()).stream,
50170             coordinates = graph.childNodes(entity).map(function(n) {
50171                 return n.loc;
50172             });
50173
50174         if (entity.tags.oneway === '-1') coordinates.reverse();
50175
50176         geoStream({
50177             type: 'LineString',
50178             coordinates: coordinates
50179         }, projection$$1.stream(clip({
50180             lineStart: function() {},
50181             lineEnd: function() {
50182                 a = null;
50183             },
50184             point: function(x, y) {
50185                 b = [x, y];
50186
50187                 if (a) {
50188                     var span = geoEuclideanDistance(a, b) - offset;
50189
50190                     if (span >= 0) {
50191                         var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
50192                             dx = dt * Math.cos(angle),
50193                             dy = dt * Math.sin(angle),
50194                             p = [a[0] + offset * Math.cos(angle),
50195                                  a[1] + offset * Math.sin(angle)];
50196
50197                         var segment = 'M' + a[0] + ',' + a[1] +
50198                                       'L' + p[0] + ',' + p[1];
50199
50200                         for (span -= dt; span >= 0; span -= dt) {
50201                             p[0] += dx;
50202                             p[1] += dy;
50203                             segment += 'L' + p[0] + ',' + p[1];
50204                         }
50205
50206                         segment += 'L' + b[0] + ',' + b[1];
50207                         segments.push({id: entity.id, index: i, d: segment});
50208                     }
50209
50210                     offset = -span;
50211                     i++;
50212                 }
50213
50214                 a = b;
50215             }
50216         })));
50217
50218         return segments;
50219     };
50220 }
50221
50222 function svgPath(projection$$1, graph, isArea) {
50223
50224     // Explanation of magic numbers:
50225     // "padding" here allows space for strokes to extend beyond the viewport,
50226     // so that the stroke isn't drawn along the edge of the viewport when
50227     // the shape is clipped.
50228     //
50229     // When drawing lines, pad viewport by 5px.
50230     // When drawing areas, pad viewport by 65px in each direction to allow
50231     // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
50232
50233     var cache = {},
50234         padding = isArea ? 65 : 5,
50235         viewport = projection$$1.clipExtent(),
50236         paddedExtent = [
50237             [viewport[0][0] - padding, viewport[0][1] - padding],
50238             [viewport[1][0] + padding, viewport[1][1] + padding]
50239         ],
50240         clip = identity$5().clipExtent(paddedExtent).stream,
50241         project = projection$$1.stream,
50242         path$$1 = index$4()
50243             .projection({stream: function(output) { return project(clip(output)); }});
50244
50245     return function(entity) {
50246         if (entity.id in cache) {
50247             return cache[entity.id];
50248         } else {
50249             return cache[entity.id] = path$$1(entity.asGeoJSON(graph));
50250         }
50251     };
50252 }
50253
50254 function svgPoints$$1(projection, context) {
50255
50256     function markerPath(selection, klass) {
50257         selection
50258             .attr('class', klass)
50259             .attr('transform', 'translate(-8, -23)')
50260             .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');
50261     }
50262
50263     function sortY(a, b) {
50264         return b.loc[1] - a.loc[1];
50265     }
50266
50267
50268     return function drawPoints(selection, graph, entities, filter) {
50269         var wireframe = context.surface().classed('fill-wireframe'),
50270             points = wireframe ? [] : lodash.filter(entities, function(e) {
50271                 return e.geometry(graph) === 'point';
50272             });
50273
50274         points.sort(sortY);
50275
50276         var layer = selection.selectAll('.layer-hit');
50277
50278         var groups = layer.selectAll('g.point')
50279             .filter(filter)
50280             .data(points, osmEntity$$1.key);
50281
50282         groups.exit()
50283             .remove();
50284
50285         var enter = groups.enter()
50286             .append('g')
50287             .attr('class', function(d) { return 'node point ' + d.id; })
50288             .order();
50289
50290         enter.append('path')
50291             .call(markerPath, 'shadow');
50292
50293         enter.append('ellipse')
50294             .attr('cx', 0.5)
50295             .attr('cy', 1)
50296             .attr('rx', 6.5)
50297             .attr('ry', 3)
50298             .attr('class', 'stroke');
50299
50300         enter.append('path')
50301             .call(markerPath, 'stroke');
50302
50303         enter.append('use')
50304             .attr('transform', 'translate(-5, -19)')
50305             .attr('class', 'icon')
50306             .attr('width', '11px')
50307             .attr('height', '11px');
50308
50309         groups = groups
50310             .merge(enter)
50311             .attr('transform', svgPointTransform(projection))
50312             .call(svgTagClasses());
50313
50314         // Selecting the following implicitly
50315         // sets the data (point entity) on the element
50316         groups.select('.shadow');
50317         groups.select('.stroke');
50318         groups.select('.icon')
50319             .attr('xlink:href', function(entity) {
50320                 var preset = context.presets().match(entity, graph),
50321                     picon = preset && preset.icon;
50322
50323                 if (!picon)
50324                     return '';
50325                 else {
50326                     var isMaki = dataFeatureIcons.indexOf(picon) !== -1;
50327                     return '#' + picon + (isMaki ? '-11' : '');
50328                 }
50329             });
50330     };
50331 }
50332
50333 function svgRelationMemberTags(graph) {
50334     return function(entity) {
50335         var tags = entity.tags;
50336         graph.parentRelations(entity).forEach(function(relation) {
50337             var type = relation.tags.type;
50338             if (type === 'multipolygon' || type === 'boundary') {
50339                 tags = lodash.extend({}, relation.tags, tags);
50340             }
50341         });
50342         return tags;
50343     };
50344 }
50345
50346 function svgTagClasses() {
50347     var primaries = [
50348             'building', 'highway', 'railway', 'waterway', 'aeroway',
50349             'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
50350             'leisure', 'military', 'place'
50351         ],
50352         statuses = [
50353             'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
50354             'razed', 'demolished', 'obliterated'
50355         ],
50356         secondaries = [
50357             'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
50358             'surface', 'tracktype', 'crossing'
50359         ],
50360         tagClassRe = /^tag-/,
50361         tags = function(entity) { return entity.tags; };
50362
50363
50364     var tagClasses = function(selection$$1) {
50365         selection$$1.each(function tagClassesEach(entity) {
50366             var value = this.className,
50367                 classes, primary, status;
50368
50369             if (value.baseVal !== undefined) value = value.baseVal;
50370
50371             classes = value.trim().split(/\s+/).filter(function(name) {
50372                 return name.length && !tagClassRe.test(name);
50373             }).join(' ');
50374
50375             var t = tags(entity), i, k, v;
50376
50377             // pick at most one primary classification tag..
50378             for (i = 0; i < primaries.length; i++) {
50379                 k = primaries[i];
50380                 v = t[k];
50381                 if (!v || v === 'no') continue;
50382
50383                 primary = k;
50384                 if (statuses.indexOf(v) !== -1) {   // e.g. `railway=abandoned`
50385                     status = v;
50386                     classes += ' tag-' + k;
50387                 } else {
50388                     classes += ' tag-' + k + ' tag-' + k + '-' + v;
50389                 }
50390
50391                 break;
50392             }
50393
50394             // add at most one status tag, only if relates to primary tag..
50395             if (!status) {
50396                 for (i = 0; i < statuses.length; i++) {
50397                     k = statuses[i];
50398                     v = t[k];
50399                     if (!v || v === 'no') continue;
50400
50401                     if (v === 'yes') {   // e.g. `railway=rail + abandoned=yes`
50402                         status = k;
50403                     }
50404                     else if (primary && primary === v) {  // e.g. `railway=rail + abandoned=railway`
50405                         status = k;
50406                     } else if (!primary && primaries.indexOf(v) !== -1) {  // e.g. `abandoned=railway`
50407                         status = k;
50408                         primary = v;
50409                         classes += ' tag-' + v;
50410                     }  // else ignore e.g.  `highway=path + abandoned=railway`
50411
50412                     if (status) break;
50413                 }
50414             }
50415
50416             if (status) {
50417                 classes += ' tag-status tag-status-' + status;
50418             }
50419
50420             // add any secondary (structure) tags
50421             for (i = 0; i < secondaries.length; i++) {
50422                 k = secondaries[i];
50423                 v = t[k];
50424                 if (!v || v === 'no') continue;
50425                 classes += ' tag-' + k + ' tag-' + k + '-' + v;
50426             }
50427
50428             // For highways, look for surface tagging..
50429             if (primary === 'highway') {
50430                 var paved = (t.highway !== 'track');
50431                 for (k in t) {
50432                     v = t[k];
50433                     if (k in osmPavedTags) {
50434                         paved = !!osmPavedTags[k][v];
50435                         break;
50436                     }
50437                 }
50438                 if (!paved) {
50439                     classes += ' tag-unpaved';
50440                 }
50441             }
50442
50443             classes = classes.trim();
50444
50445             if (classes !== value) {
50446                 select(this).attr('class', classes);
50447             }
50448         });
50449     };
50450
50451
50452     tagClasses.tags = function(_) {
50453         if (!arguments.length) return tags;
50454         tags = _;
50455         return tagClasses;
50456     };
50457
50458     return tagClasses;
50459 }
50460
50461 function svgTurns(projection) {
50462
50463     return function drawTurns(selection, graph, turns) {
50464
50465         function key(turn) {
50466             return [turn.from.node + turn.via.node + turn.to.node].join('-');
50467         }
50468
50469         function icon(turn) {
50470             var u = turn.u ? '-u' : '';
50471             if (!turn.restriction)
50472                 return '#turn-yes' + u;
50473             var restriction = graph.entity(turn.restriction).tags.restriction;
50474             return '#turn-' +
50475                 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
50476         }
50477
50478         var groups = selection.selectAll('.layer-hit').selectAll('g.turn')
50479             .data(turns, key);
50480
50481         groups.exit()
50482             .remove();
50483
50484
50485         var enter = groups.enter()
50486             .append('g')
50487             .attr('class', 'turn');
50488
50489         var nEnter = enter
50490             .filter(function (turn) { return !turn.u; });
50491
50492         nEnter.append('rect')
50493             .attr('transform', 'translate(-22, -12)')
50494             .attr('width', '44')
50495             .attr('height', '24');
50496
50497         nEnter.append('use')
50498             .attr('transform', 'translate(-22, -12)')
50499             .attr('width', '44')
50500             .attr('height', '24');
50501
50502
50503         var uEnter = enter
50504             .filter(function (turn) { return turn.u; });
50505
50506         uEnter.append('circle')
50507             .attr('r', '16');
50508
50509         uEnter.append('use')
50510             .attr('transform', 'translate(-16, -16)')
50511             .attr('width', '32')
50512             .attr('height', '32');
50513
50514
50515         groups = groups
50516             .merge(enter);
50517
50518         groups
50519             .attr('transform', function (turn) {
50520                 var v = graph.entity(turn.via.node),
50521                     t = graph.entity(turn.to.node),
50522                     a = geoAngle(v, t, projection),
50523                     p = projection(v.loc),
50524                     r = turn.u ? 0 : 60;
50525
50526                 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
50527                     'rotate(' + a * 180 / Math.PI + ')';
50528             });
50529
50530         groups.select('use')
50531             .attr('xlink:href', icon);
50532
50533         groups.select('rect');
50534         groups.select('circle');
50535
50536         return this;
50537     };
50538 }
50539
50540 function svgVertices$$1(projection$$1, context) {
50541     var radiuses = {
50542         //       z16-, z17, z18+, tagged
50543         shadow: [6,    7.5,   7.5,  11.5],
50544         stroke: [2.5,  3.5,   3.5,  7],
50545         fill:   [1,    1.5,   1.5,  1.5]
50546     };
50547
50548     var hover;
50549
50550
50551     function siblingAndChildVertices(ids, graph, extent$$1) {
50552         var vertices = {};
50553
50554         function addChildVertices(entity) {
50555             if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
50556                 var i;
50557                 if (entity.type === 'way') {
50558                     for (i = 0; i < entity.nodes.length; i++) {
50559                         addChildVertices(graph.entity(entity.nodes[i]));
50560                     }
50561                 } else if (entity.type === 'relation') {
50562                     for (i = 0; i < entity.members.length; i++) {
50563                         var member = context.hasEntity(entity.members[i].id);
50564                         if (member) {
50565                             addChildVertices(member);
50566                         }
50567                     }
50568                 } else if (entity.intersects(extent$$1, graph)) {
50569                     vertices[entity.id] = entity;
50570                 }
50571             }
50572         }
50573
50574         ids.forEach(function(id) {
50575             var entity = context.hasEntity(id);
50576             if (entity && entity.type === 'node') {
50577                 vertices[entity.id] = entity;
50578                 context.graph().parentWays(entity).forEach(function(entity) {
50579                     addChildVertices(entity);
50580                 });
50581             } else if (entity) {
50582                 addChildVertices(entity);
50583             }
50584         });
50585
50586         return vertices;
50587     }
50588
50589
50590     function draw(selection$$1, vertices, klass, graph, zoom$$1, siblings$$1) {
50591
50592         function icon(entity) {
50593             if (entity.id in icons) return icons[entity.id];
50594             icons[entity.id] =
50595                 entity.hasInterestingTags() &&
50596                 context.presets().match(entity, graph).icon;
50597             return icons[entity.id];
50598         }
50599
50600         function setClass(klass) {
50601             return function(entity) {
50602                 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
50603             };
50604         }
50605
50606         function setAttributes(selection$$1) {
50607             ['shadow','stroke','fill'].forEach(function(klass) {
50608                 var rads = radiuses[klass];
50609                 selection$$1.selectAll('.' + klass)
50610                     .each(function(entity) {
50611                         var i = z && icon(entity),
50612                             c = i ? 0.5 : 0,
50613                             r = rads[i ? 3 : z];
50614
50615                         // slightly increase the size of unconnected endpoints #3775
50616                         if (entity.isEndpoint(graph) && !entity.isConnected(graph)) {
50617                             r += 1.5;
50618                         }
50619
50620                         this.setAttribute('cx', c);
50621                         this.setAttribute('cy', -c);
50622                         this.setAttribute('r', r);
50623                         if (i && klass === 'fill') {
50624                             this.setAttribute('visibility', 'hidden');
50625                         } else {
50626                             this.removeAttribute('visibility');
50627                         }
50628                     });
50629             });
50630
50631             selection$$1.selectAll('use')
50632                 .each(function() {
50633                     if (z) {
50634                         this.removeAttribute('visibility');
50635                     } else {
50636                         this.setAttribute('visibility', 'hidden');
50637                     }
50638                 });
50639         }
50640
50641
50642         siblings$$1 = siblings$$1 || {};
50643
50644         var icons = {},
50645             z = (zoom$$1 < 17 ? 0 : zoom$$1 < 18 ? 1 : 2);
50646
50647         var groups = selection$$1
50648             .data(vertices, osmEntity$$1.key);
50649
50650         groups.exit()
50651             .remove();
50652
50653         var enter = groups.enter()
50654             .append('g')
50655             .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
50656
50657         enter.append('circle')
50658             .each(setClass('shadow'));
50659
50660         enter.append('circle')
50661             .each(setClass('stroke'));
50662
50663         // Vertices with icons get a `use`.
50664         enter.filter(function(d) { return icon(d); })
50665             .append('use')
50666             .attr('transform', 'translate(-5, -6)')
50667             .attr('xlink:href', function(d) {
50668                 var picon = icon(d),
50669                     isMaki = dataFeatureIcons.indexOf(picon) !== -1;
50670                 return '#' + picon + (isMaki ? '-11' : '');
50671             })
50672             .attr('width', '11px')
50673             .attr('height', '11px')
50674             .each(setClass('icon'));
50675
50676         // Vertices with tags get a fill.
50677         enter.filter(function(d) { return d.hasInterestingTags(); })
50678             .append('circle')
50679             .each(setClass('fill'));
50680
50681         groups
50682             .merge(enter)
50683             .attr('transform', svgPointTransform(projection$$1))
50684             .classed('sibling', function(entity) { return entity.id in siblings$$1; })
50685             .classed('shared', function(entity) { return graph.isShared(entity); })
50686             .classed('endpoint', function(entity) { return entity.isEndpoint(graph); })
50687             .call(setAttributes);
50688     }
50689
50690
50691     function drawVertices(selection$$1, graph, entities, filter, extent$$1, zoom$$1) {
50692         var siblings$$1 = siblingAndChildVertices(context.selectedIDs(), graph, extent$$1),
50693             wireframe = context.surface().classed('fill-wireframe'),
50694             vertices = [];
50695
50696         for (var i = 0; i < entities.length; i++) {
50697             var entity = entities[i],
50698                 geometry = entity.geometry(graph);
50699
50700             if (wireframe && geometry === 'point') {
50701                 vertices.push(entity);
50702                 continue;
50703             }
50704
50705             if (geometry !== 'vertex')
50706                 continue;
50707
50708             if (entity.id in siblings$$1 ||
50709                 entity.hasInterestingTags() ||
50710                 entity.isEndpoint(graph) ||
50711                 entity.isConnected(graph)) {
50712                 vertices.push(entity);
50713             }
50714         }
50715
50716         var layer = selection$$1.selectAll('.layer-hit');
50717         layer.selectAll('g.vertex.vertex-persistent')
50718             .filter(filter)
50719             .call(draw, vertices, 'vertex-persistent', graph, zoom$$1, siblings$$1);
50720
50721         drawHover(selection$$1, graph, extent$$1, zoom$$1);
50722     }
50723
50724
50725     function drawHover(selection$$1, graph, extent$$1, zoom$$1) {
50726         var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent$$1) : {};
50727         var layer = selection$$1.selectAll('.layer-hit');
50728
50729         layer.selectAll('g.vertex.vertex-hover')
50730             .call(draw, values(hovered), 'vertex-hover', graph, zoom$$1);
50731     }
50732
50733
50734     drawVertices.drawHover = function(selection$$1, graph, target, extent$$1, zoom$$1) {
50735         if (target === hover) return;
50736         hover = target;
50737         drawHover(selection$$1, graph, extent$$1, zoom$$1);
50738     };
50739
50740     return drawVertices;
50741 }
50742
50743 function behaviorEdit(context) {
50744
50745     function edit() {
50746         context.map()
50747             .minzoom(context.minEditableZoom());
50748     }
50749
50750
50751     edit.off = function() {
50752         context.map()
50753             .minzoom(0);
50754     };
50755
50756
50757     return edit;
50758 }
50759
50760 /*
50761    The hover behavior adds the `.hover` class on mouseover to all elements to which
50762    the identical datum is bound, and removes it on mouseout.
50763
50764    The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
50765    representation may consist of several elements scattered throughout the DOM hierarchy.
50766    Only one of these elements can have the :hover pseudo-class, but all of them will
50767    have the .hover class.
50768  */
50769 function behaviorHover(context) {
50770     var dispatch$$1 = dispatch('hover'),
50771         _selection = select(null),
50772         newId = null,
50773         buttonDown,
50774         altDisables,
50775         target;
50776
50777
50778     function keydown() {
50779         if (altDisables && event.keyCode === d3keybinding.modifierCodes.alt) {
50780             _selection.selectAll('.hover')
50781                 .classed('hover-suppressed', true)
50782                 .classed('hover', false);
50783
50784             _selection
50785                 .classed('hover-disabled', true);
50786
50787             dispatch$$1.call('hover', this, null);
50788         }
50789     }
50790
50791
50792     function keyup() {
50793         if (altDisables && event.keyCode === d3keybinding.modifierCodes.alt) {
50794             _selection.selectAll('.hover-suppressed')
50795                 .classed('hover-suppressed', false)
50796                 .classed('hover', true);
50797
50798             _selection
50799                 .classed('hover-disabled', false);
50800
50801             dispatch$$1.call('hover', this, target ? target.id : null);
50802         }
50803     }
50804
50805
50806     var hover = function(selection$$1) {
50807         _selection = selection$$1;
50808         newId = null;
50809
50810         _selection
50811             .on('mouseover.hover', mouseover)
50812             .on('mouseout.hover', mouseout)
50813             .on('mousedown.hover', mousedown);
50814
50815         select(window)
50816             .on('keydown.hover', keydown)
50817             .on('keyup.hover', keyup);
50818
50819
50820         function mouseover() {
50821             if (buttonDown) return;
50822             var target = event.target;
50823             enter(target ? target.__data__ : null);
50824         }
50825
50826
50827         function mouseout() {
50828             if (buttonDown) return;
50829             var target = event.relatedTarget;
50830             enter(target ? target.__data__ : null);
50831         }
50832
50833
50834         function mousedown() {
50835             buttonDown = true;
50836             select(window)
50837                 .on('mouseup.hover', mouseup, true);
50838         }
50839
50840
50841         function mouseup() {
50842             buttonDown = false;
50843             select(window)
50844                 .on('mouseup.hover', null, true);
50845         }
50846
50847
50848         function enter(d) {
50849             if (d === target) return;
50850             target = d;
50851
50852             _selection.selectAll('.hover')
50853                 .classed('hover', false);
50854             _selection.selectAll('.hover-suppressed')
50855                 .classed('hover-suppressed', false);
50856
50857             if (target instanceof osmEntity$$1 && target.id !== newId) {
50858
50859                 // If drawing a way, don't hover on a node that was just placed. #3974
50860                 var mode = context.mode() && context.mode().id;
50861                 if ((mode === 'draw-line' || mode === 'draw-area') && !newId && target.type === 'node') {
50862                     newId = target.id;
50863                     return;
50864                 }
50865
50866                 var selector$$1 = '.' + target.id;
50867
50868                 if (target.type === 'relation') {
50869                     target.members.forEach(function(member) {
50870                         selector$$1 += ', .' + member.id;
50871                     });
50872                 }
50873
50874                 var suppressed = altDisables && event && event.altKey;
50875
50876                 _selection.selectAll(selector$$1)
50877                     .classed(suppressed ? 'hover-suppressed' : 'hover', true);
50878
50879                 dispatch$$1.call('hover', this, !suppressed && target.id);
50880
50881             } else {
50882                 dispatch$$1.call('hover', this, null);
50883             }
50884         }
50885
50886     };
50887
50888
50889     hover.off = function(selection$$1) {
50890         selection$$1.selectAll('.hover')
50891             .classed('hover', false);
50892         selection$$1.selectAll('.hover-suppressed')
50893             .classed('hover-suppressed', false);
50894         selection$$1
50895             .classed('hover-disabled', false);
50896
50897
50898         selection$$1
50899             .on('mouseover.hover', null)
50900             .on('mouseout.hover', null)
50901             .on('mousedown.hover', null);
50902
50903         select(window)
50904             .on('keydown.hover', null)
50905             .on('keyup.hover', null);
50906     };
50907
50908
50909     hover.altDisables = function(_) {
50910         if (!arguments.length) return altDisables;
50911         altDisables = _;
50912         return hover;
50913     };
50914
50915
50916     return utilRebind(hover, dispatch$$1, 'on');
50917 }
50918
50919 function behaviorTail() {
50920     var text$$1,
50921         container,
50922         xmargin = 25,
50923         tooltipSize = [0, 0],
50924         selectionSize = [0, 0];
50925
50926
50927     function tail(selection$$1) {
50928         if (!text$$1) return;
50929
50930         select(window)
50931             .on('resize.tail', function() { selectionSize = utilGetDimensions(selection$$1); });
50932
50933         container = select(document.body)
50934             .append('div')
50935             .style('display', 'none')
50936             .attr('class', 'tail tooltip-inner');
50937
50938         container.append('div')
50939             .text(text$$1);
50940
50941         selection$$1
50942             .on('mousemove.tail', mousemove)
50943             .on('mouseenter.tail', mouseenter)
50944             .on('mouseleave.tail', mouseleave);
50945
50946         container
50947             .on('mousemove.tail', mousemove);
50948
50949         tooltipSize = utilGetDimensions(container);
50950         selectionSize = utilGetDimensions(selection$$1);
50951
50952
50953         function show() {
50954             container.style('display', 'block');
50955             tooltipSize = utilGetDimensions(container);
50956         }
50957
50958
50959         function mousemove() {
50960             if (container.style('display') === 'none') show();
50961             var xoffset = ((event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
50962                 -tooltipSize[0] - xmargin : xmargin;
50963             container.classed('left', xoffset > 0);
50964             utilSetTransform(container, event.clientX + xoffset, event.clientY);
50965         }
50966
50967
50968         function mouseleave() {
50969             if (event.relatedTarget !== container.node()) {
50970                 container.style('display', 'none');
50971             }
50972         }
50973
50974
50975         function mouseenter() {
50976             if (event.relatedTarget !== container.node()) {
50977                 show();
50978             }
50979         }
50980     }
50981
50982
50983     tail.off = function(selection$$1) {
50984         if (!text$$1) return;
50985
50986         container
50987             .on('mousemove.tail', null)
50988             .remove();
50989
50990         selection$$1
50991             .on('mousemove.tail', null)
50992             .on('mouseenter.tail', null)
50993             .on('mouseleave.tail', null);
50994
50995         select(window)
50996             .on('resize.tail', null);
50997     };
50998
50999
51000     tail.text = function(_) {
51001         if (!arguments.length) return text$$1;
51002         text$$1 = _;
51003         return tail;
51004     };
51005
51006
51007     return tail;
51008 }
51009
51010 var usedTails = {};
51011 var disableSpace = false;
51012 var lastSpace = null;
51013
51014
51015 function behaviorDraw(context) {
51016     var dispatch$$1 = dispatch('move', 'click', 'clickWay',
51017             'clickNode', 'undo', 'cancel', 'finish'),
51018         keybinding = d3keybinding('draw'),
51019         hover = behaviorHover(context)
51020             .altDisables(true)
51021             .on('hover', context.ui().sidebar.hover),
51022         tail = behaviorTail(),
51023         edit = behaviorEdit(context),
51024         closeTolerance = 4,
51025         tolerance = 12,
51026         mouseLeave = false,
51027         lastMouse = null;
51028
51029
51030     function datum() {
51031         if (event.altKey) return {};
51032
51033         if (event.type === 'keydown') {
51034             return (lastMouse && lastMouse.target.__data__) || {};
51035         } else {
51036             return event.target.__data__ || {};
51037         }
51038     }
51039
51040
51041     function mousedown() {
51042
51043         function point() {
51044             var p = context.container().node();
51045             return touchId !== null ? touches(p).filter(function(p) {
51046                 return p.identifier === touchId;
51047             })[0] : mouse(p);
51048         }
51049
51050         var element = select(this),
51051             touchId = event.touches ? event.changedTouches[0].identifier : null,
51052             t1 = +new Date(),
51053             p1 = point();
51054
51055         element.on('mousemove.draw', null);
51056
51057         select(window).on('mouseup.draw', function() {
51058             var t2 = +new Date(),
51059                 p2 = point(),
51060                 dist = geoEuclideanDistance(p1, p2);
51061
51062             element.on('mousemove.draw', mousemove);
51063             select(window).on('mouseup.draw', null);
51064
51065             if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
51066                 // Prevent a quick second click
51067                 select(window).on('click.draw-block', function() {
51068                     event.stopPropagation();
51069                 }, true);
51070
51071                 context.map().dblclickEnable(false);
51072
51073                 window.setTimeout(function() {
51074                     context.map().dblclickEnable(true);
51075                     select(window).on('click.draw-block', null);
51076                 }, 500);
51077
51078                 click();
51079             }
51080         }, true);
51081     }
51082
51083
51084     function mousemove() {
51085         lastMouse = event;
51086         dispatch$$1.call('move', this, datum());
51087     }
51088
51089
51090     function mouseenter() {
51091         mouseLeave = false;
51092     }
51093
51094
51095     function mouseleave() {
51096         mouseLeave = true;
51097     }
51098
51099
51100     function click() {
51101         var d = datum();
51102         if (d.type === 'way') {
51103             var dims = context.map().dimensions(),
51104                 mouse$$1 = context.mouse(),
51105                 pad = 5,
51106                 trySnap = mouse$$1[0] > pad && mouse$$1[0] < dims[0] - pad &&
51107                     mouse$$1[1] > pad && mouse$$1[1] < dims[1] - pad;
51108
51109             if (trySnap) {
51110                 var choice = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection),
51111                     edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
51112                 dispatch$$1.call('clickWay', this, choice.loc, edge);
51113             } else {
51114                 dispatch$$1.call('click', this, context.map().mouseCoordinates());
51115             }
51116
51117         } else if (d.type === 'node') {
51118             dispatch$$1.call('clickNode', this, d);
51119
51120         } else {
51121             dispatch$$1.call('click', this, context.map().mouseCoordinates());
51122         }
51123     }
51124
51125
51126     function space() {
51127         event.preventDefault();
51128         event.stopPropagation();
51129
51130         var currSpace = context.mouse();
51131         if (disableSpace && lastSpace) {
51132             var dist = geoEuclideanDistance(lastSpace, currSpace);
51133             if (dist > tolerance) {
51134                 disableSpace = false;
51135             }
51136         }
51137
51138         if (disableSpace || mouseLeave || !lastMouse) return;
51139
51140         // user must move mouse or release space bar to allow another click
51141         lastSpace = currSpace;
51142         disableSpace = true;
51143
51144         select(window).on('keyup.space-block', function() {
51145             event.preventDefault();
51146             event.stopPropagation();
51147             disableSpace = false;
51148             select(window).on('keyup.space-block', null);
51149         });
51150
51151         click();
51152     }
51153
51154
51155     function backspace() {
51156         event.preventDefault();
51157         dispatch$$1.call('undo');
51158     }
51159
51160
51161     function del() {
51162         event.preventDefault();
51163         dispatch$$1.call('cancel');
51164     }
51165
51166
51167     function ret() {
51168         event.preventDefault();
51169         dispatch$$1.call('finish');
51170     }
51171
51172
51173     function draw(selection$$1) {
51174         context.install(hover);
51175         context.install(edit);
51176
51177         if (!context.inIntro() && !usedTails[tail.text()]) {
51178             context.install(tail);
51179         }
51180
51181         keybinding
51182             .on('⌫', backspace)
51183             .on('⌦', del)
51184             .on('⎋', ret)
51185             .on('↩', ret)
51186             .on('space', space)
51187             .on('⌥space', space);
51188
51189         selection$$1
51190             .on('mouseenter.draw', mouseenter)
51191             .on('mouseleave.draw', mouseleave)
51192             .on('mousedown.draw', mousedown)
51193             .on('mousemove.draw', mousemove);
51194
51195         select(document)
51196             .call(keybinding);
51197
51198         return draw;
51199     }
51200
51201
51202     draw.off = function(selection$$1) {
51203         context.ui().sidebar.hover.cancel();
51204         context.uninstall(hover);
51205         context.uninstall(edit);
51206
51207         if (!context.inIntro() && !usedTails[tail.text()]) {
51208             context.uninstall(tail);
51209             usedTails[tail.text()] = true;
51210         }
51211
51212         selection$$1
51213             .on('mouseenter.draw', null)
51214             .on('mouseleave.draw', null)
51215             .on('mousedown.draw', null)
51216             .on('mousemove.draw', null);
51217
51218         select(window)
51219             .on('mouseup.draw', null);
51220             // note: keyup.space-block, click.draw-block should remain
51221
51222         select(document)
51223             .call(keybinding.off);
51224     };
51225
51226
51227     draw.tail = function(_) {
51228         tail.text(_);
51229         return draw;
51230     };
51231
51232
51233     return utilRebind(draw, dispatch$$1, 'on');
51234 }
51235
51236 function behaviorAddWay(context) {
51237     var dispatch$$1 = dispatch('start', 'startFromWay', 'startFromNode'),
51238         draw = behaviorDraw(context);
51239
51240     var addWay = function(surface) {
51241         draw.on('click', function() { dispatch$$1.apply('start', this, arguments); })
51242             .on('clickWay', function() { dispatch$$1.apply('startFromWay', this, arguments); })
51243             .on('clickNode', function() { dispatch$$1.apply('startFromNode', this, arguments); })
51244             .on('cancel', addWay.cancel)
51245             .on('finish', addWay.cancel);
51246
51247         context.map()
51248             .dblclickEnable(false);
51249
51250         surface.call(draw);
51251     };
51252
51253
51254     addWay.off = function(surface) {
51255         surface.call(draw.off);
51256     };
51257
51258
51259     addWay.cancel = function() {
51260         window.setTimeout(function() {
51261             context.map().dblclickEnable(true);
51262         }, 1000);
51263
51264         context.enter(modeBrowse(context));
51265     };
51266
51267
51268     addWay.tail = function(text$$1) {
51269         draw.tail(text$$1);
51270         return addWay;
51271     };
51272
51273
51274     return utilRebind(addWay, dispatch$$1, 'on');
51275 }
51276
51277 function behaviorBreathe() {
51278     var duration = 800,
51279         steps = 4,
51280         selector$$1 = '.selected.shadow, .selected .shadow',
51281         selected = select(null),
51282         classed = '',
51283         params = {},
51284         done = false,
51285         timer$$1;
51286
51287
51288     function ratchetyInterpolator(a, b, steps, units) {
51289         a = parseFloat(a);
51290         b = parseFloat(b);
51291         var sample = quantize$1()
51292             .domain([0, 1])
51293             .range(quantize(reinterpolate(a, b), steps));
51294
51295         return function(t) {
51296             return String(sample(t)) + (units || '');
51297         };
51298     }
51299
51300
51301     function reset(selection$$1) {
51302         selection$$1
51303             .style('stroke-opacity', null)
51304             .style('stroke-width', null)
51305             .style('fill-opacity', null)
51306             .style('r', null);
51307     }
51308
51309
51310     function setAnimationParams(transition$$1, fromTo) {
51311         var toFrom = (fromTo === 'from' ? 'to' : 'from');
51312
51313         transition$$1
51314             .styleTween('stroke-opacity', function(d) {
51315                 return ratchetyInterpolator(
51316                     params[d.id][toFrom].opacity,
51317                     params[d.id][fromTo].opacity,
51318                     steps
51319                 );
51320             })
51321             .styleTween('stroke-width', function(d) {
51322                 return ratchetyInterpolator(
51323                     params[d.id][toFrom].width,
51324                     params[d.id][fromTo].width,
51325                     steps,
51326                     'px'
51327                 );
51328             })
51329             .styleTween('fill-opacity', function(d) {
51330                 return ratchetyInterpolator(
51331                     params[d.id][toFrom].opacity,
51332                     params[d.id][fromTo].opacity,
51333                     steps
51334                 );
51335             })
51336             .styleTween('r', function(d) {
51337                 return ratchetyInterpolator(
51338                     params[d.id][toFrom].width,
51339                     params[d.id][fromTo].width,
51340                     steps,
51341                     'px'
51342                 );
51343             });
51344     }
51345
51346
51347     function calcAnimationParams(selection$$1) {
51348         selection$$1
51349             .call(reset)
51350             .each(function(d) {
51351                 var s = select(this),
51352                     tag = s.node().tagName,
51353                     p = {'from': {}, 'to': {}},
51354                     opacity, width;
51355
51356                 // determine base opacity and width
51357                 if (tag === 'circle') {
51358                     opacity = parseFloat(s.style('fill-opacity') || 0.5);
51359                     width = parseFloat(s.style('r') || 15.5);
51360                 } else {
51361                     opacity = parseFloat(s.style('stroke-opacity') || 0.7);
51362                     width = parseFloat(s.style('stroke-width') || 10);
51363                 }
51364
51365                 // calculate from/to interpolation params..
51366                 p.tag = tag;
51367                 p.from.opacity = opacity * 0.6;
51368                 p.to.opacity = opacity * 1.25;
51369                 p.from.width = width * 0.7;
51370                 p.to.width = width * (tag === 'circle' ? 1.5 : 1);
51371                 params[d.id] = p;
51372             });
51373     }
51374
51375
51376     function run(surface, fromTo) {
51377         var toFrom = (fromTo === 'from' ? 'to' : 'from'),
51378             currSelected = surface.selectAll(selector$$1),
51379             currClassed = surface.attr('class');
51380
51381         if (done || currSelected.empty()) {
51382             selected.call(reset);
51383             return;
51384         }
51385
51386         if (!lodash.isEqual(currSelected.data(), selected.data()) || currClassed !== classed) {
51387             selected.call(reset);
51388             classed = currClassed;
51389             selected = currSelected.call(calcAnimationParams);
51390         }
51391
51392         selected
51393             .transition()
51394             .duration(duration)
51395             .call(setAnimationParams, fromTo)
51396             .on('end', function() {
51397                 surface.call(run, toFrom);
51398             });
51399     }
51400
51401
51402     var breathe = function(surface) {
51403         done = false;
51404         timer$$1 = timer(function() {
51405             // wait for elements to actually become selected
51406             if (surface.selectAll(selector$$1).empty()) {
51407                 return false;
51408             }
51409
51410             surface.call(run, 'from');
51411             timer$$1.stop();
51412             return true;
51413         }, 20);
51414     };
51415
51416
51417     breathe.off = function() {
51418         done = true;
51419         if (timer$$1) {
51420             timer$$1.stop();
51421         }
51422         selected
51423             .interrupt()
51424             .call(reset);
51425     };
51426
51427
51428     return breathe;
51429 }
51430
51431 function behaviorCopy(context) {
51432     var keybinding = d3keybinding('copy');
51433
51434
51435     function groupEntities(ids, graph) {
51436         var entities = ids.map(function (id) { return graph.entity(id); });
51437         return lodash.extend({relation: [], way: [], node: []},
51438             lodash.groupBy(entities, function(entity) { return entity.type; }));
51439     }
51440
51441
51442     function getDescendants(id, graph, descendants) {
51443         var entity = graph.entity(id),
51444             i, children;
51445
51446         descendants = descendants || {};
51447
51448         if (entity.type === 'relation') {
51449             children = lodash.map(entity.members, 'id');
51450         } else if (entity.type === 'way') {
51451             children = entity.nodes;
51452         } else {
51453             children = [];
51454         }
51455
51456         for (i = 0; i < children.length; i++) {
51457             if (!descendants[children[i]]) {
51458                 descendants[children[i]] = true;
51459                 descendants = getDescendants(children[i], graph, descendants);
51460             }
51461         }
51462
51463         return descendants;
51464     }
51465
51466
51467     function doCopy() {
51468         event.preventDefault();
51469
51470         var graph = context.graph(),
51471             selected = groupEntities(context.selectedIDs(), graph),
51472             canCopy = [],
51473             skip = {},
51474             i, entity;
51475
51476         for (i = 0; i < selected.relation.length; i++) {
51477             entity = selected.relation[i];
51478             if (!skip[entity.id] && entity.isComplete(graph)) {
51479                 canCopy.push(entity.id);
51480                 skip = getDescendants(entity.id, graph, skip);
51481             }
51482         }
51483         for (i = 0; i < selected.way.length; i++) {
51484             entity = selected.way[i];
51485             if (!skip[entity.id]) {
51486                 canCopy.push(entity.id);
51487                 skip = getDescendants(entity.id, graph, skip);
51488             }
51489         }
51490         for (i = 0; i < selected.node.length; i++) {
51491             entity = selected.node[i];
51492             if (!skip[entity.id]) {
51493                 canCopy.push(entity.id);
51494             }
51495         }
51496
51497         context.copyIDs(canCopy);
51498     }
51499
51500
51501     function copy() {
51502         keybinding.on(uiCmd('⌘C'), doCopy);
51503         select(document).call(keybinding);
51504         return copy;
51505     }
51506
51507
51508     copy.off = function() {
51509         select(document).call(keybinding.off);
51510     };
51511
51512
51513     return copy;
51514 }
51515
51516 /*
51517     `behaviorDrag` is like `d3.behavior.drag`, with the following differences:
51518
51519     * The `origin` function is expected to return an [x, y] tuple rather than an
51520       {x, y} object.
51521     * The events are `start`, `move`, and `end`.
51522       (https://github.com/mbostock/d3/issues/563)
51523     * The `start` event is not dispatched until the first cursor movement occurs.
51524       (https://github.com/mbostock/d3/pull/368)
51525     * The `move` event has a `point` and `delta` [x, y] tuple properties rather
51526       than `x`, `y`, `dx`, and `dy` properties.
51527     * The `end` event is not dispatched if no movement occurs.
51528     * An `off` function is available that unbinds the drag's internal event handlers.
51529  */
51530
51531 function behaviorDrag() {
51532     var event$$1 = dispatch('start', 'move', 'end'),
51533         origin = null,
51534         selector$$1 = '',
51535         filter = null,
51536         event_, target, surface;
51537
51538
51539     var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect'),
51540         d3_event_userSelectSuppress = function() {
51541             var selection$$1 = selection(),
51542                 select$$1 = selection$$1.style(d3_event_userSelectProperty);
51543             selection$$1.style(d3_event_userSelectProperty, 'none');
51544             return function() {
51545                 selection$$1.style(d3_event_userSelectProperty, select$$1);
51546             };
51547         };
51548
51549
51550     function d3_eventCancel() {
51551         event.stopPropagation();
51552         event.preventDefault();
51553     }
51554
51555
51556     function eventOf(thiz, argumentz) {
51557         return function(e1) {
51558             e1.target = drag$$1;
51559             customEvent(e1, event$$1.apply, event$$1, [e1.type, thiz, argumentz]);
51560         };
51561     }
51562
51563
51564     function dragstart() {
51565         target = this;
51566         event_ = eventOf(target, arguments);
51567
51568         var eventTarget = event.target,
51569             touchId = event.touches ? event.changedTouches[0].identifier : null,
51570             offset,
51571             origin_ = point(),
51572             started = false,
51573             selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
51574
51575         select(window)
51576             .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
51577             .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
51578
51579         if (origin) {
51580             offset = origin.apply(target, arguments);
51581             offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
51582         } else {
51583             offset = [0, 0];
51584         }
51585
51586         if (touchId === null) {
51587             event.stopPropagation();
51588         }
51589
51590
51591         function point() {
51592             var p = surface || target.parentNode;
51593             return touchId !== null ? touches(p).filter(function(p) {
51594                 return p.identifier === touchId;
51595             })[0] : mouse(p);
51596         }
51597
51598
51599         function dragmove() {
51600             var p = point(),
51601                 dx = p[0] - origin_[0],
51602                 dy = p[1] - origin_[1];
51603
51604             if (dx === 0 && dy === 0)
51605                 return;
51606
51607             if (!started) {
51608                 started = true;
51609                 event_({ type: 'start' });
51610             }
51611
51612             origin_ = p;
51613             d3_eventCancel();
51614
51615             event_({
51616                 type: 'move',
51617                 point: [p[0] + offset[0],  p[1] + offset[1]],
51618                 delta: [dx, dy]
51619             });
51620         }
51621
51622
51623         function dragend() {
51624             if (started) {
51625                 event_({ type: 'end' });
51626
51627                 d3_eventCancel();
51628                 if (event.target === eventTarget) {
51629                     select(window)
51630                         .on('click.drag', click, true);
51631                 }
51632             }
51633
51634             select(window)
51635                 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
51636                 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
51637
51638             selectEnable();
51639         }
51640
51641
51642         function click() {
51643             d3_eventCancel();
51644             select(window)
51645                 .on('click.drag', null);
51646         }
51647     }
51648
51649
51650     function drag$$1(selection$$1) {
51651         var matchesSelector = utilPrefixDOMProperty('matchesSelector'),
51652             delegate = dragstart;
51653
51654         if (selector$$1) {
51655             delegate = function() {
51656                 var root = this,
51657                     target = event.target;
51658                 for (; target && target !== root; target = target.parentNode) {
51659                     if (target[matchesSelector](selector$$1) &&
51660                             (!filter || filter(target.__data__))) {
51661                         return dragstart.call(target, target.__data__);
51662                     }
51663                 }
51664             };
51665         }
51666
51667         selection$$1
51668             .on('mousedown.drag' + selector$$1, delegate)
51669             .on('touchstart.drag' + selector$$1, delegate);
51670     }
51671
51672
51673     drag$$1.off = function(selection$$1) {
51674         selection$$1
51675             .on('mousedown.drag' + selector$$1, null)
51676             .on('touchstart.drag' + selector$$1, null);
51677     };
51678
51679
51680     drag$$1.selector = function(_) {
51681         if (!arguments.length) return selector$$1;
51682         selector$$1 = _;
51683         return drag$$1;
51684     };
51685
51686
51687     drag$$1.filter = function(_) {
51688         if (!arguments.length) return origin;
51689         filter = _;
51690         return drag$$1;
51691     };
51692
51693
51694     drag$$1.origin = function (_) {
51695         if (!arguments.length) return origin;
51696         origin = _;
51697         return drag$$1;
51698     };
51699
51700
51701     drag$$1.cancel = function() {
51702         select(window)
51703             .on('mousemove.drag', null)
51704             .on('mouseup.drag', null);
51705         return drag$$1;
51706     };
51707
51708
51709     drag$$1.target = function() {
51710         if (!arguments.length) return target;
51711         target = arguments[0];
51712         event_ = eventOf(target, Array.prototype.slice.call(arguments, 1));
51713         return drag$$1;
51714     };
51715
51716
51717     drag$$1.surface = function() {
51718         if (!arguments.length) return surface;
51719         surface = arguments[0];
51720         return drag$$1;
51721     };
51722
51723
51724     return utilRebind(drag$$1, event$$1, 'on');
51725 }
51726
51727 function behaviorDrawWay(context, wayId, index, mode, startGraph) {
51728
51729     var origWay = context.entity(wayId),
51730         isArea = context.geometry(wayId) === 'area',
51731         tempEdits = 0,
51732         annotation = t((origWay.isDegenerate() ?
51733             'operations.start.annotation.' :
51734             'operations.continue.annotation.') + context.geometry(wayId)),
51735         draw = behaviorDraw(context),
51736         startIndex,
51737         start,
51738         end,
51739         segment;
51740
51741
51742     // initialize the temporary drawing entities
51743     if (!isArea) {
51744         startIndex = typeof index === 'undefined' ? origWay.nodes.length - 1 : 0;
51745         start = osmNode({ id: 'nStart', loc: context.entity(origWay.nodes[startIndex]).loc });
51746         end = osmNode({ id: 'nEnd', loc: context.map().mouseCoordinates() });
51747         segment = osmWay({ id: 'wTemp',
51748             nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
51749             tags: lodash.clone(origWay.tags)
51750         });
51751     } else {
51752         end = osmNode({ loc: context.map().mouseCoordinates() });
51753     }
51754
51755     // Push an annotated state for undo to return back to.
51756     // We must make sure to remove this edit later.
51757     context.perform(actionNoop(), annotation);
51758     tempEdits++;
51759
51760     // Add the temporary drawing entities to the graph.
51761     // We must make sure to remove this edit later.
51762     context.perform(AddDrawEntities());
51763     tempEdits++;
51764
51765
51766     function move(datum) {
51767         var loc;
51768
51769         if (datum.type === 'node' && datum.id !== end.id) {
51770             loc = datum.loc;
51771
51772         } else if (datum.type === 'way') {
51773             var dims = context.map().dimensions(),
51774                 mouse = context.mouse(),
51775                 pad = 5,
51776                 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
51777                     mouse[1] > pad && mouse[1] < dims[1] - pad;
51778
51779             if (trySnap) {
51780                 loc = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
51781             }
51782         }
51783
51784         if (!loc) {
51785             loc = context.map().mouseCoordinates();
51786         }
51787
51788         context.replace(actionMoveNode(end.id, loc));
51789         end = context.entity(end.id);
51790     }
51791
51792
51793     function undone() {
51794         // Undo popped the history back to the initial annotated no-op edit.
51795         // Remove initial no-op edit and whatever edit happened immediately before it.
51796         context.pop(2);
51797         tempEdits = 0;
51798
51799         if (context.hasEntity(wayId)) {
51800             context.enter(mode);
51801         } else {
51802             context.enter(modeBrowse(context));
51803         }
51804     }
51805
51806
51807     function setActiveElements() {
51808         var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
51809         context.surface().selectAll(utilEntitySelector(active))
51810             .classed('active', true);
51811     }
51812
51813
51814     var drawWay = function(surface) {
51815         draw.on('move', move)
51816             .on('click', drawWay.add)
51817             .on('clickWay', drawWay.addWay)
51818             .on('clickNode', drawWay.addNode)
51819             .on('undo', context.undo)
51820             .on('cancel', drawWay.cancel)
51821             .on('finish', drawWay.finish);
51822
51823         context.map()
51824             .dblclickEnable(false)
51825             .on('drawn.draw', setActiveElements);
51826
51827         setActiveElements();
51828
51829         surface.call(draw);
51830
51831         context.history()
51832             .on('undone.draw', undone);
51833     };
51834
51835
51836     drawWay.off = function(surface) {
51837         // Drawing was interrupted unexpectedly.
51838         // This can happen if the user changes modes,
51839         // clicks geolocate button, a hashchange event occurs, etc.
51840         if (tempEdits) {
51841             context.pop(tempEdits);
51842             while (context.graph() !== startGraph) {
51843                 context.pop();
51844             }
51845         }
51846
51847         context.map()
51848             .on('drawn.draw', null);
51849
51850         surface.call(draw.off)
51851             .selectAll('.active')
51852             .classed('active', false);
51853
51854         context.history()
51855             .on('undone.draw', null);
51856     };
51857
51858
51859     function AddDrawEntities() {
51860         return function(graph) {
51861             if (isArea) {
51862                 // For area drawing, there is no need for a temporary node.
51863                 // `end` gets inserted into the way as the penultimate node.
51864                 return graph
51865                     .replace(end)
51866                     .replace(origWay.addNode(end.id));
51867             } else {
51868                 // For line drawing, add a temporary start, end, and segment to the graph.
51869                 // This allows us to class the new segment as `active`, but still
51870                 // connect it back to parts of the way that have already been drawn.
51871                 return graph
51872                     .replace(start)
51873                     .replace(end)
51874                     .replace(segment);
51875             }
51876         };
51877     }
51878
51879
51880     function ReplaceDrawEntities(newNode) {
51881         return function(graph) {
51882             if (isArea) {
51883                 // For area drawing, we didn't create a temporary node.
51884                 // `newNode` gets inserted into the _original_ way as the penultimate node.
51885                 return graph
51886                     .replace(origWay.addNode(newNode.id))
51887                     .remove(end);
51888             } else {
51889                 // For line drawing, add the `newNode` to the way at specified index,
51890                 // and remove the temporary start, end, and segment.
51891                 return graph
51892                     .replace(origWay.addNode(newNode.id, index))
51893                     .remove(end)
51894                     .remove(segment)
51895                     .remove(start);
51896             }
51897         };
51898     }
51899
51900
51901     // Accept the current position of the temporary node and continue drawing.
51902     drawWay.add = function(loc) {
51903         // prevent duplicate nodes
51904         var last = context.hasEntity(origWay.nodes[origWay.nodes.length - (isArea ? 2 : 1)]);
51905         if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
51906
51907         context.pop(tempEdits);
51908
51909         if (isArea) {
51910             context.perform(
51911                 AddDrawEntities(),
51912                 annotation
51913             );
51914         } else {
51915             var newNode = osmNode({loc: loc});
51916             context.perform(
51917                 actionAddEntity(newNode),
51918                 ReplaceDrawEntities(newNode),
51919                 annotation
51920             );
51921         }
51922
51923         tempEdits = 0;
51924         context.enter(mode);
51925     };
51926
51927
51928     // Connect the way to an existing way.
51929     drawWay.addWay = function(loc, edge) {
51930         if (isArea) {
51931             context.pop(tempEdits);
51932
51933             context.perform(
51934                 AddDrawEntities(),
51935                 actionAddMidpoint({ loc: loc, edge: edge}, end),
51936                 annotation
51937             );
51938         } else {
51939             var previousEdge = startIndex ?
51940                 [origWay.nodes[startIndex], origWay.nodes[startIndex - 1]] :
51941                 [origWay.nodes[0], origWay.nodes[1]];
51942
51943             // Avoid creating duplicate segments
51944             if (geoEdgeEqual(edge, previousEdge))
51945                 return;
51946
51947             context.pop(tempEdits);
51948
51949             var newNode = osmNode({ loc: loc });
51950             context.perform(
51951                 actionAddMidpoint({ loc: loc, edge: edge}, newNode),
51952                 ReplaceDrawEntities(newNode),
51953                 annotation
51954             );
51955         }
51956
51957         tempEdits = 0;
51958         context.enter(mode);
51959     };
51960
51961
51962     // Connect the way to an existing node and continue drawing.
51963     drawWay.addNode = function(node) {
51964         // Avoid creating duplicate segments
51965         if (origWay.areAdjacent(node.id, origWay.nodes[origWay.nodes.length - 1])) return;
51966
51967         // Clicks should not occur on the drawing node, however a space keypress can
51968         // sometimes grab that node's datum (before it gets classed as `active`?)  #4016
51969         if (node.id === end.id) {
51970             drawWay.add(node.loc);
51971             return;
51972         }
51973
51974         context.pop(tempEdits);
51975
51976         context.perform(
51977             ReplaceDrawEntities(node),
51978             annotation
51979         );
51980
51981         tempEdits = 0;
51982         context.enter(mode);
51983     };
51984
51985
51986     // Finish the draw operation, removing the temporary edits.
51987     // If the way has enough nodes to be valid, it's selected.
51988     // Otherwise, delete everything and return to browse mode.
51989     drawWay.finish = function() {
51990         context.pop(tempEdits);
51991         tempEdits = 0;
51992
51993         var way = context.hasEntity(wayId);
51994         if (!way || way.isDegenerate()) {
51995             drawWay.cancel();
51996             return;
51997         }
51998
51999         window.setTimeout(function() {
52000             context.map().dblclickEnable(true);
52001         }, 1000);
52002
52003         context.enter(modeSelect(context, [wayId]).newFeature(true));
52004     };
52005
52006
52007     // Cancel the draw operation, delete everything, and return to browse mode.
52008     drawWay.cancel = function() {
52009         context.pop(tempEdits);
52010         tempEdits = 0;
52011
52012         while (context.graph() !== startGraph) {
52013             context.pop();
52014         }
52015
52016         window.setTimeout(function() {
52017             context.map().dblclickEnable(true);
52018         }, 1000);
52019
52020         context.enter(modeBrowse(context));
52021     };
52022
52023
52024     drawWay.tail = function(text) {
52025         draw.tail(text);
52026         return drawWay;
52027     };
52028
52029
52030     return drawWay;
52031 }
52032
52033 function behaviorHash(context) {
52034     var s0 = null, // cached window.location.hash
52035         lat = 90 - 1e-8; // allowable latitude range
52036
52037
52038     var parser = function(map, s) {
52039         var q = utilStringQs(s);
52040         var args = (q.map || '').split('/').map(Number);
52041
52042         if (args.length < 3 || args.some(isNaN)) {
52043             return true; // replace bogus hash
52044
52045         } else if (s !== formatter(map).slice(1)) {   // hash has changed
52046             var mode = context.mode(),
52047                 dist = geoSphericalDistance(map.center(), [args[2], args[1]]),
52048                 maxdist = 500;
52049
52050             // Don't allow the hash location to change too much while drawing
52051             // This can happen if the user accidently hit the back button.  #3996
52052             if (mode && mode.id.match(/^draw/) !== null && dist > maxdist) {
52053                 context.enter(modeBrowse(context));
52054             }
52055
52056             map.centerZoom([args[2], Math.min(lat, Math.max(-lat, args[1]))], args[0]);
52057         }
52058     };
52059
52060
52061     var formatter = function(map) {
52062         var center = map.center(),
52063             zoom$$1 = map.zoom(),
52064             precision = Math.max(0, Math.ceil(Math.log(zoom$$1) / Math.LN2)),
52065             q = lodash.omit(utilStringQs(window.location.hash.substring(1)), ['comment', 'walkthrough']),
52066             newParams = {};
52067
52068         delete q.id;
52069         var selected = context.selectedIDs().filter(function(id) {
52070             return !context.entity(id).isNew();
52071         });
52072         if (selected.length) {
52073             newParams.id = selected.join(',');
52074         }
52075
52076         newParams.map = zoom$$1.toFixed(2) +
52077             '/' + center[1].toFixed(precision) +
52078             '/' + center[0].toFixed(precision);
52079
52080         return '#' + utilQsString(lodash.assign(q, newParams), true);
52081     };
52082
52083
52084     function update() {
52085         if (context.inIntro()) return;
52086         var s1 = formatter(context.map());
52087         if (s0 !== s1) {
52088             window.location.replace(s0 = s1);  // don't recenter the map!
52089         }
52090     }
52091
52092
52093     var throttledUpdate = lodash.throttle(update, 500);
52094
52095
52096     function hashchange() {
52097         if (window.location.hash === s0) return;  // ignore spurious hashchange events
52098         if (parser(context.map(), (s0 = window.location.hash).substring(1))) {
52099             update(); // replace bogus hash
52100         }
52101     }
52102
52103
52104     function hash() {
52105         context.map()
52106             .on('move.hash', throttledUpdate);
52107
52108         context
52109             .on('enter.hash', throttledUpdate);
52110
52111         select(window)
52112             .on('hashchange.hash', hashchange);
52113
52114         if (window.location.hash) {
52115
52116             var q = utilStringQs(window.location.hash.substring(1));
52117
52118             if (q.id) {
52119                 context.zoomToEntity(q.id.split(',')[0], !q.map);
52120             }
52121
52122             if (q.comment) {
52123                 context.storage('comment', q.comment);
52124                 context.storage('commentDate', Date.now());
52125             }
52126
52127             if (q.walkthrough) {
52128                 hash.startWalkthrough = true;
52129             }
52130
52131             hashchange();
52132
52133             if (q.map) {
52134                 hash.hadHash = true;
52135             }
52136         }
52137     }
52138
52139
52140     hash.off = function() {
52141         throttledUpdate.cancel();
52142
52143         context.map()
52144             .on('move.hash', null);
52145
52146         context
52147             .on('enter.hash', null);
52148
52149         select(window)
52150             .on('hashchange.hash', null);
52151
52152         window.location.hash = '';
52153     };
52154
52155
52156     return hash;
52157 }
52158
52159 function behaviorLasso(context) {
52160
52161     var behavior = function(selection$$1) {
52162         var lasso;
52163
52164
52165         function mousedown() {
52166             var button = 0;  // left
52167             if (event.button === button && event.shiftKey === true) {
52168                 lasso = null;
52169
52170                 select(window)
52171                     .on('mousemove.lasso', mousemove)
52172                     .on('mouseup.lasso', mouseup);
52173
52174                 event.stopPropagation();
52175             }
52176         }
52177
52178
52179         function mousemove() {
52180             if (!lasso) {
52181                 lasso = uiLasso(context);
52182                 context.surface().call(lasso);
52183             }
52184
52185             lasso.p(context.mouse());
52186         }
52187
52188
52189         function normalize(a, b) {
52190             return [
52191                 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
52192                 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
52193         }
52194
52195
52196         function lassoed() {
52197             if (!lasso) return [];
52198
52199             var graph = context.graph(),
52200                 bounds$$1 = lasso.extent().map(context.projection.invert),
52201                 extent$$1 = geoExtent$$1(normalize(bounds$$1[0], bounds$$1[1]));
52202
52203             return lodash.map(context.intersects(extent$$1).filter(function(entity) {
52204                 return entity.type === 'node' &&
52205                     geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) &&
52206                     !context.features().isHidden(entity, graph, entity.geometry(graph));
52207             }), 'id');
52208         }
52209
52210
52211         function mouseup() {
52212             select(window)
52213                 .on('mousemove.lasso', null)
52214                 .on('mouseup.lasso', null);
52215
52216             if (!lasso) return;
52217
52218             var ids = lassoed();
52219             lasso.close();
52220
52221             if (ids.length) {
52222                 context.enter(modeSelect(context, ids));
52223             }
52224         }
52225
52226         selection$$1
52227             .on('mousedown.lasso', mousedown);
52228     };
52229
52230
52231     behavior.off = function(selection$$1) {
52232         selection$$1.on('mousedown.lasso', null);
52233     };
52234
52235
52236     return behavior;
52237 }
52238
52239 /* Creates a keybinding behavior for an operation */
52240 function behaviorOperation() {
52241     var which, keybinding;
52242
52243
52244     function drawIcon(selection$$1) {
52245         var button = selection$$1
52246             .append('svg')
52247             .attr('class', 'operation-icon')
52248             .append('g')
52249             .attr('class', 'radial-menu-item radial-menu-item-' + which.id)
52250             .attr('transform', 'translate(10,10)')
52251             .classed('disabled', which.disabled());
52252
52253         button
52254             .append('circle')
52255             .attr('r', 9);
52256
52257         button
52258             .append('use')
52259             .attr('transform', 'translate(-7,-7)')
52260             .attr('width', '14')
52261             .attr('height', '14')
52262             .attr('xlink:href', '#operation-' + which.id);
52263
52264         return selection$$1;
52265     }
52266
52267
52268     var behavior = function () {
52269         if (which && which.available()) {
52270             keybinding = d3keybinding('behavior.key.' + which.id);
52271             keybinding.on(which.keys, function() {
52272                 event.preventDefault();
52273                 var disabled = which.disabled();
52274
52275                 if (disabled) {
52276                     uiFlash(3000)
52277                         .html('')
52278                         .call(drawIcon)
52279                         .append('div')
52280                         .attr('class', 'operation-tip')
52281                         .text(which.tooltip);
52282
52283                 } else {
52284                     uiFlash(1500)
52285                         .html('')
52286                         .call(drawIcon)
52287                         .append('div')
52288                         .attr('class', 'operation-tip')
52289                         .text(which.annotation() || which.title);
52290
52291                     which();
52292                 }
52293             });
52294             select(document).call(keybinding);
52295         }
52296         return behavior;
52297     };
52298
52299
52300     behavior.off = function() {
52301         if (keybinding) {
52302             select(document).call(keybinding.off);
52303         }
52304     };
52305
52306
52307     behavior.which = function (_) {
52308         if (!arguments.length) return which;
52309         which = _;
52310         return behavior;
52311     };
52312
52313
52314     return behavior;
52315 }
52316
52317 function behaviorPaste(context) {
52318     var keybinding = d3keybinding('paste');
52319
52320
52321     function doPaste() {
52322         event.preventDefault();
52323
52324         var baseGraph = context.graph(),
52325             mouse$$1 = context.mouse(),
52326             projection$$1 = context.projection,
52327             viewport = geoExtent$$1(projection$$1.clipExtent()).polygon();
52328
52329         if (!geoPointInPolygon(mouse$$1, viewport)) return;
52330
52331         var extent$$1 = geoExtent$$1(),
52332             oldIDs = context.copyIDs(),
52333             oldGraph = context.copyGraph(),
52334             newIDs = [];
52335
52336         if (!oldIDs.length) return;
52337
52338         var action = actionCopyEntities(oldIDs, oldGraph);
52339         context.perform(action);
52340
52341         var copies = action.copies();
52342         var originals = lodash.invert(lodash.mapValues(copies, 'id'));
52343         for (var id in copies) {
52344             var oldEntity = oldGraph.entity(id),
52345                 newEntity = copies[id];
52346
52347             extent$$1._extend(oldEntity.extent(oldGraph));
52348
52349             // Exclude child nodes from newIDs if their parent way was also copied.
52350             var parents = context.graph().parentWays(newEntity),
52351                 parentCopied = false;
52352             for (var i = 0; i < parents.length; i++) {
52353                 if (originals[parents[i].id]) {
52354                     parentCopied = true;
52355                     break;
52356                 }
52357             }
52358
52359             if (!parentCopied) {
52360                 newIDs.push(newEntity.id);
52361             }
52362         }
52363
52364         // Put pasted objects where mouse pointer is..
52365         var center = projection$$1(extent$$1.center()),
52366             delta = [ mouse$$1[0] - center[0], mouse$$1[1] - center[1] ];
52367
52368         context.perform(actionMove(newIDs, delta, projection$$1));
52369         context.enter(modeMove$$1(context, newIDs, baseGraph));
52370     }
52371
52372
52373     function paste() {
52374         keybinding.on(uiCmd('⌘V'), doPaste);
52375         select(document).call(keybinding);
52376         return paste;
52377     }
52378
52379
52380     paste.off = function() {
52381         select(document).call(keybinding.off);
52382     };
52383
52384
52385     return paste;
52386 }
52387
52388 function behaviorSelect(context) {
52389     var lastMouse = null,
52390         suppressMenu = true,
52391         tolerance = 4,
52392         p1 = null;
52393
52394
52395     function point() {
52396         return mouse(context.container().node());
52397     }
52398
52399
52400     function keydown() {
52401         var e = event;
52402         if (e && e.shiftKey) {
52403             context.surface()
52404                 .classed('behavior-multiselect', true);
52405         }
52406
52407         if (e && e.keyCode === 93) {  // context menu
52408             e.preventDefault();
52409             e.stopPropagation();
52410         }
52411     }
52412
52413
52414     function keyup() {
52415         var e = event;
52416         if (!e || !e.shiftKey) {
52417             context.surface()
52418                 .classed('behavior-multiselect', false);
52419         }
52420
52421
52422         if (e && e.keyCode === 93) {  // context menu
52423             e.preventDefault();
52424             e.stopPropagation();
52425             contextmenu();
52426         }
52427     }
52428
52429
52430     function mousedown() {
52431         if (!p1) p1 = point();
52432         select(window)
52433             .on('mouseup.select', mouseup, true);
52434
52435         var isShowAlways = +context.storage('edit-menu-show-always') === 1;
52436         suppressMenu = !isShowAlways;
52437     }
52438
52439
52440     function mousemove() {
52441         if (event) lastMouse = event;
52442     }
52443
52444
52445     function mouseup() {
52446         click();
52447     }
52448
52449
52450     function contextmenu() {
52451         var e = event;
52452         e.preventDefault();
52453         e.stopPropagation();
52454
52455         if (!+e.clientX && !+e.clientY) {
52456             if (lastMouse) {
52457                 e.sourceEvent = lastMouse;
52458             } else {
52459                 return;
52460             }
52461         }
52462
52463         if (!p1) p1 = point();
52464         suppressMenu = false;
52465         click();
52466     }
52467
52468
52469     function click() {
52470         select(window)
52471             .on('mouseup.select', null, true);
52472
52473         if (!p1) return;
52474         var p2 = point(),
52475             dist = geoEuclideanDistance(p1, p2);
52476
52477         p1 = null;
52478         if (dist > tolerance) {
52479             return;
52480         }
52481
52482         var isMultiselect = event.shiftKey || select('#surface .lasso').node(),
52483             isShowAlways = +context.storage('edit-menu-show-always') === 1,
52484             datum = event.target.__data__ || (lastMouse && lastMouse.target.__data__),
52485             mode = context.mode();
52486
52487
52488         if (datum && datum.type === 'midpoint') {
52489             datum = datum.parents[0];
52490         }
52491
52492         if (!(datum instanceof osmEntity$$1)) {
52493             // clicked nothing..
52494             if (!isMultiselect && mode.id !== 'browse') {
52495                 context.enter(modeBrowse(context));
52496             }
52497
52498         } else {
52499             // clicked an entity..
52500             var selectedIDs = context.selectedIDs();
52501
52502             if (!isMultiselect) {
52503                 if (selectedIDs.length > 1 && (!suppressMenu && !isShowAlways)) {
52504                     // multiple things already selected, just show the menu...
52505                     mode.suppressMenu(false).reselect();
52506                 } else {
52507                     // select a single thing..
52508                     context.enter(modeSelect(context, [datum.id]).suppressMenu(suppressMenu));
52509                 }
52510
52511             } else {
52512                 if (selectedIDs.indexOf(datum.id) !== -1) {
52513                     // clicked entity is already in the selectedIDs list..
52514                     if (!suppressMenu && !isShowAlways) {
52515                         // don't deselect clicked entity, just show the menu.
52516                         mode.suppressMenu(false).reselect();
52517                     } else {
52518                         // deselect clicked entity, then reenter select mode or return to browse mode..
52519                         selectedIDs = lodash.without(selectedIDs, datum.id);
52520                         context.enter(selectedIDs.length ? modeSelect(context, selectedIDs) : modeBrowse(context));
52521                     }
52522                 } else {
52523                     // clicked entity is not in the selected list, add it..
52524                     selectedIDs = selectedIDs.concat([datum.id]);
52525                     context.enter(modeSelect(context, selectedIDs).suppressMenu(suppressMenu));
52526                 }
52527             }
52528         }
52529
52530         // reset for next time..
52531         suppressMenu = true;
52532     }
52533
52534
52535     var behavior = function(selection$$1) {
52536         lastMouse = null;
52537         suppressMenu = true;
52538         p1 = null;
52539
52540         select(window)
52541             .on('keydown.select', keydown)
52542             .on('keyup.select', keyup)
52543             .on('contextmenu.select-window', function() {
52544                 // Edge and IE really like to show the contextmenu on the
52545                 // menubar when user presses a keyboard menu button
52546                 // even after we've already preventdefaulted the key event.
52547                 var e = event;
52548                 if (+e.clientX === 0 && +e.clientY === 0) {
52549                     event.preventDefault();
52550                     event.stopPropagation();
52551                 }
52552             });
52553
52554         selection$$1
52555             .on('mousedown.select', mousedown)
52556             .on('mousemove.select', mousemove)
52557             .on('contextmenu.select', contextmenu);
52558
52559         if (event && event.shiftKey) {
52560             context.surface()
52561                 .classed('behavior-multiselect', true);
52562         }
52563     };
52564
52565
52566     behavior.off = function(selection$$1) {
52567         select(window)
52568             .on('keydown.select', null)
52569             .on('keyup.select', null)
52570             .on('contextmenu.select-window', null)
52571             .on('mouseup.select', null, true);
52572
52573         selection$$1
52574             .on('mousedown.select', null)
52575             .on('mousemove.select', null)
52576             .on('contextmenu.select', null);
52577
52578         context.surface()
52579             .classed('behavior-multiselect', false);
52580     };
52581
52582
52583     return behavior;
52584 }
52585
52586 function modeAddArea$$1(context) {
52587     var mode = {
52588         id: 'add-area',
52589         button: 'area',
52590         title: t('modes.add_area.title'),
52591         description: t('modes.add_area.description'),
52592         key: '3'
52593     };
52594
52595     var behavior = behaviorAddWay(context)
52596             .tail(t('modes.add_area.tail'))
52597             .on('start', start)
52598             .on('startFromWay', startFromWay)
52599             .on('startFromNode', startFromNode),
52600         defaultTags = { area: 'yes' };
52601
52602
52603     function actionClose(wayId) {
52604         return function (graph) {
52605             return graph.replace(graph.entity(wayId).close());
52606         };
52607     }
52608
52609
52610     function start(loc) {
52611         var startGraph = context.graph(),
52612             node = osmNode({ loc: loc }),
52613             way = osmWay({ tags: defaultTags });
52614
52615         context.perform(
52616             actionAddEntity(node),
52617             actionAddEntity(way),
52618             actionAddVertex(way.id, node.id),
52619             actionClose(way.id)
52620         );
52621
52622         context.enter(modeDrawArea(context, way.id, startGraph));
52623     }
52624
52625
52626     function startFromWay(loc, edge) {
52627         var startGraph = context.graph(),
52628             node = osmNode({ loc: loc }),
52629             way = osmWay({ tags: defaultTags });
52630
52631         context.perform(
52632             actionAddEntity(node),
52633             actionAddEntity(way),
52634             actionAddVertex(way.id, node.id),
52635             actionClose(way.id),
52636             actionAddMidpoint({ loc: loc, edge: edge }, node)
52637         );
52638
52639         context.enter(modeDrawArea(context, way.id, startGraph));
52640     }
52641
52642
52643     function startFromNode(node) {
52644         var startGraph = context.graph(),
52645             way = osmWay({ tags: defaultTags });
52646
52647         context.perform(
52648             actionAddEntity(way),
52649             actionAddVertex(way.id, node.id),
52650             actionClose(way.id)
52651         );
52652
52653         context.enter(modeDrawArea(context, way.id, startGraph));
52654     }
52655
52656
52657     mode.enter = function() {
52658         context.install(behavior);
52659     };
52660
52661
52662     mode.exit = function() {
52663         context.uninstall(behavior);
52664     };
52665
52666
52667     return mode;
52668 }
52669
52670 function modeAddLine$$1(context) {
52671     var mode = {
52672         id: 'add-line',
52673         button: 'line',
52674         title: t('modes.add_line.title'),
52675         description: t('modes.add_line.description'),
52676         key: '2'
52677     };
52678
52679     var behavior = behaviorAddWay(context)
52680         .tail(t('modes.add_line.tail'))
52681         .on('start', start)
52682         .on('startFromWay', startFromWay)
52683         .on('startFromNode', startFromNode);
52684
52685
52686     function start(loc) {
52687         var startGraph = context.graph(),
52688             node = osmNode({ loc: loc }),
52689             way = osmWay();
52690
52691         context.perform(
52692             actionAddEntity(node),
52693             actionAddEntity(way),
52694             actionAddVertex(way.id, node.id)
52695         );
52696
52697         context.enter(modeDrawLine(context, way.id, startGraph));
52698     }
52699
52700
52701     function startFromWay(loc, edge) {
52702         var startGraph = context.graph(),
52703             node = osmNode({ loc: loc }),
52704             way = osmWay();
52705
52706         context.perform(
52707             actionAddEntity(node),
52708             actionAddEntity(way),
52709             actionAddVertex(way.id, node.id),
52710             actionAddMidpoint({ loc: loc, edge: edge }, node)
52711         );
52712
52713         context.enter(modeDrawLine(context, way.id, startGraph));
52714     }
52715
52716
52717     function startFromNode(node) {
52718         var startGraph = context.graph(),
52719             way = osmWay();
52720
52721         context.perform(
52722             actionAddEntity(way),
52723             actionAddVertex(way.id, node.id)
52724         );
52725
52726         context.enter(modeDrawLine(context, way.id, startGraph));
52727     }
52728
52729
52730     mode.enter = function() {
52731         context.install(behavior);
52732     };
52733
52734
52735     mode.exit = function() {
52736         context.uninstall(behavior);
52737     };
52738
52739     return mode;
52740 }
52741
52742 function modeAddPoint$$1(context) {
52743     var mode = {
52744         id: 'add-point',
52745         button: 'point',
52746         title: t('modes.add_point.title'),
52747         description: t('modes.add_point.description'),
52748         key: '1'
52749     };
52750
52751     var behavior = behaviorDraw(context)
52752         .tail(t('modes.add_point.tail'))
52753         .on('click', add)
52754         .on('clickWay', addWay)
52755         .on('clickNode', addNode)
52756         .on('cancel', cancel)
52757         .on('finish', cancel);
52758
52759
52760     function add(loc) {
52761         var node = osmNode({ loc: loc });
52762
52763         context.perform(
52764             actionAddEntity(node),
52765             t('operations.add.annotation.point')
52766         );
52767
52768         context.enter(
52769             modeSelect(context, [node.id]).newFeature(true)
52770         );
52771     }
52772
52773
52774     function addWay(loc) {
52775         add(loc);
52776     }
52777
52778
52779     function addNode(node) {
52780         add(node.loc);
52781     }
52782
52783
52784     function cancel() {
52785         context.enter(modeBrowse(context));
52786     }
52787
52788
52789     mode.enter = function() {
52790         context.install(behavior);
52791     };
52792
52793
52794     mode.exit = function() {
52795         context.uninstall(behavior);
52796     };
52797
52798
52799     return mode;
52800 }
52801
52802 function modeDragNode$$1(context) {
52803     var mode = {
52804         id: 'drag-node',
52805         button: 'browse'
52806     };
52807
52808     var nudgeInterval,
52809         activeIDs,
52810         wasMidpoint,
52811         isCancelled,
52812         lastLoc,
52813         selectedIDs = [],
52814         hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover),
52815         edit = behaviorEdit(context);
52816
52817
52818     function vecSub(a, b) {
52819         return [a[0] - b[0], a[1] - b[1]];
52820     }
52821
52822     function edge(point, size) {
52823         var pad = [80, 20, 50, 20],   // top, right, bottom, left
52824             x = 0,
52825             y = 0;
52826
52827         if (point[0] > size[0] - pad[1])
52828             x = -10;
52829         if (point[0] < pad[3])
52830             x = 10;
52831         if (point[1] > size[1] - pad[2])
52832             y = -10;
52833         if (point[1] < pad[0])
52834             y = 10;
52835
52836         if (x || y) {
52837             return [x, y];
52838         } else {
52839             return null;
52840         }
52841     }
52842
52843
52844     function startNudge(entity, nudge) {
52845         if (nudgeInterval) window.clearInterval(nudgeInterval);
52846         nudgeInterval = window.setInterval(function() {
52847             context.pan(nudge);
52848             doMove(entity, nudge);
52849         }, 50);
52850     }
52851
52852
52853     function stopNudge() {
52854         if (nudgeInterval) {
52855             window.clearInterval(nudgeInterval);
52856             nudgeInterval = null;
52857         }
52858     }
52859
52860
52861     function moveAnnotation(entity) {
52862         return t('operations.move.annotation.' + entity.geometry(context.graph()));
52863     }
52864
52865
52866     function connectAnnotation(entity) {
52867         return t('operations.connect.annotation.' + entity.geometry(context.graph()));
52868     }
52869
52870
52871     function origin(entity) {
52872         return context.projection(entity.loc);
52873     }
52874
52875
52876     function start(entity) {
52877         wasMidpoint = entity.type === 'midpoint';
52878
52879         isCancelled = event.sourceEvent.shiftKey ||
52880             context.features().hasHiddenConnections(entity, context.graph());
52881
52882         if (isCancelled) {
52883             return behavior.cancel();
52884         }
52885
52886         if (wasMidpoint) {
52887             var midpoint = entity;
52888             entity = osmNode();
52889             context.perform(actionAddMidpoint(midpoint, entity));
52890
52891             var vertex = context.surface().selectAll('.' + entity.id);
52892             behavior.target(vertex.node(), entity);
52893
52894         } else {
52895             context.perform(actionNoop());
52896         }
52897
52898         // activeIDs generate no pointer events.  This prevents the node or vertex
52899         // being dragged from trying to connect to itself or its parent element.
52900         activeIDs = lodash.map(context.graph().parentWays(entity), 'id');
52901         activeIDs.push(entity.id);
52902         setActiveElements();
52903
52904         context.enter(mode);
52905     }
52906
52907
52908     function datum() {
52909         var event$$1 = event && event.sourceEvent;
52910         if (!event$$1 || event$$1.altKey) {
52911             return {};
52912         } else {
52913             return event$$1.target.__data__ || {};
52914         }
52915     }
52916
52917
52918     function doMove(entity, nudge) {
52919         nudge = nudge || [0, 0];
52920
52921         var currPoint = (event && event.point) || context.projection(lastLoc),
52922             currMouse = vecSub(currPoint, nudge),
52923             loc = context.projection.invert(currMouse),
52924             d = datum();
52925
52926         if (!nudgeInterval) {
52927             if (d.type === 'node' && d.id !== entity.id) {
52928                 loc = d.loc;
52929             } else if (d.type === 'way' && !select(event.sourceEvent.target).classed('fill')) {
52930                 loc = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
52931             }
52932         }
52933
52934         context.replace(
52935             actionMoveNode(entity.id, loc),
52936             moveAnnotation(entity)
52937         );
52938
52939         lastLoc = loc;
52940     }
52941
52942
52943     function move(entity) {
52944         if (isCancelled) return;
52945         event.sourceEvent.stopPropagation();
52946         lastLoc = context.projection.invert(event.point);
52947
52948         doMove(entity);
52949         var nudge = edge(event.point, context.map().dimensions());
52950         if (nudge) {
52951             startNudge(entity, nudge);
52952         } else {
52953             stopNudge();
52954         }
52955     }
52956
52957
52958     function end(entity) {
52959         if (isCancelled) return;
52960
52961         var d = datum();
52962
52963         if (d.type === 'way') {
52964             var choice = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection);
52965             context.replace(
52966                 actionAddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
52967                 connectAnnotation(d)
52968             );
52969
52970         } else if (d.type === 'node' && d.id !== entity.id) {
52971             context.replace(
52972                 actionConnect([d.id, entity.id]),
52973                 connectAnnotation(d)
52974             );
52975
52976         } else if (wasMidpoint) {
52977             context.replace(
52978                 actionNoop(),
52979                 t('operations.add.annotation.vertex')
52980             );
52981
52982         } else {
52983             context.replace(
52984                 actionNoop(),
52985                 moveAnnotation(entity)
52986             );
52987         }
52988
52989         var reselection = selectedIDs.filter(function(id) {
52990             return context.graph().hasEntity(id);
52991         });
52992
52993         if (reselection.length) {
52994             context.enter(modeSelect(context, reselection));
52995         } else {
52996             context.enter(modeBrowse(context));
52997         }
52998     }
52999
53000
53001     function cancel() {
53002         behavior.cancel();
53003         context.enter(modeBrowse(context));
53004     }
53005
53006
53007     function setActiveElements() {
53008         context.surface().selectAll(utilEntitySelector(activeIDs))
53009             .classed('active', true);
53010     }
53011
53012
53013     var behavior = behaviorDrag()
53014         .selector('g.node, g.point, g.midpoint')
53015         .surface(select('#map').node())
53016         .origin(origin)
53017         .on('start', start)
53018         .on('move', move)
53019         .on('end', end);
53020
53021
53022     mode.enter = function() {
53023         context.install(hover);
53024         context.install(edit);
53025
53026         context.history()
53027             .on('undone.drag-node', cancel);
53028
53029         context.map()
53030             .on('drawn.drag-node', setActiveElements);
53031
53032         setActiveElements();
53033     };
53034
53035
53036     mode.exit = function() {
53037         context.ui().sidebar.hover.cancel();
53038         context.uninstall(hover);
53039         context.uninstall(edit);
53040
53041         context.history()
53042             .on('undone.drag-node', null);
53043
53044         context.map()
53045             .on('drawn.drag-node', null);
53046
53047         context.surface()
53048             .selectAll('.active')
53049             .classed('active', false);
53050
53051         stopNudge();
53052     };
53053
53054
53055     mode.selectedIDs = function(_) {
53056         if (!arguments.length) return selectedIDs;
53057         selectedIDs = _;
53058         return mode;
53059     };
53060
53061
53062     mode.behavior = behavior;
53063
53064
53065     return mode;
53066 }
53067
53068 function modeBrowse(context) {
53069     var mode = {
53070         button: 'browse',
53071         id: 'browse',
53072         title: t('modes.browse.title'),
53073         description: t('modes.browse.description')
53074     }, sidebar;
53075
53076     var behaviors = [
53077         behaviorPaste(context),
53078         behaviorHover(context).on('hover', context.ui().sidebar.hover),
53079         behaviorSelect(context),
53080         behaviorLasso(context),
53081         modeDragNode$$1(context).behavior
53082     ];
53083
53084
53085     mode.enter = function() {
53086         behaviors.forEach(function(behavior) {
53087             context.install(behavior);
53088         });
53089
53090         // Get focus on the body.
53091         if (document.activeElement && document.activeElement.blur) {
53092             document.activeElement.blur();
53093         }
53094
53095         if (sidebar) {
53096             context.ui().sidebar.show(sidebar);
53097         } else {
53098             context.ui().sidebar.select(null);
53099         }
53100     };
53101
53102
53103     mode.exit = function() {
53104         context.ui().sidebar.hover.cancel();
53105         behaviors.forEach(function(behavior) {
53106             context.uninstall(behavior);
53107         });
53108
53109         if (sidebar) {
53110             context.ui().sidebar.hide();
53111         }
53112     };
53113
53114
53115     mode.sidebar = function(_) {
53116         if (!arguments.length) return sidebar;
53117         sidebar = _;
53118         return mode;
53119     };
53120
53121
53122     return mode;
53123 }
53124
53125 function modeDrawArea(context, wayId, startGraph) {
53126     var mode = {
53127         button: 'area',
53128         id: 'draw-area'
53129     };
53130
53131     var behavior;
53132
53133
53134     mode.enter = function() {
53135         var way = context.entity(wayId);
53136
53137         behavior = behaviorDrawWay(context, wayId, undefined, mode, startGraph)
53138             .tail(t('modes.draw_area.tail'));
53139
53140         var addNode = behavior.addNode;
53141
53142         behavior.addNode = function(node) {
53143             var length = way.nodes.length,
53144                 penultimate = length > 2 ? way.nodes[length - 2] : null;
53145
53146             if (node.id === way.first() || node.id === penultimate) {
53147                 behavior.finish();
53148             } else {
53149                 addNode(node);
53150             }
53151         };
53152
53153         context.install(behavior);
53154     };
53155
53156
53157     mode.exit = function() {
53158         context.uninstall(behavior);
53159     };
53160
53161
53162     mode.selectedIDs = function() {
53163         return [wayId];
53164     };
53165
53166
53167     return mode;
53168 }
53169
53170 function modeDrawLine(context, wayId, startGraph, affix) {
53171     var mode = {
53172         button: 'line',
53173         id: 'draw-line'
53174     };
53175
53176     var behavior;
53177
53178
53179     mode.enter = function() {
53180         var way = context.entity(wayId),
53181             index = (affix === 'prefix') ? 0 : undefined,
53182             headId = (affix === 'prefix') ? way.first() : way.last();
53183
53184         behavior = behaviorDrawWay(context, wayId, index, mode, startGraph)
53185             .tail(t('modes.draw_line.tail'));
53186
53187         var addNode = behavior.addNode;
53188
53189         behavior.addNode = function(node) {
53190             if (node.id === headId) {
53191                 behavior.finish();
53192             } else {
53193                 addNode(node);
53194             }
53195         };
53196
53197         context.install(behavior);
53198     };
53199
53200
53201     mode.exit = function() {
53202         context.uninstall(behavior);
53203     };
53204
53205
53206     mode.selectedIDs = function() {
53207         return [wayId];
53208     };
53209
53210
53211     return mode;
53212 }
53213
53214 function operationCircularize(selectedIDs, context) {
53215     var entityId = selectedIDs[0],
53216         entity = context.entity(entityId),
53217         extent = entity.extent(context.graph()),
53218         geometry = context.geometry(entityId),
53219         action = actionCircularize(entityId, context.projection);
53220
53221
53222     var operation = function() {
53223         context.perform(action, operation.annotation());
53224     };
53225
53226
53227     operation.available = function() {
53228         return selectedIDs.length === 1 &&
53229             entity.type === 'way' &&
53230             lodash.uniq(entity.nodes).length > 1;
53231     };
53232
53233
53234     operation.disabled = function() {
53235         var reason;
53236         if (extent.percentContainedIn(context.extent()) < 0.8) {
53237             reason = 'too_large';
53238         } else if (context.hasHiddenConnections(entityId)) {
53239             reason = 'connected_to_hidden';
53240         }
53241         return action.disabled(context.graph()) || reason;
53242     };
53243
53244
53245     operation.tooltip = function() {
53246         var disable = operation.disabled();
53247         return disable ?
53248             t('operations.circularize.' + disable) :
53249             t('operations.circularize.description.' + geometry);
53250     };
53251
53252
53253     operation.annotation = function() {
53254         return t('operations.circularize.annotation.' + geometry);
53255     };
53256
53257
53258     operation.id = 'circularize';
53259     operation.keys = [t('operations.circularize.key')];
53260     operation.title = t('operations.circularize.title');
53261     operation.behavior = behaviorOperation(context).which(operation);
53262
53263     return operation;
53264 }
53265
53266 function operationContinue(selectedIDs, context) {
53267     var graph = context.graph(),
53268         entities = selectedIDs.map(function(id) { return graph.entity(id); }),
53269         geometries = lodash.extend({ line: [], vertex: [] },
53270             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); })),
53271         vertex = geometries.vertex[0];
53272
53273
53274     function candidateWays() {
53275         return graph.parentWays(vertex).filter(function(parent) {
53276             return parent.geometry(graph) === 'line' &&
53277                 !parent.isClosed() &&
53278                 parent.affix(vertex.id) &&
53279                 (geometries.line.length === 0 || geometries.line[0] === parent);
53280         });
53281     }
53282
53283
53284     var operation = function() {
53285         var candidate = candidateWays()[0];
53286         context.enter(
53287             modeDrawLine(context, candidate.id, context.graph(), candidate.affix(vertex.id))
53288         );
53289     };
53290
53291
53292     operation.available = function() {
53293         return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
53294             !context.features().hasHiddenConnections(vertex, context.graph());
53295     };
53296
53297
53298     operation.disabled = function() {
53299         var candidates = candidateWays();
53300         if (candidates.length === 0)
53301             return 'not_eligible';
53302         if (candidates.length > 1)
53303             return 'multiple';
53304     };
53305
53306
53307     operation.tooltip = function() {
53308         var disable = operation.disabled();
53309         return disable ?
53310             t('operations.continue.' + disable) :
53311             t('operations.continue.description');
53312     };
53313
53314
53315     operation.annotation = function() {
53316         return t('operations.continue.annotation.line');
53317     };
53318
53319
53320     operation.id = 'continue';
53321     operation.keys = [t('operations.continue.key')];
53322     operation.title = t('operations.continue.title');
53323     operation.behavior = behaviorOperation(context).which(operation);
53324
53325     return operation;
53326 }
53327
53328 function operationDelete(selectedIDs, context) {
53329     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
53330         action = actionDeleteMultiple(selectedIDs),
53331         extent = selectedIDs.reduce(function(extent, id) {
53332                 return extent.extend(context.entity(id).extent(context.graph()));
53333             }, geoExtent$$1());
53334
53335
53336     var operation = function() {
53337         var nextSelectedID;
53338
53339         if (selectedIDs.length === 1) {
53340             var id = selectedIDs[0],
53341                 entity = context.entity(id),
53342                 geometry = context.geometry(id),
53343                 parents = context.graph().parentWays(entity),
53344                 parent = parents[0];
53345
53346             // Select the next closest node in the way.
53347             if (geometry === 'vertex' && parent.nodes.length > 2) {
53348                 var nodes = parent.nodes,
53349                     i = nodes.indexOf(id);
53350
53351                 if (i === 0) {
53352                     i++;
53353                 } else if (i === nodes.length - 1) {
53354                     i--;
53355                 } else {
53356                     var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
53357                         b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
53358                     i = a < b ? i - 1 : i + 1;
53359                 }
53360
53361                 nextSelectedID = nodes[i];
53362             }
53363         }
53364
53365         context.perform(action, operation.annotation());
53366
53367         if (nextSelectedID && context.hasEntity(nextSelectedID)) {
53368             context.enter(modeSelect(context, [nextSelectedID]).follow(true));
53369         } else {
53370             context.enter(modeBrowse(context));
53371         }
53372
53373     };
53374
53375
53376     operation.available = function() {
53377         return true;
53378     };
53379
53380
53381     operation.disabled = function() {
53382         var reason;
53383         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
53384             reason = 'too_large';
53385         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
53386             reason = 'connected_to_hidden';
53387         } else if (lodash.some(selectedIDs, protectedMember)) {
53388             reason = 'part_of_relation';
53389         } else if (lodash.some(selectedIDs, incompleteRelation)) {
53390             reason = 'incomplete_relation';
53391         }
53392         return reason;
53393
53394         function incompleteRelation(id) {
53395             var entity = context.entity(id);
53396             return entity.type === 'relation' && !entity.isComplete(context.graph());
53397         }
53398
53399         function protectedMember(id) {
53400             var entity = context.entity(id);
53401             if (entity.type !== 'way') return false;
53402
53403             var parents = context.graph().parentRelations(entity);
53404             for (var i = 0; i < parents.length; i++) {
53405                 var parent = parents[i],
53406                     type = parent.tags.type,
53407                     role = parent.memberById(id).role || 'outer';
53408                 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
53409                     return true;
53410                 }
53411             }
53412             return false;
53413         }
53414
53415     };
53416
53417
53418     operation.tooltip = function() {
53419         var disable = operation.disabled();
53420         return disable ?
53421             t('operations.delete.' + disable + '.' + multi) :
53422             t('operations.delete.description' + '.' + multi);
53423     };
53424
53425
53426     operation.annotation = function() {
53427         return selectedIDs.length === 1 ?
53428             t('operations.delete.annotation.' + context.geometry(selectedIDs[0])) :
53429             t('operations.delete.annotation.multiple', { n: selectedIDs.length });
53430     };
53431
53432
53433     operation.id = 'delete';
53434     operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
53435     operation.title = t('operations.delete.title');
53436     operation.behavior = behaviorOperation(context).which(operation);
53437
53438     return operation;
53439 }
53440
53441 function operationDisconnect(selectedIDs, context) {
53442     var vertices = lodash.filter(selectedIDs, function(entityId) {
53443         return context.geometry(entityId) === 'vertex';
53444     });
53445
53446     var entityId = vertices[0],
53447         action = actionDisconnect(entityId);
53448
53449     if (selectedIDs.length > 1) {
53450         action.limitWays(lodash.without(selectedIDs, entityId));
53451     }
53452
53453
53454     var operation = function() {
53455         context.perform(action, operation.annotation());
53456     };
53457
53458
53459     operation.available = function() {
53460         return vertices.length === 1;
53461     };
53462
53463
53464     operation.disabled = function() {
53465         var reason;
53466         if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
53467             reason = 'connected_to_hidden';
53468         }
53469         return action.disabled(context.graph()) || reason;
53470     };
53471
53472
53473     operation.tooltip = function() {
53474         var disable = operation.disabled();
53475         return disable ?
53476             t('operations.disconnect.' + disable) :
53477             t('operations.disconnect.description');
53478     };
53479
53480
53481     operation.annotation = function() {
53482         return t('operations.disconnect.annotation');
53483     };
53484
53485
53486     operation.id = 'disconnect';
53487     operation.keys = [t('operations.disconnect.key')];
53488     operation.title = t('operations.disconnect.title');
53489     operation.behavior = behaviorOperation(context).which(operation);
53490
53491     return operation;
53492 }
53493
53494 function operationMerge(selectedIDs, context) {
53495
53496     function updatePresetTags(newGraph, ids) {
53497         var id = ids[0],
53498             newEntity = newGraph.hasEntity(id);
53499
53500         if (!newEntity) return;
53501
53502         var newPreset = context.presets().match(newEntity, newGraph);
53503
53504         context.replace(actionChangePreset(id, null, newPreset), operation.annotation());
53505     }
53506
53507
53508     var join = actionJoin(selectedIDs),
53509         merge = actionMerge(selectedIDs),
53510         mergePolygon = actionMergePolygon(selectedIDs);
53511
53512
53513     var operation = function() {
53514         var origGraph = context.graph(),
53515             action;
53516
53517         if (!join.disabled(origGraph)) {
53518             action = join;
53519         } else if (!merge.disabled(origGraph)) {
53520             action = merge;
53521         } else {
53522             action = mergePolygon;
53523         }
53524
53525         context.perform(action, operation.annotation());
53526
53527         var ids = selectedIDs.filter(function(id) {
53528             var entity = context.hasEntity(id);
53529             return entity && entity.type !== 'node';
53530         });
53531
53532         // if we merged tags, rematch preset to update tags if necessary (#3851)
53533         if (action === merge) {
53534             updatePresetTags(context.graph(), ids);
53535         }
53536
53537         context.enter(modeSelect(context, ids));
53538     };
53539
53540
53541     operation.available = function() {
53542         return selectedIDs.length >= 2;
53543     };
53544
53545
53546     operation.disabled = function() {
53547         return join.disabled(context.graph()) &&
53548             merge.disabled(context.graph()) &&
53549             mergePolygon.disabled(context.graph());
53550     };
53551
53552
53553     operation.tooltip = function() {
53554         var j = join.disabled(context.graph()),
53555             m = merge.disabled(context.graph()),
53556             p = mergePolygon.disabled(context.graph());
53557
53558         if (j === 'restriction' && m && p) {
53559             return t('operations.merge.restriction',
53560                 { relation: context.presets().item('type/restriction').name() });
53561         }
53562
53563         if (p === 'incomplete_relation' && j && m) {
53564             return t('operations.merge.incomplete_relation');
53565         }
53566
53567         if (j && m && p) {
53568             return t('operations.merge.' + j);
53569         }
53570
53571         return t('operations.merge.description');
53572     };
53573
53574
53575     operation.annotation = function() {
53576         return t('operations.merge.annotation', { n: selectedIDs.length });
53577     };
53578
53579
53580     operation.id = 'merge';
53581     operation.keys = [t('operations.merge.key')];
53582     operation.title = t('operations.merge.title');
53583     operation.behavior = behaviorOperation(context).which(operation);
53584
53585     return operation;
53586 }
53587
53588 function operationMove(selectedIDs, context) {
53589     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
53590         extent = selectedIDs.reduce(function(extent, id) {
53591             return extent.extend(context.entity(id).extent(context.graph()));
53592         }, geoExtent$$1());
53593
53594
53595     var operation = function() {
53596         context.enter(modeMove$$1(context, selectedIDs));
53597     };
53598
53599
53600     operation.available = function() {
53601         return selectedIDs.length > 1 ||
53602             context.entity(selectedIDs[0]).type !== 'node';
53603     };
53604
53605
53606     operation.disabled = function() {
53607         var reason;
53608         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
53609             reason = 'too_large';
53610         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
53611             reason = 'connected_to_hidden';
53612         } else if (lodash.some(selectedIDs, incompleteRelation)) {
53613             reason = 'incomplete_relation';
53614         }
53615         return reason;
53616
53617         function incompleteRelation(id) {
53618             var entity = context.entity(id);
53619             return entity.type === 'relation' && !entity.isComplete(context.graph());
53620         }
53621     };
53622
53623
53624     operation.tooltip = function() {
53625         var disable = operation.disabled();
53626         return disable ?
53627             t('operations.move.' + disable + '.' + multi) :
53628             t('operations.move.description.' + multi);
53629     };
53630
53631
53632     operation.annotation = function() {
53633         return selectedIDs.length === 1 ?
53634             t('operations.move.annotation.' + context.geometry(selectedIDs[0])) :
53635             t('operations.move.annotation.multiple');
53636     };
53637
53638
53639     operation.id = 'move';
53640     operation.keys = [t('operations.move.key')];
53641     operation.title = t('operations.move.title');
53642     operation.behavior = behaviorOperation(context).which(operation);
53643
53644     return operation;
53645 }
53646
53647 function operationOrthogonalize(selectedIDs, context) {
53648     var entityId = selectedIDs[0],
53649         entity = context.entity(entityId),
53650         extent = entity.extent(context.graph()),
53651         geometry = context.geometry(entityId),
53652         action = actionOrthogonalize(entityId, context.projection);
53653
53654
53655     var operation = function() {
53656         context.perform(action, operation.annotation());
53657     };
53658
53659
53660     operation.available = function() {
53661         return selectedIDs.length === 1 &&
53662             entity.type === 'way' &&
53663             entity.isClosed() &&
53664             lodash.uniq(entity.nodes).length > 2;
53665     };
53666
53667
53668     operation.disabled = function() {
53669         var reason;
53670         if (extent.percentContainedIn(context.extent()) < 0.8) {
53671             reason = 'too_large';
53672         } else if (context.hasHiddenConnections(entityId)) {
53673             reason = 'connected_to_hidden';
53674         }
53675         return action.disabled(context.graph()) || reason;
53676     };
53677
53678
53679     operation.tooltip = function() {
53680         var disable = operation.disabled();
53681         return disable ?
53682             t('operations.orthogonalize.' + disable) :
53683             t('operations.orthogonalize.description.' + geometry);
53684     };
53685
53686
53687     operation.annotation = function() {
53688         return t('operations.orthogonalize.annotation.' + geometry);
53689     };
53690
53691
53692     operation.id = 'orthogonalize';
53693     operation.keys = [t('operations.orthogonalize.key')];
53694     operation.title = t('operations.orthogonalize.title');
53695     operation.behavior = behaviorOperation(context).which(operation);
53696
53697     return operation;
53698 }
53699
53700 function operationReflectShort(selectedIDs, context) {
53701     return operationReflect(selectedIDs, context, 'short');
53702 }
53703
53704
53705 function operationReflectLong(selectedIDs, context) {
53706     return operationReflect(selectedIDs, context, 'long');
53707 }
53708
53709
53710 function operationReflect(selectedIDs, context, axis) {
53711     axis = axis || 'long';
53712     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
53713         extent = selectedIDs.reduce(function(extent, id) {
53714             return extent.extend(context.entity(id).extent(context.graph()));
53715         }, geoExtent$$1());
53716
53717
53718     var operation = function() {
53719         var action = actionReflect(selectedIDs, context.projection)
53720             .useLongAxis(Boolean(axis === 'long'));
53721         context.perform(action, operation.annotation());
53722     };
53723
53724
53725     operation.available = function() {
53726         return lodash.some(selectedIDs, hasArea);
53727
53728         function hasArea(id) {
53729             var entity = context.entity(id);
53730             return (entity.type === 'way' && entity.isClosed()) ||
53731                 (entity.type ==='relation' && entity.isMultipolygon());
53732         }
53733     };
53734
53735
53736     operation.disabled = function() {
53737         var reason;
53738         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
53739             reason = 'too_large';
53740         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
53741             reason = 'connected_to_hidden';
53742         } else if (lodash.some(selectedIDs, incompleteRelation)) {
53743             reason = 'incomplete_relation';
53744         }
53745         return reason;
53746
53747         function incompleteRelation(id) {
53748             var entity = context.entity(id);
53749             return entity.type === 'relation' && !entity.isComplete(context.graph());
53750         }
53751     };
53752
53753
53754     operation.tooltip = function() {
53755         var disable = operation.disabled();
53756         return disable ?
53757             t('operations.reflect.' + disable + '.' + multi) :
53758             t('operations.reflect.description.' + axis + '.' + multi);
53759     };
53760
53761
53762     operation.annotation = function() {
53763         return t('operations.reflect.annotation.' + axis + '.' + multi);
53764     };
53765
53766
53767     operation.id = 'reflect-' + axis;
53768     operation.keys = [t('operations.reflect.key.' + axis)];
53769     operation.title = t('operations.reflect.title.' + axis);
53770     operation.behavior = behaviorOperation(context).which(operation);
53771
53772     return operation;
53773 }
53774
53775 function operationReverse(selectedIDs, context) {
53776     var entityId = selectedIDs[0];
53777
53778     var operation = function() {
53779         context.perform(actionReverse(entityId), operation.annotation());
53780     };
53781
53782
53783     operation.available = function() {
53784         return selectedIDs.length === 1 && context.geometry(entityId) === 'line';
53785     };
53786
53787
53788     operation.disabled = function() {
53789         return false;
53790     };
53791
53792
53793     operation.tooltip = function() {
53794         return t('operations.reverse.description');
53795     };
53796
53797
53798     operation.annotation = function() {
53799         return t('operations.reverse.annotation');
53800     };
53801
53802
53803     operation.id = 'reverse';
53804     operation.keys = [t('operations.reverse.key')];
53805     operation.title = t('operations.reverse.title');
53806     operation.behavior = behaviorOperation(context).which(operation);
53807
53808     return operation;
53809 }
53810
53811 function operationRotate(selectedIDs, context) {
53812     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
53813         extent = selectedIDs.reduce(function(extent, id) {
53814             return extent.extend(context.entity(id).extent(context.graph()));
53815         }, geoExtent$$1());
53816
53817
53818     var operation = function() {
53819         context.enter(modeRotate$$1(context, selectedIDs));
53820     };
53821
53822
53823     operation.available = function() {
53824         return lodash.some(selectedIDs, hasArea);
53825
53826         function hasArea(id) {
53827             var entity = context.entity(id);
53828             return (entity.type === 'way' && entity.isClosed()) ||
53829                 (entity.type ==='relation' && entity.isMultipolygon());
53830         }
53831     };
53832
53833
53834     operation.disabled = function() {
53835         var reason;
53836         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
53837             reason = 'too_large';
53838         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
53839             reason = 'connected_to_hidden';
53840         } else if (lodash.some(selectedIDs, incompleteRelation)) {
53841             reason = 'incomplete_relation';
53842         }
53843         return reason;
53844
53845         function incompleteRelation(id) {
53846             var entity = context.entity(id);
53847             return entity.type === 'relation' && !entity.isComplete(context.graph());
53848         }
53849     };
53850
53851
53852     operation.tooltip = function() {
53853         var disable = operation.disabled();
53854         return disable ?
53855             t('operations.rotate.' + disable + '.' + multi) :
53856             t('operations.rotate.description.' + multi);
53857     };
53858
53859
53860     operation.annotation = function() {
53861         return selectedIDs.length === 1 ?
53862             t('operations.rotate.annotation.' + context.geometry(selectedIDs[0])) :
53863             t('operations.rotate.annotation.multiple');
53864     };
53865
53866
53867     operation.id = 'rotate';
53868     operation.keys = [t('operations.rotate.key')];
53869     operation.title = t('operations.rotate.title');
53870     operation.behavior = behaviorOperation(context).which(operation);
53871
53872     return operation;
53873 }
53874
53875 function operationSplit(selectedIDs, context) {
53876     var vertices = lodash.filter(selectedIDs, function(entityId) {
53877         return context.geometry(entityId) === 'vertex';
53878     });
53879
53880     var entityId = vertices[0],
53881         action = actionSplit(entityId),
53882         ways = [];
53883
53884     if (vertices.length === 1) {
53885         if (selectedIDs.length > 1) {
53886             action.limitWays(lodash.without(selectedIDs, entityId));
53887         }
53888         ways = action.ways(context.graph());
53889     }
53890
53891
53892     var operation = function() {
53893         var difference = context.perform(action, operation.annotation());
53894         context.enter(modeSelect(context, difference.extantIDs()));
53895     };
53896
53897
53898     operation.available = function() {
53899         return vertices.length === 1;
53900     };
53901
53902
53903     operation.disabled = function() {
53904         var reason;
53905         if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
53906             reason = 'connected_to_hidden';
53907         }
53908         return action.disabled(context.graph()) || reason;
53909     };
53910
53911
53912     operation.tooltip = function() {
53913         var disable = operation.disabled();
53914         if (disable) {
53915             return t('operations.split.' + disable);
53916         }
53917         if (ways.length === 1) {
53918             return t('operations.split.description.' + context.geometry(ways[0].id));
53919         } else {
53920             return t('operations.split.description.multiple');
53921         }
53922     };
53923
53924
53925     operation.annotation = function() {
53926         return ways.length === 1 ?
53927             t('operations.split.annotation.' + context.geometry(ways[0].id)) :
53928             t('operations.split.annotation.multiple', { n: ways.length });
53929     };
53930
53931
53932     operation.id = 'split';
53933     operation.keys = [t('operations.split.key')];
53934     operation.title = t('operations.split.title');
53935     operation.behavior = behaviorOperation(context).which(operation);
53936
53937     return operation;
53938 }
53939
53940 function operationStraighten(selectedIDs, context) {
53941     var entityId = selectedIDs[0],
53942         action = actionStraighten(entityId, context.projection);
53943
53944
53945     function operation() {
53946         context.perform(action, operation.annotation());
53947     }
53948
53949
53950     operation.available = function() {
53951         var entity = context.entity(entityId);
53952         return selectedIDs.length === 1 &&
53953             entity.type === 'way' &&
53954             !entity.isClosed() &&
53955             lodash.uniq(entity.nodes).length > 2;
53956     };
53957
53958
53959     operation.disabled = function() {
53960         var reason;
53961         if (context.hasHiddenConnections(entityId)) {
53962             reason = 'connected_to_hidden';
53963         }
53964         return action.disabled(context.graph()) || reason;
53965     };
53966
53967
53968     operation.tooltip = function() {
53969         var disable = operation.disabled();
53970         return disable ?
53971             t('operations.straighten.' + disable) :
53972             t('operations.straighten.description');
53973     };
53974
53975
53976     operation.annotation = function() {
53977         return t('operations.straighten.annotation');
53978     };
53979
53980
53981     operation.id = 'straighten';
53982     operation.keys = [t('operations.straighten.key')];
53983     operation.title = t('operations.straighten.title');
53984     operation.behavior = behaviorOperation(context).which(operation);
53985
53986     return operation;
53987 }
53988
53989
53990
53991 var Operations = Object.freeze({
53992         operationCircularize: operationCircularize,
53993         operationContinue: operationContinue,
53994         operationDelete: operationDelete,
53995         operationDisconnect: operationDisconnect,
53996         operationMerge: operationMerge,
53997         operationMove: operationMove,
53998         operationOrthogonalize: operationOrthogonalize,
53999         operationReflectShort: operationReflectShort,
54000         operationReflectLong: operationReflectLong,
54001         operationReverse: operationReverse,
54002         operationRotate: operationRotate,
54003         operationSplit: operationSplit,
54004         operationStraighten: operationStraighten
54005 });
54006
54007 function modeMove$$1(context, entityIDs, baseGraph) {
54008     var mode = {
54009         id: 'move',
54010         button: 'browse'
54011     };
54012
54013     var keybinding = d3keybinding('move'),
54014         behaviors = [
54015             behaviorEdit(context),
54016             operationCircularize(entityIDs, context).behavior,
54017             operationDelete(entityIDs, context).behavior,
54018             operationOrthogonalize(entityIDs, context).behavior,
54019             operationReflectLong(entityIDs, context).behavior,
54020             operationReflectShort(entityIDs, context).behavior,
54021             operationRotate(entityIDs, context).behavior
54022         ],
54023         annotation = entityIDs.length === 1 ?
54024             t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
54025             t('operations.move.annotation.multiple'),
54026         prevGraph,
54027         cache,
54028         origin,
54029         nudgeInterval;
54030
54031
54032     function vecSub(a, b) {
54033         return [a[0] - b[0], a[1] - b[1]];
54034     }
54035
54036
54037     function edge(point, size) {
54038         var pad = [80, 20, 50, 20],   // top, right, bottom, left
54039             x = 0,
54040             y = 0;
54041
54042         if (point[0] > size[0] - pad[1])
54043             x = -10;
54044         if (point[0] < pad[3])
54045             x = 10;
54046         if (point[1] > size[1] - pad[2])
54047             y = -10;
54048         if (point[1] < pad[0])
54049             y = 10;
54050
54051         if (x || y) {
54052             return [x, y];
54053         } else {
54054             return null;
54055         }
54056     }
54057
54058
54059     function doMove(nudge) {
54060         nudge = nudge || [0, 0];
54061
54062         var fn;
54063         if (prevGraph !== context.graph()) {
54064             cache = {};
54065             origin = context.map().mouseCoordinates();
54066             fn = context.perform;
54067         } else {
54068             fn = context.overwrite;
54069         }
54070
54071         var currMouse = context.mouse(),
54072             origMouse = context.projection(origin),
54073             delta = vecSub(vecSub(currMouse, origMouse), nudge);
54074
54075         fn(actionMove(entityIDs, delta, context.projection, cache), annotation);
54076         prevGraph = context.graph();
54077     }
54078
54079
54080     function startNudge(nudge) {
54081         if (nudgeInterval) window.clearInterval(nudgeInterval);
54082         nudgeInterval = window.setInterval(function() {
54083             context.pan(nudge);
54084             doMove(nudge);
54085         }, 50);
54086     }
54087
54088
54089     function stopNudge() {
54090         if (nudgeInterval) {
54091             window.clearInterval(nudgeInterval);
54092             nudgeInterval = null;
54093         }
54094     }
54095
54096
54097     function move() {
54098         doMove();
54099         var nudge = edge(context.mouse(), context.map().dimensions());
54100         if (nudge) {
54101             startNudge(nudge);
54102         } else {
54103             stopNudge();
54104         }
54105     }
54106
54107
54108     function finish() {
54109         event.stopPropagation();
54110         context.enter(modeSelect(context, entityIDs));
54111         stopNudge();
54112     }
54113
54114
54115     function cancel() {
54116         if (baseGraph) {
54117             while (context.graph() !== baseGraph) context.pop();
54118             context.enter(modeBrowse(context));
54119         } else {
54120             context.pop();
54121             context.enter(modeSelect(context, entityIDs));
54122         }
54123         stopNudge();
54124     }
54125
54126
54127     function undone() {
54128         context.enter(modeBrowse(context));
54129     }
54130
54131
54132     mode.enter = function() {
54133         origin = context.map().mouseCoordinates();
54134         prevGraph = null;
54135         cache = {};
54136
54137         behaviors.forEach(function(behavior) {
54138             context.install(behavior);
54139         });
54140
54141         context.surface()
54142             .on('mousemove.move', move)
54143             .on('click.move', finish);
54144
54145         context.history()
54146             .on('undone.move', undone);
54147
54148         keybinding
54149             .on('⎋', cancel)
54150             .on('↩', finish);
54151
54152         select(document)
54153             .call(keybinding);
54154     };
54155
54156
54157     mode.exit = function() {
54158         stopNudge();
54159
54160         behaviors.forEach(function(behavior) {
54161             context.uninstall(behavior);
54162         });
54163
54164         context.surface()
54165             .on('mousemove.move', null)
54166             .on('click.move', null);
54167
54168         context.history()
54169             .on('undone.move', null);
54170
54171         keybinding.off();
54172     };
54173
54174
54175     return mode;
54176 }
54177
54178 function modeRotate$$1(context, entityIDs) {
54179     var mode = {
54180         id: 'rotate',
54181         button: 'browse'
54182     };
54183
54184     var keybinding = d3keybinding('rotate'),
54185         behaviors = [
54186             behaviorEdit(context),
54187             operationCircularize(entityIDs, context).behavior,
54188             operationDelete(entityIDs, context).behavior,
54189             operationMove(entityIDs, context).behavior,
54190             operationOrthogonalize(entityIDs, context).behavior,
54191             operationReflectLong(entityIDs, context).behavior,
54192             operationReflectShort(entityIDs, context).behavior
54193         ],
54194         annotation = entityIDs.length === 1 ?
54195             t('operations.rotate.annotation.' + context.geometry(entityIDs[0])) :
54196             t('operations.rotate.annotation.multiple'),
54197         prevGraph,
54198         prevAngle,
54199         prevTransform,
54200         pivot;
54201
54202
54203     function doRotate() {
54204         var fn;
54205         if (context.graph() !== prevGraph) {
54206             fn = context.perform;
54207         } else {
54208             fn = context.replace;
54209         }
54210
54211         // projection changed, recalculate pivot
54212         var projection$$1 = context.projection;
54213         var currTransform = projection$$1.transform();
54214         if (!prevTransform ||
54215             currTransform.k !== prevTransform.k ||
54216             currTransform.x !== prevTransform.x ||
54217             currTransform.y !== prevTransform.y) {
54218
54219             var nodes = utilGetAllNodes(entityIDs, context.graph()),
54220                 points = nodes.map(function(n) { return projection$$1(n.loc); });
54221
54222             pivot = d3polygonCentroid(d3polygonHull(points));
54223             prevAngle = undefined;
54224         }
54225
54226
54227         var currMouse = context.mouse(),
54228             currAngle = Math.atan2(currMouse[1] - pivot[1], currMouse[0] - pivot[0]);
54229
54230         if (typeof prevAngle === 'undefined') prevAngle = currAngle;
54231         var delta = currAngle - prevAngle;
54232
54233         fn(actionRotate(entityIDs, pivot, delta, projection$$1), annotation);
54234
54235         prevTransform = currTransform;
54236         prevAngle = currAngle;
54237         prevGraph = context.graph();
54238     }
54239
54240
54241     function finish() {
54242         event.stopPropagation();
54243         context.enter(modeSelect(context, entityIDs));
54244     }
54245
54246
54247     function cancel() {
54248         context.pop();
54249         context.enter(modeSelect(context, entityIDs));
54250     }
54251
54252
54253     function undone() {
54254         context.enter(modeBrowse(context));
54255     }
54256
54257
54258     mode.enter = function() {
54259         behaviors.forEach(function(behavior) {
54260             context.install(behavior);
54261         });
54262
54263         context.surface()
54264             .on('mousemove.rotate', doRotate)
54265             .on('click.rotate', finish);
54266
54267         context.history()
54268             .on('undone.rotate', undone);
54269
54270         keybinding
54271             .on('⎋', cancel)
54272             .on('↩', finish);
54273
54274         select(document)
54275             .call(keybinding);
54276     };
54277
54278
54279     mode.exit = function() {
54280         behaviors.forEach(function(behavior) {
54281             context.uninstall(behavior);
54282         });
54283
54284         context.surface()
54285             .on('mousemove.rotate', null)
54286             .on('click.rotate', null);
54287
54288         context.history()
54289             .on('undone.rotate', null);
54290
54291         keybinding.off();
54292     };
54293
54294
54295     return mode;
54296 }
54297
54298 function modeSave$$1(context) {
54299     var mode = {
54300         id: 'save'
54301     };
54302
54303     var commit = uiCommit(context)
54304             .on('cancel', cancel)
54305             .on('save', save);
54306
54307
54308     function cancel() {
54309         context.enter(modeBrowse(context));
54310     }
54311
54312
54313     function save(changeset, tryAgain) {
54314
54315         var loading = uiLoading(context).message(t('save.uploading')).blocking(true),
54316             history = context.history(),
54317             origChanges = history.changes(actionDiscardTags(history.difference())),
54318             localGraph = context.graph(),
54319             remoteGraph = coreGraph$$1(history.base(), true),
54320             modified = lodash.filter(history.difference().summary(), {changeType: 'modified'}),
54321             toCheck = lodash.map(lodash.map(modified, 'entity'), 'id'),
54322             toLoad = withChildNodes(toCheck, localGraph),
54323             conflicts = [],
54324             errors = [];
54325
54326         if (!tryAgain) {
54327             history.perform(actionNoop());  // checkpoint
54328         }
54329
54330         context.container().call(loading);
54331
54332         if (toCheck.length) {
54333             context.connection().loadMultiple(toLoad, loaded);
54334         } else {
54335             upload();
54336         }
54337
54338
54339         function withChildNodes(ids, graph) {
54340             return lodash.uniq(lodash.reduce(ids, function(result, id) {
54341                 var entity = graph.entity(id);
54342                 if (entity.type === 'way') {
54343                     try {
54344                         var cn = graph.childNodes(entity);
54345                         result.push.apply(result, lodash.map(lodash.filter(cn, 'version'), 'id'));
54346                     } catch (err) {
54347                         /* eslint-disable no-console */
54348                         if (typeof console !== 'undefined') console.error(err);
54349                         /* eslint-enable no-console */
54350                     }
54351                 }
54352                 return result;
54353             }, lodash.clone(ids)));
54354         }
54355
54356
54357         // Reload modified entities into an alternate graph and check for conflicts..
54358         function loaded(err, result) {
54359             if (errors.length) return;
54360
54361             if (err) {
54362                 errors.push({
54363                     msg: err.responseText,
54364                     details: [ t('save.status_code', { code: err.status }) ]
54365                 });
54366                 showErrors();
54367
54368             } else {
54369                 var loadMore = [];
54370                 lodash.each(result.data, function(entity) {
54371                     remoteGraph.replace(entity);
54372                     toLoad = lodash.without(toLoad, entity.id);
54373
54374                     // Because loadMultiple doesn't download /full like loadEntity,
54375                     // need to also load children that aren't already being checked..
54376                     if (!entity.visible) return;
54377                     if (entity.type === 'way') {
54378                         loadMore.push.apply(loadMore,
54379                             lodash.difference(entity.nodes, toCheck, toLoad, loadMore));
54380                     } else if (entity.type === 'relation' && entity.isMultipolygon()) {
54381                         loadMore.push.apply(loadMore,
54382                             lodash.difference(lodash.map(entity.members, 'id'), toCheck, toLoad, loadMore));
54383                     }
54384                 });
54385
54386                 if (loadMore.length) {
54387                     toLoad.push.apply(toLoad, loadMore);
54388                     context.connection().loadMultiple(loadMore, loaded);
54389                 }
54390
54391                 if (!toLoad.length) {
54392                     checkConflicts();
54393                 }
54394             }
54395         }
54396
54397
54398         function checkConflicts() {
54399             function choice(id, text$$1, action) {
54400                 return { id: id, text: text$$1, action: function() { history.replace(action); } };
54401             }
54402             function formatUser(d) {
54403                 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
54404             }
54405             function entityName(entity) {
54406                 return utilDisplayName(entity) || (utilDisplayType(entity.id) + ' ' + entity.id);
54407             }
54408
54409             function compareVersions(local, remote) {
54410                 if (local.version !== remote.version) return false;
54411
54412                 if (local.type === 'way') {
54413                     var children = lodash.union(local.nodes, remote.nodes);
54414
54415                     for (var i = 0; i < children.length; i++) {
54416                         var a = localGraph.hasEntity(children[i]),
54417                             b = remoteGraph.hasEntity(children[i]);
54418
54419                         if (a && b && a.version !== b.version) return false;
54420                     }
54421                 }
54422
54423                 return true;
54424             }
54425
54426             lodash.each(toCheck, function(id) {
54427                 var local = localGraph.entity(id),
54428                     remote = remoteGraph.entity(id);
54429
54430                 if (compareVersions(local, remote)) return;
54431
54432                 var action = actionMergeRemoteChanges,
54433                     merge$$1 = action(id, localGraph, remoteGraph, formatUser);
54434
54435                 history.replace(merge$$1);
54436
54437                 var mergeConflicts = merge$$1.conflicts();
54438                 if (!mergeConflicts.length) return;  // merged safely
54439
54440                 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
54441                     forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
54442                     keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
54443                     keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
54444
54445                 conflicts.push({
54446                     id: id,
54447                     name: entityName(local),
54448                     details: mergeConflicts,
54449                     chosen: 1,
54450                     choices: [
54451                         choice(id, keepMine, forceLocal),
54452                         choice(id, keepTheirs, forceRemote)
54453                     ]
54454                 });
54455             });
54456
54457             upload();
54458         }
54459
54460
54461         function upload() {
54462             if (conflicts.length) {
54463                 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
54464                 showConflicts();
54465             } else if (errors.length) {
54466                 showErrors();
54467             } else {
54468                 var changes = history.changes(actionDiscardTags(history.difference()));
54469                 if (changes.modified.length || changes.created.length || changes.deleted.length) {
54470                     context.connection().putChangeset(changeset, changes, uploadCallback);
54471                 } else {        // changes were insignificant or reverted by user
54472                     select('.inspector-wrap *').remove();
54473                     loading.close();
54474                     context.flush();
54475                     cancel();
54476                 }
54477             }
54478         }
54479
54480
54481         function uploadCallback(err, changeset) {
54482             if (err) {
54483                 errors.push({
54484                     msg: err.responseText,
54485                     details: [ t('save.status_code', { code: err.status }) ]
54486                 });
54487                 showErrors();
54488             } else {
54489                 history.clearSaved();
54490                 success(changeset);
54491                 // Add delay to allow for postgres replication #1646 #2678
54492                 window.setTimeout(function() {
54493                     select('.inspector-wrap *').remove();
54494                     loading.close();
54495                     context.flush();
54496                 }, 2500);
54497             }
54498         }
54499
54500
54501         function showConflicts() {
54502             var selection$$1 = context.container()
54503                 .select('#sidebar')
54504                 .append('div')
54505                 .attr('class','sidebar-component');
54506
54507             loading.close();
54508
54509             selection$$1.call(uiConflicts(context)
54510                 .list(conflicts)
54511                 .on('download', function() {
54512                     var data = JXON.stringify(changeset.update({ id: 'CHANGEME' }).osmChangeJXON(origChanges)),
54513                         win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
54514                     win.focus();
54515                 })
54516                 .on('cancel', function() {
54517                     history.pop();
54518                     selection$$1.remove();
54519                 })
54520                 .on('save', function() {
54521                     for (var i = 0; i < conflicts.length; i++) {
54522                         if (conflicts[i].chosen === 1) {  // user chose "keep theirs"
54523                             var entity = context.hasEntity(conflicts[i].id);
54524                             if (entity && entity.type === 'way') {
54525                                 var children = lodash.uniq(entity.nodes);
54526                                 for (var j = 0; j < children.length; j++) {
54527                                     history.replace(actionRevert(children[j]));
54528                                 }
54529                             }
54530                             history.replace(actionRevert(conflicts[i].id));
54531                         }
54532                     }
54533
54534                     selection$$1.remove();
54535                     save(changeset, true);
54536                 })
54537             );
54538         }
54539
54540
54541         function showErrors() {
54542             var selection$$1 = uiConfirm(context.container());
54543
54544             history.pop();
54545             loading.close();
54546
54547             selection$$1
54548                 .select('.modal-section.header')
54549                 .append('h3')
54550                 .text(t('save.error'));
54551
54552             addErrors(selection$$1, errors);
54553             selection$$1.okButton();
54554         }
54555
54556
54557         function addErrors(selection$$1, data) {
54558             var message = selection$$1
54559                 .select('.modal-section.message-text');
54560
54561             var items = message
54562                 .selectAll('.error-container')
54563                 .data(data);
54564
54565             var enter = items.enter()
54566                 .append('div')
54567                 .attr('class', 'error-container');
54568
54569             enter
54570                 .append('a')
54571                 .attr('class', 'error-description')
54572                 .attr('href', '#')
54573                 .classed('hide-toggle', true)
54574                 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
54575                 .on('click', function() {
54576                     var error = select(this),
54577                         detail = select(this.nextElementSibling),
54578                         exp = error.classed('expanded');
54579
54580                     detail.style('display', exp ? 'none' : 'block');
54581                     error.classed('expanded', !exp);
54582
54583                     event.preventDefault();
54584                 });
54585
54586             var details = enter
54587                 .append('div')
54588                 .attr('class', 'error-detail-container')
54589                 .style('display', 'none');
54590
54591             details
54592                 .append('ul')
54593                 .attr('class', 'error-detail-list')
54594                 .selectAll('li')
54595                 .data(function(d) { return d.details || []; })
54596                 .enter()
54597                 .append('li')
54598                 .attr('class', 'error-detail-item')
54599                 .text(function(d) { return d; });
54600
54601             items.exit()
54602                 .remove();
54603         }
54604
54605     }
54606
54607
54608     function success(changeset) {
54609         commit.reset();
54610         context.enter(modeBrowse(context)
54611             .sidebar(uiSuccess(context)
54612                 .changeset(changeset)
54613                 .on('cancel', function() {
54614                     context.ui().sidebar.hide();
54615                 })
54616             )
54617         );
54618     }
54619
54620
54621     mode.enter = function() {
54622         function done() {
54623             context.ui().sidebar.show(commit);
54624         }
54625
54626         context.container().selectAll('#content')
54627             .attr('class', 'inactive');
54628
54629         if (context.connection().authenticated()) {
54630             done();
54631         } else {
54632             context.connection().authenticate(function(err) {
54633                 if (err) {
54634                     cancel();
54635                 } else {
54636                     done();
54637                 }
54638             });
54639         }
54640     };
54641
54642
54643     mode.exit = function() {
54644         context.container().selectAll('#content')
54645             .attr('class', 'active');
54646
54647         context.ui().sidebar.hide();
54648     };
54649
54650     return mode;
54651 }
54652
54653 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
54654 // For example, ⌘Z -> Ctrl+Z
54655 var uiCmd = function (code) {
54656     var detected = utilDetect();
54657
54658     if (detected.os === 'mac') {
54659         return code;
54660     }
54661
54662     if (detected.os === 'win') {
54663         if (code === '⌘⇧Z') return 'Ctrl+Y';
54664     }
54665
54666     var result = '',
54667         replacements = {
54668             '⌘': 'Ctrl',
54669             '⇧': 'Shift',
54670             '⌥': 'Alt',
54671             '⌫': 'Backspace',
54672             '⌦': 'Delete'
54673         };
54674
54675     for (var i = 0; i < code.length; i++) {
54676         if (code[i] in replacements) {
54677             result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
54678         } else {
54679             result += code[i];
54680         }
54681     }
54682
54683     return result;
54684 };
54685
54686
54687 // return a display-focused string for a given keyboard code
54688 uiCmd.display = function(code) {
54689     if (code.length !== 1) return code;
54690
54691     var detected = utilDetect();
54692     var mac = (detected.os === 'mac');
54693     var replacements = {
54694         '⌘': mac ? '⌘ ' + t('shortcuts.key.cmd')    : t('shortcuts.key.ctrl'),
54695         '⇧': mac ? '⇧ ' + t('shortcuts.key.shift')  : t('shortcuts.key.shift'),
54696         '⌥': mac ? '⌥ ' + t('shortcuts.key.option') : t('shortcuts.key.alt'),
54697         '⌃': mac ? '⌃ ' + t('shortcuts.key.ctrl')   : t('shortcuts.key.ctrl'),
54698         '⌫': mac ? '⌫ ' + t('shortcuts.key.delete') : t('shortcuts.key.backspace'),
54699         '⌦': mac ? '⌦ ' + t('shortcuts.key.del')    : t('shortcuts.key.del'),
54700         '↖': mac ? '↖ ' + t('shortcuts.key.pgup')   : t('shortcuts.key.pgup'),
54701         '↘': mac ? '↘ ' + t('shortcuts.key.pgdn')   : t('shortcuts.key.pgdn'),
54702         '⇞': mac ? '⇞ ' + t('shortcuts.key.home')   : t('shortcuts.key.home'),
54703         '⇟': mac ? '⇟ ' + t('shortcuts.key.end')    : t('shortcuts.key.end'),
54704         '↵': mac ? '↵ ' + t('shortcuts.key.return') : t('shortcuts.key.enter'),
54705         '⎋': mac ? '⎋ ' + t('shortcuts.key.esc')    : t('shortcuts.key.esc'),
54706     };
54707
54708     return replacements[code] || code;
54709 };
54710
54711 // deprecation warning - Radial Menu to be removed in iD v3
54712 var relatedParent;
54713
54714
54715 function modeSelect(context, selectedIDs) {
54716     var mode = {
54717         id: 'select',
54718         button: 'browse'
54719     };
54720
54721     var keybinding = d3keybinding('select'),
54722         timeout = null,
54723         behaviors = [
54724             behaviorCopy(context),
54725             behaviorPaste(context),
54726             behaviorBreathe(context),
54727             behaviorHover(context),
54728             behaviorSelect(context),
54729             behaviorLasso(context),
54730             modeDragNode$$1(context).selectedIDs(selectedIDs).behavior
54731         ],
54732         inspector,
54733         editMenu,
54734         newFeature = false,
54735         suppressMenu = true,
54736         follow = false;
54737
54738
54739     var wrap = context.container()
54740         .select('.inspector-wrap');
54741
54742
54743     function singular() {
54744         if (selectedIDs.length === 1) {
54745             return context.hasEntity(selectedIDs[0]);
54746         }
54747     }
54748
54749
54750     function checkSelectedIDs() {
54751         var ids = [];
54752         if (Array.isArray(selectedIDs)) {
54753             ids = selectedIDs.filter(function(id) {
54754                 return context.hasEntity(id);
54755             });
54756         }
54757
54758         if (ids.length) {
54759             selectedIDs = ids;
54760         } else {
54761             context.enter(modeBrowse(context));
54762         }
54763         return !!ids.length;
54764     }
54765
54766
54767     // find the common parent ways for nextVertex, previousVertex
54768     function commonParents() {
54769         var graph = context.graph(),
54770             commonParents = [];
54771
54772         for (var i = 0; i < selectedIDs.length; i++) {
54773             var entity = context.hasEntity(selectedIDs[i]);
54774             if (!entity || entity.geometry(graph) !== 'vertex') {
54775                 return [];  // selection includes some not vertexes
54776             }
54777
54778             var currParents = lodash.map(graph.parentWays(entity), 'id');
54779             if (!commonParents.length) {
54780                 commonParents = currParents;
54781                 continue;
54782             }
54783
54784             commonParents = lodash.intersection(commonParents, currParents);
54785             if (!commonParents.length) {
54786                 return [];
54787             }
54788         }
54789
54790         return commonParents;
54791     }
54792
54793
54794     function singularParent() {
54795         var parents = commonParents();
54796         if (!parents || parents.length === 0) {
54797             relatedParent = null;
54798             return null;
54799         }
54800
54801         // relatedParent is used when we visit a vertex with multiple
54802         // parents, and we want to remember which parent line we started on.
54803
54804         if (parents.length === 1) {
54805             relatedParent = parents[0];  // remember this parent for later
54806             return relatedParent;
54807         }
54808
54809         if (parents.indexOf(relatedParent) !== -1) {
54810             return relatedParent;   // prefer the previously seen parent
54811         }
54812
54813         return parents[0];
54814     }
54815
54816
54817     function closeMenu() {
54818         if (editMenu) {
54819             context.surface().call(editMenu.close);
54820         }
54821     }
54822
54823
54824     function positionMenu() {
54825         if (!editMenu) { return; }
54826
54827         var entity = singular();
54828         if (entity && context.geometry(entity.id) === 'relation') {
54829             suppressMenu = true;
54830         } else {
54831             var point = context.mouse(),
54832                 viewport = geoExtent$$1(context.projection.clipExtent()).polygon();
54833
54834             if (point && geoPointInPolygon(point, viewport)) {
54835                 editMenu.center(point);
54836             } else {
54837                 suppressMenu = true;
54838             }
54839         }
54840     }
54841
54842
54843     function showMenu() {
54844         closeMenu();
54845         if (editMenu) {
54846             context.surface().call(editMenu);
54847         }
54848     }
54849
54850
54851     function toggleMenu() {
54852         // deprecation warning - Radial Menu to be removed in iD v3
54853         if (select('.edit-menu, .radial-menu').empty()) {
54854             positionMenu();
54855             showMenu();
54856         } else {
54857             closeMenu();
54858         }
54859     }
54860
54861
54862     mode.selectedIDs = function() {
54863         return selectedIDs;
54864     };
54865
54866
54867     mode.reselect = function() {
54868         if (!checkSelectedIDs()) return;
54869
54870         var surfaceNode = context.surface().node();
54871         if (surfaceNode.focus) {   // FF doesn't support it
54872             surfaceNode.focus();
54873         }
54874
54875         positionMenu();
54876         if (!suppressMenu) {
54877             showMenu();
54878         }
54879     };
54880
54881
54882     mode.newFeature = function(_) {
54883         if (!arguments.length) return newFeature;
54884         newFeature = _;
54885         return mode;
54886     };
54887
54888
54889     mode.suppressMenu = function(_) {
54890         if (!arguments.length) return suppressMenu;
54891         suppressMenu = _;
54892         return mode;
54893     };
54894
54895
54896     mode.follow = function(_) {
54897         if (!arguments.length) return follow;
54898         follow = _;
54899         return mode;
54900     };
54901
54902
54903     mode.enter = function() {
54904
54905         function update() {
54906             closeMenu();
54907             checkSelectedIDs();
54908         }
54909
54910
54911         function dblclick() {
54912             var target = select(event.target),
54913                 datum = target.datum();
54914
54915             if (datum instanceof osmWay && !target.classed('fill')) {
54916                 var choice = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection),
54917                     prev = datum.nodes[choice.index - 1],
54918                     next = datum.nodes[choice.index];
54919
54920                 context.perform(
54921                     actionAddMidpoint({loc: choice.loc, edge: [prev, next]}, osmNode()),
54922                     t('operations.add.annotation.vertex')
54923                 );
54924
54925                 event.preventDefault();
54926                 event.stopPropagation();
54927
54928             } else if (datum.type === 'midpoint') {
54929                 context.perform(
54930                     actionAddMidpoint({loc: datum.loc, edge: datum.edge}, osmNode()),
54931                     t('operations.add.annotation.vertex'));
54932
54933                 event.preventDefault();
54934                 event.stopPropagation();
54935             }
54936         }
54937
54938
54939         function selectElements(drawn) {
54940             if (!checkSelectedIDs()) return;
54941
54942             var surface = context.surface(),
54943                 entity = singular();
54944
54945             if (entity && context.geometry(entity.id) === 'relation') {
54946                 suppressMenu = true;
54947                 return;
54948             }
54949
54950             surface.selectAll('.related')
54951                 .classed('related', false);
54952
54953             singularParent();
54954             if (relatedParent) {
54955                 surface.selectAll(utilEntitySelector([relatedParent]))
54956                     .classed('related', true);
54957             }
54958
54959             var selection$$1 = context.surface()
54960                 .selectAll(utilEntityOrMemberSelector(selectedIDs, context.graph()));
54961
54962             if (selection$$1.empty()) {
54963                 // Return to browse mode if selected DOM elements have
54964                 // disappeared because the user moved them out of view..
54965                 var source = event && event.type === 'zoom' && event.sourceEvent;
54966                 if (drawn && source && (source.type === 'mousemove' || source.type === 'touchmove')) {
54967                     context.enter(modeBrowse(context));
54968                 }
54969             } else {
54970                 selection$$1
54971                     .classed('selected', true);
54972             }
54973         }
54974
54975
54976         function esc() {
54977             context.enter(modeBrowse(context));
54978         }
54979
54980
54981         function firstVertex() {
54982             event.preventDefault();
54983             var parent = singularParent();
54984             if (parent) {
54985                 var way = context.entity(parent);
54986                 context.enter(
54987                     modeSelect(context, [way.first()]).follow(true)
54988                 );
54989             }
54990         }
54991
54992
54993         function lastVertex() {
54994             event.preventDefault();
54995             var parent = singularParent();
54996             if (parent) {
54997                 var way = context.entity(parent);
54998                 context.enter(
54999                     modeSelect(context, [way.last()]).follow(true)
55000                 );
55001             }
55002         }
55003
55004
55005         function previousVertex() {
55006             event.preventDefault();
55007             var parent = singularParent();
55008             if (!parent) return;
55009
55010             var way = context.entity(parent),
55011                 length = way.nodes.length,
55012                 curr = way.nodes.indexOf(selectedIDs[0]),
55013                 index = -1;
55014
55015             if (curr > 0) {
55016                 index = curr - 1;
55017             } else if (way.isClosed()) {
55018                 index = length - 2;
55019             }
55020
55021             if (index !== -1) {
55022                 context.enter(
55023                     modeSelect(context, [way.nodes[index]]).follow(true)
55024                 );
55025             }
55026         }
55027
55028
55029         function nextVertex() {
55030             event.preventDefault();
55031             var parent = singularParent();
55032             if (!parent) return;
55033
55034             var way = context.entity(parent),
55035                 length = way.nodes.length,
55036                 curr = way.nodes.indexOf(selectedIDs[0]),
55037                 index = -1;
55038
55039             if (curr < length - 1) {
55040                 index = curr + 1;
55041             } else if (way.isClosed()) {
55042                 index = 0;
55043             }
55044
55045             if (index !== -1) {
55046                 context.enter(
55047                     modeSelect(context, [way.nodes[index]]).follow(true)
55048                 );
55049             }
55050         }
55051
55052
55053         function nextParent() {
55054             event.preventDefault();
55055             var parents = lodash.uniq(commonParents());
55056             if (!parents || parents.length < 2) return;
55057
55058             var index = parents.indexOf(relatedParent);
55059             if (index < 0 || index > parents.length - 2) {
55060                 relatedParent = parents[0];
55061             } else {
55062                 relatedParent = parents[index + 1];
55063             }
55064
55065             var surface = context.surface();
55066             surface.selectAll('.related')
55067                 .classed('related', false);
55068
55069             if (relatedParent) {
55070                 surface.selectAll(utilEntitySelector([relatedParent]))
55071                     .classed('related', true);
55072             }
55073         }
55074
55075
55076         if (!checkSelectedIDs()) return;
55077
55078         var operations = lodash.without(values(Operations), operationDelete)
55079                 .map(function(o) { return o(selectedIDs, context); })
55080                 .filter(function(o) { return o.available(); });
55081
55082         // deprecation warning - Radial Menu to be removed in iD v3
55083         var isRadialMenu = context.storage('edit-menu-style') === 'radial';
55084         if (isRadialMenu) {
55085             operations = operations.slice(0,7);
55086             operations.unshift(operationDelete(selectedIDs, context));
55087         } else {
55088             operations.push(operationDelete(selectedIDs, context));
55089         }
55090
55091         operations.forEach(function(operation) {
55092             if (operation.behavior) {
55093                 behaviors.push(operation.behavior);
55094             }
55095         });
55096
55097         behaviors.forEach(function(behavior) {
55098             context.install(behavior);
55099         });
55100
55101         keybinding
55102             .on(['[', 'pgup'], previousVertex)
55103             .on([']', 'pgdown'], nextVertex)
55104             .on(['{', uiCmd('⌘['), 'home'], firstVertex)
55105             .on(['}', uiCmd('⌘]'), 'end'], lastVertex)
55106             .on(['\\', 'pause'], nextParent)
55107             .on('⎋', esc, true)
55108             .on('space', toggleMenu);
55109
55110         select(document)
55111             .call(keybinding);
55112
55113
55114         // deprecation warning - Radial Menu to be removed in iD v3
55115         editMenu = isRadialMenu
55116             ? uiRadialMenu(context, operations)
55117             : uiEditMenu(context, operations);
55118
55119         context.ui().sidebar
55120             .select(singular() ? singular().id : null, newFeature);
55121
55122         context.history()
55123             .on('undone.select', update)
55124             .on('redone.select', update);
55125
55126         context.map()
55127             .on('move.select', closeMenu)
55128             .on('drawn.select', selectElements);
55129
55130         context.surface()
55131             .on('dblclick.select', dblclick);
55132
55133
55134         selectElements();
55135
55136         if (selectedIDs.length > 1) {
55137             var entities = uiSelectionList(context, selectedIDs);
55138             context.ui().sidebar.show(entities);
55139         }
55140
55141         if (follow) {
55142             var extent$$1 = geoExtent$$1(),
55143                 graph = context.graph();
55144             selectedIDs.forEach(function(id) {
55145                 var entity = context.entity(id);
55146                 extent$$1._extend(entity.extent(graph));
55147             });
55148
55149             var loc = extent$$1.center();
55150             context.map().centerEase(loc);
55151         } else if (singular() && singular().type === 'way') {
55152             context.map().pan([0,0]);  // full redraw, to adjust z-sorting #2914
55153         }
55154
55155         timeout = window.setTimeout(function() {
55156             positionMenu();
55157             if (!suppressMenu) {
55158                 showMenu();
55159             }
55160         }, 270);  /* after any centerEase completes */
55161
55162     };
55163
55164
55165     mode.exit = function() {
55166         if (timeout) window.clearTimeout(timeout);
55167
55168         if (inspector) wrap.call(inspector.close);
55169
55170         behaviors.forEach(function(behavior) {
55171             context.uninstall(behavior);
55172         });
55173
55174         keybinding.off();
55175         closeMenu();
55176         editMenu = undefined;
55177
55178         context.history()
55179             .on('undone.select', null)
55180             .on('redone.select', null);
55181
55182         var surface = context.surface();
55183
55184         surface
55185             .on('dblclick.select', null);
55186
55187         surface
55188             .selectAll('.selected')
55189             .classed('selected', false);
55190
55191         surface
55192             .selectAll('.related')
55193             .classed('related', false);
55194
55195         context.map().on('drawn.select', null);
55196         context.ui().sidebar.hide();
55197     };
55198
55199
55200     return mode;
55201 }
55202
55203 function uiAccount(context) {
55204     var connection = context.connection();
55205
55206
55207     function update(selection$$1) {
55208         if (!connection.authenticated()) {
55209             selection$$1.selectAll('#userLink, #logoutLink')
55210                 .classed('hide', true);
55211             return;
55212         }
55213
55214         connection.userDetails(function(err, details) {
55215             var userLink = selection$$1.select('#userLink'),
55216                 logoutLink = selection$$1.select('#logoutLink');
55217
55218             userLink.html('');
55219             logoutLink.html('');
55220
55221             if (err) return;
55222
55223             selection$$1.selectAll('#userLink, #logoutLink')
55224                 .classed('hide', false);
55225
55226             // Link
55227             userLink.append('a')
55228                 .attr('href', connection.userURL(details.display_name))
55229                 .attr('target', '_blank');
55230
55231             // Add thumbnail or dont
55232             if (details.image_url) {
55233                 userLink.append('img')
55234                     .attr('class', 'icon pre-text user-icon')
55235                     .attr('src', details.image_url);
55236             } else {
55237                 userLink
55238                     .call(svgIcon('#icon-avatar', 'pre-text light'));
55239             }
55240
55241             // Add user name
55242             userLink.append('span')
55243                 .attr('class', 'label')
55244                 .text(details.display_name);
55245
55246             logoutLink.append('a')
55247                 .attr('class', 'logout')
55248                 .attr('href', '#')
55249                 .text(t('logout'))
55250                 .on('click.logout', function() {
55251                     event.preventDefault();
55252                     connection.logout();
55253                 });
55254         });
55255     }
55256
55257
55258     return function(selection$$1) {
55259         selection$$1.append('li')
55260             .attr('id', 'logoutLink')
55261             .classed('hide', true);
55262
55263         selection$$1.append('li')
55264             .attr('id', 'userLink')
55265             .classed('hide', true);
55266
55267         connection
55268             .on('change.account', function() { update(selection$$1); });
55269
55270         update(selection$$1);
55271     };
55272 }
55273
55274 function uiAttribution(context) {
55275     var selection$$1;
55276
55277
55278     function attribution(data, klass) {
55279         var div = selection$$1.selectAll('.' + klass)
55280             .data([0]);
55281
55282         div = div.enter()
55283             .append('div')
55284             .attr('class', klass)
55285             .merge(div);
55286
55287
55288         var background = div.selectAll('.attribution')
55289             .data(data, function(d) { return d.name(); });
55290
55291         background.exit()
55292             .remove();
55293
55294         background = background.enter()
55295             .append('span')
55296             .attr('class', 'attribution')
55297             .each(function(d) {
55298                 if (d.terms_html) {
55299                     select(this)
55300                         .html(d.terms_html);
55301                     return;
55302                 }
55303
55304                 var selection$$1;
55305                 if (d.terms_url) {
55306                     selection$$1 = select(this)
55307                         .append('a')
55308                         .attr('href', d.terms_url)
55309                         .attr('target', '_blank');
55310                 } else {
55311                     selection$$1 = select(this);
55312                 }
55313
55314
55315                 var id_safe = d.id.replace('.', '<TX_DOT>');
55316                 var terms_text = t('imagery.' + id_safe + '.attribution.text',
55317                     { default: d.terms_text || d.id || d.name() }
55318                 );
55319
55320                 if (d.icon && !d.overlay) {
55321                     selection$$1
55322                         .append('img')
55323                         .attr('class', 'source-image')
55324                         .attr('src', d.icon);
55325                 }
55326
55327                 selection$$1
55328                     .append('span')
55329                     .attr('class', 'attribution-text')
55330                     .text(terms_text);
55331             })
55332             .merge(background);
55333
55334
55335         var copyright = background.selectAll('.copyright-notice')
55336             .data(function(d) {
55337                 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
55338                 return notice ? [notice] : [];
55339             });
55340
55341         copyright.exit()
55342             .remove();
55343
55344         copyright = copyright.enter()
55345             .append('span')
55346             .attr('class', 'copyright-notice')
55347             .merge(copyright);
55348
55349         copyright
55350             .text(String);
55351     }
55352
55353
55354     function update() {
55355         attribution([context.background().baseLayerSource()], 'base-layer-attribution');
55356         attribution(context.background().overlayLayerSources().filter(function (s) {
55357             return s.validZoom(context.map().zoom());
55358         }), 'overlay-layer-attribution');
55359     }
55360
55361
55362     return function(select$$1) {
55363         selection$$1 = select$$1;
55364
55365         context.background()
55366             .on('change.attribution', update);
55367
55368         context.map()
55369             .on('move.attribution', lodash.throttle(update, 400, {leading: false}));
55370
55371         update();
55372     };
55373 }
55374
55375 function localeDateString(s) {
55376     if (!s) return null;
55377     var d = new Date(s);
55378     if (isNaN(d.getTime())) return null;
55379     return d.toLocaleDateString();
55380 }
55381
55382 function vintageRange(vintage) {
55383     var s;
55384     if (vintage.start || vintage.end) {
55385         s = (vintage.start || '?');
55386         if (vintage.start !== vintage.end) {
55387             s += ' - ' + (vintage.end || '?');
55388         }
55389     }
55390     return s;
55391 }
55392
55393
55394 function rendererBackgroundSource(data) {
55395     var source = lodash.clone(data),
55396         offset = [0, 0],
55397         name = source.name,
55398         description = source.description,
55399         best = !!source.best;
55400
55401     source.scaleExtent = data.scaleExtent || [0, 20];
55402     source.overzoom = data.overzoom !== false;
55403
55404
55405     source.offset = function(_) {
55406         if (!arguments.length) return offset;
55407         offset = _;
55408         return source;
55409     };
55410
55411
55412     source.nudge = function(_, zoomlevel) {
55413         offset[0] += _[0] / Math.pow(2, zoomlevel);
55414         offset[1] += _[1] / Math.pow(2, zoomlevel);
55415         return source;
55416     };
55417
55418
55419     source.name = function() {
55420         var id_safe = source.id.replace('.', '<TX_DOT>');
55421         return t('imagery.' + id_safe + '.name', { default: name });
55422     };
55423
55424
55425     source.description = function() {
55426         var id_safe = source.id.replace('.', '<TX_DOT>');
55427         return t('imagery.' + id_safe + '.description', { default: description });
55428     };
55429
55430
55431     source.best = function() {
55432         return best;
55433     };
55434
55435
55436     source.area = function() {
55437         if (!data.polygon) return Number.MAX_VALUE;  // worldwide
55438         var area$$1 = area({ type: 'MultiPolygon', coordinates: [ data.polygon ] });
55439         return isNaN(area$$1) ? 0 : area$$1;
55440     };
55441
55442
55443     source.imageryUsed = function() {
55444         return name || source.id;
55445     };
55446
55447
55448     source.url = function(coord) {
55449         return data.template
55450             .replace('{x}', coord[0])
55451             .replace('{y}', coord[1])
55452             // TMS-flipped y coordinate
55453             .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
55454             .replace(/\{z(oom)?\}/, coord[2])
55455             .replace(/\{switch:([^}]+)\}/, function(s, r) {
55456                 var subdomains = r.split(',');
55457                 return subdomains[(coord[0] + coord[1]) % subdomains.length];
55458             })
55459             .replace('{u}', function() {
55460                 var u = '';
55461                 for (var zoom$$1 = coord[2]; zoom$$1 > 0; zoom$$1--) {
55462                     var b = 0;
55463                     var mask = 1 << (zoom$$1 - 1);
55464                     if ((coord[0] & mask) !== 0) b++;
55465                     if ((coord[1] & mask) !== 0) b += 2;
55466                     u += b.toString();
55467                 }
55468                 return u;
55469             });
55470     };
55471
55472
55473     source.intersects = function(extent$$1) {
55474         extent$$1 = extent$$1.polygon();
55475         return !data.polygon || data.polygon.some(function(polygon) {
55476             return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
55477         });
55478     };
55479
55480
55481     source.validZoom = function(z) {
55482         return source.scaleExtent[0] <= z &&
55483             (source.overzoom || source.scaleExtent[1] > z);
55484     };
55485
55486
55487     source.isLocatorOverlay = function() {
55488         return source.id === 'mapbox_locator_overlay';
55489     };
55490
55491
55492     source.copyrightNotices = function() {};
55493
55494
55495     source.getVintage = function(center, tileCoord, callback) {
55496         var vintage = {
55497             start: localeDateString(source.startDate),
55498             end: localeDateString(source.endDate)
55499         };
55500         vintage.range = vintageRange(vintage);
55501         callback(null, vintage);
55502     };
55503
55504
55505     return source;
55506 }
55507
55508
55509 rendererBackgroundSource.Bing = function(data, dispatch$$1) {
55510     // http://msdn.microsoft.com/en-us/library/ff701716.aspx
55511     // http://msdn.microsoft.com/en-us/library/ff701701.aspx
55512
55513     data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
55514
55515     var bing = rendererBackgroundSource(data),
55516         key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
55517         url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
55518             key + '&jsonp={callback}',
55519         cache = {},
55520         providers = [];
55521
55522     jsonpRequest(url, function(json$$1) {
55523         providers = json$$1.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
55524             return {
55525                 attribution: provider.attribution,
55526                 areas: provider.coverageAreas.map(function(area$$1) {
55527                     return {
55528                         zoom: [area$$1.zoomMin, area$$1.zoomMax],
55529                         extent: geoExtent$$1([area$$1.bbox[1], area$$1.bbox[0]], [area$$1.bbox[3], area$$1.bbox[2]])
55530                     };
55531                 })
55532             };
55533         });
55534         dispatch$$1.call('change');
55535     });
55536
55537
55538     bing.copyrightNotices = function(zoom$$1, extent$$1) {
55539         zoom$$1 = Math.min(zoom$$1, 21);
55540         return providers.filter(function(provider) {
55541             return lodash.some(provider.areas, function(area$$1) {
55542                 return extent$$1.intersects(area$$1.extent) &&
55543                     area$$1.zoom[0] <= zoom$$1 &&
55544                     area$$1.zoom[1] >= zoom$$1;
55545             });
55546         }).map(function(provider) {
55547             return provider.attribution;
55548         }).join(', ');
55549     };
55550
55551
55552     bing.getVintage = function(center, tileCoord, callback) {
55553         var tileId = tileCoord.slice(0, 3).join('/'),
55554             zoom$$1 = Math.min(tileCoord[2], 21),
55555             centerPoint = center[1] + ',' + center[0],  // lat,lng
55556             url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint +
55557                 '?zl=' + zoom$$1 + '&key=' + key + '&jsonp={callback}';
55558
55559         if (!cache[tileId]) {
55560             cache[tileId] = {};
55561         }
55562         if (cache[tileId] && cache[tileId].vintage) {
55563             return callback(null, cache[tileId].vintage);
55564         }
55565
55566         jsonpRequest(url, function(result) {
55567             var err = (!result && 'Unknown Error') || result.errorDetails;
55568             if (err) {
55569                 return callback(err);
55570             } else {
55571                 var vintage = {
55572                     start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
55573                     end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
55574                 };
55575                 vintage.range = vintageRange(vintage);
55576                 cache[tileId].vintage = vintage;
55577                 return callback(null, vintage);
55578             }
55579         });
55580     };
55581
55582
55583     bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
55584
55585
55586     return bing;
55587 };
55588
55589
55590 rendererBackgroundSource.None = function() {
55591     var source = rendererBackgroundSource({ id: 'none', template: '' });
55592
55593
55594     source.name = function() {
55595         return t('background.none');
55596     };
55597
55598
55599     source.imageryUsed = function() {
55600         return 'None';
55601     };
55602
55603
55604     source.area = function() {
55605         return -1;  // sources in background pane are sorted by area
55606     };
55607
55608
55609     return source;
55610 };
55611
55612
55613 rendererBackgroundSource.Custom = function(template) {
55614     var source = rendererBackgroundSource({ id: 'custom', template: template });
55615
55616
55617     source.name = function() {
55618         return t('background.custom');
55619     };
55620
55621
55622     source.imageryUsed = function() {
55623         return 'Custom (' + template + ')';
55624     };
55625
55626
55627     source.area = function() {
55628         return -2;  // sources in background pane are sorted by area
55629     };
55630
55631
55632     return source;
55633 };
55634
55635 function rendererTileLayer(context) {
55636     var tileSize = 256,
55637         tile = d3geoTile(),
55638         projection$$1,
55639         cache = {},
55640         tileOrigin,
55641         z,
55642         transformProp = utilPrefixCSSProperty('Transform'),
55643         source = rendererBackgroundSource.None();
55644
55645
55646     // blacklist overlay tiles around Null Island..
55647     function nearNullIsland(x, y, z) {
55648         if (z >= 7) {
55649             var center = Math.pow(2, z - 1),
55650                 width = Math.pow(2, z - 6),
55651                 min$$1 = center - (width / 2),
55652                 max$$1 = center + (width / 2) - 1;
55653             return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
55654         }
55655         return false;
55656     }
55657
55658
55659     function tileSizeAtZoom(d, z) {
55660         var epsilon = 0.002;
55661         return ((tileSize * Math.pow(2, z - d[2])) / tileSize) + epsilon;
55662     }
55663
55664
55665     function atZoom(t$$1, distance$$1) {
55666         var power = Math.pow(2, distance$$1);
55667         return [
55668             Math.floor(t$$1[0] * power),
55669             Math.floor(t$$1[1] * power),
55670             t$$1[2] + distance$$1];
55671     }
55672
55673
55674     function lookUp(d) {
55675         for (var up = -1; up > -d[2]; up--) {
55676             var tile = atZoom(d, up);
55677             if (cache[source.url(tile)] !== false) {
55678                 return tile;
55679             }
55680         }
55681     }
55682
55683
55684     function uniqueBy(a, n) {
55685         var o = [], seen = {};
55686         for (var i = 0; i < a.length; i++) {
55687             if (seen[a[i][n]] === undefined) {
55688                 o.push(a[i]);
55689                 seen[a[i][n]] = true;
55690             }
55691         }
55692         return o;
55693     }
55694
55695
55696     function addSource(d) {
55697         d.push(source.url(d));
55698         return d;
55699     }
55700
55701
55702     // Update tiles based on current state of `projection`.
55703     function background(selection$$1) {
55704         tile.scale(projection$$1.scale() * 2 * Math.PI)
55705             .translate(projection$$1.translate());
55706
55707         tileOrigin = [
55708             projection$$1.scale() * Math.PI - projection$$1.translate()[0],
55709             projection$$1.scale() * Math.PI - projection$$1.translate()[1]];
55710
55711         z = Math.max(Math.log(projection$$1.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
55712
55713         render(selection$$1);
55714     }
55715
55716
55717     // Derive the tiles onscreen, remove those offscreen and position them.
55718     // Important that this part not depend on `projection` because it's
55719     // rentered when tiles load/error (see #644).
55720     function render(selection$$1) {
55721         var requests = [];
55722         var showDebug = context.getDebug('tile') && !source.overlay;
55723
55724         if (source.validZoom(z)) {
55725             tile().forEach(function(d) {
55726                 addSource(d);
55727                 if (d[3] === '') return;
55728                 if (typeof d[3] !== 'string') return; // Workaround for #2295
55729                 requests.push(d);
55730                 if (cache[d[3]] === false && lookUp(d)) {
55731                     requests.push(addSource(lookUp(d)));
55732                 }
55733             });
55734
55735             requests = uniqueBy(requests, 3).filter(function(r) {
55736                 if (!!source.overlay && nearNullIsland(r[0], r[1], r[2])) {
55737                     return false;
55738                 }
55739                 // don't re-request tiles which have failed in the past
55740                 return cache[r[3]] !== false;
55741             });
55742         }
55743
55744         var pixelOffset = [
55745             source.offset()[0] * Math.pow(2, z),
55746             source.offset()[1] * Math.pow(2, z)
55747         ];
55748
55749
55750         function load(d) {
55751             cache[d[3]] = true;
55752             select(this)
55753                 .on('error', null)
55754                 .on('load', null)
55755                 .classed('tile-loaded', true);
55756             render(selection$$1);
55757         }
55758
55759         function error(d) {
55760             cache[d[3]] = false;
55761             select(this)
55762                 .on('error', null)
55763                 .on('load', null)
55764                 .remove();
55765             render(selection$$1);
55766         }
55767
55768         function imageTransform(d) {
55769             var _ts = tileSize * Math.pow(2, z - d[2]);
55770             var scale = tileSizeAtZoom(d, z);
55771             return 'translate(' +
55772                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
55773                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
55774                 'scale(' + scale + ',' + scale + ')';
55775         }
55776
55777         function tileCenter(d) {
55778             var _ts = tileSize * Math.pow(2, z - d[2]);
55779             return [
55780                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0] + (_ts / 2)),
55781                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1] + (_ts / 2))
55782             ];
55783         }
55784
55785         function debugTransform(d) {
55786             var coord = tileCenter(d);
55787             return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
55788         }
55789
55790
55791         // Pick a representative tile near the center of the viewport
55792         // (This is useful for sampling the imagery vintage)
55793         var dims = tile.size(),
55794             mapCenter = [dims[0] / 2, dims[1] / 2],
55795             minDist = Math.max(dims[0], dims[1]),
55796             nearCenter;
55797
55798         requests.forEach(function(d) {
55799             var c = tileCenter(d);
55800             var dist = geoEuclideanDistance(c, mapCenter);
55801             if (dist < minDist) {
55802                 minDist = dist;
55803                 nearCenter = d;
55804             }
55805         });
55806
55807
55808         var image = selection$$1.selectAll('img')
55809             .data(requests, function(d) { return d[3]; });
55810
55811         image.exit()
55812             .style(transformProp, imageTransform)
55813             .classed('tile-removing', true)
55814             .classed('tile-center', false)
55815             .each(function() {
55816                 var tile = select(this);
55817                 window.setTimeout(function() {
55818                     if (tile.classed('tile-removing')) {
55819                         tile.remove();
55820                     }
55821                 }, 300);
55822             });
55823
55824         image.enter()
55825           .append('img')
55826             .attr('class', 'tile')
55827             .attr('src', function(d) { return d[3]; })
55828             .on('error', error)
55829             .on('load', load)
55830           .merge(image)
55831             .style(transformProp, imageTransform)
55832             .classed('tile-debug', showDebug)
55833             .classed('tile-removing', false)
55834             .classed('tile-center', function(d) { return d === nearCenter; });
55835
55836
55837
55838         var debug = selection$$1.selectAll('.tile-label-debug')
55839             .data(showDebug ? requests : [], function(d) { return d[3]; });
55840
55841         debug.exit()
55842             .remove();
55843
55844         if (showDebug) {
55845             var debugEnter = debug.enter()
55846                 .append('div')
55847                 .attr('class', 'tile-label-debug');
55848
55849             debugEnter
55850                 .append('div')
55851                 .attr('class', 'tile-label-debug-coord');
55852
55853             debugEnter
55854                 .append('div')
55855                 .attr('class', 'tile-label-debug-vintage');
55856
55857             debug = debug.merge(debugEnter);
55858
55859             debug
55860                 .style(transformProp, debugTransform);
55861
55862             debug
55863                 .selectAll('.tile-label-debug-coord')
55864                 .text(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; });
55865
55866             debug
55867                 .selectAll('.tile-label-debug-vintage')
55868                 .each(function(d) {
55869                     var span = select(this);
55870                     var center = context.projection.invert(tileCenter(d));
55871                     source.getVintage(center, d, function(err, result) {
55872                         span.text((result && result.range) ||
55873                             t('info_panels.background.vintage') + ': ' + t('info_panels.background.unknown')
55874                         );
55875                     });
55876                 });
55877         }
55878
55879     }
55880
55881
55882     background.projection = function(_) {
55883         if (!arguments.length) return projection$$1;
55884         projection$$1 = _;
55885         return background;
55886     };
55887
55888
55889     background.dimensions = function(_) {
55890         if (!arguments.length) return tile.size();
55891         tile.size(_);
55892         return background;
55893     };
55894
55895
55896     background.source = function(_) {
55897         if (!arguments.length) return source;
55898         source = _;
55899         cache = {};
55900         tile.scaleExtent(source.scaleExtent);
55901         return background;
55902     };
55903
55904
55905     return background;
55906 }
55907
55908 function rendererBackground(context) {
55909     var dispatch$$1 = dispatch('change'),
55910         baseLayer = rendererTileLayer(context).projection(context.projection),
55911         overlayLayers = [],
55912         backgroundSources;
55913
55914
55915     function findSource(id) {
55916         return lodash.find(backgroundSources, function(d) {
55917             return d.id && d.id === id;
55918         });
55919     }
55920
55921
55922     function background(selection$$1) {
55923         var base = selection$$1.selectAll('.layer-background')
55924             .data([0]);
55925
55926         base.enter()
55927             .insert('div', '.layer-data')
55928             .attr('class', 'layer layer-background')
55929             .merge(base)
55930             .call(baseLayer);
55931
55932         var overlays = selection$$1.selectAll('.layer-overlay')
55933             .data(overlayLayers, function(d) { return d.source().name(); });
55934
55935         overlays.exit()
55936             .remove();
55937
55938         overlays.enter()
55939             .insert('div', '.layer-data')
55940             .attr('class', 'layer layer-overlay')
55941             .merge(overlays)
55942             .each(function(layer) { select(this).call(layer); });
55943     }
55944
55945
55946     background.updateImagery = function() {
55947         if (context.inIntro()) return;
55948
55949         var b = background.baseLayerSource(),
55950             o = overlayLayers
55951                 .filter(function (d) { return !d.source().isLocatorOverlay(); })
55952                 .map(function (d) { return d.source().id; })
55953                 .join(','),
55954             meters = geoOffsetToMeters(b.offset()),
55955             epsilon = 0.01,
55956             x = +meters[0].toFixed(2),
55957             y = +meters[1].toFixed(2),
55958             q = utilStringQs(window.location.hash.substring(1));
55959
55960         var id = b.id;
55961         if (id === 'custom') {
55962             id = 'custom:' + b.template;
55963         }
55964
55965         if (id) {
55966             q.background = id;
55967         } else {
55968             delete q.background;
55969         }
55970
55971         if (o) {
55972             q.overlays = o;
55973         } else {
55974             delete q.overlays;
55975         }
55976
55977         if (Math.abs(x) > epsilon || Math.abs(y) > epsilon) {
55978             q.offset = x + ',' + y;
55979         } else {
55980             delete q.offset;
55981         }
55982
55983         window.location.replace('#' + utilQsString(q, true));
55984
55985         var imageryUsed = [b.imageryUsed()];
55986
55987         overlayLayers
55988             .filter(function (d) { return !d.source().isLocatorOverlay(); })
55989             .forEach(function (d) { imageryUsed.push(d.source().imageryUsed()); });
55990
55991         var gpx = context.layers().layer('gpx');
55992         if (gpx && gpx.enabled() && gpx.hasGpx()) {
55993             imageryUsed.push('Local GPX');
55994         }
55995
55996         var mapillary_images = context.layers().layer('mapillary-images');
55997         if (mapillary_images && mapillary_images.enabled()) {
55998             imageryUsed.push('Mapillary Images');
55999         }
56000
56001         var mapillary_signs = context.layers().layer('mapillary-signs');
56002         if (mapillary_signs && mapillary_signs.enabled()) {
56003             imageryUsed.push('Mapillary Signs');
56004         }
56005
56006         context.history().imageryUsed(imageryUsed);
56007     };
56008
56009
56010     background.sources = function(extent$$1) {
56011         return backgroundSources.filter(function(source) {
56012             return source.intersects(extent$$1);
56013         });
56014     };
56015
56016
56017     background.dimensions = function(_) {
56018         if (!_) return;
56019         baseLayer.dimensions(_);
56020
56021         overlayLayers.forEach(function(layer) {
56022             layer.dimensions(_);
56023         });
56024     };
56025
56026
56027     background.baseLayerSource = function(d) {
56028         if (!arguments.length) return baseLayer.source();
56029
56030         // test source against OSM imagery blacklists..
56031         var blacklists = context.connection().imageryBlacklists();
56032
56033         var fail = false,
56034             tested = 0,
56035             regex, i;
56036
56037         for (i = 0; i < blacklists.length; i++) {
56038             try {
56039                 regex = new RegExp(blacklists[i]);
56040                 fail = regex.test(d.template);
56041                 tested++;
56042                 if (fail) break;
56043             } catch (e) {
56044                 /* noop */
56045             }
56046         }
56047
56048         // ensure at least one test was run.
56049         if (!tested) {
56050             regex = new RegExp('.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*');
56051             fail = regex.test(d.template);
56052         }
56053
56054         baseLayer.source(!fail ? d : rendererBackgroundSource.None());
56055         dispatch$$1.call('change');
56056         background.updateImagery();
56057         return background;
56058     };
56059
56060
56061     background.bing = function() {
56062         background.baseLayerSource(findSource('Bing'));
56063     };
56064
56065
56066     background.showsLayer = function(d) {
56067         return d.id === baseLayer.source().id ||
56068             overlayLayers.some(function(layer) { return d.id === layer.source().id; });
56069     };
56070
56071
56072     background.overlayLayerSources = function() {
56073         return overlayLayers.map(function (l) { return l.source(); });
56074     };
56075
56076
56077     background.toggleOverlayLayer = function(d) {
56078         var layer;
56079
56080         for (var i = 0; i < overlayLayers.length; i++) {
56081             layer = overlayLayers[i];
56082             if (layer.source() === d) {
56083                 overlayLayers.splice(i, 1);
56084                 dispatch$$1.call('change');
56085                 background.updateImagery();
56086                 return;
56087             }
56088         }
56089
56090         layer = rendererTileLayer(context)
56091             .source(d)
56092             .projection(context.projection)
56093             .dimensions(baseLayer.dimensions());
56094
56095         overlayLayers.push(layer);
56096         dispatch$$1.call('change');
56097         background.updateImagery();
56098     };
56099
56100
56101     background.nudge = function(d, zoom$$1) {
56102         baseLayer.source().nudge(d, zoom$$1);
56103         dispatch$$1.call('change');
56104         background.updateImagery();
56105         return background;
56106     };
56107
56108
56109     background.offset = function(d) {
56110         if (!arguments.length) return baseLayer.source().offset();
56111         baseLayer.source().offset(d);
56112         dispatch$$1.call('change');
56113         background.updateImagery();
56114         return background;
56115     };
56116
56117
56118     background.init = function() {
56119         function parseMap(qmap) {
56120             if (!qmap) return false;
56121             var args = qmap.split('/').map(Number);
56122             if (args.length < 3 || args.some(isNaN)) return false;
56123             return geoExtent$$1([args[2], args[1]]);
56124         }
56125
56126         var dataImagery = data.imagery || [],
56127             q = utilStringQs(window.location.hash.substring(1)),
56128             chosen = q.background || q.layer,
56129             extent$$1 = parseMap(q.map),
56130             best;
56131
56132         backgroundSources = dataImagery.map(function(source) {
56133             if (source.type === 'bing') {
56134                 return rendererBackgroundSource.Bing(source, dispatch$$1);
56135             } else {
56136                 return rendererBackgroundSource(source);
56137             }
56138         });
56139
56140         backgroundSources.unshift(rendererBackgroundSource.None());
56141
56142         if (!chosen && extent$$1) {
56143             best = lodash.find(this.sources(extent$$1), function(s) { return s.best(); });
56144         }
56145
56146         if (chosen && chosen.indexOf('custom:') === 0) {
56147             background.baseLayerSource(rendererBackgroundSource.Custom(chosen.replace(/^custom:/, '')));
56148         } else {
56149             background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
56150         }
56151
56152         var locator = lodash.find(backgroundSources, function(d) {
56153             return d.overlay && d.default;
56154         });
56155
56156         if (locator) {
56157             background.toggleOverlayLayer(locator);
56158         }
56159
56160         var overlays = (q.overlays || '').split(',');
56161         overlays.forEach(function(overlay) {
56162             overlay = findSource(overlay);
56163             if (overlay) {
56164                 background.toggleOverlayLayer(overlay);
56165             }
56166         });
56167
56168         if (q.gpx) {
56169             var gpx = context.layers().layer('gpx');
56170             if (gpx) {
56171                 gpx.url(q.gpx);
56172             }
56173         }
56174
56175         if (q.offset) {
56176             var offset = q.offset.replace(/;/g, ',').split(',').map(function(n) {
56177                 return !isNaN(n) && n;
56178             });
56179
56180             if (offset.length === 2) {
56181                 background.offset(geoMetersToOffset(offset));
56182             }
56183         }
56184     };
56185
56186
56187     return utilRebind(background, dispatch$$1, 'on');
56188 }
56189
56190 function rendererFeatures(context) {
56191     var traffic_roads = {
56192         'motorway': true,
56193         'motorway_link': true,
56194         'trunk': true,
56195         'trunk_link': true,
56196         'primary': true,
56197         'primary_link': true,
56198         'secondary': true,
56199         'secondary_link': true,
56200         'tertiary': true,
56201         'tertiary_link': true,
56202         'residential': true,
56203         'unclassified': true,
56204         'living_street': true
56205     };
56206
56207     var service_roads = {
56208         'service': true,
56209         'road': true,
56210         'track': true
56211     };
56212
56213     var paths = {
56214         'path': true,
56215         'footway': true,
56216         'cycleway': true,
56217         'bridleway': true,
56218         'steps': true,
56219         'pedestrian': true,
56220         'corridor': true
56221     };
56222
56223     var past_futures = {
56224         'proposed': true,
56225         'construction': true,
56226         'abandoned': true,
56227         'dismantled': true,
56228         'disused': true,
56229         'razed': true,
56230         'demolished': true,
56231         'obliterated': true
56232     };
56233
56234     var dispatch$$1 = dispatch('change', 'redraw'),
56235         _cullFactor = 1,
56236         _cache = {},
56237         _features = {},
56238         _stats = {},
56239         _keys = [],
56240         _hidden = [];
56241
56242
56243     function update() {
56244         _hidden = features.hidden();
56245         dispatch$$1.call('change');
56246         dispatch$$1.call('redraw');
56247     }
56248
56249
56250     function defineFeature(k, filter, max$$1) {
56251         _keys.push(k);
56252         _features[k] = {
56253             filter: filter,
56254             enabled: true,   // whether the user wants it enabled..
56255             count: 0,
56256             currentMax: (max$$1 || Infinity),
56257             defaultMax: (max$$1 || Infinity),
56258             enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
56259             disable: function() { this.enabled = false; this.currentMax = 0; },
56260             hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
56261             autoHidden: function() { return this.hidden() && this.currentMax > 0; }
56262         };
56263     }
56264
56265
56266     defineFeature('points', function isPoint(entity, resolver, geometry) {
56267         return geometry === 'point';
56268     }, 200);
56269
56270     defineFeature('traffic_roads', function isTrafficRoad(entity) {
56271         return traffic_roads[entity.tags.highway];
56272     });
56273
56274     defineFeature('service_roads', function isServiceRoad(entity) {
56275         return service_roads[entity.tags.highway];
56276     });
56277
56278     defineFeature('paths', function isPath(entity) {
56279         return paths[entity.tags.highway];
56280     });
56281
56282     defineFeature('buildings', function isBuilding(entity) {
56283         return (
56284             !!entity.tags['building:part'] ||
56285             (!!entity.tags.building && entity.tags.building !== 'no') ||
56286             entity.tags.amenity === 'shelter' ||
56287             entity.tags.parking === 'multi-storey' ||
56288             entity.tags.parking === 'sheds' ||
56289             entity.tags.parking === 'carports' ||
56290             entity.tags.parking === 'garage_boxes'
56291         );
56292     }, 250);
56293
56294     defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
56295         return geometry === 'area' &&
56296             !_features.buildings.filter(entity) &&
56297             !_features.water.filter(entity);
56298     });
56299
56300     defineFeature('boundaries', function isBoundary(entity) {
56301         return !!entity.tags.boundary;
56302     });
56303
56304     defineFeature('water', function isWater(entity) {
56305         return (
56306             !!entity.tags.waterway ||
56307             entity.tags.natural === 'water' ||
56308             entity.tags.natural === 'coastline' ||
56309             entity.tags.natural === 'bay' ||
56310             entity.tags.landuse === 'pond' ||
56311             entity.tags.landuse === 'basin' ||
56312             entity.tags.landuse === 'reservoir' ||
56313             entity.tags.landuse === 'salt_pond'
56314         );
56315     });
56316
56317     defineFeature('rail', function isRail(entity) {
56318         return (
56319             !!entity.tags.railway ||
56320             entity.tags.landuse === 'railway'
56321         ) && !(
56322             traffic_roads[entity.tags.highway] ||
56323             service_roads[entity.tags.highway] ||
56324             paths[entity.tags.highway]
56325         );
56326     });
56327
56328     defineFeature('power', function isPower(entity) {
56329         return !!entity.tags.power;
56330     });
56331
56332     // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
56333     defineFeature('past_future', function isPastFuture(entity) {
56334         if (
56335             traffic_roads[entity.tags.highway] ||
56336             service_roads[entity.tags.highway] ||
56337             paths[entity.tags.highway]
56338         ) { return false; }
56339
56340         var strings = Object.keys(entity.tags);
56341
56342         for (var i = 0; i < strings.length; i++) {
56343             var s = strings[i];
56344             if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
56345         }
56346         return false;
56347     });
56348
56349     // Lines or areas that don't match another feature filter.
56350     // IMPORTANT: The 'others' feature must be the last one defined,
56351     //   so that code in getMatches can skip this test if `hasMatch = true`
56352     defineFeature('others', function isOther(entity, resolver, geometry) {
56353         return (geometry === 'line' || geometry === 'area');
56354     });
56355
56356
56357     function features() {}
56358
56359
56360     features.features = function() {
56361         return _features;
56362     };
56363
56364
56365     features.keys = function() {
56366         return _keys;
56367     };
56368
56369
56370     features.enabled = function(k) {
56371         if (!arguments.length) {
56372             return _keys.filter(function(k) { return _features[k].enabled; });
56373         }
56374         return _features[k] && _features[k].enabled;
56375     };
56376
56377
56378     features.disabled = function(k) {
56379         if (!arguments.length) {
56380             return _keys.filter(function(k) { return !_features[k].enabled; });
56381         }
56382         return _features[k] && !_features[k].enabled;
56383     };
56384
56385
56386     features.hidden = function(k) {
56387         if (!arguments.length) {
56388             return _keys.filter(function(k) { return _features[k].hidden(); });
56389         }
56390         return _features[k] && _features[k].hidden();
56391     };
56392
56393
56394     features.autoHidden = function(k) {
56395         if (!arguments.length) {
56396             return _keys.filter(function(k) { return _features[k].autoHidden(); });
56397         }
56398         return _features[k] && _features[k].autoHidden();
56399     };
56400
56401
56402     features.enable = function(k) {
56403         if (_features[k] && !_features[k].enabled) {
56404             _features[k].enable();
56405             update();
56406         }
56407     };
56408
56409
56410     features.disable = function(k) {
56411         if (_features[k] && _features[k].enabled) {
56412             _features[k].disable();
56413             update();
56414         }
56415     };
56416
56417
56418     features.toggle = function(k) {
56419         if (_features[k]) {
56420             (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
56421             update();
56422         }
56423     };
56424
56425
56426     features.resetStats = function() {
56427         for (var i = 0; i < _keys.length; i++) {
56428             _features[_keys[i]].count = 0;
56429         }
56430         dispatch$$1.call('change');
56431     };
56432
56433
56434     features.gatherStats = function(d, resolver, dimensions) {
56435         var needsRedraw = false,
56436             type = lodash.groupBy(d, function(ent) { return ent.type; }),
56437             entities = [].concat(type.relation || [], type.way || [], type.node || []),
56438             currHidden, geometry, matches, i, j;
56439
56440         for (i = 0; i < _keys.length; i++) {
56441             _features[_keys[i]].count = 0;
56442         }
56443
56444         // adjust the threshold for point/building culling based on viewport size..
56445         // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
56446         _cullFactor = dimensions[0] * dimensions[1] / 1000000;
56447
56448         for (i = 0; i < entities.length; i++) {
56449             geometry = entities[i].geometry(resolver);
56450             if (!(geometry === 'vertex' || geometry === 'relation')) {
56451                 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
56452                 for (j = 0; j < matches.length; j++) {
56453                     _features[matches[j]].count++;
56454                 }
56455             }
56456         }
56457
56458         currHidden = features.hidden();
56459         if (currHidden !== _hidden) {
56460             _hidden = currHidden;
56461             needsRedraw = true;
56462             dispatch$$1.call('change');
56463         }
56464
56465         return needsRedraw;
56466     };
56467
56468
56469     features.stats = function() {
56470         for (var i = 0; i < _keys.length; i++) {
56471             _stats[_keys[i]] = _features[_keys[i]].count;
56472         }
56473
56474         return _stats;
56475     };
56476
56477
56478     features.clear = function(d) {
56479         for (var i = 0; i < d.length; i++) {
56480             features.clearEntity(d[i]);
56481         }
56482     };
56483
56484
56485     features.clearEntity = function(entity) {
56486         delete _cache[osmEntity$$1.key(entity)];
56487     };
56488
56489
56490     features.reset = function() {
56491         _cache = {};
56492     };
56493
56494
56495     features.getMatches = function(entity, resolver, geometry) {
56496         if (geometry === 'vertex' || geometry === 'relation') return {};
56497
56498         var ent = osmEntity$$1.key(entity);
56499         if (!_cache[ent]) {
56500             _cache[ent] = {};
56501         }
56502
56503         if (!_cache[ent].matches) {
56504             var matches = {},
56505                 hasMatch = false;
56506
56507             for (var i = 0; i < _keys.length; i++) {
56508                 if (_keys[i] === 'others') {
56509                     if (hasMatch) continue;
56510
56511                     // Multipolygon members:
56512                     // If an entity...
56513                     //   1. is a way that hasn't matched other 'interesting' feature rules,
56514                     //   2. and it belongs to a single parent multipolygon relation
56515                     // ...then match whatever feature rules the parent multipolygon has matched.
56516                     // see #2548, #2887
56517                     //
56518                     // IMPORTANT:
56519                     // For this to work, getMatches must be called on relations before ways.
56520                     //
56521                     if (entity.type === 'way') {
56522                         var parents = features.getParents(entity, resolver, geometry);
56523                         if (parents.length === 1 && parents[0].isMultipolygon()) {
56524                             var pkey = osmEntity$$1.key(parents[0]);
56525                             if (_cache[pkey] && _cache[pkey].matches) {
56526                                 matches = lodash.clone(_cache[pkey].matches);
56527                                 continue;
56528                             }
56529                         }
56530                     }
56531                 }
56532
56533                 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
56534                     matches[_keys[i]] = hasMatch = true;
56535                 }
56536             }
56537             _cache[ent].matches = matches;
56538         }
56539
56540         return _cache[ent].matches;
56541     };
56542
56543
56544     features.getParents = function(entity, resolver, geometry) {
56545         if (geometry === 'point') return [];
56546
56547         var ent = osmEntity$$1.key(entity);
56548         if (!_cache[ent]) {
56549             _cache[ent] = {};
56550         }
56551
56552         if (!_cache[ent].parents) {
56553             var parents = [];
56554             if (geometry === 'vertex') {
56555                 parents = resolver.parentWays(entity);
56556             } else {   // 'line', 'area', 'relation'
56557                 parents = resolver.parentRelations(entity);
56558             }
56559             _cache[ent].parents = parents;
56560         }
56561         return _cache[ent].parents;
56562     };
56563
56564
56565     features.isHiddenFeature = function(entity, resolver, geometry) {
56566         if (!_hidden.length) return false;
56567         if (!entity.version) return false;
56568
56569         var matches = features.getMatches(entity, resolver, geometry);
56570
56571         for (var i = 0; i < _hidden.length; i++) {
56572             if (matches[_hidden[i]]) return true;
56573         }
56574         return false;
56575     };
56576
56577
56578     features.isHiddenChild = function(entity, resolver, geometry) {
56579         if (!_hidden.length) return false;
56580         if (!entity.version || geometry === 'point') return false;
56581
56582         var parents = features.getParents(entity, resolver, geometry);
56583         if (!parents.length) return false;
56584
56585         for (var i = 0; i < parents.length; i++) {
56586             if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
56587                 return false;
56588             }
56589         }
56590         return true;
56591     };
56592
56593
56594     features.hasHiddenConnections = function(entity, resolver) {
56595         if (!_hidden.length) return false;
56596         var childNodes, connections;
56597
56598         if (entity.type === 'midpoint') {
56599             childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
56600             connections = [];
56601         } else {
56602             childNodes = entity.nodes ? resolver.childNodes(entity) : [];
56603             connections = features.getParents(entity, resolver, entity.geometry(resolver));
56604         }
56605
56606         // gather ways connected to child nodes..
56607         connections = lodash.reduce(childNodes, function(result, e) {
56608             return resolver.isShared(e) ? lodash.union(result, resolver.parentWays(e)) : result;
56609         }, connections);
56610
56611         return connections.length ? lodash.some(connections, function(e) {
56612             return features.isHidden(e, resolver, e.geometry(resolver));
56613         }) : false;
56614     };
56615
56616
56617     features.isHidden = function(entity, resolver, geometry) {
56618         if (!_hidden.length) return false;
56619         if (!entity.version) return false;
56620
56621         var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
56622         return fn(entity, resolver, geometry);
56623     };
56624
56625
56626     features.filter = function(d, resolver) {
56627         if (!_hidden.length) return d;
56628
56629         var result = [];
56630         for (var i = 0; i < d.length; i++) {
56631             var entity = d[i];
56632             if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
56633                 result.push(entity);
56634             }
56635         }
56636         return result;
56637     };
56638
56639
56640     return utilRebind(features, dispatch$$1, 'on');
56641 }
56642
56643 function utilBindOnce(target, type, listener, capture) {
56644     var typeOnce = type + '.once';
56645     function one() {
56646         target.on(typeOnce, null);
56647         listener.apply(this, arguments);
56648     }
56649     target.on(typeOnce, one, capture);
56650     return this;
56651 }
56652
56653 function rendererMap(context) {
56654
56655     var dimensions = [1, 1],
56656         dispatch$$1 = dispatch('move', 'drawn'),
56657         projection$$1 = context.projection,
56658         curtainProjection = context.curtainProjection,
56659         dblclickEnabled = true,
56660         redrawEnabled = true,
56661         transformStart = projection$$1.transform(),
56662         transformLast,
56663         transformed = false,
56664         minzoom = 0,
56665         drawLayers = svgLayers(projection$$1, context),
56666         drawPoints = svgPoints$$1(projection$$1, context),
56667         drawVertices = svgVertices$$1(projection$$1, context),
56668         drawLines = svgLines$$1(projection$$1, context),
56669         drawAreas = svgAreas$$1(projection$$1, context),
56670         drawMidpoints = svgMidpoints$$1(projection$$1, context),
56671         drawLabels = svgLabels(projection$$1, context),
56672         supersurface = select(null),
56673         wrapper = select(null),
56674         surface = select(null),
56675         mouse$$1,
56676         mousemove;
56677
56678     var zoom$$1 = zoom()
56679             .scaleExtent([ztok(2), ztok(24)])
56680             .interpolate(interpolateValue)
56681             .filter(zoomEventFilter)
56682             .on('zoom', zoomPan);
56683
56684     var _selection = select(null);
56685
56686
56687     function map(selection$$1) {
56688
56689         _selection = selection$$1;
56690
56691         context
56692             .on('change.map', immediateRedraw);
56693
56694         context.connection()
56695             .on('change.map', immediateRedraw);
56696
56697         context.history()
56698             .on('change.map', immediateRedraw)
56699             .on('undone.map redone.map', function(stack$$1) {
56700                 var mode = context.mode().id;
56701                 if (mode !== 'browse' && mode !== 'select') return;
56702
56703                 var followSelected = false;
56704                 if (Array.isArray(stack$$1.selectedIDs)) {
56705                     followSelected = (stack$$1.selectedIDs.length === 1 && stack$$1.selectedIDs[0][0] === 'n');
56706                     context.enter(
56707                         modeSelect(context, stack$$1.selectedIDs).follow(followSelected)
56708                     );
56709                 }
56710                 if (!followSelected && stack$$1.transform) {
56711                     map.transformEase(stack$$1.transform);
56712                 }
56713             });
56714
56715         context.background()
56716             .on('change.map', immediateRedraw);
56717
56718         context.features()
56719             .on('redraw.map', immediateRedraw);
56720
56721         drawLayers
56722             .on('change.map', function() {
56723                 context.background().updateImagery();
56724                 immediateRedraw();
56725             });
56726
56727         selection$$1
56728             .on('dblclick.map', dblClick)
56729             .call(zoom$$1)
56730             .call(zoom$$1.transform, projection$$1.transform());
56731
56732         supersurface = selection$$1.append('div')
56733             .attr('id', 'supersurface')
56734             .call(utilSetTransform, 0, 0);
56735
56736         // Need a wrapper div because Opera can't cope with an absolutely positioned
56737         // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
56738         wrapper = supersurface
56739             .append('div')
56740             .attr('class', 'layer layer-data');
56741
56742         map.surface = surface = wrapper
56743             .call(drawLayers)
56744             .selectAll('.surface')
56745             .attr('id', 'surface');
56746
56747         surface
56748             .call(drawLabels.observe)
56749             .on('mousedown.zoom', function() {
56750                 if (event.button === 2) {
56751                     event.stopPropagation();
56752                 }
56753             }, true)
56754             .on('mouseup.zoom', function() {
56755                 if (resetTransform()) immediateRedraw();
56756             })
56757             .on('mousemove.map', function() {
56758                 mousemove = event;
56759             })
56760             .on('mouseover.vertices', function() {
56761                 if (map.editable() && !transformed) {
56762                     var hover = event.target.__data__;
56763                     surface.selectAll('.data-layer-osm')
56764                         .call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
56765                     dispatch$$1.call('drawn', this, {full: false});
56766                 }
56767             })
56768             .on('mouseout.vertices', function() {
56769                 if (map.editable() && !transformed) {
56770                     var hover = event.relatedTarget && event.relatedTarget.__data__;
56771                     surface.selectAll('.data-layer-osm')
56772                         .call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
56773                     dispatch$$1.call('drawn', this, {full: false});
56774                 }
56775             });
56776
56777         supersurface
56778             .call(context.background());
56779
56780         context.on('enter.map', function() {
56781             if (map.editable() && !transformed) {
56782                 var all = context.intersects(map.extent()),
56783                     filter = utilFunctor(true),
56784                     graph = context.graph();
56785
56786                 all = context.features().filter(all, graph);
56787                 surface.selectAll('.data-layer-osm')
56788                     .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
56789                     .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
56790                 dispatch$$1.call('drawn', this, {full: false});
56791             }
56792         });
56793
56794         map.dimensions(utilGetDimensions(selection$$1));
56795     }
56796
56797
56798     function zoomEventFilter() {
56799         // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
56800         // Intercept `mousedown` and check if there is an orphaned zoom gesture.
56801         // This can happen if a previous `mousedown` occurred without a `mouseup`.
56802         // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
56803         // so that d3-zoom won't stop propagation of new `mousedown` events.
56804         if (event.type === 'mousedown') {
56805             var hasOrphan = false;
56806             var listeners = window.__on;
56807             for (var i = 0; i < listeners.length; i++) {
56808                 var listener = listeners[i];
56809                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
56810                     hasOrphan = true;
56811                     break;
56812                 }
56813             }
56814             if (hasOrphan) {
56815                 var event$$1 = window.CustomEvent;
56816                 if (event$$1) {
56817                     event$$1 = new event$$1('mouseup');
56818                 } else {
56819                     event$$1 = window.document.createEvent('Event');
56820                     event$$1.initEvent('mouseup', false, false);
56821                 }
56822                 // Event needs to be dispatched with an event.view property.
56823                 event$$1.view = window;
56824                 window.dispatchEvent(event$$1);
56825             }
56826         }
56827
56828         return event.button !== 2;   // ignore right clicks
56829     }
56830
56831
56832     function ztok(z) {
56833         return 256 * Math.pow(2, z);
56834     }
56835
56836     function ktoz(k) {
56837         return Math.max(Math.log(k) / Math.LN2 - 8, 0);
56838     }
56839
56840     function pxCenter() {
56841         return [dimensions[0] / 2, dimensions[1] / 2];
56842     }
56843
56844
56845     function drawVector(difference, extent$$1) {
56846         var graph = context.graph(),
56847             features = context.features(),
56848             all = context.intersects(map.extent()),
56849             data, filter;
56850
56851         if (difference) {
56852             var complete = difference.complete(map.extent());
56853             data = lodash.compact(lodash.values(complete));
56854             filter = function(d) { return d.id in complete; };
56855             features.clear(data);
56856
56857         } else {
56858             // force a full redraw if gatherStats detects that a feature
56859             // should be auto-hidden (e.g. points or buildings)..
56860             if (features.gatherStats(all, graph, dimensions)) {
56861                 extent$$1 = undefined;
56862             }
56863
56864             if (extent$$1) {
56865                 data = context.intersects(map.extent().intersection(extent$$1));
56866                 var set = set$2(lodash.map(data, 'id'));
56867                 filter = function(d) { return set.has(d.id); };
56868
56869             } else {
56870                 data = all;
56871                 filter = utilFunctor(true);
56872             }
56873         }
56874
56875         data = features.filter(data, graph);
56876
56877         surface.selectAll('.data-layer-osm')
56878             .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
56879             .call(drawLines, graph, data, filter)
56880             .call(drawAreas, graph, data, filter)
56881             .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
56882             .call(drawLabels, graph, data, filter, dimensions, !difference && !extent$$1)
56883             .call(drawPoints, graph, data, filter);
56884
56885         dispatch$$1.call('drawn', this, {full: true});
56886     }
56887
56888
56889     function editOff() {
56890         context.features().resetStats();
56891         surface.selectAll('.layer-osm *').remove();
56892         dispatch$$1.call('drawn', this, {full: true});
56893     }
56894
56895
56896     function dblClick() {
56897         if (!dblclickEnabled) {
56898             event.preventDefault();
56899             event.stopImmediatePropagation();
56900         }
56901     }
56902
56903
56904     function zoomPan(manualEvent) {
56905         var event$$1 = (manualEvent || event),
56906             source = event$$1.sourceEvent,
56907             eventTransform = event$$1.transform;
56908
56909         if (transformStart.x === eventTransform.x &&
56910             transformStart.y === eventTransform.y &&
56911             transformStart.k === eventTransform.k) {
56912             return;  // no change
56913         }
56914
56915         // Normalize mousewheel - #3029
56916         // If wheel delta is provided in LINE units, recalculate it in PIXEL units
56917         // We are essentially redoing the calculations that occur here:
56918         //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
56919         // See this for more info:
56920         //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
56921         if (source && source.type === 'wheel' && source.deltaMode === 1 /* LINE */) {
56922             // pick sensible scroll amount if user scrolling fast or slow..
56923             var lines = Math.abs(source.deltaY),
56924                 scroll = lines > 2 ? 40 : lines * 10;
56925
56926             var t0 = transformed ? transformLast : transformStart,
56927                 p0 = mouse$$1(source),
56928                 p1 = t0.invert(p0),
56929                 k2 = t0.k * Math.pow(2, -source.deltaY * scroll / 500),
56930                 x2 = p0[0] - p1[0] * k2,
56931                 y2 = p0[1] - p1[1] * k2;
56932
56933             eventTransform = identity$8.translate(x2,y2).scale(k2);
56934             _selection.node().__zoom = eventTransform;
56935         }
56936
56937         if (ktoz(eventTransform.k * 2 * Math.PI) < minzoom) {
56938             surface.interrupt();
56939             uiFlash().text(t('cannot_zoom'));
56940             setZoom(context.minEditableZoom(), true);
56941             queueRedraw();
56942             dispatch$$1.call('move', this, map);
56943             return;
56944         }
56945
56946         projection$$1.transform(eventTransform);
56947
56948         var scale = eventTransform.k / transformStart.k,
56949             tX = (eventTransform.x / scale - transformStart.x) * scale,
56950             tY = (eventTransform.y / scale - transformStart.y) * scale;
56951
56952         if (context.inIntro()) {
56953             curtainProjection.transform({
56954                 x: eventTransform.x - tX,
56955                 y: eventTransform.y - tY,
56956                 k: eventTransform.k
56957             });
56958         }
56959
56960         transformed = true;
56961         transformLast = eventTransform;
56962         utilSetTransform(supersurface, tX, tY, scale);
56963         queueRedraw();
56964
56965         dispatch$$1.call('move', this, map);
56966     }
56967
56968
56969     function resetTransform() {
56970         if (!transformed) return false;
56971
56972         // deprecation warning - Radial Menu to be removed in iD v3
56973         surface.selectAll('.edit-menu, .radial-menu').interrupt().remove();
56974         utilSetTransform(supersurface, 0, 0);
56975         transformed = false;
56976         if (context.inIntro()) {
56977             curtainProjection.transform(projection$$1.transform());
56978         }
56979         return true;
56980     }
56981
56982
56983     function redraw(difference, extent$$1) {
56984         if (surface.empty() || !redrawEnabled) return;
56985
56986         // If we are in the middle of a zoom/pan, we can't do differenced redraws.
56987         // It would result in artifacts where differenced entities are redrawn with
56988         // one transform and unchanged entities with another.
56989         if (resetTransform()) {
56990             difference = extent$$1 = undefined;
56991         }
56992
56993         var z = String(~~map.zoom());
56994         if (surface.attr('data-zoom') !== z) {
56995             surface.attr('data-zoom', z)
56996                 .classed('low-zoom', z <= 16);
56997         }
56998
56999         if (!difference) {
57000             supersurface.call(context.background());
57001         }
57002
57003         wrapper
57004             .call(drawLayers);
57005
57006         // OSM
57007         if (map.editable()) {
57008             context.loadTiles(projection$$1, dimensions);
57009             drawVector(difference, extent$$1);
57010         } else {
57011             editOff();
57012         }
57013
57014         transformStart = projection$$1.transform();
57015
57016         return map;
57017     }
57018
57019
57020     var queueRedraw = lodash.throttle(redraw, 750);
57021
57022
57023     var immediateRedraw = function(difference, extent$$1) {
57024         if (!difference && !extent$$1) queueRedraw.cancel();
57025         redraw(difference, extent$$1);
57026     };
57027
57028
57029     function pointLocation(p) {
57030         var translate = projection$$1.translate(),
57031             scale = projection$$1.scale() * 2 * Math.PI;
57032         return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
57033     }
57034
57035
57036     function locationPoint(l) {
57037         var translate = projection$$1.translate(),
57038             scale = projection$$1.scale() * 2 * Math.PI;
57039         return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
57040     }
57041
57042
57043     map.mouse = function() {
57044         var event$$1 = mousemove || event;
57045         if (event$$1) {
57046             var s;
57047             while ((s = event$$1.sourceEvent)) { event$$1 = s; }
57048             return mouse$$1(event$$1);
57049         }
57050         return null;
57051     };
57052
57053
57054     map.mouseCoordinates = function() {
57055         return projection$$1.invert(map.mouse());
57056     };
57057
57058
57059     map.dblclickEnable = function(_) {
57060         if (!arguments.length) return dblclickEnabled;
57061         dblclickEnabled = _;
57062         return map;
57063     };
57064
57065
57066     map.redrawEnable = function(_) {
57067         if (!arguments.length) return redrawEnabled;
57068         redrawEnabled = _;
57069         return map;
57070     };
57071
57072
57073     function setTransform(t2, duration, force) {
57074         var t$$1 = projection$$1.transform();
57075         if (!force && t2.k === t$$1.k && t2.x === t$$1.x && t2.y === t$$1.y) {
57076             return false;
57077         }
57078
57079         if (duration) {
57080             _selection
57081                 .transition()
57082                 .duration(duration)
57083                 .on('start', function() { map.startEase(); })
57084                 .call(zoom$$1.transform, identity$8.translate(t2.x, t2.y).scale(t2.k));
57085         } else {
57086             projection$$1.transform(t2);
57087             transformStart = t2;
57088             _selection.call(zoom$$1.transform, transformStart);
57089         }
57090     }
57091
57092
57093     function setZoom(z2, force, duration) {
57094         if (z2 === map.zoom() && !force) {
57095             return false;
57096         }
57097
57098         var k = projection$$1.scale(),
57099             k2 = Math.max(ztok(2), Math.min(ztok(24), ztok(z2))) / (2 * Math.PI),
57100             center = pxCenter(),
57101             l = pointLocation(center);
57102
57103         projection$$1.scale(k2);
57104
57105         var t$$1 = projection$$1.translate();
57106         l = locationPoint(l);
57107
57108         t$$1[0] += center[0] - l[0];
57109         t$$1[1] += center[1] - l[1];
57110
57111         if (duration) {
57112             projection$$1.scale(k);  // reset scale
57113             _selection
57114                 .transition()
57115                 .duration(duration)
57116                 .on('start', function() { map.startEase(); })
57117                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k2));
57118         } else {
57119             projection$$1.translate(t$$1);
57120             transformStart = projection$$1.transform();
57121             _selection.call(zoom$$1.transform, transformStart);
57122         }
57123
57124         return true;
57125     }
57126
57127
57128     function setCenter(loc2, duration) {
57129         var c = map.center();
57130         if (loc2[0] === c[0] && loc2[1] === c[1]) {
57131             return false;
57132         }
57133
57134         var t$$1 = projection$$1.translate(),
57135             k = projection$$1.scale(),
57136             pxC = pxCenter(),
57137             ll = projection$$1(loc2);
57138
57139         t$$1[0] = t$$1[0] - ll[0] + pxC[0];
57140         t$$1[1] = t$$1[1] - ll[1] + pxC[1];
57141
57142         if (duration) {
57143             _selection
57144                 .transition()
57145                 .duration(duration)
57146                 .on('start', function() { map.startEase(); })
57147                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
57148         } else {
57149             projection$$1.translate(t$$1);
57150             transformStart = projection$$1.transform();
57151             _selection.call(zoom$$1.transform, transformStart);
57152         }
57153
57154         return true;
57155     }
57156
57157
57158     map.pan = function(delta, duration) {
57159         var t$$1 = projection$$1.translate(),
57160             k = projection$$1.scale();
57161
57162         t$$1[0] += delta[0];
57163         t$$1[1] += delta[1];
57164
57165         if (duration) {
57166             _selection
57167                 .transition()
57168                 .duration(duration)
57169                 .on('start', function() { map.startEase(); })
57170                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
57171         } else {
57172             projection$$1.translate(t$$1);
57173             transformStart = projection$$1.transform();
57174             _selection.call(zoom$$1.transform, transformStart);
57175             dispatch$$1.call('move', this, map);
57176             immediateRedraw();
57177         }
57178
57179         return map;
57180     };
57181
57182
57183     map.dimensions = function(_) {
57184         if (!arguments.length) return dimensions;
57185         var center = map.center();
57186         dimensions = _;
57187         drawLayers.dimensions(dimensions);
57188         context.background().dimensions(dimensions);
57189         projection$$1.clipExtent([[0, 0], dimensions]);
57190         mouse$$1 = utilFastMouse(supersurface.node());
57191         setCenter(center);
57192
57193         queueRedraw();
57194         return map;
57195     };
57196
57197
57198     function zoomIn(delta) {
57199         setZoom(~~map.zoom() + delta, true, 250);
57200     }
57201
57202     function zoomOut(delta) {
57203         setZoom(~~map.zoom() - delta, true, 250);
57204     }
57205
57206     map.zoomIn = function() { zoomIn(1); };
57207     map.zoomInFurther = function() { zoomIn(4); };
57208
57209     map.zoomOut = function() { zoomOut(1); };
57210     map.zoomOutFurther = function() { zoomOut(4); };
57211
57212
57213     map.center = function(loc2) {
57214         if (!arguments.length) {
57215             return projection$$1.invert(pxCenter());
57216         }
57217
57218         if (setCenter(loc2)) {
57219             dispatch$$1.call('move', this, map);
57220         }
57221
57222         queueRedraw();
57223         return map;
57224     };
57225
57226
57227     map.zoom = function(z2) {
57228         if (!arguments.length) {
57229             return Math.max(ktoz(projection$$1.scale() * 2 * Math.PI), 0);
57230         }
57231
57232         if (z2 < minzoom) {
57233             surface.interrupt();
57234             uiFlash().text(t('cannot_zoom'));
57235             z2 = context.minEditableZoom();
57236         }
57237
57238         if (setZoom(z2)) {
57239             dispatch$$1.call('move', this, map);
57240         }
57241
57242         queueRedraw();
57243         return map;
57244     };
57245
57246
57247     map.zoomTo = function(entity, zoomLimits) {
57248         var extent$$1 = entity.extent(context.graph());
57249         if (!isFinite(extent$$1.area())) return;
57250
57251         var z2 = map.trimmedExtentZoom(extent$$1);
57252         zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
57253         map.centerZoom(extent$$1.center(), Math.min(Math.max(z2, zoomLimits[0]), zoomLimits[1]));
57254     };
57255
57256
57257     map.centerZoom = function(loc2, z2) {
57258         var centered = setCenter(loc2),
57259             zoomed   = setZoom(z2);
57260
57261         if (centered || zoomed) {
57262             dispatch$$1.call('move', this, map);
57263         }
57264
57265         queueRedraw();
57266         return map;
57267     };
57268
57269
57270     map.centerEase = function(loc2, duration) {
57271         duration = duration || 250;
57272         setCenter(loc2, duration);
57273         return map;
57274     };
57275
57276
57277     map.zoomEase = function(z2, duration) {
57278         duration = duration || 250;
57279         setZoom(z2, false, duration);
57280         return map;
57281     };
57282
57283
57284     map.transformEase = function(t2, duration) {
57285         duration = duration || 250;
57286         setTransform(t2, duration, false);
57287         return map;
57288     };
57289
57290
57291     map.startEase = function() {
57292         utilBindOnce(surface, 'mousedown.ease', function() {
57293             map.cancelEase();
57294         });
57295         return map;
57296     };
57297
57298
57299     map.cancelEase = function() {
57300         _selection.interrupt();
57301         return map;
57302     };
57303
57304
57305     map.extent = function(_) {
57306         if (!arguments.length) {
57307             return new geoExtent$$1(projection$$1.invert([0, dimensions[1]]),
57308                                  projection$$1.invert([dimensions[0], 0]));
57309         } else {
57310             var extent$$1 = geoExtent$$1(_);
57311             map.centerZoom(extent$$1.center(), map.extentZoom(extent$$1));
57312         }
57313     };
57314
57315
57316     map.trimmedExtent = function(_) {
57317         if (!arguments.length) {
57318             var headerY = 60, footerY = 30, pad = 10;
57319             return new geoExtent$$1(projection$$1.invert([pad, dimensions[1] - footerY - pad]),
57320                                  projection$$1.invert([dimensions[0] - pad, headerY + pad]));
57321         } else {
57322             var extent$$1 = geoExtent$$1(_);
57323             map.centerZoom(extent$$1.center(), map.trimmedExtentZoom(extent$$1));
57324         }
57325     };
57326
57327
57328     function calcZoom(extent$$1, dim) {
57329         var tl = projection$$1([extent$$1[0][0], extent$$1[1][1]]),
57330             br = projection$$1([extent$$1[1][0], extent$$1[0][1]]);
57331
57332         // Calculate maximum zoom that fits extent
57333         var hFactor = (br[0] - tl[0]) / dim[0],
57334             vFactor = (br[1] - tl[1]) / dim[1],
57335             hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
57336             vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
57337             newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
57338
57339         return newZoom;
57340     }
57341
57342
57343     map.extentZoom = function(_) {
57344         return calcZoom(geoExtent$$1(_), dimensions);
57345     };
57346
57347
57348     map.trimmedExtentZoom = function(_) {
57349         var trimY = 120, trimX = 40,
57350             trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
57351         return calcZoom(geoExtent$$1(_), trimmed);
57352     };
57353
57354
57355     map.editable = function() {
57356         return map.zoom() >= context.minEditableZoom();
57357     };
57358
57359
57360     map.minzoom = function(_) {
57361         if (!arguments.length) return minzoom;
57362         minzoom = _;
57363         return map;
57364     };
57365
57366
57367     map.layers = drawLayers;
57368
57369
57370     return utilRebind(map, dispatch$$1, 'on');
57371 }
57372
57373 var TAU = 2 * Math.PI;
57374 function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
57375 function ktoz(k) { return Math.log(k * TAU) / Math.LN2 - 8; }
57376 function vecSub(a, b) { return [ a[0] - b[0], a[1] - b[1] ]; }
57377 function vecScale(a, b) { return [ a[0] * b, a[1] * b ]; }
57378
57379
57380 function uiMapInMap(context) {
57381
57382
57383     function map_in_map(selection$$1) {
57384         var backgroundLayer = rendererTileLayer(context),
57385             overlayLayers = {},
57386             projection$$1 = geoRawMercator(),
57387             gpxLayer = svgGpx(projection$$1, context).showLabels(false),
57388             debugLayer = svgDebug(projection$$1, context),
57389             zoom$$1 = zoom()
57390                 .scaleExtent([ztok(0.5), ztok(24)])
57391                 .on('start', zoomStarted)
57392                 .on('zoom', zoomed)
57393                 .on('end', zoomEnded),
57394             isTransformed = false,
57395             isHidden = true,
57396             skipEvents = false,
57397             gesture = null,
57398             zDiff = 6,    // by default, minimap renders at (main zoom - 6)
57399             wrap = select(null),
57400             tiles = select(null),
57401             viewport = select(null),
57402             tStart,  // transform at start of gesture
57403             tCurr,   // transform at most recent event
57404             timeoutId;
57405
57406
57407         function zoomStarted() {
57408             if (skipEvents) return;
57409             tStart = tCurr = projection$$1.transform();
57410             gesture = null;
57411         }
57412
57413
57414         function zoomed() {
57415             if (skipEvents) return;
57416
57417             var x = event.transform.x,
57418                 y = event.transform.y,
57419                 k = event.transform.k,
57420                 isZooming = (k !== tStart.k),
57421                 isPanning = (x !== tStart.x || y !== tStart.y);
57422
57423             if (!isZooming && !isPanning) {
57424                 return;  // no change
57425             }
57426
57427             // lock in either zooming or panning, don't allow both in minimap.
57428             if (!gesture) {
57429                 gesture = isZooming ? 'zoom' : 'pan';
57430             }
57431
57432             var tMini = projection$$1.transform(),
57433                 tX, tY, scale;
57434
57435             if (gesture === 'zoom') {
57436                 var dMini = utilGetDimensions(wrap),
57437                     cMini = vecScale(dMini, 0.5);
57438                 scale = k / tMini.k;
57439                 tX = (cMini[0] / scale - cMini[0]) * scale;
57440                 tY = (cMini[1] / scale - cMini[1]) * scale;
57441             } else {
57442                 k = tMini.k;
57443                 scale = 1;
57444                 tX = x - tMini.x;
57445                 tY = y - tMini.y;
57446             }
57447
57448             utilSetTransform(tiles, tX, tY, scale);
57449             utilSetTransform(viewport, 0, 0, scale);
57450             isTransformed = true;
57451             tCurr = identity$8.translate(x, y).scale(k);
57452
57453             var zMain = ktoz(context.projection.scale()),
57454                 zMini = ktoz(k);
57455
57456             zDiff = zMain - zMini;
57457
57458             queueRedraw();
57459         }
57460
57461
57462         function zoomEnded() {
57463             if (skipEvents) return;
57464             if (gesture !== 'pan') return;
57465
57466             updateProjection();
57467             gesture = null;
57468             var dMini = utilGetDimensions(wrap),
57469                 cMini = vecScale(dMini, 0.5);
57470             context.map().center(projection$$1.invert(cMini));   // recenter main map..
57471         }
57472
57473
57474         function updateProjection() {
57475             var loc = context.map().center(),
57476                 dMini = utilGetDimensions(wrap),
57477                 cMini = vecScale(dMini, 0.5),
57478                 tMain = context.projection.transform(),
57479                 zMain = ktoz(tMain.k),
57480                 zMini = Math.max(zMain - zDiff, 0.5),
57481                 kMini = ztok(zMini);
57482
57483             projection$$1
57484                 .translate([tMain.x, tMain.y])
57485                 .scale(kMini);
57486
57487             var point = projection$$1(loc),
57488                 mouse$$1 = (gesture === 'pan') ? vecSub([tCurr.x, tCurr.y], [tStart.x, tStart.y]) : [0, 0],
57489                 xMini = cMini[0] - point[0] + tMain.x + mouse$$1[0],
57490                 yMini = cMini[1] - point[1] + tMain.y + mouse$$1[1];
57491
57492             projection$$1
57493                 .translate([xMini, yMini])
57494                 .clipExtent([[0, 0], dMini]);
57495
57496             tCurr = projection$$1.transform();
57497
57498             if (isTransformed) {
57499                 utilSetTransform(tiles, 0, 0);
57500                 utilSetTransform(viewport, 0, 0);
57501                 isTransformed = false;
57502             }
57503
57504             zoom$$1
57505                 .scaleExtent([ztok(0.5), ztok(zMain - 3)]);
57506
57507             skipEvents = true;
57508             wrap.call(zoom$$1.transform, tCurr);
57509             skipEvents = false;
57510         }
57511
57512
57513         function redraw() {
57514             clearTimeout(timeoutId);
57515             if (isHidden) return;
57516
57517             updateProjection();
57518
57519             var dMini = utilGetDimensions(wrap),
57520                 zMini = ktoz(projection$$1.scale());
57521
57522             // setup tile container
57523             tiles = wrap
57524                 .selectAll('.map-in-map-tiles')
57525                 .data([0]);
57526
57527             tiles = tiles.enter()
57528                 .append('div')
57529                 .attr('class', 'map-in-map-tiles')
57530                 .merge(tiles);
57531
57532             // redraw background
57533             backgroundLayer
57534                 .source(context.background().baseLayerSource())
57535                 .projection(projection$$1)
57536                 .dimensions(dMini);
57537
57538             var background = tiles
57539                 .selectAll('.map-in-map-background')
57540                 .data([0]);
57541
57542             background.enter()
57543                 .append('div')
57544                 .attr('class', 'map-in-map-background')
57545                 .merge(background)
57546                 .call(backgroundLayer);
57547
57548
57549             // redraw overlay
57550             var overlaySources = context.background().overlayLayerSources();
57551             var activeOverlayLayers = [];
57552             for (var i = 0; i < overlaySources.length; i++) {
57553                 if (overlaySources[i].validZoom(zMini)) {
57554                     if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
57555                     activeOverlayLayers.push(overlayLayers[i]
57556                         .source(overlaySources[i])
57557                         .projection(projection$$1)
57558                         .dimensions(dMini));
57559                 }
57560             }
57561
57562             var overlay = tiles
57563                 .selectAll('.map-in-map-overlay')
57564                 .data([0]);
57565
57566             overlay = overlay.enter()
57567                 .append('div')
57568                 .attr('class', 'map-in-map-overlay')
57569                 .merge(overlay);
57570
57571
57572             var overlays = overlay
57573                 .selectAll('div')
57574                 .data(activeOverlayLayers, function(d) { return d.source().name(); });
57575
57576             overlays.exit()
57577                 .remove();
57578
57579             overlays = overlays.enter()
57580                 .append('div')
57581                 .merge(overlays)
57582                 .each(function(layer) { select(this).call(layer); });
57583
57584
57585             var dataLayers = tiles
57586                 .selectAll('.map-in-map-data')
57587                 .data([0]);
57588
57589             dataLayers.exit()
57590                 .remove();
57591
57592             dataLayers = dataLayers.enter()
57593                 .append('svg')
57594                 .attr('class', 'map-in-map-data')
57595                 .merge(dataLayers)
57596                 .call(gpxLayer)
57597                 .call(debugLayer);
57598
57599
57600             // redraw viewport bounding box
57601             if (gesture !== 'pan') {
57602                 var getPath = index$4(projection$$1),
57603                     bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
57604
57605                 viewport = wrap.selectAll('.map-in-map-viewport')
57606                     .data([0]);
57607
57608                 viewport = viewport.enter()
57609                     .append('svg')
57610                     .attr('class', 'map-in-map-viewport')
57611                     .merge(viewport);
57612
57613
57614                 var path$$1 = viewport.selectAll('.map-in-map-bbox')
57615                     .data([bbox]);
57616
57617                 path$$1.enter()
57618                     .append('path')
57619                     .attr('class', 'map-in-map-bbox')
57620                     .merge(path$$1)
57621                     .attr('d', getPath)
57622                     .classed('thick', function(d) { return getPath.area(d) < 30; });
57623             }
57624         }
57625
57626
57627         function queueRedraw() {
57628             clearTimeout(timeoutId);
57629             timeoutId = setTimeout(function() { redraw(); }, 750);
57630         }
57631
57632
57633         function toggle() {
57634             if (event) event.preventDefault();
57635
57636             isHidden = !isHidden;
57637
57638             var label = select('.minimap-toggle');
57639             label.classed('active', !isHidden)
57640                 .select('input').property('checked', !isHidden);
57641
57642             if (isHidden) {
57643                 wrap
57644                     .style('display', 'block')
57645                     .style('opacity', '1')
57646                     .transition()
57647                     .duration(200)
57648                     .style('opacity', '0')
57649                     .on('end', function() {
57650                         selection$$1.selectAll('.map-in-map')
57651                             .style('display', 'none');
57652                     });
57653             } else {
57654                 wrap
57655                     .style('display', 'block')
57656                     .style('opacity', '0')
57657                     .transition()
57658                     .duration(200)
57659                     .style('opacity', '1')
57660                     .on('end', function() {
57661                         redraw();
57662                     });
57663             }
57664         }
57665
57666
57667         uiMapInMap.toggle = toggle;
57668
57669         wrap = selection$$1.selectAll('.map-in-map')
57670             .data([0]);
57671
57672         wrap = wrap.enter()
57673             .append('div')
57674             .attr('class', 'map-in-map')
57675             .style('display', (isHidden ? 'none' : 'block'))
57676             .call(zoom$$1)
57677             .on('dblclick.zoom', null)
57678             .merge(wrap);
57679
57680         context.map()
57681             .on('drawn.map-in-map', function(drawn) {
57682                 if (drawn.full === true) {
57683                     redraw();
57684                 }
57685             });
57686
57687         redraw();
57688
57689         var keybinding = d3keybinding('map-in-map')
57690             .on(t('background.minimap.key'), toggle);
57691
57692         select(document)
57693             .call(keybinding);
57694     }
57695
57696     return map_in_map;
57697 }
57698
57699 function uiTooltipHtml(text, key, heading) {
57700     var s = '';
57701
57702     if (heading) {
57703         s += '<div class="tooltip-heading"><span>' + heading + '</span></div>';
57704     }
57705     if (text) {
57706         s += '<div class="tooltip-text"><span>' + text + '</span></div>';
57707     }
57708     if (key) {
57709         s += '<div class="keyhint-wrap"><span>' + t('tooltip_keyhint') + '</span>' +
57710             '<span class="keyhint">' + key + '</span></div>';
57711     }
57712
57713     return s;
57714 }
57715
57716 function uiBackground(context) {
57717     var key = t('background.key'),
57718         detected = utilDetect(),
57719         opacities = [1, 0.75, 0.5, 0.25],
57720         directions = [
57721             ['right', [0.5, 0]],
57722             ['top', [0, -0.5]],
57723             ['left', [-0.5, 0]],
57724             ['bottom', [0, 0.5]]],
57725         opacityDefault = (context.storage('background-opacity') !== null) ?
57726             (+context.storage('background-opacity')) : 1.0,
57727         customTemplate = context.storage('background-custom-template') || '',
57728         previous;
57729
57730     // Can be 0 from <1.3.0 use or due to issue #1923.
57731     if (opacityDefault === 0) opacityDefault = 1.0;
57732
57733
57734     function background(selection$$1) {
57735
57736         function sortSources(a, b) {
57737             return a.best() && !b.best() ? -1
57738                 : b.best() && !a.best() ? 1
57739                 : descending(a.area(), b.area()) || ascending(a.name(), b.name()) || 0;
57740         }
57741
57742
57743         function setOpacity(d) {
57744             var bg = context.container().selectAll('.layer-background')
57745                 .transition()
57746                 .style('opacity', d)
57747                 .attr('data-opacity', d);
57748
57749             if (!detected.opera) {
57750                 utilSetTransform(bg, 0, 0);
57751             }
57752
57753             opacityList.selectAll('li')
57754                 .classed('active', function(_) { return _ === d; });
57755
57756             context.storage('background-opacity', d);
57757         }
57758
57759
57760         function setTooltips(selection$$1) {
57761             selection$$1.each(function(d, i, nodes) {
57762                 var item = select(this).select('label'),
57763                     span = item.select('span'),
57764                     placement = (i < nodes.length / 2) ? 'bottom' : 'top',
57765                     description = d.description(),
57766                     isOverflowing = (span.property('clientWidth') !== span.property('scrollWidth'));
57767
57768                 if (d === previous) {
57769                     item.call(tooltip()
57770                         .placement(placement)
57771                         .html(true)
57772                         .title(function() {
57773                             var tip = '<div>' + t('background.switch') + '</div>';
57774                             return uiTooltipHtml(tip, uiCmd('⌘' + key));
57775                         })
57776                     );
57777                 } else if (description || isOverflowing) {
57778                     item.call(tooltip()
57779                         .placement(placement)
57780                         .title(description || d.name())
57781                     );
57782                 } else {
57783                     item.call(tooltip().destroy);
57784                 }
57785             });
57786         }
57787
57788
57789         function selectLayer() {
57790             function active$$1(d) {
57791                 return context.background().showsLayer(d);
57792             }
57793
57794             content.selectAll('.layer, .custom_layer')
57795                 .classed('active', active$$1)
57796                 .classed('switch', function(d) { return d === previous; })
57797                 .call(setTooltips)
57798                 .selectAll('input')
57799                 .property('checked', active$$1);
57800         }
57801
57802
57803         function clickSetSource(d) {
57804             event.preventDefault();
57805             previous = context.background().baseLayerSource();
57806             context.background().baseLayerSource(d);
57807             selectLayer();
57808             document.activeElement.blur();
57809         }
57810
57811
57812         function editCustom() {
57813             event.preventDefault();
57814             var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
57815             var template = window.prompt(t('background.custom_prompt', { example: example }), customTemplate);
57816             if (template) {
57817                 setCustom(template);
57818             } else {
57819                 selectLayer();
57820             }
57821         }
57822
57823
57824         function setCustom(template) {
57825             context.storage('background-custom-template', template);
57826             var d = rendererBackgroundSource.Custom(template);
57827             content.selectAll('.custom_layer').datum(d);
57828             clickSetSource(d);
57829         }
57830
57831
57832         function clickSetOverlay(d) {
57833             event.preventDefault();
57834             context.background().toggleOverlayLayer(d);
57835             selectLayer();
57836             document.activeElement.blur();
57837         }
57838
57839
57840         function drawList(layerList, type, change, filter) {
57841             var sources = context.background()
57842                 .sources(context.map().extent())
57843                 .filter(filter);
57844
57845             var layerLinks = layerList.selectAll('li.layer')
57846                 .data(sources, function(d) { return d.name(); });
57847
57848             layerLinks.exit()
57849                 .remove();
57850
57851             var enter = layerLinks.enter()
57852                 .insert('li', '.custom_layer')
57853                 .attr('class', 'layer')
57854                 .classed('best', function(d) { return d.best(); });
57855
57856             enter.filter(function(d) { return d.best(); })
57857                 .append('div')
57858                 .attr('class', 'best')
57859                 .call(tooltip()
57860                     .title(t('background.best_imagery'))
57861                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
57862                 .append('span')
57863                 .html('&#9733;');
57864
57865             var label = enter
57866                 .append('label');
57867
57868             label
57869                 .append('input')
57870                 .attr('type', type)
57871                 .attr('name', 'layers')
57872                 .on('change', change);
57873
57874             label
57875                 .append('span')
57876                 .text(function(d) { return d.name(); });
57877
57878
57879             layerList.selectAll('li.layer')
57880                 .sort(sortSources)
57881                 .style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
57882         }
57883
57884
57885         function update() {
57886             backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
57887             overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
57888
57889             selectLayer();
57890
57891             var source = context.background().baseLayerSource();
57892             if (source.id === 'custom') {
57893                 customTemplate = source.template;
57894             }
57895
57896             updateOffsetVal();
57897         }
57898
57899
57900         function updateOffsetVal() {
57901             var meters = geoOffsetToMeters(context.background().offset()),
57902                 x = +meters[0].toFixed(2),
57903                 y = +meters[1].toFixed(2);
57904
57905             selectAll('.nudge-inner-rect')
57906                 .select('input')
57907                 .classed('error', false)
57908                 .property('value', x + ', ' + y);
57909
57910             selectAll('.nudge-reset')
57911                 .classed('disabled', function() {
57912                     return (x === 0 && y === 0);
57913                 });
57914         }
57915
57916
57917         function resetOffset() {
57918             if (event.button !== 0) return;
57919             context.background().offset([0, 0]);
57920             updateOffsetVal();
57921         }
57922
57923
57924         function nudge(d) {
57925             context.background().nudge(d, context.map().zoom());
57926             updateOffsetVal();
57927         }
57928
57929
57930         function buttonOffset(d) {
57931             if (event.button !== 0) return;
57932             var timeout = window.setTimeout(function() {
57933                     interval = window.setInterval(nudge.bind(null, d), 100);
57934                 }, 500),
57935                 interval;
57936
57937             function doneNudge() {
57938                 window.clearTimeout(timeout);
57939                 window.clearInterval(interval);
57940                 select(window)
57941                     .on('mouseup.buttonoffset', null, true)
57942                     .on('mousedown.buttonoffset', null, true);
57943             }
57944
57945             select(window)
57946                 .on('mouseup.buttonoffset', doneNudge, true)
57947                 .on('mousedown.buttonoffset', doneNudge, true);
57948
57949             nudge(d);
57950         }
57951
57952
57953         function inputOffset() {
57954             if (event.button !== 0) return;
57955             var input = select(this);
57956             var d = input.node().value;
57957
57958             if (d === '') return resetOffset();
57959
57960             d = d.replace(/;/g, ',').split(',').map(function(n) {
57961                 // if n is NaN, it will always get mapped to false.
57962                 return !isNaN(n) && n;
57963             });
57964
57965             if (d.length !== 2 || !d[0] || !d[1]) {
57966                 input.classed('error', true);
57967                 return;
57968             }
57969
57970             context.background().offset(geoMetersToOffset(d));
57971             updateOffsetVal();
57972         }
57973
57974
57975         function dragOffset() {
57976             if (event.button !== 0) return;
57977             var origin = [event.clientX, event.clientY];
57978
57979             context.container()
57980                 .append('div')
57981                 .attr('class', 'nudge-surface');
57982
57983             select(window)
57984                 .on('mousemove.offset', function() {
57985                     var latest = [event.clientX, event.clientY];
57986                     var d = [
57987                         -(origin[0] - latest[0]) / 4,
57988                         -(origin[1] - latest[1]) / 4
57989                     ];
57990
57991                     origin = latest;
57992                     nudge(d);
57993                 })
57994                 .on('mouseup.offset', function() {
57995                     if (event.button !== 0) return;
57996                     selectAll('.nudge-surface')
57997                         .remove();
57998
57999                     select(window)
58000                         .on('mousemove.offset', null)
58001                         .on('mouseup.offset', null);
58002                 });
58003
58004             event.preventDefault();
58005         }
58006
58007
58008         function hide() {
58009             setVisible(false);
58010         }
58011
58012
58013         function toggle() {
58014             if (event) event.preventDefault();
58015             tooltipBehavior.hide(button);
58016             setVisible(!button.classed('active'));
58017         }
58018
58019
58020         function quickSwitch() {
58021             if (previous) {
58022                 clickSetSource(previous);
58023             }
58024         }
58025
58026
58027         function setVisible(show) {
58028             if (show !== shown) {
58029                 button.classed('active', show);
58030                 shown = show;
58031
58032                 if (show) {
58033                     selection$$1
58034                         .on('mousedown.background-inside', function() {
58035                             event.stopPropagation();
58036                         });
58037
58038                     content
58039                         .style('display', 'block')
58040                         .style('right', '-300px')
58041                         .transition()
58042                         .duration(200)
58043                         .style('right', '0px');
58044
58045                     content.selectAll('.layer, .custom_layer')
58046                         .call(setTooltips);
58047
58048                 } else {
58049                     content
58050                         .style('display', 'block')
58051                         .style('right', '0px')
58052                         .transition()
58053                         .duration(200)
58054                         .style('right', '-300px')
58055                         .on('end', function() {
58056                             select(this).style('display', 'none');
58057                         });
58058
58059                     selection$$1
58060                         .on('mousedown.background-inside', null);
58061                 }
58062             }
58063         }
58064
58065
58066         var content = selection$$1
58067                 .append('div')
58068                 .attr('class', 'fillL map-overlay col3 content hide'),
58069             tooltipBehavior = tooltip()
58070                 .placement((textDirection === 'rtl') ? 'right' : 'left')
58071                 .html(true)
58072                 .title(uiTooltipHtml(t('background.description'), key)),
58073             button = selection$$1
58074                 .append('button')
58075                 .attr('tabindex', -1)
58076                 .on('click', toggle)
58077                 .call(svgIcon('#icon-layers', 'light'))
58078                 .call(tooltipBehavior),
58079             shown = false;
58080
58081
58082         /* opacity switcher */
58083
58084         var opawrap = content
58085                 .append('div')
58086                 .attr('class', 'opacity-options-wrapper');
58087
58088         opawrap
58089             .append('h4')
58090             .text(t('background.title'));
58091
58092         var opacityList = opawrap
58093             .append('ul')
58094             .attr('class', 'opacity-options');
58095
58096         opacityList.selectAll('div.opacity')
58097             .data(opacities)
58098             .enter()
58099             .append('li')
58100             .attr('data-original-title', function(d) {
58101                 return t('background.percent_brightness', { opacity: (d * 100) });
58102             })
58103             .on('click.set-opacity', setOpacity)
58104             .html('<div class="select-box"></div>')
58105             .call(tooltip()
58106                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
58107             .append('div')
58108             .attr('class', 'opacity')
58109             .style('opacity', function(d) { return 1.25 - d; });
58110
58111
58112         /* background switcher */
58113
58114         var backgroundList = content
58115             .append('ul')
58116             .attr('class', 'layer-list')
58117             .attr('dir', 'auto');
58118
58119         var custom = backgroundList
58120             .append('li')
58121             .attr('class', 'custom_layer')
58122             .datum(rendererBackgroundSource.Custom());
58123
58124         custom
58125             .append('button')
58126             .attr('class', 'layer-browse')
58127             .call(tooltip()
58128                 .title(t('background.custom_button'))
58129                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
58130             .on('click', editCustom)
58131             .call(svgIcon('#icon-search'));
58132
58133         var label = custom
58134             .append('label');
58135
58136         label
58137             .append('input')
58138             .attr('type', 'radio')
58139             .attr('name', 'layers')
58140             .on('change', function () {
58141                 if (customTemplate) {
58142                     setCustom(customTemplate);
58143                 } else {
58144                     editCustom();
58145                 }
58146             });
58147
58148         label
58149             .append('span')
58150             .text(t('background.custom'));
58151
58152         content
58153             .append('div')
58154             .attr('class', 'imagery-faq')
58155             .append('a')
58156             .attr('target', '_blank')
58157             .attr('tabindex', -1)
58158             .call(svgIcon('#icon-out-link', 'inline'))
58159             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
58160             .append('span')
58161             .text(t('background.imagery_source_faq'));
58162
58163         var overlayList = content
58164             .append('ul')
58165             .attr('class', 'layer-list');
58166
58167         var controls = content
58168             .append('div')
58169             .attr('class', 'controls-list');
58170
58171
58172         /* minimap toggle */
58173
58174         var minimapLabel = controls
58175             .append('label')
58176             .call(tooltip()
58177                 .html(true)
58178                 .title(uiTooltipHtml(t('background.minimap.tooltip'), t('background.minimap.key')))
58179                 .placement('top')
58180             );
58181
58182         minimapLabel
58183             .classed('minimap-toggle', true)
58184             .append('input')
58185             .attr('type', 'checkbox')
58186             .on('change', function() {
58187                 uiMapInMap.toggle();
58188                 event.preventDefault();
58189             });
58190
58191         minimapLabel
58192             .append('span')
58193             .text(t('background.minimap.description'));
58194
58195
58196         /* imagery offset controls */
58197
58198         var adjustments = content
58199             .append('div')
58200             .attr('class', 'adjustments');
58201
58202         adjustments
58203             .append('a')
58204             .text(t('background.fix_misalignment'))
58205             .attr('href', '#')
58206             .classed('hide-toggle', true)
58207             .classed('expanded', false)
58208             .on('click', function() {
58209                 if (event.button !== 0) return;
58210                 var exp = select(this).classed('expanded');
58211                 nudgeContainer.style('display', exp ? 'none' : 'block');
58212                 select(this).classed('expanded', !exp);
58213                 event.preventDefault();
58214             });
58215
58216         var nudgeContainer = adjustments
58217             .append('div')
58218             .attr('class', 'nudge-container cf')
58219             .style('display', 'none');
58220
58221         nudgeContainer
58222             .append('div')
58223             .attr('class', 'nudge-instructions')
58224             .text(t('background.offset'));
58225
58226         var nudgeRect = nudgeContainer
58227             .append('div')
58228             .attr('class', 'nudge-outer-rect')
58229             .on('mousedown', dragOffset);
58230
58231         nudgeRect
58232             .append('div')
58233             .attr('class', 'nudge-inner-rect')
58234             .append('input')
58235             .on('change', inputOffset)
58236             .on('mousedown', function() {
58237                 if (event.button !== 0) return;
58238                 event.stopPropagation();
58239             });
58240
58241         nudgeContainer
58242             .append('div')
58243             .selectAll('button')
58244             .data(directions).enter()
58245             .append('button')
58246             .attr('class', function(d) { return d[0] + ' nudge'; })
58247             .on('mousedown', function(d) {
58248                 if (event.button !== 0) return;
58249                 buttonOffset(d[1]);
58250             });
58251
58252         nudgeContainer
58253             .append('button')
58254             .attr('title', t('background.reset'))
58255             .attr('class', 'nudge-reset disabled')
58256             .on('click', resetOffset)
58257             .call(
58258                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
58259             );
58260
58261         context.map()
58262             .on('move.background-update', lodash.debounce(update, 1000));
58263
58264         context.background()
58265             .on('change.background-update', update);
58266
58267
58268         update();
58269         setOpacity(opacityDefault);
58270
58271         var keybinding = d3keybinding('background')
58272             .on(key, toggle)
58273             .on(uiCmd('⌘' + key), quickSwitch)
58274             .on([t('map_data.key'), t('help.key')], hide);
58275
58276         select(document)
58277             .call(keybinding);
58278
58279         context.surface().on('mousedown.background-outside', hide);
58280         context.container().on('mousedown.background-outside', hide);
58281     }
58282
58283     return background;
58284 }
58285
58286 function uiContributors(context) {
58287     var debouncedUpdate = lodash.debounce(function() { update(); }, 1000),
58288         limit = 4,
58289         hidden = false,
58290         wrap = select(null);
58291
58292
58293     function update() {
58294         var users = {},
58295             entities = context.intersects(context.map().extent());
58296
58297         entities.forEach(function(entity) {
58298             if (entity && entity.user) users[entity.user] = true;
58299         });
58300
58301         var u = Object.keys(users),
58302             subset = u.slice(0, u.length > limit ? limit - 1 : limit);
58303
58304         wrap.html('')
58305             .call(svgIcon('#icon-nearby', 'pre-text light'));
58306
58307         var userList = select(document.createElement('span'));
58308
58309         userList.selectAll()
58310             .data(subset)
58311             .enter()
58312             .append('a')
58313             .attr('class', 'user-link')
58314             .attr('href', function(d) { return context.connection().userURL(d); })
58315             .attr('target', '_blank')
58316             .attr('tabindex', -1)
58317             .text(String);
58318
58319         if (u.length > limit) {
58320             var count = select(document.createElement('span'));
58321
58322             count.append('a')
58323                 .attr('target', '_blank')
58324                 .attr('tabindex', -1)
58325                 .attr('href', function() {
58326                     return context.connection().changesetsURL(context.map().center(), context.map().zoom());
58327                 })
58328                 .text(u.length - limit + 1);
58329
58330             wrap.append('span')
58331                 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
58332
58333         } else {
58334             wrap.append('span')
58335                 .html(t('contributors.list', { users: userList.html() }));
58336         }
58337
58338         if (!u.length) {
58339             hidden = true;
58340             wrap
58341                 .transition()
58342                 .style('opacity', 0);
58343
58344         } else if (hidden) {
58345             wrap
58346                 .transition()
58347                 .style('opacity', 1);
58348         }
58349     }
58350
58351
58352     return function(selection$$1) {
58353         wrap = selection$$1;
58354         update();
58355
58356         context.connection().on('loaded.contributors', debouncedUpdate);
58357         context.map().on('move.contributors', debouncedUpdate);
58358     };
58359 }
58360
58361 function uiFeatureInfo(context) {
58362     function update(selection$$1) {
58363         var features = context.features(),
58364             stats = features.stats(),
58365             count = 0,
58366             hiddenList = lodash.compact(lodash.map(features.hidden(), function(k) {
58367                 if (stats[k]) {
58368                     count += stats[k];
58369                     return String(stats[k]) + ' ' + t('feature.' + k + '.description');
58370                 }
58371             }));
58372
58373         selection$$1.html('');
58374
58375         if (hiddenList.length) {
58376             var tooltipBehavior = tooltip()
58377                     .placement('top')
58378                     .html(true)
58379                     .title(function() {
58380                         return uiTooltipHtml(hiddenList.join('<br/>'));
58381                     });
58382
58383             var warning = selection$$1.append('a')
58384                 .attr('href', '#')
58385                 .attr('tabindex', -1)
58386                 .html(t('feature_info.hidden_warning', { count: count }))
58387                 .call(tooltipBehavior)
58388                 .on('click', function() {
58389                     tooltipBehavior.hide(warning);
58390                     // open map data panel?
58391                     event.preventDefault();
58392                 });
58393         }
58394
58395         selection$$1
58396             .classed('hide', !hiddenList.length);
58397     }
58398
58399
58400     return function(selection$$1) {
58401         update(selection$$1);
58402
58403         context.features().on('change.feature_info', function() {
58404             update(selection$$1);
58405         });
58406     };
58407 }
58408
58409 function uiFullScreen(context) {
58410     var element = context.container().node(),
58411         keybinding = d3keybinding('full-screen');
58412         // button;
58413
58414
58415     function getFullScreenFn() {
58416         if (element.requestFullscreen) {
58417             return element.requestFullscreen;
58418         } else if (element.msRequestFullscreen) {
58419             return element.msRequestFullscreen;
58420         } else if (element.mozRequestFullScreen) {
58421             return element.mozRequestFullScreen;
58422         } else if (element.webkitRequestFullscreen) {
58423             return element.webkitRequestFullscreen;
58424         }
58425     }
58426
58427
58428     function getExitFullScreenFn() {
58429         if (document.exitFullscreen) {
58430             return document.exitFullscreen;
58431         } else if (document.msExitFullscreen) {
58432             return document.msExitFullscreen;
58433         } else if (document.mozCancelFullScreen) {
58434             return document.mozCancelFullScreen;
58435         } else if (document.webkitExitFullscreen) {
58436             return document.webkitExitFullscreen;
58437         }
58438     }
58439
58440
58441     function isFullScreen() {
58442         return document.fullscreenElement ||
58443             document.mozFullScreenElement ||
58444             document.webkitFullscreenElement ||
58445             document.msFullscreenElement;
58446     }
58447
58448
58449     function isSupported() {
58450         return !!getFullScreenFn();
58451     }
58452
58453
58454     function fullScreen() {
58455         event.preventDefault();
58456         if (!isFullScreen()) {
58457             // button.classed('active', true);
58458             getFullScreenFn().apply(element);
58459         } else {
58460             // button.classed('active', false);
58461             getExitFullScreenFn().apply(document);
58462         }
58463     }
58464
58465
58466     return function() { // selection) {
58467         if (!isSupported())
58468             return;
58469
58470         // button = selection.append('button')
58471         //     .attr('title', t('full_screen'))
58472         //     .attr('tabindex', -1)
58473         //     .on('click', fullScreen)
58474         //     .call(tooltip);
58475
58476         // button.append('span')
58477         //     .attr('class', 'icon full-screen');
58478
58479         var detected = utilDetect();
58480         var keys$$1 = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
58481         keybinding.on(keys$$1, fullScreen);
58482
58483         select(document)
58484             .call(keybinding);
58485     };
58486 }
58487
58488 function uiModal(selection$$1, blocking) {
58489     var keybinding = d3keybinding('modal');
58490     var previous = selection$$1.select('div.modal');
58491     var animate = previous.empty();
58492
58493     previous.transition()
58494         .duration(200)
58495         .style('opacity', 0)
58496         .remove();
58497
58498     var shaded = selection$$1
58499         .append('div')
58500         .attr('class', 'shaded')
58501         .style('opacity', 0);
58502
58503     shaded.close = function() {
58504         shaded
58505             .transition()
58506             .duration(200)
58507             .style('opacity',0)
58508             .remove();
58509
58510         modal
58511             .transition()
58512             .duration(200)
58513             .style('top','0px');
58514
58515         keybinding.off();
58516     };
58517
58518
58519     var modal = shaded
58520         .append('div')
58521         .attr('class', 'modal fillL col6');
58522
58523     if (!blocking) {
58524         shaded.on('click.remove-modal', function() {
58525             if (event.target === this) {
58526                 shaded.close();
58527             }
58528         });
58529
58530         modal.append('button')
58531             .attr('class', 'close')
58532             .on('click', shaded.close)
58533             .call(svgIcon('#icon-close'));
58534
58535         keybinding
58536             .on('⌫', shaded.close)
58537             .on('⎋', shaded.close);
58538
58539         select(document)
58540             .call(keybinding);
58541     }
58542
58543     modal
58544         .append('div')
58545         .attr('class', 'content');
58546
58547     if (animate) {
58548         shaded.transition().style('opacity', 1);
58549     } else {
58550         shaded.style('opacity', 1);
58551     }
58552
58553
58554     return shaded;
58555 }
58556
58557 function uiLoading(context) {
58558     var message = '',
58559         blocking = false,
58560         modalSelection;
58561
58562
58563     var loading = function(selection) {
58564         modalSelection = uiModal(selection, blocking);
58565
58566         var loadertext = modalSelection.select('.content')
58567             .classed('loading-modal', true)
58568             .append('div')
58569             .attr('class', 'modal-section fillL');
58570
58571         loadertext
58572             .append('img')
58573             .attr('class', 'loader')
58574             .attr('src', context.imagePath('loader-white.gif'));
58575
58576         loadertext
58577             .append('h3')
58578             .text(message);
58579
58580         modalSelection.select('button.close')
58581             .attr('class', 'hide');
58582
58583         return loading;
58584     };
58585
58586
58587     loading.message = function(_) {
58588         if (!arguments.length) return message;
58589         message = _;
58590         return loading;
58591     };
58592
58593
58594     loading.blocking = function(_) {
58595         if (!arguments.length) return blocking;
58596         blocking = _;
58597         return loading;
58598     };
58599
58600
58601     loading.close = function() {
58602         modalSelection.remove();
58603     };
58604
58605
58606     return loading;
58607 }
58608
58609 function uiGeolocate(context) {
58610     var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
58611         locating = uiLoading(context).message(t('geolocate.locating')).blocking(true),
58612         timeoutId;
58613
58614
58615     function click() {
58616         if (context.inIntro()) return;
58617         context.enter(modeBrowse(context));
58618         context.container().call(locating);
58619         navigator.geolocation.getCurrentPosition(success, error, geoOptions);
58620
58621         // This timeout ensures that we still call finish() even if
58622         // the user declines to share their location in Firefox
58623         timeoutId = setTimeout(finish, 10000 /* 10sec */ );
58624     }
58625
58626
58627     function success(position) {
58628         var map = context.map(),
58629             extent = geoExtent$$1([position.coords.longitude, position.coords.latitude])
58630                 .padByMeters(position.coords.accuracy);
58631
58632         map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
58633         finish();
58634     }
58635
58636
58637     function error() {
58638         finish();
58639     }
58640
58641
58642     function finish() {
58643         locating.close();  // unblock ui
58644         if (timeoutId) { clearTimeout(timeoutId); }
58645         timeoutId = undefined;
58646     }
58647
58648
58649     return function(selection) {
58650         if (!navigator.geolocation) return;
58651
58652         selection
58653             .append('button')
58654             .attr('tabindex', -1)
58655             .attr('title', t('geolocate.title'))
58656             .on('click', click)
58657             .call(svgIcon('#icon-geolocate', 'light'))
58658             .call(tooltip()
58659                 .placement((textDirection === 'rtl') ? 'right' : 'left'));
58660     };
58661 }
58662
58663 var marked = createCommonjsModule(function (module, exports) {
58664 /**
58665  * marked - a markdown parser
58666  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
58667  * https://github.com/chjj/marked
58668  */
58669
58670 (function() {
58671
58672 /**
58673  * Block-Level Grammar
58674  */
58675
58676 var block = {
58677   newline: /^\n+/,
58678   code: /^( {4}[^\n]+\n*)+/,
58679   fences: noop,
58680   hr: /^( *[-*_]){3,} *(?:\n+|$)/,
58681   heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
58682   nptable: noop,
58683   lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
58684   blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
58685   list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
58686   html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
58687   def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
58688   table: noop,
58689   paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
58690   text: /^[^\n]+/
58691 };
58692
58693 block.bullet = /(?:[*+-]|\d+\.)/;
58694 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
58695 block.item = replace(block.item, 'gm')
58696   (/bull/g, block.bullet)
58697   ();
58698
58699 block.list = replace(block.list)
58700   (/bull/g, block.bullet)
58701   ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
58702   ('def', '\\n+(?=' + block.def.source + ')')
58703   ();
58704
58705 block.blockquote = replace(block.blockquote)
58706   ('def', block.def)
58707   ();
58708
58709 block._tag = '(?!(?:'
58710   + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
58711   + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
58712   + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
58713
58714 block.html = replace(block.html)
58715   ('comment', /<!--[\s\S]*?-->/)
58716   ('closed', /<(tag)[\s\S]+?<\/\1>/)
58717   ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
58718   (/tag/g, block._tag)
58719   ();
58720
58721 block.paragraph = replace(block.paragraph)
58722   ('hr', block.hr)
58723   ('heading', block.heading)
58724   ('lheading', block.lheading)
58725   ('blockquote', block.blockquote)
58726   ('tag', '<' + block._tag)
58727   ('def', block.def)
58728   ();
58729
58730 /**
58731  * Normal Block Grammar
58732  */
58733
58734 block.normal = merge({}, block);
58735
58736 /**
58737  * GFM Block Grammar
58738  */
58739
58740 block.gfm = merge({}, block.normal, {
58741   fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
58742   paragraph: /^/,
58743   heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
58744 });
58745
58746 block.gfm.paragraph = replace(block.paragraph)
58747   ('(?!', '(?!'
58748     + block.gfm.fences.source.replace('\\1', '\\2') + '|'
58749     + block.list.source.replace('\\1', '\\3') + '|')
58750   ();
58751
58752 /**
58753  * GFM + Tables Block Grammar
58754  */
58755
58756 block.tables = merge({}, block.gfm, {
58757   nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
58758   table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
58759 });
58760
58761 /**
58762  * Block Lexer
58763  */
58764
58765 function Lexer(options) {
58766   this.tokens = [];
58767   this.tokens.links = {};
58768   this.options = options || marked.defaults;
58769   this.rules = block.normal;
58770
58771   if (this.options.gfm) {
58772     if (this.options.tables) {
58773       this.rules = block.tables;
58774     } else {
58775       this.rules = block.gfm;
58776     }
58777   }
58778 }
58779
58780 /**
58781  * Expose Block Rules
58782  */
58783
58784 Lexer.rules = block;
58785
58786 /**
58787  * Static Lex Method
58788  */
58789
58790 Lexer.lex = function(src, options) {
58791   var lexer = new Lexer(options);
58792   return lexer.lex(src);
58793 };
58794
58795 /**
58796  * Preprocessing
58797  */
58798
58799 Lexer.prototype.lex = function(src) {
58800   src = src
58801     .replace(/\r\n|\r/g, '\n')
58802     .replace(/\t/g, '    ')
58803     .replace(/\u00a0/g, ' ')
58804     .replace(/\u2424/g, '\n');
58805
58806   return this.token(src, true);
58807 };
58808
58809 /**
58810  * Lexing
58811  */
58812
58813 Lexer.prototype.token = function(src, top, bq) {
58814   var src = src.replace(/^ +$/gm, '')
58815     , next
58816     , loose
58817     , cap
58818     , bull
58819     , b
58820     , item
58821     , space
58822     , i
58823     , l;
58824
58825   while (src) {
58826     // newline
58827     if (cap = this.rules.newline.exec(src)) {
58828       src = src.substring(cap[0].length);
58829       if (cap[0].length > 1) {
58830         this.tokens.push({
58831           type: 'space'
58832         });
58833       }
58834     }
58835
58836     // code
58837     if (cap = this.rules.code.exec(src)) {
58838       src = src.substring(cap[0].length);
58839       cap = cap[0].replace(/^ {4}/gm, '');
58840       this.tokens.push({
58841         type: 'code',
58842         text: !this.options.pedantic
58843           ? cap.replace(/\n+$/, '')
58844           : cap
58845       });
58846       continue;
58847     }
58848
58849     // fences (gfm)
58850     if (cap = this.rules.fences.exec(src)) {
58851       src = src.substring(cap[0].length);
58852       this.tokens.push({
58853         type: 'code',
58854         lang: cap[2],
58855         text: cap[3] || ''
58856       });
58857       continue;
58858     }
58859
58860     // heading
58861     if (cap = this.rules.heading.exec(src)) {
58862       src = src.substring(cap[0].length);
58863       this.tokens.push({
58864         type: 'heading',
58865         depth: cap[1].length,
58866         text: cap[2]
58867       });
58868       continue;
58869     }
58870
58871     // table no leading pipe (gfm)
58872     if (top && (cap = this.rules.nptable.exec(src))) {
58873       src = src.substring(cap[0].length);
58874
58875       item = {
58876         type: 'table',
58877         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
58878         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
58879         cells: cap[3].replace(/\n$/, '').split('\n')
58880       };
58881
58882       for (i = 0; i < item.align.length; i++) {
58883         if (/^ *-+: *$/.test(item.align[i])) {
58884           item.align[i] = 'right';
58885         } else if (/^ *:-+: *$/.test(item.align[i])) {
58886           item.align[i] = 'center';
58887         } else if (/^ *:-+ *$/.test(item.align[i])) {
58888           item.align[i] = 'left';
58889         } else {
58890           item.align[i] = null;
58891         }
58892       }
58893
58894       for (i = 0; i < item.cells.length; i++) {
58895         item.cells[i] = item.cells[i].split(/ *\| */);
58896       }
58897
58898       this.tokens.push(item);
58899
58900       continue;
58901     }
58902
58903     // lheading
58904     if (cap = this.rules.lheading.exec(src)) {
58905       src = src.substring(cap[0].length);
58906       this.tokens.push({
58907         type: 'heading',
58908         depth: cap[2] === '=' ? 1 : 2,
58909         text: cap[1]
58910       });
58911       continue;
58912     }
58913
58914     // hr
58915     if (cap = this.rules.hr.exec(src)) {
58916       src = src.substring(cap[0].length);
58917       this.tokens.push({
58918         type: 'hr'
58919       });
58920       continue;
58921     }
58922
58923     // blockquote
58924     if (cap = this.rules.blockquote.exec(src)) {
58925       src = src.substring(cap[0].length);
58926
58927       this.tokens.push({
58928         type: 'blockquote_start'
58929       });
58930
58931       cap = cap[0].replace(/^ *> ?/gm, '');
58932
58933       // Pass `top` to keep the current
58934       // "toplevel" state. This is exactly
58935       // how markdown.pl works.
58936       this.token(cap, top, true);
58937
58938       this.tokens.push({
58939         type: 'blockquote_end'
58940       });
58941
58942       continue;
58943     }
58944
58945     // list
58946     if (cap = this.rules.list.exec(src)) {
58947       src = src.substring(cap[0].length);
58948       bull = cap[2];
58949
58950       this.tokens.push({
58951         type: 'list_start',
58952         ordered: bull.length > 1
58953       });
58954
58955       // Get each top-level item.
58956       cap = cap[0].match(this.rules.item);
58957
58958       next = false;
58959       l = cap.length;
58960       i = 0;
58961
58962       for (; i < l; i++) {
58963         item = cap[i];
58964
58965         // Remove the list item's bullet
58966         // so it is seen as the next token.
58967         space = item.length;
58968         item = item.replace(/^ *([*+-]|\d+\.) +/, '');
58969
58970         // Outdent whatever the
58971         // list item contains. Hacky.
58972         if (~item.indexOf('\n ')) {
58973           space -= item.length;
58974           item = !this.options.pedantic
58975             ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
58976             : item.replace(/^ {1,4}/gm, '');
58977         }
58978
58979         // Determine whether the next list item belongs here.
58980         // Backpedal if it does not belong in this list.
58981         if (this.options.smartLists && i !== l - 1) {
58982           b = block.bullet.exec(cap[i + 1])[0];
58983           if (bull !== b && !(bull.length > 1 && b.length > 1)) {
58984             src = cap.slice(i + 1).join('\n') + src;
58985             i = l - 1;
58986           }
58987         }
58988
58989         // Determine whether item is loose or not.
58990         // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
58991         // for discount behavior.
58992         loose = next || /\n\n(?!\s*$)/.test(item);
58993         if (i !== l - 1) {
58994           next = item.charAt(item.length - 1) === '\n';
58995           if (!loose) loose = next;
58996         }
58997
58998         this.tokens.push({
58999           type: loose
59000             ? 'loose_item_start'
59001             : 'list_item_start'
59002         });
59003
59004         // Recurse.
59005         this.token(item, false, bq);
59006
59007         this.tokens.push({
59008           type: 'list_item_end'
59009         });
59010       }
59011
59012       this.tokens.push({
59013         type: 'list_end'
59014       });
59015
59016       continue;
59017     }
59018
59019     // html
59020     if (cap = this.rules.html.exec(src)) {
59021       src = src.substring(cap[0].length);
59022       this.tokens.push({
59023         type: this.options.sanitize
59024           ? 'paragraph'
59025           : 'html',
59026         pre: !this.options.sanitizer
59027           && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
59028         text: cap[0]
59029       });
59030       continue;
59031     }
59032
59033     // def
59034     if ((!bq && top) && (cap = this.rules.def.exec(src))) {
59035       src = src.substring(cap[0].length);
59036       this.tokens.links[cap[1].toLowerCase()] = {
59037         href: cap[2],
59038         title: cap[3]
59039       };
59040       continue;
59041     }
59042
59043     // table (gfm)
59044     if (top && (cap = this.rules.table.exec(src))) {
59045       src = src.substring(cap[0].length);
59046
59047       item = {
59048         type: 'table',
59049         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
59050         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
59051         cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
59052       };
59053
59054       for (i = 0; i < item.align.length; i++) {
59055         if (/^ *-+: *$/.test(item.align[i])) {
59056           item.align[i] = 'right';
59057         } else if (/^ *:-+: *$/.test(item.align[i])) {
59058           item.align[i] = 'center';
59059         } else if (/^ *:-+ *$/.test(item.align[i])) {
59060           item.align[i] = 'left';
59061         } else {
59062           item.align[i] = null;
59063         }
59064       }
59065
59066       for (i = 0; i < item.cells.length; i++) {
59067         item.cells[i] = item.cells[i]
59068           .replace(/^ *\| *| *\| *$/g, '')
59069           .split(/ *\| */);
59070       }
59071
59072       this.tokens.push(item);
59073
59074       continue;
59075     }
59076
59077     // top-level paragraph
59078     if (top && (cap = this.rules.paragraph.exec(src))) {
59079       src = src.substring(cap[0].length);
59080       this.tokens.push({
59081         type: 'paragraph',
59082         text: cap[1].charAt(cap[1].length - 1) === '\n'
59083           ? cap[1].slice(0, -1)
59084           : cap[1]
59085       });
59086       continue;
59087     }
59088
59089     // text
59090     if (cap = this.rules.text.exec(src)) {
59091       // Top-level should never reach here.
59092       src = src.substring(cap[0].length);
59093       this.tokens.push({
59094         type: 'text',
59095         text: cap[0]
59096       });
59097       continue;
59098     }
59099
59100     if (src) {
59101       throw new
59102         Error('Infinite loop on byte: ' + src.charCodeAt(0));
59103     }
59104   }
59105
59106   return this.tokens;
59107 };
59108
59109 /**
59110  * Inline-Level Grammar
59111  */
59112
59113 var inline = {
59114   escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
59115   autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
59116   url: noop,
59117   tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
59118   link: /^!?\[(inside)\]\(href\)/,
59119   reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
59120   nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
59121   strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
59122   em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
59123   code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
59124   br: /^ {2,}\n(?!\s*$)/,
59125   del: noop,
59126   text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
59127 };
59128
59129 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
59130 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
59131
59132 inline.link = replace(inline.link)
59133   ('inside', inline._inside)
59134   ('href', inline._href)
59135   ();
59136
59137 inline.reflink = replace(inline.reflink)
59138   ('inside', inline._inside)
59139   ();
59140
59141 /**
59142  * Normal Inline Grammar
59143  */
59144
59145 inline.normal = merge({}, inline);
59146
59147 /**
59148  * Pedantic Inline Grammar
59149  */
59150
59151 inline.pedantic = merge({}, inline.normal, {
59152   strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
59153   em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
59154 });
59155
59156 /**
59157  * GFM Inline Grammar
59158  */
59159
59160 inline.gfm = merge({}, inline.normal, {
59161   escape: replace(inline.escape)('])', '~|])')(),
59162   url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
59163   del: /^~~(?=\S)([\s\S]*?\S)~~/,
59164   text: replace(inline.text)
59165     (']|', '~]|')
59166     ('|', '|https?://|')
59167     ()
59168 });
59169
59170 /**
59171  * GFM + Line Breaks Inline Grammar
59172  */
59173
59174 inline.breaks = merge({}, inline.gfm, {
59175   br: replace(inline.br)('{2,}', '*')(),
59176   text: replace(inline.gfm.text)('{2,}', '*')()
59177 });
59178
59179 /**
59180  * Inline Lexer & Compiler
59181  */
59182
59183 function InlineLexer(links, options) {
59184   this.options = options || marked.defaults;
59185   this.links = links;
59186   this.rules = inline.normal;
59187   this.renderer = this.options.renderer || new Renderer;
59188   this.renderer.options = this.options;
59189
59190   if (!this.links) {
59191     throw new
59192       Error('Tokens array requires a `links` property.');
59193   }
59194
59195   if (this.options.gfm) {
59196     if (this.options.breaks) {
59197       this.rules = inline.breaks;
59198     } else {
59199       this.rules = inline.gfm;
59200     }
59201   } else if (this.options.pedantic) {
59202     this.rules = inline.pedantic;
59203   }
59204 }
59205
59206 /**
59207  * Expose Inline Rules
59208  */
59209
59210 InlineLexer.rules = inline;
59211
59212 /**
59213  * Static Lexing/Compiling Method
59214  */
59215
59216 InlineLexer.output = function(src, links, options) {
59217   var inline = new InlineLexer(links, options);
59218   return inline.output(src);
59219 };
59220
59221 /**
59222  * Lexing/Compiling
59223  */
59224
59225 InlineLexer.prototype.output = function(src) {
59226   var out = ''
59227     , link
59228     , text
59229     , href
59230     , cap;
59231
59232   while (src) {
59233     // escape
59234     if (cap = this.rules.escape.exec(src)) {
59235       src = src.substring(cap[0].length);
59236       out += cap[1];
59237       continue;
59238     }
59239
59240     // autolink
59241     if (cap = this.rules.autolink.exec(src)) {
59242       src = src.substring(cap[0].length);
59243       if (cap[2] === '@') {
59244         text = cap[1].charAt(6) === ':'
59245           ? this.mangle(cap[1].substring(7))
59246           : this.mangle(cap[1]);
59247         href = this.mangle('mailto:') + text;
59248       } else {
59249         text = escape(cap[1]);
59250         href = text;
59251       }
59252       out += this.renderer.link(href, null, text);
59253       continue;
59254     }
59255
59256     // url (gfm)
59257     if (!this.inLink && (cap = this.rules.url.exec(src))) {
59258       src = src.substring(cap[0].length);
59259       text = escape(cap[1]);
59260       href = text;
59261       out += this.renderer.link(href, null, text);
59262       continue;
59263     }
59264
59265     // tag
59266     if (cap = this.rules.tag.exec(src)) {
59267       if (!this.inLink && /^<a /i.test(cap[0])) {
59268         this.inLink = true;
59269       } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
59270         this.inLink = false;
59271       }
59272       src = src.substring(cap[0].length);
59273       out += this.options.sanitize
59274         ? this.options.sanitizer
59275           ? this.options.sanitizer(cap[0])
59276           : escape(cap[0])
59277         : cap[0];
59278       continue;
59279     }
59280
59281     // link
59282     if (cap = this.rules.link.exec(src)) {
59283       src = src.substring(cap[0].length);
59284       this.inLink = true;
59285       out += this.outputLink(cap, {
59286         href: cap[2],
59287         title: cap[3]
59288       });
59289       this.inLink = false;
59290       continue;
59291     }
59292
59293     // reflink, nolink
59294     if ((cap = this.rules.reflink.exec(src))
59295         || (cap = this.rules.nolink.exec(src))) {
59296       src = src.substring(cap[0].length);
59297       link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
59298       link = this.links[link.toLowerCase()];
59299       if (!link || !link.href) {
59300         out += cap[0].charAt(0);
59301         src = cap[0].substring(1) + src;
59302         continue;
59303       }
59304       this.inLink = true;
59305       out += this.outputLink(cap, link);
59306       this.inLink = false;
59307       continue;
59308     }
59309
59310     // strong
59311     if (cap = this.rules.strong.exec(src)) {
59312       src = src.substring(cap[0].length);
59313       out += this.renderer.strong(this.output(cap[2] || cap[1]));
59314       continue;
59315     }
59316
59317     // em
59318     if (cap = this.rules.em.exec(src)) {
59319       src = src.substring(cap[0].length);
59320       out += this.renderer.em(this.output(cap[2] || cap[1]));
59321       continue;
59322     }
59323
59324     // code
59325     if (cap = this.rules.code.exec(src)) {
59326       src = src.substring(cap[0].length);
59327       out += this.renderer.codespan(escape(cap[2], true));
59328       continue;
59329     }
59330
59331     // br
59332     if (cap = this.rules.br.exec(src)) {
59333       src = src.substring(cap[0].length);
59334       out += this.renderer.br();
59335       continue;
59336     }
59337
59338     // del (gfm)
59339     if (cap = this.rules.del.exec(src)) {
59340       src = src.substring(cap[0].length);
59341       out += this.renderer.del(this.output(cap[1]));
59342       continue;
59343     }
59344
59345     // text
59346     if (cap = this.rules.text.exec(src)) {
59347       src = src.substring(cap[0].length);
59348       out += this.renderer.text(escape(this.smartypants(cap[0])));
59349       continue;
59350     }
59351
59352     if (src) {
59353       throw new
59354         Error('Infinite loop on byte: ' + src.charCodeAt(0));
59355     }
59356   }
59357
59358   return out;
59359 };
59360
59361 /**
59362  * Compile Link
59363  */
59364
59365 InlineLexer.prototype.outputLink = function(cap, link) {
59366   var href = escape(link.href)
59367     , title = link.title ? escape(link.title) : null;
59368
59369   return cap[0].charAt(0) !== '!'
59370     ? this.renderer.link(href, title, this.output(cap[1]))
59371     : this.renderer.image(href, title, escape(cap[1]));
59372 };
59373
59374 /**
59375  * Smartypants Transformations
59376  */
59377
59378 InlineLexer.prototype.smartypants = function(text) {
59379   if (!this.options.smartypants) return text;
59380   return text
59381     // em-dashes
59382     .replace(/---/g, '\u2014')
59383     // en-dashes
59384     .replace(/--/g, '\u2013')
59385     // opening singles
59386     .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
59387     // closing singles & apostrophes
59388     .replace(/'/g, '\u2019')
59389     // opening doubles
59390     .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
59391     // closing doubles
59392     .replace(/"/g, '\u201d')
59393     // ellipses
59394     .replace(/\.{3}/g, '\u2026');
59395 };
59396
59397 /**
59398  * Mangle Links
59399  */
59400
59401 InlineLexer.prototype.mangle = function(text) {
59402   if (!this.options.mangle) return text;
59403   var out = ''
59404     , l = text.length
59405     , i = 0
59406     , ch;
59407
59408   for (; i < l; i++) {
59409     ch = text.charCodeAt(i);
59410     if (Math.random() > 0.5) {
59411       ch = 'x' + ch.toString(16);
59412     }
59413     out += '&#' + ch + ';';
59414   }
59415
59416   return out;
59417 };
59418
59419 /**
59420  * Renderer
59421  */
59422
59423 function Renderer(options) {
59424   this.options = options || {};
59425 }
59426
59427 Renderer.prototype.code = function(code, lang, escaped) {
59428   if (this.options.highlight) {
59429     var out = this.options.highlight(code, lang);
59430     if (out != null && out !== code) {
59431       escaped = true;
59432       code = out;
59433     }
59434   }
59435
59436   if (!lang) {
59437     return '<pre><code>'
59438       + (escaped ? code : escape(code, true))
59439       + '\n</code></pre>';
59440   }
59441
59442   return '<pre><code class="'
59443     + this.options.langPrefix
59444     + escape(lang, true)
59445     + '">'
59446     + (escaped ? code : escape(code, true))
59447     + '\n</code></pre>\n';
59448 };
59449
59450 Renderer.prototype.blockquote = function(quote) {
59451   return '<blockquote>\n' + quote + '</blockquote>\n';
59452 };
59453
59454 Renderer.prototype.html = function(html) {
59455   return html;
59456 };
59457
59458 Renderer.prototype.heading = function(text, level, raw) {
59459   return '<h'
59460     + level
59461     + ' id="'
59462     + this.options.headerPrefix
59463     + raw.toLowerCase().replace(/[^\w]+/g, '-')
59464     + '">'
59465     + text
59466     + '</h'
59467     + level
59468     + '>\n';
59469 };
59470
59471 Renderer.prototype.hr = function() {
59472   return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
59473 };
59474
59475 Renderer.prototype.list = function(body, ordered) {
59476   var type = ordered ? 'ol' : 'ul';
59477   return '<' + type + '>\n' + body + '</' + type + '>\n';
59478 };
59479
59480 Renderer.prototype.listitem = function(text) {
59481   return '<li>' + text + '</li>\n';
59482 };
59483
59484 Renderer.prototype.paragraph = function(text) {
59485   return '<p>' + text + '</p>\n';
59486 };
59487
59488 Renderer.prototype.table = function(header, body) {
59489   return '<table>\n'
59490     + '<thead>\n'
59491     + header
59492     + '</thead>\n'
59493     + '<tbody>\n'
59494     + body
59495     + '</tbody>\n'
59496     + '</table>\n';
59497 };
59498
59499 Renderer.prototype.tablerow = function(content) {
59500   return '<tr>\n' + content + '</tr>\n';
59501 };
59502
59503 Renderer.prototype.tablecell = function(content, flags) {
59504   var type = flags.header ? 'th' : 'td';
59505   var tag = flags.align
59506     ? '<' + type + ' style="text-align:' + flags.align + '">'
59507     : '<' + type + '>';
59508   return tag + content + '</' + type + '>\n';
59509 };
59510
59511 // span level renderer
59512 Renderer.prototype.strong = function(text) {
59513   return '<strong>' + text + '</strong>';
59514 };
59515
59516 Renderer.prototype.em = function(text) {
59517   return '<em>' + text + '</em>';
59518 };
59519
59520 Renderer.prototype.codespan = function(text) {
59521   return '<code>' + text + '</code>';
59522 };
59523
59524 Renderer.prototype.br = function() {
59525   return this.options.xhtml ? '<br/>' : '<br>';
59526 };
59527
59528 Renderer.prototype.del = function(text) {
59529   return '<del>' + text + '</del>';
59530 };
59531
59532 Renderer.prototype.link = function(href, title, text) {
59533   if (this.options.sanitize) {
59534     try {
59535       var prot = decodeURIComponent(unescape(href))
59536         .replace(/[^\w:]/g, '')
59537         .toLowerCase();
59538     } catch (e) {
59539       return '';
59540     }
59541     if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
59542       return '';
59543     }
59544   }
59545   var out = '<a href="' + href + '"';
59546   if (title) {
59547     out += ' title="' + title + '"';
59548   }
59549   out += '>' + text + '</a>';
59550   return out;
59551 };
59552
59553 Renderer.prototype.image = function(href, title, text) {
59554   var out = '<img src="' + href + '" alt="' + text + '"';
59555   if (title) {
59556     out += ' title="' + title + '"';
59557   }
59558   out += this.options.xhtml ? '/>' : '>';
59559   return out;
59560 };
59561
59562 Renderer.prototype.text = function(text) {
59563   return text;
59564 };
59565
59566 /**
59567  * Parsing & Compiling
59568  */
59569
59570 function Parser(options) {
59571   this.tokens = [];
59572   this.token = null;
59573   this.options = options || marked.defaults;
59574   this.options.renderer = this.options.renderer || new Renderer;
59575   this.renderer = this.options.renderer;
59576   this.renderer.options = this.options;
59577 }
59578
59579 /**
59580  * Static Parse Method
59581  */
59582
59583 Parser.parse = function(src, options, renderer) {
59584   var parser = new Parser(options, renderer);
59585   return parser.parse(src);
59586 };
59587
59588 /**
59589  * Parse Loop
59590  */
59591
59592 Parser.prototype.parse = function(src) {
59593   this.inline = new InlineLexer(src.links, this.options, this.renderer);
59594   this.tokens = src.reverse();
59595
59596   var out = '';
59597   while (this.next()) {
59598     out += this.tok();
59599   }
59600
59601   return out;
59602 };
59603
59604 /**
59605  * Next Token
59606  */
59607
59608 Parser.prototype.next = function() {
59609   return this.token = this.tokens.pop();
59610 };
59611
59612 /**
59613  * Preview Next Token
59614  */
59615
59616 Parser.prototype.peek = function() {
59617   return this.tokens[this.tokens.length - 1] || 0;
59618 };
59619
59620 /**
59621  * Parse Text Tokens
59622  */
59623
59624 Parser.prototype.parseText = function() {
59625   var body = this.token.text;
59626
59627   while (this.peek().type === 'text') {
59628     body += '\n' + this.next().text;
59629   }
59630
59631   return this.inline.output(body);
59632 };
59633
59634 /**
59635  * Parse Current Token
59636  */
59637
59638 Parser.prototype.tok = function() {
59639   switch (this.token.type) {
59640     case 'space': {
59641       return '';
59642     }
59643     case 'hr': {
59644       return this.renderer.hr();
59645     }
59646     case 'heading': {
59647       return this.renderer.heading(
59648         this.inline.output(this.token.text),
59649         this.token.depth,
59650         this.token.text);
59651     }
59652     case 'code': {
59653       return this.renderer.code(this.token.text,
59654         this.token.lang,
59655         this.token.escaped);
59656     }
59657     case 'table': {
59658       var header = ''
59659         , body = ''
59660         , i
59661         , row
59662         , cell
59663         , flags
59664         , j;
59665
59666       // header
59667       cell = '';
59668       for (i = 0; i < this.token.header.length; i++) {
59669         flags = { header: true, align: this.token.align[i] };
59670         cell += this.renderer.tablecell(
59671           this.inline.output(this.token.header[i]),
59672           { header: true, align: this.token.align[i] }
59673         );
59674       }
59675       header += this.renderer.tablerow(cell);
59676
59677       for (i = 0; i < this.token.cells.length; i++) {
59678         row = this.token.cells[i];
59679
59680         cell = '';
59681         for (j = 0; j < row.length; j++) {
59682           cell += this.renderer.tablecell(
59683             this.inline.output(row[j]),
59684             { header: false, align: this.token.align[j] }
59685           );
59686         }
59687
59688         body += this.renderer.tablerow(cell);
59689       }
59690       return this.renderer.table(header, body);
59691     }
59692     case 'blockquote_start': {
59693       var body = '';
59694
59695       while (this.next().type !== 'blockquote_end') {
59696         body += this.tok();
59697       }
59698
59699       return this.renderer.blockquote(body);
59700     }
59701     case 'list_start': {
59702       var body = ''
59703         , ordered = this.token.ordered;
59704
59705       while (this.next().type !== 'list_end') {
59706         body += this.tok();
59707       }
59708
59709       return this.renderer.list(body, ordered);
59710     }
59711     case 'list_item_start': {
59712       var body = '';
59713
59714       while (this.next().type !== 'list_item_end') {
59715         body += this.token.type === 'text'
59716           ? this.parseText()
59717           : this.tok();
59718       }
59719
59720       return this.renderer.listitem(body);
59721     }
59722     case 'loose_item_start': {
59723       var body = '';
59724
59725       while (this.next().type !== 'list_item_end') {
59726         body += this.tok();
59727       }
59728
59729       return this.renderer.listitem(body);
59730     }
59731     case 'html': {
59732       var html = !this.token.pre && !this.options.pedantic
59733         ? this.inline.output(this.token.text)
59734         : this.token.text;
59735       return this.renderer.html(html);
59736     }
59737     case 'paragraph': {
59738       return this.renderer.paragraph(this.inline.output(this.token.text));
59739     }
59740     case 'text': {
59741       return this.renderer.paragraph(this.parseText());
59742     }
59743   }
59744 };
59745
59746 /**
59747  * Helpers
59748  */
59749
59750 function escape(html, encode) {
59751   return html
59752     .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
59753     .replace(/</g, '&lt;')
59754     .replace(/>/g, '&gt;')
59755     .replace(/"/g, '&quot;')
59756     .replace(/'/g, '&#39;');
59757 }
59758
59759 function unescape(html) {
59760         // explicitly match decimal, hex, and named HTML entities 
59761   return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
59762     n = n.toLowerCase();
59763     if (n === 'colon') return ':';
59764     if (n.charAt(0) === '#') {
59765       return n.charAt(1) === 'x'
59766         ? String.fromCharCode(parseInt(n.substring(2), 16))
59767         : String.fromCharCode(+n.substring(1));
59768     }
59769     return '';
59770   });
59771 }
59772
59773 function replace(regex, opt) {
59774   regex = regex.source;
59775   opt = opt || '';
59776   return function self(name, val) {
59777     if (!name) return new RegExp(regex, opt);
59778     val = val.source || val;
59779     val = val.replace(/(^|[^\[])\^/g, '$1');
59780     regex = regex.replace(name, val);
59781     return self;
59782   };
59783 }
59784
59785 function noop() {}
59786 noop.exec = noop;
59787
59788 function merge(obj) {
59789   var i = 1
59790     , target
59791     , key;
59792
59793   for (; i < arguments.length; i++) {
59794     target = arguments[i];
59795     for (key in target) {
59796       if (Object.prototype.hasOwnProperty.call(target, key)) {
59797         obj[key] = target[key];
59798       }
59799     }
59800   }
59801
59802   return obj;
59803 }
59804
59805
59806 /**
59807  * Marked
59808  */
59809
59810 function marked(src, opt, callback) {
59811   if (callback || typeof opt === 'function') {
59812     if (!callback) {
59813       callback = opt;
59814       opt = null;
59815     }
59816
59817     opt = merge({}, marked.defaults, opt || {});
59818
59819     var highlight = opt.highlight
59820       , tokens
59821       , pending
59822       , i = 0;
59823
59824     try {
59825       tokens = Lexer.lex(src, opt);
59826     } catch (e) {
59827       return callback(e);
59828     }
59829
59830     pending = tokens.length;
59831
59832     var done = function(err) {
59833       if (err) {
59834         opt.highlight = highlight;
59835         return callback(err);
59836       }
59837
59838       var out;
59839
59840       try {
59841         out = Parser.parse(tokens, opt);
59842       } catch (e) {
59843         err = e;
59844       }
59845
59846       opt.highlight = highlight;
59847
59848       return err
59849         ? callback(err)
59850         : callback(null, out);
59851     };
59852
59853     if (!highlight || highlight.length < 3) {
59854       return done();
59855     }
59856
59857     delete opt.highlight;
59858
59859     if (!pending) return done();
59860
59861     for (; i < tokens.length; i++) {
59862       (function(token) {
59863         if (token.type !== 'code') {
59864           return --pending || done();
59865         }
59866         return highlight(token.text, token.lang, function(err, code) {
59867           if (err) return done(err);
59868           if (code == null || code === token.text) {
59869             return --pending || done();
59870           }
59871           token.text = code;
59872           token.escaped = true;
59873           --pending || done();
59874         });
59875       })(tokens[i]);
59876     }
59877
59878     return;
59879   }
59880   try {
59881     if (opt) opt = merge({}, marked.defaults, opt);
59882     return Parser.parse(Lexer.lex(src, opt), opt);
59883   } catch (e) {
59884     e.message += '\nPlease report this to https://github.com/chjj/marked.';
59885     if ((opt || marked.defaults).silent) {
59886       return '<p>An error occured:</p><pre>'
59887         + escape(e.message + '', true)
59888         + '</pre>';
59889     }
59890     throw e;
59891   }
59892 }
59893
59894 /**
59895  * Options
59896  */
59897
59898 marked.options =
59899 marked.setOptions = function(opt) {
59900   merge(marked.defaults, opt);
59901   return marked;
59902 };
59903
59904 marked.defaults = {
59905   gfm: true,
59906   tables: true,
59907   breaks: false,
59908   pedantic: false,
59909   sanitize: false,
59910   sanitizer: null,
59911   mangle: true,
59912   smartLists: false,
59913   silent: false,
59914   highlight: null,
59915   langPrefix: 'lang-',
59916   smartypants: false,
59917   headerPrefix: '',
59918   renderer: new Renderer,
59919   xhtml: false
59920 };
59921
59922 /**
59923  * Expose
59924  */
59925
59926 marked.Parser = Parser;
59927 marked.parser = Parser.parse;
59928
59929 marked.Renderer = Renderer;
59930
59931 marked.Lexer = Lexer;
59932 marked.lexer = Lexer.lex;
59933
59934 marked.InlineLexer = InlineLexer;
59935 marked.inlineLexer = InlineLexer.output;
59936
59937 marked.parse = marked;
59938
59939 {
59940   module.exports = marked;
59941 }
59942
59943 }).call(function() {
59944   return this || (typeof window !== 'undefined' ? window : commonjsGlobal);
59945 }());
59946 });
59947
59948 function pointBox(loc, context) {
59949     var rect = context.surfaceRect();
59950     var point = context.curtainProjection(loc);
59951     return {
59952         left: point[0] + rect.left - 40,
59953         top: point[1] + rect.top - 60,
59954         width: 80,
59955         height: 90
59956     };
59957 }
59958
59959
59960 function pad$1(locOrBox, padding, context) {
59961     var box;
59962     if (locOrBox instanceof Array) {
59963         var rect = context.surfaceRect();
59964         var point = context.curtainProjection(locOrBox);
59965         box = {
59966             left: point[0] + rect.left,
59967             top: point[1] + rect.top
59968         };
59969     } else {
59970         box = locOrBox;
59971     }
59972
59973     return {
59974         left: box.left - padding,
59975         top: box.top - padding,
59976         width: (box.width || 0) + 2 * padding,
59977         height: (box.width || 0) + 2 * padding
59978     };
59979 }
59980
59981
59982 function icon(name, svgklass) {
59983     return '<svg class="icon ' + (svgklass || '') + '">' +
59984          '<use xlink:href="' + name + '"></use></svg>';
59985 }
59986
59987
59988 function slugify(text$$1) {
59989     return text$$1.toString().toLowerCase()
59990         .replace(/\s+/g, '-')           // Replace spaces with -
59991         .replace(/[^\w\-]+/g, '')       // Remove all non-word chars
59992         .replace(/\-\-+/g, '-')         // Replace multiple - with single -
59993         .replace(/^-+/, '')             // Trim - from start of text
59994         .replace(/-+$/, '');            // Trim - from end of text
59995 }
59996
59997
59998 // console warning for missing walkthrough names
59999 var missingStrings = {};
60000 function checkKey(key, text$$1) {
60001     if (t(key, { default: undefined}) === undefined) {
60002         if (missingStrings.hasOwnProperty(key)) return;  // warn once
60003         missingStrings[key] = text$$1;
60004         var missing = key + ': ' + text$$1;
60005         if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
60006     }
60007 }
60008
60009
60010 function localize(obj) {
60011     var key;
60012
60013     // Assign name if entity has one..
60014     var name = obj.tags && obj.tags.name;
60015     if (name) {
60016         key = 'intro.graph.name.' + slugify(name);
60017         obj.tags.name = t(key, { default: name });
60018         checkKey(key, name);
60019     }
60020
60021     // Assign street name if entity has one..
60022     var street = obj.tags && obj.tags['addr:street'];
60023     if (street) {
60024         key = 'intro.graph.name.' + slugify(street);
60025         obj.tags['addr:street'] = t(key, { default: street });
60026         checkKey(key, street);
60027
60028         // Add address details common across walkthrough..
60029         var addrTags = [
60030             'block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood',
60031             'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'
60032         ];
60033         addrTags.forEach(function(k) {
60034             var key = 'intro.graph.' + k,
60035                 tag = 'addr:' + k,
60036                 val = obj.tags && obj.tags[tag],
60037                 str = t(key, { default: val });
60038
60039             if (str) {
60040                 if (str.match(/^<.*>$/) !== null) {
60041                     delete obj.tags[tag];
60042                 } else {
60043                     obj.tags[tag] = str;
60044                 }
60045             }
60046         });
60047     }
60048
60049     return obj;
60050 }
60051
60052
60053 // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
60054 function isMostlySquare(points) {
60055     // note: uses 15 here instead of the 12 from actionOrthogonalize because
60056     // actionOrthogonalize can actually straighten some larger angles as it iterates
60057     var threshold$$1 = 15, // degrees within right or straight
60058         lowerBound = Math.cos((90 - threshold$$1) * Math.PI / 180),  // near right
60059         upperBound = Math.cos(threshold$$1 * Math.PI / 180),         // near straight
60060         mag;
60061
60062     for (var i = 0; i < points.length; i++) {
60063         mag = Math.abs(normalizedDotProduct(i, points));
60064         if (mag > lowerBound && mag < upperBound) {
60065             return false;
60066         }
60067     }
60068
60069     return true;
60070
60071
60072     function normalizedDotProduct(i, points) {
60073         var a = points[(i - 1 + points.length) % points.length],
60074             b = points[i],
60075             c = points[(i + 1) % points.length],
60076             p = subtractPoints(a, b),
60077             q = subtractPoints(c, b);
60078
60079         p = normalizePoint(p);
60080         q = normalizePoint(q);
60081
60082         return p[0] * q[0] + p[1] * q[1];
60083
60084
60085         function subtractPoints(a, b) {
60086             return [a[0] - b[0], a[1] - b[1]];
60087         }
60088
60089         function normalizePoint(point) {
60090             var vector = [0, 0];
60091             var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
60092             if (length !== 0) {
60093                 vector[0] = point[0] / length;
60094                 vector[1] = point[1] / length;
60095             }
60096             return vector;
60097         }
60098     }
60099 }
60100
60101
60102 function selectMenuItem(operation) {
60103     var selector$$1 = '.edit-menu .edit-menu-item-' + operation +
60104         ', .radial-menu .radial-menu-item-' + operation;
60105     return select(selector$$1);
60106 }
60107
60108
60109 function transitionTime(point1, point2) {
60110     var distance$$1 = geoSphericalDistance(point1, point2);
60111     if (distance$$1 === 0)
60112         return 0;
60113     else if (distance$$1 < 80)
60114         return 500;
60115     else
60116         return 1000;
60117 }
60118
60119 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"}}};
60120
60121 // toggles the visibility of ui elements, using a combination of the
60122 // hide class, which sets display=none, and a d3 transition for opacity.
60123 // this will cause blinking when called repeatedly, so check that the
60124 // value actually changes between calls.
60125 function uiToggle(show, callback) {
60126     return function(selection$$1) {
60127         selection$$1
60128             .style('opacity', show ? 0 : 1)
60129             .classed('hide', false)
60130             .transition()
60131             .style('opacity', show ? 1 : 0)
60132             .on('end', function() {
60133                 select(this)
60134                     .classed('hide', !show)
60135                     .style('opacity', null);
60136                 if (callback) callback.apply(this);
60137             });
60138     };
60139 }
60140
60141 // Tooltips and svg mask used to highlight certain features
60142 function uiCurtain() {
60143
60144     var surface = select(null),
60145         tooltip = select(null),
60146         darkness = select(null);
60147
60148     function curtain(selection$$1) {
60149         surface = selection$$1
60150             .append('svg')
60151             .attr('id', 'curtain')
60152             .style('z-index', 1000)
60153             .style('pointer-events', 'none')
60154             .style('position', 'absolute')
60155             .style('top', 0)
60156             .style('left', 0);
60157
60158         darkness = surface.append('path')
60159             .attr('x', 0)
60160             .attr('y', 0)
60161             .attr('class', 'curtain-darkness');
60162
60163         select(window).on('resize.curtain', resize);
60164
60165         tooltip = selection$$1.append('div')
60166             .attr('class', 'tooltip')
60167             .style('z-index', 1002);
60168
60169         tooltip
60170             .append('div')
60171             .attr('class', 'tooltip-arrow');
60172
60173         tooltip
60174             .append('div')
60175             .attr('class', 'tooltip-inner');
60176
60177         resize();
60178
60179
60180         function resize() {
60181             surface
60182                 .attr('width', window.innerWidth)
60183                 .attr('height', window.innerHeight);
60184             curtain.cut(darkness.datum());
60185         }
60186     }
60187
60188
60189     /**
60190      * Reveal cuts the curtain to highlight the given box,
60191      * and shows a tooltip with instructions next to the box.
60192      *
60193      * @param  {String|ClientRect} [box]   box used to cut the curtain
60194      * @param  {String}    [text]          text for a tooltip
60195      * @param  {Object}    [options]
60196      * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
60197      * @param  {integer}   [options.duration]        transition time in milliseconds
60198      * @param  {string}    [options.buttonText]      if set, create a button with this text label
60199      * @param  {function}  [options.buttonCallback]  if set, the callback for the button
60200      * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
60201      */
60202     curtain.reveal = function(box, text$$1, options) {
60203         if (typeof box === 'string') {
60204             box = select(box).node();
60205         }
60206         if (box && box.getBoundingClientRect) {
60207             box = copyBox(box.getBoundingClientRect());
60208         }
60209
60210         options = options || {};
60211
60212         var tooltipBox;
60213         if (options.tooltipBox) {
60214             tooltipBox = options.tooltipBox;
60215             if (typeof tooltipBox === 'string') {
60216                 tooltipBox = select(tooltipBox).node();
60217             }
60218             if (tooltipBox && tooltipBox.getBoundingClientRect) {
60219                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
60220             }
60221         } else {
60222             tooltipBox = box;
60223         }
60224
60225         if (tooltipBox && text$$1) {
60226             // pseudo markdown bold text for the instruction section..
60227             var parts = text$$1.split('**');
60228             var html$$1 = parts[0] ? '<span>' + parts[0] + '</span>' : '';
60229             if (parts[1]) {
60230                 html$$1 += '<span class="instruction">' + parts[1] + '</span>';
60231             }
60232
60233             html$$1 = html$$1.replace(/\*(.*?)\*/g, '<em>$1</em>');   // emphasis
60234             html$$1 = html$$1.replace(/\{br\}/g, '<br/><br/>');       // linebreak
60235
60236             if (options.buttonText && options.buttonCallback) {
60237                 html$$1 += '<div class="button-section">' +
60238                     '<button href="#" class="button action col8">' + options.buttonText + '</button></div>';
60239             }
60240
60241             var classes = 'curtain-tooltip tooltip in ' + (options.tooltipClass || '');
60242             tooltip
60243                 .classed(classes, true)
60244                 .selectAll('.tooltip-inner')
60245                 .html(html$$1);
60246
60247             if (options.buttonText && options.buttonCallback) {
60248                 var button = tooltip.selectAll('.button-section .button.action');
60249                 button
60250                     .on('click', function() {
60251                         event.preventDefault();
60252                         options.buttonCallback();
60253                     });
60254             }
60255
60256             var tip = copyBox(tooltip.node().getBoundingClientRect()),
60257                 w = window.innerWidth,
60258                 h = window.innerHeight,
60259                 tooltipWidth = 200,
60260                 tooltipArrow = 5,
60261                 side, pos;
60262
60263
60264             // hack: this will have bottom placement,
60265             // so need to reserve extra space for the tooltip illustration.
60266             if (options.tooltipClass === 'intro-mouse') {
60267                 tip.height += 80;
60268             }
60269
60270             // trim box dimensions to just the portion that fits in the window..
60271             if (tooltipBox.top + tooltipBox.height > h) {
60272                 tooltipBox.height -= (tooltipBox.top + tooltipBox.height - h);
60273             }
60274             if (tooltipBox.left + tooltipBox.width > w) {
60275                 tooltipBox.width -= (tooltipBox.left + tooltipBox.width - w);
60276             }
60277
60278             // determine tooltip placement..
60279
60280             if (tooltipBox.top + tooltipBox.height < 100) {
60281                 // tooltip below box..
60282                 side = 'bottom';
60283                 pos = [
60284                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
60285                     tooltipBox.top + tooltipBox.height
60286                 ];
60287
60288             } else if (tooltipBox.top > h - 140) {
60289                 // tooltip above box..
60290                 side = 'top';
60291                 pos = [
60292                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
60293                     tooltipBox.top - tip.height
60294                 ];
60295
60296             } else {
60297                 // tooltip to the side of the tooltipBox..
60298                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
60299
60300                 if (textDirection === 'rtl') {
60301                     if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
60302                         side = 'right';
60303                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
60304
60305                     } else {
60306                         side = 'left';
60307                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
60308                     }
60309
60310                 } else {
60311                     if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
60312                         side = 'left';
60313                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
60314                     }
60315                     else {
60316                         side = 'right';
60317                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
60318                     }
60319                 }
60320             }
60321
60322             if (options.duration !== 0 || !tooltip.classed(side)) {
60323                 tooltip.call(uiToggle(true));
60324             }
60325
60326             tooltip
60327                 .style('top', pos[1] + 'px')
60328                 .style('left', pos[0] + 'px')
60329                 .attr('class', classes + ' ' + side);
60330
60331
60332             // shift tooltip-inner if it is very close to the top or bottom edge
60333             // (doesn't affect the placement of the tooltip-arrow)
60334             var shiftY = 0;
60335             if (side === 'left' || side === 'right') {
60336                 if (pos[1] < 60) {
60337                     shiftY = 60 - pos[1];
60338                 }
60339                 else if (pos[1] + tip.height > h - 100) {
60340                     shiftY = h - pos[1] - tip.height - 100;
60341                 }
60342             }
60343             tooltip.selectAll('.tooltip-inner')
60344                 .style('top', shiftY + 'px');
60345
60346         } else {
60347             tooltip
60348                 .classed('in', false)
60349                 .call(uiToggle(false));
60350         }
60351
60352         curtain.cut(box, options.duration);
60353
60354         return tooltip;
60355     };
60356
60357
60358     curtain.cut = function(datum, duration) {
60359         darkness.datum(datum)
60360             .interrupt();
60361
60362         var selection$$1;
60363         if (duration === 0) {
60364             selection$$1 = darkness;
60365         } else {
60366             selection$$1 = darkness
60367                 .transition()
60368                 .duration(duration || 600)
60369                 .ease(linear$1);
60370         }
60371
60372         selection$$1
60373             .attr('d', function(d) {
60374                 var string = 'M 0,0 L 0,' + window.innerHeight + ' L ' +
60375                     window.innerWidth + ',' + window.innerHeight + 'L' +
60376                     window.innerWidth + ',0 Z';
60377
60378                 if (!d) return string;
60379                 return string + 'M' +
60380                     d.left + ',' + d.top + 'L' +
60381                     d.left + ',' + (d.top + d.height) + 'L' +
60382                     (d.left + d.width) + ',' + (d.top + d.height) + 'L' +
60383                     (d.left + d.width) + ',' + (d.top) + 'Z';
60384
60385             });
60386     };
60387
60388
60389     curtain.remove = function() {
60390         surface.remove();
60391         tooltip.remove();
60392         select(window).on('resize.curtain', null);
60393     };
60394
60395
60396     // ClientRects are immutable, so copy them to an object,
60397     // in case we need to trim the height/width.
60398     function copyBox(src) {
60399         return {
60400             top: src.top,
60401             right: src.right,
60402             bottom: src.bottom,
60403             left: src.left,
60404             width: src.width,
60405             height: src.height
60406         };
60407     }
60408
60409
60410     return curtain;
60411 }
60412
60413 function uiIntroWelcome(context, reveal) {
60414     var dispatch$$1 = dispatch('done'),
60415         listener = clickListener();
60416
60417     var chapter = {
60418         title: 'intro.welcome.title'
60419     };
60420
60421
60422     function welcome() {
60423         context.map().centerZoom([-85.63591, 41.94285], 19);
60424         reveal('.intro-nav-wrap .chapter-welcome',
60425             t('intro.welcome.welcome'),
60426             { buttonText: t('intro.ok'), buttonCallback: practice }
60427         );
60428     }
60429
60430     function practice() {
60431         reveal('.intro-nav-wrap .chapter-welcome',
60432             t('intro.welcome.practice'),
60433             { buttonText: t('intro.ok'), buttonCallback: words }
60434         );
60435     }
60436
60437     function words() {
60438         reveal('.intro-nav-wrap .chapter-welcome',
60439             t('intro.welcome.words'),
60440             { buttonText: t('intro.ok'), buttonCallback: mouse$$1 }
60441         );
60442     }
60443
60444
60445     function mouse$$1() {
60446         reveal('.intro-nav-wrap .chapter-welcome',
60447             t('intro.welcome.mouse'),
60448             { buttonText: t('intro.ok'), buttonCallback: leftClick }
60449         );
60450     }
60451
60452
60453     function leftClick() {
60454         var counter = 0,
60455             times = 5;
60456
60457         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
60458             t('intro.welcome.leftclick', { num: times }),
60459             { tooltipClass: 'intro-mouse' }
60460         );
60461
60462         tooltip.selectAll('.tooltip-inner')
60463             .insert('svg', 'span')
60464             .attr('class', 'tooltip-illustration')
60465             .append('use')
60466             .attr('xlink:href', '#walkthrough-mouse');
60467
60468         tooltip
60469             .append('div')
60470             .attr('class', 'counter');
60471
60472         tooltip.call(listener);
60473
60474         listener.on('click', function(which) {
60475             if (which === 'left') {
60476                 select('.curtain-tooltip.intro-mouse .counter')
60477                     .text(String(++counter));
60478
60479                 if (counter === times) {
60480                     window.setTimeout(function() { continueTo(rightClick); }, 1000);
60481                 }
60482             }
60483         });
60484
60485         function continueTo(nextStep) {
60486             listener.on('click', null);
60487             tooltip.call(listener.off);
60488             tooltip.select('.counter').remove();
60489             nextStep();
60490         }
60491     }
60492
60493
60494     function rightClick() {
60495         var counter = 0,
60496             times = 5;
60497
60498         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
60499             t('intro.welcome.rightclick', { num: times }),
60500             { tooltipClass: 'intro-mouse' }
60501         );
60502
60503         tooltip.selectAll('.tooltip-inner')
60504             .insert('svg', 'span')
60505             .attr('class', 'tooltip-illustration')
60506             .append('use')
60507             .attr('xlink:href', '#walkthrough-mouse');
60508
60509         tooltip
60510             .append('div')
60511             .attr('class', 'counter');
60512
60513         tooltip.call(listener);
60514
60515         listener.on('click', function(which) {
60516             if (which === 'right') {
60517                 select('.curtain-tooltip.intro-mouse .counter')
60518                     .text(String(++counter));
60519
60520                 if (counter === times) {
60521                     window.setTimeout(function() { continueTo(chapters); }, 1000);
60522                 }
60523             }
60524         });
60525
60526         function continueTo(nextStep) {
60527             listener.on('click', null);
60528             tooltip.call(listener.off);
60529             tooltip.select('.counter').remove();
60530             nextStep();
60531         }
60532     }
60533
60534
60535     function chapters() {
60536         dispatch$$1.call('done');
60537         reveal('.intro-nav-wrap .chapter-navigation',
60538             t('intro.welcome.chapters', { next: t('intro.navigation.title') })
60539         );
60540     }
60541
60542
60543     chapter.enter = function() {
60544         welcome();
60545     };
60546
60547
60548     chapter.exit = function() {
60549         listener.off();
60550     };
60551
60552
60553     chapter.restart = function() {
60554         chapter.exit();
60555         chapter.enter();
60556     };
60557
60558
60559     return utilRebind(chapter, dispatch$$1, 'on');
60560 }
60561
60562
60563
60564 function clickListener() {
60565     var dispatch$$1 = dispatch('click'),
60566         minTime = 120,
60567         tooltip = select(null),
60568         down = {};
60569
60570     // `down` keeps track of which buttons/keys are down.
60571     // Setting a property in `down` happens immediately.
60572     // Unsetting a property in `down` is delayed because
60573     //   on Windows a contextmenu event happens after keyup/mouseup
60574
60575     function keydown() {
60576         if (event.keyCode === 93)  {   // context menu
60577             event.preventDefault();
60578             event.stopPropagation();
60579             down.menu = event.timeStamp;
60580             tooltip.classed('rightclick', true);
60581         }
60582     }
60583
60584
60585     function keyup() {
60586         if (event.keyCode === 93)  {   // context menu
60587             event.preventDefault();
60588             event.stopPropagation();
60589             var endTime = event.timeStamp,
60590                 startTime = down.menu || endTime,
60591                 delay = (endTime - startTime < minTime) ? minTime : 0;
60592
60593             window.setTimeout(function() {
60594                 tooltip.classed('rightclick', false);
60595                 down.menu = undefined;  // delayed, for Windows
60596             }, delay);
60597
60598             dispatch$$1.call('click', this, 'right');
60599         }
60600     }
60601
60602
60603     function mousedown() {
60604         var button = event.button;
60605         if (button === 0 && !event.ctrlKey) {
60606             tooltip.classed('leftclick', true);
60607         } else if (button === 2) {
60608             tooltip.classed('rightclick', true);
60609         }
60610         down[button] = event.timeStamp;
60611     }
60612
60613
60614     function mouseup() {
60615         var button = event.button,
60616             endTime = event.timeStamp,
60617             startTime = down[button] || endTime,
60618             delay = (endTime - startTime < minTime) ? minTime : 0;
60619
60620         if (button === 0 && !event.ctrlKey) {
60621             window.setTimeout(function() {
60622                 tooltip.classed('leftclick', false);
60623                 down[button] = undefined;  // delayed, for Windows
60624             }, delay);
60625
60626             dispatch$$1.call('click', this, 'left');
60627
60628         } else if (button === 2) {
60629             window.setTimeout(function() {
60630                 tooltip.classed('rightclick', false);
60631                 down[button] = undefined;  // delayed, for Windows
60632             }, delay);
60633
60634             dispatch$$1.call('click', this, 'right');
60635
60636         } else {
60637             window.setTimeout(function() {
60638                 down[button] = undefined;  // delayed, for Windows
60639             }, delay);
60640         }
60641     }
60642
60643
60644     function contextmenu() {
60645         event.preventDefault();
60646         event.stopPropagation();
60647         if (!down[2] && !down.menu) {
60648             tooltip.classed('rightclick', true);
60649             window.setTimeout(function() {
60650                 tooltip.classed('rightclick', false);
60651             }, minTime);
60652             dispatch$$1.call('click', this, 'right');
60653         }
60654     }
60655
60656
60657     var behavior = function(selection$$1) {
60658         tooltip = selection$$1;
60659         down = {};
60660
60661         select(window)
60662             .on('keydown.intro', keydown)
60663             .on('keyup.intro', keyup)
60664             .on('mousedown.intro', mousedown)
60665             .on('mouseup.intro', mouseup)
60666             .on('contextmenu.intro', contextmenu);
60667     };
60668
60669
60670     behavior.off = function() {
60671         select(window)
60672             .on('keydown.intro', null)
60673             .on('keyup.intro', null)
60674             .on('mousedown.intro', null)
60675             .on('mouseup.intro', null)
60676             .on('contextmenu.intro', null);
60677
60678         tooltip
60679             .classed('leftclick', false)
60680             .classed('rightclick', false);
60681     };
60682
60683     return utilRebind(behavior, dispatch$$1, 'on');
60684 }
60685
60686 function uiIntroNavigation(context, reveal) {
60687     var dispatch$$1 = dispatch('done'),
60688         timeouts = [],
60689         hallId = 'n2061',
60690         townHall = [-85.63591, 41.94285],
60691         springStreetId = 'w397',
60692         springStreetEndId = 'n1834',
60693         springStreet = [-85.63582, 41.94255],
60694         onewayField = context.presets().field('oneway'),
60695         maxspeedField = context.presets().field('maxspeed');
60696
60697
60698     var chapter = {
60699         title: 'intro.navigation.title'
60700     };
60701
60702
60703     function timeout(f, t$$1) {
60704         timeouts.push(window.setTimeout(f, t$$1));
60705     }
60706
60707
60708     function eventCancel() {
60709         event.stopPropagation();
60710         event.preventDefault();
60711     }
60712
60713
60714     function isTownHallSelected() {
60715         var ids = context.selectedIDs();
60716         return ids.length === 1 && ids[0] === hallId;
60717     }
60718
60719
60720     function dragMap() {
60721         context.enter(modeBrowse(context));
60722         context.history().reset('initial');
60723
60724         var msec = transitionTime(townHall, context.map().center());
60725         if (msec) { reveal(null, null, { duration: 0 }); }
60726         context.map().zoom(19).centerEase(townHall, msec);
60727
60728         timeout(function() {
60729             var centerStart = context.map().center();
60730
60731             reveal('#surface', t('intro.navigation.drag'));
60732             context.map().on('drawn.intro', function() {
60733                 reveal('#surface', t('intro.navigation.drag'), { duration: 0 });
60734             });
60735
60736             context.map().on('move.intro', function() {
60737                 var centerNow = context.map().center();
60738                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
60739                     context.map().on('move.intro', null);
60740                     timeout(function() { continueTo(zoomMap); }, 3000);
60741                 }
60742             });
60743
60744         }, msec + 100);
60745
60746         function continueTo(nextStep) {
60747             context.map().on('move.intro drawn.intro', null);
60748             nextStep();
60749         }
60750     }
60751
60752
60753     function zoomMap() {
60754         var zoomStart = context.map().zoom();
60755
60756         reveal('#surface',
60757             t('intro.navigation.zoom', {
60758                 plus: icon('#icon-plus', 'pre-text'),
60759                 minus: icon('#icon-minus', 'pre-text')
60760             })
60761         );
60762
60763         context.map().on('drawn.intro', function() {
60764             reveal('#surface',
60765                 t('intro.navigation.zoom', {
60766                     plus: icon('#icon-plus', 'pre-text'),
60767                     minus: icon('#icon-minus', 'pre-text')
60768                 }), { duration: 0 }
60769             );
60770         });
60771
60772         context.map().on('move.intro', function() {
60773             if (context.map().zoom() !== zoomStart) {
60774                 context.map().on('move.intro', null);
60775                 timeout(function() { continueTo(features); }, 3000);
60776             }
60777         });
60778
60779         function continueTo(nextStep) {
60780             context.map().on('move.intro drawn.intro', null);
60781             nextStep();
60782         }
60783     }
60784
60785
60786     function features() {
60787         var onClick = function() { continueTo(pointsLinesAreas); };
60788
60789         reveal('#surface', t('intro.navigation.features'),
60790             { buttonText: t('intro.ok'), buttonCallback: onClick }
60791         );
60792
60793         context.map().on('drawn.intro', function() {
60794             reveal('#surface', t('intro.navigation.features'),
60795                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
60796             );
60797         });
60798
60799         function continueTo(nextStep) {
60800             context.map().on('drawn.intro', null);
60801             nextStep();
60802         }
60803     }
60804
60805     function pointsLinesAreas() {
60806         var onClick = function() { continueTo(nodesWays); };
60807
60808         reveal('#surface', t('intro.navigation.points_lines_areas'),
60809             { buttonText: t('intro.ok'), buttonCallback: onClick }
60810         );
60811
60812         context.map().on('drawn.intro', function() {
60813             reveal('#surface', t('intro.navigation.points_lines_areas'),
60814                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
60815             );
60816         });
60817
60818         function continueTo(nextStep) {
60819             context.map().on('drawn.intro', null);
60820             nextStep();
60821         }
60822     }
60823
60824     function nodesWays() {
60825         var onClick = function() { continueTo(clickTownHall); };
60826
60827         reveal('#surface', t('intro.navigation.nodes_ways'),
60828             { buttonText: t('intro.ok'), buttonCallback: onClick }
60829         );
60830
60831         context.map().on('drawn.intro', function() {
60832             reveal('#surface', t('intro.navigation.nodes_ways'),
60833                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
60834             );
60835         });
60836
60837         function continueTo(nextStep) {
60838             context.map().on('drawn.intro', null);
60839             nextStep();
60840         }
60841     }
60842
60843     function clickTownHall() {
60844         context.enter(modeBrowse(context));
60845         context.history().reset('initial');
60846
60847         reveal(null, null, { duration: 0 });
60848         context.map().zoomEase(19, 500);
60849
60850         timeout(function() {
60851             var entity = context.hasEntity(hallId);
60852             if (!entity) return;
60853             context.map().centerEase(entity.loc, 500);
60854
60855             timeout(function() {
60856                 var entity = context.hasEntity(hallId);
60857                 if (!entity) return;
60858                 var box = pointBox(entity.loc, context);
60859                 reveal(box, t('intro.navigation.click_townhall'));
60860
60861                 context.map().on('move.intro drawn.intro', function() {
60862                     var entity = context.hasEntity(hallId);
60863                     if (!entity) return;
60864                     var box = pointBox(entity.loc, context);
60865                     reveal(box, t('intro.navigation.click_townhall'), { duration: 0 });
60866                 });
60867
60868                 context.on('enter.intro', function() {
60869                     if (isTownHallSelected()) continueTo(selectedTownHall);
60870                 });
60871
60872             }, 550);  // after centerEase
60873
60874         }, 550); // after zoomEase
60875
60876         context.history().on('change.intro', function() {
60877             if (!context.hasEntity(hallId)) {
60878                 continueTo(clickTownHall);
60879             }
60880         });
60881
60882         function continueTo(nextStep) {
60883             context.on('enter.intro', null);
60884             context.map().on('move.intro drawn.intro', null);
60885             context.history().on('change.intro', null);
60886             nextStep();
60887         }
60888     }
60889
60890
60891     function selectedTownHall() {
60892         if (!isTownHallSelected()) return clickTownHall();
60893
60894         var entity = context.hasEntity(hallId);
60895         if (!entity) return clickTownHall();
60896
60897         var box = pointBox(entity.loc, context);
60898         var onClick = function() { continueTo(editorTownHall); };
60899
60900         reveal(box, t('intro.navigation.selected_townhall'),
60901             { buttonText: t('intro.ok'), buttonCallback: onClick }
60902         );
60903
60904         context.map().on('move.intro drawn.intro', function() {
60905             var entity = context.hasEntity(hallId);
60906             if (!entity) return;
60907             var box = pointBox(entity.loc, context);
60908             reveal(box, t('intro.navigation.selected_townhall'),
60909                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
60910             );
60911         });
60912
60913         context.history().on('change.intro', function() {
60914             if (!context.hasEntity(hallId)) {
60915                 continueTo(clickTownHall);
60916             }
60917         });
60918
60919         function continueTo(nextStep) {
60920             context.map().on('move.intro drawn.intro', null);
60921             context.history().on('change.intro', null);
60922             nextStep();
60923         }
60924     }
60925
60926
60927     function editorTownHall() {
60928         if (!isTownHallSelected()) return clickTownHall();
60929
60930         // disallow scrolling
60931         select('.inspector-wrap').on('wheel.intro', eventCancel);
60932
60933         var onClick = function() { continueTo(presetTownHall); };
60934
60935         reveal('.entity-editor-pane',
60936             t('intro.navigation.editor_townhall'),
60937             { buttonText: t('intro.ok'), buttonCallback: onClick }
60938         );
60939
60940         context.on('exit.intro', function() {
60941             continueTo(clickTownHall);
60942         });
60943
60944         context.history().on('change.intro', function() {
60945             if (!context.hasEntity(hallId)) {
60946                 continueTo(clickTownHall);
60947             }
60948         });
60949
60950         function continueTo(nextStep) {
60951             context.on('exit.intro', null);
60952             context.history().on('change.intro', null);
60953             select('.inspector-wrap').on('wheel.intro', null);
60954             nextStep();
60955         }
60956     }
60957
60958
60959     function presetTownHall() {
60960         if (!isTownHallSelected()) return clickTownHall();
60961
60962         // reset pane, in case user happened to change it..
60963         select('.inspector-wrap .panewrap').style('right', '0%');
60964         // disallow scrolling
60965         select('.inspector-wrap').on('wheel.intro', eventCancel);
60966
60967         // preset match, in case the user happened to change it.
60968         var entity = context.entity(context.selectedIDs()[0]);
60969         var preset = context.presets().match(entity, context.graph());
60970
60971         var onClick = function() { continueTo(fieldsTownHall); };
60972
60973         context.on('exit.intro', function() {
60974             continueTo(clickTownHall);
60975         });
60976
60977         context.history().on('change.intro', function() {
60978             if (!context.hasEntity(hallId)) {
60979                 continueTo(clickTownHall);
60980             }
60981         });
60982
60983         reveal('.inspector-body .preset-list-item.inspector-inner',
60984             t('intro.navigation.preset_townhall', { preset: preset.name() }),
60985             { buttonText: t('intro.ok'), buttonCallback: onClick }
60986         );
60987
60988         function continueTo(nextStep) {
60989             context.on('exit.intro', null);
60990             context.history().on('change.intro', null);
60991             select('.inspector-wrap').on('wheel.intro', null);
60992             nextStep();
60993         }
60994     }
60995
60996
60997     function fieldsTownHall() {
60998         if (!isTownHallSelected()) return clickTownHall();
60999
61000         // reset pane, in case user happened to change it..
61001         select('.inspector-wrap .panewrap').style('right', '0%');
61002         // disallow scrolling
61003         select('.inspector-wrap').on('wheel.intro', eventCancel);
61004
61005         var onClick = function() { continueTo(closeTownHall); };
61006
61007         reveal('.inspector-body .inspector-preset',
61008             t('intro.navigation.fields_townhall'),
61009             { buttonText: t('intro.ok'), buttonCallback: onClick }
61010         );
61011
61012         context.on('exit.intro', function() {
61013             continueTo(clickTownHall);
61014         });
61015
61016         context.history().on('change.intro', function() {
61017             if (!context.hasEntity(hallId)) {
61018                 continueTo(clickTownHall);
61019             }
61020         });
61021
61022         function continueTo(nextStep) {
61023             context.on('exit.intro', null);
61024             context.history().on('change.intro', null);
61025             select('.inspector-wrap').on('wheel.intro', null);
61026             nextStep();
61027         }
61028     }
61029
61030
61031     function closeTownHall() {
61032         if (!isTownHallSelected()) return clickTownHall();
61033
61034         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61035         var href = select(selector$$1).attr('href') || '#icon-close';
61036
61037         reveal('.entity-editor-pane',
61038             t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') })
61039         );
61040
61041         context.on('exit.intro', function() {
61042             continueTo(searchStreet);
61043         });
61044
61045         context.history().on('change.intro', function() {
61046             // update the close icon in the tooltip if the user edits something.
61047             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61048             var href = select(selector$$1).attr('href') || '#icon-close';
61049
61050             reveal('.entity-editor-pane',
61051                 t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') }),
61052                 { duration: 0 }
61053             );
61054         });
61055
61056         function continueTo(nextStep) {
61057             context.on('exit.intro', null);
61058             context.history().on('change.intro', null);
61059             nextStep();
61060         }
61061     }
61062
61063
61064     function searchStreet() {
61065         context.enter(modeBrowse(context));
61066         context.history().reset('initial');  // ensure spring street exists
61067
61068         var msec = transitionTime(springStreet, context.map().center());
61069         if (msec) { reveal(null, null, { duration: 0 }); }
61070         context.map().zoom(19).centerEase(springStreet, msec);  // ..and user can see it
61071
61072         timeout(function() {
61073             reveal('.search-header input',
61074                 t('intro.navigation.search_street', { name: t('intro.graph.name.spring-street') })
61075             );
61076
61077             select('.search-header input')
61078                 .on('keyup.intro', checkSearchResult);
61079         }, msec + 100);
61080     }
61081
61082
61083     function checkSearchResult() {
61084         var first = select('.feature-list-item:nth-child(0n+2)'),  // skip "No Results" item
61085             firstName = first.select('.entity-name'),
61086             name = t('intro.graph.name.spring-street');
61087
61088         if (!firstName.empty() && firstName.text() === name) {
61089             reveal(first.node(),
61090                 t('intro.navigation.choose_street', { name: name }),
61091                 { duration: 300 }
61092             );
61093
61094             context.on('exit.intro', function() {
61095                 continueTo(selectedStreet);
61096             });
61097
61098             select('.search-header input')
61099                 .on('keydown.intro', eventCancel, true)
61100                 .on('keyup.intro', null);
61101         }
61102
61103         function continueTo(nextStep) {
61104             context.on('exit.intro', null);
61105             select('.search-header input')
61106                 .on('keydown.intro', null)
61107                 .on('keyup.intro', null);
61108             nextStep();
61109         }
61110     }
61111
61112
61113     function selectedStreet() {
61114         if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
61115             return searchStreet();
61116         }
61117
61118         var onClick = function() { continueTo(editorStreet); };
61119         var entity = context.entity(springStreetEndId);
61120         var box = pointBox(entity.loc, context);
61121         box.height = 500;
61122
61123         reveal(box,
61124             t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
61125             { duration: 600, buttonText: t('intro.ok'), buttonCallback: onClick }
61126         );
61127
61128         timeout(function() {
61129             context.map().on('move.intro drawn.intro', function() {
61130                 var entity = context.hasEntity(springStreetEndId);
61131                 if (!entity) return;
61132                 var box = pointBox(entity.loc, context);
61133                 box.height = 500;
61134                 reveal(box,
61135                     t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
61136                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
61137                 );
61138             });
61139         }, 600);  // after reveal.
61140
61141         context.on('enter.intro', function(mode) {
61142             if (!context.hasEntity(springStreetId)) {
61143                 return continueTo(searchStreet);
61144             }
61145             var ids = context.selectedIDs();
61146             if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
61147                 // keep Spring Street selected..
61148                 context.enter(modeSelect(context, [springStreetId]));
61149             }
61150         });
61151
61152         context.history().on('change.intro', function() {
61153             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
61154                 timeout(function() {
61155                     continueTo(searchStreet);
61156                 }, 300);  // after any transition (e.g. if user deleted intersection)
61157             }
61158         });
61159
61160         function continueTo(nextStep) {
61161             context.map().on('move.intro drawn.intro', null);
61162             context.on('enter.intro', null);
61163             context.history().on('change.intro', null);
61164             nextStep();
61165         }
61166     }
61167
61168
61169     function editorStreet() {
61170         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61171         var href = select(selector$$1).attr('href') || '#icon-close';
61172
61173         reveal('.entity-editor-pane',
61174             t('intro.navigation.editor_street', {
61175                 button: icon(href, 'pre-text'),
61176                 field1: onewayField.label(),
61177                 field2: maxspeedField.label()
61178             })
61179         );
61180
61181         context.on('exit.intro', function() {
61182             continueTo(play);
61183         });
61184
61185         context.history().on('change.intro', function() {
61186             // update the close icon in the tooltip if the user edits something.
61187             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61188             var href = select(selector$$1).attr('href') || '#icon-close';
61189
61190             reveal('.entity-editor-pane',
61191                 t('intro.navigation.editor_street', {
61192                     button: icon(href, 'pre-text'),
61193                     field1: onewayField.label().toLowerCase(),
61194                     field2: maxspeedField.label().toLowerCase()
61195                 }), { duration: 0 }
61196             );
61197         });
61198
61199         function continueTo(nextStep) {
61200             context.on('exit.intro', null);
61201             context.history().on('change.intro', null);
61202             nextStep();
61203         }
61204     }
61205
61206
61207     function play() {
61208         dispatch$$1.call('done');
61209         reveal('#id-container',
61210             t('intro.navigation.play', { next: t('intro.points.title') }), {
61211                 tooltipBox: '.intro-nav-wrap .chapter-point',
61212                 buttonText: t('intro.ok'),
61213                 buttonCallback: function() { reveal('#id-container'); }
61214             }
61215         );
61216     }
61217
61218
61219     chapter.enter = function() {
61220         dragMap();
61221     };
61222
61223
61224     chapter.exit = function() {
61225         timeouts.forEach(window.clearTimeout);
61226         context.on('enter.intro exit.intro', null);
61227         context.map().on('move.intro drawn.intro', null);
61228         context.history().on('change.intro', null);
61229         select('.inspector-wrap').on('wheel.intro', null);
61230         select('.search-header input').on('keydown.intro keyup.intro', null);
61231     };
61232
61233
61234     chapter.restart = function() {
61235         chapter.exit();
61236         chapter.enter();
61237     };
61238
61239
61240     return utilRebind(chapter, dispatch$$1, 'on');
61241 }
61242
61243 function uiIntroPoint(context, reveal) {
61244     var dispatch$$1 = dispatch('done'),
61245         timeouts = [],
61246         intersection = [-85.63279, 41.94394],
61247         building = [-85.632422, 41.944045],
61248         cafePreset = context.presets().item('amenity/cafe'),
61249         pointId = null;
61250
61251
61252     var chapter = {
61253         title: 'intro.points.title'
61254     };
61255
61256
61257     function timeout(f, t$$1) {
61258         timeouts.push(window.setTimeout(f, t$$1));
61259     }
61260
61261
61262     function revealEditMenu(loc, text$$1, options) {
61263         var rect = context.surfaceRect();
61264         var point = context.curtainProjection(loc);
61265         var pad = 40;
61266         var width = 250 + (2 * pad);
61267         var height = 250;
61268         var startX = rect.left + point[0];
61269         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
61270         var box = {
61271             left: left,
61272             top: point[1] + rect.top - 60,
61273             width: width,
61274             height: height
61275         };
61276         reveal(box, text$$1, options);
61277     }
61278
61279
61280     function eventCancel() {
61281         event.stopPropagation();
61282         event.preventDefault();
61283     }
61284
61285
61286     function addPoint() {
61287         context.enter(modeBrowse(context));
61288         context.history().reset('initial');
61289
61290         var msec = transitionTime(intersection, context.map().center());
61291         if (msec) { reveal(null, null, { duration: 0 }); }
61292         context.map().zoom(19).centerEase(intersection, msec);
61293
61294         timeout(function() {
61295             var tooltip = reveal('button.add-point',
61296                 t('intro.points.add_point', { button: icon('#icon-point', 'pre-text') }));
61297
61298             pointId = null;
61299
61300             tooltip.selectAll('.tooltip-inner')
61301                 .insert('svg', 'span')
61302                 .attr('class', 'tooltip-illustration')
61303                 .append('use')
61304                 .attr('xlink:href', '#poi-images');
61305
61306             context.on('enter.intro', function(mode) {
61307                 if (mode.id !== 'add-point') return;
61308                 continueTo(placePoint);
61309             });
61310         }, msec + 100);
61311
61312         function continueTo(nextStep) {
61313             context.on('enter.intro', null);
61314             nextStep();
61315         }
61316     }
61317
61318
61319     function placePoint() {
61320         if (context.mode().id !== 'add-point') {
61321             return chapter.restart();
61322         }
61323
61324         var pointBox$$1 = pad$1(building, 150, context);
61325         reveal(pointBox$$1, t('intro.points.place_point'));
61326
61327         context.map().on('move.intro drawn.intro', function() {
61328             pointBox$$1 = pad$1(building, 150, context);
61329             reveal(pointBox$$1, t('intro.points.place_point'), { duration: 0 });
61330         });
61331
61332         context.on('enter.intro', function(mode) {
61333             if (mode.id !== 'select') return chapter.restart();
61334             pointId = context.mode().selectedIDs()[0];
61335             continueTo(searchPreset);
61336         });
61337
61338         function continueTo(nextStep) {
61339             context.map().on('move.intro drawn.intro', null);
61340             context.on('enter.intro', null);
61341             nextStep();
61342         }
61343     }
61344
61345
61346     function searchPreset() {
61347         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61348             return addPoint();
61349         }
61350
61351         // disallow scrolling
61352         select('.inspector-wrap').on('wheel.intro', eventCancel);
61353
61354         select('.preset-search-input')
61355             .on('keydown.intro', null)
61356             .on('keyup.intro', checkPresetSearch);
61357
61358         reveal('.preset-search-input',
61359             t('intro.points.search_cafe', { preset: cafePreset.name() })
61360         );
61361
61362         context.on('enter.intro', function(mode) {
61363             if (!pointId || !context.hasEntity(pointId)) {
61364                 return continueTo(addPoint);
61365             }
61366
61367             var ids = context.selectedIDs();
61368             if (mode.id !== 'select' || !ids.length || ids[0] !== pointId) {
61369                 // keep the user's point selected..
61370                 context.enter(modeSelect(context, [pointId]));
61371
61372                 // disallow scrolling
61373                 select('.inspector-wrap').on('wheel.intro', eventCancel);
61374
61375                 select('.preset-search-input')
61376                     .on('keydown.intro', null)
61377                     .on('keyup.intro', checkPresetSearch);
61378
61379                 reveal('.preset-search-input',
61380                     t('intro.points.search_cafe', { preset: cafePreset.name() })
61381                 );
61382
61383                 context.history().on('change.intro', null);
61384             }
61385         });
61386
61387
61388         function checkPresetSearch() {
61389             var first = select('.preset-list-item:first-child');
61390
61391             if (first.classed('preset-amenity-cafe')) {
61392                 select('.preset-search-input')
61393                     .on('keydown.intro', eventCancel, true)
61394                     .on('keyup.intro', null);
61395
61396                 reveal(first.select('.preset-list-button').node(),
61397                     t('intro.points.choose_cafe', { preset: cafePreset.name() }),
61398                     { duration: 300 }
61399                 );
61400
61401                 context.history().on('change.intro', function() {
61402                     continueTo(aboutFeatureEditor);
61403                 });
61404             }
61405         }
61406
61407         function continueTo(nextStep) {
61408             context.on('enter.intro', null);
61409             context.history().on('change.intro', null);
61410             select('.inspector-wrap').on('wheel.intro', null);
61411             select('.preset-search-input').on('keydown.intro keyup.intro', null);
61412             nextStep();
61413         }
61414     }
61415
61416
61417     function aboutFeatureEditor() {
61418         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61419             return addPoint();
61420         }
61421
61422         timeout(function() {
61423             reveal('.entity-editor-pane', t('intro.points.feature_editor'), {
61424                 tooltipClass: 'intro-points-describe',
61425                 buttonText: t('intro.ok'),
61426                 buttonCallback: function() { continueTo(addName); }
61427             });
61428         }, 400);
61429
61430         context.on('exit.intro', function() {
61431             // if user leaves select mode here, just continue with the tutorial.
61432             continueTo(reselectPoint);
61433         });
61434
61435         function continueTo(nextStep) {
61436             context.on('exit.intro', null);
61437             nextStep();
61438         }
61439     }
61440
61441
61442     function addName() {
61443         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61444             return addPoint();
61445         }
61446
61447         // reset pane, in case user happened to change it..
61448         select('.inspector-wrap .panewrap').style('right', '0%');
61449
61450         timeout(function() {
61451             // It's possible for the user to add a name in a previous step..
61452             // If so, don't tell them to add the name in this step.
61453             // Give them an OK button instead.
61454             var entity = context.entity(pointId);
61455             if (entity.tags.name) {
61456                 var tooltip = reveal('.entity-editor-pane', t('intro.points.add_name'), {
61457                     tooltipClass: 'intro-points-describe',
61458                     buttonText: t('intro.ok'),
61459                     buttonCallback: function() { continueTo(addCloseEditor); }
61460                 });
61461                 tooltip.select('.instruction').style('display', 'none');
61462
61463             } else {
61464                 reveal('.entity-editor-pane', t('intro.points.add_name'),
61465                     { tooltipClass: 'intro-points-describe' }
61466                 );
61467             }
61468         }, 400);
61469
61470         context.history().on('change.intro', function() {
61471             continueTo(addCloseEditor);
61472         });
61473
61474         context.on('exit.intro', function() {
61475             // if user leaves select mode here, just continue with the tutorial.
61476             continueTo(reselectPoint);
61477         });
61478
61479         function continueTo(nextStep) {
61480             context.on('exit.intro', null);
61481             context.history().on('change.intro', null);
61482             nextStep();
61483         }
61484     }
61485
61486
61487     function addCloseEditor() {
61488         // reset pane, in case user happened to change it..
61489         select('.inspector-wrap .panewrap').style('right', '0%');
61490
61491         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61492         var href = select(selector$$1).attr('href') || '#icon-close';
61493
61494         context.on('exit.intro', function() {
61495             continueTo(reselectPoint);
61496         });
61497
61498         reveal('.entity-editor-pane',
61499             t('intro.points.add_close', { button: icon(href, 'pre-text') })
61500         );
61501
61502         function continueTo(nextStep) {
61503             context.on('exit.intro', null);
61504             nextStep();
61505         }
61506     }
61507
61508
61509     function reselectPoint() {
61510         if (!pointId) return chapter.restart();
61511         var entity = context.hasEntity(pointId);
61512         if (!entity) return chapter.restart();
61513
61514         // make sure it's still a cafe, in case user somehow changed it..
61515         var oldPreset = context.presets().match(entity, context.graph());
61516         context.replace(actionChangePreset(pointId, oldPreset, cafePreset));
61517
61518         context.enter(modeBrowse(context));
61519
61520         var msec = transitionTime(entity.loc, context.map().center());
61521         if (msec) { reveal(null, null, { duration: 0 }); }
61522         context.map().centerEase(entity.loc, msec);
61523
61524         timeout(function() {
61525             var box = pointBox(entity.loc, context);
61526             reveal(box, t('intro.points.reselect'), { duration: 600 });
61527
61528             timeout(function() {
61529                 context.map().on('move.intro drawn.intro', function() {
61530                     var entity = context.hasEntity(pointId);
61531                     if (!entity) return chapter.restart();
61532                     var box = pointBox(entity.loc, context);
61533                     reveal(box, t('intro.points.reselect'), { duration: 0 });
61534                 });
61535             }, 600); // after reveal..
61536
61537             context.on('enter.intro', function(mode) {
61538                 if (mode.id !== 'select') return;
61539                 continueTo(updatePoint);
61540             });
61541
61542         }, msec + 100);
61543
61544         function continueTo(nextStep) {
61545             context.map().on('move.intro drawn.intro', null);
61546             context.on('enter.intro', null);
61547             nextStep();
61548         }
61549     }
61550
61551
61552     function updatePoint() {
61553         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61554             return continueTo(reselectPoint);
61555         }
61556
61557         // reset pane, in case user happened to untag the point..
61558         select('.inspector-wrap .panewrap').style('right', '0%');
61559
61560         context.on('exit.intro', function() {
61561             continueTo(reselectPoint);
61562         });
61563
61564         context.history().on('change.intro', function() {
61565             continueTo(updateCloseEditor);
61566         });
61567
61568         timeout(function() {
61569             reveal('.entity-editor-pane', t('intro.points.update'),
61570                 { tooltipClass: 'intro-points-describe' }
61571             );
61572         }, 400);
61573
61574         function continueTo(nextStep) {
61575             context.on('exit.intro', null);
61576             context.history().on('change.intro', null);
61577             nextStep();
61578         }
61579     }
61580
61581
61582     function updateCloseEditor() {
61583         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61584             return continueTo(reselectPoint);
61585         }
61586
61587         // reset pane, in case user happened to change it..
61588         select('.inspector-wrap .panewrap').style('right', '0%');
61589
61590         context.on('exit.intro', function() {
61591             continueTo(rightClickPoint);
61592         });
61593
61594         timeout(function() {
61595             reveal('.entity-editor-pane',
61596                 t('intro.points.update_close', { button: icon('#icon-apply', 'pre-text') })
61597             );
61598         }, 500);
61599
61600         function continueTo(nextStep) {
61601             context.on('exit.intro', null);
61602             nextStep();
61603         }
61604     }
61605
61606
61607     function rightClickPoint() {
61608         if (!pointId) return chapter.restart();
61609         var entity = context.hasEntity(pointId);
61610         if (!entity) return chapter.restart();
61611
61612         context.enter(modeBrowse(context));
61613
61614         var box = pointBox(entity.loc, context);
61615         reveal(box, t('intro.points.rightclick'), { duration: 600 });
61616
61617         timeout(function() {
61618             context.map().on('move.intro drawn.intro', function() {
61619                 var entity = context.hasEntity(pointId);
61620                 if (!entity) return chapter.restart();
61621                 var box = pointBox(entity.loc, context);
61622                 reveal(box, t('intro.points.rightclick'), { duration: 0 });
61623             });
61624         }, 600); // after reveal
61625
61626         context.on('enter.intro', function(mode) {
61627             if (mode.id !== 'select') return;
61628             var ids = context.selectedIDs();
61629             if (ids.length !== 1 || ids[0] !== pointId) return;
61630
61631             timeout(function() {
61632                 var node = selectMenuItem('delete').node();
61633                 if (!node) return;
61634                 continueTo(enterDelete);
61635             }, 300);  // after menu visible
61636         });
61637
61638         function continueTo(nextStep) {
61639             context.on('enter.intro', null);
61640             context.map().on('move.intro drawn.intro', null);
61641             nextStep();
61642         }
61643     }
61644
61645
61646     function enterDelete() {
61647         if (!pointId) return chapter.restart();
61648         var entity = context.hasEntity(pointId);
61649         if (!entity) return chapter.restart();
61650
61651         var node = selectMenuItem('delete').node();
61652         if (!node) { return continueTo(rightClickPoint); }
61653
61654         revealEditMenu(entity.loc,
61655             t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') })
61656         );
61657
61658         timeout(function() {
61659             context.map().on('move.intro drawn.intro', function() {
61660                 revealEditMenu(entity.loc,
61661                     t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') }),
61662                     { duration: 0}
61663                 );
61664             });
61665         }, 300); // after menu visible
61666
61667         context.on('exit.intro', function() {
61668             if (!pointId) return chapter.restart();
61669             var entity = context.hasEntity(pointId);
61670             if (entity) return continueTo(rightClickPoint);  // point still exists
61671         });
61672
61673         context.history().on('change.intro', function(changed) {
61674             if (changed.deleted().length) {
61675                 continueTo(undo);
61676             }
61677         });
61678
61679         function continueTo(nextStep) {
61680             context.map().on('move.intro drawn.intro', null);
61681             context.history().on('change.intro', null);
61682             context.on('exit.intro', null);
61683             nextStep();
61684         }
61685     }
61686
61687
61688     function undo() {
61689         context.history().on('change.intro', function() {
61690             continueTo(play);
61691         });
61692
61693         var iconName = '#icon-' + (textDirection === 'rtl' ? 'redo' : 'undo');
61694         reveal('#bar button.undo-button',
61695             t('intro.points.undo', { button: icon(iconName, 'pre-text') })
61696         );
61697
61698         function continueTo(nextStep) {
61699             context.history().on('change.intro', null);
61700             nextStep();
61701         }
61702     }
61703
61704
61705     function play() {
61706         dispatch$$1.call('done');
61707         reveal('#id-container',
61708             t('intro.points.play', { next: t('intro.areas.title') }), {
61709                 tooltipBox: '.intro-nav-wrap .chapter-area',
61710                 buttonText: t('intro.ok'),
61711                 buttonCallback: function() { reveal('#id-container'); }
61712             }
61713         );
61714     }
61715
61716
61717     chapter.enter = function() {
61718         addPoint();
61719     };
61720
61721
61722     chapter.exit = function() {
61723         timeouts.forEach(window.clearTimeout);
61724         context.on('enter.intro exit.intro', null);
61725         context.map().on('move.intro drawn.intro', null);
61726         context.history().on('change.intro', null);
61727         select('.inspector-wrap').on('wheel.intro', eventCancel);
61728         select('.preset-search-input').on('keydown.intro keyup.intro', null);
61729     };
61730
61731
61732     chapter.restart = function() {
61733         chapter.exit();
61734         chapter.enter();
61735     };
61736
61737
61738     return utilRebind(chapter, dispatch$$1, 'on');
61739 }
61740
61741 function uiIntroArea(context, reveal) {
61742     var dispatch$$1 = dispatch('done'),
61743         playground = [-85.63552, 41.94159],
61744         playgroundPreset = context.presets().item('leisure/playground'),
61745         descriptionField = context.presets().field('description'),
61746         timeouts = [],
61747         areaId;
61748
61749
61750     var chapter = {
61751         title: 'intro.areas.title'
61752     };
61753
61754
61755     function timeout(f, t$$1) {
61756         timeouts.push(window.setTimeout(f, t$$1));
61757     }
61758
61759
61760     function eventCancel() {
61761         event.stopPropagation();
61762         event.preventDefault();
61763     }
61764
61765
61766     function revealPlayground(center, text$$1, options) {
61767         var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
61768         var box = pad$1(center, padding, context);
61769         reveal(box, text$$1, options);
61770     }
61771
61772
61773     function addArea() {
61774         context.enter(modeBrowse(context));
61775         context.history().reset('initial');
61776         areaId = null;
61777
61778         var msec = transitionTime(playground, context.map().center());
61779         if (msec) { reveal(null, null, { duration: 0 }); }
61780         context.map().zoom(19).centerEase(playground, msec);
61781
61782         timeout(function() {
61783             var tooltip = reveal('button.add-area',
61784                 t('intro.areas.add_playground', { button: icon('#icon-area', 'pre-text') }));
61785
61786             tooltip.selectAll('.tooltip-inner')
61787                 .insert('svg', 'span')
61788                 .attr('class', 'tooltip-illustration')
61789                 .append('use')
61790                 .attr('xlink:href', '#landuse-images');
61791
61792             context.on('enter.intro', function(mode) {
61793                 if (mode.id !== 'add-area') return;
61794                 continueTo(startPlayground);
61795             });
61796         }, msec + 100);
61797
61798         function continueTo(nextStep) {
61799             context.on('enter.intro', null);
61800             nextStep();
61801         }
61802     }
61803
61804
61805     function startPlayground() {
61806         if (context.mode().id !== 'add-area') {
61807             return chapter.restart();
61808         }
61809
61810         areaId = null;
61811         context.map().zoomEase(19.5, 500);
61812
61813         timeout(function() {
61814             revealPlayground(playground,
61815                 t('intro.areas.start_playground'), { duration: 250 }
61816             );
61817
61818             timeout(function() {
61819                 context.map().on('move.intro drawn.intro', function() {
61820                     revealPlayground(playground,
61821                         t('intro.areas.start_playground'), { duration: 0 }
61822                     );
61823                 });
61824                 context.on('enter.intro', function(mode) {
61825                     if (mode.id !== 'draw-area') return chapter.restart();
61826                     continueTo(continuePlayground);
61827                 });
61828             }, 250);  // after reveal
61829
61830         }, 550);  // after easing
61831
61832         function continueTo(nextStep) {
61833             context.map().on('move.intro drawn.intro', null);
61834             context.on('enter.intro', null);
61835             nextStep();
61836         }
61837     }
61838
61839
61840     function continuePlayground() {
61841         if (context.mode().id !== 'draw-area') {
61842             return chapter.restart();
61843         }
61844
61845         areaId = null;
61846         revealPlayground(playground,
61847             t('intro.areas.continue_playground', { alt: uiCmd.display('⌥') }),
61848             { duration: 250 }
61849         );
61850
61851         timeout(function() {
61852             context.map().on('move.intro drawn.intro', function() {
61853                 revealPlayground(playground,
61854                     t('intro.areas.continue_playground', { alt: uiCmd.display('⌥') }),
61855                     { duration: 0 }
61856                 );
61857             });
61858         }, 250);  // after reveal
61859
61860         context.on('enter.intro', function(mode) {
61861             if (mode.id === 'draw-area') {
61862                 var entity = context.hasEntity(context.selectedIDs()[0]);
61863                 if (entity && entity.nodes.length >= 6) {
61864                     return continueTo(finishPlayground);
61865                 } else {
61866                     return;
61867                 }
61868             } else if (mode.id === 'select') {
61869                 areaId = context.selectedIDs()[0];
61870                 return continueTo(searchPresets);
61871             } else {
61872                 return chapter.restart();
61873             }
61874         });
61875
61876         function continueTo(nextStep) {
61877             context.map().on('move.intro drawn.intro', null);
61878             context.on('enter.intro', null);
61879             nextStep();
61880         }
61881     }
61882
61883
61884     function finishPlayground() {
61885         if (context.mode().id !== 'draw-area') {
61886             return chapter.restart();
61887         }
61888
61889         areaId = null;
61890         revealPlayground(playground,
61891             t('intro.areas.finish_playground'), { duration: 250 }
61892         );
61893
61894         timeout(function() {
61895             context.map().on('move.intro drawn.intro', function() {
61896                 revealPlayground(playground,
61897                     t('intro.areas.finish_playground'), { duration: 0 }
61898                 );
61899             });
61900         }, 250);  // after reveal
61901
61902         context.on('enter.intro', function(mode) {
61903             if (mode.id === 'draw-area') {
61904                 return;
61905             } else if (mode.id === 'select') {
61906                 areaId = context.selectedIDs()[0];
61907                 return continueTo(searchPresets);
61908             } else {
61909                 return chapter.restart();
61910             }
61911         });
61912
61913         function continueTo(nextStep) {
61914             context.map().on('move.intro drawn.intro', null);
61915             context.on('enter.intro', null);
61916             nextStep();
61917         }
61918     }
61919
61920
61921     function searchPresets() {
61922         if (!areaId || !context.hasEntity(areaId)) {
61923             return addArea();
61924         }
61925         var ids = context.selectedIDs();
61926         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
61927             context.enter(modeSelect(context, [areaId]));
61928         }
61929
61930         // disallow scrolling
61931         select('.inspector-wrap').on('wheel.intro', eventCancel);
61932
61933         timeout(function() {
61934             // reset pane, in case user somehow happened to change it..
61935             select('.inspector-wrap .panewrap').style('right', '-100%');
61936
61937             select('.preset-search-input')
61938                 .on('keydown.intro', null)
61939                 .on('keyup.intro', checkPresetSearch);
61940
61941             reveal('.preset-search-input',
61942                 t('intro.areas.search_playground', { preset: playgroundPreset.name() })
61943             );
61944         }, 400);  // after preset list pane visible..
61945
61946         context.on('enter.intro', function(mode) {
61947             if (!areaId || !context.hasEntity(areaId)) {
61948                 return continueTo(addArea);
61949             }
61950
61951             var ids = context.selectedIDs();
61952             if (mode.id !== 'select' || !ids.length || ids[0] !== areaId) {
61953                 // keep the user's area selected..
61954                 context.enter(modeSelect(context, [areaId]));
61955
61956                 // reset pane, in case user somehow happened to change it..
61957                 select('.inspector-wrap .panewrap').style('right', '-100%');
61958                 // disallow scrolling
61959                 select('.inspector-wrap').on('wheel.intro', eventCancel);
61960
61961                 select('.preset-search-input')
61962                     .on('keydown.intro', null)
61963                     .on('keyup.intro', checkPresetSearch);
61964
61965                 reveal('.preset-search-input',
61966                     t('intro.areas.search_playground', { preset: playgroundPreset.name() })
61967                 );
61968
61969                 context.history().on('change.intro', null);
61970             }
61971         });
61972
61973         function checkPresetSearch() {
61974             var first = select('.preset-list-item:first-child');
61975
61976             if (first.classed('preset-leisure-playground')) {
61977                 reveal(first.select('.preset-list-button').node(),
61978                     t('intro.areas.choose_playground', { preset: playgroundPreset.name() }),
61979                     { duration: 300 }
61980                 );
61981
61982                 select('.preset-search-input')
61983                     .on('keydown.intro', eventCancel, true)
61984                     .on('keyup.intro', null);
61985
61986                 context.history().on('change.intro', function() {
61987                     continueTo(clickAddField);
61988                 });
61989             }
61990         }
61991
61992         function continueTo(nextStep) {
61993             select('.inspector-wrap').on('wheel.intro', null);
61994             context.on('enter.intro', null);
61995             context.history().on('change.intro', null);
61996             select('.preset-search-input').on('keydown.intro keyup.intro', null);
61997             nextStep();
61998         }
61999     }
62000
62001
62002     function clickAddField() {
62003         if (!areaId || !context.hasEntity(areaId)) {
62004             return addArea();
62005         }
62006         var ids = context.selectedIDs();
62007         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62008             return searchPresets();
62009         }
62010
62011         if (!select('.form-field-description').empty()) {
62012             return continueTo(describePlayground);
62013         }
62014
62015         // disallow scrolling
62016         select('.inspector-wrap').on('wheel.intro', eventCancel);
62017
62018         timeout(function() {
62019             // reset pane, in case user somehow happened to change it..
62020             select('.inspector-wrap .panewrap').style('right', '0%');
62021
62022             // It's possible for the user to add a description in a previous step..
62023             // If they did this already, just continue to next step.
62024             var entity = context.entity(areaId);
62025             if (entity.tags.description) {
62026                 return continueTo(play);
62027             }
62028
62029             reveal('.more-fields .combobox-input',
62030                 t('intro.areas.add_field'),
62031                 { duration: 300 }
62032             );
62033
62034             select('.more-fields .combobox-input')
62035                 .on('click.intro', function() {
62036                     continueTo(chooseDescriptionField);
62037                 });
62038         }, 400);  // after editor pane visible
62039
62040         context.on('exit.intro', function() {
62041             return continueTo(searchPresets);
62042         });
62043
62044         function continueTo(nextStep) {
62045             select('.inspector-wrap').on('wheel.intro', null);
62046             select('.more-fields .combobox-input').on('click.intro', null);
62047             context.on('exit.intro', null);
62048             nextStep();
62049         }
62050     }
62051
62052
62053     function chooseDescriptionField() {
62054         if (!areaId || !context.hasEntity(areaId)) {
62055             return addArea();
62056         }
62057         var ids = context.selectedIDs();
62058         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62059             return searchPresets();
62060         }
62061
62062         if (!select('.form-field-description').empty()) {
62063             return continueTo(describePlayground);
62064         }
62065
62066         // Make sure combobox is ready..
62067         if (select('div.combobox').empty()) {
62068             return continueTo(clickAddField);
62069         }
62070         // Watch for the combobox to go away..
62071         var watcher;
62072         watcher = window.setInterval(function() {
62073             if (select('div.combobox').empty()) {
62074                 window.clearInterval(watcher);
62075                 timeout(function() {
62076                     if (select('.form-field-description').empty()) {
62077                         continueTo(retryChooseDescription);
62078                     } else {
62079                         continueTo(describePlayground);
62080                     }
62081                 }, 300);  // after description field added.
62082             }
62083         }, 300);
62084
62085         reveal('div.combobox',
62086             t('intro.areas.choose_field', { field: descriptionField.label() }),
62087             { duration: 300 }
62088         );
62089
62090         context.on('exit.intro', function() {
62091             return continueTo(searchPresets);
62092         });
62093
62094         function continueTo(nextStep) {
62095             if (watcher) window.clearInterval(watcher);
62096             context.on('exit.intro', null);
62097             nextStep();
62098         }
62099     }
62100
62101
62102     function describePlayground() {
62103         if (!areaId || !context.hasEntity(areaId)) {
62104             return addArea();
62105         }
62106         var ids = context.selectedIDs();
62107         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62108             return searchPresets();
62109         }
62110
62111         // reset pane, in case user happened to change it..
62112         select('.inspector-wrap .panewrap').style('right', '0%');
62113
62114         if (select('.form-field-description').empty()) {
62115             return continueTo(retryChooseDescription);
62116         }
62117
62118         context.on('exit.intro', function() {
62119             continueTo(play);
62120         });
62121
62122         reveal('.entity-editor-pane',
62123             t('intro.areas.describe_playground', { button: icon('#icon-apply', 'pre-text') }),
62124             { duration: 300 }
62125         );
62126
62127         function continueTo(nextStep) {
62128             context.on('exit.intro', null);
62129             nextStep();
62130         }
62131     }
62132
62133
62134     function retryChooseDescription() {
62135         if (!areaId || !context.hasEntity(areaId)) {
62136             return addArea();
62137         }
62138         var ids = context.selectedIDs();
62139         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62140             return searchPresets();
62141         }
62142
62143         // reset pane, in case user happened to change it..
62144         select('.inspector-wrap .panewrap').style('right', '0%');
62145
62146         reveal('.entity-editor-pane',
62147             t('intro.areas.retry_add_field', { field: descriptionField.label() }), {
62148             buttonText: t('intro.ok'),
62149             buttonCallback: function() { continueTo(clickAddField); }
62150         });
62151
62152         context.on('exit.intro', function() {
62153             return continueTo(searchPresets);
62154         });
62155
62156         function continueTo(nextStep) {
62157             context.on('exit.intro', null);
62158             nextStep();
62159         }
62160     }
62161
62162
62163     function play() {
62164         dispatch$$1.call('done');
62165         reveal('#id-container',
62166             t('intro.areas.play', { next: t('intro.lines.title') }), {
62167                 tooltipBox: '.intro-nav-wrap .chapter-line',
62168                 buttonText: t('intro.ok'),
62169                 buttonCallback: function() { reveal('#id-container'); }
62170             }
62171         );
62172     }
62173
62174
62175     chapter.enter = function() {
62176         addArea();
62177     };
62178
62179
62180     chapter.exit = function() {
62181         timeouts.forEach(window.clearTimeout);
62182         context.on('enter.intro exit.intro', null);
62183         context.map().on('move.intro drawn.intro', null);
62184         context.history().on('change.intro', null);
62185         select('.inspector-wrap').on('wheel.intro', null);
62186         select('.preset-search-input').on('keydown.intro keyup.intro', null);
62187         select('.more-fields .combobox-input').on('click.intro', null);
62188     };
62189
62190
62191     chapter.restart = function() {
62192         chapter.exit();
62193         chapter.enter();
62194     };
62195
62196
62197     return utilRebind(chapter, dispatch$$1, 'on');
62198 }
62199
62200 function uiIntroLine(context, reveal) {
62201     var dispatch$$1 = dispatch('done'),
62202         timeouts = [],
62203         tulipRoadId = null,
62204         flowerRoadId = 'w646',
62205         tulipRoadStart = [-85.6297754121684, 41.95805253325314],
62206         tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204],
62207         tulipRoadIntersection = [-85.62974496187628, 41.95742515554585],
62208         roadCategory = context.presets().item('category-road'),
62209         residentialPreset = context.presets().item('highway/residential'),
62210         woodRoadId = 'w525',
62211         woodRoadEndId = 'n2862',
62212         woodRoadAddNode = [-85.62390110349587, 41.95397111462291],
62213         woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487],
62214         woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872],
62215         washingtonStreetId = 'w522',
62216         twelfthAvenueId = 'w1',
62217         eleventhAvenueEndId = 'n3550',
62218         twelfthAvenueEndId = 'n5',
62219         washingtonSegmentId = null,
62220         eleventhAvenueEnd = context.entity(eleventhAvenueEndId).loc,
62221         twelfthAvenueEnd = context.entity(twelfthAvenueEndId).loc,
62222         deleteLinesLoc = [-85.6219395542764, 41.95228033922477],
62223         twelfthAvenue = [-85.62219310052491, 41.952505413152956];
62224
62225
62226     var chapter = {
62227         title: 'intro.lines.title'
62228     };
62229
62230
62231     function timeout(f, t$$1) {
62232         timeouts.push(window.setTimeout(f, t$$1));
62233     }
62234
62235
62236     function eventCancel() {
62237         event.stopPropagation();
62238         event.preventDefault();
62239     }
62240
62241
62242     function revealEditMenu(loc, text$$1, options) {
62243         var rect = context.surfaceRect();
62244         var point = context.curtainProjection(loc);
62245         var pad = 40;
62246         var width = 250 + (2 * pad);
62247         var height = 350;
62248         var startX = rect.left + point[0];
62249         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
62250         var box = {
62251             left: left,
62252             top: point[1] + rect.top - 60,
62253             width: width,
62254             height: height
62255         };
62256         reveal(box, text$$1, options);
62257     }
62258
62259
62260     function addLine() {
62261         context.enter(modeBrowse(context));
62262         context.history().reset('initial');
62263
62264         var msec = transitionTime(tulipRoadStart, context.map().center());
62265         if (msec) { reveal(null, null, { duration: 0 }); }
62266         context.map().zoom(18.5).centerEase(tulipRoadStart, msec);
62267
62268         timeout(function() {
62269             var tooltip = reveal('button.add-line',
62270                 t('intro.lines.add_line', { button: icon('#icon-line', 'pre-text') }));
62271
62272             tooltip.selectAll('.tooltip-inner')
62273                 .insert('svg', 'span')
62274                 .attr('class', 'tooltip-illustration')
62275                 .append('use')
62276                 .attr('xlink:href', '#feature-images');
62277
62278             context.on('enter.intro', function(mode) {
62279                 if (mode.id !== 'add-line') return;
62280                 continueTo(startLine);
62281             });
62282         }, msec + 100);
62283
62284         function continueTo(nextStep) {
62285             context.on('enter.intro', null);
62286             nextStep();
62287         }
62288     }
62289
62290
62291     function startLine() {
62292         if (context.mode().id !== 'add-line') {
62293             return chapter.restart();
62294         }
62295
62296         tulipRoadId = null;
62297
62298         var padding = 70 * Math.pow(2, context.map().zoom() - 18);
62299         var box = pad$1(tulipRoadStart, padding, context);
62300         box.height = box.height + 100;
62301         reveal(box, t('intro.lines.start_line'));
62302
62303         context.map().on('move.intro drawn.intro', function() {
62304             padding = 70 * Math.pow(2, context.map().zoom() - 18);
62305             box = pad$1(tulipRoadStart, padding, context);
62306             box.height = box.height + 100;
62307             reveal(box, t('intro.lines.start_line'), { duration: 0 });
62308         });
62309
62310         context.on('enter.intro', function(mode) {
62311             if (mode.id !== 'draw-line') return chapter.restart();
62312             continueTo(drawLine);
62313         });
62314
62315         function continueTo(nextStep) {
62316             context.map().on('move.intro drawn.intro', null);
62317             context.on('enter.intro', null);
62318             nextStep();
62319         }
62320     }
62321
62322
62323     function drawLine() {
62324         if (context.mode().id !== 'draw-line') {
62325             return chapter.restart();
62326         }
62327
62328         tulipRoadId = context.mode().selectedIDs()[0];
62329         context.map().centerEase(tulipRoadMidpoint, 500);
62330
62331         timeout(function() {
62332             var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
62333             var box = pad$1(tulipRoadMidpoint, padding, context);
62334             box.height = box.height * 2;
62335             reveal(box,
62336                 t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') })
62337             );
62338
62339             context.map().on('move.intro drawn.intro', function() {
62340                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
62341                 box = pad$1(tulipRoadMidpoint, padding, context);
62342                 box.height = box.height * 2;
62343                 reveal(box,
62344                     t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') }),
62345                     { duration: 0 }
62346                 );
62347             });
62348         }, 550);  // after easing..
62349
62350         context.history().on('change.intro', function() {
62351             var entity = tulipRoadId && context.hasEntity(tulipRoadId);
62352             if (!entity) return chapter.restart();
62353
62354             if (isLineConnected()) {
62355                 continueTo(continueLine);
62356             }
62357         });
62358
62359         context.on('enter.intro', function(mode) {
62360             if (mode.id === 'draw-line')
62361                 return;
62362             else if (mode.id === 'select') {
62363                 continueTo(retryIntersect);
62364                 return;
62365             }
62366             else
62367                 return chapter.restart();
62368         });
62369
62370         function continueTo(nextStep) {
62371             context.map().on('move.intro drawn.intro', null);
62372             context.history().on('change.intro', null);
62373             context.on('enter.intro', null);
62374             nextStep();
62375         }
62376     }
62377
62378
62379     function isLineConnected() {
62380         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
62381         if (!entity) return false;
62382
62383         var drawNodes = context.graph().childNodes(entity);
62384         return lodash.some(drawNodes, function(node) {
62385             return lodash.some(context.graph().parentWays(node), function(parent) {
62386                 return parent.id === flowerRoadId;
62387             });
62388         });
62389     }
62390
62391
62392     function retryIntersect() {
62393         select(window).on('mousedown.intro', eventCancel, true);
62394
62395         var box = pad$1(tulipRoadIntersection, 80, context);
62396         reveal(box,
62397             t('intro.lines.retry_intersect', { name: t('intro.graph.name.flower-street') })
62398         );
62399
62400         timeout(chapter.restart, 3000);
62401     }
62402
62403
62404     function continueLine() {
62405         if (context.mode().id !== 'draw-line') return chapter.restart();
62406         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
62407         if (!entity) return chapter.restart();
62408
62409         context.map().centerEase(tulipRoadIntersection, 500);
62410
62411         reveal('#surface', t('intro.lines.continue_line'));
62412
62413         context.on('enter.intro', function(mode) {
62414             if (mode.id === 'draw-line')
62415                 return;
62416             else if (mode.id === 'select')
62417                 return continueTo(chooseCategoryRoad);
62418             else
62419                 return chapter.restart();
62420         });
62421
62422         function continueTo(nextStep) {
62423             context.on('enter.intro', null);
62424             nextStep();
62425         }
62426     }
62427
62428
62429     function chooseCategoryRoad() {
62430         if (context.mode().id !== 'select') {
62431             return chapter.restart();
62432         }
62433
62434         context.on('exit.intro', function() {
62435             return chapter.restart();
62436         });
62437
62438         var button = select('.preset-category-road .preset-list-button');
62439         if (button.empty()) return chapter.restart();
62440
62441         // disallow scrolling
62442         select('.inspector-wrap').on('wheel.intro', eventCancel);
62443
62444         timeout(function() {
62445             // reset pane, in case user somehow happened to change it..
62446             select('.inspector-wrap .panewrap').style('right', '-100%');
62447
62448             reveal(button.node(),
62449                 t('intro.lines.choose_category_road', { category: roadCategory.name() })
62450             );
62451
62452             button.on('click.intro', function() {
62453                 continueTo(choosePresetResidential);
62454             });
62455
62456         }, 400);  // after editor pane visible
62457
62458         function continueTo(nextStep) {
62459             select('.inspector-wrap').on('wheel.intro', null);
62460             select('.preset-list-button').on('click.intro', null);
62461             context.on('exit.intro', null);
62462             nextStep();
62463         }
62464     }
62465
62466
62467     function choosePresetResidential() {
62468         if (context.mode().id !== 'select') {
62469             return chapter.restart();
62470         }
62471
62472         context.on('exit.intro', function() {
62473             return chapter.restart();
62474         });
62475
62476         var subgrid = select('.preset-category-road .subgrid');
62477         if (subgrid.empty()) return chapter.restart();
62478
62479         subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button')
62480             .on('click.intro', function() {
62481                 continueTo(retryPresetResidential);
62482             });
62483
62484         subgrid.selectAll('.preset-highway-residential .preset-list-button')
62485             .on('click.intro', function() {
62486                 continueTo(nameRoad);
62487             });
62488
62489         timeout(function() {
62490             reveal(subgrid.node(),
62491                 t('intro.lines.choose_preset_residential', { preset: residentialPreset.name() }),
62492                 { tooltipBox: '.preset-highway-residential .preset-list-button', duration: 300 }
62493             );
62494         }, 300);
62495
62496         function continueTo(nextStep) {
62497             select('.preset-list-button').on('click.intro', null);
62498             context.on('exit.intro', null);
62499             nextStep();
62500         }
62501     }
62502
62503
62504     // selected wrong road type
62505     function retryPresetResidential() {
62506         if (context.mode().id !== 'select') {
62507             return chapter.restart();
62508         }
62509
62510         context.on('exit.intro', function() {
62511             return chapter.restart();
62512         });
62513
62514         // disallow scrolling
62515         select('.inspector-wrap').on('wheel.intro', eventCancel);
62516
62517         timeout(function() {
62518             var button = select('.entity-editor-pane .preset-list-button');
62519
62520             reveal(button.node(),
62521                 t('intro.lines.retry_preset_residential', { preset: residentialPreset.name() })
62522             );
62523
62524             button.on('click.intro', function() {
62525                 continueTo(chooseCategoryRoad);
62526             });
62527
62528         }, 500);
62529
62530         function continueTo(nextStep) {
62531             select('.inspector-wrap').on('wheel.intro', null);
62532             select('.preset-list-button').on('click.intro', null);
62533             context.on('exit.intro', null);
62534             nextStep();
62535         }
62536     }
62537
62538
62539     function nameRoad() {
62540         context.on('exit.intro', function() {
62541             continueTo(didNameRoad);
62542         });
62543
62544         timeout(function() {
62545             reveal('.entity-editor-pane',
62546                 t('intro.lines.name_road', { button: icon('#icon-apply', 'pre-text') }),
62547                 { tooltipClass: 'intro-lines-name_road' }
62548             );
62549         }, 500);
62550
62551         function continueTo(nextStep) {
62552             context.on('exit.intro', null);
62553             nextStep();
62554         }
62555     }
62556
62557
62558     function didNameRoad() {
62559         context.history().checkpoint('doneAddLine');
62560
62561         timeout(function() {
62562             reveal('#surface', t('intro.lines.did_name_road'), {
62563                 buttonText: t('intro.ok'),
62564                 buttonCallback: function() { continueTo(updateLine); }
62565             });
62566         }, 500);
62567
62568         function continueTo(nextStep) {
62569             nextStep();
62570         }
62571     }
62572
62573
62574     function updateLine() {
62575         context.history().reset('doneAddLine');
62576         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62577             return chapter.restart();
62578         }
62579
62580         var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
62581         if (msec) { reveal(null, null, { duration: 0 }); }
62582         context.map().zoom(19).centerEase(woodRoadDragMidpoint, msec);
62583
62584         timeout(function() {
62585             var padding = 250 * Math.pow(2, context.map().zoom() - 19);
62586             var box = pad$1(woodRoadDragMidpoint, padding, context);
62587             var advance = function() { continueTo(addNode); };
62588
62589             reveal(box, t('intro.lines.update_line'),
62590                 { buttonText: t('intro.ok'), buttonCallback: advance }
62591             );
62592
62593             context.map().on('move.intro drawn.intro', function() {
62594                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
62595                 var box = pad$1(woodRoadDragMidpoint, padding, context);
62596                 reveal(box, t('intro.lines.update_line'),
62597                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
62598                 );
62599             });
62600         }, msec + 100);
62601
62602         function continueTo(nextStep) {
62603             context.map().on('move.intro drawn.intro', null);
62604             nextStep();
62605         }
62606     }
62607
62608
62609     function addNode() {
62610         context.history().reset('doneAddLine');
62611         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62612             return chapter.restart();
62613         }
62614
62615         var padding = 40 * Math.pow(2, context.map().zoom() - 19);
62616         var box = pad$1(woodRoadAddNode, padding, context);
62617         reveal(box, t('intro.lines.add_node'));
62618
62619         context.map().on('move.intro drawn.intro', function() {
62620             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
62621             var box = pad$1(woodRoadAddNode, padding, context);
62622             reveal(box, t('intro.lines.add_node'), { duration: 0 });
62623         });
62624
62625         context.history().on('change.intro', function(changed) {
62626             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62627                 return continueTo(updateLine);
62628             }
62629             if (changed.created().length === 1) {
62630                 timeout(function() { continueTo(startDragEndpoint); }, 500);
62631             }
62632         });
62633
62634         context.on('enter.intro', function(mode) {
62635             if (mode.id !== 'select') {
62636                 continueTo(updateLine);
62637             }
62638         });
62639
62640         function continueTo(nextStep) {
62641             context.map().on('move.intro drawn.intro', null);
62642             context.history().on('change.intro', null);
62643             context.on('enter.intro', null);
62644             nextStep();
62645         }
62646     }
62647
62648
62649     function startDragEndpoint() {
62650         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62651             return continueTo(updateLine);
62652         }
62653         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
62654             context.enter(modeSelect(context, [woodRoadId]));
62655         }
62656
62657         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62658         var box = pad$1(woodRoadDragEndpoint, padding, context);
62659         reveal(box, t('intro.lines.start_drag_endpoint'));
62660
62661         context.map().on('move.intro drawn.intro', function() {
62662             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62663                 return continueTo(updateLine);
62664             }
62665             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62666             var box = pad$1(woodRoadDragEndpoint, padding, context);
62667             reveal(box, t('intro.lines.start_drag_endpoint'), { duration: 0 });
62668
62669             var entity = context.entity(woodRoadEndId);
62670             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
62671                 continueTo(finishDragEndpoint);
62672             }
62673         });
62674
62675         context.on('enter.intro', function(mode) {
62676             if (mode.id !== 'select') {
62677                 // keep Wood Road selected so endpoint stays draggable..
62678                 context.enter(modeSelect(context, [woodRoadId]));
62679             }
62680         });
62681
62682         function continueTo(nextStep) {
62683             context.map().on('move.intro drawn.intro', null);
62684             context.on('enter.intro', null);
62685             nextStep();
62686         }
62687     }
62688
62689
62690     function finishDragEndpoint() {
62691         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62692             return continueTo(updateLine);
62693         }
62694
62695         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62696         var box = pad$1(woodRoadDragEndpoint, padding, context);
62697         reveal(box, t('intro.lines.finish_drag_endpoint'));
62698
62699         context.map().on('move.intro drawn.intro', function() {
62700             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62701                 return continueTo(updateLine);
62702             }
62703             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62704             var box = pad$1(woodRoadDragEndpoint, padding, context);
62705             reveal(box, t('intro.lines.finish_drag_endpoint'), { duration: 0 });
62706
62707             var entity = context.entity(woodRoadEndId);
62708             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
62709                 continueTo(startDragEndpoint);
62710             }
62711         });
62712
62713         context.on('enter.intro', function() {
62714             continueTo(startDragMidpoint);
62715         });
62716
62717         function continueTo(nextStep) {
62718             context.map().on('move.intro drawn.intro', null);
62719             context.on('enter.intro', null);
62720             nextStep();
62721         }
62722     }
62723
62724
62725     function startDragMidpoint() {
62726         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62727             return continueTo(updateLine);
62728         }
62729         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
62730             context.enter(modeSelect(context, [woodRoadId]));
62731         }
62732
62733         var padding = 80 * Math.pow(2, context.map().zoom() - 19);
62734         var box = pad$1(woodRoadDragMidpoint, padding, context);
62735         reveal(box, t('intro.lines.start_drag_midpoint'));
62736
62737         context.map().on('move.intro drawn.intro', function() {
62738             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62739                 return continueTo(updateLine);
62740             }
62741             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
62742             var box = pad$1(woodRoadDragMidpoint, padding, context);
62743             reveal(box, t('intro.lines.start_drag_midpoint'), { duration: 0 });
62744         });
62745
62746         context.history().on('change.intro', function(changed) {
62747             if (changed.created().length === 1) {
62748                 continueTo(continueDragMidpoint);
62749             }
62750         });
62751
62752         context.on('enter.intro', function(mode) {
62753             if (mode.id !== 'select') {
62754                 // keep Wood Road selected so midpoint triangles are drawn..
62755                 context.enter(modeSelect(context, [woodRoadId]));
62756             }
62757         });
62758
62759         function continueTo(nextStep) {
62760             context.map().on('move.intro drawn.intro', null);
62761             context.history().on('change.intro', null);
62762             context.on('enter.intro', null);
62763             nextStep();
62764         }
62765     }
62766
62767
62768     function continueDragMidpoint() {
62769         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62770             return continueTo(updateLine);
62771         }
62772
62773         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62774         var box = pad$1(woodRoadDragEndpoint, padding, context);
62775         box.height += 400;
62776
62777         var advance = function() {
62778             context.history().checkpoint('doneUpdateLine');
62779             continueTo(deleteLines);
62780         };
62781
62782         reveal(box, t('intro.lines.continue_drag_midpoint'),
62783             { buttonText: t('intro.ok'), buttonCallback: advance }
62784         );
62785
62786         context.map().on('move.intro drawn.intro', function() {
62787             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62788                 return continueTo(updateLine);
62789             }
62790             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62791             var box = pad$1(woodRoadDragEndpoint, padding, context);
62792             box.height += 400;
62793             reveal(box, t('intro.lines.continue_drag_midpoint'),
62794                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
62795             );
62796         });
62797
62798         function continueTo(nextStep) {
62799             context.map().on('move.intro drawn.intro', null);
62800             nextStep();
62801         }
62802     }
62803
62804
62805     function deleteLines() {
62806         context.history().reset('doneUpdateLine');
62807         context.enter(modeBrowse(context));
62808
62809         if (!context.hasEntity(washingtonStreetId) ||
62810             !context.hasEntity(twelfthAvenueId) ||
62811             !context.hasEntity(eleventhAvenueEndId)) {
62812             return chapter.restart();
62813         }
62814
62815         var msec = transitionTime(deleteLinesLoc, context.map().center());
62816         if (msec) { reveal(null, null, { duration: 0 }); }
62817         context.map().zoom(18).centerEase(deleteLinesLoc, msec);
62818
62819         timeout(function() {
62820             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
62821             var box = pad$1(deleteLinesLoc, padding, context);
62822             box.top -= 200;
62823             box.height += 400;
62824             var advance = function() { continueTo(rightClickIntersection); };
62825
62826             reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
62827                 { buttonText: t('intro.ok'), buttonCallback: advance }
62828             );
62829
62830             context.map().on('move.intro drawn.intro', function() {
62831                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
62832                 var box = pad$1(deleteLinesLoc, padding, context);
62833                 box.top -= 200;
62834                 box.height += 400;
62835                 reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
62836                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
62837                 );
62838             });
62839
62840             context.history().on('change.intro', function() {
62841                 timeout(function() {
62842                     continueTo(deleteLines);
62843                 }, 500);  // after any transition (e.g. if user deleted intersection)
62844             });
62845
62846         }, msec + 100);
62847
62848         function continueTo(nextStep) {
62849             context.map().on('move.intro drawn.intro', null);
62850             context.history().on('change.intro', null);
62851             nextStep();
62852         }
62853     }
62854
62855
62856     function rightClickIntersection() {
62857         context.history().reset('doneUpdateLine');
62858         context.enter(modeBrowse(context));
62859
62860         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
62861
62862         timeout(function() {
62863             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
62864             var box = pad$1(eleventhAvenueEnd, padding, context);
62865             reveal(box, t('intro.lines.rightclick_intersection',
62866                 { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') })
62867             );
62868
62869             context.map().on('move.intro drawn.intro', function() {
62870                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
62871                 var box = pad$1(eleventhAvenueEnd, padding, context);
62872                 reveal(box, t('intro.lines.rightclick_intersection',
62873                     { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') }),
62874                     { duration: 0 }
62875                 );
62876             });
62877
62878             context.on('enter.intro', function(mode) {
62879                 if (mode.id !== 'select') return;
62880                 var ids = context.selectedIDs();
62881                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndId) return;
62882
62883                 timeout(function() {
62884                     var node = selectMenuItem('split').node();
62885                     if (!node) return;
62886                     continueTo(splitIntersection);
62887                 }, 300);  // after menu visible
62888             });
62889
62890             context.history().on('change.intro', function() {
62891                 timeout(function() {
62892                     continueTo(deleteLines);
62893                 }, 300);  // after any transition (e.g. if user deleted intersection)
62894             });
62895
62896         }, 600);
62897
62898         function continueTo(nextStep) {
62899             context.map().on('move.intro drawn.intro', null);
62900             context.on('enter.intro', null);
62901             context.history().on('change.intro', null);
62902             nextStep();
62903         }
62904     }
62905
62906
62907     function splitIntersection() {
62908         if (!context.hasEntity(washingtonStreetId) ||
62909             !context.hasEntity(twelfthAvenueId) ||
62910             !context.hasEntity(eleventhAvenueEndId)) {
62911             return continueTo(deleteLines);
62912         }
62913
62914         var node = selectMenuItem('split').node();
62915         if (!node) { return continueTo(rightClickIntersection); }
62916
62917         var wasChanged = false;
62918         var menuCoords = context.map().mouseCoordinates();
62919         washingtonSegmentId = null;
62920
62921         revealEditMenu(menuCoords, t('intro.lines.split_intersection',
62922             { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') })
62923         );
62924
62925         context.map().on('move.intro drawn.intro', function() {
62926             var node = selectMenuItem('split').node();
62927             if (!wasChanged && !node) { return continueTo(rightClickIntersection); }
62928
62929             revealEditMenu(menuCoords, t('intro.lines.split_intersection',
62930                 { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') }),
62931                 { duration: 0 }
62932             );
62933         });
62934
62935         context.history().on('change.intro', function(changed) {
62936             wasChanged = true;
62937             timeout(function() {
62938                 if (context.history().undoAnnotation() === t('operations.split.annotation.line')) {
62939                     washingtonSegmentId = changed.created()[0].id;
62940                     continueTo(didSplit);
62941                 } else {
62942                     washingtonSegmentId = null;
62943                     continueTo(retrySplit);
62944                 }
62945             }, 300);  // after any transition (e.g. if user deleted intersection)
62946         });
62947
62948         function continueTo(nextStep) {
62949             context.map().on('move.intro drawn.intro', null);
62950             context.history().on('change.intro', null);
62951             nextStep();
62952         }
62953     }
62954
62955
62956     function retrySplit() {
62957         context.enter(modeBrowse(context));
62958         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
62959         var advance = function() { continueTo(rightClickIntersection); };
62960
62961         var padding = 60 * Math.pow(2, context.map().zoom() - 18);
62962         var box = pad$1(eleventhAvenueEnd, padding, context);
62963         reveal(box, t('intro.lines.retry_split'),
62964             { buttonText: t('intro.ok'), buttonCallback: advance }
62965         );
62966
62967         context.map().on('move.intro drawn.intro', function() {
62968             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
62969             var box = pad$1(eleventhAvenueEnd, padding, context);
62970             reveal(box, t('intro.lines.retry_split'),
62971                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
62972             );
62973         });
62974
62975         function continueTo(nextStep) {
62976             context.map().on('move.intro drawn.intro', null);
62977             nextStep();
62978         }
62979     }
62980
62981
62982     function didSplit() {
62983         if (!washingtonSegmentId ||
62984             !context.hasEntity(washingtonSegmentId) ||
62985             !context.hasEntity(washingtonStreetId) ||
62986             !context.hasEntity(twelfthAvenueId) ||
62987             !context.hasEntity(eleventhAvenueEndId)) {
62988             return continueTo(rightClickIntersection);
62989         }
62990
62991         var ids = context.selectedIDs();
62992         var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
62993         var street = t('intro.graph.name.washington-street');
62994
62995         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
62996         var box = pad$1(twelfthAvenue, padding, context);
62997         box.width = box.width / 2;
62998         reveal(box, t(string, { street1: street, street2: street }),
62999             { duration: 500 }
63000         );
63001
63002         timeout(function() {
63003             context.map().zoom(18).centerEase(twelfthAvenue, 500);
63004
63005             context.map().on('move.intro drawn.intro', function() {
63006                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63007                 var box = pad$1(twelfthAvenue, padding, context);
63008                 box.width = box.width / 2;
63009                 reveal(box, t(string, { street1: street, street2: street }),
63010                     { duration: 0 }
63011                 );
63012             });
63013         }, 600);  // after initial reveal and curtain cut
63014
63015         context.on('enter.intro', function() {
63016             var ids = context.selectedIDs();
63017             if (ids.length === 1 && ids[0] === washingtonSegmentId) {
63018                 continueTo(multiSelect);
63019             }
63020         });
63021
63022         context.history().on('change.intro', function() {
63023             if (!washingtonSegmentId ||
63024                 !context.hasEntity(washingtonSegmentId) ||
63025                 !context.hasEntity(washingtonStreetId) ||
63026                 !context.hasEntity(twelfthAvenueId) ||
63027                 !context.hasEntity(eleventhAvenueEndId)) {
63028                 return continueTo(rightClickIntersection);
63029             }
63030         });
63031
63032         function continueTo(nextStep) {
63033             context.map().on('move.intro drawn.intro', null);
63034             context.on('enter.intro', null);
63035             context.history().on('change.intro', null);
63036             nextStep();
63037         }
63038     }
63039
63040
63041     function multiSelect() {
63042         if (!washingtonSegmentId ||
63043             !context.hasEntity(washingtonSegmentId) ||
63044             !context.hasEntity(washingtonStreetId) ||
63045             !context.hasEntity(twelfthAvenueId) ||
63046             !context.hasEntity(eleventhAvenueEndId)) {
63047             return continueTo(rightClickIntersection);
63048         }
63049
63050         var ids = context.selectedIDs();
63051         var hasWashington = ids.indexOf(washingtonSegmentId) !== -1;
63052         var hasTwelfth = ids.indexOf(twelfthAvenueId) !== -1;
63053
63054         if (hasWashington && hasTwelfth) {
63055             return continueTo(multiRightClick);
63056         } else if (!hasWashington && !hasTwelfth) {
63057             return continueTo(didSplit);
63058         }
63059
63060         context.map().zoom(18).centerEase(twelfthAvenue, 500);
63061
63062         timeout(function() {
63063             var selected, other, padding, box;
63064             if (hasWashington) {
63065                 selected = t('intro.graph.name.washington-street');
63066                 other = t('intro.graph.name.12th-avenue');
63067                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
63068                 box = pad$1(twelfthAvenueEnd, padding, context);
63069                 box.width *= 3;
63070             } else {
63071                 selected = t('intro.graph.name.12th-avenue');
63072                 other = t('intro.graph.name.washington-street');
63073                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
63074                 box = pad$1(twelfthAvenue, padding, context);
63075                 box.width /= 2;
63076             }
63077
63078             reveal(box,
63079                 t('intro.lines.multi_select', { selected: selected, other1: other, other2: other })
63080             );
63081
63082             context.map().on('move.intro drawn.intro', function() {
63083                 if (hasWashington) {
63084                     selected = t('intro.graph.name.washington-street');
63085                     other = t('intro.graph.name.12th-avenue');
63086                     padding = 60 * Math.pow(2, context.map().zoom() - 18);
63087                     box = pad$1(twelfthAvenueEnd, padding, context);
63088                     box.width *= 3;
63089                 } else {
63090                     selected = t('intro.graph.name.12th-avenue');
63091                     other = t('intro.graph.name.washington-street');
63092                     padding = 200 * Math.pow(2, context.map().zoom() - 18);
63093                     box = pad$1(twelfthAvenue, padding, context);
63094                     box.width /= 2;
63095                 }
63096
63097                 reveal(box,
63098                     t('intro.lines.multi_select', { selected: selected, other1: other, other2: other }),
63099                     { duration: 0 }
63100                 );
63101             });
63102
63103             context.on('enter.intro', function() {
63104                 continueTo(multiSelect);
63105             });
63106
63107             context.history().on('change.intro', function() {
63108                 if (!washingtonSegmentId ||
63109                     !context.hasEntity(washingtonSegmentId) ||
63110                     !context.hasEntity(washingtonStreetId) ||
63111                     !context.hasEntity(twelfthAvenueId) ||
63112                     !context.hasEntity(eleventhAvenueEndId)) {
63113                     return continueTo(rightClickIntersection);
63114                 }
63115             });
63116         }, 600);
63117
63118         function continueTo(nextStep) {
63119             context.map().on('move.intro drawn.intro', null);
63120             context.on('enter.intro', null);
63121             context.history().on('change.intro', null);
63122             nextStep();
63123         }
63124     }
63125
63126
63127     function multiRightClick() {
63128         if (!washingtonSegmentId ||
63129             !context.hasEntity(washingtonSegmentId) ||
63130             !context.hasEntity(washingtonStreetId) ||
63131             !context.hasEntity(twelfthAvenueId) ||
63132             !context.hasEntity(eleventhAvenueEndId)) {
63133             return continueTo(rightClickIntersection);
63134         }
63135
63136         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63137         var box = pad$1(twelfthAvenue, padding, context);
63138         reveal(box, t('intro.lines.multi_rightclick'));
63139
63140         context.map().on('move.intro drawn.intro', function() {
63141             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63142             var box = pad$1(twelfthAvenue, padding, context);
63143             reveal(box, t('intro.lines.multi_rightclick'), { duration: 0 });
63144         });
63145
63146         select(window).on('click.intro contextmenu.intro', function() {
63147             timeout(function() {
63148                 var ids = context.selectedIDs();
63149                 if (ids.length === 2 &&
63150                     ids.indexOf(twelfthAvenueId) !== -1 &&
63151                     ids.indexOf(washingtonSegmentId) !== -1) {
63152                         var node = selectMenuItem('delete').node();
63153                         if (!node) return;
63154                         continueTo(multiDelete);
63155                 } else if (ids.length === 1 &&
63156                     ids.indexOf(washingtonSegmentId) !== -1) {
63157                     return continueTo(multiSelect);
63158                 } else {
63159                     return continueTo(didSplit);
63160                 }
63161             }, 300);  // after edit menu visible
63162         }, true);
63163
63164         context.history().on('change.intro', function() {
63165             if (!washingtonSegmentId ||
63166                 !context.hasEntity(washingtonSegmentId) ||
63167                 !context.hasEntity(washingtonStreetId) ||
63168                 !context.hasEntity(twelfthAvenueId) ||
63169                 !context.hasEntity(eleventhAvenueEndId)) {
63170                 return continueTo(rightClickIntersection);
63171             }
63172         });
63173
63174         function continueTo(nextStep) {
63175             context.map().on('move.intro drawn.intro', null);
63176             select(window).on('click.intro contextmenu.intro', null, true);
63177             context.history().on('change.intro', null);
63178             nextStep();
63179         }
63180     }
63181
63182
63183     function multiDelete() {
63184         if (!washingtonSegmentId ||
63185             !context.hasEntity(washingtonSegmentId) ||
63186             !context.hasEntity(washingtonStreetId) ||
63187             !context.hasEntity(twelfthAvenueId) ||
63188             !context.hasEntity(eleventhAvenueEndId)) {
63189             return continueTo(rightClickIntersection);
63190         }
63191
63192         var node = selectMenuItem('delete').node();
63193         if (!node) return continueTo(multiRightClick);
63194
63195         var menuCoords = context.map().mouseCoordinates();
63196         revealEditMenu(menuCoords,
63197             t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') })
63198         );
63199
63200         context.map().on('move.intro drawn.intro', function() {
63201             revealEditMenu(menuCoords,
63202                 t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') }),
63203                 { duration: 0 }
63204             );
63205         });
63206
63207         context.on('exit.intro', function() {
63208             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
63209                 return continueTo(multiSelect);  // left select mode but roads still exist
63210             }
63211         });
63212
63213         context.history().on('change.intro', function() {
63214             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
63215                 continueTo(retryDelete);         // changed something but roads still exist
63216             } else {
63217                 continueTo(play);
63218             }
63219         });
63220
63221         function continueTo(nextStep) {
63222             context.map().on('move.intro drawn.intro', null);
63223             context.on('exit.intro', null);
63224             context.history().on('change.intro', null);
63225             nextStep();
63226         }
63227     }
63228
63229
63230     function retryDelete() {
63231         context.enter(modeBrowse(context));
63232
63233         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63234         var box = pad$1(twelfthAvenue, padding, context);
63235         reveal(box, t('intro.lines.retry_delete'), {
63236             buttonText: t('intro.ok'),
63237             buttonCallback: function() { continueTo(multiSelect); }
63238         });
63239
63240         function continueTo(nextStep) {
63241             nextStep();
63242         }
63243     }
63244
63245
63246     function play() {
63247         dispatch$$1.call('done');
63248         reveal('#id-container',
63249             t('intro.lines.play', { next: t('intro.buildings.title') }), {
63250                 tooltipBox: '.intro-nav-wrap .chapter-building',
63251                 buttonText: t('intro.ok'),
63252                 buttonCallback: function() { reveal('#id-container'); }
63253             }
63254         );
63255    }
63256
63257
63258     chapter.enter = function() {
63259         addLine();
63260     };
63261
63262
63263     chapter.exit = function() {
63264         timeouts.forEach(window.clearTimeout);
63265         select(window).on('mousedown.intro', null, true);
63266         context.on('enter.intro exit.intro', null);
63267         context.map().on('move.intro drawn.intro', null);
63268         context.history().on('change.intro', null);
63269         select('.inspector-wrap').on('wheel.intro', null);
63270         select('.preset-list-button').on('click.intro', null);
63271     };
63272
63273
63274     chapter.restart = function() {
63275         chapter.exit();
63276         chapter.enter();
63277     };
63278
63279
63280     return utilRebind(chapter, dispatch$$1, 'on');
63281 }
63282
63283 function uiIntroBuilding(context, reveal) {
63284     var dispatch$$1 = dispatch('done'),
63285         house = [-85.62815, 41.95638],
63286         tank = [-85.62732, 41.95347],
63287         buildingCatetory = context.presets().item('category-building'),
63288         housePreset = context.presets().item('building/house'),
63289         tankPreset = context.presets().item('man_made/storage_tank'),
63290         timeouts = [],
63291         houseId = null,
63292         tankId = null;
63293
63294
63295     var chapter = {
63296         title: 'intro.buildings.title'
63297     };
63298
63299
63300     function timeout(f, t$$1) {
63301         timeouts.push(window.setTimeout(f, t$$1));
63302     }
63303
63304
63305     function eventCancel() {
63306         event.stopPropagation();
63307         event.preventDefault();
63308     }
63309
63310
63311     function revealHouse(center, text$$1, options) {
63312         var padding = 160 * Math.pow(2, context.map().zoom() - 20);
63313         var box = pad$1(center, padding, context);
63314         reveal(box, text$$1, options);
63315     }
63316
63317
63318     function revealTank(center, text$$1, options) {
63319         var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
63320         var box = pad$1(center, padding, context);
63321         reveal(box, text$$1, options);
63322     }
63323
63324
63325     function revealEditMenu(loc, text$$1, options) {
63326         var rect = context.surfaceRect();
63327         var point = context.curtainProjection(loc);
63328         var pad = 40;
63329         var width = 250 + (2 * pad);
63330         var height = 350;
63331         var startX = rect.left + point[0];
63332         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
63333         var box = {
63334             left: left,
63335             top: point[1] + rect.top - 60,
63336             width: width,
63337             height: height
63338         };
63339         reveal(box, text$$1, options);
63340     }
63341
63342
63343     function addHouse() {
63344         context.enter(modeBrowse(context));
63345         context.history().reset('initial');
63346         houseId = null;
63347
63348         var msec = transitionTime(house, context.map().center());
63349         if (msec) { reveal(null, null, { duration: 0 }); }
63350         context.map().zoom(19).centerEase(house, msec);
63351
63352         timeout(function() {
63353             var tooltip = reveal('button.add-area',
63354                 t('intro.buildings.add_building', { button: icon('#icon-area', 'pre-text') }));
63355
63356             tooltip.selectAll('.tooltip-inner')
63357                 .insert('svg', 'span')
63358                 .attr('class', 'tooltip-illustration')
63359                 .append('use')
63360                 .attr('xlink:href', '#building-images');
63361
63362             context.on('enter.intro', function(mode) {
63363                 if (mode.id !== 'add-area') return;
63364                 continueTo(startHouse);
63365             });
63366         }, msec + 100);
63367
63368         function continueTo(nextStep) {
63369             context.on('enter.intro', null);
63370             nextStep();
63371         }
63372     }
63373
63374
63375     function startHouse() {
63376         if (context.mode().id !== 'add-area') {
63377             return continueTo(addHouse);
63378         }
63379
63380         houseId = null;
63381         context.map().zoomEase(20, 500);
63382
63383         timeout(function() {
63384             revealHouse(house, t('intro.buildings.start_building'));
63385
63386             context.map().on('move.intro drawn.intro', function() {
63387                 revealHouse(house, t('intro.buildings.start_building'), { duration: 0 });
63388             });
63389
63390             context.on('enter.intro', function(mode) {
63391                 if (mode.id !== 'draw-area') return chapter.restart();
63392                 continueTo(continueHouse);
63393             });
63394
63395         }, 550);  // after easing
63396
63397         function continueTo(nextStep) {
63398             context.map().on('move.intro drawn.intro', null);
63399             context.on('enter.intro', null);
63400             nextStep();
63401         }
63402     }
63403
63404
63405     function continueHouse() {
63406         if (context.mode().id !== 'draw-area') {
63407             return continueTo(addHouse);
63408         }
63409
63410         houseId = null;
63411
63412         revealHouse(house, t('intro.buildings.continue_building'));
63413
63414         context.map().on('move.intro drawn.intro', function() {
63415             revealHouse(house, t('intro.buildings.continue_building'), { duration: 0 });
63416         });
63417
63418         context.on('enter.intro', function(mode) {
63419             if (mode.id === 'draw-area') {
63420                 return;
63421             } else if (mode.id === 'select') {
63422                 var graph = context.graph(),
63423                     way = context.entity(context.selectedIDs()[0]),
63424                     nodes = graph.childNodes(way),
63425                     points = lodash.uniq(nodes).map(function(n) { return context.projection(n.loc); });
63426
63427                 if (isMostlySquare(points)) {
63428                     houseId = way.id;
63429                     return continueTo(chooseCategoryBuilding);
63430                 } else {
63431                     return continueTo(retryHouse);
63432                 }
63433
63434             } else {
63435                 return chapter.restart();
63436             }
63437         });
63438
63439         function continueTo(nextStep) {
63440             context.map().on('move.intro drawn.intro', null);
63441             context.on('enter.intro', null);
63442             nextStep();
63443         }
63444     }
63445
63446
63447     function retryHouse() {
63448         var onClick = function() { continueTo(addHouse); };
63449
63450         revealHouse(house, t('intro.buildings.retry_building'),
63451             { buttonText: t('intro.ok'), buttonCallback: onClick }
63452         );
63453
63454         context.map().on('move.intro drawn.intro', function() {
63455             revealHouse(house, t('intro.buildings.retry_building'),
63456                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
63457             );
63458         });
63459
63460         function continueTo(nextStep) {
63461             context.map().on('move.intro drawn.intro', null);
63462             nextStep();
63463         }
63464     }
63465
63466
63467     function chooseCategoryBuilding() {
63468         if (!houseId || !context.hasEntity(houseId)) {
63469             return addHouse();
63470         }
63471         var ids = context.selectedIDs();
63472         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
63473             context.enter(modeSelect(context, [houseId]));
63474         }
63475
63476         // disallow scrolling
63477         select('.inspector-wrap').on('wheel.intro', eventCancel);
63478
63479         timeout(function() {
63480             // reset pane, in case user somehow happened to change it..
63481             select('.inspector-wrap .panewrap').style('right', '-100%');
63482
63483             var button = select('.preset-category-building .preset-list-button');
63484
63485             reveal(button.node(),
63486                 t('intro.buildings.choose_category_building', { category: buildingCatetory.name() })
63487             );
63488
63489             button.on('click.intro', function() {
63490                 button.on('click.intro', null);
63491                 continueTo(choosePresetHouse);
63492             });
63493
63494         }, 400);  // after preset list pane visible..
63495
63496
63497         context.on('enter.intro', function(mode) {
63498             if (!houseId || !context.hasEntity(houseId)) {
63499                 return continueTo(addHouse);
63500             }
63501             var ids = context.selectedIDs();
63502             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
63503                 return continueTo(chooseCategoryBuilding);
63504             }
63505         });
63506
63507         function continueTo(nextStep) {
63508             select('.inspector-wrap').on('wheel.intro', null);
63509             select('.preset-list-button').on('click.intro', null);
63510             context.on('enter.intro', null);
63511             nextStep();
63512         }
63513     }
63514
63515
63516     function choosePresetHouse() {
63517         if (!houseId || !context.hasEntity(houseId)) {
63518             return addHouse();
63519         }
63520         var ids = context.selectedIDs();
63521         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
63522             context.enter(modeSelect(context, [houseId]));
63523         }
63524
63525         // disallow scrolling
63526         select('.inspector-wrap').on('wheel.intro', eventCancel);
63527
63528         timeout(function() {
63529             // reset pane, in case user somehow happened to change it..
63530             select('.inspector-wrap .panewrap').style('right', '-100%');
63531
63532             var button = select('.preset-building-house .preset-list-button');
63533
63534             reveal(button.node(),
63535                 t('intro.buildings.choose_preset_house', { preset: housePreset.name() }),
63536                 { duration: 300 }
63537             );
63538
63539             button.on('click.intro', function() {
63540                 button.on('click.intro', null);
63541                 continueTo(closeEditorHouse);
63542             });
63543
63544
63545         }, 400);  // after preset list pane visible..
63546
63547         context.on('enter.intro', function(mode) {
63548             if (!houseId || !context.hasEntity(houseId)) {
63549                 return continueTo(addHouse);
63550             }
63551             var ids = context.selectedIDs();
63552             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
63553                 return continueTo(chooseCategoryBuilding);
63554             }
63555         });
63556
63557         function continueTo(nextStep) {
63558             select('.inspector-wrap').on('wheel.intro', null);
63559             select('.preset-list-button').on('click.intro', null);
63560             context.on('enter.intro', null);
63561             nextStep();
63562         }
63563     }
63564
63565
63566     function closeEditorHouse() {
63567         if (!houseId || !context.hasEntity(houseId)) {
63568             return addHouse();
63569         }
63570         var ids = context.selectedIDs();
63571         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
63572             context.enter(modeSelect(context, [houseId]));
63573         }
63574
63575         context.history().checkpoint('hasHouse');
63576
63577         context.on('exit.intro', function() {
63578             continueTo(rightClickHouse);
63579         });
63580
63581         timeout(function() {
63582             reveal('.entity-editor-pane',
63583                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
63584             );
63585         }, 500);
63586
63587         function continueTo(nextStep) {
63588             context.on('exit.intro', null);
63589             nextStep();
63590         }
63591     }
63592
63593
63594     function rightClickHouse() {
63595         if (!houseId) return chapter.restart();
63596
63597         context.enter(modeBrowse(context));
63598         context.history().reset('hasHouse');
63599         context.map().centerEase(house, 500);
63600
63601         timeout(function() {
63602             if (context.map().zoom() < 20) {
63603                 context.map().zoomEase(20, 500);
63604             }
63605         }, 520);
63606
63607         context.on('enter.intro', function(mode) {
63608             if (mode.id !== 'select') return;
63609             var ids = context.selectedIDs();
63610             if (ids.length !== 1 || ids[0] !== houseId) return;
63611
63612             timeout(function() {
63613                 var node = selectMenuItem('orthogonalize').node();
63614                 if (!node) return;
63615                 continueTo(clickSquare);
63616             }, 300);  // after menu visible
63617         });
63618
63619         context.map().on('move.intro drawn.intro', function() {
63620             revealHouse(house, t('intro.buildings.rightclick_building'), { duration: 0 });
63621         });
63622
63623         context.history().on('change.intro', function() {
63624             continueTo(rightClickHouse);
63625         });
63626
63627         function continueTo(nextStep) {
63628             context.on('enter.intro', null);
63629             context.map().on('move.intro drawn.intro', null);
63630             context.history().on('change.intro', null);
63631             nextStep();
63632         }
63633     }
63634
63635
63636     function clickSquare() {
63637         if (!houseId) return chapter.restart();
63638         var entity = context.hasEntity(houseId);
63639         if (!entity) return continueTo(rightClickHouse);
63640
63641         var node = selectMenuItem('orthogonalize').node();
63642         if (!node) { return continueTo(rightClickHouse); }
63643
63644         var wasChanged = false;
63645         var menuCoords = context.map().mouseCoordinates();
63646
63647         revealEditMenu(menuCoords,
63648             t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') })
63649         );
63650
63651         context.on('enter.intro', function(mode) {
63652             if (mode.id === 'browse') {
63653                 continueTo(rightClickHouse);
63654             } else if (mode.id === 'move' || mode.id === 'rotate') {
63655                 continueTo(retryClickSquare);
63656             }
63657         });
63658
63659         context.map().on('move.intro drawn.intro', function() {
63660             var node = selectMenuItem('orthogonalize').node();
63661             if (!wasChanged && !node) { return continueTo(rightClickHouse); }
63662
63663             revealEditMenu(menuCoords,
63664                 t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') }),
63665                 { duration: 0 }
63666             );
63667         });
63668
63669         context.history().on('change.intro', function() {
63670             wasChanged = true;
63671             context.history().on('change.intro', null);
63672
63673             // Something changed.  Wait for transition to complete and check undo annotation.
63674             timeout(function() {
63675                 if (context.history().undoAnnotation() === t('operations.orthogonalize.annotation.area')) {
63676                     continueTo(doneSquare);
63677                 } else {
63678                     continueTo(retryClickSquare);
63679                 }
63680             }, 500);  // after transitioned actions
63681         });
63682
63683         function continueTo(nextStep) {
63684             context.on('enter.intro', null);
63685             context.map().on('move.intro drawn.intro', null);
63686             context.history().on('change.intro', null);
63687             nextStep();
63688         }
63689     }
63690
63691
63692     function retryClickSquare() {
63693         context.enter(modeBrowse(context));
63694
63695         revealHouse(house, t('intro.buildings.retry_square'), {
63696             buttonText: t('intro.ok'),
63697             buttonCallback: function() { continueTo(rightClickHouse); }
63698         });
63699
63700         function continueTo(nextStep) {
63701             nextStep();
63702         }
63703     }
63704
63705
63706     function doneSquare() {
63707         context.history().checkpoint('doneSquare');
63708
63709         revealHouse(house, t('intro.buildings.done_square'), {
63710             buttonText: t('intro.ok'),
63711             buttonCallback: function() { continueTo(addTank); }
63712         });
63713
63714         function continueTo(nextStep) {
63715             nextStep();
63716         }
63717     }
63718
63719
63720     function addTank() {
63721         context.enter(modeBrowse(context));
63722         context.history().reset('doneSquare');
63723         tankId = null;
63724
63725         var msec = transitionTime(tank, context.map().center());
63726         if (msec) { reveal(null, null, { duration: 0 }); }
63727         context.map().zoom(19.5).centerEase(tank, msec);
63728
63729         timeout(function() {
63730             reveal('button.add-area',
63731                 t('intro.buildings.add_tank', { button: icon('#icon-area', 'pre-text') })
63732             );
63733
63734             context.on('enter.intro', function(mode) {
63735                 if (mode.id !== 'add-area') return;
63736                 continueTo(startTank);
63737             });
63738         }, msec + 100);
63739
63740         function continueTo(nextStep) {
63741             context.on('enter.intro', null);
63742             nextStep();
63743         }
63744     }
63745
63746
63747     function startTank() {
63748         if (context.mode().id !== 'add-area') {
63749             return continueTo(addTank);
63750         }
63751
63752         tankId = null;
63753
63754         timeout(function() {
63755             revealTank(tank, t('intro.buildings.start_tank'));
63756
63757             context.map().on('move.intro drawn.intro', function() {
63758                 revealTank(tank, t('intro.buildings.start_tank'), { duration: 0 });
63759             });
63760
63761             context.on('enter.intro', function(mode) {
63762                 if (mode.id !== 'draw-area') return chapter.restart();
63763                 continueTo(continueTank);
63764             });
63765
63766         }, 550);  // after easing
63767
63768         function continueTo(nextStep) {
63769             context.map().on('move.intro drawn.intro', null);
63770             context.on('enter.intro', null);
63771             nextStep();
63772         }
63773     }
63774
63775
63776     function continueTank() {
63777         if (context.mode().id !== 'draw-area') {
63778             return continueTo(addTank);
63779         }
63780
63781         tankId = null;
63782
63783         revealTank(tank, t('intro.buildings.continue_tank'));
63784
63785         context.map().on('move.intro drawn.intro', function() {
63786             revealTank(tank, t('intro.buildings.continue_tank'), { duration: 0 });
63787         });
63788
63789         context.on('enter.intro', function(mode) {
63790             if (mode.id === 'draw-area') {
63791                 return;
63792             } else if (mode.id === 'select') {
63793                 tankId = context.selectedIDs()[0];
63794                 return continueTo(searchPresetTank);
63795             } else {
63796                 return continueTo(addTank);
63797             }
63798         });
63799
63800         function continueTo(nextStep) {
63801             context.map().on('move.intro drawn.intro', null);
63802             context.on('enter.intro', null);
63803             nextStep();
63804         }
63805     }
63806
63807
63808     function searchPresetTank() {
63809         if (!tankId || !context.hasEntity(tankId)) {
63810             return addTank();
63811         }
63812         var ids = context.selectedIDs();
63813         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
63814             context.enter(modeSelect(context, [tankId]));
63815         }
63816
63817         // disallow scrolling
63818         select('.inspector-wrap').on('wheel.intro', eventCancel);
63819
63820         timeout(function() {
63821             // reset pane, in case user somehow happened to change it..
63822             select('.inspector-wrap .panewrap').style('right', '-100%');
63823
63824             select('.preset-search-input')
63825                 .on('keydown.intro', null)
63826                 .on('keyup.intro', checkPresetSearch);
63827
63828             reveal('.preset-search-input',
63829                 t('intro.buildings.search_tank', { preset: tankPreset.name() })
63830             );
63831         }, 400);  // after preset list pane visible..
63832
63833         context.on('enter.intro', function(mode) {
63834             if (!tankId || !context.hasEntity(tankId)) {
63835                 return continueTo(addTank);
63836             }
63837
63838             var ids = context.selectedIDs();
63839             if (mode.id !== 'select' || !ids.length || ids[0] !== tankId) {
63840                 // keep the user's area selected..
63841                 context.enter(modeSelect(context, [tankId]));
63842
63843                 // reset pane, in case user somehow happened to change it..
63844                 select('.inspector-wrap .panewrap').style('right', '-100%');
63845                 // disallow scrolling
63846                 select('.inspector-wrap').on('wheel.intro', eventCancel);
63847
63848                 select('.preset-search-input')
63849                     .on('keydown.intro', null)
63850                     .on('keyup.intro', checkPresetSearch);
63851
63852                 reveal('.preset-search-input',
63853                     t('intro.buildings.search_tank', { preset: tankPreset.name() })
63854                 );
63855
63856                 context.history().on('change.intro', null);
63857             }
63858         });
63859
63860         function checkPresetSearch() {
63861             var first = select('.preset-list-item:first-child');
63862
63863             if (first.classed('preset-man_made-storage_tank')) {
63864                 reveal(first.select('.preset-list-button').node(),
63865                     t('intro.buildings.choose_tank', { preset: tankPreset.name() }),
63866                     { duration: 300 }
63867                 );
63868
63869                 select('.preset-search-input')
63870                     .on('keydown.intro', eventCancel, true)
63871                     .on('keyup.intro', null);
63872
63873                 context.history().on('change.intro', function() {
63874                     continueTo(closeEditorTank);
63875                 });
63876             }
63877         }
63878
63879         function continueTo(nextStep) {
63880             select('.inspector-wrap').on('wheel.intro', null);
63881             context.on('enter.intro', null);
63882             context.history().on('change.intro', null);
63883             select('.preset-search-input').on('keydown.intro keyup.intro', null);
63884             nextStep();
63885         }
63886     }
63887
63888
63889     function closeEditorTank() {
63890         if (!tankId || !context.hasEntity(tankId)) {
63891             return addTank();
63892         }
63893         var ids = context.selectedIDs();
63894         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
63895             context.enter(modeSelect(context, [tankId]));
63896         }
63897
63898         context.history().checkpoint('hasTank');
63899
63900         context.on('exit.intro', function() {
63901             continueTo(rightClickTank);
63902         });
63903
63904         timeout(function() {
63905             reveal('.entity-editor-pane',
63906                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
63907             );
63908         }, 500);
63909
63910         function continueTo(nextStep) {
63911             context.on('exit.intro', null);
63912             nextStep();
63913         }
63914     }
63915
63916
63917     function rightClickTank() {
63918         if (!tankId) return continueTo(addTank);
63919
63920         context.enter(modeBrowse(context));
63921         context.history().reset('hasTank');
63922         context.map().centerEase(tank, 500);
63923
63924         timeout(function() {
63925             context.on('enter.intro', function(mode) {
63926                 if (mode.id !== 'select') return;
63927                 var ids = context.selectedIDs();
63928                 if (ids.length !== 1 || ids[0] !== tankId) return;
63929
63930                 timeout(function() {
63931                     var node = selectMenuItem('circularize').node();
63932                     if (!node) return;
63933                     continueTo(clickCircle);
63934                 }, 300);  // after menu visible
63935             });
63936
63937             revealTank(tank, t('intro.buildings.rightclick_tank'));
63938
63939             context.map().on('move.intro drawn.intro', function() {
63940                 revealTank(tank, t('intro.buildings.rightclick_tank'), { duration: 0 });
63941             });
63942
63943             context.history().on('change.intro', function() {
63944                 continueTo(rightClickTank);
63945             });
63946
63947         }, 600);
63948
63949         function continueTo(nextStep) {
63950             context.on('enter.intro', null);
63951             context.map().on('move.intro drawn.intro', null);
63952             context.history().on('change.intro', null);
63953             nextStep();
63954         }
63955     }
63956
63957
63958     function clickCircle() {
63959         if (!tankId) return chapter.restart();
63960         var entity = context.hasEntity(tankId);
63961         if (!entity) return continueTo(rightClickTank);
63962
63963         var node = selectMenuItem('circularize').node();
63964         if (!node) { return continueTo(rightClickTank); }
63965
63966         var wasChanged = false;
63967         var menuCoords = context.map().mouseCoordinates();
63968
63969         revealEditMenu(menuCoords,
63970             t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') })
63971         );
63972
63973         context.on('enter.intro', function(mode) {
63974             if (mode.id === 'browse') {
63975                 continueTo(rightClickTank);
63976             } else if (mode.id === 'move' || mode.id === 'rotate') {
63977                 continueTo(retryClickCircle);
63978             }
63979         });
63980
63981         context.map().on('move.intro drawn.intro', function() {
63982             var node = selectMenuItem('circularize').node();
63983             if (!wasChanged && !node) { return continueTo(rightClickTank); }
63984
63985             revealEditMenu(menuCoords,
63986                 t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') }),
63987                 { duration: 0 }
63988             );
63989         });
63990
63991         context.history().on('change.intro', function() {
63992             wasChanged = true;
63993             context.history().on('change.intro', null);
63994
63995             // Something changed.  Wait for transition to complete and check undo annotation.
63996             timeout(function() {
63997                 if (context.history().undoAnnotation() === t('operations.circularize.annotation.area')) {
63998                     continueTo(play);
63999                 } else {
64000                     continueTo(retryClickCircle);
64001                 }
64002             }, 500);  // after transitioned actions
64003         });
64004
64005         function continueTo(nextStep) {
64006             context.on('enter.intro', null);
64007             context.map().on('move.intro drawn.intro', null);
64008             context.history().on('change.intro', null);
64009             nextStep();
64010         }
64011     }
64012
64013
64014     function retryClickCircle() {
64015         context.enter(modeBrowse(context));
64016
64017         revealTank(tank, t('intro.buildings.retry_circle'), {
64018             buttonText: t('intro.ok'),
64019             buttonCallback: function() { continueTo(rightClickTank); }
64020         });
64021
64022         function continueTo(nextStep) {
64023             nextStep();
64024         }
64025     }
64026
64027
64028     function play() {
64029         dispatch$$1.call('done');
64030         reveal('#id-container',
64031             t('intro.buildings.play', { next: t('intro.startediting.title') }), {
64032                 tooltipBox: '.intro-nav-wrap .chapter-startEditing',
64033                 buttonText: t('intro.ok'),
64034                 buttonCallback: function() { reveal('#id-container'); }
64035             }
64036         );
64037     }
64038
64039
64040     chapter.enter = function() {
64041         addHouse();
64042     };
64043
64044
64045     chapter.exit = function() {
64046         timeouts.forEach(window.clearTimeout);
64047         context.on('enter.intro exit.intro', null);
64048         context.map().on('move.intro drawn.intro', null);
64049         context.history().on('change.intro', null);
64050         select('.inspector-wrap').on('wheel.intro', null);
64051         select('.preset-search-input').on('keydown.intro keyup.intro', null);
64052         select('.more-fields .combobox-input').on('click.intro', null);
64053     };
64054
64055
64056     chapter.restart = function() {
64057         chapter.exit();
64058         chapter.enter();
64059     };
64060
64061
64062     return utilRebind(chapter, dispatch$$1, 'on');
64063 }
64064
64065 function uiIntroStartEditing(context, reveal) {
64066     var dispatch$$1 = dispatch('done', 'startEditing'),
64067         modalSelection = select(null);
64068
64069
64070     var chapter = {
64071         title: 'intro.startediting.title'
64072     };
64073
64074     function showHelp() {
64075         reveal('.map-control.help-control',
64076             t('intro.startediting.help', { button: icon('#icon-help', 'pre-text'), key: t('help.key') }), {
64077                 buttonText: t('intro.ok'),
64078                 buttonCallback: function() { shortcuts(); }
64079             }
64080         );
64081     }
64082
64083     function shortcuts() {
64084         reveal('.map-control.help-control',
64085             t('intro.startediting.shortcuts', { key: t('shortcuts.toggle.key') }), {
64086                 buttonText: t('intro.ok'),
64087                 buttonCallback: function() { showSave(); }
64088             }
64089         );
64090     }
64091
64092     function showSave() {
64093         selectAll('.shaded').remove();  // in case user opened keyboard shortcuts
64094         reveal('#bar button.save',
64095             t('intro.startediting.save'), {
64096                 buttonText: t('intro.ok'),
64097                 buttonCallback: function() { showStart(); }
64098             }
64099         );
64100     }
64101
64102     function showStart() {
64103         selectAll('.shaded').remove();  // in case user opened keyboard shortcuts
64104
64105         modalSelection = uiModal(context.container());
64106
64107         modalSelection.select('.modal')
64108             .attr('class', 'modal-splash modal col6');
64109
64110         modalSelection.selectAll('.close').remove();
64111
64112         var startbutton = modalSelection.select('.content')
64113             .attr('class', 'fillL')
64114             .append('button')
64115                 .attr('class', 'modal-section huge-modal-button')
64116                 .on('click', function() {
64117                     modalSelection.remove();
64118                 });
64119
64120             startbutton
64121                 .append('svg')
64122                 .attr('class', 'illustration')
64123                 .append('use')
64124                 .attr('xlink:href', '#logo-walkthrough');
64125
64126             startbutton
64127                 .append('h2')
64128                 .text(t('intro.startediting.start'));
64129
64130         dispatch$$1.call('startEditing');
64131     }
64132
64133
64134     chapter.enter = function() {
64135         showHelp();
64136     };
64137
64138
64139     chapter.exit = function() {
64140         modalSelection.remove();
64141         selectAll('.shaded').remove();  // in case user opened keyboard shortcuts
64142     };
64143
64144
64145     return utilRebind(chapter, dispatch$$1, 'on');
64146 }
64147
64148 var chapterUi = {
64149     welcome: uiIntroWelcome,
64150     navigation: uiIntroNavigation,
64151     point: uiIntroPoint,
64152     area: uiIntroArea,
64153     line: uiIntroLine,
64154     building: uiIntroBuilding,
64155     startEditing: uiIntroStartEditing
64156 };
64157
64158 var chapterFlow = [
64159     'welcome',
64160     'navigation',
64161     'point',
64162     'area',
64163     'line',
64164     'building',
64165     'startEditing'
64166 ];
64167
64168
64169 function uiIntro(context) {
64170     var introGraph = {},
64171         currChapter;
64172
64173
64174     // create entities for intro graph and localize names
64175     for (var id in dataIntroGraph) {
64176         introGraph[id] = osmEntity$$1(localize(dataIntroGraph[id]));
64177     }
64178
64179
64180     function intro(selection$$1) {
64181         context.enter(modeBrowse(context));
64182
64183         // Save current map state
64184         var history = context.history().toJSON(),
64185             hash = window.location.hash,
64186             center = context.map().center(),
64187             zoom$$1 = context.map().zoom(),
64188             background = context.background().baseLayerSource(),
64189             overlays = context.background().overlayLayerSources(),
64190             opacity = selectAll('#map .layer-background').style('opacity'),
64191             loadedTiles = context.connection().loadedTiles(),
64192             baseEntities = context.history().graph().base().entities,
64193             countryCode = services.geocoder.countryCode;
64194
64195         // Block saving
64196         context.inIntro(true);
64197
64198         // Load semi-real data used in intro
64199         context.connection().toggle(false).reset();
64200         context.history().reset();
64201         context.history().merge(values(coreGraph$$1().load(introGraph).entities));
64202         context.history().checkpoint('initial');
64203         context.background().bing();
64204         overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
64205
64206         // Mock geocoder
64207         services.geocoder.countryCode = function(location, callback) {
64208             callback(null, t('intro.graph.countrycode'));
64209         };
64210
64211         selectAll('#map .layer-background').style('opacity', 1);
64212
64213         var curtain = uiCurtain();
64214         selection$$1.call(curtain);
64215
64216         var chapters = chapterFlow.map(function(chapter, i) {
64217             var s = chapterUi[chapter](context, curtain.reveal)
64218                 .on('done', function() {
64219                     context.presets().init();  // clear away "recent" presets
64220
64221                     buttons.filter(function(d) {
64222                         return d.title === s.title;
64223                     }).classed('finished', true);
64224
64225                     if (i < chapterFlow.length - 1) {
64226                         var next = chapterFlow[i + 1];
64227                         select('button.chapter-' + next)
64228                             .classed('next', true);
64229                     }
64230                 });
64231             return s;
64232         });
64233
64234         chapters[chapters.length - 1].on('startEditing', function() {
64235             curtain.remove();
64236             navwrap.remove();
64237             selectAll('#map .layer-background').style('opacity', opacity);
64238             context.connection().toggle(true).reset().loadedTiles(loadedTiles);
64239             context.history().reset().merge(values(baseEntities));
64240             context.background().baseLayerSource(background);
64241             overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
64242             if (history) context.history().fromJSON(history, false);
64243             context.map().centerZoom(center, zoom$$1);
64244             window.location.replace(hash);
64245             services.geocoder.countryCode = countryCode;
64246             context.inIntro(false);
64247         });
64248
64249         var navwrap = selection$$1
64250             .append('div')
64251             .attr('class', 'intro-nav-wrap fillD');
64252
64253         navwrap
64254             .append('svg')
64255             .attr('class', 'intro-nav-wrap-logo')
64256             .append('use')
64257             .attr('xlink:href', '#logo-walkthrough');
64258
64259         var buttonwrap = navwrap
64260             .append('div')
64261             .attr('class', 'joined')
64262             .selectAll('button.chapter');
64263
64264         var buttons = buttonwrap
64265             .data(chapters)
64266             .enter()
64267             .append('button')
64268             .attr('class', function(d, i) { return 'chapter chapter-' + chapterFlow[i]; })
64269             .on('click', enterChapter);
64270
64271         buttons
64272             .append('span')
64273             .text(function(d) { return t(d.title); });
64274
64275         buttons
64276             .append('span')
64277             .attr('class', 'status')
64278             .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'));
64279
64280         enterChapter(chapters[0]);
64281
64282
64283         function enterChapter(newChapter) {
64284             if (currChapter) { currChapter.exit(); }
64285             context.enter(modeBrowse(context));
64286
64287             currChapter = newChapter;
64288             currChapter.enter();
64289
64290             buttons
64291                 .classed('next', false)
64292                 .classed('active', function(d) {
64293                     return d.title === currChapter.title;
64294                 });
64295         }
64296     }
64297
64298
64299     return intro;
64300 }
64301
64302 function uiShortcuts() {
64303     var detected = utilDetect();
64304     var activeTab = 0;
64305     var modalSelection;
64306     var savedSelection;
64307
64308
64309     var keybinding = d3keybinding('shortcuts')
64310         .on(t('shortcuts.toggle.key'), function () {
64311             if (selectAll('.modal-shortcuts').size()) {  // already showing
64312                 if (modalSelection) {
64313                     modalSelection.close();
64314                     modalSelection = null;
64315                 }
64316             } else {
64317                 modalSelection = uiModal(savedSelection);
64318                 shortcutsModal(modalSelection);
64319             }
64320         });
64321
64322     select(document)
64323         .call(keybinding);
64324
64325
64326
64327     function shortcutsModal(modalSelection) {
64328         modalSelection.select('.modal')
64329             .classed('modal-shortcuts', true);
64330
64331         var shortcutsModal = modalSelection.select('.content');
64332
64333         shortcutsModal
64334             .append('div')
64335             .attr('class', 'modal-section')
64336             .append('h3')
64337             .text(t('shortcuts.title'));
64338
64339         shortcutsModal
64340             .call(render);
64341     }
64342
64343
64344     function render(selection$$1) {
64345         var wrapper = selection$$1
64346             .selectAll('.wrapper')
64347             .data([0]);
64348
64349         var wrapperEnter = wrapper
64350             .enter()
64351             .append('div')
64352             .attr('class', 'wrapper modal-section');
64353
64354         var tabsBar = wrapperEnter
64355             .append('div')
64356             .attr('class', 'tabs-bar');
64357
64358         var shortcutsList = wrapperEnter
64359             .append('div')
64360             .attr('class', 'shortcuts-list');
64361
64362         wrapper = wrapper.merge(wrapperEnter);
64363
64364         var tabs = tabsBar
64365             .selectAll('.tab')
64366             .data(dataShortcuts);
64367
64368         var tabsEnter = tabs
64369             .enter()
64370             .append('div')
64371             .attr('class', 'tab')
64372             .on('click', function (d, i) {
64373                 activeTab = i;
64374                 render(selection$$1);
64375             });
64376
64377         tabsEnter
64378             .append('span')
64379             .text(function (d) { return t(d.text); });
64380
64381         tabs = tabs
64382             .merge(tabsEnter);
64383
64384         // Update
64385         wrapper.selectAll('.tab')
64386             .classed('active', function (d, i) {
64387                 return i === activeTab;
64388             });
64389
64390
64391         var shortcuts = shortcutsList
64392             .selectAll('.shortcut-tab')
64393             .data(dataShortcuts);
64394
64395         var shortcutsEnter = shortcuts
64396             .enter()
64397             .append('div')
64398             .attr('class', function(d) { return 'shortcut-tab shortcut-tab-' + d.tab; });
64399
64400         var columnsEnter = shortcutsEnter
64401             .selectAll('.shortcut-column')
64402             .data(function (d) { return d.columns; })
64403             .enter()
64404             .append('table')
64405             .attr('class', 'shortcut-column');
64406
64407         var rowsEnter = columnsEnter
64408             .selectAll('.shortcut-row')
64409             .data(function (d) { return d.rows; })
64410             .enter()
64411             .append('tr')
64412             .attr('class', 'shortcut-row');
64413
64414
64415         var sectionRows = rowsEnter
64416             .filter(function (d) { return !d.shortcuts; });
64417
64418         sectionRows
64419             .append('td');
64420
64421         sectionRows
64422             .append('td')
64423             .attr('class', 'shortcut-section')
64424             .append('h3')
64425             .text(function (d) { return t(d.text); });
64426
64427
64428         var shortcutRows = rowsEnter
64429             .filter(function (d) { return d.shortcuts; });
64430
64431         var shortcutKeys = shortcutRows
64432             .append('td')
64433             .attr('class', 'shortcut-keys');
64434
64435         var modifierKeys = shortcutKeys
64436             .filter(function (d) { return d.modifiers; });
64437
64438         modifierKeys
64439             .selectAll('kbd.modifier')
64440             .data(function (d) {
64441                 if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
64442                     return ['⌘'];
64443                 } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
64444                     return [];
64445                 } else {
64446                     return d.modifiers;
64447                 }
64448             })
64449             .enter()
64450             .each(function () {
64451                 var selection$$1 = select(this);
64452
64453                 selection$$1
64454                     .append('kbd')
64455                     .attr('class', 'modifier')
64456                     .text(function (d) { return uiCmd.display(d); });
64457
64458                 selection$$1
64459                     .append('span')
64460                     .text('+');
64461             });
64462
64463
64464         shortcutKeys
64465             .selectAll('kbd.shortcut')
64466             .data(function (d) {
64467                 var arr = d.shortcuts;
64468                 if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
64469                     arr = ['Y'];
64470                 } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
64471                     arr = ['F11'];
64472                 }
64473
64474                 return arr.map(function(s) {
64475                     return {
64476                         shortcut: s,
64477                         separator: d.separator
64478                     };
64479                 });
64480             })
64481             .enter()
64482             .each(function (d, i, nodes) {
64483                 var selection$$1 = select(this);
64484                 var click = d.shortcut.toLowerCase().match(/(.*).click/);
64485
64486                 if (click && click[1]) {
64487                     selection$$1
64488                         .call(svgIcon('#walkthrough-mouse', 'mouseclick', click[1]));
64489                 } else {
64490                     selection$$1
64491                         .append('kbd')
64492                         .attr('class', 'shortcut')
64493                         .text(function (d) {
64494                             var key = d.shortcut;
64495                             return key.indexOf('.') !== -1 ? uiCmd.display(t(key)) : uiCmd.display(key);
64496                         });
64497                 }
64498
64499                 if (i < nodes.length - 1) {
64500                     selection$$1
64501                         .append('span')
64502                         .text(d.separator || '\u00a0' + t('shortcuts.or') + '\u00a0');
64503                 }
64504             });
64505
64506
64507         shortcutKeys
64508             .filter(function(d) { return d.gesture; })
64509             .each(function () {
64510                 var selection$$1 = select(this);
64511
64512                 selection$$1
64513                     .append('span')
64514                     .text('+');
64515
64516                 selection$$1
64517                     .append('span')
64518                     .attr('class', 'gesture')
64519                     .text(function (d) { return t(d.gesture); });
64520             });
64521
64522
64523         shortcutRows
64524             .append('td')
64525             .attr('class', 'shortcut-desc')
64526             .text(function (d) { return d.text ? t(d.text) : '\u00a0'; });
64527
64528
64529         shortcuts = shortcuts
64530             .merge(shortcutsEnter);
64531
64532         // Update
64533         wrapper.selectAll('.shortcut-tab')
64534             .style('display', function (d, i) {
64535                 return i === activeTab ? 'flex' : 'none';
64536             });
64537     }
64538
64539
64540     return function(selection$$1, show) {
64541         savedSelection = selection$$1;
64542         if (show) {
64543             modalSelection = uiModal(selection$$1);
64544             shortcutsModal(modalSelection);
64545         }
64546     };
64547 }
64548
64549 function uiHelp(context) {
64550     var key = t('help.key');
64551
64552     var docKeys = [
64553         'help.help',
64554         'help.editing_saving',
64555         'help.roads',
64556         'help.gps',
64557         'help.imagery',
64558         'help.addresses',
64559         'help.inspector',
64560         'help.buildings',
64561         'help.relations'];
64562
64563     var docs = docKeys.map(function(key) {
64564         var text$$1 = t(key);
64565         return {
64566             title: text$$1.split('\n')[0].replace('#', '').trim(),
64567             html: marked(text$$1.split('\n').slice(1).join('\n'))
64568         };
64569     });
64570
64571
64572     function help(selection$$1) {
64573
64574         function hide() {
64575             setVisible(false);
64576         }
64577
64578
64579         function toggle() {
64580             if (event) event.preventDefault();
64581             tooltipBehavior.hide(button);
64582             setVisible(!button.classed('active'));
64583         }
64584
64585
64586         function setVisible(show) {
64587             if (show !== shown) {
64588                 button.classed('active', show);
64589                 shown = show;
64590
64591                 if (show) {
64592                     selection$$1.on('mousedown.help-inside', function() {
64593                         return event.stopPropagation();
64594                     });
64595                     pane.style('display', 'block')
64596                         .style('right', '-500px')
64597                         .transition()
64598                         .duration(200)
64599                         .style('right', '0px');
64600                 } else {
64601                     pane.style('right', '0px')
64602                         .transition()
64603                         .duration(200)
64604                         .style('right', '-500px')
64605                         .on('end', function() {
64606                             select(this).style('display', 'none');
64607                         });
64608                     selection$$1.on('mousedown.help-inside', null);
64609                 }
64610             }
64611         }
64612
64613
64614         function clickHelp(d, i) {
64615             var rtl = (textDirection === 'rtl');
64616             pane.property('scrollTop', 0);
64617             doctitle.html(d.title);
64618
64619             body.html(d.html);
64620             body.selectAll('a')
64621                 .attr('target', '_blank');
64622             menuItems.classed('selected', function(m) {
64623                 return m.title === d.title;
64624             });
64625
64626             nav.html('');
64627             if (rtl) {
64628                 nav.call(drawNext).call(drawPrevious);
64629             } else {
64630                 nav.call(drawPrevious).call(drawNext);
64631             }
64632
64633
64634             function drawNext(selection$$1) {
64635                 if (i < docs.length - 1) {
64636                     var nextLink = selection$$1
64637                         .append('a')
64638                         .attr('class', 'next')
64639                         .on('click', function() {
64640                             clickHelp(docs[i + 1], i + 1);
64641                         });
64642
64643                     nextLink
64644                         .append('span')
64645                         .text(docs[i + 1].title)
64646                         .call(svgIcon((rtl ? '#icon-backward' : '#icon-forward'), 'inline'));
64647                 }
64648             }
64649
64650
64651             function drawPrevious(selection$$1) {
64652                 if (i > 0) {
64653                     var prevLink = selection$$1
64654                         .append('a')
64655                         .attr('class', 'previous')
64656                         .on('click', function() {
64657                             clickHelp(docs[i - 1], i - 1);
64658                         });
64659
64660                     prevLink
64661                         .call(svgIcon((rtl ? '#icon-forward' : '#icon-backward'), 'inline'))
64662                         .append('span')
64663                         .text(docs[i - 1].title);
64664                 }
64665             }
64666         }
64667
64668
64669         function clickWalkthrough() {
64670             if (context.inIntro()) return;
64671             context.container().call(uiIntro(context));
64672             setVisible(false);
64673         }
64674
64675
64676         function clickShortcuts() {
64677             context.container().call(uiShortcuts(context), true);
64678         }
64679
64680
64681         var pane = selection$$1.append('div')
64682                 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
64683             tooltipBehavior = tooltip()
64684                 .placement((textDirection === 'rtl') ? 'right' : 'left')
64685                 .html(true)
64686                 .title(uiTooltipHtml(t('help.title'), key)),
64687             button = selection$$1.append('button')
64688                 .attr('tabindex', -1)
64689                 .on('click', toggle)
64690                 .call(svgIcon('#icon-help', 'light'))
64691                 .call(tooltipBehavior),
64692             shown = false;
64693
64694
64695         var toc = pane.append('ul')
64696             .attr('class', 'toc');
64697
64698         var menuItems = toc.selectAll('li')
64699             .data(docs)
64700             .enter()
64701             .append('li')
64702             .append('a')
64703             .html(function(d) { return d.title; })
64704             .on('click', clickHelp);
64705
64706         var shortcuts = toc
64707             .append('li')
64708             .attr('class', 'shortcuts')
64709             .call(tooltip()
64710                 .html(true)
64711                 .title(uiTooltipHtml(t('shortcuts.tooltip'), '?'))
64712                 .placement('top')
64713             )
64714             .append('a')
64715             .on('click', clickShortcuts);
64716
64717         shortcuts
64718             .append('div')
64719             .text(t('shortcuts.title'));
64720
64721         var walkthrough = toc
64722             .append('li')
64723             .attr('class', 'walkthrough')
64724             .append('a')
64725             .on('click', clickWalkthrough);
64726
64727         walkthrough
64728             .append('svg')
64729             .attr('class', 'logo logo-walkthrough')
64730             .append('use')
64731             .attr('xlink:href', '#logo-walkthrough');
64732
64733         walkthrough
64734             .append('div')
64735             .text(t('splash.walkthrough'));
64736
64737
64738         var content = pane.append('div')
64739             .attr('class', 'left-content');
64740
64741         var doctitle = content.append('h2')
64742             .text(t('help.title'));
64743
64744         var body = content.append('div')
64745             .attr('class', 'body');
64746
64747         var nav = content.append('div')
64748             .attr('class', 'nav');
64749
64750         clickHelp(docs[0], 0);
64751
64752         var keybinding = d3keybinding('help')
64753             .on(key, toggle)
64754             .on([t('background.key'), t('map_data.key')], hide);
64755
64756         select(document)
64757             .call(keybinding);
64758
64759         context.surface().on('mousedown.help-outside', hide);
64760         context.container().on('mousedown.help-outside', hide);
64761     }
64762
64763     return help;
64764 }
64765
64766 function uiPanelBackground(context) {
64767     var background = context.background();
64768     var currSource = null;
64769     var currZoom = '';
64770     var currVintage = '';
64771
64772
64773     function redraw(selection$$1) {
64774         if (currSource !== background.baseLayerSource().name()) {
64775             currSource = background.baseLayerSource().name();
64776             currZoom = '';
64777             currVintage = '';
64778         }
64779
64780         selection$$1.html('');
64781
64782         var list = selection$$1
64783             .append('ul')
64784             .attr('class', 'background-info');
64785
64786         list
64787             .append('li')
64788             .text(currSource);
64789
64790         list
64791             .append('li')
64792             .text(t('info_panels.background.zoom') + ': ')
64793             .append('span')
64794             .attr('class', 'zoom')
64795             .text(currZoom);
64796
64797         list
64798             .append('li')
64799             .text(t('info_panels.background.vintage') + ': ')
64800             .append('span')
64801             .attr('class', 'vintage')
64802             .text(currVintage);
64803
64804         if (!currVintage) {
64805             debouncedGetVintage(selection$$1);
64806         }
64807
64808         var toggle = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles';
64809
64810         selection$$1
64811             .append('a')
64812             .text(t('info_panels.background.' + toggle))
64813             .attr('href', '#')
64814             .attr('class', 'button button-toggle-tiles')
64815             .on('click', function() {
64816                 event.preventDefault();
64817                 context.setDebug('tile', !context.getDebug('tile'));
64818                 selection$$1.call(redraw);
64819             });
64820     }
64821
64822
64823     var debouncedGetVintage = lodash.debounce(getVintage, 250);
64824     function getVintage(selection$$1) {
64825         var tile = select('.layer-background img.tile-center');   // tile near viewport center
64826         if (tile.empty()) return;
64827
64828         var d = tile.datum(),
64829             zoom$$1 = (d && d.length >= 3 && d[2]) || Math.floor(context.map().zoom()),
64830             center = context.map().center();
64831
64832         currZoom = String(zoom$$1);
64833         selection$$1.selectAll('.zoom')
64834             .text(currZoom);
64835
64836         if (!d || !d.length >= 3) return;
64837         background.baseLayerSource().getVintage(center, d, function(err, result) {
64838             currVintage = (result && result.range) || t('info_panels.background.unknown');
64839             selection$$1.selectAll('.vintage')
64840                 .text(currVintage);
64841         });
64842     }
64843
64844
64845     var panel = function(selection$$1) {
64846         selection$$1.call(redraw);
64847
64848         context.map()
64849             .on('drawn.info-background', function() {
64850                 selection$$1.call(redraw);
64851             })
64852             .on('move.info-background', function() {
64853                 selection$$1.call(debouncedGetVintage);
64854             });
64855
64856     };
64857
64858     panel.off = function() {
64859         context.map()
64860             .on('drawn.info-background', null)
64861             .on('move.info-background', null);
64862     };
64863
64864     panel.id = 'background';
64865     panel.title = t('info_panels.background.title');
64866     panel.key = t('info_panels.background.key');
64867
64868
64869     return panel;
64870 }
64871
64872 function uiPanelHistory(context) {
64873
64874
64875     function displayTimestamp(entity) {
64876         if (!entity.timestamp) return t('info_panels.history.unknown');
64877
64878         var d = new Date(entity.timestamp);
64879         if (isNaN(d.getTime())) return t('info_panels.history.unknown');
64880
64881         return d.toLocaleString();
64882     }
64883
64884
64885     function displayUser(selection, entity) {
64886         if (!entity.user) {
64887             selection
64888                 .append('span')
64889                 .text(t('info_panels.history.unknown'));
64890             return;
64891         }
64892
64893         selection
64894             .append('span')
64895             .attr('class', 'user-name')
64896             .text(entity.user);
64897
64898         var links = selection
64899             .append('div')
64900             .attr('class', 'links');
64901
64902         links
64903             .append('a')
64904             .attr('class', 'user-osm-link')
64905             .attr('href', context.connection().userURL(entity.user))
64906             .attr('target', '_blank')
64907             .attr('tabindex', -1)
64908             .text('OSM');
64909
64910         links
64911             .append('a')
64912             .attr('class', 'user-hdyc-link')
64913             .attr('href', 'https://hdyc.neis-one.org/?' + entity.user)
64914             .attr('target', '_blank')
64915             .attr('tabindex', -1)
64916             .text('HDYC');
64917     }
64918
64919
64920     function displayChangeset(selection, entity) {
64921         if (!entity.changeset) {
64922             selection
64923                 .append('span')
64924                 .text(t('info_panels.history.unknown'));
64925             return;
64926         }
64927
64928         selection
64929             .append('span')
64930             .attr('class', 'changeset-id')
64931             .text(entity.changeset);
64932
64933         var links = selection
64934             .append('div')
64935             .attr('class', 'links');
64936
64937         links
64938             .append('a')
64939             .attr('class', 'changeset-osm-link')
64940             .attr('href', context.connection().changesetURL(entity.changeset))
64941             .attr('target', '_blank')
64942             .attr('tabindex', -1)
64943             .text('OSM');
64944
64945         links
64946             .append('a')
64947             .attr('class', 'changeset-osmcha-link')
64948             .attr('href', 'https://osmcha.mapbox.com/changesets/' + entity.changeset)
64949             .attr('target', '_blank')
64950             .attr('tabindex', -1)
64951             .text('OSMCha');
64952     }
64953
64954
64955     function redraw(selection) {
64956         var selected = lodash.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
64957             singular = selected.length === 1 ? selected[0] : null;
64958
64959         selection.html('');
64960
64961         selection
64962             .append('h4')
64963             .attr('class', 'history-heading')
64964             .text(singular || t('info_panels.history.selected', { n: selected.length }));
64965
64966         if (!singular) return;
64967
64968         var entity = context.entity(singular);
64969
64970         var list = selection
64971             .append('ul');
64972
64973         list
64974             .append('li')
64975             .text(t('info_panels.history.version') + ': ' + entity.version);
64976
64977         list
64978             .append('li')
64979             .text(t('info_panels.history.last_edit') + ': ' + displayTimestamp(entity));
64980
64981         list
64982             .append('li')
64983             .text(t('info_panels.history.edited_by') + ': ')
64984             .call(displayUser, entity);
64985
64986         list
64987             .append('li')
64988             .text(t('info_panels.history.changeset') + ': ')
64989             .call(displayChangeset, entity);
64990
64991         selection
64992             .append('a')
64993             .attr('class', 'view-history-on-osm')
64994             .attr('target', '_blank')
64995             .attr('tabindex', -1)
64996             .attr('href', context.connection().historyURL(entity))
64997             .call(svgIcon('#icon-out-link', 'inline'))
64998             .append('span')
64999             .text(t('info_panels.history.link_text'));
65000     }
65001
65002
65003     var panel = function(selection) {
65004         selection.call(redraw);
65005
65006         context.map()
65007             .on('drawn.info-history', function() {
65008                 selection.call(redraw);
65009             });
65010     };
65011
65012     panel.off = function() {
65013         context.map()
65014             .on('drawn.info-history', null);
65015     };
65016
65017     panel.id = 'history';
65018     panel.title = t('info_panels.history.title');
65019     panel.key = t('info_panels.history.key');
65020
65021
65022     return panel;
65023 }
65024
65025 function uiPanelLocation(context) {
65026     var currLocation = '';
65027     var OSM_PRECISION = 7;
65028
65029
65030     function wrap(x, min, max) {
65031         var d = max - min;
65032         return ((x - min) % d + d) % d + min;
65033     }
65034
65035
65036     function clamp(x, min, max) {
65037         return Math.max(min, Math.min(x, max));
65038     }
65039
65040
65041     function redraw(selection) {
65042         selection.html('');
65043
65044         var list = selection
65045             .append('ul');
65046
65047         // Mouse coordinates
65048         var coord = context.map().mouseCoordinates();
65049         if (coord.some(isNaN)) {
65050             coord = context.map().center();
65051         }
65052
65053         var coordStr =
65054             clamp(coord[1], -90, 90).toFixed(OSM_PRECISION) + ', ' +
65055             wrap(coord[0], -180, 180).toFixed(OSM_PRECISION);
65056
65057         list
65058             .append('li')
65059             .text(coordStr);
65060
65061         // Location Info
65062         selection
65063             .append('div')
65064             .attr('class', 'location-info')
65065             .text(currLocation || ' ');
65066
65067         debouncedGetLocation(selection, coord);
65068     }
65069
65070
65071     var debouncedGetLocation = lodash.debounce(getLocation, 250);
65072     function getLocation(selection, coord) {
65073         if (!services.geocoder) {
65074             currLocation = t('info_panels.location.unknown_location');
65075             selection.selectAll('.location-info')
65076                 .text(currLocation);
65077         } else {
65078             services.geocoder.reverse(coord, function(err, result) {
65079                 currLocation = result ? result.display_name : t('info_panels.location.unknown_location');
65080                 selection.selectAll('.location-info')
65081                     .text(currLocation);
65082             });
65083         }
65084     }
65085
65086
65087     var panel = function(selection) {
65088         selection.call(redraw);
65089
65090         context.surface()
65091             .on('mousemove.info-location', function() {
65092                 selection.call(redraw);
65093             });
65094     };
65095
65096     panel.off = function() {
65097         context.surface()
65098             .on('mousemove.info-location', null);
65099     };
65100
65101     panel.id = 'location';
65102     panel.title = t('info_panels.location.title');
65103     panel.key = t('info_panels.location.key');
65104
65105
65106     return panel;
65107 }
65108
65109 function uiPanelMeasurement(context) {
65110     var isImperial = (utilDetect().locale.toLowerCase() === 'en-us');
65111     var OSM_PRECISION = 7;
65112
65113
65114     function radiansToMeters(r) {
65115         // using WGS84 authalic radius (6371007.1809 m)
65116         return r * 6371007.1809;
65117     }
65118
65119     function steradiansToSqmeters(r) {
65120         // http://gis.stackexchange.com/a/124857/40446
65121         return r / (4 * Math.PI) * 510065621724000;
65122     }
65123
65124
65125     function toLineString(feature) {
65126         if (feature.type === 'LineString') return feature;
65127
65128         var result = { type: 'LineString', coordinates: [] };
65129         if (feature.type === 'Polygon') {
65130             result.coordinates = feature.coordinates[0];
65131         } else if (feature.type === 'MultiPolygon') {
65132             result.coordinates = feature.coordinates[0][0];
65133         }
65134
65135         return result;
65136     }
65137
65138
65139     function displayLength(m) {
65140         var d = m * (isImperial ? 3.28084 : 1),
65141             p, unit;
65142
65143         if (isImperial) {
65144             if (d >= 5280) {
65145                 d /= 5280;
65146                 unit = 'mi';
65147             } else {
65148                 unit = 'ft';
65149             }
65150         } else {
65151             if (d >= 1000) {
65152                 d /= 1000;
65153                 unit = 'km';
65154             } else {
65155                 unit = 'm';
65156             }
65157         }
65158
65159         // drop unnecessary precision
65160         p = d > 1000 ? 0 : d > 100 ? 1 : 2;
65161
65162         return String(d.toFixed(p)) + ' ' + unit;
65163     }
65164
65165
65166     function displayArea(m2) {
65167         var d = m2 * (isImperial ? 10.7639111056 : 1),
65168             d1, d2, p1, p2, unit1, unit2;
65169
65170         if (isImperial) {
65171             if (d >= 6969600) {     // > 0.25mi² show mi²
65172                 d1 = d / 27878400;
65173                 unit1 = 'mi²';
65174             } else {
65175                 d1 = d;
65176                 unit1 = 'ft²';
65177             }
65178
65179             if (d > 4356 && d < 43560000) {   // 0.1 - 1000 acres
65180                 d2 = d / 43560;
65181                 unit2 = 'ac';
65182             }
65183
65184         } else {
65185             if (d >= 250000) {    // > 0.25km² show km²
65186                 d1 = d / 1000000;
65187                 unit1 = 'km²';
65188             } else {
65189                 d1 = d;
65190                 unit1 = 'm²';
65191             }
65192
65193             if (d > 1000 && d < 10000000) {   // 0.1 - 1000 hectares
65194                 d2 = d / 10000;
65195                 unit2 = 'ha';
65196             }
65197         }
65198
65199         // drop unnecessary precision
65200         p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
65201         p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
65202
65203         return String(d1.toFixed(p1)) + ' ' + unit1 +
65204             (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
65205     }
65206
65207
65208     function redraw(selection$$1) {
65209         var resolver = context.graph(),
65210             selected = lodash.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
65211             singular = selected.length === 1 ? selected[0] : null,
65212             extent$$1 = geoExtent$$1(),
65213             entity;
65214
65215         selection$$1.html('');
65216
65217         selection$$1
65218             .append('h4')
65219             .attr('class', 'measurement-heading')
65220             .text(singular || t('info_panels.measurement.selected', { n: selected.length }));
65221
65222         if (!selected.length) return;
65223
65224         var center;
65225         for (var i = 0; i < selected.length; i++) {
65226             entity = context.entity(selected[i]);
65227             extent$$1._extend(entity.extent(resolver));
65228         }
65229         center = extent$$1.center();
65230
65231
65232         var list = selection$$1
65233             .append('ul');
65234
65235         // multiple features, just display extent center..
65236         if (!singular) {
65237             list
65238                 .append('li')
65239                 .text(t('info_panels.measurement.center') + ': ' +
65240                     center[1].toFixed(OSM_PRECISION) + ', ' + center[0].toFixed(OSM_PRECISION)
65241                 );
65242             return;
65243         }
65244
65245         // single feature, display details..
65246         if (!entity) return;
65247         var geometry = entity.geometry(resolver);
65248
65249         if (geometry === 'line' || geometry === 'area') {
65250             var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
65251                 feature = entity.asGeoJSON(resolver),
65252                 length = radiansToMeters(d3GeoLength(toLineString(feature))),
65253                 lengthLabel = t('info_panels.measurement.' + (closed ? 'perimeter' : 'length')),
65254                 centroid = d3GeoCentroid(feature);
65255
65256             list
65257                 .append('li')
65258                 .text(t('info_panels.measurement.geometry') + ': ' +
65259                     (closed ? t('info_panels.measurement.closed') + ' ' : '') + t('geometry.' + geometry) );
65260
65261             if (closed) {
65262                 var area$$1 = steradiansToSqmeters(entity.area(resolver));
65263                 list
65264                     .append('li')
65265                     .text(t('info_panels.measurement.area') + ': ' + displayArea(area$$1));
65266             }
65267
65268             list
65269                 .append('li')
65270                 .text(lengthLabel + ': ' + displayLength(length));
65271
65272             list
65273                 .append('li')
65274                 .text(t('info_panels.measurement.centroid') + ': ' +
65275                     centroid[1].toFixed(OSM_PRECISION) + ', ' + centroid[0].toFixed(OSM_PRECISION)
65276                 );
65277
65278
65279             var toggle  = isImperial ? 'imperial' : 'metric';
65280
65281             selection$$1
65282                 .append('a')
65283                 .text(t('info_panels.measurement.' + toggle))
65284                 .attr('href', '#')
65285                 .attr('class', 'button button-toggle-units')
65286                 .on('click', function() {
65287                     event.preventDefault();
65288                     isImperial = !isImperial;
65289                     selection$$1.call(redraw);
65290                 });
65291
65292         } else {
65293             var centerLabel = t('info_panels.measurement.' + (entity.type === 'node' ? 'location' : 'center'));
65294
65295             list
65296                 .append('li')
65297                 .text(t('info_panels.measurement.geometry') + ': ' + t('geometry.' + geometry));
65298
65299             list
65300                 .append('li')
65301                 .text(centerLabel + ': ' +
65302                     center[1].toFixed(OSM_PRECISION) + ', ' + center[0].toFixed(OSM_PRECISION)
65303                 );
65304         }
65305     }
65306
65307
65308     var panel = function(selection$$1) {
65309         selection$$1.call(redraw);
65310
65311         context.map()
65312             .on('drawn.info-measurement', function() {
65313                 selection$$1.call(redraw);
65314             });
65315     };
65316
65317     panel.off = function() {
65318         context.map()
65319             .on('drawn.info-measurement', null);
65320     };
65321
65322     panel.id = 'measurement';
65323     panel.title = t('info_panels.measurement.title');
65324     panel.key = t('info_panels.measurement.key');
65325
65326
65327     return panel;
65328 }
65329
65330 var uiInfoPanels = {
65331     background: uiPanelBackground,
65332     history: uiPanelHistory,
65333     location: uiPanelLocation,
65334     measurement: uiPanelMeasurement,
65335 };
65336
65337 function uiInfo(context) {
65338     var ids = Object.keys(uiInfoPanels),
65339         wasActive = ['measurement'],
65340         panels = {},
65341         active$$1 = {};
65342
65343     // create panels
65344     ids.forEach(function(k) {
65345         if (!panels[k]) {
65346             panels[k] = uiInfoPanels[k](context);
65347             active$$1[k] = false;
65348         }
65349     });
65350
65351
65352     function info(selection$$1) {
65353
65354         function redraw() {
65355             var activeids = ids.filter(function(k) { return active$$1[k]; }).sort();
65356
65357             var containers = infoPanels.selectAll('.panel-container')
65358                 .data(activeids, function(k) { return k; });
65359
65360             containers.exit()
65361                 .style('opacity', 1)
65362                 .transition()
65363                 .duration(200)
65364                 .style('opacity', 0)
65365                 .on('end', function(d) {
65366                     select(this)
65367                         .call(panels[d].off)
65368                         .remove();
65369                 });
65370
65371             var enter = containers.enter()
65372                 .append('div')
65373                 .attr('class', function(d) { return 'fillD2 panel-container panel-container-' + d; });
65374
65375             enter
65376                 .style('opacity', 0)
65377                 .transition()
65378                 .duration(200)
65379                 .style('opacity', 1);
65380
65381             var title = enter
65382                 .append('div')
65383                 .attr('class', 'panel-title fillD2');
65384
65385             title
65386                 .append('h3')
65387                 .text(function(d) { return panels[d].title; });
65388
65389             title
65390                 .append('button')
65391                 .attr('class', 'close')
65392                 .on('click', function (d) { toggle(d); })
65393                 .call(svgIcon('#icon-close'));
65394
65395             enter
65396                 .append('div')
65397                 .attr('class', function(d) { return 'panel-content panel-content-' + d; });
65398
65399
65400             // redraw the panels
65401             infoPanels.selectAll('.panel-content')
65402                 .each(function(d) {
65403                     select(this).call(panels[d]);
65404                 });
65405         }
65406
65407
65408         function toggle(which) {
65409             if (event) event.preventDefault();
65410
65411             var activeids = ids.filter(function(k) { return active$$1[k]; });
65412
65413             if (which) {  // toggle one
65414                 active$$1[which] = !active$$1[which];
65415                 if (activeids.length === 1 && activeids[0] === which) {  // none active anymore
65416                     wasActive = [which];
65417                 }
65418             } else {      // toggle all
65419                 if (activeids.length) {
65420                     wasActive = activeids;
65421                     activeids.forEach(function(k) { active$$1[k] = false; });
65422                 } else {
65423                     wasActive.forEach(function(k) { active$$1[k] = true; });
65424                 }
65425             }
65426
65427             redraw();
65428         }
65429
65430
65431         var infoPanels = selection$$1.selectAll('.info-panels')
65432             .data([0]);
65433
65434         infoPanels = infoPanels.enter()
65435             .append('div')
65436             .attr('class', 'info-panels')
65437             .merge(infoPanels);
65438
65439         redraw();
65440
65441         var keybinding = d3keybinding('info')
65442             .on(uiCmd('⌘' + t('info_panels.key')), toggle);
65443
65444         ids.forEach(function(k) {
65445             var key = t('info_panels.' + k + '.key', { default: null });
65446             if (!key) return;
65447             keybinding
65448                 .on(uiCmd('⌘⇧' + key), function() { toggle(k); });
65449         });
65450
65451         select(document)
65452             .call(keybinding);
65453     }
65454
65455     return info;
65456 }
65457
65458 function uiMapData(context) {
65459     var key = t('map_data.key'),
65460         features = context.features().keys(),
65461         layers = context.layers(),
65462         fills = ['wireframe', 'partial', 'full'],
65463         fillDefault = context.storage('area-fill') || 'partial',
65464         fillSelected = fillDefault;
65465
65466
65467     function map_data(selection$$1) {
65468
65469         function showsFeature(d) {
65470             return context.features().enabled(d);
65471         }
65472
65473
65474         function autoHiddenFeature(d) {
65475             return context.features().autoHidden(d);
65476         }
65477
65478
65479         function clickFeature(d) {
65480             context.features().toggle(d);
65481             update();
65482         }
65483
65484
65485         function showsFill(d) {
65486             return fillSelected === d;
65487         }
65488
65489
65490         function setFill(d) {
65491             lodash.each(fills, function(opt) {
65492                 context.surface().classed('fill-' + opt, Boolean(opt === d));
65493             });
65494
65495             fillSelected = d;
65496             if (d !== 'wireframe') {
65497                 fillDefault = d;
65498                 context.storage('area-fill', d);
65499             }
65500             update();
65501         }
65502
65503
65504         function showsLayer(which) {
65505             var layer = layers.layer(which);
65506             if (layer) {
65507                 return layer.enabled();
65508             }
65509             return false;
65510         }
65511
65512
65513         function setLayer(which, enabled) {
65514             var layer = layers.layer(which);
65515             if (layer) {
65516                 layer.enabled(enabled);
65517                 update();
65518             }
65519         }
65520
65521
65522         function toggleLayer(which) {
65523             setLayer(which, !showsLayer(which));
65524         }
65525
65526
65527         function clickGpx() {
65528             toggleLayer('gpx');
65529         }
65530
65531
65532         function clickMapillaryImages() {
65533             toggleLayer('mapillary-images');
65534             if (!showsLayer('mapillary-images')) {
65535                 setLayer('mapillary-signs', false);
65536             }
65537         }
65538
65539
65540         function clickMapillarySigns() {
65541             toggleLayer('mapillary-signs');
65542         }
65543
65544
65545         function drawMapillaryItems(selection$$1) {
65546             var mapillaryImages = layers.layer('mapillary-images'),
65547                 mapillarySigns = layers.layer('mapillary-signs'),
65548                 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
65549                 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
65550                 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
65551                 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
65552
65553             var mapillaryList = selection$$1
65554                 .selectAll('.layer-list-mapillary')
65555                 .data([0]);
65556
65557             mapillaryList = mapillaryList.enter()
65558                 .append('ul')
65559                 .attr('class', 'layer-list layer-list-mapillary')
65560                 .merge(mapillaryList);
65561
65562
65563             var mapillaryImageLayerItem = mapillaryList
65564                 .selectAll('.list-item-mapillary-images')
65565                 .data(supportsMapillaryImages ? [0] : []);
65566
65567             mapillaryImageLayerItem.exit()
65568                 .remove();
65569
65570             var enterImages = mapillaryImageLayerItem.enter()
65571                 .append('li')
65572                 .attr('class', 'list-item-mapillary-images');
65573
65574             var labelImages = enterImages
65575                 .append('label')
65576                 .call(tooltip()
65577                     .title(t('mapillary_images.tooltip'))
65578                     .placement('top'));
65579
65580             labelImages
65581                 .append('input')
65582                 .attr('type', 'checkbox')
65583                 .on('change', clickMapillaryImages);
65584
65585             labelImages
65586                 .append('span')
65587                 .text(t('mapillary_images.title'));
65588
65589
65590             var mapillarySignLayerItem = mapillaryList
65591                 .selectAll('.list-item-mapillary-signs')
65592                 .data(supportsMapillarySigns ? [0] : []);
65593
65594             mapillarySignLayerItem.exit()
65595                 .remove();
65596
65597             var enterSigns = mapillarySignLayerItem.enter()
65598                 .append('li')
65599                 .attr('class', 'list-item-mapillary-signs');
65600
65601             var labelSigns = enterSigns
65602                 .append('label')
65603                 .call(tooltip()
65604                     .title(t('mapillary_signs.tooltip'))
65605                     .placement('top'));
65606
65607             labelSigns
65608                 .append('input')
65609                 .attr('type', 'checkbox')
65610                 .on('change', clickMapillarySigns);
65611
65612             labelSigns
65613                 .append('span')
65614                 .text(t('mapillary_signs.title'));
65615
65616
65617             // Updates
65618             mapillaryImageLayerItem = mapillaryImageLayerItem
65619                 .merge(enterImages);
65620
65621             mapillaryImageLayerItem
65622                 .classed('active', showsMapillaryImages)
65623                 .selectAll('input')
65624                 .property('checked', showsMapillaryImages);
65625
65626
65627             mapillarySignLayerItem = mapillarySignLayerItem
65628                 .merge(enterSigns);
65629
65630             mapillarySignLayerItem
65631                 .classed('active', showsMapillarySigns)
65632                 .selectAll('input')
65633                 .property('disabled', !showsMapillaryImages)
65634                 .property('checked', showsMapillarySigns);
65635
65636             mapillarySignLayerItem
65637                 .selectAll('label')
65638                 .classed('deemphasize', !showsMapillaryImages);
65639         }
65640
65641
65642         function drawGpxItem(selection$$1) {
65643             var gpx = layers.layer('gpx'),
65644                 hasGpx = gpx && gpx.hasGpx(),
65645                 showsGpx = hasGpx && gpx.enabled();
65646
65647             var gpxLayerItem = selection$$1
65648                 .selectAll('.layer-list-gpx')
65649                 .data(gpx ? [0] : []);
65650
65651             // Exit
65652             gpxLayerItem.exit()
65653                 .remove();
65654
65655             // Enter
65656             var enter = gpxLayerItem.enter()
65657                 .append('ul')
65658                 .attr('class', 'layer-list layer-list-gpx')
65659                 .append('li')
65660                 .classed('list-item-gpx', true);
65661
65662             enter
65663                 .append('button')
65664                 .attr('class', 'list-item-gpx-extent')
65665                 .call(tooltip()
65666                     .title(t('gpx.zoom'))
65667                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
65668                 .on('click', function() {
65669                     event.preventDefault();
65670                     event.stopPropagation();
65671                     gpx.fitZoom();
65672                 })
65673                 .call(svgIcon('#icon-search'));
65674
65675             enter
65676                 .append('button')
65677                 .attr('class', 'list-item-gpx-browse')
65678                 .call(tooltip()
65679                     .title(t('gpx.browse'))
65680                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
65681                 .on('click', function() {
65682                     select(document.createElement('input'))
65683                         .attr('type', 'file')
65684                         .on('change', function() {
65685                             gpx.files(event.target.files);
65686                         })
65687                         .node().click();
65688                 })
65689                 .call(svgIcon('#icon-geolocate'));
65690
65691             var labelGpx = enter
65692                 .append('label')
65693                 .call(tooltip().title(t('gpx.drag_drop')).placement('top'));
65694
65695             labelGpx
65696                 .append('input')
65697                 .attr('type', 'checkbox')
65698                 .on('change', clickGpx);
65699
65700             labelGpx
65701                 .append('span')
65702                 .text(t('gpx.local_layer'));
65703
65704
65705             // Update
65706             gpxLayerItem = gpxLayerItem
65707                 .merge(enter);
65708
65709             gpxLayerItem
65710                 .classed('active', showsGpx)
65711                 .selectAll('input')
65712                 .property('disabled', !hasGpx)
65713                 .property('checked', showsGpx);
65714
65715             gpxLayerItem
65716                 .selectAll('label')
65717                 .classed('deemphasize', !hasGpx);
65718         }
65719
65720
65721         function drawList(selection$$1, data, type, name, change, active$$1) {
65722             var items = selection$$1.selectAll('li')
65723                 .data(data);
65724
65725             // Exit
65726             items.exit()
65727                 .remove();
65728
65729             // Enter
65730             var enter = items.enter()
65731                 .append('li')
65732                 .attr('class', 'layer')
65733                 .call(tooltip()
65734                     .html(true)
65735                     .title(function(d) {
65736                         var tip = t(name + '.' + d + '.tooltip'),
65737                             key = (d === 'wireframe' ? t('area_fill.wireframe.key') : null);
65738
65739                         if (name === 'feature' && autoHiddenFeature(d)) {
65740                             tip += '<div>' + t('map_data.autohidden') + '</div>';
65741                         }
65742                         return uiTooltipHtml(tip, key);
65743                     })
65744                     .placement('top')
65745                 );
65746
65747             var label = enter
65748                 .append('label');
65749
65750             label
65751                 .append('input')
65752                 .attr('type', type)
65753                 .attr('name', name)
65754                 .on('change', change);
65755
65756             label
65757                 .append('span')
65758                 .text(function(d) { return t(name + '.' + d + '.description'); });
65759
65760             // Update
65761             items = items
65762                 .merge(enter);
65763
65764             items
65765                 .classed('active', active$$1)
65766                 .selectAll('input')
65767                 .property('checked', active$$1)
65768                 .property('indeterminate', function(d) {
65769                     return (name === 'feature' && autoHiddenFeature(d));
65770                 });
65771         }
65772
65773
65774         function update() {
65775             dataLayerContainer.call(drawMapillaryItems);
65776             dataLayerContainer.call(drawGpxItem);
65777
65778             fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
65779             featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
65780         }
65781
65782
65783         function hidePanel() {
65784             setVisible(false);
65785         }
65786
65787
65788         function togglePanel() {
65789             if (event) event.preventDefault();
65790             tooltipBehavior.hide(button);
65791             setVisible(!button.classed('active'));
65792         }
65793
65794
65795         function toggleWireframe() {
65796             if (event) {
65797                 event.preventDefault();
65798                 event.stopPropagation();
65799             }
65800             setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
65801             context.map().pan([0,0]);  // trigger a redraw
65802         }
65803
65804
65805         function setVisible(show) {
65806             if (show !== shown) {
65807                 button.classed('active', show);
65808                 shown = show;
65809
65810                 if (show) {
65811                     update();
65812                     selection$$1.on('mousedown.map_data-inside', function() {
65813                         return event.stopPropagation();
65814                     });
65815                     content.style('display', 'block')
65816                         .style('right', '-300px')
65817                         .transition()
65818                         .duration(200)
65819                         .style('right', '0px');
65820                 } else {
65821                     content.style('display', 'block')
65822                         .style('right', '0px')
65823                         .transition()
65824                         .duration(200)
65825                         .style('right', '-300px')
65826                         .on('end', function() {
65827                             select(this).style('display', 'none');
65828                         });
65829                     selection$$1.on('mousedown.map_data-inside', null);
65830                 }
65831             }
65832         }
65833
65834
65835         var content = selection$$1
65836                 .append('div')
65837                 .attr('class', 'fillL map-overlay col3 content hide'),
65838             tooltipBehavior = tooltip()
65839                 .placement((textDirection === 'rtl') ? 'right' : 'left')
65840                 .html(true)
65841                 .title(uiTooltipHtml(t('map_data.description'), key)),
65842             button = selection$$1
65843                 .append('button')
65844                 .attr('tabindex', -1)
65845                 .on('click', togglePanel)
65846                 .call(svgIcon('#icon-data', 'light'))
65847                 .call(tooltipBehavior),
65848             shown = false;
65849
65850         content
65851             .append('h4')
65852             .text(t('map_data.title'));
65853
65854
65855         // data layers
65856         content
65857             .append('a')
65858             .text(t('map_data.data_layers'))
65859             .attr('href', '#')
65860             .classed('hide-toggle', true)
65861             .classed('expanded', true)
65862             .on('click', function() {
65863                 var exp = select(this).classed('expanded');
65864                 dataLayerContainer.style('display', exp ? 'none' : 'block');
65865                 select(this).classed('expanded', !exp);
65866                 event.preventDefault();
65867             });
65868
65869         var dataLayerContainer = content
65870             .append('div')
65871             .attr('class', 'data-data-layers')
65872             .style('display', 'block');
65873
65874
65875         // area fills
65876         content
65877             .append('a')
65878             .text(t('map_data.fill_area'))
65879             .attr('href', '#')
65880             .classed('hide-toggle', true)
65881             .classed('expanded', false)
65882             .on('click', function() {
65883                 var exp = select(this).classed('expanded');
65884                 fillContainer.style('display', exp ? 'none' : 'block');
65885                 select(this).classed('expanded', !exp);
65886                 event.preventDefault();
65887             });
65888
65889         var fillContainer = content
65890             .append('div')
65891             .attr('class', 'data-area-fills')
65892             .style('display', 'none');
65893
65894         var fillList = fillContainer
65895             .append('ul')
65896             .attr('class', 'layer-list layer-fill-list');
65897
65898
65899         // feature filters
65900         content
65901             .append('a')
65902             .text(t('map_data.map_features'))
65903             .attr('href', '#')
65904             .classed('hide-toggle', true)
65905             .classed('expanded', false)
65906             .on('click', function() {
65907                 var exp = select(this).classed('expanded');
65908                 featureContainer.style('display', exp ? 'none' : 'block');
65909                 select(this).classed('expanded', !exp);
65910                 event.preventDefault();
65911             });
65912
65913         var featureContainer = content
65914             .append('div')
65915             .attr('class', 'data-feature-filters')
65916             .style('display', 'none');
65917
65918         var featureList = featureContainer
65919             .append('ul')
65920             .attr('class', 'layer-list layer-feature-list');
65921
65922
65923         context.features()
65924             .on('change.map_data-update', update);
65925
65926         setFill(fillDefault);
65927
65928         var keybinding = d3keybinding('features')
65929             .on(key, togglePanel)
65930             .on(t('area_fill.wireframe.key'), toggleWireframe)
65931             .on([t('background.key'), t('help.key')], hidePanel);
65932
65933         select(document)
65934             .call(keybinding);
65935
65936         context.surface().on('mousedown.map_data-outside', hidePanel);
65937         context.container().on('mousedown.map_data-outside', hidePanel);
65938     }
65939
65940
65941     return map_data;
65942 }
65943
65944 function uiModes(context) {
65945     var modes = [
65946         modeAddPoint$$1(context),
65947         modeAddLine$$1(context),
65948         modeAddArea$$1(context)
65949     ];
65950
65951
65952     function editable() {
65953         return context.editable() && context.mode().id !== 'save';
65954     }
65955
65956
65957     return function(selection$$1) {
65958         var buttons = selection$$1.selectAll('button.add-button')
65959             .data(modes);
65960
65961         buttons = buttons.enter()
65962             .append('button')
65963             .attr('tabindex', -1)
65964             .attr('class', function(mode) { return mode.id + ' add-button col4'; })
65965             .on('click.mode-buttons', function(mode) {
65966                 if (mode.id === context.mode().id) {
65967                     context.enter(modeBrowse(context));
65968                 } else {
65969                     context.enter(mode);
65970                 }
65971             })
65972             .call(tooltip()
65973                 .placement('bottom')
65974                 .html(true)
65975                 .title(function(mode) {
65976                     return uiTooltipHtml(mode.description, mode.key);
65977                 })
65978             );
65979
65980         context.map()
65981             .on('move.modes', lodash.debounce(update, 500));
65982
65983         context
65984             .on('enter.modes', update);
65985
65986         buttons
65987             .each(function(d) {
65988                 select(this)
65989                     .call(svgIcon('#icon-' + d.button, 'pre-text'));
65990             });
65991
65992         buttons
65993             .append('span')
65994             .attr('class', 'label')
65995             .text(function(mode) { return mode.title; });
65996
65997         context
65998             .on('enter.editor', function(entered) {
65999                 selection$$1.selectAll('button.add-button')
66000                     .classed('active', function(mode) { return entered.button === mode.button; });
66001                 context.container()
66002                     .classed('mode-' + entered.id, true);
66003             });
66004
66005         context
66006             .on('exit.editor', function(exited) {
66007                 context.container()
66008                     .classed('mode-' + exited.id, false);
66009             });
66010
66011         var keybinding = d3keybinding('mode-buttons');
66012
66013         modes.forEach(function(mode) {
66014             keybinding.on(mode.key, function() {
66015                 if (editable()) {
66016                     if (mode.id === context.mode().id) {
66017                         context.enter(modeBrowse(context));
66018                     } else {
66019                         context.enter(mode);
66020                     }
66021                 }
66022             });
66023         });
66024
66025         select(document)
66026             .call(keybinding);
66027
66028
66029         function update() {
66030             selection$$1.selectAll('button.add-button')
66031                 .property('disabled', !editable());
66032         }
66033     };
66034 }
66035
66036 function uiRestore(context) {
66037
66038     return function(selection) {
66039         if (!context.history().lock() || !context.history().restorableChanges())
66040             return;
66041
66042         var modalSelection = uiModal(selection, true);
66043
66044         modalSelection.select('.modal')
66045             .attr('class', 'modal fillL col6');
66046
66047         var introModal = modalSelection.select('.content');
66048
66049         introModal
66050             .attr('class','cf');
66051
66052         introModal
66053             .append('div')
66054             .attr('class', 'modal-section')
66055             .append('h3')
66056             .text(t('restore.heading'));
66057
66058         introModal
66059             .append('div')
66060             .attr('class','modal-section')
66061             .append('p')
66062             .text(t('restore.description'));
66063
66064         var buttonWrap = introModal
66065             .append('div')
66066             .attr('class', 'modal-actions cf');
66067
66068         var restore = buttonWrap
66069             .append('button')
66070             .attr('class', 'restore col6')
66071             .on('click', function() {
66072                 context.history().restore();
66073                 modalSelection.remove();
66074             });
66075
66076         restore
66077             .append('svg')
66078             .attr('class', 'logo logo-restore')
66079             .append('use')
66080             .attr('xlink:href', '#logo-restore');
66081
66082         restore
66083             .append('div')
66084             .text(t('restore.restore'));
66085
66086         var reset = buttonWrap
66087             .append('button')
66088             .attr('class', 'reset col6')
66089             .on('click', function() {
66090                 context.history().clearSaved();
66091                 modalSelection.remove();
66092             });
66093
66094         reset
66095             .append('svg')
66096             .attr('class', 'logo logo-reset')
66097             .append('use')
66098             .attr('xlink:href', '#logo-reset');
66099
66100         reset
66101             .append('div')
66102             .text(t('restore.reset'));
66103
66104         restore.node().focus();
66105     };
66106 }
66107
66108 function uiSave(context) {
66109     var history = context.history(),
66110         key = uiCmd('⌘S');
66111
66112
66113     function saving() {
66114         return context.mode().id === 'save';
66115     }
66116
66117
66118     function save() {
66119         event.preventDefault();
66120         if (!context.inIntro() && !saving() && history.hasChanges()) {
66121             context.enter(modeSave$$1(context));
66122         }
66123     }
66124
66125
66126     function getBackground(numChanges) {
66127         var step$$1;
66128         if (numChanges === 0) {
66129             return null;
66130         } else if (numChanges <= 50) {
66131             step$$1 = numChanges / 50;
66132             return interpolateRgb('#fff', '#ff8')(step$$1);  // white -> yellow
66133         } else {
66134             step$$1 = Math.min((numChanges - 50) / 50, 1.0);
66135             return interpolateRgb('#ff8', '#f88')(step$$1);  // yellow -> red
66136         }
66137     }
66138
66139
66140     return function(selection$$1) {
66141         var numChanges = 0;
66142
66143         function updateCount() {
66144             var _ = history.difference().summary().length;
66145             if (_ === numChanges) return;
66146             numChanges = _;
66147
66148             tooltipBehavior
66149                 .title(uiTooltipHtml(
66150                     t(numChanges > 0 ? 'save.help' : 'save.no_changes'), key)
66151                 );
66152
66153             var background = getBackground(numChanges);
66154
66155             button
66156                 .classed('disabled', numChanges === 0)
66157                 .classed('has-count', numChanges > 0)
66158                 .style('background', background);
66159
66160             button.select('span.count')
66161                 .text(numChanges)
66162                 .style('background', background)
66163                 .style('border-color', background);
66164         }
66165
66166
66167         var tooltipBehavior = tooltip()
66168             .placement('bottom')
66169             .html(true)
66170             .title(uiTooltipHtml(t('save.no_changes'), key));
66171
66172         var button = selection$$1
66173             .append('button')
66174             .attr('class', 'save col12 disabled')
66175             .attr('tabindex', -1)
66176             .on('click', save)
66177             .call(tooltipBehavior);
66178
66179         button
66180             .call(svgIcon('#icon-save', 'pre-text'))
66181             .append('span')
66182             .attr('class', 'label')
66183             .text(t('save.title'));
66184
66185         button
66186             .append('span')
66187             .attr('class', 'count')
66188             .text('0');
66189
66190         updateCount();
66191
66192
66193         var keybinding = d3keybinding('save')
66194             .on(key, save, true);
66195
66196         select(document)
66197             .call(keybinding);
66198
66199         context.history()
66200             .on('change.save', updateCount);
66201
66202         context
66203             .on('enter.save', function() {
66204                 button.property('disabled', saving());
66205                 if (saving()) button.call(tooltipBehavior.hide);
66206             });
66207     };
66208 }
66209
66210 function uiScale(context) {
66211     var projection = context.projection,
66212         isImperial = (utilDetect().locale.toLowerCase() === 'en-us'),
66213         maxLength = 180,
66214         tickHeight = 8;
66215
66216
66217     function scaleDefs(loc1, loc2) {
66218         var lat = (loc2[1] + loc1[1]) / 2,
66219             conversion = (isImperial ? 3.28084 : 1),
66220             dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
66221             scale = { dist: 0, px: 0, text: '' },
66222             buckets, i, val, dLon;
66223
66224         if (isImperial) {
66225             buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
66226         } else {
66227             buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
66228         }
66229
66230         // determine a user-friendly endpoint for the scale
66231         for (i = 0; i < buckets.length; i++) {
66232             val = buckets[i];
66233             if (dist >= val) {
66234                 scale.dist = Math.floor(dist / val) * val;
66235                 break;
66236             } else {
66237                 scale.dist = +dist.toFixed(2);
66238             }
66239         }
66240
66241         dLon = geoMetersToLon(scale.dist / conversion, lat);
66242         scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
66243
66244         if (isImperial) {
66245             if (scale.dist >= 5280) {
66246                 scale.dist /= 5280;
66247                 scale.text = String(scale.dist) + ' mi';
66248             } else {
66249                 scale.text = String(scale.dist) + ' ft';
66250             }
66251         } else {
66252             if (scale.dist >= 1000) {
66253                 scale.dist /= 1000;
66254                 scale.text = String(scale.dist) + ' km';
66255             } else {
66256                 scale.text = String(scale.dist) + ' m';
66257             }
66258         }
66259
66260         return scale;
66261     }
66262
66263
66264     function update(selection) {
66265         // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
66266         var dims = context.map().dimensions(),
66267             loc1 = projection.invert([0, dims[1]]),
66268             loc2 = projection.invert([maxLength, dims[1]]),
66269             scale = scaleDefs(loc1, loc2);
66270
66271         selection.select('#scale-path')
66272             .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
66273
66274         selection.select('#scale-textgroup')
66275             .attr('transform', 'translate(' + (scale.px + 8) + ',' + tickHeight + ')');
66276
66277         selection.select('#scale-text')
66278             .text(scale.text);
66279     }
66280
66281
66282     return function(selection) {
66283         function switchUnits() {
66284             isImperial = !isImperial;
66285             selection.call(update);
66286         }
66287
66288         var scalegroup = selection.append('svg')
66289             .attr('id', 'scale')
66290             .on('click', switchUnits)
66291             .append('g')
66292             .attr('transform', 'translate(10,11)');
66293
66294         scalegroup
66295             .append('path')
66296             .attr('id', 'scale-path');
66297
66298         scalegroup
66299             .append('g')
66300             .attr('id', 'scale-textgroup')
66301             .append('text')
66302             .attr('id', 'scale-text');
66303
66304         selection.call(update);
66305
66306         context.map().on('move.scale', function() {
66307             update(selection);
66308         });
66309     };
66310 }
66311
66312 var pair_1 = pair$1;
66313 function search(x, dims, r) {
66314   if (!dims) dims = 'NSEW';
66315   if (typeof x !== 'string') return { val: null, regex: r };
66316   r = r || /[\s\,]*([\-|\—|\―]?[0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/gi;
66317   var m = r.exec(x);
66318   if (!m) return { val: null, regex: r };
66319   else if (m[4] && dims.indexOf(m[4]) === -1) return { val: null, regex: r };
66320   else return {
66321     val: (((m[1]) ? parseFloat(m[1]) : 0) +
66322           ((m[2] ? parseFloat(m[2]) / 60 : 0)) +
66323           ((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
66324           ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1),
66325     regex: r,
66326     raw: m[0],
66327     dim: m[4]
66328   };
66329 }
66330
66331 function pair$1(x, dims) {
66332   x = x.trim();
66333   var one = search(x, dims);
66334   if (one.val === null) return null;
66335   var two = search(x, dims, one.regex);
66336   if (two.val === null) return null;
66337   // null if one/two are not contiguous.
66338   if (one.raw + two.raw !== x) return null;
66339   if (one.dim) {
66340     return swapdim(one.val, two.val, one.dim);
66341   } else {
66342     return [one.val, two.val];
66343   }
66344 }
66345
66346 function swapdim(a, b, dim) {
66347   if (dim === 'N' || dim === 'S') return [a, b];
66348   if (dim === 'W' || dim === 'E') return [b, a];
66349 }
66350
66351 function uiFeatureList(context) {
66352     var geocodeResults;
66353
66354
66355     function featureList(selection$$1) {
66356         var header = selection$$1
66357             .append('div')
66358             .attr('class', 'header fillL cf');
66359
66360         header.append('h3')
66361             .text(t('inspector.feature_list'));
66362
66363         var searchWrap = selection$$1
66364             .append('div')
66365             .attr('class', 'search-header');
66366
66367         var search = searchWrap
66368             .append('input')
66369             .attr('placeholder', t('inspector.search'))
66370             .attr('type', 'search')
66371             .call(utilNoAuto)
66372             .on('keypress', keypress)
66373             .on('input', inputevent);
66374
66375         searchWrap
66376             .call(svgIcon('#icon-search', 'pre-text'));
66377
66378         var listWrap = selection$$1
66379             .append('div')
66380             .attr('class', 'inspector-body');
66381
66382         var list = listWrap
66383             .append('div')
66384             .attr('class', 'feature-list cf');
66385
66386         context
66387             .on('exit.feature-list', clearSearch);
66388         context.map()
66389             .on('drawn.feature-list', mapDrawn);
66390
66391
66392         function keypress() {
66393             var q = search.property('value'),
66394                 items = list.selectAll('.feature-list-item');
66395             if (event.keyCode === 13 && q.length && items.size()) {
66396                 click(items.datum());
66397             }
66398         }
66399
66400
66401         function inputevent() {
66402             geocodeResults = undefined;
66403             drawList();
66404         }
66405
66406
66407         function clearSearch() {
66408             search.property('value', '');
66409             drawList();
66410         }
66411
66412
66413         function mapDrawn(e) {
66414             if (e.full) {
66415                 drawList();
66416             }
66417         }
66418
66419
66420         function features() {
66421             var entities = {},
66422                 result = [],
66423                 graph = context.graph(),
66424                 q = search.property('value').toLowerCase();
66425
66426             if (!q) return result;
66427
66428             var idMatch = q.match(/^([nwr])([0-9]+)$/);
66429
66430             if (idMatch) {
66431                 result.push({
66432                     id: idMatch[0],
66433                     geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
66434                     type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
66435                     name: idMatch[2]
66436                 });
66437             }
66438
66439             var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
66440
66441             if (locationMatch) {
66442                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
66443                 result.push({
66444                     id: -1,
66445                     geometry: 'point',
66446                     type: t('inspector.location'),
66447                     name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
66448                     location: loc
66449                 });
66450             }
66451
66452             function addEntity(entity) {
66453                 if (entity.id in entities || result.length > 200)
66454                     return;
66455
66456                 entities[entity.id] = true;
66457
66458                 var name = utilDisplayName(entity) || '';
66459                 if (name.toLowerCase().indexOf(q) >= 0) {
66460                     var matched = context.presets().match(entity, graph),
66461                         type = (matched && matched.name()) || utilDisplayType(entity.id);
66462                     result.push({
66463                         id: entity.id,
66464                         entity: entity,
66465                         geometry: context.geometry(entity.id),
66466                         type: type,
66467                         name: name
66468                     });
66469                 }
66470
66471                 graph.parentRelations(entity).forEach(function(parent) {
66472                     addEntity(parent);
66473                 });
66474             }
66475
66476             var visible = context.surface().selectAll('.point, .line, .area').nodes();
66477             for (var i = 0; i < visible.length && result.length <= 200; i++) {
66478                 addEntity(visible[i].__data__);
66479             }
66480
66481             (geocodeResults || []).forEach(function(d) {
66482                 // https://github.com/openstreetmap/iD/issues/1890
66483                 if (d.osm_type && d.osm_id) {
66484                     result.push({
66485                         id: osmEntity$$1.id.fromOSM(d.osm_type, d.osm_id),
66486                         geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
66487                         type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
66488                                                : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
66489                         name: d.display_name,
66490                         extent: new geoExtent$$1(
66491                             [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
66492                             [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
66493                     });
66494                 }
66495             });
66496
66497             return result;
66498         }
66499
66500
66501         function drawList() {
66502             var value = search.property('value'),
66503                 results = features();
66504
66505             list.classed('filtered', value.length);
66506
66507             var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
66508
66509             var resultsIndicator = list.selectAll('.no-results-item')
66510                 .data([0])
66511                 .enter().append('button')
66512                 .property('disabled', true)
66513                 .attr('class', 'no-results-item')
66514                 .call(svgIcon('#icon-alert', 'pre-text'));
66515
66516             resultsIndicator.append('span')
66517                 .attr('class', 'entity-name');
66518
66519             list.selectAll('.no-results-item .entity-name')
66520                 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
66521
66522             if (services.geocoder) {
66523               list.selectAll('.geocode-item')
66524                   .data([0])
66525                   .enter().append('button')
66526                   .attr('class', 'geocode-item')
66527                   .on('click', geocoderSearch)
66528                   .append('div')
66529                   .attr('class', 'label')
66530                   .append('span')
66531                   .attr('class', 'entity-name')
66532                   .text(t('geocoder.search'));
66533             }
66534
66535             list.selectAll('.no-results-item')
66536                 .style('display', (value.length && !results.length) ? 'block' : 'none');
66537
66538             list.selectAll('.geocode-item')
66539                 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
66540
66541             list.selectAll('.feature-list-item')
66542                 .data([-1])
66543                 .remove();
66544
66545             var items = list.selectAll('.feature-list-item')
66546                 .data(results, function(d) { return d.id; });
66547
66548             var enter = items.enter()
66549                 .insert('button', '.geocode-item')
66550                 .attr('class', 'feature-list-item')
66551                 .on('mouseover', mouseover)
66552                 .on('mouseout', mouseout)
66553                 .on('click', click);
66554
66555             var label = enter
66556                 .append('div')
66557                 .attr('class', 'label');
66558
66559             label.each(function(d) {
66560                 select(this)
66561                     .call(svgIcon('#icon-' + d.geometry, 'pre-text'));
66562             });
66563
66564             label.append('span')
66565                 .attr('class', 'entity-type')
66566                 .text(function(d) { return d.type; });
66567
66568             label.append('span')
66569                 .attr('class', 'entity-name')
66570                 .text(function(d) { return d.name; });
66571
66572             enter.style('opacity', 0)
66573                 .transition()
66574                 .style('opacity', 1);
66575
66576             items.order();
66577
66578             items.exit()
66579                 .remove();
66580         }
66581
66582
66583         function mouseover(d) {
66584             if (d.id === -1) return;
66585
66586             context.surface().selectAll(utilEntityOrMemberSelector([d.id], context.graph()))
66587                 .classed('hover', true);
66588         }
66589
66590
66591         function mouseout() {
66592             context.surface().selectAll('.hover')
66593                 .classed('hover', false);
66594         }
66595
66596
66597         function click(d) {
66598             event.preventDefault();
66599             if (d.location) {
66600                 context.map().centerZoom([d.location[1], d.location[0]], 20);
66601             }
66602             else if (d.entity) {
66603                 if (d.entity.type === 'node') {
66604                     context.map().center(d.entity.loc);
66605                 } else if (d.entity.type === 'way') {
66606                     var center = context.projection(context.map().center()),
66607                         edge = geoChooseEdge(context.childNodes(d.entity), center, context.projection);
66608                     context.map().center(edge.loc);
66609                 }
66610                 context.enter(modeSelect(context, [d.entity.id]));
66611             } else {
66612                 context.zoomToEntity(d.id);
66613             }
66614         }
66615
66616
66617         function geocoderSearch() {
66618             services.geocoder.search(search.property('value'), function (err, resp) {
66619                 geocodeResults = resp || [];
66620                 drawList();
66621             });
66622         }
66623     }
66624
66625
66626     return featureList;
66627 }
66628
66629 function uiPresetIcon() {
66630     var preset, geometry;
66631
66632
66633     function presetIcon(selection$$1) {
66634         selection$$1.each(render);
66635     }
66636
66637
66638     function getIcon(p, geom) {
66639         if (p.icon)
66640             return p.icon;
66641         else if (geom === 'line')
66642             return 'other-line';
66643         else if (geom === 'vertex')
66644             return p.isFallback() ? '' : 'poi-vertex';
66645         else
66646             return 'marker-stroked';
66647     }
66648
66649
66650     function render() {
66651         var selection$$1 = select(this),
66652             p = preset.apply(this, arguments),
66653             geom = geometry.apply(this, arguments),
66654             picon = getIcon(p, geom),
66655             isPoi = picon.match(/^poi-/) !== null,
66656             isMaki = dataFeatureIcons.indexOf(picon) !== -1,
66657             isFramed = (geom === 'area' || geom === 'verex');
66658
66659
66660         function tag_classes(p) {
66661             var s = '';
66662             for (var i in p.tags) {
66663                 s += ' tag-' + i;
66664                 if (p.tags[i] !== '*') {
66665                     s += ' tag-' + i + '-' + p.tags[i];
66666                 }
66667             }
66668             return s;
66669         }
66670
66671
66672         var fill = selection$$1.selectAll('.preset-icon-fill')
66673             .data([0]);
66674
66675         fill = fill.enter()
66676             .append('div')
66677             .merge(fill);
66678
66679         fill
66680             .attr('class', function() {
66681                 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
66682             });
66683
66684
66685         var areaFrame = selection$$1.selectAll('.preset-icon-frame')
66686             .data((geom === 'area') ? [0] : []);
66687
66688         areaFrame.exit()
66689             .remove();
66690
66691         areaFrame = areaFrame.enter()
66692             .append('div')
66693             .attr('class', 'preset-icon-frame')
66694             .call(svgIcon('#preset-icon-frame'));
66695
66696
66697         var icon = selection$$1.selectAll('.preset-icon')
66698             .data([0]);
66699
66700         icon = icon.enter()
66701             .append('div')
66702             .attr('class', 'preset-icon')
66703             .call(svgIcon(''))
66704             .merge(icon);
66705
66706         icon
66707             .attr('class', 'preset-icon preset-icon-' +
66708                 ((isMaki || isPoi) ? (isFramed ? '24' : '28') : (isFramed ? '44' : '60'))
66709             );
66710
66711         icon.selectAll('svg')
66712             .attr('class', function() {
66713                 return 'icon ' + picon + (isMaki || isPoi ? '' : tag_classes(p));
66714             });
66715
66716         icon.selectAll('use')
66717             .attr('href', '#' + picon + (isMaki ? '-15' : ''));
66718     }
66719
66720
66721     presetIcon.preset = function(_) {
66722         if (!arguments.length) return preset;
66723         preset = utilFunctor(_);
66724         return presetIcon;
66725     };
66726
66727
66728     presetIcon.geometry = function(_) {
66729         if (!arguments.length) return geometry;
66730         geometry = utilFunctor(_);
66731         return presetIcon;
66732     };
66733
66734     return presetIcon;
66735 }
66736
66737 function d3combobox() {
66738     var dispatch$$1 = dispatch('accept'),
66739         container = select(document.body),
66740         data = [],
66741         suggestions = [],
66742         minItems = 2,
66743         caseSensitive = false;
66744
66745     var fetcher = function(val, cb) {
66746         cb(data.filter(function(d) {
66747             return d.value
66748                 .toString()
66749                 .toLowerCase()
66750                 .indexOf(val.toLowerCase()) !== -1;
66751         }));
66752     };
66753
66754     var combobox = function(input, attachTo) {
66755         var idx = -1,
66756             wrapper = container
66757                 .selectAll('div.combobox')
66758                 .filter(function(d) { return d === input.node(); }),
66759             shown = !wrapper.empty();
66760
66761         input
66762             .classed('combobox-input', true)
66763             .on('focus.typeahead', focus)
66764             .on('blur.typeahead', blur)
66765             .on('keydown.typeahead', keydown)
66766             .on('keyup.typeahead', keyup)
66767             .on('input.typeahead', change)
66768             .each(function() {
66769                 var parent = this.parentNode,
66770                     sibling = this.nextSibling;
66771
66772                 var caret = select(parent).selectAll('.combobox-caret')
66773                     .filter(function(d) { return d === input.node(); })
66774                     .data([input.node()]);
66775
66776                 caret = caret.enter()
66777                   .insert('div', function() { return sibling; })
66778                     .attr('class', 'combobox-caret')
66779                   .merge(caret);
66780
66781                 caret
66782                     .on('mousedown', function () {
66783                         // prevent the form element from blurring. it blurs
66784                         // on mousedown
66785                         event.stopPropagation();
66786                         event.preventDefault();
66787                         if (!shown) {
66788                             input.node().focus();
66789                             fetch('', render);
66790                         } else {
66791                             hide();
66792                         }
66793                     });
66794             });
66795
66796         function focus() {
66797             fetch(value(), render);
66798         }
66799
66800         function blur() {
66801             window.setTimeout(hide, 150);
66802         }
66803
66804         function show() {
66805             if (!shown) {
66806                 wrapper = container
66807                     .insert('div', ':first-child')
66808                     .datum(input.node())
66809                     .attr('class', 'combobox')
66810                     .style('position', 'absolute')
66811                     .style('display', 'block')
66812                     .style('left', '0px')
66813                     .on('mousedown', function () {
66814                         // prevent moving focus out of the text field
66815                         event.preventDefault();
66816                     });
66817
66818                 select('body')
66819                     .on('scroll.combobox', render, true);
66820
66821                 shown = true;
66822             }
66823         }
66824
66825         function hide() {
66826             if (shown) {
66827                 idx = -1;
66828                 wrapper.remove();
66829
66830                 select('body')
66831                     .on('scroll.combobox', null);
66832
66833                 shown = false;
66834             }
66835         }
66836
66837         function keydown() {
66838            switch (event.keyCode) {
66839                // backspace, delete
66840                case 8:
66841                case 46:
66842                    input.on('input.typeahead', function() {
66843                        idx = -1;
66844                        render();
66845                        var start = input.property('selectionStart');
66846                        input.node().setSelectionRange(start, start);
66847                        input.on('input.typeahead', change);
66848                    });
66849                    break;
66850                // tab
66851                case 9:
66852                    wrapper.selectAll('a.selected').each(function (d) {
66853                        dispatch$$1.call('accept', this, d);
66854                    });
66855                    hide();
66856                    break;
66857                // return
66858                case 13:
66859                    event.preventDefault();
66860                    break;
66861                // up arrow
66862                case 38:
66863                    nav(-1);
66864                    event.preventDefault();
66865                    break;
66866                // down arrow
66867                case 40:
66868                    nav(+1);
66869                    event.preventDefault();
66870                    break;
66871            }
66872            event.stopPropagation();
66873         }
66874
66875         function keyup() {
66876             switch (event.keyCode) {
66877                 // escape
66878                 case 27:
66879                     hide();
66880                     break;
66881                 // return
66882                 case 13:
66883                     wrapper.selectAll('a.selected').each(function (d) {
66884                        dispatch$$1.call('accept', this, d);
66885                     });
66886                     hide();
66887                     break;
66888             }
66889         }
66890
66891         function change() {
66892             fetch(value(), function() {
66893                 if (input.property('selectionEnd') === input.property('value').length) {
66894                     autocomplete();
66895                 }
66896                 render();
66897             });
66898         }
66899
66900         function nav(dir) {
66901             if (!suggestions.length) return;
66902             idx = Math.max(Math.min(idx + dir, suggestions.length - 1), 0);
66903             input.property('value', suggestions[idx].value);
66904             render();
66905             ensureVisible();
66906         }
66907
66908         function value() {
66909             var value = input.property('value'),
66910                 start = input.property('selectionStart'),
66911                 end = input.property('selectionEnd');
66912
66913             if (start && end) {
66914                 value = value.substring(0, start);
66915             }
66916
66917             return value;
66918         }
66919
66920         function fetch(v, cb) {
66921             fetcher.call(input, v, function(_) {
66922                 suggestions = _;
66923                 cb();
66924             });
66925         }
66926
66927         function autocomplete() {
66928             var v = caseSensitive ? value() : value().toLowerCase();
66929             idx = -1;
66930             if (!v) return;
66931
66932             for (var i = 0; i < suggestions.length; i++) {
66933                 var suggestion = suggestions[i].value,
66934                     compare = caseSensitive ? suggestion : suggestion.toLowerCase();
66935
66936                 if (compare.indexOf(v) === 0) {
66937                     idx = i;
66938                     input.property('value', suggestion);
66939                     input.node().setSelectionRange(v.length, suggestion.length);
66940                     return;
66941                 }
66942             }
66943         }
66944
66945         function render() {
66946             if (suggestions.length >= minItems && document.activeElement === input.node()) {
66947                 show();
66948             } else {
66949                 hide();
66950                 return;
66951             }
66952
66953             var options = wrapper
66954                 .selectAll('a.combobox-option')
66955                 .data(suggestions, function(d) { return d.value; });
66956
66957             options.exit()
66958                 .remove();
66959
66960             options.enter()
66961                 .append('a')
66962                 .attr('class', 'combobox-option')
66963                 .text(function(d) { return d.value; })
66964                 .merge(options)
66965                 .attr('title', function(d) { return d.title; })
66966                 .classed('selected', function(d, i) { return i === idx; })
66967                 .on('mouseover', select$$1)
66968                 .on('click', accept)
66969                 .order();
66970
66971
66972             var node = attachTo ? attachTo.node() : input.node(),
66973                 rect = node.getBoundingClientRect();
66974
66975             wrapper
66976                 .style('left', rect.left + 'px')
66977                 .style('width', rect.width + 'px')
66978                 .style('top', rect.height + rect.top + 'px');
66979         }
66980
66981         function select$$1(d, i) {
66982             idx = i;
66983             render();
66984         }
66985
66986         function ensureVisible() {
66987             var node = wrapper.selectAll('a.selected').node();
66988             if (node) node.scrollIntoView();
66989         }
66990
66991         function accept(d) {
66992             if (!shown) return;
66993             input.property('value', d.value);
66994             utilTriggerEvent(input, 'change');
66995             dispatch$$1.call('accept', this, d);
66996             hide();
66997         }
66998     };
66999
67000     combobox.fetcher = function(_) {
67001         if (!arguments.length) return fetcher;
67002         fetcher = _;
67003         return combobox;
67004     };
67005
67006     combobox.data = function(_) {
67007         if (!arguments.length) return data;
67008         data = _;
67009         return combobox;
67010     };
67011
67012     combobox.minItems = function(_) {
67013         if (!arguments.length) return minItems;
67014         minItems = _;
67015         return combobox;
67016     };
67017
67018     combobox.caseSensitive = function(_) {
67019         if (!arguments.length) return caseSensitive;
67020         caseSensitive = _;
67021         return combobox;
67022     };
67023
67024     combobox.container = function(_) {
67025         if (!arguments.length) return container;
67026         container = _;
67027         return combobox;
67028     };
67029
67030     return utilRebind(combobox, dispatch$$1, 'on');
67031 }
67032
67033
67034 d3combobox.off = function(input) {
67035     input
67036         .on('focus.typeahead', null)
67037         .on('blur.typeahead', null)
67038         .on('keydown.typeahead', null)
67039         .on('keyup.typeahead', null)
67040         .on('input.typeahead', null)
67041         .each(function() {
67042             select(this.parentNode).selectAll('.combobox-caret')
67043                 .filter(function(d) { return d === input.node(); })
67044                 .on('mousedown', null);
67045         });
67046
67047     select('body')
67048         .on('scroll.combobox', null);
67049 };
67050
67051 function uiDisclosure() {
67052     var dispatch$$1 = dispatch('toggled'),
67053         title,
67054         expanded = false,
67055         content = function () {};
67056
67057
67058     var disclosure = function(selection$$1) {
67059         var hideToggle = selection$$1.selectAll('.hide-toggle')
67060             .data([0]);
67061
67062         hideToggle = hideToggle.enter()
67063             .append('a')
67064             .attr('href', '#')
67065             .attr('class', 'hide-toggle')
67066             .merge(hideToggle);
67067
67068         hideToggle
67069             .text(title)
67070             .on('click', toggle)
67071             .classed('expanded', expanded);
67072
67073
67074         var wrap = selection$$1.selectAll('div')
67075             .data([0]);
67076
67077         wrap = wrap.enter()
67078             .append('div')
67079             .merge(wrap);
67080
67081         wrap
67082             .classed('hide', !expanded)
67083             .call(content);
67084
67085
67086         function toggle() {
67087             expanded = !expanded;
67088             hideToggle.classed('expanded', expanded);
67089             wrap.call(uiToggle(expanded));
67090             dispatch$$1.call('toggled', this, expanded);
67091         }
67092     };
67093
67094
67095     disclosure.title = function(_) {
67096         if (!arguments.length) return title;
67097         title = _;
67098         return disclosure;
67099     };
67100
67101
67102     disclosure.expanded = function(_) {
67103         if (!arguments.length) return expanded;
67104         expanded = _;
67105         return disclosure;
67106     };
67107
67108
67109     disclosure.content = function(_) {
67110         if (!arguments.length) return content;
67111         content = _;
67112         return disclosure;
67113     };
67114
67115
67116     return utilRebind(disclosure, dispatch$$1, 'on');
67117 }
67118
67119 function uiRawMemberEditor(context) {
67120     var id,
67121         taginfo = services.taginfo;
67122
67123
67124     function selectMember(d) {
67125         event.preventDefault();
67126         context.enter(modeSelect(context, [d.id]));
67127     }
67128
67129
67130     function changeRole(d) {
67131         var role = select(this).property('value');
67132         var member = { id: d.id, type: d.type, role: role };
67133         context.perform(
67134             actionChangeMember(d.relation.id, member, d.index),
67135             t('operations.change_role.annotation')
67136         );
67137     }
67138
67139
67140     function deleteMember(d) {
67141         context.perform(
67142             actionDeleteMember(d.relation.id, d.index),
67143             t('operations.delete_member.annotation')
67144         );
67145
67146         if (!context.hasEntity(d.relation.id)) {
67147             context.enter(modeBrowse(context));
67148         }
67149     }
67150
67151
67152     function rawMemberEditor(selection$$1) {
67153         var entity = context.entity(id),
67154             memberships = [];
67155
67156         entity.members.slice(0, 1000).forEach(function(member, index) {
67157             memberships.push({
67158                 index: index,
67159                 id: member.id,
67160                 type: member.type,
67161                 role: member.role,
67162                 relation: entity,
67163                 member: context.hasEntity(member.id)
67164             });
67165         });
67166
67167         var gt = entity.members.length > 1000 ? '>' : '';
67168         selection$$1.call(uiDisclosure()
67169             .title(t('inspector.all_members') + ' (' + gt + memberships.length + ')')
67170             .expanded(true)
67171             .on('toggled', toggled)
67172             .content(content)
67173         );
67174
67175
67176         function toggled(expanded) {
67177             if (expanded) {
67178                 selection$$1.node().parentNode.scrollTop += 200;
67179             }
67180         }
67181
67182
67183         function content(wrap) {
67184             var list = wrap.selectAll('.member-list')
67185                 .data([0]);
67186
67187             list = list.enter()
67188                 .append('ul')
67189                 .attr('class', 'member-list')
67190                 .merge(list);
67191
67192
67193             var items = list.selectAll('li')
67194                 .data(memberships, function(d) {
67195                     return osmEntity$$1.key(d.relation) + ',' + d.index + ',' +
67196                         (d.member ? osmEntity$$1.key(d.member) : 'incomplete');
67197                 });
67198
67199             items.exit()
67200                 .each(unbind)
67201                 .remove();
67202
67203             var enter = items.enter()
67204                 .append('li')
67205                 .attr('class', 'member-row form-field')
67206                 .classed('member-incomplete', function(d) { return !d.member; });
67207
67208             enter
67209                 .each(function(d) {
67210                     if (d.member) {
67211                         var label = select(this).append('label')
67212                             .attr('class', 'form-label')
67213                             .append('a')
67214                             .attr('href', '#')
67215                             .on('click', selectMember);
67216
67217                         label.append('span')
67218                             .attr('class', 'member-entity-type')
67219                             .text(function(d) {
67220                                 var matched = context.presets().match(d.member, context.graph());
67221                                 return (matched && matched.name()) || utilDisplayType(d.member.id);
67222                             });
67223
67224                         label.append('span')
67225                             .attr('class', 'member-entity-name')
67226                             .text(function(d) { return utilDisplayName(d.member); });
67227
67228                     } else {
67229                         select(this).append('label')
67230                             .attr('class', 'form-label')
67231                             .text(t('inspector.incomplete', { id: d.id }));
67232                     }
67233                 });
67234
67235             enter
67236                 .append('input')
67237                 .attr('class', 'member-role')
67238                 .property('type', 'text')
67239                 .attr('maxlength', 255)
67240                 .attr('placeholder', t('inspector.role'))
67241                 .call(utilNoAuto)
67242                 .property('value', function(d) { return d.role; })
67243                 .on('change', changeRole);
67244
67245             enter
67246                 .append('button')
67247                 .attr('tabindex', -1)
67248                 .attr('class', 'remove button-input-action member-delete minor')
67249                 .on('click', deleteMember)
67250                 .call(svgIcon('#operation-delete'));
67251
67252             if (taginfo) {
67253                 enter.each(bindTypeahead);
67254             }
67255
67256
67257             function bindTypeahead(d) {
67258                 var row = select(this),
67259                     role = row.selectAll('input.member-role');
67260
67261                 function sort(value, data) {
67262                     var sameletter = [],
67263                         other = [];
67264                     for (var i = 0; i < data.length; i++) {
67265                         if (data[i].value.substring(0, value.length) === value) {
67266                             sameletter.push(data[i]);
67267                         } else {
67268                             other.push(data[i]);
67269                         }
67270                     }
67271                     return sameletter.concat(other);
67272                 }
67273
67274                 role.call(d3combobox()
67275                     .container(context.container())
67276                     .fetcher(function(role, callback) {
67277                         var rtype = entity.tags.type;
67278                         taginfo.roles({
67279                             debounce: true,
67280                             rtype: rtype || '',
67281                             geometry: context.geometry(d.member.id),
67282                             query: role
67283                         }, function(err, data) {
67284                             if (!err) callback(sort(role, data));
67285                         });
67286                     }));
67287             }
67288
67289
67290             function unbind() {
67291                 var row = select(this);
67292
67293                 row.selectAll('input.member-role')
67294                     .call(d3combobox.off);
67295             }
67296         }
67297     }
67298
67299
67300     rawMemberEditor.entityID = function(_) {
67301         if (!arguments.length) return id;
67302         id = _;
67303         return rawMemberEditor;
67304     };
67305
67306
67307     return rawMemberEditor;
67308 }
67309
67310 function uiRawMembershipEditor(context) {
67311     var taginfo = services.taginfo,
67312         id, showBlank;
67313
67314
67315     function selectRelation(d) {
67316         event.preventDefault();
67317         context.enter(modeSelect(context, [d.relation.id]));
67318     }
67319
67320
67321     function changeRole(d) {
67322         var role = select(this).property('value');
67323         context.perform(
67324             actionChangeMember(d.relation.id, lodash.extend({}, d.member, { role: role }), d.index),
67325             t('operations.change_role.annotation')
67326         );
67327     }
67328
67329
67330     function addMembership(d, role) {
67331         showBlank = false;
67332
67333         if (d.relation) {
67334             context.perform(
67335                 actionAddMember(d.relation.id, { id: id, type: context.entity(id).type, role: role }),
67336                 t('operations.add_member.annotation')
67337             );
67338
67339         } else {
67340             var relation = osmRelation();
67341             context.perform(
67342                 actionAddEntity(relation),
67343                 actionAddMember(relation.id, { id: id, type: context.entity(id).type, role: role }),
67344                 t('operations.add.annotation.relation')
67345             );
67346
67347             context.enter(modeSelect(context, [relation.id]));
67348         }
67349     }
67350
67351
67352     function deleteMembership(d) {
67353         context.perform(
67354             actionDeleteMember(d.relation.id, d.index),
67355             t('operations.delete_member.annotation')
67356         );
67357     }
67358
67359
67360     function relations(q) {
67361         var newRelation = {
67362                 relation: null,
67363                 value: t('inspector.new_relation')
67364             },
67365             result = [],
67366             graph = context.graph();
67367
67368         context.intersects(context.extent()).forEach(function(entity) {
67369             if (entity.type !== 'relation' || entity.id === id)
67370                 return;
67371
67372             var matched = context.presets().match(entity, graph),
67373                 presetName = (matched && matched.name()) || t('inspector.relation'),
67374                 entityName = utilDisplayName(entity) || '';
67375
67376             var value = presetName + ' ' + entityName;
67377             if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
67378                 return;
67379
67380             result.push({
67381                 relation: entity,
67382                 value: value
67383             });
67384         });
67385
67386         result.sort(function(a, b) {
67387             return osmRelation.creationOrder(a.relation, b.relation);
67388         });
67389
67390         // Dedupe identical names by appending relation id - see #2891
67391         var dupeGroups = lodash(result)
67392             .groupBy('value')
67393             .filter(function(v) { return v.length > 1; })
67394             .value();
67395
67396         dupeGroups.forEach(function(group) {
67397             group.forEach(function(obj) {
67398                 obj.value += ' ' + obj.relation.id;
67399             });
67400         });
67401
67402         result.unshift(newRelation);
67403         return result;
67404     }
67405
67406
67407     function rawMembershipEditor(selection$$1) {
67408         var entity = context.entity(id),
67409             parents = context.graph().parentRelations(entity),
67410             memberships = [];
67411
67412         parents.slice(0, 1000).forEach(function(relation) {
67413             relation.members.forEach(function(member, index) {
67414                 if (member.id === entity.id) {
67415                     memberships.push({ relation: relation, member: member, index: index });
67416                 }
67417             });
67418         });
67419
67420         var gt = parents.length > 1000 ? '>' : '';
67421         selection$$1.call(uiDisclosure()
67422             .title(t('inspector.all_relations') + ' (' + gt + memberships.length + ')')
67423             .expanded(true)
67424             .on('toggled', toggled)
67425             .content(content)
67426         );
67427
67428
67429         function toggled(expanded) {
67430             if (expanded) {
67431                 selection$$1.node().parentNode.scrollTop += 200;
67432             }
67433         }
67434
67435
67436         function content(wrap) {
67437             var list = wrap.selectAll('.member-list')
67438                 .data([0]);
67439
67440             list = list.enter()
67441                 .append('ul')
67442                 .attr('class', 'member-list')
67443                 .merge(list);
67444
67445
67446             var items = list.selectAll('li.member-row-normal')
67447                 .data(memberships, function(d) {
67448                     return osmEntity$$1.key(d.relation) + ',' + d.index;
67449                 });
67450
67451             items.exit()
67452                 .each(unbind)
67453                 .remove();
67454
67455             var enter = items.enter()
67456                 .append('li')
67457                 .attr('class', 'member-row member-row-normal form-field');
67458
67459             var label = enter
67460                 .append('label')
67461                 .attr('class', 'form-label')
67462                 .append('a')
67463                 .attr('href', '#')
67464                 .on('click', selectRelation);
67465
67466             label
67467                 .append('span')
67468                 .attr('class', 'member-entity-type')
67469                 .text(function(d) {
67470                     var matched = context.presets().match(d.relation, context.graph());
67471                     return (matched && matched.name()) || t('inspector.relation');
67472                 });
67473
67474             label
67475                 .append('span')
67476                 .attr('class', 'member-entity-name')
67477                 .text(function(d) { return utilDisplayName(d.relation); });
67478
67479             enter
67480                 .append('input')
67481                 .attr('class', 'member-role')
67482                 .property('type', 'text')
67483                 .attr('maxlength', 255)
67484                 .attr('placeholder', t('inspector.role'))
67485                 .call(utilNoAuto)
67486                 .property('value', function(d) { return d.member.role; })
67487                 .on('change', changeRole);
67488
67489             enter
67490                 .append('button')
67491                 .attr('tabindex', -1)
67492                 .attr('class', 'remove button-input-action member-delete minor')
67493                 .on('click', deleteMembership)
67494                 .call(svgIcon('#operation-delete'));
67495
67496             if (taginfo) {
67497                 enter.each(bindTypeahead);
67498             }
67499
67500
67501             var newrow = list.selectAll('.member-row-new')
67502                 .data(showBlank ? [0] : []);
67503
67504             newrow.exit()
67505                 .remove();
67506
67507             enter = newrow.enter()
67508                 .append('li')
67509                 .attr('class', 'member-row member-row-new form-field');
67510
67511             enter
67512                 .append('input')
67513                 .attr('type', 'text')
67514                 .attr('class', 'member-entity-input')
67515                 .call(utilNoAuto);
67516
67517             enter
67518                 .append('input')
67519                 .attr('class', 'member-role')
67520                 .property('type', 'text')
67521                 .attr('maxlength', 255)
67522                 .attr('placeholder', t('inspector.role'))
67523                 .call(utilNoAuto)
67524                 .on('change', changeRole);
67525
67526             enter
67527                 .append('button')
67528                 .attr('tabindex', -1)
67529                 .attr('class', 'remove button-input-action member-delete minor')
67530                 .on('click', deleteMembership)
67531                 .call(svgIcon('#operation-delete'));
67532
67533             newrow = newrow
67534                 .merge(enter);
67535
67536             newrow.selectAll('.member-entity-input')
67537                 .call(d3combobox()
67538                     .container(context.container())
67539                     .minItems(1)
67540                     .fetcher(function(value, callback) { callback(relations(value)); })
67541                     .on('accept', onAccept)
67542                 );
67543
67544
67545             var addrel = wrap.selectAll('.add-relation')
67546                 .data([0]);
67547
67548             addrel = addrel.enter()
67549                 .append('button')
67550                 .attr('class', 'add-relation')
67551                 .merge(addrel);
67552
67553             addrel
67554                 .call(svgIcon('#icon-plus', 'light'))
67555                 .on('click', function() {
67556                     showBlank = true;
67557                     content(wrap);
67558                     list.selectAll('.member-entity-input').node().focus();
67559                 });
67560
67561
67562             function onAccept(d) {
67563                 var role = list.selectAll('.member-row-new .member-role').property('value');
67564                 addMembership(d, role);
67565             }
67566
67567
67568             function bindTypeahead(d) {
67569                 var row = select(this),
67570                     role = row.selectAll('input.member-role');
67571
67572                 function sort(value, data) {
67573                     var sameletter = [],
67574                         other = [];
67575                     for (var i = 0; i < data.length; i++) {
67576                         if (data[i].value.substring(0, value.length) === value) {
67577                             sameletter.push(data[i]);
67578                         } else {
67579                             other.push(data[i]);
67580                         }
67581                     }
67582                     return sameletter.concat(other);
67583                 }
67584
67585                 role.call(d3combobox()
67586                     .container(context.container())
67587                     .fetcher(function(role, callback) {
67588                         var rtype = d.relation.tags.type;
67589                         taginfo.roles({
67590                             debounce: true,
67591                             rtype: rtype || '',
67592                             geometry: context.geometry(id),
67593                             query: role
67594                         }, function(err, data) {
67595                             if (!err) callback(sort(role, data));
67596                         });
67597                     }));
67598             }
67599
67600
67601             function unbind() {
67602                 var row = select(this);
67603
67604                 row.selectAll('input.member-role')
67605                     .call(d3combobox.off);
67606             }
67607         }
67608     }
67609
67610
67611     rawMembershipEditor.entityID = function(_) {
67612         if (!arguments.length) return id;
67613         id = _;
67614         return rawMembershipEditor;
67615     };
67616
67617
67618     return rawMembershipEditor;
67619 }
67620
67621 function uiTagReference(tag) {
67622     var taginfo = services.taginfo,
67623         tagReference = {},
67624         button,
67625         body,
67626         loaded,
67627         showing;
67628
67629
67630     function findLocal(data) {
67631         var locale = utilDetect().locale.toLowerCase(),
67632             localized;
67633
67634         if (locale !== 'pt-br') {  // see #3776, prefer 'pt' over 'pt-br'
67635             localized = lodash.find(data, function(d) {
67636                 return d.lang.toLowerCase() === locale;
67637             });
67638             if (localized) return localized;
67639         }
67640
67641         // try the non-regional version of a language, like
67642         // 'en' if the language is 'en-US'
67643         if (locale.indexOf('-') !== -1) {
67644             var first = locale.split('-')[0];
67645             localized = lodash.find(data, function(d) {
67646                 return d.lang.toLowerCase() === first;
67647             });
67648             if (localized) return localized;
67649         }
67650
67651         // finally fall back to english
67652         return lodash.find(data, function(d) {
67653             return d.lang.toLowerCase() === 'en';
67654         });
67655     }
67656
67657
67658     function load(param) {
67659         if (!taginfo) return;
67660
67661         button.classed('tag-reference-loading', true);
67662
67663         taginfo.docs(param, function show(err, data) {
67664             var docs;
67665             if (!err && data) {
67666                 docs = findLocal(data);
67667             }
67668
67669             body.html('');
67670
67671
67672             if (!docs || !docs.title) {
67673                 if (param.hasOwnProperty('value')) {
67674                     load(lodash.omit(param, 'value'));   // retry with key only
67675                 } else {
67676                     body.append('p').text(t('inspector.no_documentation_key'));
67677                     done();
67678                 }
67679                 return;
67680             }
67681
67682
67683             if (docs.image && docs.image.thumb_url_prefix) {
67684                 body
67685                     .append('img')
67686                     .attr('class', 'wiki-image')
67687                     .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
67688                     .on('load', function() { done(); })
67689                     .on('error', function() { select(this).remove(); done(); });
67690             } else {
67691                 done();
67692             }
67693
67694             body
67695                 .append('p')
67696                 .text(docs.description || t('inspector.documentation_redirect'));
67697
67698             body
67699                 .append('a')
67700                 .attr('target', '_blank')
67701                 .attr('tabindex', -1)
67702                 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
67703                 .call(svgIcon('#icon-out-link', 'inline'))
67704                 .append('span')
67705                 .text(t('inspector.reference'));
67706         });
67707     }
67708
67709
67710     function done() {
67711         loaded = true;
67712
67713         button.classed('tag-reference-loading', false);
67714
67715         body.transition()
67716             .duration(200)
67717             .style('max-height', '200px')
67718             .style('opacity', '1');
67719
67720         showing = true;
67721     }
67722
67723
67724     function hide(selection$$1) {
67725         selection$$1 = selection$$1 || body.transition().duration(200);
67726
67727         selection$$1
67728             .style('max-height', '0px')
67729             .style('opacity', '0');
67730
67731         showing = false;
67732     }
67733
67734
67735     tagReference.button = function(selection$$1) {
67736         button = selection$$1.selectAll('.tag-reference-button')
67737             .data([0]);
67738
67739         button = button.enter()
67740             .append('button')
67741             .attr('class', 'tag-reference-button')
67742             .attr('tabindex', -1)
67743             .call(svgIcon('#icon-inspect'))
67744             .merge(button);
67745
67746         button
67747             .on('click', function () {
67748                 event.stopPropagation();
67749                 event.preventDefault();
67750                 if (showing) {
67751                     hide();
67752                 } else if (loaded) {
67753                     done();
67754                 } else {
67755                     load(tag);
67756                 }
67757             });
67758     };
67759
67760
67761     tagReference.body = function(selection$$1) {
67762         body = selection$$1.selectAll('.tag-reference-body')
67763             .data([0]);
67764
67765         body = body.enter()
67766             .append('div')
67767             .attr('class', 'tag-reference-body cf')
67768             .style('max-height', '0')
67769             .style('opacity', '0')
67770             .merge(body);
67771
67772         if (showing === false) {
67773             hide(body);
67774         }
67775     };
67776
67777
67778     tagReference.showing = function(_) {
67779         if (!arguments.length) return showing;
67780         showing = _;
67781         return tagReference;
67782     };
67783
67784
67785     return tagReference;
67786 }
67787
67788 function uiRawTagEditor(context) {
67789     var taginfo = services.taginfo,
67790         dispatch$$1 = dispatch('change'),
67791         expanded = context.storage('raw_tag_editor.expanded') === 'true',
67792         readOnlyTags = [],
67793         updatePreference = true,
67794         showBlank = false,
67795         newRow,
67796         state,
67797         preset,
67798         tags,
67799         id;
67800
67801
67802     function rawTagEditor(selection$$1) {
67803         var count = Object.keys(tags).filter(function(d) { return d; }).length;
67804
67805         selection$$1.call(uiDisclosure()
67806             .title(t('inspector.all_tags') + ' (' + count + ')')
67807             .expanded(expanded)
67808             .on('toggled', toggled)
67809             .content(content)
67810         );
67811
67812         function toggled(expanded) {
67813             if (updatePreference) {
67814                 context.storage('raw_tag_editor.expanded', expanded);
67815             }
67816             if (expanded) {
67817                 selection$$1.node().parentNode.scrollTop += 200;
67818             }
67819         }
67820     }
67821
67822
67823     function content(wrap) {
67824         var entries$$1 = entries(tags);
67825
67826         if (!entries$$1.length || showBlank) {
67827             showBlank = false;
67828             entries$$1.push({key: '', value: ''});
67829             newRow = '';
67830         }
67831
67832         var list = wrap.selectAll('.tag-list')
67833             .data([0]);
67834
67835         list = list.enter()
67836             .append('ul')
67837             .attr('class', 'tag-list')
67838             .merge(list);
67839
67840         var newTag = wrap.selectAll('.add-tag')
67841             .data([0]);
67842
67843         newTag.enter()
67844             .append('button')
67845             .attr('class', 'add-tag')
67846             .on('click', addTag)
67847             .call(svgIcon('#icon-plus', 'light'));
67848
67849
67850         var items = list.selectAll('.tag-row')
67851             .data(entries$$1, function(d) { return d.key; });
67852
67853         items.exit()
67854             .each(unbind)
67855             .remove();
67856
67857         // Enter
67858
67859         var enter = items.enter()
67860             .append('li')
67861             .attr('class', 'tag-row cf')
67862             .classed('readonly', isReadOnly);
67863
67864         enter
67865             .append('div')
67866             .attr('class', 'key-wrap')
67867             .append('input')
67868             .property('type', 'text')
67869             .attr('class', 'key')
67870             .attr('maxlength', 255)
67871             .call(utilNoAuto)
67872             .on('blur', keyChange)
67873             .on('change', keyChange);
67874
67875         enter
67876             .append('div')
67877             .attr('class', 'input-wrap-position')
67878             .append('input')
67879             .property('type', 'text')
67880             .attr('class', 'value')
67881             .attr('maxlength', 255)
67882             .call(utilNoAuto)
67883             .on('blur', valueChange)
67884             .on('change', valueChange)
67885             .on('keydown.push-more', pushMore);
67886
67887         enter
67888             .append('button')
67889             .attr('tabindex', -1)
67890             .attr('class', 'remove minor')
67891             .call(svgIcon('#operation-delete'));
67892
67893
67894         // Update
67895
67896         items = items
67897             .merge(enter)
67898             .sort(function(a, b) {
67899                 return (a.key === newRow && b.key !== newRow) ? 1
67900                     : (a.key !== newRow && b.key === newRow) ? -1
67901                     : ascending(a.key, b.key);
67902             });
67903
67904         items
67905             .each(function(tag) {
67906                 var row = select(this),
67907                     key = row.select('input.key'),      // propagate bound data to child
67908                     value = row.select('input.value');  // propagate bound data to child
67909
67910                 if (id && taginfo) {
67911                     bindTypeahead(key, value);
67912                 }
67913
67914                 var isRelation = (id && context.entity(id).type === 'relation'),
67915                     reference;
67916
67917                 if (isRelation && tag.key === 'type') {
67918                     reference = uiTagReference({ rtype: tag.value }, context);
67919                 } else {
67920                     reference = uiTagReference({ key: tag.key, value: tag.value }, context);
67921                 }
67922
67923                 if (state === 'hover') {
67924                     reference.showing(false);
67925                 }
67926
67927                 row
67928                     .call(reference.button)
67929                     .call(reference.body);
67930             });
67931
67932         items.selectAll('input.key')
67933             .attr('title', function(d) { return d.key; })
67934             .call(utilGetSetValue, function(d) { return d.key; })
67935             .property('disabled', isReadOnly);
67936
67937         items.selectAll('input.value')
67938             .attr('title', function(d) { return d.value; })
67939             .call(utilGetSetValue, function(d) { return d.value; })
67940             .property('disabled', isReadOnly);
67941
67942         items.selectAll('button.remove')
67943             .on('click', removeTag);
67944
67945
67946
67947         function isReadOnly(d) {
67948             return readOnlyTags.indexOf(d.key) !== -1;
67949         }
67950
67951
67952         function pushMore() {
67953             if (event.keyCode === 9 && !event.shiftKey &&
67954                 list.selectAll('li:last-child input.value').node() === this) {
67955                 addTag();
67956             }
67957         }
67958
67959
67960         function bindTypeahead(key, value) {
67961             if (isReadOnly({ key: key })) return;
67962             var geometry = context.geometry(id);
67963
67964             key.call(d3combobox()
67965                 .container(context.container())
67966                 .fetcher(function(value, callback) {
67967                     taginfo.keys({
67968                         debounce: true,
67969                         geometry: geometry,
67970                         query: value
67971                     }, function(err, data) {
67972                         if (!err) callback(sort(value, data));
67973                     });
67974                 }));
67975
67976             value.call(d3combobox()
67977                 .container(context.container())
67978                 .fetcher(function(value, callback) {
67979                     taginfo.values({
67980                         debounce: true,
67981                         key: utilGetSetValue(key),
67982                         geometry: geometry,
67983                         query: value
67984                     }, function(err, data) {
67985                         if (!err) callback(sort(value, data));
67986                     });
67987                 }));
67988
67989
67990             function sort(value, data) {
67991                 var sameletter = [],
67992                     other = [];
67993                 for (var i = 0; i < data.length; i++) {
67994                     if (data[i].value.substring(0, value.length) === value) {
67995                         sameletter.push(data[i]);
67996                     } else {
67997                         other.push(data[i]);
67998                     }
67999                 }
68000                 return sameletter.concat(other);
68001             }
68002         }
68003
68004
68005         function unbind() {
68006             var row = select(this);
68007
68008             row.selectAll('input.key')
68009                 .call(d3combobox.off);
68010
68011             row.selectAll('input.value')
68012                 .call(d3combobox.off);
68013         }
68014
68015
68016         function keyChange(d) {
68017             var kOld = d.key,
68018                 kNew = this.value.trim(),
68019                 tag = {};
68020
68021
68022             if (isReadOnly({ key: kNew })) {
68023                 this.value = kOld;
68024                 return;
68025             }
68026
68027             if (kNew && kNew !== kOld) {
68028                 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
68029                     base = match[1],
68030                     suffix = +(match[2] || 1);
68031                 while (tags[kNew]) {  // rename key if already in use
68032                     kNew = base + '_' + suffix++;
68033                 }
68034             }
68035             tag[kOld] = undefined;
68036             tag[kNew] = d.value;
68037
68038             d.key = kNew; // Maintain DOM identity through the subsequent update.
68039
68040             if (newRow === kOld) {  // see if this row is still a new row
68041                 newRow = ((d.value === '' || kNew === '') ? kNew : undefined);
68042             }
68043
68044             this.value = kNew;
68045             dispatch$$1.call('change', this, tag);
68046         }
68047
68048
68049         function valueChange(d) {
68050             if (isReadOnly(d)) return;
68051             var tag = {};
68052             tag[d.key] = this.value;
68053
68054             if (newRow === d.key && d.key !== '' && d.value !== '') {   // not a new row anymore
68055                 newRow = undefined;
68056             }
68057
68058             dispatch$$1.call('change', this, tag);
68059         }
68060
68061
68062         function removeTag(d) {
68063             if (isReadOnly(d)) return;
68064             var tag = {};
68065             tag[d.key] = undefined;
68066             dispatch$$1.call('change', this, tag);
68067             select(this.parentNode).remove();
68068         }
68069
68070
68071         function addTag() {
68072             // Wrapped in a setTimeout in case it's being called from a blur
68073             // handler. Without the setTimeout, the call to `content` would
68074             // wipe out the pending value change.
68075             setTimeout(function() {
68076                 showBlank = true;
68077                 content(wrap);
68078                 list.selectAll('li:last-child input.key').node().focus();
68079             }, 0);
68080         }
68081     }
68082
68083
68084     rawTagEditor.state = function(_) {
68085         if (!arguments.length) return state;
68086         state = _;
68087         return rawTagEditor;
68088     };
68089
68090
68091     rawTagEditor.preset = function(_) {
68092         if (!arguments.length) return preset;
68093         preset = _;
68094         if (preset.isFallback()) {
68095             expanded = true;
68096             updatePreference = false;
68097         } else {
68098             expanded = context.storage('raw_tag_editor.expanded') === 'true';
68099             updatePreference = true;
68100         }
68101         return rawTagEditor;
68102     };
68103
68104
68105     rawTagEditor.tags = function(_) {
68106         if (!arguments.length) return tags;
68107         tags = _;
68108         return rawTagEditor;
68109     };
68110
68111
68112     rawTagEditor.entityID = function(_) {
68113         if (!arguments.length) return id;
68114         id = _;
68115         return rawTagEditor;
68116     };
68117
68118
68119     rawTagEditor.expanded = function(_) {
68120         if (!arguments.length) return expanded;
68121         expanded = _;
68122         updatePreference = false;
68123         return rawTagEditor;
68124     };
68125
68126
68127     rawTagEditor.readOnlyTags = function(_) {
68128         if (!arguments.length) return readOnlyTags;
68129         readOnlyTags = _;
68130         return rawTagEditor;
68131     };
68132
68133
68134     return utilRebind(rawTagEditor, dispatch$$1, 'on');
68135 }
68136
68137 function uiFieldCheck(field, context) {
68138     var dispatch$$1 = dispatch('change'),
68139         options = field.strings && field.strings.options,
68140         values$$1 = [],
68141         texts = [],
68142         input = select(null),
68143         text$$1 = select(null),
68144         label = select(null),
68145         reverser = select(null),
68146         impliedYes,
68147         entityId,
68148         value;
68149
68150
68151     if (options) {
68152         for (var k in options) {
68153             values$$1.push(k === 'undefined' ? undefined : k);
68154             texts.push(field.t('options.' + k, { 'default': options[k] }));
68155         }
68156     } else {
68157         values$$1 = [undefined, 'yes'];
68158         texts = [t('inspector.unknown'), t('inspector.check.yes')];
68159         if (field.type !== 'defaultCheck') {
68160             values$$1.push('no');
68161             texts.push(t('inspector.check.no'));
68162         }
68163     }
68164
68165
68166     // Checks tags to see whether an undefined value is "Assumed to be Yes"
68167     function checkImpliedYes() {
68168         impliedYes = (field.id === 'oneway_yes');
68169
68170         // hack: pretend `oneway` field is a `oneway_yes` field
68171         // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
68172         if (field.id === 'oneway') {
68173             var entity = context.entity(entityId);
68174             for (var key in entity.tags) {
68175                 if (key in osmOneWayTags && (entity.tags[key] in osmOneWayTags[key])) {
68176                     impliedYes = true;
68177                     texts[0] = t('presets.fields.oneway_yes.options.undefined');
68178                     break;
68179                 }
68180             }
68181         }
68182     }
68183
68184
68185     function reverserHidden() {
68186         if (!select('div.inspector-hover').empty()) return true;
68187         return !(value === 'yes' || (impliedYes && !value));
68188     }
68189
68190
68191     function reverserSetText(selection$$1) {
68192         var entity = context.hasEntity(entityId);
68193         if (reverserHidden() || !entity) return selection$$1;
68194
68195         var first = entity.first(),
68196             last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last(),
68197             pseudoDirection = first < last,
68198             icon = pseudoDirection ? '#icon-forward' : '#icon-backward';
68199
68200         selection$$1.selectAll('.reverser-span')
68201             .text(t('inspector.check.reverser'))
68202             .call(svgIcon(icon, 'inline'));
68203
68204         return selection$$1;
68205     }
68206
68207
68208     var check = function(selection$$1) {
68209         checkImpliedYes();
68210         selection$$1.classed('checkselect', 'true');
68211
68212         label = selection$$1.selectAll('.preset-input-wrap')
68213             .data([0]);
68214
68215         var enter = label.enter()
68216             .append('label')
68217             .attr('class', 'preset-input-wrap');
68218
68219         enter
68220             .append('input')
68221             .property('indeterminate', field.type !== 'defaultCheck')
68222             .attr('type', 'checkbox')
68223             .attr('id', 'preset-input-' + field.id);
68224
68225         enter
68226             .append('span')
68227             .text(texts[0])
68228             .attr('class', 'value');
68229
68230         if (field.type === 'onewayCheck') {
68231             enter
68232                 .append('a')
68233                 .attr('id', 'preset-input-' + field.id + '-reverser')
68234                 .attr('class', 'reverser button' + (reverserHidden() ? ' hide' : ''))
68235                 .attr('href', '#')
68236                 .append('span')
68237                 .attr('class', 'reverser-span');
68238         }
68239
68240         label = label.merge(enter);
68241         input = label.selectAll('input');
68242         text$$1 = label.selectAll('span.value');
68243
68244         input
68245             .on('click', function() {
68246                 var t$$1 = {};
68247                 t$$1[field.key] = values$$1[(values$$1.indexOf(value) + 1) % values$$1.length];
68248                 dispatch$$1.call('change', this, t$$1);
68249                 event.stopPropagation();
68250             });
68251
68252         if (field.type === 'onewayCheck') {
68253             reverser = label.selectAll('.reverser');
68254
68255             reverser
68256                 .call(reverserSetText)
68257                 .on('click', function() {
68258                     event.preventDefault();
68259                     event.stopPropagation();
68260                     context.perform(
68261                         actionReverse(entityId),
68262                         t('operations.reverse.annotation')
68263                     );
68264                     select(this)
68265                         .call(reverserSetText);
68266                 });
68267         }
68268     };
68269
68270
68271     check.entity = function(_) {
68272         if (!arguments.length) return context.hasEntity(entityId);
68273         entityId = _.id;
68274         return check;
68275     };
68276
68277
68278     check.tags = function(tags) {
68279         checkImpliedYes();
68280         value = tags[field.key] && tags[field.key].toLowerCase();
68281
68282         if (field.type === 'onewayCheck' && (value === '1' || value === '-1')) {
68283             value = 'yes';
68284         }
68285
68286         input
68287             .property('indeterminate', field.type !== 'defaultCheck' && !value)
68288             .property('checked', value === 'yes');
68289
68290         text$$1
68291             .text(texts[values$$1.indexOf(value)]);
68292
68293         label
68294             .classed('set', !!value);
68295
68296         if (field.type === 'onewayCheck') {
68297             reverser
68298                 .classed('hide', reverserHidden())
68299                 .call(reverserSetText);
68300         }
68301     };
68302
68303
68304     check.focus = function() {
68305         input.node().focus();
68306     };
68307
68308     return utilRebind(check, dispatch$$1, 'on');
68309 }
68310
68311 function uiFieldCombo(field, context) {
68312     var dispatch$$1 = dispatch('change'),
68313         nominatim = services.geocoder,
68314         taginfo = services.taginfo,
68315         isMulti = (field.type === 'multiCombo'),
68316         isNetwork = (field.type === 'networkCombo'),
68317         isSemi = (field.type === 'semiCombo'),
68318         optstrings = field.strings && field.strings.options,
68319         optarray = field.options,
68320         snake_case = (field.snake_case || (field.snake_case === undefined)),
68321         combobox = d3combobox()
68322             .container(context.container())
68323             .minItems(isMulti || isSemi ? 1 : 2),
68324         comboData = [],
68325         multiData = [],
68326         container,
68327         input,
68328         entity,
68329         country;
68330
68331     // ensure multiCombo field.key ends with a ':'
68332     if (isMulti && field.key.match(/:$/) === null) {
68333         field.key += ':';
68334     }
68335
68336
68337     function snake(s) {
68338         return s.replace(/\s+/g, '_');
68339     }
68340
68341     function unsnake(s) {
68342         return s.replace(/_+/g, ' ');
68343     }
68344
68345     function clean(s) {
68346         return s.split(';')
68347             .map(function(s) { return s.trim(); })
68348             .join(';');
68349     }
68350
68351
68352     // returns the tag value for a display value
68353     // (for multiCombo, dval should be the key suffix, not the entire key)
68354     function tagValue(dval) {
68355         dval = clean(dval || '');
68356
68357         if (optstrings) {
68358             var match = lodash.find(comboData, function(o) {
68359                 return o.key && clean(o.value) === dval;
68360             });
68361             if (match) {
68362                 return match.key;
68363             }
68364         }
68365
68366         if (field.type === 'typeCombo' && !dval) {
68367             return 'yes';
68368         }
68369
68370         return (snake_case ? snake(dval) : dval) || undefined;
68371     }
68372
68373
68374     // returns the display value for a tag value
68375     // (for multiCombo, tval should be the key suffix, not the entire key)
68376     function displayValue(tval) {
68377         tval = tval || '';
68378
68379         if (optstrings) {
68380             var match = lodash.find(comboData, function(o) { return o.key === tval && o.value; });
68381             if (match) {
68382                 return match.value;
68383             }
68384         }
68385
68386         if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
68387             return '';
68388         }
68389
68390         return snake_case ? unsnake(tval) : tval;
68391     }
68392
68393
68394     function objectDifference(a, b) {
68395         return lodash.reject(a, function(d1) {
68396             return lodash.some(b, function(d2) { return d1.value === d2.value; });
68397         });
68398     }
68399
68400
68401     function initCombo(selection$$1, attachTo) {
68402         if (optstrings) {
68403             selection$$1.attr('readonly', 'readonly');
68404             selection$$1.call(combobox, attachTo);
68405             setStaticValues(setPlaceholder);
68406
68407         } else if (optarray) {
68408             selection$$1.call(combobox, attachTo);
68409             setStaticValues(setPlaceholder);
68410
68411         } else if (taginfo) {
68412             selection$$1.call(combobox.fetcher(setTaginfoValues), attachTo);
68413             setTaginfoValues('', setPlaceholder);
68414         }
68415     }
68416
68417
68418     function setStaticValues(callback) {
68419         if (!(optstrings || optarray)) return;
68420
68421         if (optstrings) {
68422             comboData = Object.keys(optstrings).map(function(k) {
68423                 var v = field.t('options.' + k, { 'default': optstrings[k] });
68424                 return {
68425                     key: k,
68426                     value: v,
68427                     title: v
68428                 };
68429             });
68430
68431         } else if (optarray) {
68432             comboData = optarray.map(function(k) {
68433                 var v = snake_case ? unsnake(k) : k;
68434                 return {
68435                     key: k,
68436                     value: v,
68437                     title: v
68438                 };
68439             });
68440         }
68441
68442         combobox.data(objectDifference(comboData, multiData));
68443         if (callback) callback(comboData);
68444     }
68445
68446
68447     function setTaginfoValues(q, callback) {
68448         var fn = isMulti ? 'multikeys' : 'values';
68449         var query = (isMulti ? field.key : '') + q;
68450         var hasCountryPrefix = isNetwork && country && country.indexOf(q.toLowerCase()) === 0;
68451         if (hasCountryPrefix) {
68452             query = country + ':';
68453         }
68454
68455         taginfo[fn]({
68456             debounce: (q !== ''),
68457             key: field.key,
68458             geometry: context.geometry(entity.id),
68459             query: query
68460         }, function(err, data) {
68461             if (err) return;
68462             if (hasCountryPrefix) {
68463                 data = lodash.filter(data, function(d) {
68464                     return d.value.toLowerCase().indexOf(country + ':') === 0;
68465                 });
68466             }
68467
68468             comboData = lodash.map(data, function(d) {
68469                 var k = d.value;
68470                 if (isMulti) k = k.replace(field.key, '');
68471                 var v = snake_case ? unsnake(k) : k;
68472                 return {
68473                     key: k,
68474                     value: v,
68475                     title: isMulti ? v : d.title
68476                 };
68477             });
68478
68479             comboData = objectDifference(comboData, multiData);
68480             if (callback) callback(comboData);
68481         });
68482     }
68483
68484
68485     function setPlaceholder(d) {
68486         var ph;
68487
68488         if (isMulti || isSemi) {
68489             ph = field.placeholder() || t('inspector.add');
68490         } else {
68491             var vals = lodash.map(d, 'value').filter(function(s) { return s.length < 20; }),
68492                 placeholders = vals.length > 1 ? vals : lodash.map(d, 'key');
68493             ph = field.placeholder() || placeholders.slice(0, 3).join(', ');
68494         }
68495
68496         if (ph.match(/(…|\.\.\.)$/) === null) {
68497             ph += '…';
68498         }
68499
68500         container.selectAll('input')
68501             .attr('placeholder', ph);
68502     }
68503
68504
68505     function change() {
68506         var val = tagValue(utilGetSetValue(input)),
68507             t$$1 = {};
68508
68509         if (isMulti || isSemi) {
68510             if (!val) return;
68511             container.classed('active', false);
68512             utilGetSetValue(input, '');
68513             if (isMulti) {
68514                 field.keys.push(field.key + val);
68515                 t$$1[field.key + val] = 'yes';
68516             } else if (isSemi) {
68517                 var arr = multiData.map(function(d) { return d.key; });
68518                 arr.push(val);
68519                 t$$1[field.key] = lodash.compact(lodash.uniq(arr)).join(';');
68520             }
68521             window.setTimeout(function() { input.node().focus(); }, 10);
68522
68523         } else {
68524             t$$1[field.key] = val;
68525         }
68526
68527         dispatch$$1.call('change', this, t$$1);
68528     }
68529
68530
68531     function removeMultikey(d) {
68532         event.stopPropagation();
68533         var t$$1 = {};
68534         if (isMulti) {
68535             t$$1[d.key] = undefined;
68536         } else if (isSemi) {
68537             lodash.remove(multiData, function(md) { return md.key === d.key; });
68538             var arr = multiData.map(function(md) { return md.key; });
68539             arr = lodash.compact(lodash.uniq(arr));
68540             t$$1[field.key] = arr.length ? arr.join(';') : undefined;
68541         }
68542         dispatch$$1.call('change', this, t$$1);
68543     }
68544
68545
68546     function combo(selection$$1) {
68547         if (isMulti || isSemi) {
68548             container = selection$$1.selectAll('ul').data([0]);
68549
68550             container = container.enter()
68551                 .append('ul')
68552                 .attr('class', 'form-field-multicombo')
68553                 .on('click', function() {
68554                     window.setTimeout(function() { input.node().focus(); }, 10);
68555                 })
68556                 .merge(container);
68557
68558         } else {
68559             container = selection$$1;
68560         }
68561
68562         input = container.selectAll('input')
68563             .data([0]);
68564
68565         input = input.enter()
68566             .append('input')
68567             .attr('type', 'text')
68568             .attr('id', 'preset-input-' + field.id)
68569             .call(utilNoAuto)
68570             .call(initCombo, selection$$1)
68571             .merge(input);
68572
68573         if (isNetwork && nominatim && entity) {
68574             var center = entity.extent(context.graph()).center();
68575             nominatim.countryCode(center, function (err, code) {
68576                 country = code;
68577             });
68578         }
68579
68580         input
68581             .on('change', change)
68582             .on('blur', change);
68583
68584         if (isMulti || isSemi) {
68585             combobox
68586                 .on('accept', function() {
68587                     input.node().blur();
68588                     input.node().focus();
68589                 });
68590
68591             input
68592                 .on('focus', function() { container.classed('active', true); });
68593         }
68594     }
68595
68596
68597     combo.tags = function(tags) {
68598         if (isMulti || isSemi) {
68599             multiData = [];
68600
68601             if (isMulti) {
68602                 // Build multiData array containing keys already set..
68603                 Object.keys(tags).forEach(function(key) {
68604                     if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return;
68605
68606                     var suffix = key.substring(field.key.length);
68607                     multiData.push({
68608                         key: key,
68609                         value: displayValue(suffix)
68610                     });
68611                 });
68612
68613                 // Set keys for form-field modified (needed for undo and reset buttons)..
68614                 field.keys = lodash.map(multiData, 'key');
68615
68616             } else if (isSemi) {
68617                 var arr = lodash.compact(lodash.uniq((tags[field.key] || '').split(';')));
68618                 multiData = arr.map(function(key) {
68619                     return {
68620                         key: key,
68621                         value: displayValue(key)
68622                     };
68623                 });
68624             }
68625
68626             // Exclude existing multikeys from combo options..
68627             var available = objectDifference(comboData, multiData);
68628             combobox.data(available);
68629
68630             // Hide 'Add' button if this field uses fixed set of
68631             // translateable optstrings and they're all currently used..
68632             container.selectAll('.combobox-input, .combobox-caret')
68633                 .classed('hide', optstrings && !available.length);
68634
68635
68636             // Render chips
68637             var chips = container.selectAll('.chips')
68638                 .data(multiData);
68639
68640             chips.exit()
68641                 .remove();
68642
68643             var enter = chips.enter()
68644                 .insert('li', 'input')
68645                 .attr('class', 'chips');
68646
68647             enter.append('span');
68648             enter.append('a');
68649
68650             chips = chips.merge(enter);
68651
68652             chips.select('span')
68653                 .text(function(d) { return d.value; });
68654
68655             chips.select('a')
68656                 .on('click', removeMultikey)
68657                 .attr('class', 'remove')
68658                 .text('×');
68659
68660         } else {
68661             utilGetSetValue(input, displayValue(tags[field.key]));
68662         }
68663     };
68664
68665
68666     combo.focus = function() {
68667         input.node().focus();
68668     };
68669
68670
68671     combo.entity = function(_) {
68672         if (!arguments.length) return entity;
68673         entity = _;
68674         return combo;
68675     };
68676
68677
68678     return utilRebind(combo, dispatch$$1, 'on');
68679 }
68680
68681 function uiFieldText(field, context) {
68682     var dispatch$$1 = dispatch('change'),
68683         nominatim = services.geocoder,
68684         input,
68685         entity;
68686
68687
68688     function i(selection$$1) {
68689         var fieldId = 'preset-input-' + field.id;
68690
68691         input = selection$$1.selectAll('input')
68692             .data([0]);
68693
68694         input = input.enter()
68695             .append('input')
68696             .attr('type', field.type)
68697             .attr('id', fieldId)
68698             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
68699             .call(utilNoAuto)
68700             .merge(input);
68701
68702         input
68703             .on('input', change(true))
68704             .on('blur', change())
68705             .on('change', change());
68706
68707         if (field.type === 'tel' && nominatim && entity) {
68708             var center = entity.extent(context.graph()).center();
68709             nominatim.countryCode(center, function (err, countryCode) {
68710                 if (err || !dataPhoneFormats[countryCode]) return;
68711                 selection$$1.selectAll('#' + fieldId)
68712                     .attr('placeholder', dataPhoneFormats[countryCode]);
68713             });
68714
68715         } else if (field.type === 'number') {
68716             input.attr('type', 'text');
68717
68718             var spinControl = selection$$1.selectAll('.spin-control')
68719                 .data([0]);
68720
68721             var enter = spinControl.enter()
68722                 .append('div')
68723                 .attr('class', 'spin-control');
68724
68725             enter
68726                 .append('button')
68727                 .datum(-1)
68728                 .attr('class', 'decrement')
68729                 .attr('tabindex', -1);
68730
68731             enter
68732                 .append('button')
68733                 .datum(1)
68734                 .attr('class', 'increment')
68735                 .attr('tabindex', -1);
68736
68737             spinControl = spinControl
68738                 .merge(enter);
68739
68740             spinControl.selectAll('button')
68741                 .on('click', function(d) {
68742                     event.preventDefault();
68743                     var num = parseInt(input.node().value || 0, 10);
68744                     if (!isNaN(num)) input.node().value = num + d;
68745                     change()();
68746                 });
68747         }
68748     }
68749
68750
68751     function change(onInput) {
68752         return function() {
68753             var t$$1 = {};
68754             t$$1[field.key] = utilGetSetValue(input) || undefined;
68755             dispatch$$1.call('change', this, t$$1, onInput);
68756         };
68757     }
68758
68759
68760     i.entity = function(_) {
68761         if (!arguments.length) return entity;
68762         entity = _;
68763         return i;
68764     };
68765
68766
68767     i.tags = function(tags) {
68768         utilGetSetValue(input, tags[field.key] || '');
68769     };
68770
68771
68772     i.focus = function() {
68773         var node = input.node();
68774         if (node) node.focus();
68775     };
68776
68777     return utilRebind(i, dispatch$$1, 'on');
68778 }
68779
68780 function uiFieldAccess(field, context) {
68781     var dispatch$$1 = dispatch('change'),
68782         items;
68783
68784     function access(selection$$1) {
68785         var wrap = selection$$1.selectAll('.preset-input-wrap')
68786             .data([0]);
68787
68788         wrap = wrap.enter()
68789             .append('div')
68790             .attr('class', 'cf preset-input-wrap')
68791             .append('ul')
68792             .merge(wrap);
68793
68794         var list = wrap.selectAll('ul')
68795             .data([0]);
68796
68797         list = list.enter()
68798             .append('ul')
68799             .merge(list);
68800
68801
68802         items = list.selectAll('li')
68803             .data(field.keys);
68804
68805         // Enter
68806         var enter = items.enter()
68807             .append('li')
68808             .attr('class', function(d) { return 'cf preset-access-' + d; });
68809
68810         enter
68811             .append('span')
68812             .attr('class', 'col6 label preset-label-access')
68813             .attr('for', function(d) { return 'preset-input-access-' + d; })
68814             .text(function(d) { return field.t('types.' + d); });
68815
68816         enter
68817             .append('div')
68818             .attr('class', 'col6 preset-input-access-wrap')
68819             .append('input')
68820             .attr('type', 'text')
68821             .attr('class', 'preset-input-access')
68822             .attr('id', function(d) { return 'preset-input-access-' + d; })
68823             .call(utilNoAuto)
68824             .each(function(d) {
68825                 select(this)
68826                     .call(d3combobox()
68827                         .container(context.container())
68828                         .data(access.options(d))
68829                     );
68830             });
68831
68832
68833         // Update
68834         items = items.merge(enter);
68835
68836         wrap.selectAll('.preset-input-access')
68837             .on('change', change)
68838             .on('blur', change);
68839     }
68840
68841
68842     function change(d) {
68843         var tag = {};
68844         tag[d] = utilGetSetValue(select(this)) || undefined;
68845         dispatch$$1.call('change', this, tag);
68846     }
68847
68848
68849     access.options = function(type) {
68850         var options = ['no', 'permissive', 'private', 'destination'];
68851
68852         if (type !== 'access') {
68853             options.unshift('yes');
68854             options.push('designated');
68855
68856             if (type === 'bicycle') {
68857                 options.push('dismount');
68858             }
68859         }
68860
68861         return options.map(function(option) {
68862             return {
68863                 title: field.t('options.' + option + '.description'),
68864                 value: option
68865             };
68866         });
68867     };
68868
68869
68870     var placeholders = {
68871         footway: {
68872             foot: 'designated',
68873             motor_vehicle: 'no'
68874         },
68875         steps: {
68876             foot: 'yes',
68877             motor_vehicle: 'no',
68878             bicycle: 'no',
68879             horse: 'no'
68880         },
68881         pedestrian: {
68882             foot: 'yes',
68883             motor_vehicle: 'no'
68884         },
68885         cycleway: {
68886             motor_vehicle: 'no',
68887             bicycle: 'designated'
68888         },
68889         bridleway: {
68890             motor_vehicle: 'no',
68891             horse: 'designated'
68892         },
68893         path: {
68894             foot: 'yes',
68895             motor_vehicle: 'no',
68896             bicycle: 'yes',
68897             horse: 'yes'
68898         },
68899         motorway: {
68900             foot: 'no',
68901             motor_vehicle: 'yes',
68902             bicycle: 'no',
68903             horse: 'no'
68904         },
68905         trunk: {
68906             motor_vehicle: 'yes'
68907         },
68908         primary: {
68909             foot: 'yes',
68910             motor_vehicle: 'yes',
68911             bicycle: 'yes',
68912             horse: 'yes'
68913         },
68914         secondary: {
68915             foot: 'yes',
68916             motor_vehicle: 'yes',
68917             bicycle: 'yes',
68918             horse: 'yes'
68919         },
68920         tertiary: {
68921             foot: 'yes',
68922             motor_vehicle: 'yes',
68923             bicycle: 'yes',
68924             horse: 'yes'
68925         },
68926         residential: {
68927             foot: 'yes',
68928             motor_vehicle: 'yes',
68929             bicycle: 'yes',
68930             horse: 'yes'
68931         },
68932         unclassified: {
68933             foot: 'yes',
68934             motor_vehicle: 'yes',
68935             bicycle: 'yes',
68936             horse: 'yes'
68937         },
68938         service: {
68939             foot: 'yes',
68940             motor_vehicle: 'yes',
68941             bicycle: 'yes',
68942             horse: 'yes'
68943         },
68944         motorway_link: {
68945             foot: 'no',
68946             motor_vehicle: 'yes',
68947             bicycle: 'no',
68948             horse: 'no'
68949         },
68950         trunk_link: {
68951             motor_vehicle: 'yes'
68952         },
68953         primary_link: {
68954             foot: 'yes',
68955             motor_vehicle: 'yes',
68956             bicycle: 'yes',
68957             horse: 'yes'
68958         },
68959         secondary_link: {
68960             foot: 'yes',
68961             motor_vehicle: 'yes',
68962             bicycle: 'yes',
68963             horse: 'yes'
68964         },
68965         tertiary_link: {
68966             foot: 'yes',
68967             motor_vehicle: 'yes',
68968             bicycle: 'yes',
68969             horse: 'yes'
68970         }
68971     };
68972
68973
68974     access.tags = function(tags) {
68975         utilGetSetValue(items.selectAll('.preset-input-access'),
68976             function(d) { return tags[d] || ''; })
68977             .attr('placeholder', function() {
68978                 return tags.access ? tags.access : field.placeholder();
68979             });
68980
68981         items.selectAll('#preset-input-access-access')
68982             .attr('placeholder', 'yes');
68983
68984         lodash.forEach(placeholders[tags.highway], function(v, k) {
68985             items.selectAll('#preset-input-access-' + k)
68986                 .attr('placeholder', function() { return (tags.access || v); });
68987         });
68988     };
68989
68990
68991     access.focus = function() {
68992         items.selectAll('.preset-input-access')
68993             .node().focus();
68994     };
68995
68996
68997     return utilRebind(access, dispatch$$1, 'on');
68998 }
68999
69000 function uiFieldAddress(field, context) {
69001     var dispatch$$1 = dispatch('init', 'change'),
69002         nominatim = services.geocoder,
69003         wrap = select(null),
69004         isInitialized = false,
69005         entity;
69006
69007     function getNearStreets() {
69008         var extent$$1 = entity.extent(context.graph()),
69009             l = extent$$1.center(),
69010             box = geoExtent$$1(l).padByMeters(200);
69011
69012         var streets = context.intersects(box)
69013             .filter(isAddressable)
69014             .map(function(d) {
69015                 var loc = context.projection([
69016                     (extent$$1[0][0] + extent$$1[1][0]) / 2,
69017                     (extent$$1[0][1] + extent$$1[1][1]) / 2]),
69018                     choice = geoChooseEdge(context.childNodes(d), loc, context.projection);
69019                 return {
69020                     title: d.tags.name,
69021                     value: d.tags.name,
69022                     dist: choice.distance
69023                 };
69024             })
69025             .sort(function(a, b) {
69026                 return a.dist - b.dist;
69027             });
69028
69029         return lodash.uniqBy(streets, 'value');
69030
69031         function isAddressable(d) {
69032             return d.tags.highway && d.tags.name && d.type === 'way';
69033         }
69034     }
69035
69036
69037     function getNearCities() {
69038         var extent$$1 = entity.extent(context.graph()),
69039             l = extent$$1.center(),
69040             box = geoExtent$$1(l).padByMeters(200);
69041
69042         var cities = context.intersects(box)
69043             .filter(isAddressable)
69044             .map(function(d) {
69045                 return {
69046                     title: d.tags['addr:city'] || d.tags.name,
69047                     value: d.tags['addr:city'] || d.tags.name,
69048                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
69049                 };
69050             })
69051             .sort(function(a, b) {
69052                 return a.dist - b.dist;
69053             });
69054
69055         return lodash.uniqBy(cities, 'value');
69056
69057
69058         function isAddressable(d) {
69059             if (d.tags.name &&
69060                 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
69061                 return true;
69062
69063             if (d.tags.place && d.tags.name && (
69064                     d.tags.place === 'city' ||
69065                     d.tags.place === 'town' ||
69066                     d.tags.place === 'village'))
69067                 return true;
69068
69069             if (d.tags['addr:city']) return true;
69070
69071             return false;
69072         }
69073     }
69074
69075     function getNearValues(key) {
69076         var extent$$1 = entity.extent(context.graph()),
69077             l = extent$$1.center(),
69078             box = geoExtent$$1(l).padByMeters(200);
69079
69080         var results = context.intersects(box)
69081             .filter(function hasTag(d) {
69082                 return d.tags[key];
69083             })
69084             .map(function(d) {
69085                 return {
69086                     title: d.tags[key],
69087                     value: d.tags[key],
69088                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
69089                 };
69090             })
69091             .sort(function(a, b) {
69092                 return a.dist - b.dist;
69093             });
69094
69095         return lodash.uniqBy(results, 'value');
69096     }
69097
69098
69099     function initCallback(err, countryCode) {
69100         if (err) return;
69101
69102         var addressFormat = lodash.find(dataAddressFormats, function (a) {
69103             return a && a.countryCodes && lodash.includes(a.countryCodes, countryCode.toLowerCase());
69104         }) || lodash.first(dataAddressFormats);
69105
69106         var widths = addressFormat.widths || {
69107             housenumber: 1/3, street: 2/3,
69108             city: 2/3, state: 1/4, postcode: 1/3
69109         };
69110
69111         function row(r) {
69112             // Normalize widths.
69113             var total = lodash.reduce(r, function(sum$$1, field) {
69114                 return sum$$1 + (widths[field] || 0.5);
69115             }, 0);
69116
69117             return r.map(function (field) {
69118                 return {
69119                     id: field,
69120                     width: (widths[field] || 0.5) / total
69121                 };
69122             });
69123         }
69124
69125         wrap.selectAll('div.addr-row')
69126             .data(addressFormat.format)
69127             .enter()
69128             .append('div')
69129             .attr('class', 'addr-row')
69130             .selectAll('input')
69131             .data(row)
69132             .enter()
69133             .append('input')
69134             .property('type', 'text')
69135             .attr('placeholder', function (d) {
69136                 var localkey = d.id + '!' + countryCode.toLowerCase(),
69137                     tkey = field.strings.placeholders[localkey] ? localkey : d.id;
69138                 return field.t('placeholders.' + tkey);
69139             })
69140             .attr('class', function (d) { return 'addr-' + d.id; })
69141             .call(utilNoAuto)
69142             .style('width', function (d) { return d.width * 100 + '%'; });
69143
69144         // Update
69145
69146         // setup dropdowns for common address tags
69147         var dropdowns = addressFormat.dropdowns || [
69148             'city', 'county', 'country', 'district', 'hamlet',
69149             'neighbourhood', 'place', 'postcode', 'province',
69150             'quarter', 'state', 'street', 'subdistrict', 'suburb'
69151         ];
69152
69153         // If fields exist for any of these tags, create dropdowns to pick nearby values..
69154         dropdowns.forEach(function(tag) {
69155             var nearValues = (tag === 'street') ? getNearStreets
69156                     : (tag === 'city') ? getNearCities
69157                     : getNearValues;
69158
69159             wrap.selectAll('input.addr-' + tag)
69160                 .call(d3combobox()
69161                     .container(context.container())
69162                     .minItems(1)
69163                     .fetcher(function(value, callback) {
69164                         callback(nearValues('addr:' + tag));
69165                     })
69166                 );
69167         });
69168
69169         wrap.selectAll('input')
69170             .on('blur', change())
69171             .on('change', change());
69172
69173         wrap.selectAll('input:not(.combobox-input)')
69174             .on('input', change(true));
69175
69176         dispatch$$1.call('init');
69177         isInitialized = true;
69178     }
69179
69180
69181     function address(selection$$1) {
69182         isInitialized = false;
69183
69184         wrap = selection$$1.selectAll('.preset-input-wrap')
69185             .data([0]);
69186
69187         wrap = wrap.enter()
69188             .append('div')
69189             .attr('class', 'preset-input-wrap')
69190             .merge(wrap);
69191
69192         if (nominatim && entity) {
69193             var center = entity.extent(context.graph()).center();
69194             nominatim.countryCode(center, initCallback);
69195         }
69196     }
69197
69198
69199     function change(onInput) {
69200         return function() {
69201             var tags = {};
69202
69203             wrap.selectAll('input')
69204                 .each(function (field) {
69205                     tags['addr:' + field.id] = this.value || undefined;
69206                 });
69207
69208             dispatch$$1.call('change', this, tags, onInput);
69209         };
69210     }
69211
69212
69213     function updateTags(tags) {
69214         utilGetSetValue(wrap.selectAll('input'), function (field) {
69215             return tags['addr:' + field.id] || '';
69216         });
69217     }
69218
69219
69220     address.entity = function(_) {
69221         if (!arguments.length) return entity;
69222         entity = _;
69223         return address;
69224     };
69225
69226
69227     address.tags = function(tags) {
69228         if (isInitialized) {
69229             updateTags(tags);
69230         } else {
69231             dispatch$$1.on('init', function () {
69232                 dispatch$$1.on('init', null);
69233                 updateTags(tags);
69234             });
69235         }
69236     };
69237
69238
69239     address.focus = function() {
69240         var node = wrap.selectAll('input').node();
69241         if (node) node.focus();
69242     };
69243
69244
69245     return utilRebind(address, dispatch$$1, 'on');
69246 }
69247
69248 function uiFieldCycleway(field, context) {
69249     var dispatch$$1 = dispatch('change'),
69250         items = select(null);
69251
69252
69253     function cycleway(selection$$1) {
69254
69255         function stripcolon(s) {
69256             return s.replace(':', '');
69257         }
69258
69259
69260         var wrap = selection$$1.selectAll('.preset-input-wrap')
69261             .data([0]);
69262
69263         wrap = wrap.enter()
69264             .append('div')
69265             .attr('class', 'cf preset-input-wrap')
69266             .merge(wrap);
69267
69268
69269         var div = wrap.selectAll('ul')
69270             .data([0]);
69271
69272         div = div.enter()
69273             .append('ul')
69274             .merge(div);
69275
69276
69277         items = div.selectAll('li')
69278             .data(field.keys);
69279
69280         var enter = items.enter()
69281             .append('li')
69282             .attr('class', function(d) { return 'cf preset-cycleway-' + stripcolon(d); });
69283
69284         enter
69285             .append('span')
69286             .attr('class', 'col6 label preset-label-cycleway')
69287             .attr('for', function(d) { return 'preset-input-cycleway-' + stripcolon(d); })
69288             .text(function(d) { return field.t('types.' + d); });
69289
69290         enter
69291             .append('div')
69292             .attr('class', 'col6 preset-input-cycleway-wrap')
69293             .append('input')
69294             .attr('type', 'text')
69295             .attr('class', function(d) { return 'preset-input-cycleway preset-input-' + stripcolon(d); })
69296             .call(utilNoAuto)
69297             .each(function(d) {
69298                 select(this)
69299                     .call(d3combobox()
69300                         .container(context.container())
69301                         .data(cycleway.options(d))
69302                     );
69303             });
69304
69305
69306         // Update
69307         wrap.selectAll('.preset-input-cycleway')
69308             .on('change', change)
69309             .on('blur', change);
69310     }
69311
69312
69313     function change() {
69314         var left = utilGetSetValue(select('.preset-input-cyclewayleft')),
69315             right = utilGetSetValue(select('.preset-input-cyclewayright')),
69316             tag = {};
69317
69318         if (left === 'none' || left === '') { left = undefined; }
69319         if (right === 'none' || right === '') { right = undefined; }
69320
69321         // Always set both left and right as changing one can affect the other
69322         tag = {
69323             cycleway: undefined,
69324             'cycleway:left': left,
69325             'cycleway:right': right
69326         };
69327
69328         // If the left and right tags match, use the cycleway tag to tag both
69329         // sides the same way
69330         if (left === right) {
69331             tag = {
69332                 cycleway: left,
69333                 'cycleway:left': undefined,
69334                 'cycleway:right': undefined
69335             };
69336         }
69337
69338         dispatch$$1.call('change', this, tag);
69339     }
69340
69341
69342     cycleway.options = function() {
69343         return keys(field.strings.options).map(function(option) {
69344             return {
69345                 title: field.t('options.' + option + '.description'),
69346                 value: option
69347             };
69348         });
69349     };
69350
69351
69352     cycleway.tags = function(tags) {
69353         utilGetSetValue(items.selectAll('.preset-input-cycleway'), function(d) {
69354                 // If cycleway is set, always return that
69355                 if (tags.cycleway) {
69356                     return tags.cycleway;
69357                 }
69358                 return tags[d] || '';
69359             })
69360             .attr('placeholder', field.placeholder());
69361     };
69362
69363
69364     cycleway.focus = function() {
69365         items.selectAll('.preset-input-cycleway')
69366             .node().focus();
69367     };
69368
69369
69370     return utilRebind(cycleway, dispatch$$1, 'on');
69371 }
69372
69373 function uiFieldLanes(field, context) {
69374     var dispatch$$1 = dispatch('change'),
69375         LANE_WIDTH = 40,
69376         LANE_HEIGHT = 200,
69377         wayID,
69378         lanesData;
69379
69380     function lanes(selection$$1) {
69381         lanesData = context.entity(wayID).lanes();
69382
69383         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
69384             selection$$1.call(lanes.off);
69385             return;
69386         }
69387
69388         var wrap = selection$$1.selectAll('.preset-input-wrap')
69389             .data([0]);
69390
69391         wrap = wrap.enter()
69392             .append('div')
69393             .attr('class', 'preset-input-wrap')
69394             .merge(wrap);
69395
69396         var surface =  wrap.selectAll('.surface')
69397             .data([0]);
69398
69399         var d = utilGetDimensions(wrap);
69400         var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
69401
69402         surface = surface.enter()
69403             .append('svg')
69404             .attr('width', d[0])
69405             .attr('height', 300)
69406             .attr('class', 'surface')
69407             .merge(surface);
69408
69409
69410         var lanesSelection = surface.selectAll('.lanes')
69411             .data([0]);
69412
69413         lanesSelection = lanesSelection.enter()
69414             .append('g')
69415             .attr('class', 'lanes')
69416             .merge(lanesSelection);
69417
69418         lanesSelection
69419             .attr('transform', function () {
69420                 return 'translate(' + (freeSpace / 2) + ', 0)';
69421             });
69422
69423
69424         var lane = lanesSelection.selectAll('.lane')
69425            .data(lanesData.lanes);
69426
69427         lane.exit()
69428             .remove();
69429
69430         var enter = lane.enter()
69431             .append('g')
69432             .attr('class', 'lane');
69433
69434         enter
69435             .append('g')
69436             .append('rect')
69437             .attr('y', 50)
69438             .attr('width', LANE_WIDTH)
69439             .attr('height', LANE_HEIGHT);
69440
69441         enter
69442             .append('g')
69443             .attr('class', 'forward')
69444             .append('text')
69445             .attr('y', 40)
69446             .attr('x', 14)
69447             .text('▲');
69448
69449         enter
69450             .append('g')
69451             .attr('class', 'bothways')
69452             .append('text')
69453             .attr('y', 40)
69454             .attr('x', 14)
69455             .text('▲▼');
69456
69457         enter
69458             .append('g')
69459             .attr('class', 'backward')
69460             .append('text')
69461             .attr('y', 40)
69462             .attr('x', 14)
69463             .text('▼');
69464
69465
69466         lane = lane
69467             .merge(enter);
69468
69469         lane
69470             .attr('transform', function(d) {
69471                 return 'translate(' + (LANE_WIDTH * d.index * 1.5) + ', 0)';
69472             });
69473
69474         lane.select('.forward')
69475             .style('visibility', function(d) {
69476                 return d.direction === 'forward' ? 'visible' : 'hidden';
69477             });
69478
69479         lane.select('.bothways')
69480             .style('visibility', function(d) {
69481                 return d.direction === 'bothways' ? 'visible' : 'hidden';
69482             });
69483
69484         lane.select('.backward')
69485             .style('visibility', function(d) {
69486                 return d.direction === 'backward' ? 'visible' : 'hidden';
69487             });
69488     }
69489
69490
69491     lanes.entity = function(_) {
69492         if (!wayID || wayID !== _.id) {
69493             wayID = _.id;
69494         }
69495     };
69496
69497     lanes.tags = function() {};
69498     lanes.focus = function() {};
69499     lanes.off = function() {};
69500
69501     return utilRebind(lanes, dispatch$$1, 'on');
69502 }
69503
69504 function uiFieldLocalized(field, context) {
69505     var dispatch$$1 = dispatch('change', 'input'),
69506         wikipedia = services.wikipedia,
69507         input = select(null),
69508         localizedInputs = select(null),
69509         wikiTitles,
69510         entity;
69511
69512
69513     function localized(selection$$1) {
69514         input = selection$$1.selectAll('.localized-main')
69515             .data([0]);
69516
69517         input = input.enter()
69518             .append('input')
69519             .attr('type', 'text')
69520             .attr('id', 'preset-input-' + field.id)
69521             .attr('class', 'localized-main')
69522             .attr('placeholder', field.placeholder())
69523             .call(utilNoAuto)
69524             .merge(input);
69525
69526         if (field.id === 'name') {
69527             var preset = context.presets().match(entity, context.graph());
69528             input
69529                 .call(d3combobox()
69530                     .container(context.container())
69531                     .fetcher(utilSuggestNames(preset, dataSuggestions))
69532                 );
69533         }
69534
69535         input
69536             .on('input', change(true))
69537             .on('blur', change())
69538             .on('change', change());
69539
69540
69541         var translateButton = selection$$1.selectAll('.localized-add')
69542             .data([0]);
69543
69544         translateButton = translateButton.enter()
69545             .append('button')
69546             .attr('class', 'button-input-action localized-add minor')
69547             .attr('tabindex', -1)
69548             .call(svgIcon('#icon-plus'))
69549             .call(tooltip()
69550                 .title(t('translate.translate'))
69551                 .placement('left'))
69552             .merge(translateButton);
69553
69554         translateButton
69555             .on('click', addNew);
69556
69557
69558         localizedInputs = selection$$1.selectAll('.localized-wrap')
69559             .data([0]);
69560
69561         localizedInputs = localizedInputs.enter().append('div')
69562             .attr('class', 'localized-wrap')
69563             .merge(localizedInputs);
69564     }
69565
69566
69567     function addNew() {
69568         event.preventDefault();
69569         var data$$1 = localizedInputs.selectAll('div.entry').data();
69570         var defaultLang = utilDetect().locale.toLowerCase().split('-')[0];
69571         var langExists = lodash.find(data$$1, function(datum) { return datum.lang === defaultLang;});
69572         var isLangEn = defaultLang.indexOf('en') > -1;
69573         if (isLangEn || langExists) {
69574             defaultLang = '';
69575         }
69576         data$$1.push({ lang: defaultLang, value: '' });
69577         localizedInputs.call(render, data$$1);
69578     }
69579
69580
69581     function change(onInput) {
69582         return function() {
69583             var t$$1 = {};
69584             t$$1[field.key] = utilGetSetValue(select(this)) || undefined;
69585             dispatch$$1.call('change', this, t$$1, onInput);
69586         };
69587     }
69588
69589
69590     function key(lang) {
69591         return field.key + ':' + lang;
69592     }
69593
69594
69595     function changeLang(d) {
69596         var lang = utilGetSetValue(select(this)),
69597             t$$1 = {},
69598             language = lodash.find(dataWikipedia, function(d) {
69599                 return d[0].toLowerCase() === lang.toLowerCase() ||
69600                     d[1].toLowerCase() === lang.toLowerCase();
69601             });
69602
69603         if (language) lang = language[2];
69604
69605         if (d.lang && d.lang !== lang) {
69606             t$$1[key(d.lang)] = undefined;
69607         }
69608
69609         var value = utilGetSetValue(select(this.parentNode)
69610             .selectAll('.localized-value'));
69611
69612         if (lang && value) {
69613             t$$1[key(lang)] = value;
69614         } else if (lang && wikiTitles && wikiTitles[d.lang]) {
69615             t$$1[key(lang)] = wikiTitles[d.lang];
69616         }
69617
69618         d.lang = lang;
69619         dispatch$$1.call('change', this, t$$1);
69620     }
69621
69622
69623     function changeValue(d) {
69624         if (!d.lang) return;
69625         var t$$1 = {};
69626         t$$1[key(d.lang)] = utilGetSetValue(select(this)) || undefined;
69627         dispatch$$1.call('change', this, t$$1);
69628     }
69629
69630
69631     function fetcher(value, cb) {
69632         var v = value.toLowerCase();
69633
69634         cb(dataWikipedia.filter(function(d) {
69635             return d[0].toLowerCase().indexOf(v) >= 0 ||
69636             d[1].toLowerCase().indexOf(v) >= 0 ||
69637             d[2].toLowerCase().indexOf(v) >= 0;
69638         }).map(function(d) {
69639             return { value: d[1] };
69640         }));
69641     }
69642
69643
69644     function render(selection$$1, data$$1) {
69645         var wraps = selection$$1.selectAll('div.entry').
69646             data(data$$1, function(d) { return d.lang; });
69647
69648         wraps.exit()
69649             .transition()
69650             .duration(200)
69651             .style('max-height','0px')
69652             .style('opacity', '0')
69653             .style('top','-10px')
69654             .remove();
69655
69656         var innerWrap = wraps.enter()
69657             .insert('div', ':first-child');
69658
69659         innerWrap.attr('class', 'entry')
69660             .each(function() {
69661                 var wrap = select(this);
69662                 var langcombo = d3combobox()
69663                     .container(context.container())
69664                     .fetcher(fetcher)
69665                     .minItems(0);
69666
69667                 var label = wrap
69668                     .append('label')
69669                     .attr('class','form-label')
69670                     .text(t('translate.localized_translation_label'))
69671                     .attr('for','localized-lang');
69672
69673                 label
69674                     .append('button')
69675                     .attr('class', 'minor remove')
69676                     .on('click', function(d){
69677                         event.preventDefault();
69678                         var t$$1 = {};
69679                         t$$1[key(d.lang)] = undefined;
69680                         dispatch$$1.call('change', this, t$$1);
69681                         select(this.parentNode.parentNode)
69682                             .style('top','0')
69683                             .style('max-height','240px')
69684                             .transition()
69685                             .style('opacity', '0')
69686                             .style('max-height','0px')
69687                             .remove();
69688                     })
69689                     .call(svgIcon('#operation-delete'));
69690
69691                 wrap
69692                     .append('input')
69693                     .attr('class', 'localized-lang')
69694                     .attr('type', 'text')
69695                     .attr('placeholder',t('translate.localized_translation_language'))
69696                     .on('blur', changeLang)
69697                     .on('change', changeLang)
69698                     .call(langcombo);
69699
69700                 wrap
69701                     .append('input')
69702                     .on('blur', changeValue)
69703                     .on('change', changeValue)
69704                     .attr('type', 'text')
69705                     .attr('placeholder', t('translate.localized_translation_name'))
69706                     .attr('class', 'localized-value');
69707             });
69708
69709         innerWrap
69710             .style('margin-top', '0px')
69711             .style('max-height', '0px')
69712             .style('opacity', '0')
69713             .transition()
69714             .duration(200)
69715             .style('margin-top', '10px')
69716             .style('max-height', '240px')
69717             .style('opacity', '1')
69718             .on('end', function() {
69719                 select(this)
69720                     .style('max-height', '')
69721                     .style('overflow', 'visible');
69722             });
69723
69724
69725         var entry = selection$$1.selectAll('.entry');
69726
69727         utilGetSetValue(entry.select('.localized-lang'), function(d) {
69728                 var lang = lodash.find(dataWikipedia, function(lang) { return lang[2] === d.lang; });
69729                 return lang ? lang[1] : d.lang;
69730             });
69731
69732         utilGetSetValue(entry.select('.localized-value'),
69733             function(d) { return d.value; });
69734     }
69735
69736
69737     localized.tags = function(tags) {
69738         // Fetch translations from wikipedia
69739         if (tags.wikipedia && !wikiTitles) {
69740             wikiTitles = {};
69741             var wm = tags.wikipedia.match(/([^:]+):(.+)/);
69742             if (wm && wm[0] && wm[1]) {
69743                 wikipedia.translations(wm[1], wm[2], function(d) {
69744                     wikiTitles = d;
69745                 });
69746             }
69747         }
69748
69749         utilGetSetValue(input, tags[field.key] || '');
69750
69751         var postfixed = [], k, m;
69752         for (k in tags) {
69753             m = k.match(/^(.*):([a-zA-Z_-]+)$/);
69754             if (m && m[1] === field.key && m[2]) {
69755                 postfixed.push({ lang: m[2], value: tags[k] });
69756             }
69757         }
69758
69759         localizedInputs.call(render, postfixed.reverse());
69760     };
69761
69762
69763     localized.focus = function() {
69764         input.node().focus();
69765     };
69766
69767
69768     localized.entity = function(_) {
69769         if (!arguments.length) return entity;
69770         entity = _;
69771         return localized;
69772     };
69773
69774     return utilRebind(localized, dispatch$$1, 'on');
69775 }
69776
69777 function uiFieldMaxspeed(field, context) {
69778     var dispatch$$1 = dispatch('change'),
69779         entity,
69780         isImperial,
69781         unitInput = select(null),
69782         input = select(null),
69783         combobox;
69784
69785     var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
69786         imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
69787
69788
69789     function maxspeed(selection$$1) {
69790         combobox = d3combobox()
69791             .container(context.container());
69792
69793         var unitCombobox = d3combobox()
69794             .container(context.container())
69795             .data(['km/h', 'mph'].map(comboValues));
69796
69797         input = selection$$1.selectAll('#preset-input-' + field.id)
69798             .data([0]);
69799
69800         input = input.enter()
69801             .append('input')
69802             .attr('type', 'text')
69803             .attr('id', 'preset-input-' + field.id)
69804             .attr('placeholder', field.placeholder())
69805             .call(utilNoAuto)
69806             .call(combobox)
69807             .merge(input);
69808
69809         input
69810             .on('change', change)
69811             .on('blur', change);
69812
69813         var childNodes = context.graph().childNodes(context.entity(entity.id)),
69814             loc = childNodes[~~(childNodes.length/2)].loc;
69815
69816         isImperial = lodash.some(dataImperial.features, function(f) {
69817             return lodash.some(f.geometry.coordinates, function(d) {
69818                 return geoPointInPolygon(loc, d);
69819             });
69820         });
69821
69822         unitInput = selection$$1.selectAll('input.maxspeed-unit')
69823             .data([0]);
69824
69825         unitInput = unitInput.enter()
69826             .append('input')
69827             .attr('type', 'text')
69828             .attr('class', 'maxspeed-unit')
69829             .call(unitCombobox)
69830             .merge(unitInput);
69831
69832         unitInput
69833             .on('blur', changeUnits)
69834             .on('change', changeUnits);
69835
69836
69837         function changeUnits() {
69838             isImperial = utilGetSetValue(unitInput) === 'mph';
69839             utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
69840             setSuggestions();
69841             change();
69842         }
69843     }
69844
69845
69846     function setSuggestions() {
69847         combobox.data((isImperial ? imperialValues : metricValues).map(comboValues));
69848         utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
69849     }
69850
69851
69852     function comboValues(d) {
69853         return {
69854             value: d.toString(),
69855             title: d.toString()
69856         };
69857     }
69858
69859
69860     function change() {
69861         var tag = {},
69862             value = utilGetSetValue(input);
69863
69864         if (!value) {
69865             tag[field.key] = undefined;
69866         } else if (isNaN(value) || !isImperial) {
69867             tag[field.key] = value;
69868         } else {
69869             tag[field.key] = value + ' mph';
69870         }
69871
69872         dispatch$$1.call('change', this, tag);
69873     }
69874
69875
69876     maxspeed.tags = function(tags) {
69877         var value = tags[field.key];
69878
69879         if (value && value.indexOf('mph') >= 0) {
69880             value = parseInt(value, 10);
69881             isImperial = true;
69882         } else if (value) {
69883             isImperial = false;
69884         }
69885
69886         setSuggestions();
69887         utilGetSetValue(input, value || '');
69888     };
69889
69890
69891     maxspeed.focus = function() {
69892         input.node().focus();
69893     };
69894
69895
69896     maxspeed.entity = function(_) {
69897         entity = _;
69898     };
69899
69900
69901     return utilRebind(maxspeed, dispatch$$1, 'on');
69902 }
69903
69904 function uiFieldRadio(field, context) {
69905     var dispatch$$1 = dispatch('change'),
69906         taginfo = services.taginfo,
69907         placeholder = select(null),
69908         wrap = select(null),
69909         labels = select(null),
69910         radios = select(null),
69911         typeInput = select(null),
69912         layerInput = select(null),
69913         oldType = {},
69914         entity;
69915
69916
69917     function selectedKey() {
69918         var selector$$1 = '.form-field-structure .toggle-list label.active input',
69919             node = selectAll(selector$$1);
69920         return !node.empty() && node.datum();
69921     }
69922
69923     // returns the tag value for a display value
69924     function tagValue(dispVal) {
69925         dispVal = snake(clean(dispVal || ''));
69926         return dispVal.toLowerCase() || 'yes';
69927     }
69928
69929     // returns the display value for a tag value
69930     function displayValue(tagVal) {
69931         tagVal = tagVal || '';
69932         return tagVal.toLowerCase() === 'yes' ? '' : unsnake(tagVal);
69933     }
69934
69935     function snake(s) {
69936         return s.replace(/\s+/g, '_');
69937     }
69938
69939     function unsnake(s) {
69940         return s.replace(/_+/g, ' ');
69941     }
69942
69943     function clean(s) {
69944         return s.split(';')
69945             .map(function(s) { return s.trim(); })
69946             .join(';');
69947     }
69948
69949
69950     function radio(selection$$1) {
69951         selection$$1.classed('preset-radio', true);
69952
69953         wrap = selection$$1.selectAll('.preset-input-wrap')
69954             .data([0]);
69955
69956         var enter = wrap.enter()
69957             .append('div')
69958             .attr('class', 'preset-input-wrap toggle-list');
69959
69960         enter
69961             .append('span')
69962             .attr('class', 'placeholder');
69963
69964         wrap = wrap
69965             .merge(enter);
69966
69967
69968         placeholder = wrap.selectAll('.placeholder');
69969
69970         labels = wrap.selectAll('label')
69971             .data(field.options || field.keys);
69972
69973         enter = labels.enter()
69974             .append('label');
69975
69976         enter
69977             .append('input')
69978             .attr('type', 'radio')
69979             .attr('name', field.id)
69980             .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
69981             .attr('checked', false);
69982
69983         enter
69984             .append('span')
69985             .text(function(d) { return field.t('options.' + d, { 'default': d }); });
69986
69987         labels = labels
69988             .merge(enter);
69989
69990         radios = labels.selectAll('input')
69991             .on('change', changeRadio);
69992     }
69993
69994
69995     function structureExtras(selection$$1) {
69996         var selected = selectedKey();
69997
69998         var extrasWrap = selection$$1.selectAll('.structure-extras-wrap')
69999                 .data(selected ? [0] : []);
70000
70001         extrasWrap.exit()
70002             .remove();
70003
70004         extrasWrap = extrasWrap.enter()
70005             .append('div')
70006             .attr('class', 'structure-extras-wrap')
70007             .merge(extrasWrap);
70008
70009         var list = extrasWrap.selectAll('ul')
70010             .data([0]);
70011
70012         list = list.enter()
70013             .append('ul')
70014             .merge(list);
70015
70016
70017         // Type
70018         var typeItem = list.selectAll('.structure-type-item')
70019             .data([0]);
70020
70021         var typeEnter = typeItem.enter()
70022             .append('li')
70023             .attr('class', 'cf structure-type-item');
70024
70025         typeEnter
70026             .append('span')
70027             .attr('class', 'col6 label structure-label-type')
70028             .attr('for', 'structure-input-type')
70029             .text(t('inspector.radio.structure.type'));
70030
70031         typeEnter
70032             .append('div')
70033             .attr('class', 'col6 structure-input-type-wrap')
70034             .append('input')
70035             .attr('type', 'text')
70036             .attr('class', 'structure-input-type')
70037             .attr('placeholder', t('inspector.radio.structure.default'))
70038             .call(utilNoAuto);
70039
70040         typeItem = typeItem
70041             .merge(typeEnter);
70042
70043         typeInput = typeItem.selectAll('.structure-input-type');
70044
70045         if (taginfo) {
70046             typeInput
70047                 .call(d3combobox()
70048                     .container(context.container())
70049                     .fetcher(typeFetcher)
70050                 );
70051         }
70052
70053         typeInput
70054             .on('change', changeType)
70055             .on('blur', changeType);
70056
70057
70058         // Layer
70059         var showLayer = (selected === 'bridge' || selected === 'tunnel');
70060
70061         var layerItem = list.selectAll('.structure-layer-item')
70062             .data(showLayer ? [0] : []);
70063
70064         layerItem.exit()
70065             .remove();
70066
70067         var layerEnter = layerItem.enter()
70068             .append('li')
70069             .attr('class', 'cf structure-layer-item');
70070
70071         layerEnter
70072             .append('span')
70073             .attr('class', 'col6 label structure-label-layer')
70074             .attr('for', 'structure-input-layer')
70075             .text(t('inspector.radio.structure.layer'));
70076
70077         layerEnter
70078             .append('div')
70079             .attr('class', 'col6 structure-input-layer-wrap')
70080             .append('input')
70081             .attr('type', 'text')
70082             .attr('class', 'structure-input-layer')
70083             .attr('placeholder', '0')
70084             .call(utilNoAuto);
70085
70086         var spin = layerEnter
70087             .append('div')
70088             .attr('class', 'spin-control');
70089
70090         spin
70091             .append('button')
70092             .datum(-1)
70093             .attr('class', 'decrement')
70094             .attr('tabindex', -1);
70095
70096         spin
70097             .append('button')
70098             .datum(1)
70099             .attr('class', 'increment')
70100             .attr('tabindex', -1);
70101
70102         layerItem = layerItem
70103             .merge(layerEnter);
70104
70105         layerInput = layerItem.selectAll('.structure-input-layer')
70106             .on('change', changeLayer)
70107             .on('blur', changeLayer);
70108
70109         layerItem.selectAll('button')
70110             .on('click', function(d) {
70111                 event.preventDefault();
70112                 var num = parseInt(layerInput.node().value || 0, 10);
70113                 if (!isNaN(num)) layerInput.node().value = num + d;
70114                 changeLayer();
70115             });
70116
70117     }
70118
70119
70120     function typeFetcher(q, callback) {
70121         taginfo.values({
70122             debounce: true,
70123             key: selectedKey(),
70124             query: q
70125         }, function(err, data) {
70126             if (err) return;
70127             var comboData = data.map(function(d) {
70128                 return {
70129                     key: d.value,
70130                     value: unsnake(d.value),
70131                     title: d.title
70132                 };
70133             });
70134             if (callback) callback(comboData);
70135         });
70136     }
70137
70138
70139     function changeType() {
70140         var key = selectedKey(),
70141             t$$1 = {};
70142
70143         if (!key) return;
70144         var val = tagValue(utilGetSetValue(typeInput));
70145         t$$1[key] = val;
70146         if (val !== 'no') oldType[key] = val;
70147         dispatch$$1.call('change', this, t$$1);
70148     }
70149
70150
70151     function changeLayer() {
70152         // note: don't use utilGetSetValue here because we want 0 to be falsy.
70153         var t$$1 = { layer: layerInput.node().value || undefined };
70154         dispatch$$1.call('change', this, t$$1);
70155     }
70156
70157
70158     function changeRadio() {
70159         var t$$1 = {},
70160             activeKey;
70161
70162         if (field.key) {
70163             t$$1[field.key] = undefined;
70164         }
70165
70166         radios.each(function(d) {
70167             var active$$1 = select(this).property('checked');
70168             if (active$$1) activeKey = d;
70169
70170             if (field.key) {
70171                 if (active$$1) t$$1[field.key] = d;
70172             } else {
70173                 var val = oldType[activeKey] || 'yes';
70174                 t$$1[d] = active$$1 ? val : undefined;
70175             }
70176         });
70177
70178         if (field.type === 'structureRadio') {
70179             if (activeKey === 'bridge') {
70180                 t$$1.layer = '1';
70181             } else if (activeKey === 'tunnel') {
70182                 t$$1.layer = '-1';
70183             } else {
70184                 t$$1.layer = undefined;
70185             }
70186         }
70187
70188         dispatch$$1.call('change', this, t$$1);
70189     }
70190
70191
70192     radio.tags = function(tags) {
70193         function checked(d) {
70194             if (field.key) {
70195                 return tags[field.key] === d;
70196             } else {
70197                 return !!(tags[d] && tags[d].toLowerCase() !== 'no');
70198             }
70199         }
70200
70201         labels.classed('active', checked);
70202         radios.property('checked', checked);
70203
70204         var selection$$1 = radios.filter(function() { return this.checked; });
70205         var typeVal = '';
70206
70207         if (selection$$1.empty()) {
70208             placeholder.text(t('inspector.none'));
70209         } else {
70210             placeholder.text(selection$$1.attr('value'));
70211             typeVal = oldType[selection$$1.datum()] = tags[selection$$1.datum()];
70212         }
70213
70214         if (field.type === 'structureRadio') {
70215             wrap.call(structureExtras);
70216             utilGetSetValue(typeInput, displayValue(typeVal) || '');
70217             utilGetSetValue(layerInput, tags.layer || '');
70218         }
70219     };
70220
70221
70222     radio.focus = function() {
70223         radios.node().focus();
70224     };
70225
70226
70227     radio.entity = function(_) {
70228         if (!arguments.length) return entity;
70229         entity = _;
70230         oldType = {};
70231         return radio;
70232     };
70233
70234
70235     return utilRebind(radio, dispatch$$1, 'on');
70236 }
70237
70238 function uiFieldRestrictions(field, context) {
70239     var dispatch$$1 = dispatch('change'),
70240         breathe = behaviorBreathe(context),
70241         hover = behaviorHover(context),
70242         initialized = false,
70243         vertexID,
70244         fromNodeID;
70245
70246
70247     function restrictions(selection$$1) {
70248         // if form field is hidden or has detached from dom, clean up.
70249         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
70250             selection$$1.call(restrictions.off);
70251             return;
70252         }
70253
70254         var wrap = selection$$1.selectAll('.preset-input-wrap')
70255             .data([0]);
70256
70257         var enter = wrap.enter()
70258             .append('div')
70259             .attr('class', 'preset-input-wrap');
70260
70261         enter
70262             .append('div')
70263             .attr('class', 'restriction-help');
70264
70265
70266         var intersection = osmIntersection(context.graph(), vertexID),
70267             graph = intersection.graph,
70268             vertex = graph.entity(vertexID),
70269             filter = utilFunctor(true),
70270             extent$$1 = geoExtent$$1(),
70271             projection$$1 = geoRawMercator();
70272
70273         var d = utilGetDimensions(wrap.merge(enter)),
70274             c = [d[0] / 2, d[1] / 2],
70275             z = 24;
70276
70277         projection$$1
70278             .scale(256 * Math.pow(2, z) / (2 * Math.PI));
70279
70280         var s = projection$$1(vertex.loc);
70281
70282         projection$$1
70283             .translate([c[0] - s[0], c[1] - s[1]])
70284             .clipExtent([[0, 0], d]);
70285
70286         var drawLayers = svgLayers(projection$$1, context).only('osm').dimensions(d),
70287             drawVertices = svgVertices$$1(projection$$1, context),
70288             drawLines = svgLines$$1(projection$$1, context),
70289             drawTurns = svgTurns(projection$$1, context);
70290
70291         enter
70292             .call(drawLayers);
70293
70294         wrap = wrap
70295             .merge(enter);
70296
70297         var surface = wrap.selectAll('.surface');
70298
70299         if (!enter.empty()) {
70300             initialized = true;
70301             surface
70302                 .call(breathe)
70303                 .call(hover);
70304         }
70305
70306         surface
70307             .call(utilSetDimensions, d)
70308             .call(drawVertices, graph, [vertex], filter, extent$$1, z)
70309             .call(drawLines, graph, intersection.ways, filter)
70310             .call(drawTurns, graph, intersection.turns(fromNodeID));
70311
70312         surface
70313             .on('click.restrictions', click)
70314             .on('mouseover.restrictions', mouseover)
70315             .on('mouseout.restrictions', mouseout);
70316
70317         surface
70318             .selectAll('.selected')
70319             .classed('selected', false);
70320
70321         if (fromNodeID) {
70322             surface
70323                 .selectAll('.' + intersection.highways[fromNodeID].id)
70324                 .classed('selected', true);
70325         }
70326
70327         mouseout();
70328
70329         context.history()
70330             .on('change.restrictions', render);
70331
70332         select(window)
70333             .on('resize.restrictions', function() {
70334                 utilSetDimensions(wrap, null);
70335                 render();
70336             });
70337
70338
70339         function click() {
70340             surface
70341                 .call(breathe.off)
70342                 .call(breathe);
70343
70344             var datum = event.target.__data__;
70345             if (datum instanceof osmEntity$$1) {
70346                 fromNodeID = intersection.adjacentNodeId(datum.id);
70347                 render();
70348             } else if (datum instanceof osmTurn) {
70349                 if (datum.restriction) {
70350                     context.perform(
70351                         actionUnrestrictTurn(datum, projection$$1),
70352                         t('operations.restriction.annotation.delete')
70353                     );
70354                 } else {
70355                     context.perform(
70356                         actionRestrictTurn(datum, projection$$1),
70357                         t('operations.restriction.annotation.create')
70358                     );
70359                 }
70360             }
70361         }
70362
70363
70364         function mouseover() {
70365             var datum = event.target.__data__;
70366             if (datum instanceof osmTurn) {
70367                 var graph = context.graph(),
70368                     presets = context.presets(),
70369                     preset;
70370
70371                 if (datum.restriction) {
70372                     preset = presets.match(graph.entity(datum.restriction), graph);
70373                 } else {
70374                     preset = presets.item('type/restriction/' +
70375                         osmInferRestriction(
70376                             graph,
70377                             datum.from,
70378                             datum.via,
70379                             datum.to,
70380                             projection$$1
70381                         )
70382                     );
70383                 }
70384
70385                 wrap.selectAll('.restriction-help')
70386                     .text(t('operations.restriction.help.' +
70387                         (datum.restriction ? 'toggle_off' : 'toggle_on'),
70388                         { restriction: preset.name() })
70389                     );
70390             }
70391         }
70392
70393
70394         function mouseout() {
70395             wrap.selectAll('.restriction-help')
70396                 .text(t('operations.restriction.help.' +
70397                     (fromNodeID ? 'toggle' : 'select'))
70398                 );
70399         }
70400
70401
70402         function render() {
70403             if (context.hasEntity(vertexID)) {
70404                 restrictions(selection$$1);
70405             }
70406         }
70407     }
70408
70409
70410     restrictions.entity = function(_) {
70411         if (!vertexID || vertexID !== _.id) {
70412             fromNodeID = null;
70413             vertexID = _.id;
70414         }
70415     };
70416
70417
70418     restrictions.tags = function() {};
70419     restrictions.focus = function() {};
70420
70421
70422     restrictions.off = function(selection$$1) {
70423         if (!initialized) return;
70424
70425         selection$$1.selectAll('.surface')
70426             .call(hover.off)
70427             .call(breathe.off)
70428             .on('click.restrictions', null)
70429             .on('mouseover.restrictions', null)
70430             .on('mouseout.restrictions', null);
70431
70432         context.history()
70433             .on('change.restrictions', null);
70434
70435         select(window)
70436             .on('resize.restrictions', null);
70437     };
70438
70439
70440     return utilRebind(restrictions, dispatch$$1, 'on');
70441 }
70442
70443 function uiFieldTextarea(field) {
70444     var dispatch$$1 = dispatch('change'),
70445         input = select(null);
70446
70447
70448     function textarea(selection$$1) {
70449         input = selection$$1.selectAll('textarea')
70450             .data([0]);
70451
70452         input = input.enter()
70453             .append('textarea')
70454             .attr('id', 'preset-input-' + field.id)
70455             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
70456             .attr('maxlength', 255)
70457             .call(utilNoAuto)
70458             .on('input', change(true))
70459             .on('blur', change())
70460             .on('change', change())
70461             .merge(input);
70462     }
70463
70464
70465     function change(onInput) {
70466         return function() {
70467             var t$$1 = {};
70468             t$$1[field.key] = utilGetSetValue(input) || undefined;
70469             dispatch$$1.call('change', this, t$$1, onInput);
70470         };
70471     }
70472
70473
70474     textarea.tags = function(tags) {
70475         utilGetSetValue(input, tags[field.key] || '');
70476     };
70477
70478
70479     textarea.focus = function() {
70480         input.node().focus();
70481     };
70482
70483
70484     return utilRebind(textarea, dispatch$$1, 'on');
70485 }
70486
70487 function uiFieldWikipedia(field, context) {
70488     var dispatch$$1 = dispatch('change'),
70489         wikipedia = services.wikipedia,
70490         wikidata = services.wikidata,
70491         link$$1 = select(null),
70492         lang = select(null),
70493         title = select(null),
70494         wikiURL = '',
70495         entity;
70496
70497
70498     function wiki(selection$$1) {
70499         var langcombo = d3combobox()
70500             .container(context.container())
70501             .fetcher(function(value, cb) {
70502                 var v = value.toLowerCase();
70503
70504                 cb(dataWikipedia.filter(function(d) {
70505                     return d[0].toLowerCase().indexOf(v) >= 0 ||
70506                         d[1].toLowerCase().indexOf(v) >= 0 ||
70507                         d[2].toLowerCase().indexOf(v) >= 0;
70508                 }).map(function(d) {
70509                     return { value: d[1] };
70510                 }));
70511             });
70512
70513         var titlecombo = d3combobox()
70514             .container(context.container())
70515             .fetcher(function(value, cb) {
70516                 if (!value) {
70517                     value = context.entity(entity.id).tags.name || '';
70518                 }
70519
70520                 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
70521                 searchfn(language()[2], value, function(query, data$$1) {
70522                     cb(data$$1.map(function(d) {
70523                         return { value: d };
70524                     }));
70525                 });
70526             });
70527
70528
70529         lang = selection$$1.selectAll('input.wiki-lang')
70530             .data([0]);
70531
70532         lang = lang.enter()
70533             .append('input')
70534             .attr('type', 'text')
70535             .attr('class', 'wiki-lang')
70536             .attr('placeholder', t('translate.localized_translation_language'))
70537             .call(utilNoAuto)
70538             .merge(lang);
70539
70540         utilGetSetValue(lang, language()[1]);
70541
70542         lang
70543             .call(langcombo)
70544             .on('blur', changeLang)
70545             .on('change', changeLang);
70546
70547
70548         title = selection$$1.selectAll('input.wiki-title')
70549             .data([0]);
70550
70551         title = title.enter()
70552             .append('input')
70553             .attr('type', 'text')
70554             .attr('class', 'wiki-title')
70555             .attr('id', 'preset-input-' + field.id)
70556             .call(utilNoAuto)
70557             .merge(title);
70558
70559         title
70560             .call(titlecombo)
70561             .on('blur', blur)
70562             .on('change', change);
70563
70564
70565         link$$1 = selection$$1.selectAll('.wiki-link')
70566             .data([0]);
70567
70568         link$$1 = link$$1.enter()
70569             .append('button')
70570             .attr('class', 'button-input-action wiki-link minor')
70571             .attr('tabindex', -1)
70572             .call(svgIcon('#icon-out-link'))
70573             .merge(link$$1);
70574
70575         link$$1
70576             .on('click', function() {
70577                 event.preventDefault();
70578                 if (wikiURL) window.open(wikiURL, '_blank');
70579             });
70580     }
70581
70582
70583     function language() {
70584         var value = utilGetSetValue(lang).toLowerCase();
70585         var locale = utilDetect().locale.toLowerCase();
70586         var localeLanguage;
70587         return lodash.find(dataWikipedia, function(d) {
70588             if (d[2] === locale) localeLanguage = d;
70589             return d[0].toLowerCase() === value ||
70590                 d[1].toLowerCase() === value ||
70591                 d[2] === value;
70592         }) || localeLanguage || ['English', 'English', 'en'];
70593     }
70594
70595
70596     function changeLang() {
70597         utilGetSetValue(lang, language()[1]);
70598         change(true);
70599     }
70600
70601
70602     function blur() {
70603         change(true);
70604     }
70605
70606
70607     function change(skipWikidata) {
70608         var value = utilGetSetValue(title),
70609             m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
70610             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
70611             syncTags = {};
70612
70613         if (l) {
70614             // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
70615             value = decodeURIComponent(m[2]).replace(/_/g, ' ');
70616             if (m[3]) {
70617                 var anchor;
70618                 try {
70619                     // Best-effort `anchordecode:` implementation
70620                     anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
70621                 } catch (e) {
70622                     anchor = decodeURIComponent(m[3]);
70623                 }
70624                 value += '#' + anchor.replace(/_/g, ' ');
70625             }
70626             value = value.slice(0, 1).toUpperCase() + value.slice(1);
70627             utilGetSetValue(lang, l[1]);
70628             utilGetSetValue(title, value);
70629         }
70630
70631         if (value) {
70632             syncTags.wikipedia = language()[2] + ':' + value;
70633         } else {
70634             syncTags.wikipedia = undefined;
70635             syncTags.wikidata = undefined;
70636         }
70637
70638         dispatch$$1.call('change', this, syncTags);
70639
70640
70641         if (skipWikidata || !value || !language()[2]) return;
70642
70643         // attempt asynchronous update of wikidata tag..
70644         var initGraph = context.graph(),
70645             initEntityId = entity.id;
70646
70647         wikidata.itemsByTitle(language()[2], value, function(title, data$$1) {
70648             // If graph has changed, we can't apply this update.
70649             if (context.graph() !== initGraph) return;
70650
70651             if (!data$$1 || !Object.keys(data$$1).length) return;
70652
70653             var qids = Object.keys(data$$1);
70654             var value = qids && lodash.find(qids, function(id) { return id.match(/^Q\d+$/); });
70655             var currTags = lodash.clone(context.entity(initEntityId).tags);
70656
70657             currTags.wikidata = value;
70658
70659             // Coalesce the update of wikidata tag into the previous tag change
70660             context.overwrite(
70661                 actionChangeTags(initEntityId, currTags),
70662                 context.history().undoAnnotation()
70663             );
70664
70665             // do not dispatch.call('change') here, because entity_editor
70666             // changeTags() is not intended to be called asynchronously
70667         });
70668     }
70669
70670
70671     wiki.tags = function(tags) {
70672         var value = tags[field.key] || '',
70673             m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
70674             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
70675             anchor = m && m[3];
70676
70677         // value in correct format
70678         if (l) {
70679             utilGetSetValue(lang, l[1]);
70680             utilGetSetValue(title, m[2] + (anchor ? ('#' + anchor) : ''));
70681             if (anchor) {
70682                 try {
70683                     // Best-effort `anchorencode:` implementation
70684                     anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
70685                 } catch (e) {
70686                     anchor = anchor.replace(/ /g, '_');
70687                 }
70688             }
70689             wikiURL = 'https://' + m[1] + '.wikipedia.org/wiki/' +
70690                 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : '');
70691
70692         // unrecognized value format
70693         } else {
70694             utilGetSetValue(title, value);
70695             if (value && value !== '') {
70696                 utilGetSetValue(lang, '');
70697                 wikiURL = 'https://en.wikipedia.org/wiki/Special:Search?search=' + value;
70698             } else {
70699                 wikiURL = '';
70700             }
70701         }
70702     };
70703
70704
70705     wiki.entity = function(_) {
70706         if (!arguments.length) return entity;
70707         entity = _;
70708         return wiki;
70709     };
70710
70711
70712     wiki.focus = function() {
70713         title.node().focus();
70714     };
70715
70716
70717     return utilRebind(wiki, dispatch$$1, 'on');
70718 }
70719
70720 var uiFields = {
70721     access: uiFieldAccess,
70722     address: uiFieldAddress,
70723     check: uiFieldCheck,
70724     combo: uiFieldCombo,
70725     cycleway: uiFieldCycleway,
70726     defaultCheck: uiFieldCheck,
70727     email: uiFieldText,
70728     lanes: uiFieldLanes,
70729     localized: uiFieldLocalized,
70730     maxspeed: uiFieldMaxspeed,
70731     multiCombo: uiFieldCombo,
70732     networkCombo: uiFieldCombo,
70733     number: uiFieldText,
70734     onewayCheck: uiFieldCheck,
70735     radio: uiFieldRadio,
70736     restrictions: uiFieldRestrictions,
70737     semiCombo: uiFieldCombo,
70738     structureRadio: uiFieldRadio,
70739     tel: uiFieldText,
70740     text: uiFieldText,
70741     textarea: uiFieldTextarea,
70742     typeCombo: uiFieldCombo,
70743     url: uiFieldText,
70744     wikipedia: uiFieldWikipedia
70745 };
70746
70747 function uiPreset(context) {
70748     var dispatch$$1 = dispatch('change'),
70749         state,
70750         fieldsArr,
70751         preset,
70752         tags,
70753         id;
70754
70755
70756     // Field Constructor
70757     function UIField(field, entity, show) {
70758         field = lodash.clone(field);
70759
70760         field.input = uiFields[field.type](field, context)
70761             .on('change', function(t$$1, onInput) {
70762                 dispatch$$1.call('change', field, t$$1, onInput);
70763             });
70764
70765         if (field.input.entity) field.input.entity(entity);
70766
70767         field.keys = field.keys || [field.key];
70768
70769         field.show = show;
70770
70771         field.shown = function() {
70772             return field.id === 'name' || field.show || lodash.some(field.keys, function(key) { return !!tags[key]; });
70773         };
70774
70775         field.modified = function() {
70776             var original = context.graph().base().entities[entity.id];
70777             return lodash.some(field.keys, function(key) {
70778                 return original ? tags[key] !== original.tags[key] : tags[key];
70779             });
70780         };
70781
70782         field.revert = function() {
70783             var original = context.graph().base().entities[entity.id],
70784                 t$$1 = {};
70785             field.keys.forEach(function(key) {
70786                 t$$1[key] = original ? original.tags[key] : undefined;
70787             });
70788             return t$$1;
70789         };
70790
70791         field.present = function() {
70792             return lodash.some(field.keys, function(key) {
70793                 return tags[key];
70794             });
70795         };
70796
70797         field.remove = function() {
70798             var t$$1 = {};
70799             field.keys.forEach(function(key) {
70800                 t$$1[key] = undefined;
70801             });
70802             return t$$1;
70803         };
70804
70805         return field;
70806     }
70807
70808
70809     function fieldKey(field) {
70810         return field.id;
70811     }
70812
70813
70814     function presets(selection$$1) {
70815         selection$$1.call(uiDisclosure()
70816             .title(t('inspector.all_fields'))
70817             .expanded(context.storage('preset_fields.expanded') !== 'false')
70818             .on('toggled', toggled)
70819             .content(content)
70820         );
70821
70822         function toggled(expanded) {
70823             context.storage('preset_fields.expanded', expanded);
70824         }
70825     }
70826
70827
70828     function content(selection$$1) {
70829         if (!fieldsArr) {
70830             var entity = context.entity(id),
70831                 geometry = context.geometry(id),
70832                 presets = context.presets();
70833
70834             fieldsArr = [];
70835
70836             if (presets.field('name')) {
70837                 fieldsArr.push(UIField(presets.field('name'), entity));
70838             }
70839
70840             preset.fields.forEach(function(field) {
70841                 if (field.matchGeometry(geometry)) {
70842                     fieldsArr.push(UIField(field, entity, true));
70843                 }
70844             });
70845
70846             if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) {
70847                 fieldsArr.push(UIField(presets.field('restrictions'), entity, true));
70848             }
70849
70850             presets.universal().forEach(function(field) {
70851                 if (preset.fields.indexOf(field) < 0) {
70852                     fieldsArr.push(UIField(field, entity));
70853                 }
70854             });
70855         }
70856
70857         var shown = fieldsArr.filter(function(field) { return field.shown(); }),
70858             notShown = fieldsArr.filter(function(field) { return !field.shown(); });
70859
70860
70861         var form = selection$$1.selectAll('.preset-form')
70862             .data([0]);
70863
70864         form = form.enter()
70865             .append('div')
70866             .attr('class', 'preset-form inspector-inner fillL3')
70867             .merge(form);
70868
70869
70870         var fields = form.selectAll('.form-field')
70871             .data(shown, fieldKey);
70872
70873         fields.exit()
70874             .remove();
70875
70876         // Enter
70877         var enter = fields.enter()
70878             .append('div')
70879             .attr('class', function(field) {
70880                 return 'form-field form-field-' + field.id;
70881             });
70882
70883         var label = enter
70884             .append('label')
70885             .attr('class', 'form-label')
70886             .attr('for', function(field) { return 'preset-input-' + field.id; })
70887             .text(function(field) { return field.label(); });
70888
70889         var wrap = label
70890             .append('div')
70891             .attr('class', 'form-label-button-wrap');
70892
70893         wrap.append('button')
70894             .attr('class', 'remove-icon')
70895             .attr('tabindex', -1)
70896             .call(svgIcon('#operation-delete'));
70897
70898         wrap.append('button')
70899             .attr('class', 'modified-icon')
70900             .attr('tabindex', -1)
70901             .call(
70902                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
70903             );
70904
70905
70906         // Update
70907         fields = fields
70908             .merge(enter);
70909
70910         fields.selectAll('.form-label-button-wrap .remove-icon')
70911             .on('click', remove);
70912
70913         fields.selectAll('.modified-icon')
70914             .on('click', revert);
70915
70916         fields
70917             .order()
70918             .classed('modified', function(field) { return field.modified(); })
70919             .classed('present', function(field) { return field.present(); })
70920             .each(function(field) {
70921                 var referenceKey = field.key;
70922                 if (field.type === 'multiCombo') {   // lookup key without the trailing ':'
70923                     referenceKey = referenceKey.replace(/:$/, '');
70924                 }
70925                 var reference = uiTagReference(field.reference || { key: referenceKey }, context);
70926
70927                 if (state === 'hover') {
70928                     reference.showing(false);
70929                 }
70930
70931                 select(this)
70932                     .call(field.input)
70933                     .selectAll('input')
70934                     .on('keydown', function() {
70935                         // if user presses enter, and combobox is not active, accept edits..
70936                         if (event.keyCode === 13 && select('.combobox').empty()) {
70937                             context.enter(modeBrowse(context));
70938                         }
70939                     });
70940
70941                 select(this)
70942                     .call(reference.body)
70943                     .select('.form-label-button-wrap')
70944                     .call(reference.button);
70945
70946                 field.input.tags(tags);
70947             });
70948
70949         notShown = notShown.map(function(field) {
70950             return {
70951                 title: field.label(),
70952                 value: field.label(),
70953                 field: field
70954             };
70955         });
70956
70957
70958         var more = selection$$1.selectAll('.more-fields')
70959             .data((notShown.length > 0) ? [0] : []);
70960
70961         more.exit()
70962             .remove();
70963
70964         more = more.enter()
70965             .append('div')
70966             .attr('class', 'more-fields')
70967             .append('label')
70968             .text(t('inspector.add_fields'))
70969             .merge(more);
70970
70971
70972         var input = more.selectAll('.value')
70973             .data([0]);
70974
70975         input.exit()
70976             .remove();
70977
70978         input = input.enter()
70979             .append('input')
70980             .attr('class', 'value')
70981             .attr('type', 'text')
70982             .call(utilNoAuto)
70983             .merge(input);
70984
70985         input
70986             .call(utilGetSetValue, '')
70987             .attr('placeholder', function() {
70988                 var placeholder = [];
70989                 for (var field in notShown) {
70990                     placeholder.push(notShown[field].title);
70991                 }
70992                 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
70993             })
70994             .call(d3combobox()
70995                 .container(context.container())
70996                 .data(notShown)
70997                 .minItems(1)
70998                 .on('accept', show)
70999             );
71000
71001
71002         function show(field) {
71003             field = field.field;
71004             field.show = true;
71005             content(selection$$1);
71006             field.input.focus();
71007         }
71008
71009
71010         function revert(field) {
71011             event.stopPropagation();
71012             event.preventDefault();
71013             dispatch$$1.call('change', field, field.revert());
71014         }
71015
71016
71017         function remove(field) {
71018             event.stopPropagation();
71019             event.preventDefault();
71020             dispatch$$1.call('change', field, field.remove());
71021         }
71022     }
71023
71024
71025     presets.preset = function(_) {
71026         if (!arguments.length) return preset;
71027         if (preset && preset.id === _.id) return presets;
71028         preset = _;
71029         fieldsArr = null;
71030         return presets;
71031     };
71032
71033
71034     presets.state = function(_) {
71035         if (!arguments.length) return state;
71036         state = _;
71037         return presets;
71038     };
71039
71040
71041     presets.tags = function(_) {
71042         if (!arguments.length) return tags;
71043         tags = _;
71044         // Don't reset fieldsArr here.
71045         return presets;
71046     };
71047
71048
71049     presets.entityID = function(_) {
71050         if (!arguments.length) return id;
71051         if (id === _) return presets;
71052         id = _;
71053         fieldsArr = null;
71054         return presets;
71055     };
71056
71057
71058     return utilRebind(presets, dispatch$$1, 'on');
71059 }
71060
71061 function uiEntityEditor(context) {
71062     var dispatch$$1 = dispatch('choose'),
71063         state = 'select',
71064         coalesceChanges = false,
71065         modified = false,
71066         base,
71067         id,
71068         activePreset,
71069         reference;
71070
71071     var presetEditor = uiPreset(context)
71072         .on('change', changeTags);
71073     var rawTagEditor = uiRawTagEditor(context)
71074         .on('change', changeTags);
71075
71076
71077     function entityEditor(selection$$1) {
71078         var entity = context.entity(id),
71079             tags = lodash.clone(entity.tags);
71080
71081         // Header
71082         var header = selection$$1.selectAll('.header')
71083             .data([0]);
71084
71085         // Enter
71086         var enter = header.enter()
71087             .append('div')
71088             .attr('class', 'header fillL cf');
71089
71090         enter
71091             .append('button')
71092             .attr('class', 'fl preset-reset preset-choose')
71093             .call(svgIcon((textDirection === 'rtl') ? '#icon-forward' : '#icon-backward'));
71094
71095         enter
71096             .append('button')
71097             .attr('class', 'fr preset-close')
71098             .on('click', function() { context.enter(modeBrowse(context)); })
71099             .call(svgIcon(modified ? '#icon-apply' : '#icon-close'));
71100
71101         enter
71102             .append('h3')
71103             .text(t('inspector.edit'));
71104
71105         // Update
71106         header = header
71107             .merge(enter);
71108
71109         header.selectAll('.preset-reset')
71110             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
71111
71112
71113         // Body
71114         var body = selection$$1.selectAll('.inspector-body')
71115             .data([0]);
71116
71117         // Enter
71118         enter = body.enter()
71119             .append('div')
71120             .attr('class', 'inspector-body');
71121
71122         enter
71123             .append('div')
71124             .attr('class', 'preset-list-item inspector-inner')
71125             .append('div')
71126             .attr('class', 'preset-list-button-wrap')
71127             .append('button')
71128             .attr('class', 'preset-list-button preset-reset')
71129             .call(tooltip().title(t('inspector.back_tooltip')).placement('bottom'))
71130             .append('div')
71131             .attr('class', 'label');
71132
71133         enter
71134             .append('div')
71135             .attr('class', 'inspector-border inspector-preset');
71136
71137         enter
71138             .append('div')
71139             .attr('class', 'inspector-border raw-tag-editor inspector-inner');
71140
71141         enter
71142             .append('div')
71143             .attr('class', 'inspector-border raw-member-editor inspector-inner');
71144
71145         enter
71146             .append('div')
71147             .attr('class', 'raw-membership-editor inspector-inner');
71148
71149         // Update
71150         body = body
71151             .merge(enter);
71152
71153         body.selectAll('.preset-list-button-wrap')
71154             .call(reference.button);
71155
71156         body.selectAll('.preset-list-item')
71157             .call(reference.body);
71158
71159         body.selectAll('.preset-reset')
71160             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
71161
71162         body.select('.preset-list-item button')
71163             .call(uiPresetIcon()
71164                 .geometry(context.geometry(id))
71165                 .preset(activePreset));
71166
71167         body.select('.preset-list-item .label')
71168             .text(activePreset.name());
71169
71170         body.select('.inspector-preset')
71171             .call(presetEditor
71172                 .preset(activePreset)
71173                 .entityID(id)
71174                 .tags(tags)
71175                 .state(state));
71176
71177         body.select('.raw-tag-editor')
71178             .call(rawTagEditor
71179                 .preset(activePreset)
71180                 .entityID(id)
71181                 .tags(tags)
71182                 .state(state));
71183
71184         if (entity.type === 'relation') {
71185             body.select('.raw-member-editor')
71186                 .style('display', 'block')
71187                 .call(uiRawMemberEditor(context)
71188                     .entityID(id));
71189         } else {
71190             body.select('.raw-member-editor')
71191                 .style('display', 'none');
71192         }
71193
71194         body.select('.raw-membership-editor')
71195             .call(uiRawMembershipEditor(context)
71196                 .entityID(id));
71197
71198
71199         context.history()
71200             .on('change.entity-editor', historyChanged);
71201
71202
71203         function historyChanged() {
71204             if (state === 'hide') return;
71205
71206             var entity = context.hasEntity(id),
71207                 graph = context.graph();
71208             if (!entity) return;
71209
71210             entityEditor.preset(context.presets().match(entity, graph));
71211             entityEditor.modified(base !== graph);
71212             entityEditor(selection$$1);
71213         }
71214     }
71215
71216
71217     function clean(o) {
71218
71219         function cleanVal(k, v) {
71220             function keepSpaces(k) {
71221                 return k.match(/_hours|_times/) !== null;
71222             }
71223
71224             var blacklist = ['description', 'note', 'fixme'];
71225             if (lodash.some(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
71226
71227             var cleaned = v.split(';')
71228                 .map(function(s) { return s.trim(); })
71229                 .join(keepSpaces(k) ? '; ' : ';');
71230
71231             // The code below is not intended to validate websites and emails.
71232             // It is only intended to prevent obvious copy-paste errors. (#2323)
71233             // clean website- and email-like tags
71234             if (k.indexOf('website') !== -1 ||
71235                 k.indexOf('email') !== -1 ||
71236                 cleaned.indexOf('http') === 0) {
71237                 cleaned = cleaned
71238                     .replace(/[\u200B-\u200F\uFEFF]/g, '');  // strip LRM and other zero width chars
71239
71240             }
71241
71242             return cleaned;
71243         }
71244
71245         var out = {}, k, v;
71246         for (k in o) {
71247             if (k && (v = o[k]) !== undefined) {
71248                 out[k] = cleanVal(k, v);
71249             }
71250         }
71251         return out;
71252     }
71253
71254
71255     // Tag changes that fire on input can all get coalesced into a single
71256     // history operation when the user leaves the field.  #2342
71257     function changeTags(changed, onInput) {
71258         var entity = context.entity(id),
71259             annotation = t('operations.change_tags.annotation'),
71260             tags = lodash.clone(entity.tags);
71261
71262         lodash.forEach(changed, function(v, k) {
71263             if (v !== undefined || tags.hasOwnProperty(k)) {
71264                 tags[k] = v;
71265             }
71266         });
71267
71268         if (!onInput) {
71269             tags = clean(tags);
71270         }
71271
71272         if (!lodash.isEqual(entity.tags, tags)) {
71273             if (coalesceChanges) {
71274                 context.overwrite(actionChangeTags(id, tags), annotation);
71275             } else {
71276                 context.perform(actionChangeTags(id, tags), annotation);
71277                 coalesceChanges = !!onInput;
71278             }
71279         }
71280     }
71281
71282
71283     entityEditor.modified = function(_) {
71284         if (!arguments.length) return modified;
71285         modified = _;
71286         selectAll('button.preset-close use')
71287             .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
71288     };
71289
71290
71291     entityEditor.state = function(_) {
71292         if (!arguments.length) return state;
71293         state = _;
71294         return entityEditor;
71295     };
71296
71297
71298     entityEditor.entityID = function(_) {
71299         if (!arguments.length) return id;
71300         id = _;
71301         base = context.graph();
71302         entityEditor.preset(context.presets().match(context.entity(id), base));
71303         entityEditor.modified(false);
71304         coalesceChanges = false;
71305         return entityEditor;
71306     };
71307
71308
71309     entityEditor.preset = function(_) {
71310         if (!arguments.length) return activePreset;
71311         if (_ !== activePreset) {
71312             activePreset = _;
71313             reference = uiTagReference(activePreset.reference(context.geometry(id)), context)
71314                 .showing(false);
71315         }
71316         return entityEditor;
71317     };
71318
71319
71320     return utilRebind(entityEditor, dispatch$$1, 'on');
71321 }
71322
71323 function uiPresetList(context) {
71324     var dispatch$$1 = dispatch('choose'),
71325         id,
71326         currentPreset,
71327         autofocus = false;
71328
71329
71330     function presetList(selection$$1) {
71331         var entity = context.entity(id),
71332             geometry = context.geometry(id);
71333
71334         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
71335         if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
71336             geometry = 'point';
71337         }
71338
71339         var presets = context.presets().matchGeometry(geometry);
71340
71341         selection$$1.html('');
71342
71343         var messagewrap = selection$$1
71344             .append('div')
71345             .attr('class', 'header fillL cf');
71346
71347         var message = messagewrap
71348             .append('h3')
71349             .text(t('inspector.choose'));
71350
71351         if (context.entity(id).isUsed(context.graph())) {
71352             messagewrap
71353                 .append('button')
71354                 .attr('class', 'preset-choose')
71355                 .on('click', function() { dispatch$$1.call('choose', this, currentPreset); })
71356                 .call(svgIcon((textDirection === 'rtl') ? '#icon-backward' : '#icon-forward'));
71357         } else {
71358             messagewrap
71359                 .append('button')
71360                 .attr('class', 'close')
71361                 .on('click', function() {
71362                     context.enter(modeBrowse(context));
71363                 })
71364                 .call(svgIcon('#icon-close'));
71365         }
71366
71367         function keydown() {
71368             // hack to let delete shortcut work when search is autofocused
71369             if (search.property('value').length === 0 &&
71370                 (event.keyCode === d3keybinding.keyCodes['⌫'] ||
71371                  event.keyCode === d3keybinding.keyCodes['⌦'])) {
71372                 event.preventDefault();
71373                 event.stopPropagation();
71374                 operationDelete([id], context)();
71375             } else if (search.property('value').length === 0 &&
71376                 (event.ctrlKey || event.metaKey) &&
71377                 event.keyCode === d3keybinding.keyCodes.z) {
71378                 event.preventDefault();
71379                 event.stopPropagation();
71380                 context.undo();
71381             } else if (!event.ctrlKey && !event.metaKey) {
71382                 select(this).on('keydown', null);
71383             }
71384         }
71385
71386         function keypress() {
71387             // enter
71388             var value = search.property('value');
71389             if (event.keyCode === 13 && value.length) {
71390                 list.selectAll('.preset-list-item:first-child').datum().choose();
71391             }
71392         }
71393
71394         function inputevent() {
71395             var value = search.property('value');
71396             list.classed('filtered', value.length);
71397             if (value.length) {
71398                 var results = presets.search(value, geometry);
71399                 message.text(t('inspector.results', {
71400                     n: results.collection.length,
71401                     search: value
71402                 }));
71403                 list.call(drawList, results);
71404             } else {
71405                 list.call(drawList, context.presets().defaults(geometry, 36));
71406                 message.text(t('inspector.choose'));
71407             }
71408         }
71409
71410         var searchWrap = selection$$1
71411             .append('div')
71412             .attr('class', 'search-header');
71413
71414         var search = searchWrap
71415             .append('input')
71416             .attr('class', 'preset-search-input')
71417             .attr('placeholder', t('inspector.search'))
71418             .attr('type', 'search')
71419             .call(utilNoAuto)
71420             .on('keydown', keydown)
71421             .on('keypress', keypress)
71422             .on('input', inputevent);
71423
71424         searchWrap
71425             .call(svgIcon('#icon-search', 'pre-text'));
71426
71427         if (autofocus) {
71428             search.node().focus();
71429         }
71430
71431         var listWrap = selection$$1
71432             .append('div')
71433             .attr('class', 'inspector-body');
71434
71435         var list = listWrap
71436             .append('div')
71437             .attr('class', 'preset-list fillL cf')
71438             .call(drawList, context.presets().defaults(geometry, 36));
71439     }
71440
71441
71442     function drawList(list, presets) {
71443         var collection = presets.collection.map(function(preset) {
71444             return preset.members ? CategoryItem(preset) : PresetItem(preset);
71445         });
71446
71447         var items = list.selectAll('.preset-list-item')
71448             .data(collection, function(d) { return d.preset.id; });
71449
71450         items.order();
71451
71452         items.exit()
71453             .remove();
71454
71455         items.enter()
71456             .append('div')
71457             .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
71458             .classed('current', function(item) { return item.preset === currentPreset; })
71459             .each(function(item) { select(this).call(item); })
71460             .style('opacity', 0)
71461             .transition()
71462             .style('opacity', 1);
71463     }
71464
71465
71466     function CategoryItem(preset) {
71467         var box, sublist, shown = false;
71468
71469         function item(selection$$1) {
71470             var wrap = selection$$1.append('div')
71471                 .attr('class', 'preset-list-button-wrap category col12');
71472
71473             var button = wrap
71474                 .append('button')
71475                 .attr('class', 'preset-list-button')
71476                 .classed('expanded', false)
71477                 .call(uiPresetIcon()
71478                     .geometry(context.geometry(id))
71479                     .preset(preset))
71480                 .on('click', function() {
71481                     var isExpanded = select(this).classed('expanded');
71482                     var iconName = isExpanded ?
71483                         (textDirection === 'rtl' ? '#icon-backward' : '#icon-forward') : '#icon-down';
71484                     select(this)
71485                         .classed('expanded', !isExpanded);
71486                     select(this).selectAll('div.label svg.icon use')
71487                         .attr('href', iconName);
71488                     item.choose();
71489                 });
71490
71491             var label = button
71492                 .append('div')
71493                 .attr('class', 'label');
71494
71495             label
71496                 .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'))
71497                 .append('span')
71498                 .html(function() { return preset.name() + '&hellip;'; });
71499
71500             box = selection$$1.append('div')
71501                 .attr('class', 'subgrid col12')
71502                 .style('max-height', '0px')
71503                 .style('opacity', 0);
71504
71505             box.append('div')
71506                 .attr('class', 'arrow');
71507
71508             sublist = box.append('div')
71509                 .attr('class', 'preset-list fillL3 cf fl');
71510         }
71511
71512
71513         item.choose = function() {
71514             if (!box || !sublist) return;
71515
71516             if (shown) {
71517                 shown = false;
71518                 box.transition()
71519                     .duration(200)
71520                     .style('opacity', '0')
71521                     .style('max-height', '0px')
71522                     .style('padding-bottom', '0px');
71523             } else {
71524                 shown = true;
71525                 sublist.call(drawList, preset.members);
71526                 box.transition()
71527                     .duration(200)
71528                     .style('opacity', '1')
71529                     .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
71530                     .style('padding-bottom', '20px');
71531             }
71532         };
71533
71534         item.preset = preset;
71535
71536         return item;
71537     }
71538
71539
71540     function PresetItem(preset) {
71541         function item(selection$$1) {
71542             var wrap = selection$$1.append('div')
71543                 .attr('class', 'preset-list-button-wrap col12');
71544
71545             wrap.append('button')
71546                 .attr('class', 'preset-list-button')
71547                 .call(uiPresetIcon()
71548                     .geometry(context.geometry(id))
71549                     .preset(preset))
71550                 .on('click', item.choose)
71551                 .append('div')
71552                 .attr('class', 'label')
71553                 .text(preset.name());
71554
71555             wrap.call(item.reference.button);
71556             selection$$1.call(item.reference.body);
71557         }
71558
71559         item.choose = function() {
71560             context.presets().choose(preset);
71561
71562             context.perform(
71563                 actionChangePreset(id, currentPreset, preset),
71564                 t('operations.change_tags.annotation')
71565             );
71566
71567             dispatch$$1.call('choose', this, preset);
71568         };
71569
71570         item.help = function() {
71571             event.stopPropagation();
71572             item.reference.toggle();
71573         };
71574
71575         item.preset = preset;
71576         item.reference = uiTagReference(preset.reference(context.geometry(id)), context);
71577
71578         return item;
71579     }
71580
71581
71582     presetList.autofocus = function(_) {
71583         if (!arguments.length) return autofocus;
71584         autofocus = _;
71585         return presetList;
71586     };
71587
71588
71589     presetList.entityID = function(_) {
71590         if (!arguments.length) return id;
71591         id = _;
71592         presetList.preset(context.presets().match(context.entity(id), context.graph()));
71593         return presetList;
71594     };
71595
71596
71597     presetList.preset = function(_) {
71598         if (!arguments.length) return currentPreset;
71599         currentPreset = _;
71600         return presetList;
71601     };
71602
71603
71604     return utilRebind(presetList, dispatch$$1, 'on');
71605 }
71606
71607 function uiViewOnOSM(context) {
71608     var id;
71609
71610     function viewOnOSM(selection) {
71611         var entity = context.entity(id);
71612
71613         selection.style('display', entity.isNew() ? 'none' : null);
71614
71615         var link = selection.selectAll('.view-on-osm')
71616             .data([0]);
71617
71618         var enter = link.enter()
71619             .append('a')
71620             .attr('class', 'view-on-osm')
71621             .attr('target', '_blank')
71622             .call(svgIcon('#icon-out-link', 'inline'));
71623
71624         enter
71625             .append('span')
71626             .text(t('inspector.view_on_osm'));
71627
71628         link
71629             .merge(enter)
71630             .attr('href', context.connection().entityURL(entity));
71631     }
71632
71633
71634     viewOnOSM.entityID = function(_) {
71635         if (!arguments.length) return id;
71636         id = _;
71637         return viewOnOSM;
71638     };
71639
71640     return viewOnOSM;
71641 }
71642
71643 function uiInspector(context) {
71644     var presetList = uiPresetList(context),
71645         entityEditor = uiEntityEditor(context),
71646         state = 'select',
71647         entityID,
71648         newFeature = false;
71649
71650
71651     function inspector(selection$$1) {
71652         presetList
71653             .entityID(entityID)
71654             .autofocus(newFeature)
71655             .on('choose', setPreset);
71656
71657         entityEditor
71658             .state(state)
71659             .entityID(entityID)
71660             .on('choose', showList);
71661
71662         var wrap = selection$$1.selectAll('.panewrap')
71663             .data([0]);
71664
71665         var enter = wrap.enter()
71666             .append('div')
71667             .attr('class', 'panewrap');
71668
71669         enter
71670             .append('div')
71671             .attr('class', 'preset-list-pane pane');
71672
71673         enter
71674             .append('div')
71675             .attr('class', 'entity-editor-pane pane');
71676
71677         wrap = wrap.merge(enter);
71678         var presetPane = wrap.selectAll('.preset-list-pane');
71679         var editorPane = wrap.selectAll('.entity-editor-pane');
71680
71681         var graph = context.graph(),
71682             entity = context.entity(entityID),
71683             showEditor = state === 'hover' ||
71684                 entity.isUsed(graph) ||
71685                 entity.isHighwayIntersection(graph);
71686
71687         if (showEditor) {
71688             wrap.style('right', '0%');
71689             editorPane.call(entityEditor);
71690         } else {
71691             wrap.style('right', '-100%');
71692             presetPane.call(presetList);
71693         }
71694
71695         var footer = selection$$1.selectAll('.footer')
71696             .data([0]);
71697
71698         footer = footer.enter()
71699             .append('div')
71700             .attr('class', 'footer')
71701             .merge(footer);
71702
71703         footer
71704             .call(uiViewOnOSM(context).entityID(entityID));
71705
71706
71707         function showList(preset) {
71708             wrap.transition()
71709                 .styleTween('right', function() { return interpolateValue('0%', '-100%'); });
71710
71711             presetPane
71712                 .call(presetList.preset(preset).autofocus(true));
71713         }
71714
71715
71716         function setPreset(preset) {
71717             wrap.transition()
71718                 .styleTween('right', function() { return interpolateValue('-100%', '0%'); });
71719
71720             editorPane
71721                 .call(entityEditor.preset(preset));
71722         }
71723     }
71724
71725
71726     inspector.state = function(_) {
71727         if (!arguments.length) return state;
71728         state = _;
71729         entityEditor.state(state);
71730         return inspector;
71731     };
71732
71733
71734     inspector.entityID = function(_) {
71735         if (!arguments.length) return entityID;
71736         entityID = _;
71737         return inspector;
71738     };
71739
71740
71741     inspector.newFeature = function(_) {
71742         if (!arguments.length) return newFeature;
71743         newFeature = _;
71744         return inspector;
71745     };
71746
71747
71748     return inspector;
71749 }
71750
71751 function uiNotice(context) {
71752
71753     return function(selection) {
71754         var div = selection
71755             .append('div')
71756             .attr('class', 'notice');
71757
71758         var button = div
71759             .append('button')
71760             .attr('class', 'zoom-to notice')
71761             .on('click', function() { context.map().zoom(context.minEditableZoom()); });
71762
71763         button
71764             .call(svgIcon('#icon-plus', 'pre-text'))
71765             .append('span')
71766             .attr('class', 'label')
71767             .text(t('zoom_in_edit'));
71768
71769
71770         function disableTooHigh() {
71771             div.style('display', context.editable() ? 'none' : 'block');
71772         }
71773
71774         context.map()
71775             .on('move.notice', lodash.debounce(disableTooHigh, 500));
71776
71777         disableTooHigh();
71778     };
71779 }
71780
71781 function uiSidebar(context) {
71782     var inspector = uiInspector(context),
71783         current;
71784
71785
71786     function sidebar(selection) {
71787         var featureListWrap = selection
71788             .append('div')
71789             .attr('class', 'feature-list-pane')
71790             .call(uiFeatureList(context));
71791
71792         selection
71793             .call(uiNotice(context));
71794
71795         var inspectorWrap = selection
71796             .append('div')
71797             .attr('class', 'inspector-hidden inspector-wrap fr');
71798
71799
71800         function hover(id) {
71801             if (!current && context.hasEntity(id)) {
71802                 featureListWrap
71803                     .classed('inspector-hidden', true);
71804
71805                 inspectorWrap
71806                     .classed('inspector-hidden', false)
71807                     .classed('inspector-hover', true);
71808
71809                 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
71810                     inspector
71811                         .state('hover')
71812                         .entityID(id);
71813
71814                     inspectorWrap
71815                         .call(inspector);
71816                 }
71817
71818             } else if (!current) {
71819                 featureListWrap
71820                     .classed('inspector-hidden', false);
71821                 inspectorWrap
71822                     .classed('inspector-hidden', true);
71823                 inspector
71824                     .state('hide');
71825             }
71826         }
71827
71828
71829         sidebar.hover = lodash.throttle(hover, 200);
71830
71831
71832         sidebar.select = function(id, newFeature) {
71833             if (!current && id) {
71834                 featureListWrap
71835                     .classed('inspector-hidden', true);
71836
71837                 inspectorWrap
71838                     .classed('inspector-hidden', false)
71839                     .classed('inspector-hover', false);
71840
71841                 if (inspector.entityID() !== id || inspector.state() !== 'select') {
71842                     inspector
71843                         .state('select')
71844                         .entityID(id)
71845                         .newFeature(newFeature);
71846
71847                     inspectorWrap
71848                         .call(inspector);
71849                 }
71850
71851             } else if (!current) {
71852                 featureListWrap
71853                     .classed('inspector-hidden', false);
71854                 inspectorWrap
71855                     .classed('inspector-hidden', true);
71856                 inspector
71857                     .state('hide');
71858             }
71859         };
71860
71861
71862         sidebar.show = function(component) {
71863             featureListWrap
71864                 .classed('inspector-hidden', true);
71865             inspectorWrap
71866                 .classed('inspector-hidden', true);
71867
71868             if (current) current.remove();
71869             current = selection
71870                 .append('div')
71871                 .attr('class', 'sidebar-component')
71872                 .call(component);
71873         };
71874
71875
71876         sidebar.hide = function() {
71877             featureListWrap
71878                 .classed('inspector-hidden', false);
71879             inspectorWrap
71880                 .classed('inspector-hidden', true);
71881
71882             if (current) current.remove();
71883             current = null;
71884         };
71885     }
71886
71887
71888     sidebar.hover = function() {};
71889     sidebar.hover.cancel = function() {};
71890     sidebar.select = function() {};
71891     sidebar.show = function() {};
71892     sidebar.hide = function() {};
71893
71894     return sidebar;
71895 }
71896
71897 function uiSpinner(context) {
71898     var connection = context.connection();
71899
71900
71901     return function(selection) {
71902         var img = selection
71903             .append('img')
71904             .attr('src', context.imagePath('loader-black.gif'))
71905             .style('opacity', 0);
71906
71907         connection
71908             .on('loading.spinner', function() {
71909                 img.transition()
71910                     .style('opacity', 1);
71911             });
71912
71913         connection
71914             .on('loaded.spinner', function() {
71915                 img.transition()
71916                     .style('opacity', 0);
71917             });
71918     };
71919 }
71920
71921 function uiSplash(context) {
71922
71923     return function(selection) {
71924         if (context.storage('sawSplash'))
71925              return;
71926
71927         context.storage('sawSplash', true);
71928
71929         var modalSelection = uiModal(selection);
71930
71931         modalSelection.select('.modal')
71932             .attr('class', 'modal-splash modal col6');
71933
71934         var introModal = modalSelection.select('.content')
71935             .append('div')
71936             .attr('class', 'fillL');
71937
71938         introModal
71939             .append('div')
71940             .attr('class','modal-section cf')
71941             .append('h3').text(t('splash.welcome'));
71942
71943         introModal
71944             .append('div')
71945             .attr('class','modal-section')
71946             .append('p')
71947             .html(t('splash.text', {
71948                 version: context.version,
71949                 website: '<a href="http://ideditor.com/">ideditor.com</a>',
71950                 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
71951             }));
71952
71953         var buttonWrap = introModal
71954             .append('div')
71955             .attr('class', 'modal-actions cf');
71956
71957         var walkthrough = buttonWrap
71958             .append('button')
71959             .attr('class', 'walkthrough col6')
71960             .on('click', function() {
71961                 context.container().call(uiIntro(context));
71962                 modalSelection.close();
71963             });
71964
71965         walkthrough
71966             .append('svg')
71967             .attr('class', 'logo logo-walkthrough')
71968             .append('use')
71969             .attr('xlink:href', '#logo-walkthrough');
71970
71971         walkthrough
71972             .append('div')
71973             .text(t('splash.walkthrough'));
71974
71975         var startEditing = buttonWrap
71976             .append('button')
71977             .attr('class', 'start-editing col6')
71978             .on('click', modalSelection.close);
71979
71980         startEditing
71981             .append('svg')
71982             .attr('class', 'logo logo-features')
71983             .append('use')
71984             .attr('xlink:href', '#logo-features');
71985
71986         startEditing
71987             .append('div')
71988             .text(t('splash.start'));
71989
71990
71991         modalSelection.select('button.close')
71992             .attr('class','hide');
71993
71994     };
71995 }
71996
71997 function uiStatus(context) {
71998     var connection = context.connection();
71999
72000     return function(selection$$1) {
72001
72002         function update() {
72003             connection.status(function(err, apiStatus) {
72004                 selection$$1.html('');
72005
72006                 if (err) {
72007                     if (apiStatus === 'rateLimited') {
72008                         selection$$1
72009                             .text(t('status.rateLimit'))
72010                             .append('a')
72011                             .attr('class', 'api-status-login')
72012                             .attr('target', '_blank')
72013                             .call(svgIcon('#icon-out-link', 'inline'))
72014                             .append('span')
72015                             .text(t('login'))
72016                             .on('click.login', function() {
72017                                 event.preventDefault();
72018                                 connection.authenticate();
72019                             });
72020                     } else {
72021                         // TODO: nice messages for different error types
72022                         selection$$1.text(t('status.error'));
72023                     }
72024
72025                 } else if (apiStatus === 'readonly') {
72026                     selection$$1.text(t('status.readonly'));
72027                 } else if (apiStatus === 'offline') {
72028                     selection$$1.text(t('status.offline'));
72029                 }
72030
72031                 selection$$1.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
72032             });
72033         }
72034
72035         connection
72036             .on('change', function() { update(selection$$1); });
72037
72038         window.setInterval(update, 90000);
72039         update(selection$$1);
72040     };
72041 }
72042
72043 function uiUndoRedo(context) {
72044     var commands = [{
72045         id: 'undo',
72046         cmd: uiCmd('⌘Z'),
72047         action: function() { if (!saving()) context.undo(); },
72048         annotation: function() { return context.history().undoAnnotation(); }
72049     }, {
72050         id: 'redo',
72051         cmd: uiCmd('⌘⇧Z'),
72052         action: function() { if (!saving()) context.redo(); },
72053         annotation: function() { return context.history().redoAnnotation(); }
72054     }];
72055
72056
72057     function saving() {
72058         return context.mode().id === 'save';
72059     }
72060
72061
72062     return function(selection$$1) {
72063         var tooltipBehavior = tooltip()
72064             .placement('bottom')
72065             .html(true)
72066             .title(function (d) {
72067                 return uiTooltipHtml(d.annotation() ?
72068                     t(d.id + '.tooltip', {action: d.annotation()}) :
72069                     t(d.id + '.nothing'), d.cmd);
72070             });
72071
72072         var buttons = selection$$1.selectAll('button')
72073             .data(commands)
72074             .enter()
72075             .append('button')
72076             .attr('class', function(d) { return 'col6 disabled ' + d.id + '-button'; })
72077             .on('click', function(d) { return d.action(); })
72078             .call(tooltipBehavior);
72079
72080         buttons.each(function(d) {
72081             var iconName = d.id;
72082             if (textDirection === 'rtl') {
72083                 if (iconName === 'undo') {
72084                     iconName = 'redo';
72085                 } else if (iconName === 'redo') {
72086                     iconName = 'undo';
72087                 }
72088             }
72089             select(this)
72090                 .call(svgIcon('#icon-' + iconName));
72091         });
72092
72093         var keybinding = d3keybinding('undo')
72094             .on(commands[0].cmd, function() { event.preventDefault(); commands[0].action(); })
72095             .on(commands[1].cmd, function() { event.preventDefault(); commands[1].action(); });
72096
72097         select(document)
72098             .call(keybinding);
72099
72100         context.history()
72101             .on('change.undo_redo', update);
72102
72103         context
72104             .on('enter.undo_redo', update);
72105
72106         function update() {
72107             buttons
72108                 .property('disabled', saving())
72109                 .classed('disabled', function(d) { return !d.annotation(); })
72110                 .each(function() {
72111                     var selection$$1 = select(this);
72112                     if (selection$$1.property('tooltipVisible')) {
72113                         selection$$1.call(tooltipBehavior.show);
72114                     }
72115                 });
72116         }
72117     };
72118 }
72119
72120 // these are module variables so they are preserved through a ui.restart()
72121 var sawVersion = null;
72122 var isNewVersion = false;
72123 var isNewUser = false;
72124
72125
72126 function uiVersion(context) {
72127
72128     var currVersion = context.version,
72129         matchedVersion = currVersion.match(/\d\.\d\.\d.*/);
72130
72131     if (sawVersion === null && matchedVersion !== null) {
72132         isNewVersion = (context.storage('sawVersion') !== currVersion);
72133         isNewUser = !context.storage('sawSplash');
72134         context.storage('sawVersion', currVersion);
72135         sawVersion = currVersion;
72136     }
72137
72138     return function(selection) {
72139         selection
72140             .append('a')
72141             .attr('target', '_blank')
72142             .attr('tabindex', -1)
72143             .attr('href', 'https://github.com/openstreetmap/iD')
72144             .text(currVersion);
72145
72146         // only show new version indicator to users that have used iD before
72147         if (isNewVersion && !isNewUser) {
72148             selection
72149                 .append('div')
72150                 .attr('class', 'badge')
72151                 .append('a')
72152                 .attr('target', '_blank')
72153                 .attr('tabindex', -1)
72154                 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CHANGELOG.md#whats-new')
72155                 .call(svgIcon('#gift-11'))
72156                 .call(tooltip()
72157                     .title(t('version.whats_new', { version: currVersion }))
72158                     .placement('top')
72159                 );
72160         }
72161     };
72162 }
72163
72164 function uiZoom(context) {
72165     var zooms = [{
72166         id: 'zoom-in',
72167         icon: 'plus',
72168         title: t('zoom.in'),
72169         action: context.zoomIn,
72170         key: '+'
72171     }, {
72172         id: 'zoom-out',
72173         icon: 'minus',
72174         title: t('zoom.out'),
72175         action: context.zoomOut,
72176         key: '-'
72177     }];
72178
72179
72180     function zoomIn() {
72181         event.preventDefault();
72182         context.zoomIn();
72183     }
72184
72185
72186     function zoomOut() {
72187         event.preventDefault();
72188         context.zoomOut();
72189     }
72190
72191
72192     function zoomInFurther() {
72193         event.preventDefault();
72194         context.zoomInFurther();
72195     }
72196
72197
72198     function zoomOutFurther() {
72199         event.preventDefault();
72200         context.zoomOutFurther();
72201     }
72202
72203
72204     return function(selection$$1) {
72205         var button = selection$$1.selectAll('button')
72206             .data(zooms)
72207             .enter()
72208             .append('button')
72209             .attr('tabindex', -1)
72210             .attr('class', function(d) { return d.id; })
72211             .on('click.editor', function(d) { d.action(); })
72212             .call(tooltip()
72213                 .placement((textDirection === 'rtl') ? 'right' : 'left')
72214                 .html(true)
72215                 .title(function(d) {
72216                     return uiTooltipHtml(d.title, d.key);
72217                 })
72218             );
72219
72220         button.each(function(d) {
72221             select(this)
72222                 .call(svgIcon('#icon-' + d.icon, 'light'));
72223         });
72224
72225         var keybinding = d3keybinding('zoom');
72226
72227        lodash.each(['plus', 'ffplus', '=', 'ffequals'], function(key) {
72228             keybinding.on([key], zoomIn);
72229             keybinding.on([uiCmd('⌘' + key)], zoomInFurther);
72230         });
72231
72232         lodash.each(['_', '-', 'ffminus', 'dash'], function(key) {
72233             keybinding.on([key], zoomOut);
72234             keybinding.on([uiCmd('⌘' + key)], zoomOutFurther);
72235         });
72236
72237         select(document)
72238             .call(keybinding);
72239     };
72240 }
72241
72242 function uiInit(context) {
72243     var uiInitCounter = 0;
72244
72245
72246     function render(container) {
72247         container
72248             .attr('dir', textDirection);
72249
72250         var map = context.map();
72251
72252         var hash = behaviorHash(context);
72253         hash();
72254
72255         if (!hash.hadHash) {
72256             map.centerZoom([0, 0], 2);
72257         }
72258
72259         container
72260             .append('svg')
72261             .attr('id', 'defs')
72262             .call(svgDefs(context));
72263
72264         container
72265             .append('div')
72266             .attr('id', 'sidebar')
72267             .attr('class', 'col4')
72268             .call(ui.sidebar);
72269
72270         var content = container
72271             .append('div')
72272             .attr('id', 'content')
72273             .attr('class', 'active');
72274
72275         var bar = content
72276             .append('div')
72277             .attr('id', 'bar')
72278             .attr('class', 'fillD');
72279
72280         content
72281             .append('div')
72282             .attr('id', 'map')
72283             .attr('dir', 'ltr')
72284             .call(map);
72285
72286         content
72287             .call(uiMapInMap(context))
72288             .call(uiInfo(context));
72289
72290         bar
72291             .append('div')
72292             .attr('class', 'spacer col4');
72293
72294         var limiter = bar.append('div')
72295             .attr('class', 'limiter');
72296
72297         limiter
72298             .append('div')
72299             .attr('class', 'button-wrap joined col3')
72300             .call(uiModes(context), limiter);
72301
72302         limiter
72303             .append('div')
72304             .attr('class', 'button-wrap joined col1')
72305             .call(uiUndoRedo(context));
72306
72307         limiter
72308             .append('div')
72309             .attr('class', 'button-wrap col1')
72310             .call(uiSave(context));
72311
72312         bar
72313             .append('div')
72314             .attr('class', 'full-screen')
72315             .call(uiFullScreen(context));
72316
72317         bar
72318             .append('div')
72319             .attr('class', 'spinner')
72320             .call(uiSpinner(context));
72321
72322
72323         var controls = bar
72324             .append('div')
72325             .attr('class', 'map-controls');
72326
72327         controls
72328             .append('div')
72329             .attr('class', 'map-control zoombuttons')
72330             .call(uiZoom(context));
72331
72332         controls
72333             .append('div')
72334             .attr('class', 'map-control geolocate-control')
72335             .call(uiGeolocate(context));
72336
72337         controls
72338             .append('div')
72339             .attr('class', 'map-control background-control')
72340             .call(uiBackground(context));
72341
72342         controls
72343             .append('div')
72344             .attr('class', 'map-control map-data-control')
72345             .call(uiMapData(context));
72346
72347         controls
72348             .append('div')
72349             .attr('class', 'map-control help-control')
72350             .call(uiHelp(context));
72351
72352
72353         var about = content
72354             .append('div')
72355             .attr('id', 'about');
72356
72357         about
72358             .append('div')
72359             .attr('id', 'attrib')
72360             .attr('dir', 'ltr')
72361             .call(uiAttribution(context));
72362
72363         about
72364             .append('div')
72365             .attr('class', 'api-status')
72366             .call(uiStatus(context));
72367
72368
72369         var footer = about
72370             .append('div')
72371             .attr('id', 'footer')
72372             .attr('class', 'fillD');
72373
72374         footer
72375             .append('div')
72376             .attr('id', 'flash-wrap')
72377             .attr('class', 'footer-hide');
72378
72379         var footerWrap = footer
72380             .append('div')
72381             .attr('id', 'footer-wrap')
72382             .attr('class', 'footer-show');
72383
72384         footerWrap
72385             .append('div')
72386             .attr('id', 'scale-block')
72387             .call(uiScale(context));
72388
72389         var aboutList = footerWrap
72390             .append('div')
72391             .attr('id', 'info-block')
72392             .append('ul')
72393             .attr('id', 'about-list');
72394
72395         if (!context.embed()) {
72396             aboutList
72397                 .call(uiAccount(context));
72398         }
72399
72400         aboutList
72401             .append('li')
72402             .attr('class', 'version')
72403             .call(uiVersion(context));
72404
72405         var issueLinks = aboutList
72406             .append('li');
72407
72408         issueLinks
72409             .append('a')
72410             .attr('target', '_blank')
72411             .attr('tabindex', -1)
72412             .attr('href', 'https://github.com/openstreetmap/iD/issues')
72413             .call(svgIcon('#icon-bug', 'light'))
72414             .call(tooltip().title(t('report_a_bug')).placement('top'));
72415
72416         issueLinks
72417             .append('a')
72418             .attr('target', '_blank')
72419             .attr('tabindex', -1)
72420             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
72421             .call(svgIcon('#icon-translate', 'light'))
72422             .call(tooltip().title(t('help_translate')).placement('top'));
72423
72424         aboutList
72425             .append('li')
72426             .attr('class', 'feature-warning')
72427             .attr('tabindex', -1)
72428             .call(uiFeatureInfo(context));
72429
72430         aboutList
72431             .append('li')
72432             .attr('class', 'user-list')
72433             .attr('tabindex', -1)
72434             .call(uiContributors(context));
72435
72436
72437         window.onbeforeunload = function() {
72438             return context.save();
72439         };
72440
72441         window.onunload = function() {
72442             context.history().unlock();
72443         };
72444
72445         var mapDimensions = map.dimensions();
72446
72447
72448         function onResize() {
72449             mapDimensions = utilGetDimensions(content, true);
72450             map.dimensions(mapDimensions);
72451         }
72452
72453         select(window)
72454             .on('resize.editor', onResize);
72455
72456         onResize();
72457
72458         function pan(d) {
72459             return function() {
72460                 event.preventDefault();
72461                 context.pan(d, 100);
72462             };
72463         }
72464
72465
72466         // pan amount
72467         var pa = 10;
72468
72469         var keybinding = d3keybinding('main')
72470             .on('⌫', function() { event.preventDefault(); })
72471             .on('←', pan([pa, 0]))
72472             .on('↑', pan([0, pa]))
72473             .on('→', pan([-pa, 0]))
72474             .on('↓', pan([0, -pa]))
72475             .on(['⇧←', uiCmd('⌘←')], pan([mapDimensions[0], 0]))
72476             .on(['⇧↑', uiCmd('⌘↑')], pan([0, mapDimensions[1]]))
72477             .on(['⇧→', uiCmd('⌘→')], pan([-mapDimensions[0], 0]))
72478             .on(['⇧↓', uiCmd('⌘↓')], pan([0, -mapDimensions[1]]));
72479
72480         select(document)
72481             .call(keybinding);
72482
72483         context.enter(modeBrowse(context));
72484
72485         if (!uiInitCounter++) {
72486             if (!hash.startWalkthrough) {
72487                 context.container()
72488                     .call(uiSplash(context))
72489                     .call(uiRestore(context));
72490             }
72491
72492             context.container()
72493                 .call(uiShortcuts(context));
72494         }
72495
72496         var authenticating = uiLoading(context)
72497             .message(t('loading_auth'))
72498             .blocking(true);
72499
72500         context.connection()
72501             .on('authLoading.ui', function() {
72502                 context.container()
72503                     .call(authenticating);
72504             })
72505             .on('authDone.ui', function() {
72506                 authenticating.close();
72507             });
72508
72509         uiInitCounter++;
72510
72511         if (hash.startWalkthrough) {
72512             hash.startWalkthrough = false;
72513             context.container().call(uiIntro(context));
72514         }
72515     }
72516
72517
72518     var renderCallback;
72519
72520     function ui(node, callback) {
72521         renderCallback = callback;
72522         var container = select(node);
72523         context.container(container);
72524         context.loadLocale(function(err) {
72525             if (!err) {
72526                 render(container);
72527             }
72528             if (callback) {
72529                 callback(err);
72530             }
72531         });
72532     }
72533
72534
72535     ui.restart = function(arg) {
72536         context.locale(arg);
72537         context.loadLocale(function(err) {
72538             if (!err) {
72539                 context.container().selectAll('*').remove();
72540                 render(context.container());
72541                 if (renderCallback) renderCallback();
72542             }
72543         });
72544     };
72545
72546
72547     ui.sidebar = uiSidebar(context);
72548
72549     return ui;
72550 }
72551
72552 var changeset;
72553 var readOnlyTags = ['created_by', 'imagery_used', 'host', 'locale'];
72554
72555
72556 function uiCommit(context) {
72557     var dispatch$$1 = dispatch('cancel', 'save');
72558
72559
72560     function commit(selection$$1) {
72561         if (!changeset) {
72562             var detected = utilDetect(),
72563                 tags = {
72564                     created_by: ('iD ' + context.version).substr(0, 255),
72565                     imagery_used: context.history().imageryUsed().join(';').substr(0, 255),
72566                     host: detected.host.substr(0, 255),
72567                     locale: detected.locale.substr(0, 255)
72568                 };
72569
72570             changeset = new osmChangeset({ tags: tags });
72571         }
72572
72573
72574         var changes = context.history().changes(),
72575             summary = context.history().difference().summary(),
72576             rawTagEditor = uiRawTagEditor(context).on('change', changeTags),
72577             comment = context.storage('comment') || '',
72578             commentDate = +context.storage('commentDate') || 0,
72579             currDate = Date.now(),
72580             cutoff = 2 * 86400 * 1000;   // 2 days
72581
72582         // expire the stored comment if it is too old - #3947
72583         if (commentDate > currDate || currDate - commentDate > cutoff) {
72584             comment = '';
72585         }
72586
72587         selection$$1
72588             .append('div')
72589             .attr('class', 'header fillL')
72590             .append('h3')
72591             .text(t('commit.title'));
72592
72593         var body = selection$$1
72594             .append('div')
72595             .attr('class', 'body');
72596
72597         var commentSection = body
72598             .append('div')
72599             .attr('class', 'modal-section form-field commit-form');
72600
72601         commentSection
72602             .append('label')
72603             .attr('class', 'form-label')
72604             .text(t('commit.message_label'));
72605
72606         var commentField = commentSection
72607             .append('textarea')
72608             .attr('class', 'commit-form-comment')
72609             .attr('placeholder', t('commit.description_placeholder'))
72610             .attr('maxlength', 255)
72611             .property('value', comment)
72612             .on('input.save', change(true))
72613             .on('change.save', change())
72614             .on('blur.save', function() {
72615                 context.storage('comment', this.value);
72616                 context.storage('commentDate', Date.now());
72617             });
72618
72619
72620         commentField.node().select();
72621
72622         context.connection().userChangesets(function (err, changesets) {
72623             if (err) return;
72624
72625             var comments = changesets.map(function(changeset) {
72626                 return {
72627                     title: changeset.tags.comment,
72628                     value: changeset.tags.comment
72629                 };
72630             });
72631
72632             commentField
72633                 .call(d3combobox()
72634                     .container(context.container())
72635                     .caseSensitive(true)
72636                     .data(lodash.uniqBy(comments, 'title'))
72637                 );
72638         });
72639
72640         var clippyArea = commentSection.append('div')
72641             .attr('class', 'clippy-area');
72642
72643         var changeSetInfo = commentSection.append('div')
72644             .attr('class', 'changeset-info');
72645
72646         changeSetInfo.append('a')
72647             .attr('target', '_blank')
72648             .attr('tabindex', -1)
72649             .call(svgIcon('#icon-out-link', 'inline'))
72650             .attr('href', t('commit.about_changeset_comments_link'))
72651             .append('span')
72652             .text(t('commit.about_changeset_comments'));
72653
72654
72655         // Warnings
72656         var warnings = body.selectAll('div.warning-section')
72657             .data([context.history().validate(changes)]);
72658
72659         warnings = warnings.enter()
72660             .append('div')
72661             .attr('class', 'modal-section warning-section fillL2')
72662             .style('display', function(d) { return lodash.isEmpty(d) ? 'none' : null; })
72663             .style('background', '#ffb')
72664             .merge(warnings);
72665
72666         warnings
72667             .append('h3')
72668             .text(t('commit.warnings'));
72669
72670         warnings
72671             .append('ul')
72672             .attr('class', 'changeset-list');
72673
72674         var warningLi = warnings.select('ul').selectAll('li')
72675             .data(function(d) { return d; });
72676
72677         warningLi = warningLi.enter()
72678             .append('li')
72679             .on('mouseover', mouseover)
72680             .on('mouseout', mouseout)
72681             .on('click', warningClick)
72682             .merge(warningLi);
72683
72684         warningLi
72685             .call(svgIcon('#icon-alert', 'pre-text'));
72686
72687         warningLi
72688             .append('strong')
72689             .text(function(d) { return d.message; });
72690
72691         warningLi.filter(function(d) { return d.tooltip; })
72692             .call(tooltip()
72693                 .title(function(d) { return d.tooltip; })
72694                 .placement('top')
72695             );
72696
72697
72698         // Upload Explanation
72699         var saveSection = body
72700             .append('div')
72701             .attr('class','modal-section save-section fillL cf');
72702
72703         var prose = saveSection
72704             .append('p')
72705             .attr('class', 'commit-info')
72706             .html(t('commit.upload_explanation'));
72707
72708
72709         context.connection().userDetails(function(err, user) {
72710             if (err) return;
72711
72712             var userLink = select(document.createElement('div'));
72713
72714             if (user.image_url) {
72715                 userLink
72716                     .append('img')
72717                     .attr('src', user.image_url)
72718                     .attr('class', 'icon pre-text user-icon');
72719             }
72720
72721             userLink
72722                 .append('a')
72723                 .attr('class','user-info')
72724                 .text(user.display_name)
72725                 .attr('href', context.connection().userURL(user.display_name))
72726                 .attr('tabindex', -1)
72727                 .attr('target', '_blank');
72728
72729             prose
72730                 .html(t('commit.upload_explanation_with_user', { user: userLink.html() }));
72731         });
72732
72733
72734         // Buttons
72735         var buttonSection = saveSection
72736             .append('div')
72737             .attr('class', 'buttons fillL cf');
72738
72739         var cancelButton = buttonSection
72740             .append('button')
72741             .attr('class', 'secondary-action col5 button cancel-button')
72742             .on('click.cancel', function() {
72743                 dispatch$$1.call('cancel');
72744             });
72745
72746         cancelButton
72747             .append('span')
72748             .attr('class', 'label')
72749             .text(t('commit.cancel'));
72750
72751         var saveButton = buttonSection
72752             .append('button')
72753             .attr('class', 'action col5 button save-button')
72754             .attr('disabled', function() {
72755                 var n = select('.commit-form textarea').node();
72756                 return (n && n.value.length) ? null : true;
72757             })
72758             .on('click.save', function() {
72759                 dispatch$$1.call('save', this, changeset);
72760             });
72761
72762         saveButton
72763             .append('span')
72764             .attr('class', 'label')
72765             .text(t('commit.save'));
72766
72767
72768         // Raw Tag Editor
72769         var tagSection = body
72770             .append('div')
72771             .attr('class', 'modal-section tag-section raw-tag-editor');
72772
72773
72774         // Changes
72775         var changeSection = body
72776             .append('div')
72777             .attr('class', 'commit-section modal-section fillL2');
72778
72779         changeSection.append('h3')
72780             .text(t('commit.changes', { count: summary.length }));
72781
72782         var li = changeSection
72783             .append('ul')
72784             .attr('class', 'changeset-list')
72785             .selectAll('li')
72786             .data(summary);
72787
72788         li = li.enter()
72789             .append('li')
72790             .on('mouseover', mouseover)
72791             .on('mouseout', mouseout)
72792             .on('click', zoomToEntity)
72793             .merge(li);
72794
72795         li.each(function(d) {
72796             select(this)
72797                 .call(svgIcon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
72798         });
72799
72800         li.append('span')
72801             .attr('class', 'change-type')
72802             .text(function(d) { return t('commit.' + d.changeType) + ' '; });
72803
72804         li.append('strong')
72805             .attr('class', 'entity-type')
72806             .text(function(d) {
72807                 var matched = context.presets().match(d.entity, d.graph);
72808                 return (matched && matched.name()) || utilDisplayType(d.entity.id);
72809             });
72810
72811         li.append('span')
72812             .attr('class', 'entity-name')
72813             .text(function(d) {
72814                 var name = utilDisplayName(d.entity) || '',
72815                     string = '';
72816                 if (name !== '') string += ':';
72817                 return string += ' ' + name;
72818             });
72819
72820         li.style('opacity', 0)
72821             .transition()
72822             .style('opacity', 1);
72823
72824
72825         // Call change() off the bat, in case a changeset
72826         // comment is recovered from localStorage
72827         utilTriggerEvent(commentField, 'input');
72828
72829
72830         function mouseover(d) {
72831             if (d.entity) {
72832                 context.surface().selectAll(
72833                     utilEntityOrMemberSelector([d.entity.id], context.graph())
72834                 ).classed('hover', true);
72835             }
72836         }
72837
72838
72839         function mouseout() {
72840             context.surface().selectAll('.hover')
72841                 .classed('hover', false);
72842         }
72843
72844
72845         function warningClick(d) {
72846             if (d.entity) {
72847                 context.map().zoomTo(d.entity);
72848                 context.enter(modeSelect(context, [d.entity.id]));
72849             }
72850         }
72851
72852
72853         function zoomToEntity(change) {
72854             var entity = change.entity;
72855             if (change.changeType !== 'deleted' &&
72856                 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
72857                 context.map().zoomTo(entity);
72858                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph()))
72859                     .classed('hover', true);
72860             }
72861         }
72862
72863
72864         function checkComment(comment) {
72865             // Save button disabled if there is no comment..
72866             selectAll('.save-section .save-button')
72867                 .attr('disabled', (comment.length ? null : true));
72868
72869             // Warn if comment mentions Google..
72870             var googleWarning = clippyArea
72871                .html('')
72872                .selectAll('a')
72873                .data(comment.match(/google/i) ? [true] : []);
72874
72875             googleWarning.exit()
72876                 .remove();
72877
72878             googleWarning.enter()
72879                .append('a')
72880                .attr('target', '_blank')
72881                .attr('tabindex', -1)
72882                .call(svgIcon('#icon-alert', 'inline'))
72883                .attr('href', t('commit.google_warning_link'))
72884                .append('span')
72885                .text(t('commit.google_warning'));
72886         }
72887
72888
72889         function change(onInput) {
72890             return function() {
72891                 var comment = commentField.property('value').trim();
72892                 if (!onInput) {
72893                     commentField.property('value', comment);
72894                 }
72895
72896                 checkComment(comment);
72897
72898                 var changeset = updateChangeset({ comment: comment });
72899                 var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
72900
72901                 tagSection
72902                     .call(rawTagEditor
72903                         .expanded(expanded)
72904                         .readOnlyTags(readOnlyTags)
72905                         .tags(lodash.clone(changeset.tags))
72906                     );
72907             };
72908         }
72909
72910
72911         function changeTags(changed) {
72912             if (changed.hasOwnProperty('comment')) {
72913                 if (changed.comment === undefined) {
72914                     changed.comment = '';
72915                 }
72916                 changed.comment = changed.comment.trim();
72917                 commentField.property('value', changed.comment);
72918             }
72919             updateChangeset(changed);
72920             utilTriggerEvent(commentField, 'input');
72921         }
72922
72923
72924         function updateChangeset(changed) {
72925             var tags = lodash.clone(changeset.tags);
72926
72927             lodash.forEach(changed, function(v, k) {
72928                 k = k.trim().substr(0, 255);
72929                 if (readOnlyTags.indexOf(k) !== -1) return;
72930
72931                 if (k !== '' && v !== undefined) {
72932                     tags[k] = v.trim().substr(0, 255);
72933                 } else {
72934                     delete tags[k];
72935                 }
72936             });
72937
72938             if (!lodash.isEqual(changeset.tags, tags)) {
72939                 changeset = changeset.update({ tags: tags });
72940             }
72941
72942             return changeset;
72943         }
72944
72945     }
72946
72947
72948     commit.reset = function() {
72949         changeset = null;
72950     };
72951
72952
72953     return utilRebind(commit, dispatch$$1, 'on');
72954 }
72955
72956 function uiConfirm(selection) {
72957     var modalSelection = uiModal(selection);
72958
72959     modalSelection.select('.modal')
72960         .classed('modal-alert', true);
72961
72962     var section = modalSelection.select('.content');
72963
72964     section.append('div')
72965         .attr('class', 'modal-section header');
72966
72967     section.append('div')
72968         .attr('class', 'modal-section message-text');
72969
72970     var buttons = section.append('div')
72971         .attr('class', 'modal-section buttons cf');
72972
72973
72974     modalSelection.okButton = function() {
72975         buttons
72976             .append('button')
72977             .attr('class', 'action col4')
72978             .on('click.confirm', function() {
72979                 modalSelection.remove();
72980             })
72981             .text(t('confirm.okay'));
72982
72983         return modalSelection;
72984     };
72985
72986
72987     return modalSelection;
72988 }
72989
72990 function uiConflicts(context) {
72991     var dispatch$$1 = dispatch('download', 'cancel', 'save'),
72992         list;
72993
72994
72995     function conflicts(selection$$1) {
72996         var header = selection$$1
72997             .append('div')
72998             .attr('class', 'header fillL');
72999
73000         header
73001             .append('button')
73002             .attr('class', 'fr')
73003             .on('click', function() { dispatch$$1.call('cancel'); })
73004             .call(svgIcon('#icon-close'));
73005
73006         header
73007             .append('h3')
73008             .text(t('save.conflict.header'));
73009
73010         var body = selection$$1
73011             .append('div')
73012             .attr('class', 'body fillL');
73013
73014         body
73015             .append('div')
73016             .attr('class', 'conflicts-help')
73017             .text(t('save.conflict.help'))
73018             .append('a')
73019             .attr('class', 'conflicts-download')
73020             .text(t('save.conflict.download_changes'))
73021             .on('click.download', function() { dispatch$$1.call('download'); });
73022
73023         body
73024             .append('div')
73025             .attr('class', 'conflict-container fillL3')
73026             .call(showConflict, 0);
73027
73028         body
73029             .append('div')
73030             .attr('class', 'conflicts-done')
73031             .attr('opacity', 0)
73032             .style('display', 'none')
73033             .text(t('save.conflict.done'));
73034
73035         var buttons = body
73036             .append('div')
73037             .attr('class','buttons col12 joined conflicts-buttons');
73038
73039         buttons
73040             .append('button')
73041             .attr('disabled', list.length > 1)
73042             .attr('class', 'action conflicts-button col6')
73043             .text(t('save.title'))
73044             .on('click.try_again', function() { dispatch$$1.call('save'); });
73045
73046         buttons
73047             .append('button')
73048             .attr('class', 'secondary-action conflicts-button col6')
73049             .text(t('confirm.cancel'))
73050             .on('click.cancel', function() { dispatch$$1.call('cancel'); });
73051     }
73052
73053
73054     function showConflict(selection$$1, index) {
73055         if (index < 0 || index >= list.length) return;
73056
73057         var parent = select(selection$$1.node().parentNode);
73058
73059         // enable save button if this is the last conflict being reviewed..
73060         if (index === list.length - 1) {
73061             window.setTimeout(function() {
73062                 parent.select('.conflicts-button')
73063                     .attr('disabled', null);
73064
73065                 parent.select('.conflicts-done')
73066                     .transition()
73067                     .attr('opacity', 1)
73068                     .style('display', 'block');
73069             }, 250);
73070         }
73071
73072         var item = selection$$1
73073             .selectAll('.conflict')
73074             .data([list[index]]);
73075
73076         var enter = item.enter()
73077             .append('div')
73078             .attr('class', 'conflict');
73079
73080         enter
73081             .append('h4')
73082             .attr('class', 'conflict-count')
73083             .text(t('save.conflict.count', { num: index + 1, total: list.length }));
73084
73085         enter
73086             .append('a')
73087             .attr('class', 'conflict-description')
73088             .attr('href', '#')
73089             .text(function(d) { return d.name; })
73090             .on('click', function(d) {
73091                 zoomToEntity(d.id);
73092                 event.preventDefault();
73093             });
73094
73095         var details = enter
73096             .append('div')
73097             .attr('class', 'conflict-detail-container');
73098
73099         details
73100             .append('ul')
73101             .attr('class', 'conflict-detail-list')
73102             .selectAll('li')
73103             .data(function(d) { return d.details || []; })
73104             .enter()
73105             .append('li')
73106             .attr('class', 'conflict-detail-item')
73107             .html(function(d) { return d; });
73108
73109         details
73110             .append('div')
73111             .attr('class', 'conflict-choices')
73112             .call(addChoices);
73113
73114         details
73115             .append('div')
73116             .attr('class', 'conflict-nav-buttons joined cf')
73117             .selectAll('button')
73118             .data(['previous', 'next'])
73119             .enter()
73120             .append('button')
73121             .text(function(d) { return t('save.conflict.' + d); })
73122             .attr('class', 'conflict-nav-button action col6')
73123             .attr('disabled', function(d, i) {
73124                 return (i === 0 && index === 0) ||
73125                     (i === 1 && index === list.length - 1) || null;
73126             })
73127             .on('click', function(d, i) {
73128                 var container = parent.select('.conflict-container'),
73129                 sign = (i === 0 ? -1 : 1);
73130
73131                 container
73132                     .selectAll('.conflict')
73133                     .remove();
73134
73135                 container
73136                     .call(showConflict, index + sign);
73137
73138                 event.preventDefault();
73139             });
73140
73141         item.exit()
73142             .remove();
73143     }
73144
73145
73146     function addChoices(selection$$1) {
73147         var choices = selection$$1
73148             .append('ul')
73149             .attr('class', 'layer-list')
73150             .selectAll('li')
73151             .data(function(d) { return d.choices || []; });
73152
73153         var enter = choices.enter()
73154             .append('li')
73155             .attr('class', 'layer');
73156
73157         var label = enter
73158             .append('label');
73159
73160         label
73161             .append('input')
73162             .attr('type', 'radio')
73163             .attr('name', function(d) { return d.id; })
73164             .on('change', function(d, i) {
73165                 var ul = this.parentNode.parentNode.parentNode;
73166                 ul.__data__.chosen = i;
73167                 choose(ul, d);
73168             });
73169
73170         label
73171             .append('span')
73172             .text(function(d) { return d.text; });
73173
73174         choices
73175             .each(function(d, i) {
73176                 var ul = this.parentNode;
73177                 if (ul.__data__.chosen === i) choose(ul, d);
73178             });
73179     }
73180
73181
73182     function choose(ul, datum) {
73183         if (event) event.preventDefault();
73184
73185         select(ul)
73186             .selectAll('li')
73187             .classed('active', function(d) { return d === datum; })
73188             .selectAll('input')
73189             .property('checked', function(d) { return d === datum; });
73190
73191         var extent$$1 = geoExtent$$1(),
73192             entity;
73193
73194         entity = context.graph().hasEntity(datum.id);
73195         if (entity) extent$$1._extend(entity.extent(context.graph()));
73196
73197         datum.action();
73198
73199         entity = context.graph().hasEntity(datum.id);
73200         if (entity) extent$$1._extend(entity.extent(context.graph()));
73201
73202         zoomToEntity(datum.id, extent$$1);
73203     }
73204
73205
73206     function zoomToEntity(id, extent$$1) {
73207         context.surface().selectAll('.hover')
73208             .classed('hover', false);
73209
73210         var entity = context.graph().hasEntity(id);
73211         if (entity) {
73212             if (extent$$1) {
73213                 context.map().trimmedExtent(extent$$1);
73214             } else {
73215                 context.map().zoomTo(entity);
73216             }
73217             context.surface().selectAll(
73218                 utilEntityOrMemberSelector([entity.id], context.graph()))
73219                 .classed('hover', true);
73220         }
73221     }
73222
73223
73224     // The conflict list should be an array of objects like:
73225     // {
73226     //     id: id,
73227     //     name: entityName(local),
73228     //     details: merge.conflicts(),
73229     //     chosen: 1,
73230     //     choices: [
73231     //         choice(id, keepMine, forceLocal),
73232     //         choice(id, keepTheirs, forceRemote)
73233     //     ]
73234     // }
73235     conflicts.list = function(_) {
73236         if (!arguments.length) return list;
73237         list = _;
73238         return conflicts;
73239     };
73240
73241
73242     return utilRebind(conflicts, dispatch$$1, 'on');
73243 }
73244
73245 function uiEditMenu(context, operations) {
73246     var menu,
73247         center = [0, 0],
73248         offset = [0, 0],
73249         tooltip;
73250
73251     var p = 8,               // top padding
73252         m = 4,               // top margin
73253         h = 15,              // height of icon
73254         vpBottomMargin = 45, // viewport bottom margin
73255         vpSideMargin = 35,   // viewport side margin
73256         buttonWidth = 44,
73257         buttonHeight = (2 * p + h),
73258         menuWidth = buttonWidth,
73259         menuHeight = (2 * m) + operations.length * buttonHeight,
73260         menuSideMargin = 10,
73261         tooltipWidth = 200,
73262         tooltipHeight = 200;  // a reasonable guess, real height depends on tooltip contents
73263
73264
73265     var editMenu = function (selection$$1) {
73266         if (!operations.length) return;
73267
73268         selection$$1.node().parentNode.focus();
73269
73270         var isRTL = textDirection === 'rtl',
73271             viewport = context.surfaceRect();
73272
73273         if (!isRTL && (center[0] + menuSideMargin + menuWidth) > (viewport.width - vpSideMargin)) {
73274             // menu is going left-to-right and near right viewport edge, go left instead
73275             isRTL = true;
73276         } else if (isRTL && (center[0] - menuSideMargin - menuWidth) < vpSideMargin) {
73277             // menu is going right-to-left and near left viewport edge, go right instead
73278             isRTL = false;
73279         }
73280
73281         offset[0] = (isRTL ? -1 * (menuSideMargin + menuWidth) : menuSideMargin);
73282
73283         if (center[1] + menuHeight > (viewport.height - vpBottomMargin)) {
73284             // menu is near bottom viewport edge, shift upwards
73285             offset[1] = -1 * (center[1] + menuHeight - viewport.height + vpBottomMargin);
73286         }
73287
73288         var origin = [ center[0] + offset[0], center[1] + offset[1] ];
73289
73290         menu = selection$$1
73291             .append('g')
73292             .attr('class', 'edit-menu')
73293             .attr('transform', 'translate(' + origin + ')')
73294             .attr('opacity', 0);
73295
73296         menu
73297             .transition()
73298             .attr('opacity', 1);
73299
73300         menu
73301             .append('rect')
73302             .attr('class', 'edit-menu-background')
73303             .attr('x', 4)
73304             .attr('rx', 4)
73305             .attr('ry', 4)
73306             .attr('width', menuWidth)
73307             .attr('height', menuHeight)
73308             .attr('stroke-linecap', 'round');
73309
73310
73311         var button = menu.selectAll('.edit-menu-item')
73312             .data(operations)
73313             .enter()
73314             .append('g')
73315             .attr('class', function (d) { return 'edit-menu-item edit-menu-item-' + d.id; })
73316             .classed('disabled', function (d) { return d.disabled(); })
73317             .attr('transform', function (d, i) {
73318                 return 'translate(' + geoRoundCoords([
73319                     0,
73320                     m + i * buttonHeight
73321                 ]).join(',') + ')';
73322             });
73323
73324         button
73325             .append('rect')
73326             .attr('x', 4)
73327             .attr('width', buttonWidth)
73328             .attr('height', buttonHeight)
73329             .on('click', click)
73330             .on('mousedown', mousedown)
73331             .on('mouseover', mouseover)
73332             .on('mouseout', mouseout);
73333
73334         button
73335             .append('use')
73336             .attr('width', '20')
73337             .attr('height', '20')
73338             .attr('transform', function () {
73339                 return 'translate(' + [2 * p, 5] + ')';
73340             })
73341             .attr('xlink:href', function (d) { return '#operation-' + d.id; });
73342
73343         tooltip = select(document.body)
73344             .append('div')
73345             .attr('class', 'tooltip-inner edit-menu-tooltip');
73346
73347
73348         function click(operation) {
73349             event.stopPropagation();
73350             if (operation.disabled()) return;
73351             operation();
73352             editMenu.close();
73353         }
73354
73355         function mousedown() {
73356             event.stopPropagation();  // https://github.com/openstreetmap/iD/issues/1869
73357         }
73358
73359         function mouseover(d, i) {
73360             var tipX, tipY;
73361
73362             if (!isRTL) {
73363                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
73364             } else {
73365                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
73366             }
73367
73368             if (tipX + tooltipWidth > viewport.right) {
73369                 // tip is going left-to-right and near right viewport edge, go left instead
73370                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
73371             } else if (tipX < viewport.left) {
73372                 // tip is going right-to-left and near left viewport edge, go right instead
73373                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
73374             }
73375
73376             tipY = viewport.top + origin[1] + (i * buttonHeight);
73377             if (tipY + tooltipHeight > viewport.bottom) {
73378                 // tip is near bottom viewport edge, shift upwards
73379                 tipY -= tipY + tooltipHeight - viewport.bottom;
73380             }
73381
73382             tooltip
73383                 .style('left', tipX + 'px')
73384                 .style('top', tipY + 'px')
73385                 .style('display', 'block')
73386                 .html(uiTooltipHtml(d.tooltip(), d.keys[0], d.title));
73387         }
73388
73389         function mouseout() {
73390             tooltip.style('display', 'none');
73391         }
73392     };
73393
73394
73395     editMenu.close = function () {
73396         if (menu) {
73397             menu
73398                 .style('pointer-events', 'none')
73399                 .transition()
73400                 .attr('opacity', 0)
73401                 .remove();
73402         }
73403
73404         if (tooltip) {
73405             tooltip.remove();
73406         }
73407     };
73408
73409
73410     editMenu.center = function (_) {
73411         if (!arguments.length) return center;
73412         center = _;
73413         return editMenu;
73414     };
73415
73416
73417     return editMenu;
73418 }
73419
73420 var timer$1;
73421
73422 function uiFlash(showDuration) {
73423     showDuration = showDuration || 1500;
73424
73425     if (timer$1) {
73426         timer$1.stop();
73427     }
73428
73429     select('#footer-wrap')
73430         .attr('class', 'footer-hide');
73431     select('#flash-wrap')
73432         .attr('class', 'footer-show');
73433
73434     var content = select('#flash-wrap').selectAll('.content')
73435         .data([0]);
73436
73437     content = content.enter()
73438         .append('div')
73439         .attr('class', 'content')
73440         .merge(content);
73441
73442     timer$1 = timeout$1(function() {
73443         timer$1 = null;
73444         select('#footer-wrap')
73445             .attr('class', 'footer-show');
73446         select('#flash-wrap')
73447             .attr('class', 'footer-hide');
73448     }, showDuration);
73449
73450
73451     return content;
73452 }
73453
73454 function uiLasso(context) {
73455     var group, polygon;
73456
73457     lasso.coordinates = [];
73458
73459     function lasso(selection$$1) {
73460         context.container()
73461             .classed('lasso', true);
73462
73463         group = selection$$1
73464             .append('g')
73465             .attr('class', 'lasso hide');
73466
73467         polygon = group
73468             .append('path')
73469             .attr('class', 'lasso-path');
73470
73471         group
73472             .call(uiToggle(true));
73473     }
73474
73475
73476     function draw() {
73477         if (polygon) {
73478             polygon.data([lasso.coordinates])
73479                 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
73480         }
73481     }
73482
73483
73484     lasso.extent = function () {
73485         return lasso.coordinates.reduce(function(extent$$1, point) {
73486             return extent$$1.extend(geoExtent$$1(point));
73487         }, geoExtent$$1());
73488     };
73489
73490
73491     lasso.p = function(_) {
73492         if (!arguments.length) return lasso;
73493         lasso.coordinates.push(_);
73494         draw();
73495         return lasso;
73496     };
73497
73498
73499     lasso.close = function() {
73500         if (group) {
73501             group.call(uiToggle(false, function() {
73502                 select(this).remove();
73503             }));
73504         }
73505         context.container().classed('lasso', false);
73506     };
73507
73508
73509     return lasso;
73510 }
73511
73512 function uiRadialMenu(context, operations) {
73513     var menu,
73514         center = [0, 0],
73515         tooltip;
73516
73517
73518     var radialMenu = function(selection$$1) {
73519         if (!operations.length) return;
73520
73521         selection$$1.node().parentNode.focus();
73522
73523         function click(operation) {
73524             event.stopPropagation();
73525             if (operation.disabled()) return;
73526             operation();
73527             radialMenu.close();
73528         }
73529
73530         menu = selection$$1
73531             .append('g')
73532             .attr('class', 'radial-menu')
73533             .attr('transform', 'translate(' + center + ')')
73534             .attr('opacity', 0);
73535
73536         menu
73537             .transition()
73538             .attr('opacity', 1);
73539
73540         var r = 50,
73541             a = Math.PI / 4,
73542             a0 = -Math.PI / 4,
73543             a1 = a0 + (operations.length - 1) * a;
73544
73545         menu
73546             .append('path')
73547             .attr('class', 'radial-menu-background')
73548             .attr('d', 'M' + r * Math.sin(a0) + ',' +
73549                              r * Math.cos(a0) +
73550                       ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
73551                              (r * Math.sin(a1) + 1e-3) + ',' +
73552                              (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
73553             .attr('stroke-width', 50)
73554             .attr('stroke-linecap', 'round');
73555
73556         var button = menu.selectAll()
73557             .data(operations)
73558             .enter()
73559             .append('g')
73560             .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
73561             .classed('disabled', function(d) { return d.disabled(); })
73562             .attr('transform', function(d, i) {
73563                 return 'translate(' + geoRoundCoords([
73564                         r * Math.sin(a0 + i * a),
73565                         r * Math.cos(a0 + i * a)]).join(',') + ')';
73566             });
73567
73568         button
73569             .append('circle')
73570             .attr('r', 15)
73571             .on('click', click)
73572             .on('mousedown', mousedown)
73573             .on('mouseover', mouseover)
73574             .on('mouseout', mouseout);
73575
73576         button
73577             .append('use')
73578             .attr('transform', 'translate(-10,-10)')
73579             .attr('width', '20')
73580             .attr('height', '20')
73581             .attr('xlink:href', function(d) { return '#operation-' + d.id; });
73582
73583         tooltip = select(document.body)
73584             .append('div')
73585             .attr('class', 'tooltip-inner radial-menu-tooltip');
73586
73587         function mousedown() {
73588             event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
73589         }
73590
73591         function mouseover(d, i) {
73592             var rect = context.surfaceRect(),
73593                 angle = a0 + i * a,
73594                 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
73595                 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
73596                 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
73597                 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
73598
73599             tooltip
73600                 .style('top', null)
73601                 .style('left', null)
73602                 .style('bottom', null)
73603                 .style('right', null)
73604                 .style('display', 'block')
73605                 .html(uiTooltipHtml(d.tooltip(), d.keys[0]));
73606
73607             if (i === 0) {
73608                 tooltip
73609                     .style('right', right)
73610                     .style('top', top);
73611             } else if (i >= 4) {
73612                 tooltip
73613                     .style('left', left)
73614                     .style('bottom', bottom);
73615             } else {
73616                 tooltip
73617                     .style('left', left)
73618                     .style('top', top);
73619             }
73620         }
73621
73622         function mouseout() {
73623             tooltip.style('display', 'none');
73624         }
73625     };
73626
73627
73628     radialMenu.close = function() {
73629         if (menu) {
73630             menu
73631                 .style('pointer-events', 'none')
73632                 .transition()
73633                 .attr('opacity', 0)
73634                 .remove();
73635         }
73636
73637         if (tooltip) {
73638             tooltip.remove();
73639         }
73640     };
73641
73642
73643     radialMenu.center = function(_) {
73644         if (!arguments.length) return center;
73645         center = _;
73646         return radialMenu;
73647     };
73648
73649
73650     return radialMenu;
73651 }
73652
73653 function uiSelectionList(context, selectedIDs) {
73654
73655     function selectEntity(entity) {
73656         context.enter(modeSelect(context, [entity.id]));
73657     }
73658
73659
73660     function deselectEntity(entity) {
73661         event.stopPropagation();
73662         var index = selectedIDs.indexOf(entity.id);
73663         if (index > -1) {
73664             selectedIDs.splice(index, 1);
73665         }
73666         context.enter(modeSelect(context, selectedIDs));
73667     }
73668
73669
73670     function selectionList(selection$$1) {
73671         selection$$1.classed('selection-list-pane', true);
73672
73673         var header = selection$$1
73674             .append('div')
73675             .attr('class', 'header fillL cf');
73676
73677         header
73678             .append('h3')
73679             .text(t('inspector.multiselect'));
73680
73681         var listWrap = selection$$1
73682             .append('div')
73683             .attr('class', 'inspector-body');
73684
73685         var list = listWrap
73686             .append('div')
73687             .attr('class', 'feature-list cf');
73688
73689         context.history().on('change.selection-list', drawList);
73690         drawList();
73691
73692
73693         function drawList() {
73694             var entities = selectedIDs
73695                 .map(function(id) { return context.hasEntity(id); })
73696                 .filter(function(entity) { return entity; });
73697
73698             var items = list.selectAll('.feature-list-item')
73699                 .data(entities, osmEntity$$1.key);
73700
73701             items.exit()
73702                 .remove();
73703
73704             // Enter
73705             var enter = items.enter()
73706                 .append('div')
73707                 .attr('class', 'feature-list-item')
73708                 .on('click', selectEntity);
73709
73710             var label = enter
73711                 .append('button')
73712                 .attr('class', 'label');
73713
73714             enter
73715                 .append('button')
73716                 .attr('class', 'close')
73717                 .on('click', deselectEntity)
73718                 .call(svgIcon('#icon-close'));
73719
73720             label
73721                 .append('span')
73722                 .attr('class', 'entity-geom-icon')
73723                 .call(svgIcon('', 'pre-text'));
73724
73725             label
73726                 .append('span')
73727                 .attr('class', 'entity-type');
73728
73729             label
73730                 .append('span')
73731                 .attr('class', 'entity-name');
73732
73733             // Update
73734             items = items.merge(enter);
73735
73736             items.selectAll('.entity-geom-icon use')
73737                 .attr('href', function() {
73738                     var entity = this.parentNode.parentNode.__data__;
73739                     return '#icon-' + context.geometry(entity.id);
73740                 });
73741
73742             items.selectAll('.entity-type')
73743                 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
73744
73745             items.selectAll('.entity-name')
73746                 .text(function(entity) { return utilDisplayName(entity); });
73747         }
73748     }
73749
73750     return selectionList;
73751 }
73752
73753 function uiSourceSwitch(context) {
73754     var keys$$1;
73755
73756
73757     function click() {
73758         event.preventDefault();
73759
73760         if (context.history().hasChanges() &&
73761             !window.confirm(t('source_switch.lose_changes'))) return;
73762
73763         var live = select(this)
73764             .classed('live');
73765
73766         context.connection()
73767             .switch(live ? keys$$1[1] : keys$$1[0]);
73768
73769         context.enter(modeBrowse(context));
73770         context.flush();
73771
73772         select(this)
73773             .text(live ? t('source_switch.dev') : t('source_switch.live'))
73774             .classed('live', !live);
73775     }
73776
73777     var sourceSwitch = function(selection$$1) {
73778         selection$$1
73779             .append('a')
73780             .attr('href', '#')
73781             .text(t('source_switch.live'))
73782             .classed('live', true)
73783             .attr('tabindex', -1)
73784             .on('click', click);
73785     };
73786
73787
73788     sourceSwitch.keys = function(_) {
73789         if (!arguments.length) return keys$$1;
73790         keys$$1 = _;
73791         return sourceSwitch;
73792     };
73793
73794
73795     return sourceSwitch;
73796 }
73797
73798 function uiSuccess(context) {
73799     var dispatch$$1 = dispatch('cancel'),
73800         changeset;
73801
73802
73803     function success(selection$$1) {
73804         var header = selection$$1
73805             .append('div')
73806             .attr('class', 'header fillL');
73807
73808         header
73809             .append('button')
73810             .attr('class', 'fr')
73811             .on('click', function() { dispatch$$1.call('cancel'); })
73812             .call(svgIcon('#icon-close'));
73813
73814         header
73815             .append('h3')
73816             .text(t('success.just_edited'));
73817
73818         var body = selection$$1
73819             .append('div')
73820             .attr('class', 'body save-success fillL');
73821
73822         body
73823             .append('p')
73824             .html(t('success.help_html'));
73825
73826         body
73827             .append('a')
73828             .attr('class', 'details')
73829             .attr('target', '_blank')
73830             .attr('tabindex', -1)
73831             .call(svgIcon('#icon-out-link', 'inline'))
73832             .attr('href', t('success.help_link_url'))
73833             .append('span')
73834             .text(t('success.help_link_text'));
73835
73836         var changesetURL = context.connection().changesetURL(changeset.id);
73837
73838
73839         var viewOnOsm = body
73840             .append('a')
73841             .attr('class', 'button col12 osm')
73842             .attr('target', '_blank')
73843             .attr('href', changesetURL);
73844
73845         viewOnOsm
73846             .append('svg')
73847             .attr('class', 'logo logo-osm')
73848             .append('use')
73849             .attr('xlink:href', '#logo-osm');
73850
73851         viewOnOsm
73852             .append('div')
73853             .text(t('success.view_on_osm'));
73854
73855
73856         var message = (changeset.tags.comment || t('success.edited_osm')).substring(0, 130) +
73857             ' ' + context.connection().changesetURL(changeset.id);
73858
73859         var sharing = {
73860             facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
73861             twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
73862             google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
73863         };
73864
73865         body.selectAll('.button.social')
73866             .data(entries(sharing))
73867             .enter()
73868             .append('a')
73869             .attr('class', 'button social col4')
73870             .attr('target', '_blank')
73871             .attr('href', function(d) { return d.value; })
73872             .call(tooltip()
73873                 .title(function(d) { return t('success.' + d.key); })
73874                 .placement('bottom'))
73875             .each(function(d) { select(this).call(svgIcon('#logo-' + d.key, 'social')); });
73876     }
73877
73878
73879     success.changeset = function(_) {
73880         if (!arguments.length) return changeset;
73881         changeset = _;
73882         return success;
73883     };
73884
73885
73886     return utilRebind(success, dispatch$$1, 'on');
73887 }
73888
73889 function coreHistory(context) {
73890     var imageryUsed = ['Bing'],
73891         dispatch$$1 = dispatch('change', 'undone', 'redone'),
73892         lock = utilSessionMutex('lock'),
73893         duration = 150,
73894         checkpoints = {},
73895         stack$$1, index, tree$$1;
73896
73897
73898     // internal _act, accepts list of actions and eased time
73899     function _act(actions, t) {
73900         actions = Array.prototype.slice.call(actions);
73901
73902         var annotation;
73903
73904         if (!lodash.isFunction(lodash.last(actions))) {
73905             annotation = actions.pop();
73906         }
73907
73908         stack$$1[index].transform = context.projection.transform();
73909         stack$$1[index].selectedIDs = context.selectedIDs();
73910
73911         var graph = stack$$1[index].graph;
73912         for (var i = 0; i < actions.length; i++) {
73913             graph = actions[i](graph, t);
73914         }
73915
73916         return {
73917             graph: graph,
73918             annotation: annotation,
73919             imageryUsed: imageryUsed
73920         };
73921     }
73922
73923
73924     // internal _perform with eased time
73925     function _perform(args, t) {
73926         var previous = stack$$1[index].graph;
73927         stack$$1 = stack$$1.slice(0, index + 1);
73928         stack$$1.push(_act(args, t));
73929         index++;
73930         return change(previous);
73931     }
73932
73933
73934     // internal _replace with eased time
73935     function _replace(args, t) {
73936         var previous = stack$$1[index].graph;
73937         // assert(index == stack.length - 1)
73938         stack$$1[index] = _act(args, t);
73939         return change(previous);
73940     }
73941
73942
73943     // internal _overwrite with eased time
73944     function _overwrite(args, t) {
73945         var previous = stack$$1[index].graph;
73946         if (index > 0) {
73947             index--;
73948             stack$$1.pop();
73949         }
73950         stack$$1 = stack$$1.slice(0, index + 1);
73951         stack$$1.push(_act(args, t));
73952         index++;
73953         return change(previous);
73954     }
73955
73956
73957     // determine diffrence and dispatch a change event
73958     function change(previous) {
73959         var difference = coreDifference(previous, history.graph());
73960         dispatch$$1.call('change', this, difference);
73961         return difference;
73962     }
73963
73964
73965     // iD uses namespaced keys so multiple installations do not conflict
73966     function getKey(n) {
73967         return 'iD_' + window.location.origin + '_' + n;
73968     }
73969
73970
73971     var history = {
73972
73973         graph: function() {
73974             return stack$$1[index].graph;
73975         },
73976
73977
73978         base: function() {
73979             return stack$$1[0].graph;
73980         },
73981
73982
73983         merge: function(entities, extent$$1) {
73984             stack$$1[0].graph.rebase(entities, lodash.map(stack$$1, 'graph'), false);
73985             tree$$1.rebase(entities, false);
73986
73987             dispatch$$1.call('change', this, undefined, extent$$1);
73988         },
73989
73990
73991         perform: function() {
73992             // complete any transition already in progress
73993             select(document).interrupt('history.perform');
73994
73995             var transitionable = false,
73996                 action0 = arguments[0];
73997
73998             if (arguments.length === 1 ||
73999                 arguments.length === 2 && !lodash.isFunction(arguments[1])) {
74000                 transitionable = !!action0.transitionable;
74001             }
74002
74003             if (transitionable) {
74004                 var origArguments = arguments;
74005                 select(document)
74006                     .transition('history.perform')
74007                     .duration(duration)
74008                     .ease(linear$1)
74009                     .tween('history.tween', function() {
74010                         return function(t) {
74011                             if (t < 1) _overwrite([action0], t);
74012                         };
74013                     })
74014                     .on('start', function() {
74015                         _perform([action0], 0);
74016                     })
74017                     .on('end interrupt', function() {
74018                         _overwrite(origArguments, 1);
74019                     });
74020
74021             } else {
74022                 return _perform(arguments);
74023             }
74024         },
74025
74026
74027         replace: function() {
74028             select(document).interrupt('history.perform');
74029             return _replace(arguments, 1);
74030         },
74031
74032
74033         // Same as calling pop and then perform
74034         overwrite: function() {
74035             select(document).interrupt('history.perform');
74036             return _overwrite(arguments, 1);
74037         },
74038
74039
74040         pop: function(n) {
74041             select(document).interrupt('history.perform');
74042
74043             var previous = stack$$1[index].graph;
74044             if (isNaN(+n) || +n < 0) {
74045                 n = 1;
74046             }
74047             while (n-- > 0 && index > 0) {
74048                 index--;
74049                 stack$$1.pop();
74050             }
74051             return change(previous);
74052         },
74053
74054
74055         // Back to the previous annotated state or index = 0.
74056         undo: function() {
74057             select(document).interrupt('history.perform');
74058
74059             var previous = stack$$1[index].graph;
74060             while (index > 0) {
74061                 index--;
74062                 if (stack$$1[index].annotation) break;
74063             }
74064
74065             dispatch$$1.call('undone', this, stack$$1[index]);
74066             return change(previous);
74067         },
74068
74069
74070         // Forward to the next annotated state.
74071         redo: function() {
74072             select(document).interrupt('history.perform');
74073
74074             var previous = stack$$1[index].graph;
74075             var tryIndex = index;
74076             while (tryIndex < stack$$1.length - 1) {
74077                 tryIndex++;
74078                 if (stack$$1[tryIndex].annotation) {
74079                     index = tryIndex;
74080                     dispatch$$1.call('redone', this, stack$$1[index]);
74081                     break;
74082                 }
74083             }
74084
74085             return change(previous);
74086         },
74087
74088
74089         undoAnnotation: function() {
74090             var i = index;
74091             while (i >= 0) {
74092                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
74093                 i--;
74094             }
74095         },
74096
74097
74098         redoAnnotation: function() {
74099             var i = index + 1;
74100             while (i <= stack$$1.length - 1) {
74101                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
74102                 i++;
74103             }
74104         },
74105
74106
74107         intersects: function(extent$$1) {
74108             return tree$$1.intersects(extent$$1, stack$$1[index].graph);
74109         },
74110
74111
74112         difference: function() {
74113             var base = stack$$1[0].graph,
74114                 head = stack$$1[index].graph;
74115             return coreDifference(base, head);
74116         },
74117
74118
74119         changes: function(action) {
74120             var base = stack$$1[0].graph,
74121                 head = stack$$1[index].graph;
74122
74123             if (action) {
74124                 head = action(head);
74125             }
74126
74127             var difference = coreDifference(base, head);
74128
74129             return {
74130                 modified: difference.modified(),
74131                 created: difference.created(),
74132                 deleted: difference.deleted()
74133             };
74134         },
74135
74136
74137         validate: function(changes) {
74138             return lodash(Validations)
74139                 .map(function(fn) { return fn()(changes, stack$$1[index].graph); })
74140                 .flatten()
74141                 .value();
74142         },
74143
74144
74145         hasChanges: function() {
74146             return this.difference().length() > 0;
74147         },
74148
74149
74150         imageryUsed: function(sources) {
74151             if (sources) {
74152                 imageryUsed = sources;
74153                 return history;
74154             } else {
74155                 return lodash(stack$$1.slice(1, index + 1))
74156                     .map('imageryUsed')
74157                     .flatten()
74158                     .uniq()
74159                     .without(undefined, 'Custom')
74160                     .value();
74161             }
74162         },
74163
74164
74165         // save the current history state
74166         checkpoint: function(key) {
74167             checkpoints[key] = {
74168                 stack: lodash.cloneDeep(stack$$1),
74169                 index: index
74170             };
74171             return history;
74172         },
74173
74174
74175         // restore history state to a given checkpoint or reset completely
74176         reset: function(key) {
74177             if (key !== undefined && checkpoints.hasOwnProperty(key)) {
74178                 stack$$1 = lodash.cloneDeep(checkpoints[key].stack);
74179                 index = checkpoints[key].index;
74180             } else {
74181                 stack$$1 = [{graph: coreGraph$$1()}];
74182                 index = 0;
74183                 tree$$1 = coreTree(stack$$1[0].graph);
74184                 checkpoints = {};
74185             }
74186             dispatch$$1.call('change');
74187             return history;
74188         },
74189
74190
74191         toIntroGraph: function() {
74192             var nextId = { n: 0, r: 0, w: 0 },
74193                 permIds = {},
74194                 graph = this.graph(),
74195                 baseEntities = {};
74196
74197             // clone base entities..
74198             lodash.forEach(graph.base().entities, function(entity) {
74199                 var copy = lodash.cloneDeepWith(entity, customizer);
74200                 baseEntities[copy.id] = copy;
74201             });
74202
74203             // replace base entities with head entities..
74204             lodash.forEach(graph.entities, function(entity, id) {
74205                 if (entity) {
74206                     var copy = lodash.cloneDeepWith(entity, customizer);
74207                     baseEntities[copy.id] = copy;
74208                 } else {
74209                     delete baseEntities[id];
74210                 }
74211             });
74212
74213             // swap temporary for permanent ids..
74214             lodash.forEach(baseEntities, function(entity) {
74215                 if (Array.isArray(entity.nodes)) {
74216                     entity.nodes = entity.nodes.map(function(node) {
74217                         return permIds[node] || node;
74218                     });
74219                 }
74220                 if (Array.isArray(entity.members)) {
74221                     entity.members = entity.members.map(function(member) {
74222                         member.id = permIds[member.id] || member.id;
74223                         return member;
74224                     });
74225                 }
74226             });
74227
74228             return JSON.stringify({ dataIntroGraph: baseEntities });
74229
74230
74231             function customizer(src) {
74232                 var copy = lodash.omit(lodash.cloneDeep(src), ['type', 'user', 'v', 'version', 'visible']);
74233                 if (lodash.isEmpty(copy.tags)) {
74234                     delete copy.tags;
74235                 }
74236
74237                 if (Array.isArray(copy.loc)) {
74238                     copy.loc[0] = +copy.loc[0].toFixed(6);
74239                     copy.loc[1] = +copy.loc[1].toFixed(6);
74240                 }
74241
74242                 var match = src.id.match(/([nrw])-\d*/);  // temporary id
74243                 if (match !== null) {
74244                     var nrw = match[1], permId;
74245                     do { permId = nrw + (++nextId[nrw]); }
74246                     while (baseEntities.hasOwnProperty(permId));
74247
74248                     copy.id = permIds[src.id] = permId;
74249                 }
74250                 return copy;
74251             }
74252         },
74253
74254
74255         toJSON: function() {
74256             if (!this.hasChanges()) return;
74257
74258             var allEntities = {},
74259                 baseEntities = {},
74260                 base = stack$$1[0];
74261
74262             var s = stack$$1.map(function(i) {
74263                 var modified = [], deleted = [];
74264
74265                 lodash.forEach(i.graph.entities, function(entity, id) {
74266                     if (entity) {
74267                         var key = osmEntity$$1.key(entity);
74268                         allEntities[key] = entity;
74269                         modified.push(key);
74270                     } else {
74271                         deleted.push(id);
74272                     }
74273
74274                     // make sure that the originals of changed or deleted entities get merged
74275                     // into the base of the stack after restoring the data from JSON.
74276                     if (id in base.graph.entities) {
74277                         baseEntities[id] = base.graph.entities[id];
74278                     }
74279                     // get originals of parent entities too
74280                     lodash.forEach(base.graph._parentWays[id], function(parentId) {
74281                         if (parentId in base.graph.entities) {
74282                             baseEntities[parentId] = base.graph.entities[parentId];
74283                         }
74284                     });
74285                 });
74286
74287                 var x = {};
74288
74289                 if (modified.length) x.modified = modified;
74290                 if (deleted.length) x.deleted = deleted;
74291                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
74292                 if (i.annotation) x.annotation = i.annotation;
74293
74294                 return x;
74295             });
74296
74297             return JSON.stringify({
74298                 version: 3,
74299                 entities: lodash.values(allEntities),
74300                 baseEntities: lodash.values(baseEntities),
74301                 stack: s,
74302                 nextIDs: osmEntity$$1.id.next,
74303                 index: index
74304             });
74305         },
74306
74307
74308         fromJSON: function(json$$1, loadChildNodes) {
74309             var h = JSON.parse(json$$1),
74310                 loadComplete = true;
74311
74312             osmEntity$$1.id.next = h.nextIDs;
74313             index = h.index;
74314
74315             if (h.version === 2 || h.version === 3) {
74316                 var allEntities = {};
74317
74318                 h.entities.forEach(function(entity) {
74319                     allEntities[osmEntity$$1.key(entity)] = osmEntity$$1(entity);
74320                 });
74321
74322                 if (h.version === 3) {
74323                     // This merges originals for changed entities into the base of
74324                     // the stack even if the current stack doesn't have them (for
74325                     // example when iD has been restarted in a different region)
74326                     var baseEntities = h.baseEntities.map(function(d) { return osmEntity$$1(d); });
74327                     stack$$1[0].graph.rebase(baseEntities, lodash.map(stack$$1, 'graph'), true);
74328                     tree$$1.rebase(baseEntities, true);
74329
74330                     // When we restore a modified way, we also need to fetch any missing
74331                     // childnodes that would normally have been downloaded with it.. #2142
74332                     if (loadChildNodes) {
74333                         var missing =  lodash(baseEntities)
74334                                 .filter({ type: 'way' })
74335                                 .map('nodes')
74336                                 .flatten()
74337                                 .uniq()
74338                                 .reject(function(n) { return stack$$1[0].graph.hasEntity(n); })
74339                                 .value();
74340
74341                         if (!lodash.isEmpty(missing)) {
74342                             loadComplete = false;
74343                             context.redrawEnable(false);
74344
74345                             var loading = uiLoading(context).blocking(true);
74346                             context.container().call(loading);
74347
74348                             var childNodesLoaded = function(err, result) {
74349                                 if (!err) {
74350                                     var visible = lodash.groupBy(result.data, 'visible');
74351                                     if (!lodash.isEmpty(visible.true)) {
74352                                         missing = lodash.difference(missing, lodash.map(visible.true, 'id'));
74353                                         stack$$1[0].graph.rebase(visible.true, lodash.map(stack$$1, 'graph'), true);
74354                                         tree$$1.rebase(visible.true, true);
74355                                     }
74356
74357                                     // fetch older versions of nodes that were deleted..
74358                                     lodash.each(visible.false, function(entity) {
74359                                         context.connection()
74360                                             .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
74361                                     });
74362                                 }
74363
74364                                 if (err || lodash.isEmpty(missing)) {
74365                                     loading.close();
74366                                     context.redrawEnable(true);
74367                                     dispatch$$1.call('change');
74368                                 }
74369                             };
74370
74371                             context.connection().loadMultiple(missing, childNodesLoaded);
74372                         }
74373                     }
74374                 }
74375
74376                 stack$$1 = h.stack.map(function(d) {
74377                     var entities = {}, entity;
74378
74379                     if (d.modified) {
74380                         d.modified.forEach(function(key) {
74381                             entity = allEntities[key];
74382                             entities[entity.id] = entity;
74383                         });
74384                     }
74385
74386                     if (d.deleted) {
74387                         d.deleted.forEach(function(id) {
74388                             entities[id] = undefined;
74389                         });
74390                     }
74391
74392                     return {
74393                         graph: coreGraph$$1(stack$$1[0].graph).load(entities),
74394                         annotation: d.annotation,
74395                         imageryUsed: d.imageryUsed
74396                     };
74397                 });
74398
74399             } else { // original version
74400                 stack$$1 = h.stack.map(function(d) {
74401                     var entities = {};
74402
74403                     for (var i in d.entities) {
74404                         var entity = d.entities[i];
74405                         entities[i] = entity === 'undefined' ? undefined : osmEntity$$1(entity);
74406                     }
74407
74408                     d.graph = coreGraph$$1(stack$$1[0].graph).load(entities);
74409                     return d;
74410                 });
74411             }
74412
74413             if (loadComplete) {
74414                 dispatch$$1.call('change');
74415             }
74416
74417             return history;
74418         },
74419
74420
74421         save: function() {
74422             if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
74423             return history;
74424         },
74425
74426
74427         clearSaved: function() {
74428             context.debouncedSave.cancel();
74429             if (lock.locked()) context.storage(getKey('saved_history'), null);
74430             return history;
74431         },
74432
74433
74434         lock: function() {
74435             return lock.lock();
74436         },
74437
74438
74439         unlock: function() {
74440             lock.unlock();
74441         },
74442
74443
74444         // is iD not open in another window and it detects that
74445         // there's a history stored in localStorage that's recoverable?
74446         restorableChanges: function() {
74447             return lock.locked() && !!context.storage(getKey('saved_history'));
74448         },
74449
74450
74451         // load history from a version stored in localStorage
74452         restore: function() {
74453             if (!lock.locked()) return;
74454
74455             var json$$1 = context.storage(getKey('saved_history'));
74456             if (json$$1) history.fromJSON(json$$1, true);
74457         },
74458
74459
74460         _getKey: getKey
74461
74462     };
74463
74464
74465     history.reset();
74466
74467     return utilRebind(history, dispatch$$1, 'on');
74468 }
74469
74470 function presetCollection(collection) {
74471     var maxSearchResults = 50,
74472         maxSuggestionResults = 10;
74473
74474     var presets = {
74475
74476         collection: collection,
74477
74478
74479         item: function(id) {
74480             return lodash.find(this.collection, function(d) {
74481                 return d.id === id;
74482             });
74483         },
74484
74485
74486         matchGeometry: function(geometry) {
74487             return presetCollection(this.collection.filter(function(d) {
74488                 return d.matchGeometry(geometry);
74489             }));
74490         },
74491
74492
74493         search: function(value, geometry) {
74494             if (!value) return this;
74495
74496             function leading(a) {
74497                 var index = a.indexOf(value);
74498                 return index === 0 || a[index - 1] === ' ';
74499             }
74500
74501             function suggestionName(name) {
74502                 var nameArray = name.split(' - ');
74503                 if (nameArray.length > 1) {
74504                     name = nameArray.slice(0, nameArray.length - 1).join(' - ');
74505                 }
74506                 return name.toLowerCase();
74507             }
74508
74509
74510             value = value.toLowerCase();
74511
74512             var searchable = lodash.filter(this.collection, function(a) {
74513                     return a.searchable !== false && a.suggestion !== true;
74514                 }),
74515                 suggestions = lodash.filter(this.collection, function(a) {
74516                     return a.suggestion === true;
74517                 });
74518
74519
74520             // matches value to preset.name
74521             var leading_name = lodash.filter(searchable, function(a) {
74522                     return leading(a.name().toLowerCase());
74523                 }).sort(function(a, b) {
74524                     var i;
74525                     i = b.originalScore - a.originalScore;
74526                     if (i !== 0) return i;
74527
74528                     i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
74529                     if (i !== 0) return i;
74530
74531                     return a.name().length - b.name().length;
74532                 });
74533
74534             // matches value to preset.terms values
74535             var leading_terms = lodash.filter(searchable, function(a) {
74536                     return lodash.some(a.terms() || [], leading);
74537                 });
74538
74539             // matches value to preset.tags values
74540             var leading_tag_values = lodash.filter(searchable, function(a) {
74541                     return lodash.some(lodash.without(lodash.values(a.tags || {}), '*'), leading);
74542                 });
74543
74544
74545             // finds close matches to value in preset.name
74546             var similar_name = searchable.map(function(a) {
74547                     return {
74548                         preset: a,
74549                         dist: utilEditDistance(value, a.name())
74550                     };
74551                 }).filter(function(a) {
74552                     return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
74553                 }).sort(function(a, b) {
74554                     return a.dist - b.dist;
74555                 }).map(function(a) {
74556                     return a.preset;
74557                 });
74558
74559             // finds close matches to value in preset.terms
74560             var similar_terms = lodash.filter(searchable, function(a) {
74561                     return lodash.some(a.terms() || [], function(b) {
74562                         return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
74563                     });
74564                 });
74565
74566             var leading_suggestions = lodash.filter(suggestions, function(a) {
74567                     return leading(suggestionName(a.name()));
74568                 }).sort(function(a, b) {
74569                     a = suggestionName(a.name());
74570                     b = suggestionName(b.name());
74571                     var i = a.indexOf(value) - b.indexOf(value);
74572                     if (i === 0) return a.length - b.length;
74573                     else return i;
74574                 });
74575
74576             var similar_suggestions = suggestions.map(function(a) {
74577                     return {
74578                         preset: a,
74579                         dist: utilEditDistance(value, suggestionName(a.name()))
74580                     };
74581                 }).filter(function(a) {
74582                     return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
74583                 }).sort(function(a, b) {
74584                     return a.dist - b.dist;
74585                 }).map(function(a) {
74586                     return a.preset;
74587                 });
74588
74589             var other = presets.item(geometry);
74590
74591             var results = leading_name.concat(
74592                     leading_terms,
74593                     leading_tag_values,
74594                     leading_suggestions.slice(0, maxSuggestionResults + 5),
74595                     similar_name,
74596                     similar_terms,
74597                     similar_suggestions.slice(0, maxSuggestionResults)
74598                 ).slice(0, maxSearchResults - 1);
74599
74600             return presetCollection(lodash.uniq(results.concat(other)));
74601         }
74602     };
74603
74604
74605     return presets;
74606 }
74607
74608 function presetCategory(id, category, all) {
74609     category = lodash.clone(category);
74610
74611     category.id = id;
74612
74613
74614     category.members = presetCollection(category.members.map(function(id) {
74615         return all.item(id);
74616     }));
74617
74618
74619     category.matchGeometry = function(geometry) {
74620         return category.geometry.indexOf(geometry) >= 0;
74621     };
74622
74623
74624     category.matchScore = function() {
74625         return -1;
74626     };
74627
74628
74629     category.name = function() {
74630         return t('presets.categories.' + id + '.name', {'default': id});
74631     };
74632
74633
74634     category.terms = function() {
74635         return [];
74636     };
74637
74638
74639     return category;
74640 }
74641
74642 function presetField(id, field) {
74643     field = lodash.clone(field);
74644
74645     field.id = id;
74646
74647
74648     field.matchGeometry = function(geometry) {
74649         return !field.geometry || field.geometry === geometry;
74650     };
74651
74652
74653     field.t = function(scope, options) {
74654         return t('presets.fields.' + id + '.' + scope, options);
74655     };
74656
74657
74658     field.label = function() {
74659         return field.t('label', {'default': id});
74660     };
74661
74662
74663     var placeholder = field.placeholder;
74664     field.placeholder = function() {
74665         return field.t('placeholder', {'default': placeholder});
74666     };
74667
74668
74669     return field;
74670 }
74671
74672 function presetPreset(id, preset, fields) {
74673     preset = lodash.clone(preset);
74674
74675     preset.id = id;
74676     preset.fields = (preset.fields || []).map(getFields);
74677     preset.geometry = (preset.geometry || []);
74678
74679
74680     function getFields(f) {
74681         return fields[f];
74682     }
74683
74684
74685     preset.matchGeometry = function(geometry) {
74686         return preset.geometry.indexOf(geometry) >= 0;
74687     };
74688
74689
74690     preset.originalScore = preset.matchScore || 1;
74691
74692
74693     preset.matchScore = function(entity) {
74694         var tags = preset.tags,
74695             score = 0;
74696
74697         for (var t$$1 in tags) {
74698             if (entity.tags[t$$1] === tags[t$$1]) {
74699                 score += preset.originalScore;
74700             } else if (tags[t$$1] === '*' && t$$1 in entity.tags) {
74701                 score += preset.originalScore / 2;
74702             } else {
74703                 return -1;
74704             }
74705         }
74706
74707         return score;
74708     };
74709
74710
74711     preset.t = function(scope, options) {
74712         return t('presets.presets.' + id + '.' + scope, options);
74713     };
74714
74715
74716     var name = preset.name || '';
74717     preset.name = function() {
74718         if (preset.suggestion) {
74719             id = id.split('/');
74720             id = id[0] + '/' + id[1];
74721             return name + ' - ' + t('presets.presets.' + id + '.name');
74722         }
74723         return preset.t('name', {'default': name});
74724     };
74725
74726
74727     preset.terms = function() {
74728         return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
74729     };
74730
74731
74732     preset.isFallback = function() {
74733         var tagCount = Object.keys(preset.tags).length;
74734         return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
74735     };
74736
74737
74738     var reference = preset.reference || {};
74739     preset.reference = function(geometry) {
74740         var key = reference.key || Object.keys(lodash.omit(preset.tags, 'name'))[0],
74741             value = reference.value || preset.tags[key];
74742
74743         if (geometry === 'relation' && key === 'type') {
74744             if (value in preset.tags) {
74745                 key = value;
74746                 value = preset.tags[key];
74747             } else {
74748                 return { rtype: value };
74749             }
74750         }
74751
74752         if (value === '*') {
74753             return { key: key };
74754         } else {
74755             return { key: key, value: value };
74756         }
74757     };
74758
74759
74760     var removeTags = preset.removeTags || preset.tags;
74761     preset.removeTags = function(tags, geometry) {
74762         tags = lodash.omit(tags, lodash.keys(removeTags));
74763
74764         for (var f in preset.fields) {
74765             var field = preset.fields[f];
74766             if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
74767                 delete tags[field.key];
74768             }
74769         }
74770
74771         delete tags.area;
74772         return tags;
74773     };
74774
74775
74776     var applyTags = preset.addTags || preset.tags;
74777     preset.applyTags = function(tags, geometry) {
74778         var k;
74779
74780         tags = lodash.clone(tags);
74781
74782         for (k in applyTags) {
74783             if (applyTags[k] === '*') {
74784                 tags[k] = 'yes';
74785             } else {
74786                 tags[k] = applyTags[k];
74787             }
74788         }
74789
74790         // Add area=yes if necessary.
74791         // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
74792         // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
74793         // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
74794         delete tags.area;
74795         if (geometry === 'area') {
74796             var needsAreaTag = true;
74797             if (preset.geometry.indexOf('line') === -1) {
74798                 for (k in applyTags) {
74799                     if (k in areaKeys) {
74800                         needsAreaTag = false;
74801                         break;
74802                     }
74803                 }
74804             }
74805             if (needsAreaTag) {
74806                 tags.area = 'yes';
74807             }
74808         }
74809
74810         for (var f in preset.fields) {
74811             var field = preset.fields[f];
74812             if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
74813                 tags[field.key] = field.default;
74814             }
74815         }
74816
74817         return tags;
74818     };
74819
74820
74821     return preset;
74822 }
74823
74824 function presetIndex() {
74825     // a presetCollection with methods for
74826     // loading new data and returning defaults
74827
74828     var all = presetCollection([]),
74829         defaults = { area: all, line: all, point: all, vertex: all, relation: all },
74830         fields = {},
74831         universal = [],
74832         recent = presetCollection([]);
74833
74834     // Index of presets by (geometry, tag key).
74835     var index = {
74836         point: {},
74837         vertex: {},
74838         line: {},
74839         area: {},
74840         relation: {}
74841     };
74842
74843     all.match = function(entity, resolver) {
74844         var geometry = entity.geometry(resolver);
74845
74846         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
74847         if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
74848             geometry = 'point';
74849         }
74850
74851         var geometryMatches = index[geometry],
74852             best = -1,
74853             match;
74854
74855         for (var k in entity.tags) {
74856             var keyMatches = geometryMatches[k];
74857             if (!keyMatches) continue;
74858
74859             for (var i = 0; i < keyMatches.length; i++) {
74860                 var score = keyMatches[i].matchScore(entity);
74861                 if (score > best) {
74862                     best = score;
74863                     match = keyMatches[i];
74864                 }
74865             }
74866         }
74867
74868         return match || all.item(geometry);
74869     };
74870
74871
74872     // Because of the open nature of tagging, iD will never have a complete
74873     // list of tags used in OSM, so we want it to have logic like "assume
74874     // that a closed way with an amenity tag is an area, unless the amenity
74875     // is one of these specific types". This function computes a structure
74876     // that allows testing of such conditions, based on the presets designated
74877     // as as supporting (or not supporting) the area geometry.
74878     //
74879     // The returned object L is a whitelist/blacklist of tags. A closed way
74880     // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
74881     // (see `Way#isArea()`). In other words, the keys of L form the whitelist,
74882     // and the subkeys form the blacklist.
74883     all.areaKeys = function() {
74884         var areaKeys = {},
74885             ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],  // probably a line..
74886             presets = lodash.reject(all.collection, 'suggestion');
74887
74888         // whitelist
74889         presets.forEach(function(d) {
74890             for (var key in d.tags) break;
74891             if (!key) return;
74892             if (ignore.indexOf(key) !== -1) return;
74893
74894             if (d.geometry.indexOf('area') !== -1) {    // probably an area..
74895                 areaKeys[key] = areaKeys[key] || {};
74896             }
74897         });
74898
74899         // blacklist
74900         presets.forEach(function(d) {
74901             for (var key in d.tags) break;
74902             if (!key) return;
74903             if (ignore.indexOf(key) !== -1) return;
74904
74905             var value = d.tags[key];
74906             if (key in areaKeys &&                      // probably an area...
74907                 d.geometry.indexOf('line') !== -1 &&    // but sometimes a line
74908                 value !== '*') {
74909                 areaKeys[key][value] = true;
74910             }
74911         });
74912
74913         return areaKeys;
74914     };
74915
74916
74917     all.init = function() {
74918         var d = data.presets;
74919
74920         all.collection = [];
74921         recent.collection = [];
74922         fields = {};
74923         universal = [];
74924         index = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
74925
74926         if (d.fields) {
74927             lodash.forEach(d.fields, function(d, id) {
74928                 fields[id] = presetField(id, d);
74929                 if (d.universal) universal.push(fields[id]);
74930             });
74931         }
74932
74933         if (d.presets) {
74934             lodash.forEach(d.presets, function(d, id) {
74935                 all.collection.push(presetPreset(id, d, fields));
74936             });
74937         }
74938
74939         if (d.categories) {
74940             lodash.forEach(d.categories, function(d, id) {
74941                 all.collection.push(presetCategory(id, d, all));
74942             });
74943         }
74944
74945         if (d.defaults) {
74946             var getItem = lodash.bind(all.item, all);
74947             defaults = {
74948                 area: presetCollection(d.defaults.area.map(getItem)),
74949                 line: presetCollection(d.defaults.line.map(getItem)),
74950                 point: presetCollection(d.defaults.point.map(getItem)),
74951                 vertex: presetCollection(d.defaults.vertex.map(getItem)),
74952                 relation: presetCollection(d.defaults.relation.map(getItem))
74953             };
74954         }
74955
74956         for (var i = 0; i < all.collection.length; i++) {
74957             var preset = all.collection[i],
74958                 geometry = preset.geometry;
74959
74960             for (var j = 0; j < geometry.length; j++) {
74961                 var g = index[geometry[j]];
74962                 for (var k in preset.tags) {
74963                     (g[k] = g[k] || []).push(preset);
74964                 }
74965             }
74966         }
74967
74968         return all;
74969     };
74970
74971     all.field = function(id) {
74972         return fields[id];
74973     };
74974
74975     all.universal = function() {
74976         return universal;
74977     };
74978
74979     all.defaults = function(geometry, n) {
74980         var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
74981             def = lodash.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
74982         return presetCollection(lodash.uniq(rec.concat(def).concat(all.item(geometry))));
74983     };
74984
74985     all.choose = function(preset) {
74986         if (!preset.isFallback()) {
74987             recent = presetCollection(lodash.uniq([preset].concat(recent.collection)));
74988         }
74989         return all;
74990     };
74991
74992     return all;
74993 }
74994
74995 var areaKeys = {};
74996
74997 function setAreaKeys(value) {
74998     areaKeys = value;
74999 }
75000
75001
75002 function coreContext() {
75003     var context = {};
75004     context.version = '2.3.0';
75005
75006     // create a special translation that contains the keys in place of the strings
75007     var tkeys = lodash.cloneDeep(en);
75008     var parents = [];
75009
75010     function traverser(v, k, obj) {
75011         parents.push(k);
75012         if (lodash.isObject(v)) {
75013             lodash.forOwn(v, traverser);
75014         } else if (lodash.isString(v)) {
75015             obj[k] = parents.join('.');
75016         }
75017         parents.pop();
75018     }
75019
75020     lodash.forOwn(tkeys, traverser);
75021     addTranslation('_tkeys_', tkeys);
75022
75023     addTranslation('en', en);
75024     setLocale('en');
75025
75026     var dispatch$$1 = dispatch('enter', 'exit', 'change');
75027
75028     // https://github.com/openstreetmap/iD/issues/772
75029     // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
75030     var storage;
75031     try { storage = localStorage; } catch (e) {}  // eslint-disable-line no-empty
75032     storage = storage || (function() {
75033         var s = {};
75034         return {
75035             getItem: function(k) { return s[k]; },
75036             setItem: function(k, v) { s[k] = v; },
75037             removeItem: function(k) { delete s[k]; }
75038         };
75039     })();
75040
75041     context.storage = function(k, v) {
75042         try {
75043             if (arguments.length === 1) return storage.getItem(k);
75044             else if (v === null) storage.removeItem(k);
75045             else storage.setItem(k, v);
75046         } catch (e) {
75047             // localstorage quota exceeded
75048             /* eslint-disable no-console */
75049             if (typeof console !== 'undefined') console.error('localStorage quota exceeded');
75050             /* eslint-enable no-console */
75051         }
75052     };
75053
75054
75055     /* Straight accessors. Avoid using these if you can. */
75056     var ui, connection, history;
75057     context.ui = function() { return ui; };
75058     context.connection = function() { return connection; };
75059     context.history = function() { return history; };
75060
75061
75062     /* Connection */
75063     function entitiesLoaded(err, result) {
75064         if (!err) history.merge(result.data, result.extent);
75065     }
75066
75067     context.preauth = function(options) {
75068         connection.switch(options);
75069         return context;
75070     };
75071
75072     context.loadTiles = function(projection$$1, dimensions, callback) {
75073         function done(err, result) {
75074             entitiesLoaded(err, result);
75075             if (callback) callback(err, result);
75076         }
75077         connection.loadTiles(projection$$1, dimensions, done);
75078     };
75079
75080     context.loadEntity = function(id, callback) {
75081         function done(err, result) {
75082             entitiesLoaded(err, result);
75083             if (callback) callback(err, result);
75084         }
75085         connection.loadEntity(id, done);
75086     };
75087
75088     context.zoomToEntity = function(id, zoomTo) {
75089         if (zoomTo !== false) {
75090             this.loadEntity(id, function(err, result) {
75091                 if (err) return;
75092                 var entity = lodash.find(result.data, function(e) { return e.id === id; });
75093                 if (entity) { map.zoomTo(entity); }
75094             });
75095         }
75096
75097         map.on('drawn.zoomToEntity', function() {
75098             if (!context.hasEntity(id)) return;
75099             map.on('drawn.zoomToEntity', null);
75100             context.on('enter.zoomToEntity', null);
75101             context.enter(modeSelect(context, [id]));
75102         });
75103
75104         context.on('enter.zoomToEntity', function() {
75105             if (mode.id !== 'browse') {
75106                 map.on('drawn.zoomToEntity', null);
75107                 context.on('enter.zoomToEntity', null);
75108             }
75109         });
75110     };
75111
75112     var minEditableZoom = 16;
75113     context.minEditableZoom = function(_) {
75114         if (!arguments.length) return minEditableZoom;
75115         minEditableZoom = _;
75116         connection.tileZoom(_);
75117         return context;
75118     };
75119
75120
75121     /* History */
75122     var inIntro = false;
75123     context.inIntro = function(_) {
75124         if (!arguments.length) return inIntro;
75125         inIntro = _;
75126         return context;
75127     };
75128
75129     context.save = function() {
75130         // no history save, no message onbeforeunload
75131         if (inIntro || select('.modal').size()) return;
75132
75133         var canSave;
75134         if (mode && mode.id === 'save') {
75135             canSave = false;
75136         } else {
75137             canSave = context.selectedIDs().every(function(id) {
75138                 var entity = context.hasEntity(id);
75139                 return entity && !entity.isDegenerate();
75140             });
75141         }
75142
75143         if (canSave) {
75144             history.save();
75145         }
75146         if (history.hasChanges()) {
75147             return t('save.unsaved_changes');
75148         }
75149     };
75150
75151
75152     /* Graph */
75153     context.hasEntity = function(id) {
75154         return history.graph().hasEntity(id);
75155     };
75156     context.entity = function(id) {
75157         return history.graph().entity(id);
75158     };
75159     context.childNodes = function(way) {
75160         return history.graph().childNodes(way);
75161     };
75162     context.geometry = function(id) {
75163         return context.entity(id).geometry(history.graph());
75164     };
75165
75166
75167     /* Modes */
75168     var mode;
75169     context.mode = function() {
75170         return mode;
75171     };
75172     context.enter = function(newMode) {
75173         if (mode) {
75174             mode.exit();
75175             dispatch$$1.call('exit', this, mode);
75176         }
75177
75178         mode = newMode;
75179         mode.enter();
75180         dispatch$$1.call('enter', this, mode);
75181     };
75182
75183     context.selectedIDs = function() {
75184         if (mode && mode.selectedIDs) {
75185             return mode.selectedIDs();
75186         } else {
75187             return [];
75188         }
75189     };
75190
75191
75192     /* Behaviors */
75193     context.install = function(behavior) {
75194         context.surface().call(behavior);
75195     };
75196     context.uninstall = function(behavior) {
75197         context.surface().call(behavior.off);
75198     };
75199
75200
75201     /* Copy/Paste */
75202     var copyIDs = [], copyGraph;
75203     context.copyGraph = function() { return copyGraph; };
75204     context.copyIDs = function(_) {
75205         if (!arguments.length) return copyIDs;
75206         copyIDs = _;
75207         copyGraph = history.graph();
75208         return context;
75209     };
75210
75211
75212     /* Background */
75213     var background;
75214     context.background = function() { return background; };
75215
75216
75217     /* Features */
75218     var features;
75219     context.features = function() { return features; };
75220     context.hasHiddenConnections = function(id) {
75221         var graph = history.graph(),
75222             entity = graph.entity(id);
75223         return features.hasHiddenConnections(entity, graph);
75224     };
75225
75226
75227     /* Presets */
75228     var presets;
75229     context.presets = function() { return presets; };
75230
75231
75232     /* Map */
75233     var map;
75234     context.map = function() { return map; };
75235     context.layers = function() { return map.layers; };
75236     context.surface = function() { return map.surface; };
75237     context.editable = function() { return map.editable(); };
75238     context.surfaceRect = function() {
75239         return map.surface.node().getBoundingClientRect();
75240     };
75241
75242
75243     /* Debug */
75244     var debugFlags = {
75245         tile: false,
75246         collision: false,
75247         imagery: false,
75248         imperial: false,
75249         driveLeft: false
75250     };
75251     context.debugFlags = function() {
75252         return debugFlags;
75253     };
75254     context.setDebug = function(flag, val) {
75255         if (arguments.length === 1) val = true;
75256         debugFlags[flag] = val;
75257         dispatch$$1.call('change');
75258         return context;
75259     };
75260     context.getDebug = function(flag) {
75261         return flag && debugFlags[flag];
75262     };
75263
75264
75265     /* Container */
75266     var container = select(document.body);
75267     context.container = function(_) {
75268         if (!arguments.length) return container;
75269         container = _;
75270         container.classed('id-container', true);
75271         return context;
75272     };
75273     var embed;
75274     context.embed = function(_) {
75275         if (!arguments.length) return embed;
75276         embed = _;
75277         return context;
75278     };
75279
75280
75281     /* Assets */
75282     var assetPath = '';
75283     context.assetPath = function(_) {
75284         if (!arguments.length) return assetPath;
75285         assetPath = _;
75286         return context;
75287     };
75288
75289     var assetMap = {};
75290     context.assetMap = function(_) {
75291         if (!arguments.length) return assetMap;
75292         assetMap = _;
75293         return context;
75294     };
75295
75296     context.asset = function(_) {
75297         var filename = assetPath + _;
75298         return assetMap[filename] || filename;
75299     };
75300
75301     context.imagePath = function(_) {
75302         return context.asset('img/' + _);
75303     };
75304
75305
75306     /* locales */
75307     // `locale` variable contains a "requested locale".
75308     // It won't become the `currentLocale` until after loadLocale() is called.
75309     var locale, localePath;
75310
75311     context.locale = function(loc, path$$1) {
75312         if (!arguments.length) return currentLocale;
75313         locale = loc;
75314         localePath = path$$1;
75315         return context;
75316     };
75317
75318     context.loadLocale = function(callback) {
75319         if (locale && locale !== 'en' && dataLocales.hasOwnProperty(locale)) {
75320             localePath = localePath || context.asset('locales/' + locale + '.json');
75321             json(localePath, function(err, result) {
75322                 if (!err) {
75323                     addTranslation(locale, result[locale]);
75324                     setLocale(locale);
75325                     utilDetect(true);
75326                 }
75327                 if (callback) {
75328                     callback(err);
75329                 }
75330             });
75331         } else {
75332             if (locale) {
75333                 setLocale(locale);
75334                 utilDetect(true);
75335             }
75336             if (callback) {
75337                 callback();
75338             }
75339         }
75340     };
75341
75342
75343     /* reset (aka flush) */
75344     context.reset = context.flush = function() {
75345         context.debouncedSave.cancel();
75346         lodash.each(services, function(service) {
75347             if (service && typeof service.reset === 'function') {
75348                 service.reset(context);
75349             }
75350         });
75351         features.reset();
75352         history.reset();
75353         return context;
75354     };
75355
75356
75357     /* Init */
75358
75359     context.projection = geoRawMercator();
75360     context.curtainProjection = geoRawMercator();
75361
75362     locale = utilDetect().locale;
75363     if (locale && !dataLocales.hasOwnProperty(locale)) {
75364         locale = locale.split('-')[0];
75365     }
75366
75367     history = coreHistory(context);
75368     context.graph = history.graph;
75369     context.changes = history.changes;
75370     context.intersects = history.intersects;
75371
75372     // Debounce save, since it's a synchronous localStorage write,
75373     // and history changes can happen frequently (e.g. when dragging).
75374     context.debouncedSave = lodash.debounce(context.save, 350);
75375     function withDebouncedSave(fn) {
75376         return function() {
75377             var result = fn.apply(history, arguments);
75378             context.debouncedSave();
75379             return result;
75380         };
75381     }
75382
75383     context.perform = withDebouncedSave(history.perform);
75384     context.replace = withDebouncedSave(history.replace);
75385     context.pop = withDebouncedSave(history.pop);
75386     context.overwrite = withDebouncedSave(history.overwrite);
75387     context.undo = withDebouncedSave(history.undo);
75388     context.redo = withDebouncedSave(history.redo);
75389
75390     ui = uiInit(context);
75391
75392     connection = services.osm;
75393     background = rendererBackground(context);
75394     features = rendererFeatures(context);
75395     presets = presetIndex();
75396
75397     map = rendererMap(context);
75398     context.mouse = map.mouse;
75399     context.extent = map.extent;
75400     context.pan = map.pan;
75401     context.zoomIn = map.zoomIn;
75402     context.zoomOut = map.zoomOut;
75403     context.zoomInFurther = map.zoomInFurther;
75404     context.zoomOutFurther = map.zoomOutFurther;
75405     context.redrawEnable = map.redrawEnable;
75406
75407     lodash.each(services, function(service) {
75408         if (service && typeof service.init === 'function') {
75409             service.init(context);
75410         }
75411     });
75412
75413     background.init();
75414     presets.init();
75415     areaKeys = presets.areaKeys();
75416
75417
75418     return utilRebind(context, dispatch$$1, 'on');
75419 }
75420
75421 function osmWay() {
75422     if (!(this instanceof osmWay)) {
75423         return (new osmWay()).initialize(arguments);
75424     } else if (arguments.length) {
75425         this.initialize(arguments);
75426     }
75427 }
75428
75429
75430 osmEntity$$1.way = osmWay;
75431
75432 osmWay.prototype = Object.create(osmEntity$$1.prototype);
75433
75434
75435 lodash.extend(osmWay.prototype, {
75436     type: 'way',
75437     nodes: [],
75438
75439
75440     copy: function(resolver, copies) {
75441         if (copies[this.id])
75442             return copies[this.id];
75443
75444         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
75445
75446         var nodes = this.nodes.map(function(id) {
75447             return resolver.entity(id).copy(resolver, copies).id;
75448         });
75449
75450         copy = copy.update({ nodes: nodes });
75451         copies[this.id] = copy;
75452
75453         return copy;
75454     },
75455
75456
75457     extent: function(resolver) {
75458         return resolver.transient(this, 'extent', function() {
75459             var extent$$1 = geoExtent$$1();
75460             for (var i = 0; i < this.nodes.length; i++) {
75461                 var node = resolver.hasEntity(this.nodes[i]);
75462                 if (node) {
75463                     extent$$1._extend(node.extent());
75464                 }
75465             }
75466             return extent$$1;
75467         });
75468     },
75469
75470
75471     first: function() {
75472         return this.nodes[0];
75473     },
75474
75475
75476     last: function() {
75477         return this.nodes[this.nodes.length - 1];
75478     },
75479
75480
75481     contains: function(node) {
75482         return this.nodes.indexOf(node) >= 0;
75483     },
75484
75485
75486     affix: function(node) {
75487         if (this.nodes[0] === node) return 'prefix';
75488         if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
75489     },
75490
75491
75492     layer: function() {
75493         // explicit layer tag, clamp between -10, 10..
75494         if (isFinite(this.tags.layer)) {
75495             return Math.max(-10, Math.min(+(this.tags.layer), 10));
75496         }
75497
75498         // implied layer tag..
75499         if (this.tags.location === 'overground') return 1;
75500         if (this.tags.location === 'underground') return -1;
75501         if (this.tags.location === 'underwater') return -10;
75502
75503         if (this.tags.power === 'line') return 10;
75504         if (this.tags.power === 'minor_line') return 10;
75505         if (this.tags.aerialway) return 10;
75506         if (this.tags.bridge) return 1;
75507         if (this.tags.cutting) return -1;
75508         if (this.tags.tunnel) return -1;
75509         if (this.tags.waterway) return -1;
75510         if (this.tags.man_made === 'pipeline') return -10;
75511         if (this.tags.boundary) return -10;
75512         return 0;
75513     },
75514
75515
75516     isOneWay: function() {
75517         // explicit oneway tag..
75518         if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
75519         if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
75520
75521         // implied oneway tag..
75522         for (var key in this.tags) {
75523             if (key in osmOneWayTags && (this.tags[key] in osmOneWayTags[key]))
75524                 return true;
75525         }
75526         return false;
75527     },
75528
75529
75530     lanes: function() {
75531         return osmLanes(this);
75532     },
75533
75534
75535     isClosed: function() {
75536         return this.nodes.length > 1 && this.first() === this.last();
75537     },
75538
75539
75540     isConvex: function(resolver) {
75541         if (!this.isClosed() || this.isDegenerate()) return null;
75542
75543         var nodes = lodash.uniq(resolver.childNodes(this)),
75544             coords = lodash.map(nodes, 'loc'),
75545             curr = 0, prev = 0;
75546
75547         for (var i = 0; i < coords.length; i++) {
75548             var o = coords[(i+1) % coords.length],
75549                 a = coords[i],
75550                 b = coords[(i+2) % coords.length],
75551                 res = geoCross(o, a, b);
75552
75553             curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
75554             if (curr === 0) {
75555                 continue;
75556             } else if (prev && curr !== prev) {
75557                 return false;
75558             }
75559             prev = curr;
75560         }
75561         return true;
75562     },
75563
75564
75565     isArea: function() {
75566         if (this.tags.area === 'yes')
75567             return true;
75568         if (!this.isClosed() || this.tags.area === 'no')
75569             return false;
75570         for (var key in this.tags) {
75571             if (key in areaKeys && !(this.tags[key] in areaKeys[key])) {
75572                 return true;
75573             }
75574         }
75575         return false;
75576     },
75577
75578
75579     isDegenerate: function() {
75580         return lodash.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
75581     },
75582
75583
75584     areAdjacent: function(n1, n2) {
75585         for (var i = 0; i < this.nodes.length; i++) {
75586             if (this.nodes[i] === n1) {
75587                 if (this.nodes[i - 1] === n2) return true;
75588                 if (this.nodes[i + 1] === n2) return true;
75589             }
75590         }
75591         return false;
75592     },
75593
75594
75595     geometry: function(graph) {
75596         return graph.transient(this, 'geometry', function() {
75597             return this.isArea() ? 'area' : 'line';
75598         });
75599     },
75600
75601
75602     // If this way is not closed, append the beginning node to the end of the nodelist to close it.
75603     close: function() {
75604         if (this.isClosed() || !this.nodes.length) return this;
75605
75606         var nodes = this.nodes.slice();
75607         nodes = nodes.filter(noRepeatNodes);
75608         nodes.push(nodes[0]);
75609         return this.update({ nodes: nodes });
75610     },
75611
75612
75613     // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
75614     unclose: function() {
75615         if (!this.isClosed()) return this;
75616
75617         var nodes = this.nodes.slice(),
75618             connector = this.first(),
75619             i = nodes.length - 1;
75620
75621         // remove trailing connectors..
75622         while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
75623             nodes.splice(i, 1);
75624             i = nodes.length - 1;
75625         }
75626
75627         nodes = nodes.filter(noRepeatNodes);
75628         return this.update({ nodes: nodes });
75629     },
75630
75631
75632     // Adds a node (id) in front of the node which is currently at position index.
75633     // If index is undefined, the node will be added to the end of the way for linear ways,
75634     //   or just before the final connecting node for circular ways.
75635     // Consecutive duplicates are eliminated including existing ones.
75636     // Circularity is always preserved when adding a node.
75637     addNode: function(id, index) {
75638         var nodes = this.nodes.slice(),
75639             isClosed = this.isClosed(),
75640             max$$1 = isClosed ? nodes.length - 1 : nodes.length;
75641
75642         if (index === undefined) {
75643             index = max$$1;
75644         }
75645
75646         if (index < 0 || index > max$$1) {
75647             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
75648         }
75649
75650         // If this is a closed way, remove all connector nodes except the first one
75651         // (there may be duplicates) and adjust index if necessary..
75652         if (isClosed) {
75653             var connector = this.first();
75654
75655             // leading connectors..
75656             var i = 1;
75657             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
75658                 nodes.splice(i, 1);
75659                 if (index > i) index--;
75660             }
75661
75662             // trailing connectors..
75663             i = nodes.length - 1;
75664             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
75665                 nodes.splice(i, 1);
75666                 if (index > i) index--;
75667                 i = nodes.length - 1;
75668             }
75669         }
75670
75671         nodes.splice(index, 0, id);
75672         nodes = nodes.filter(noRepeatNodes);
75673
75674         // If the way was closed before, append a connector node to keep it closed..
75675         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
75676             nodes.push(nodes[0]);
75677         }
75678
75679         return this.update({ nodes: nodes });
75680     },
75681
75682
75683     // Replaces the node which is currently at position index with the given node (id).
75684     // Consecutive duplicates are eliminated including existing ones.
75685     // Circularity is preserved when updating a node.
75686     updateNode: function(id, index) {
75687         var nodes = this.nodes.slice(),
75688             isClosed = this.isClosed(),
75689             max$$1 = nodes.length - 1;
75690
75691         if (index === undefined || index < 0 || index > max$$1) {
75692             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
75693         }
75694
75695         // If this is a closed way, remove all connector nodes except the first one
75696         // (there may be duplicates) and adjust index if necessary..
75697         if (isClosed) {
75698             var connector = this.first();
75699
75700             // leading connectors..
75701             var i = 1;
75702             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
75703                 nodes.splice(i, 1);
75704                 if (index > i) index--;
75705             }
75706
75707             // trailing connectors..
75708             i = nodes.length - 1;
75709             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
75710                 nodes.splice(i, 1);
75711                 if (index === i) index = 0;  // update leading connector instead
75712                 i = nodes.length - 1;
75713             }
75714         }
75715
75716         nodes.splice(index, 1, id);
75717         nodes = nodes.filter(noRepeatNodes);
75718
75719         // If the way was closed before, append a connector node to keep it closed..
75720         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
75721             nodes.push(nodes[0]);
75722         }
75723
75724         return this.update({nodes: nodes});
75725     },
75726
75727
75728     // Replaces each occurrence of node id needle with replacement.
75729     // Consecutive duplicates are eliminated including existing ones.
75730     // Circularity is preserved.
75731     replaceNode: function(needle, replacement) {
75732         var nodes = this.nodes.slice(),
75733             isClosed = this.isClosed();
75734
75735         for (var i = 0; i < nodes.length; i++) {
75736             if (nodes[i] === needle) {
75737                 nodes[i] = replacement;
75738             }
75739         }
75740
75741         nodes = nodes.filter(noRepeatNodes);
75742
75743         // If the way was closed before, append a connector node to keep it closed..
75744         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
75745             nodes.push(nodes[0]);
75746         }
75747
75748         return this.update({nodes: nodes});
75749     },
75750
75751
75752     // Removes each occurrence of node id needle with replacement.
75753     // Consecutive duplicates are eliminated including existing ones.
75754     // Circularity is preserved.
75755     removeNode: function(id) {
75756         var nodes = this.nodes.slice(),
75757             isClosed = this.isClosed();
75758
75759         nodes = nodes
75760             .filter(function(node) { return node !== id; })
75761             .filter(noRepeatNodes);
75762
75763         // If the way was closed before, append a connector node to keep it closed..
75764         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
75765             nodes.push(nodes[0]);
75766         }
75767
75768         return this.update({nodes: nodes});
75769     },
75770
75771
75772     asJXON: function(changeset_id) {
75773         var r = {
75774             way: {
75775                 '@id': this.osmId(),
75776                 '@version': this.version || 0,
75777                 nd: lodash.map(this.nodes, function(id) {
75778                     return { keyAttributes: { ref: osmEntity$$1.id.toOSM(id) } };
75779                 }),
75780                 tag: lodash.map(this.tags, function(v, k) {
75781                     return { keyAttributes: { k: k, v: v } };
75782                 })
75783             }
75784         };
75785         if (changeset_id) {
75786             r.way['@changeset'] = changeset_id;
75787         }
75788         return r;
75789     },
75790
75791
75792     asGeoJSON: function(resolver) {
75793         return resolver.transient(this, 'GeoJSON', function() {
75794             var coordinates = lodash.map(resolver.childNodes(this), 'loc');
75795             if (this.isArea() && this.isClosed()) {
75796                 return {
75797                     type: 'Polygon',
75798                     coordinates: [coordinates]
75799                 };
75800             } else {
75801                 return {
75802                     type: 'LineString',
75803                     coordinates: coordinates
75804                 };
75805             }
75806         });
75807     },
75808
75809
75810     area: function(resolver) {
75811         return resolver.transient(this, 'area', function() {
75812             var nodes = resolver.childNodes(this);
75813
75814             var json$$1 = {
75815                 type: 'Polygon',
75816                 coordinates: [lodash.map(nodes, 'loc')]
75817             };
75818
75819             if (!this.isClosed() && nodes.length) {
75820                 json$$1.coordinates[0].push(nodes[0].loc);
75821             }
75822
75823             var area$$1 = area(json$$1);
75824
75825             // Heuristic for detecting counterclockwise winding order. Assumes
75826             // that OpenStreetMap polygons are not hemisphere-spanning.
75827             if (area$$1 > 2 * Math.PI) {
75828                 json$$1.coordinates[0] = json$$1.coordinates[0].reverse();
75829                 area$$1 = area(json$$1);
75830             }
75831
75832             return isNaN(area$$1) ? 0 : area$$1;
75833         });
75834     }
75835 });
75836
75837
75838 // Filter function to eliminate consecutive duplicates.
75839 function noRepeatNodes(node, i, arr) {
75840     return i === 0 || node !== arr[i - 1];
75841 }
75842
75843 function osmTurn(turn) {
75844     if (!(this instanceof osmTurn))
75845         return new osmTurn(turn);
75846     lodash.extend(this, turn);
75847 }
75848
75849
75850 function osmIntersection(graph, vertexId) {
75851     var vertex = graph.entity(vertexId),
75852         parentWays = graph.parentWays(vertex),
75853         coincident = [],
75854         highways = {};
75855
75856     function addHighway(way, adjacentNodeId) {
75857         if (highways[adjacentNodeId]) {
75858             coincident.push(adjacentNodeId);
75859         } else {
75860             highways[adjacentNodeId] = way;
75861         }
75862     }
75863
75864     // Pre-split ways that would need to be split in
75865     // order to add a restriction. The real split will
75866     // happen when the restriction is added.
75867     parentWays.forEach(function(way) {
75868         if (!way.tags.highway || way.isArea() || way.isDegenerate())
75869             return;
75870
75871         var isFirst = (vertexId === way.first()),
75872             isLast = (vertexId === way.last()),
75873             isAffix = (isFirst || isLast),
75874             isClosingNode = (isFirst && isLast);
75875
75876         if (isAffix && !isClosingNode) {
75877             var index = (isFirst ? 1 : way.nodes.length - 2);
75878             addHighway(way, way.nodes[index]);
75879
75880         } else {
75881             var splitIndex, wayA, wayB, indexA, indexB;
75882             if (isClosingNode) {
75883                 splitIndex = Math.ceil(way.nodes.length / 2);  // split at midpoint
75884                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
75885                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
75886                 indexA = 1;
75887                 indexB = way.nodes.length - 2;
75888             } else {
75889                 splitIndex = lodash.indexOf(way.nodes, vertex.id, 1);  // split at vertexid
75890                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
75891                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
75892                 indexA = splitIndex - 1;
75893                 indexB = splitIndex + 1;
75894             }
75895             graph = graph.replace(wayA).replace(wayB);
75896             addHighway(wayA, way.nodes[indexA]);
75897             addHighway(wayB, way.nodes[indexB]);
75898         }
75899     });
75900
75901     // remove any ways from this intersection that are coincident
75902     // (i.e. any adjacent node used by more than one intersecting way)
75903     coincident.forEach(function (n) {
75904         delete highways[n];
75905     });
75906
75907
75908     var intersection = {
75909         highways: highways,
75910         ways: lodash.values(highways),
75911         graph: graph
75912     };
75913
75914
75915     intersection.adjacentNodeId = function(fromWayId) {
75916         return lodash.find(lodash.keys(highways), function(k) {
75917             return highways[k].id === fromWayId;
75918         });
75919     };
75920
75921
75922     intersection.turns = function(fromNodeId) {
75923         var start = highways[fromNodeId];
75924         if (!start)
75925             return [];
75926
75927         if (start.first() === vertex.id && start.tags.oneway === 'yes')
75928             return [];
75929         if (start.last() === vertex.id && start.tags.oneway === '-1')
75930             return [];
75931
75932         function withRestriction(turn) {
75933             graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
75934                 if (relation.tags.type !== 'restriction')
75935                     return;
75936
75937                 var f = relation.memberByRole('from'),
75938                     t = relation.memberByRole('to'),
75939                     v = relation.memberByRole('via');
75940
75941                 if (f && f.id === turn.from.way &&
75942                     v && v.id === turn.via.node &&
75943                     t && t.id === turn.to.way) {
75944                     turn.restriction = relation.id;
75945                 } else if (/^only_/.test(relation.tags.restriction) &&
75946                     f && f.id === turn.from.way &&
75947                     v && v.id === turn.via.node &&
75948                     t && t.id !== turn.to.way) {
75949                     turn.restriction = relation.id;
75950                     turn.indirect_restriction = true;
75951                 }
75952             });
75953
75954             return osmTurn(turn);
75955         }
75956
75957
75958         var from = {
75959                 node: fromNodeId,
75960                 way: start.id.split(/-(a|b)/)[0]
75961             },
75962             via = { node: vertex.id },
75963             turns = [];
75964
75965         lodash.each(highways, function(end, adjacentNodeId) {
75966             if (end === start)
75967                 return;
75968
75969             // backward
75970             if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
75971                 turns.push(withRestriction({
75972                     from: from,
75973                     via: via,
75974                     to: {
75975                         node: adjacentNodeId,
75976                         way: end.id.split(/-(a|b)/)[0]
75977                     }
75978                 }));
75979             }
75980
75981             // forward
75982             if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
75983                 turns.push(withRestriction({
75984                     from: from,
75985                     via: via,
75986                     to: {
75987                         node: adjacentNodeId,
75988                         way: end.id.split(/-(a|b)/)[0]
75989                     }
75990                 }));
75991             }
75992
75993         });
75994
75995         // U-turn
75996         if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
75997             turns.push(withRestriction({
75998                 from: from,
75999                 via: via,
76000                 to: from,
76001                 u: true
76002             }));
76003         }
76004
76005         return turns;
76006     };
76007
76008     return intersection;
76009 }
76010
76011
76012 function osmInferRestriction(graph, from, via, to, projection) {
76013     var fromWay = graph.entity(from.way),
76014         fromNode = graph.entity(from.node),
76015         toWay = graph.entity(to.way),
76016         toNode = graph.entity(to.node),
76017         viaNode = graph.entity(via.node),
76018         fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
76019             (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
76020         toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
76021             (toWay.tags.oneway === '-1' && toWay.last() === via.node),
76022         angle = geoAngle(viaNode, fromNode, projection) -
76023                 geoAngle(viaNode, toNode, projection);
76024
76025     angle = angle * 180 / Math.PI;
76026
76027     while (angle < 0)
76028         angle += 360;
76029
76030     if (fromNode === toNode)
76031         return 'no_u_turn';
76032     if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
76033         return 'no_u_turn';
76034     if (angle < 158)
76035         return 'no_right_turn';
76036     if (angle > 202)
76037         return 'no_left_turn';
76038
76039     return 'no_straight_on';
76040 }
76041
76042 function actionAddMember(relationId, member, memberIndex) {
76043     return function(graph) {
76044         var relation = graph.entity(relationId);
76045
76046         if (isNaN(memberIndex) && member.type === 'way') {
76047             var members = relation.indexedMembers();
76048             members.push(member);
76049
76050             var joined = osmJoinWays(members, graph);
76051             for (var i = 0; i < joined.length; i++) {
76052                 var segment = joined[i];
76053                 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
76054                     if (segment[j] !== member)
76055                         continue;
76056
76057                     if (j === 0) {
76058                         memberIndex = segment[j + 1].index;
76059                     } else if (j === segment.length - 1) {
76060                         memberIndex = segment[j - 1].index + 1;
76061                     } else {
76062                         memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
76063                     }
76064                 }
76065             }
76066         }
76067
76068         return graph.replace(relation.addMember(member, memberIndex));
76069     };
76070 }
76071
76072 function actionAddMidpoint(midpoint, node) {
76073     return function(graph) {
76074         graph = graph.replace(node.move(midpoint.loc));
76075
76076         var parents = lodash.intersection(
76077             graph.parentWays(graph.entity(midpoint.edge[0])),
76078             graph.parentWays(graph.entity(midpoint.edge[1])));
76079
76080         parents.forEach(function(way) {
76081             for (var i = 0; i < way.nodes.length - 1; i++) {
76082                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
76083                     graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
76084
76085                     // Add only one midpoint on doubled-back segments,
76086                     // turning them into self-intersections.
76087                     return;
76088                 }
76089             }
76090         });
76091
76092         return graph;
76093     };
76094 }
76095
76096 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
76097 function actionAddVertex(wayId, nodeId, index) {
76098     return function(graph) {
76099         return graph.replace(graph.entity(wayId).addNode(nodeId, index));
76100     };
76101 }
76102
76103 function actionChangeMember(relationId, member, memberIndex) {
76104     return function(graph) {
76105         return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
76106     };
76107 }
76108
76109 function actionChangePreset(entityId, oldPreset, newPreset) {
76110     return function(graph) {
76111         var entity = graph.entity(entityId),
76112             geometry = entity.geometry(graph),
76113             tags = entity.tags;
76114
76115         if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
76116         if (newPreset) tags = newPreset.applyTags(tags, geometry);
76117
76118         return graph.replace(entity.update({tags: tags}));
76119     };
76120 }
76121
76122 function actionChangeTags(entityId, tags) {
76123     return function(graph) {
76124         var entity = graph.entity(entityId);
76125         return graph.replace(entity.update({tags: tags}));
76126     };
76127 }
76128
76129 function actionCircularize(wayId, projection$$1, maxAngle) {
76130     maxAngle = (maxAngle || 20) * Math.PI / 180;
76131
76132
76133     var action = function(graph, t) {
76134         if (t === null || !isFinite(t)) t = 1;
76135         t = Math.min(Math.max(+t, 0), 1);
76136
76137         var way = graph.entity(wayId),
76138             origNodes = {};
76139
76140         graph.childNodes(way).forEach(function(node) {
76141             if (!origNodes[node.id]) origNodes[node.id] = node;
76142         });
76143
76144         if (!way.isConvex(graph)) {
76145             graph = action.makeConvex(graph);
76146         }
76147
76148         var nodes = lodash.uniq(graph.childNodes(way)),
76149             keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
76150             points = nodes.map(function(n) { return projection$$1(n.loc); }),
76151             keyPoints = keyNodes.map(function(n) { return projection$$1(n.loc); }),
76152             centroid = (points.length === 2) ? geoInterp(points[0], points[1], 0.5) : d3polygonCentroid(points),
76153             radius = median(points, function(p) { return geoEuclideanDistance(centroid, p); }),
76154             sign = d3polygonArea(points) > 0 ? 1 : -1,
76155             ids;
76156
76157         // we need atleast two key nodes for the algorithm to work
76158         if (!keyNodes.length) {
76159             keyNodes = [nodes[0]];
76160             keyPoints = [points[0]];
76161         }
76162
76163         if (keyNodes.length === 1) {
76164             var index = nodes.indexOf(keyNodes[0]),
76165                 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
76166
76167             keyNodes.push(nodes[oppositeIndex]);
76168             keyPoints.push(points[oppositeIndex]);
76169         }
76170
76171         // key points and nodes are those connected to the ways,
76172         // they are projected onto the circle, inbetween nodes are moved
76173         // to constant intervals between key nodes, extra inbetween nodes are
76174         // added if necessary.
76175         for (var i = 0; i < keyPoints.length; i++) {
76176             var nextKeyNodeIndex = (i + 1) % keyNodes.length,
76177                 startNode = keyNodes[i],
76178                 endNode = keyNodes[nextKeyNodeIndex],
76179                 startNodeIndex = nodes.indexOf(startNode),
76180                 endNodeIndex = nodes.indexOf(endNode),
76181                 numberNewPoints = -1,
76182                 indexRange = endNodeIndex - startNodeIndex,
76183                 nearNodes = {},
76184                 inBetweenNodes = [],
76185                 startAngle, endAngle, totalAngle, eachAngle,
76186                 angle, loc, node, origNode, j;
76187
76188             if (indexRange < 0) {
76189                 indexRange += nodes.length;
76190             }
76191
76192             // position this key node
76193             var distance$$1 = geoEuclideanDistance(centroid, keyPoints[i]);
76194             if (distance$$1 === 0) { distance$$1 = 1e-4; }
76195             keyPoints[i] = [
76196                 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance$$1 * radius,
76197                 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance$$1 * radius
76198             ];
76199             loc = projection$$1.invert(keyPoints[i]);
76200             node = keyNodes[i];
76201             origNode = origNodes[node.id];
76202             node = node.move(geoInterp(origNode.loc, loc, t));
76203             graph = graph.replace(node);
76204
76205             // figure out the between delta angle we want to match to
76206             startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
76207             endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
76208             totalAngle = endAngle - startAngle;
76209
76210             // detects looping around -pi/pi
76211             if (totalAngle * sign > 0) {
76212                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
76213             }
76214
76215             do {
76216                 numberNewPoints++;
76217                 eachAngle = totalAngle / (indexRange + numberNewPoints);
76218             } while (Math.abs(eachAngle) > maxAngle);
76219
76220
76221             // move existing nodes
76222             for (j = 1; j < indexRange; j++) {
76223                 angle = startAngle + j * eachAngle;
76224                 loc = projection$$1.invert([
76225                     centroid[0] + Math.cos(angle) * radius,
76226                     centroid[1] + Math.sin(angle) * radius
76227                 ]);
76228
76229                 node = nodes[(j + startNodeIndex) % nodes.length];
76230                 origNode = origNodes[node.id];
76231                 nearNodes[node.id] = angle;
76232
76233                 node = node.move(geoInterp(origNode.loc, loc, t));
76234                 graph = graph.replace(node);
76235             }
76236
76237             // add new inbetween nodes if necessary
76238             for (j = 0; j < numberNewPoints; j++) {
76239                 angle = startAngle + (indexRange + j) * eachAngle;
76240                 loc = projection$$1.invert([
76241                     centroid[0] + Math.cos(angle) * radius,
76242                     centroid[1] + Math.sin(angle) * radius
76243                 ]);
76244
76245                 // choose a nearnode to use as the original
76246                 var min$$1 = Infinity;
76247                 for (var nodeId in nearNodes) {
76248                     var nearAngle = nearNodes[nodeId],
76249                         dist = Math.abs(nearAngle - angle);
76250                     if (dist < min$$1) {
76251                         dist = min$$1;
76252                         origNode = origNodes[nodeId];
76253                     }
76254                 }
76255
76256                 node = osmNode({ loc: geoInterp(origNode.loc, loc, t) });
76257                 graph = graph.replace(node);
76258
76259                 nodes.splice(endNodeIndex + j, 0, node);
76260                 inBetweenNodes.push(node.id);
76261             }
76262
76263             // Check for other ways that share these keyNodes..
76264             // If keyNodes are adjacent in both ways,
76265             // we can add inBetween nodes to that shared way too..
76266             if (indexRange === 1 && inBetweenNodes.length) {
76267                 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
76268                     endIndex1 = way.nodes.lastIndexOf(endNode.id),
76269                     wayDirection1 = (endIndex1 - startIndex1);
76270                 if (wayDirection1 < -1) { wayDirection1 = 1; }
76271
76272                 /* eslint-disable no-loop-func */
76273                 lodash.each(lodash.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
76274                     if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
76275                         var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
76276                             endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
76277                             wayDirection2 = (endIndex2 - startIndex2),
76278                             insertAt = endIndex2;
76279                         if (wayDirection2 < -1) { wayDirection2 = 1; }
76280
76281                         if (wayDirection1 !== wayDirection2) {
76282                             inBetweenNodes.reverse();
76283                             insertAt = startIndex2;
76284                         }
76285                         for (j = 0; j < inBetweenNodes.length; j++) {
76286                             sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
76287                         }
76288                         graph = graph.replace(sharedWay);
76289                     }
76290                 });
76291                 /* eslint-enable no-loop-func */
76292             }
76293
76294         }
76295
76296         // update the way to have all the new nodes
76297         ids = nodes.map(function(n) { return n.id; });
76298         ids.push(ids[0]);
76299
76300         way = way.update({nodes: ids});
76301         graph = graph.replace(way);
76302
76303         return graph;
76304     };
76305
76306
76307     action.makeConvex = function(graph) {
76308         var way = graph.entity(wayId),
76309             nodes = lodash.uniq(graph.childNodes(way)),
76310             points = nodes.map(function(n) { return projection$$1(n.loc); }),
76311             sign = d3polygonArea(points) > 0 ? 1 : -1,
76312             hull = d3polygonHull(points);
76313
76314         // D3 convex hulls go counterclockwise..
76315         if (sign === -1) {
76316             nodes.reverse();
76317             points.reverse();
76318         }
76319
76320         for (var i = 0; i < hull.length - 1; i++) {
76321             var startIndex = points.indexOf(hull[i]),
76322                 endIndex = points.indexOf(hull[i+1]),
76323                 indexRange = (endIndex - startIndex);
76324
76325             if (indexRange < 0) {
76326                 indexRange += nodes.length;
76327             }
76328
76329             // move interior nodes to the surface of the convex hull..
76330             for (var j = 1; j < indexRange; j++) {
76331                 var point = geoInterp(hull[i], hull[i+1], j / indexRange),
76332                     node = nodes[(j + startIndex) % nodes.length].move(projection$$1.invert(point));
76333                 graph = graph.replace(node);
76334             }
76335         }
76336         return graph;
76337     };
76338
76339
76340     action.disabled = function(graph) {
76341         if (!graph.entity(wayId).isClosed())
76342             return 'not_closed';
76343     };
76344
76345
76346     action.transitionable = true;
76347
76348
76349     return action;
76350 }
76351
76352 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
76353 function actionDeleteWay(wayId) {
76354
76355
76356     function canDeleteNode(node, graph) {
76357         return !graph.parentWays(node).length &&
76358             !graph.parentRelations(node).length &&
76359             !node.hasInterestingTags();
76360     }
76361
76362
76363     var action = function(graph) {
76364         var way = graph.entity(wayId);
76365
76366         graph.parentRelations(way)
76367             .forEach(function(parent) {
76368                 parent = parent.removeMembersWithID(wayId);
76369                 graph = graph.replace(parent);
76370
76371                 if (parent.isDegenerate()) {
76372                     graph = actionDeleteRelation(parent.id)(graph);
76373                 }
76374             });
76375
76376         lodash.uniq(way.nodes).forEach(function(nodeId) {
76377             graph = graph.replace(way.removeNode(nodeId));
76378
76379             var node = graph.entity(nodeId);
76380             if (canDeleteNode(node, graph)) {
76381                 graph = graph.remove(node);
76382             }
76383         });
76384
76385         return graph.remove(way);
76386     };
76387
76388
76389     return action;
76390 }
76391
76392 function actionDeleteMultiple(ids) {
76393     var actions = {
76394         way: actionDeleteWay,
76395         node: actionDeleteNode,
76396         relation: actionDeleteRelation
76397     };
76398
76399
76400     var action = function(graph) {
76401         ids.forEach(function(id) {
76402             if (graph.hasEntity(id)) { // It may have been deleted aready.
76403                 graph = actions[graph.entity(id).type](id)(graph);
76404             }
76405         });
76406
76407         return graph;
76408     };
76409
76410
76411     return action;
76412 }
76413
76414 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
76415 function actionDeleteRelation(relationId) {
76416
76417
76418     function canDeleteEntity(entity, graph) {
76419         return !graph.parentWays(entity).length &&
76420             !graph.parentRelations(entity).length &&
76421             !entity.hasInterestingTags();
76422     }
76423
76424
76425     var action = function(graph) {
76426         var relation = graph.entity(relationId);
76427
76428         graph.parentRelations(relation)
76429             .forEach(function(parent) {
76430                 parent = parent.removeMembersWithID(relationId);
76431                 graph = graph.replace(parent);
76432
76433                 if (parent.isDegenerate()) {
76434                     graph = actionDeleteRelation(parent.id)(graph);
76435                 }
76436             });
76437
76438         lodash.uniq(lodash.map(relation.members, 'id')).forEach(function(memberId) {
76439             graph = graph.replace(relation.removeMembersWithID(memberId));
76440
76441             var entity = graph.entity(memberId);
76442             if (canDeleteEntity(entity, graph)) {
76443                 graph = actionDeleteMultiple([memberId])(graph);
76444             }
76445         });
76446
76447         return graph.remove(relation);
76448     };
76449
76450
76451     return action;
76452 }
76453
76454 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
76455 function actionDeleteNode(nodeId) {
76456     var action = function(graph) {
76457         var node = graph.entity(nodeId);
76458
76459         graph.parentWays(node)
76460             .forEach(function(parent) {
76461                 parent = parent.removeNode(nodeId);
76462                 graph = graph.replace(parent);
76463
76464                 if (parent.isDegenerate()) {
76465                     graph = actionDeleteWay(parent.id)(graph);
76466                 }
76467             });
76468
76469         graph.parentRelations(node)
76470             .forEach(function(parent) {
76471                 parent = parent.removeMembersWithID(nodeId);
76472                 graph = graph.replace(parent);
76473
76474                 if (parent.isDegenerate()) {
76475                     graph = actionDeleteRelation(parent.id)(graph);
76476                 }
76477             });
76478
76479         return graph.remove(node);
76480     };
76481
76482
76483     return action;
76484 }
76485
76486 // Connect the ways at the given nodes.
76487 //
76488 // The last node will survive. All other nodes will be replaced with
76489 // the surviving node in parent ways, and then removed.
76490 //
76491 // Tags and relation memberships of of non-surviving nodes are merged
76492 // to the survivor.
76493 //
76494 // This is the inverse of `iD.actionDisconnect`.
76495 //
76496 // Reference:
76497 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
76498 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
76499 //
76500 function actionConnect(nodeIds) {
76501     return function(graph) {
76502         var survivor = graph.entity(lodash.last(nodeIds));
76503
76504         for (var i = 0; i < nodeIds.length - 1; i++) {
76505             var node = graph.entity(nodeIds[i]);
76506
76507             /* eslint-disable no-loop-func */
76508             graph.parentWays(node).forEach(function(parent) {
76509                 if (!parent.areAdjacent(node.id, survivor.id)) {
76510                     graph = graph.replace(parent.replaceNode(node.id, survivor.id));
76511                 }
76512             });
76513
76514             graph.parentRelations(node).forEach(function(parent) {
76515                 graph = graph.replace(parent.replaceMember(node, survivor));
76516             });
76517             /* eslint-enable no-loop-func */
76518
76519             survivor = survivor.mergeTags(node.tags);
76520             graph = actionDeleteNode(node.id)(graph);
76521         }
76522
76523         graph = graph.replace(survivor);
76524
76525         return graph;
76526     };
76527 }
76528
76529 function actionCopyEntities(ids, fromGraph) {
76530     var copies = {};
76531
76532
76533     var action = function(graph) {
76534         ids.forEach(function(id) {
76535             fromGraph.entity(id).copy(fromGraph, copies);
76536         });
76537
76538         for (var id in copies) {
76539             graph = graph.replace(copies[id]);
76540         }
76541
76542         return graph;
76543     };
76544
76545
76546     action.copies = function() {
76547         return copies;
76548     };
76549
76550
76551     return action;
76552 }
76553
76554 function actionDeleteMember(relationId, memberIndex) {
76555     return function(graph) {
76556         var relation = graph.entity(relationId)
76557             .removeMember(memberIndex);
76558
76559         graph = graph.replace(relation);
76560
76561         if (relation.isDegenerate())
76562             graph = actionDeleteRelation(relation.id)(graph);
76563
76564         return graph;
76565     };
76566 }
76567
76568 function actionDeprecateTags(entityId) {
76569
76570     return function(graph) {
76571         var entity = graph.entity(entityId),
76572             newtags = lodash.clone(entity.tags),
76573             change = false,
76574             rule;
76575
76576         // This handles dataDeprecated tags with a single condition
76577         for (var i = 0; i < dataDeprecated.length; i++) {
76578
76579             rule = dataDeprecated[i];
76580             var match = lodash.toPairs(rule.old)[0],
76581                 replacements = rule.replace ? lodash.toPairs(rule.replace) : null;
76582
76583             if (entity.tags[match[0]] && match[1] === '*') {
76584
76585                 var value = entity.tags[match[0]];
76586                 if (replacements && !newtags[replacements[0][0]]) {
76587                     newtags[replacements[0][0]] = value;
76588                 }
76589                 delete newtags[match[0]];
76590                 change = true;
76591
76592             } else if (entity.tags[match[0]] === match[1]) {
76593                 newtags = lodash.assign({}, rule.replace || {}, lodash.omit(newtags, match[0]));
76594                 change = true;
76595             }
76596         }
76597
76598         if (change) {
76599             return graph.replace(entity.update({tags: newtags}));
76600         } else {
76601             return graph;
76602         }
76603     };
76604 }
76605
76606 function actionDiscardTags(difference) {
76607
76608     return function(graph) {
76609         function discardTags(entity) {
76610             if (!lodash.isEmpty(entity.tags)) {
76611                 var tags = {};
76612                 lodash.each(entity.tags, function(v, k) {
76613                     if (v) tags[k] = v;
76614                 });
76615
76616                 graph = graph.replace(entity.update({
76617                     tags: lodash.omit(tags, dataDiscarded)
76618                 }));
76619             }
76620         }
76621
76622         difference.modified().forEach(discardTags);
76623         difference.created().forEach(discardTags);
76624
76625         return graph;
76626     };
76627 }
76628
76629 // Disconect the ways at the given node.
76630 //
76631 // Optionally, disconnect only the given ways.
76632 //
76633 // For testing convenience, accepts an ID to assign to the (first) new node.
76634 // Normally, this will be undefined and the way will automatically
76635 // be assigned a new ID.
76636 //
76637 // This is the inverse of `iD.actionConnect`.
76638 //
76639 // Reference:
76640 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
76641 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
76642 //
76643 function actionDisconnect(nodeId, newNodeId) {
76644     var wayIds;
76645
76646
76647     var action = function(graph) {
76648         var node = graph.entity(nodeId),
76649             connections = action.connections(graph);
76650
76651         connections.forEach(function(connection) {
76652             var way = graph.entity(connection.wayID),
76653                 newNode = osmNode({id: newNodeId, loc: node.loc, tags: node.tags});
76654
76655             graph = graph.replace(newNode);
76656             if (connection.index === 0 && way.isArea()) {
76657                 // replace shared node with shared node..
76658                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
76659             } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
76660                 // replace closing node with new new node..
76661                 graph = graph.replace(way.unclose().addNode(newNode.id));
76662             } else {
76663                 // replace shared node with multiple new nodes..
76664                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
76665             }
76666         });
76667
76668         return graph;
76669     };
76670
76671
76672     action.connections = function(graph) {
76673         var candidates = [],
76674             keeping = false,
76675             parentWays = graph.parentWays(graph.entity(nodeId));
76676
76677         parentWays.forEach(function(way) {
76678             if (wayIds && wayIds.indexOf(way.id) === -1) {
76679                 keeping = true;
76680                 return;
76681             }
76682             if (way.isArea() && (way.nodes[0] === nodeId)) {
76683                 candidates.push({ wayID: way.id, index: 0 });
76684             } else {
76685                 way.nodes.forEach(function(waynode, index) {
76686                     if (waynode === nodeId) {
76687                         candidates.push({ wayID: way.id, index: index });
76688                     }
76689                 });
76690             }
76691         });
76692
76693         return keeping ? candidates : candidates.slice(1);
76694     };
76695
76696
76697     action.disabled = function(graph) {
76698         var connections = action.connections(graph);
76699         if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
76700             return 'not_connected';
76701
76702         var parentWays = graph.parentWays(graph.entity(nodeId)),
76703             seenRelationIds = {},
76704             sharedRelation;
76705
76706         parentWays.forEach(function(way) {
76707             if (wayIds && wayIds.indexOf(way.id) === -1)
76708                 return;
76709
76710             var relations = graph.parentRelations(way);
76711             relations.forEach(function(relation) {
76712                 if (relation.id in seenRelationIds) {
76713                     sharedRelation = relation;
76714                 } else {
76715                     seenRelationIds[relation.id] = true;
76716                 }
76717             });
76718         });
76719
76720         if (sharedRelation)
76721             return 'relation';
76722     };
76723
76724
76725     action.limitWays = function(_) {
76726         if (!arguments.length) return wayIds;
76727         wayIds = _;
76728         return action;
76729     };
76730
76731
76732     return action;
76733 }
76734
76735 // Join ways at the end node they share.
76736 //
76737 // This is the inverse of `iD.actionSplit`.
76738 //
76739 // Reference:
76740 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
76741 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
76742 //
76743 function actionJoin(ids) {
76744
76745     function groupEntitiesByGeometry(graph) {
76746         var entities = ids.map(function(id) { return graph.entity(id); });
76747         return lodash.extend({line: []}, lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
76748     }
76749
76750
76751     var action = function(graph) {
76752         var ways = ids.map(graph.entity, graph),
76753             survivor = ways[0];
76754
76755         // Prefer to keep an existing way.
76756         for (var i = 0; i < ways.length; i++) {
76757             if (!ways[i].isNew()) {
76758                 survivor = ways[i];
76759                 break;
76760             }
76761         }
76762
76763         var joined = osmJoinWays(ways, graph)[0];
76764
76765         survivor = survivor.update({nodes: lodash.map(joined.nodes, 'id')});
76766         graph = graph.replace(survivor);
76767
76768         joined.forEach(function(way) {
76769             if (way.id === survivor.id)
76770                 return;
76771
76772             graph.parentRelations(way).forEach(function(parent) {
76773                 graph = graph.replace(parent.replaceMember(way, survivor));
76774             });
76775
76776             survivor = survivor.mergeTags(way.tags);
76777
76778             graph = graph.replace(survivor);
76779             graph = actionDeleteWay(way.id)(graph);
76780         });
76781
76782         return graph;
76783     };
76784
76785
76786     action.disabled = function(graph) {
76787         var geometries = groupEntitiesByGeometry(graph);
76788         if (ids.length < 2 || ids.length !== geometries.line.length)
76789             return 'not_eligible';
76790
76791         var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
76792         if (joined.length > 1)
76793             return 'not_adjacent';
76794
76795         var nodeIds = lodash.map(joined[0].nodes, 'id').slice(1, -1),
76796             relation,
76797             tags = {},
76798             conflicting = false;
76799
76800         joined[0].forEach(function(way) {
76801             var parents = graph.parentRelations(way);
76802             parents.forEach(function(parent) {
76803                 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
76804                     relation = parent;
76805             });
76806
76807             for (var k in way.tags) {
76808                 if (!(k in tags)) {
76809                     tags[k] = way.tags[k];
76810                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
76811                     conflicting = true;
76812                 }
76813             }
76814         });
76815
76816         if (relation)
76817             return 'restriction';
76818
76819         if (conflicting)
76820             return 'conflicting_tags';
76821     };
76822
76823
76824     return action;
76825 }
76826
76827 function actionMerge(ids) {
76828
76829     function groupEntitiesByGeometry(graph) {
76830         var entities = ids.map(function(id) { return graph.entity(id); });
76831         return lodash.extend({point: [], area: [], line: [], relation: []},
76832             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
76833     }
76834
76835
76836     var action = function(graph) {
76837         var geometries = groupEntitiesByGeometry(graph),
76838             target = geometries.area[0] || geometries.line[0],
76839             points = geometries.point;
76840
76841         points.forEach(function(point) {
76842             target = target.mergeTags(point.tags);
76843             graph = graph.replace(target);
76844
76845             graph.parentRelations(point).forEach(function(parent) {
76846                 graph = graph.replace(parent.replaceMember(point, target));
76847             });
76848
76849             var nodes = lodash.uniq(graph.childNodes(target)),
76850                 removeNode = point;
76851
76852             for (var i = 0; i < nodes.length; i++) {
76853                 var node = nodes[i];
76854                 if (graph.parentWays(node).length > 1 ||
76855                     graph.parentRelations(node).length ||
76856                     node.hasInterestingTags()) {
76857                     continue;
76858                 }
76859
76860                 // Found an uninteresting child node on the target way.
76861                 // Move orig point into its place to preserve point's history. #3683
76862                 graph = graph.replace(point.update({ tags: {}, loc: node.loc }));
76863                 target = target.replaceNode(node.id, point.id);
76864                 graph = graph.replace(target);
76865                 removeNode = node;
76866                 break;
76867             }
76868
76869             graph = graph.remove(removeNode);
76870         });
76871
76872         return graph;
76873     };
76874
76875
76876     action.disabled = function(graph) {
76877         var geometries = groupEntitiesByGeometry(graph);
76878         if (geometries.point.length === 0 ||
76879             (geometries.area.length + geometries.line.length) !== 1 ||
76880             geometries.relation.length !== 0)
76881             return 'not_eligible';
76882     };
76883
76884
76885     return action;
76886 }
76887
76888 function actionMergePolygon(ids, newRelationId) {
76889
76890     function groupEntities(graph) {
76891         var entities = ids.map(function (id) { return graph.entity(id); });
76892         return lodash.extend({
76893                 closedWay: [],
76894                 multipolygon: [],
76895                 other: []
76896             }, lodash.groupBy(entities, function(entity) {
76897                 if (entity.type === 'way' && entity.isClosed()) {
76898                     return 'closedWay';
76899                 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
76900                     return 'multipolygon';
76901                 } else {
76902                     return 'other';
76903                 }
76904             }));
76905     }
76906
76907
76908     var action = function(graph) {
76909         var entities = groupEntities(graph);
76910
76911         // An array representing all the polygons that are part of the multipolygon.
76912         //
76913         // Each element is itself an array of objects with an id property, and has a
76914         // locs property which is an array of the locations forming the polygon.
76915         var polygons = entities.multipolygon.reduce(function(polygons, m) {
76916             return polygons.concat(osmJoinWays(m.members, graph));
76917         }, []).concat(entities.closedWay.map(function(d) {
76918             var member = [{id: d.id}];
76919             member.nodes = graph.childNodes(d);
76920             return member;
76921         }));
76922
76923         // contained is an array of arrays of boolean values,
76924         // where contained[j][k] is true iff the jth way is
76925         // contained by the kth way.
76926         var contained = polygons.map(function(w, i) {
76927             return polygons.map(function(d, n) {
76928                 if (i === n) return null;
76929                 return geoPolygonContainsPolygon(
76930                     lodash.map(d.nodes, 'loc'),
76931                     lodash.map(w.nodes, 'loc'));
76932             });
76933         });
76934
76935         // Sort all polygons as either outer or inner ways
76936         var members = [],
76937             outer = true;
76938
76939         while (polygons.length) {
76940             extractUncontained(polygons);
76941             polygons = polygons.filter(isContained);
76942             contained = contained.filter(isContained).map(filterContained);
76943         }
76944
76945         function isContained(d, i) {
76946             return lodash.some(contained[i]);
76947         }
76948
76949         function filterContained(d) {
76950             return d.filter(isContained);
76951         }
76952
76953         function extractUncontained(polygons) {
76954             polygons.forEach(function(d, i) {
76955                 if (!isContained(d, i)) {
76956                     d.forEach(function(member) {
76957                         members.push({
76958                             type: 'way',
76959                             id: member.id,
76960                             role: outer ? 'outer' : 'inner'
76961                         });
76962                     });
76963                 }
76964             });
76965             outer = !outer;
76966         }
76967
76968         // Move all tags to one relation
76969         var relation = entities.multipolygon[0] ||
76970             osmRelation({ id: newRelationId, tags: { type: 'multipolygon' }});
76971
76972         entities.multipolygon.slice(1).forEach(function(m) {
76973             relation = relation.mergeTags(m.tags);
76974             graph = graph.remove(m);
76975         });
76976
76977         entities.closedWay.forEach(function(way) {
76978             function isThisOuter(m) {
76979                 return m.id === way.id && m.role !== 'inner';
76980             }
76981             if (members.some(isThisOuter)) {
76982                 relation = relation.mergeTags(way.tags);
76983                 graph = graph.replace(way.update({ tags: {} }));
76984             }
76985         });
76986
76987         return graph.replace(relation.update({
76988             members: members,
76989             tags: lodash.omit(relation.tags, 'area')
76990         }));
76991     };
76992
76993
76994     action.disabled = function(graph) {
76995         var entities = groupEntities(graph);
76996         if (entities.other.length > 0 ||
76997             entities.closedWay.length + entities.multipolygon.length < 2)
76998             return 'not_eligible';
76999         if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
77000             return 'incomplete_relation';
77001     };
77002
77003
77004     return action;
77005 }
77006
77007 // Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
77008 // Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
77009 //
77010 // Permission is hereby granted, free of charge, to any person
77011 // obtaining a copy of this software and associated documentation files
77012 // (the "Software"), to deal in the Software without restriction,
77013 // including without limitation the rights to use, copy, modify, merge,
77014 // publish, distribute, sublicense, and/or sell copies of the Software,
77015 // and to permit persons to whom the Software is furnished to do so,
77016 // subject to the following conditions:
77017 //
77018 // The above copyright notice and this permission notice shall be
77019 // included in all copies or substantial portions of the Software.
77020 //
77021 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
77022 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
77023 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
77024 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
77025 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
77026 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
77027 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
77028 // SOFTWARE.
77029
77030 // source:  https://bitbucket.org/lshift/synchrotron/src
77031 function longest_common_subsequence(file1, file2) {
77032     /* Text diff algorithm following Hunt and McIlroy 1976.
77033      * J. W. Hunt and M. D. McIlroy, An algorithm for differential file
77034      * comparison, Bell Telephone Laboratories CSTR #41 (1976)
77035      * http://www.cs.dartmouth.edu/~doug/
77036      *
77037      * Expects two arrays of strings.
77038      */
77039     var equivalenceClasses;
77040     var file2indices;
77041     var newCandidate;
77042     var candidates;
77043     var line;
77044     var c, i, j, jX, r, s;
77045
77046     equivalenceClasses = {};
77047     for (j = 0; j < file2.length; j++) {
77048         line = file2[j];
77049         if (equivalenceClasses[line]) {
77050             equivalenceClasses[line].push(j);
77051         } else {
77052             equivalenceClasses[line] = [j];
77053         }
77054     }
77055
77056     candidates = [{file1index: -1,
77057                    file2index: -1,
77058                    chain: null}];
77059
77060     for (i = 0; i < file1.length; i++) {
77061         line = file1[i];
77062         file2indices = equivalenceClasses[line] || [];
77063
77064         r = 0;
77065         c = candidates[0];
77066
77067         for (jX = 0; jX < file2indices.length; jX++) {
77068             j = file2indices[jX];
77069
77070             for (s = 0; s < candidates.length; s++) {
77071                 if ((candidates[s].file2index < j) &&
77072                     ((s === candidates.length - 1) ||
77073                      (candidates[s + 1].file2index > j)))
77074                     break;
77075             }
77076
77077             if (s < candidates.length) {
77078                 newCandidate = {file1index: i,
77079                                 file2index: j,
77080                                 chain: candidates[s]};
77081                 if (r === candidates.length) {
77082                     candidates.push(c);
77083                 } else {
77084                     candidates[r] = c;
77085                 }
77086                 r = s + 1;
77087                 c = newCandidate;
77088                 if (r === candidates.length) {
77089                     break; // no point in examining further (j)s
77090                 }
77091             }
77092         }
77093
77094         candidates[r] = c;
77095     }
77096
77097     // At this point, we know the LCS: it's in the reverse of the
77098     // linked-list through .chain of
77099     // candidates[candidates.length - 1].
77100
77101     return candidates[candidates.length - 1];
77102 }
77103
77104
77105
77106
77107
77108
77109
77110
77111
77112
77113
77114 function diff_indices(file1, file2) {
77115     // We apply the LCS to give a simple representation of the
77116     // offsets and lengths of mismatched chunks in the input
77117     // files. This is used by diff3_merge_indices below.
77118
77119     var result = [];
77120     var tail1 = file1.length;
77121     var tail2 = file2.length;
77122
77123     for (var candidate = longest_common_subsequence(file1, file2);
77124          candidate !== null;
77125          candidate = candidate.chain)
77126     {
77127         var mismatchLength1 = tail1 - candidate.file1index - 1;
77128         var mismatchLength2 = tail2 - candidate.file2index - 1;
77129         tail1 = candidate.file1index;
77130         tail2 = candidate.file2index;
77131
77132         if (mismatchLength1 || mismatchLength2) {
77133             result.push({file1: [tail1 + 1, mismatchLength1],
77134                          file2: [tail2 + 1, mismatchLength2]});
77135         }
77136     }
77137
77138     result.reverse();
77139     return result;
77140 }
77141
77142 function diff3_merge_indices (a, o, b) {
77143     // Given three files, A, O, and B, where both A and B are
77144     // independently derived from O, returns a fairly complicated
77145     // internal representation of merge decisions it's taken. The
77146     // interested reader may wish to consult
77147     //
77148     // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
77149     // Formal Investigation of Diff3." In Arvind and Prasad,
77150     // editors, Foundations of Software Technology and Theoretical
77151     // Computer Science (FSTTCS), December 2007.
77152     //
77153     // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
77154     var i;
77155
77156     var m1 = diff_indices(o, a);
77157     var m2 = diff_indices(o, b);
77158
77159     var hunks = [];
77160     function addHunk(h, side) {
77161         hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]);
77162     }
77163     for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); }
77164     for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); }
77165     hunks.sort();
77166
77167     var result = [];
77168     var commonOffset = 0;
77169     function copyCommon(targetOffset) {
77170         if (targetOffset > commonOffset) {
77171             result.push([1, commonOffset, targetOffset - commonOffset]);
77172             commonOffset = targetOffset;
77173         }
77174     }
77175
77176     for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {
77177         var firstHunkIndex = hunkIndex;
77178         var hunk = hunks[hunkIndex];
77179         var regionLhs = hunk[0];
77180         var regionRhs = regionLhs + hunk[2];
77181         while (hunkIndex < hunks.length - 1) {
77182             var maybeOverlapping = hunks[hunkIndex + 1];
77183             var maybeLhs = maybeOverlapping[0];
77184             if (maybeLhs > regionRhs) break;
77185             regionRhs = maybeLhs + maybeOverlapping[2];
77186             hunkIndex++;
77187         }
77188
77189         copyCommon(regionLhs);
77190         if (firstHunkIndex === hunkIndex) {
77191     // The "overlap" was only one hunk long, meaning that
77192     // there's no conflict here. Either a and o were the
77193     // same, or b and o were the same.
77194             if (hunk[4] > 0) {
77195                 result.push([hunk[1], hunk[3], hunk[4]]);
77196             }
77197         } else {
77198     // A proper conflict. Determine the extents of the
77199     // regions involved from a, o and b. Effectively merge
77200     // all the hunks on the left into one giant hunk, and
77201     // do the same for the right; then, correct for skew
77202     // in the regions of o that each side changed, and
77203     // report appropriate spans for the three sides.
77204     var regions = {
77205         0: [a.length, -1, o.length, -1],
77206         2: [b.length, -1, o.length, -1]
77207     };
77208             for (i = firstHunkIndex; i <= hunkIndex; i++) {
77209         hunk = hunks[i];
77210                 var side = hunk[1];
77211         var r = regions[side];
77212         var oLhs = hunk[0];
77213         var oRhs = oLhs + hunk[2];
77214                 var abLhs = hunk[3];
77215                 var abRhs = abLhs + hunk[4];
77216         r[0] = Math.min(abLhs, r[0]);
77217         r[1] = Math.max(abRhs, r[1]);
77218         r[2] = Math.min(oLhs, r[2]);
77219         r[3] = Math.max(oRhs, r[3]);
77220             }
77221     var aLhs = regions[0][0] + (regionLhs - regions[0][2]);
77222     var aRhs = regions[0][1] + (regionRhs - regions[0][3]);
77223     var bLhs = regions[2][0] + (regionLhs - regions[2][2]);
77224     var bRhs = regions[2][1] + (regionRhs - regions[2][3]);
77225             result.push([-1,
77226              aLhs,      aRhs      - aLhs,
77227              regionLhs, regionRhs - regionLhs,
77228              bLhs,      bRhs      - bLhs]);
77229         }
77230         commonOffset = regionRhs;
77231     }
77232
77233     copyCommon(o.length);
77234     return result;
77235 }
77236
77237 function diff3_merge (a, o, b, excludeFalseConflicts) {
77238     // Applies the output of Diff3.diff3_merge_indices to actually
77239     // construct the merged file; the returned result alternates
77240     // between "ok" and "conflict" blocks.
77241
77242     var result = [];
77243     var files = [a, o, b];
77244     var indices = diff3_merge_indices(a, o, b);
77245
77246     var okLines = [];
77247     function flushOk() {
77248         if (okLines.length) {
77249             result.push({ok: okLines});
77250         }
77251         okLines = [];
77252     }
77253     function pushOk(xs) {
77254         for (var j = 0; j < xs.length; j++) {
77255             okLines.push(xs[j]);
77256         }
77257     }
77258
77259     function isTrueConflict(rec) {
77260         if (rec[2] !== rec[6]) return true;
77261         var aoff = rec[1];
77262         var boff = rec[5];
77263         for (var j = 0; j < rec[2]; j++) {
77264             if (a[j + aoff] !== b[j + boff]) return true;
77265         }
77266         return false;
77267     }
77268
77269     for (var i = 0; i < indices.length; i++) {
77270         var x = indices[i];
77271         var side = x[0];
77272         if (side === -1) {
77273             if (excludeFalseConflicts && !isTrueConflict(x)) {
77274                 pushOk(files[0].slice(x[1], x[1] + x[2]));
77275             } else {
77276                 flushOk();
77277                 result.push({conflict: {a: a.slice(x[1], x[1] + x[2]),
77278                                         aIndex: x[1],
77279                                         o: o.slice(x[3], x[3] + x[4]),
77280                                         oIndex: x[3],
77281                                         b: b.slice(x[5], x[5] + x[6]),
77282                                         bIndex: x[5]}});
77283             }
77284         } else {
77285             pushOk(files[side].slice(x[1], x[1] + x[2]));
77286         }
77287     }
77288
77289     flushOk();
77290     return result;
77291 }
77292
77293 function actionMergeRemoteChanges(id, localGraph, remoteGraph, formatUser) {
77294     var option = 'safe',  // 'safe', 'force_local', 'force_remote'
77295         conflicts = [];
77296
77297
77298     function user(d) {
77299         return lodash.isFunction(formatUser) ? formatUser(d) : d;
77300     }
77301
77302
77303     function mergeLocation(remote, target) {
77304         function pointEqual(a, b) {
77305             var epsilon = 1e-6;
77306             return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
77307         }
77308
77309         if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
77310             return target;
77311         }
77312         if (option === 'force_remote') {
77313             return target.update({loc: remote.loc});
77314         }
77315
77316         conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
77317         return target;
77318     }
77319
77320
77321     function mergeNodes(base, remote, target) {
77322         if (option === 'force_local' || lodash.isEqual(target.nodes, remote.nodes)) {
77323             return target;
77324         }
77325         if (option === 'force_remote') {
77326             return target.update({nodes: remote.nodes});
77327         }
77328
77329         var ccount = conflicts.length,
77330             o = base.nodes || [],
77331             a = target.nodes || [],
77332             b = remote.nodes || [],
77333             nodes = [],
77334             hunks = diff3_merge(a, o, b, true);
77335
77336         for (var i = 0; i < hunks.length; i++) {
77337             var hunk = hunks[i];
77338             if (hunk.ok) {
77339                 nodes.push.apply(nodes, hunk.ok);
77340             } else {
77341                 // for all conflicts, we can assume c.a !== c.b
77342                 // because `diff3_merge` called with `true` option to exclude false conflicts..
77343                 var c = hunk.conflict;
77344                 if (lodash.isEqual(c.o, c.a)) {  // only changed remotely
77345                     nodes.push.apply(nodes, c.b);
77346                 } else if (lodash.isEqual(c.o, c.b)) {  // only changed locally
77347                     nodes.push.apply(nodes, c.a);
77348                 } else {       // changed both locally and remotely
77349                     conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
77350                     break;
77351                 }
77352             }
77353         }
77354
77355         return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
77356     }
77357
77358
77359     function mergeChildren(targetWay, children, updates, graph) {
77360         function isUsed(node, targetWay) {
77361             var parentWays = lodash.map(graph.parentWays(node), 'id');
77362             return node.hasInterestingTags() ||
77363                 lodash.without(parentWays, targetWay.id).length > 0 ||
77364                 graph.parentRelations(node).length > 0;
77365         }
77366
77367         var ccount = conflicts.length;
77368
77369         for (var i = 0; i < children.length; i++) {
77370             var id = children[i],
77371                 node = graph.hasEntity(id);
77372
77373             // remove unused childNodes..
77374             if (targetWay.nodes.indexOf(id) === -1) {
77375                 if (node && !isUsed(node, targetWay)) {
77376                     updates.removeIds.push(id);
77377                 }
77378                 continue;
77379             }
77380
77381             // restore used childNodes..
77382             var local = localGraph.hasEntity(id),
77383                 remote = remoteGraph.hasEntity(id),
77384                 target;
77385
77386             if (option === 'force_remote' && remote && remote.visible) {
77387                 updates.replacements.push(remote);
77388
77389             } else if (option === 'force_local' && local) {
77390                 target = osmEntity$$1(local);
77391                 if (remote) {
77392                     target = target.update({ version: remote.version });
77393                 }
77394                 updates.replacements.push(target);
77395
77396             } else if (option === 'safe' && local && remote && local.version !== remote.version) {
77397                 target = osmEntity$$1(local, { version: remote.version });
77398                 if (remote.visible) {
77399                     target = mergeLocation(remote, target);
77400                 } else {
77401                     conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
77402                 }
77403
77404                 if (conflicts.length !== ccount) break;
77405                 updates.replacements.push(target);
77406             }
77407         }
77408
77409         return targetWay;
77410     }
77411
77412
77413     function updateChildren(updates, graph) {
77414         for (var i = 0; i < updates.replacements.length; i++) {
77415             graph = graph.replace(updates.replacements[i]);
77416         }
77417         if (updates.removeIds.length) {
77418             graph = actionDeleteMultiple(updates.removeIds)(graph);
77419         }
77420         return graph;
77421     }
77422
77423
77424     function mergeMembers(remote, target) {
77425         if (option === 'force_local' || lodash.isEqual(target.members, remote.members)) {
77426             return target;
77427         }
77428         if (option === 'force_remote') {
77429             return target.update({members: remote.members});
77430         }
77431
77432         conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
77433         return target;
77434     }
77435
77436
77437     function mergeTags(base, remote, target) {
77438         function ignoreKey(k) {
77439             return lodash.includes(dataDiscarded, k);
77440         }
77441
77442         if (option === 'force_local' || lodash.isEqual(target.tags, remote.tags)) {
77443             return target;
77444         }
77445         if (option === 'force_remote') {
77446             return target.update({tags: remote.tags});
77447         }
77448
77449         var ccount = conflicts.length,
77450             o = base.tags || {},
77451             a = target.tags || {},
77452             b = remote.tags || {},
77453             keys = lodash.reject(lodash.union(lodash.keys(o), lodash.keys(a), lodash.keys(b)), ignoreKey),
77454             tags = lodash.clone(a),
77455             changed = false;
77456
77457         for (var i = 0; i < keys.length; i++) {
77458             var k = keys[i];
77459
77460             if (o[k] !== b[k] && a[k] !== b[k]) {    // changed remotely..
77461                 if (o[k] !== a[k]) {      // changed locally..
77462                     conflicts.push(t('merge_remote_changes.conflict.tags',
77463                         { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
77464
77465                 } else {                  // unchanged locally, accept remote change..
77466                     if (b.hasOwnProperty(k)) {
77467                         tags[k] = b[k];
77468                     } else {
77469                         delete tags[k];
77470                     }
77471                     changed = true;
77472                 }
77473             }
77474         }
77475
77476         return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
77477     }
77478
77479
77480     //  `graph.base()` is the common ancestor of the two graphs.
77481     //  `localGraph` contains user's edits up to saving
77482     //  `remoteGraph` contains remote edits to modified nodes
77483     //  `graph` must be a descendent of `localGraph` and may include
77484     //      some conflict resolution actions performed on it.
77485     //
77486     //                  --- ... --- `localGraph` -- ... -- `graph`
77487     //                 /
77488     //  `graph.base()` --- ... --- `remoteGraph`
77489     //
77490     var action = function(graph) {
77491         var updates = { replacements: [], removeIds: [] },
77492             base = graph.base().entities[id],
77493             local = localGraph.entity(id),
77494             remote = remoteGraph.entity(id),
77495             target = osmEntity$$1(local, { version: remote.version });
77496
77497         // delete/undelete
77498         if (!remote.visible) {
77499             if (option === 'force_remote') {
77500                 return actionDeleteMultiple([id])(graph);
77501
77502             } else if (option === 'force_local') {
77503                 if (target.type === 'way') {
77504                     target = mergeChildren(target, lodash.uniq(local.nodes), updates, graph);
77505                     graph = updateChildren(updates, graph);
77506                 }
77507                 return graph.replace(target);
77508
77509             } else {
77510                 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
77511                 return graph;  // do nothing
77512             }
77513         }
77514
77515         // merge
77516         if (target.type === 'node') {
77517             target = mergeLocation(remote, target);
77518
77519         } else if (target.type === 'way') {
77520             // pull in any child nodes that may not be present locally..
77521             graph.rebase(remoteGraph.childNodes(remote), [graph], false);
77522             target = mergeNodes(base, remote, target);
77523             target = mergeChildren(target, lodash.union(local.nodes, remote.nodes), updates, graph);
77524
77525         } else if (target.type === 'relation') {
77526             target = mergeMembers(remote, target);
77527         }
77528
77529         target = mergeTags(base, remote, target);
77530
77531         if (!conflicts.length) {
77532             graph = updateChildren(updates, graph).replace(target);
77533         }
77534
77535         return graph;
77536     };
77537
77538
77539     action.withOption = function(opt) {
77540         option = opt;
77541         return action;
77542     };
77543
77544
77545     action.conflicts = function() {
77546         return conflicts;
77547     };
77548
77549
77550     return action;
77551 }
77552
77553 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
77554 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
77555 function actionMove(moveIds, tryDelta, projection, cache) {
77556     var delta = tryDelta;
77557
77558     function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
77559     function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
77560
77561     function setupCache(graph) {
77562         function canMove(nodeId) {
77563             // Allow movement of any node that is in the selectedIDs list..
77564             if (moveIds.indexOf(nodeId) !== -1) return true;
77565
77566             // Allow movement of a vertex where 2 ways meet..
77567             var parents = lodash.map(graph.parentWays(graph.entity(nodeId)), 'id');
77568             if (parents.length < 3) return true;
77569
77570             // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
77571             var parentsMoving = lodash.every(parents, function(id) { return cache.moving[id]; });
77572             if (!parentsMoving) delete cache.moving[nodeId];
77573
77574             return parentsMoving;
77575         }
77576
77577         function cacheEntities(ids) {
77578             ids.forEach(function(id) {
77579                 if (cache.moving[id]) return;
77580                 cache.moving[id] = true;
77581
77582                 var entity = graph.hasEntity(id);
77583                 if (!entity) return;
77584
77585                 if (entity.type === 'node') {
77586                     cache.nodes.push(id);
77587                     cache.startLoc[id] = entity.loc;
77588                 } else if (entity.type === 'way') {
77589                     cache.ways.push(id);
77590                     cacheEntities(entity.nodes);
77591                 } else {
77592                     cacheEntities(entity.members.map(function(member) {
77593                         return member.id;
77594                     }));
77595                 }
77596             });
77597         }
77598
77599         function cacheIntersections(ids) {
77600             function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
77601
77602             ids.forEach(function(id) {
77603                 // consider only intersections with 1 moved and 1 unmoved way.
77604                 var childNodes = graph.childNodes(graph.entity(id));
77605                 childNodes.forEach(function(node) {
77606                     var parents = graph.parentWays(node);
77607                     if (parents.length !== 2) return;
77608
77609                     var moved = graph.entity(id),
77610                         unmoved = lodash.find(parents, function(way) { return !cache.moving[way.id]; });
77611                     if (!unmoved) return;
77612
77613                     // exclude ways that are overly connected..
77614                     if (lodash.intersection(moved.nodes, unmoved.nodes).length > 2) return;
77615
77616                     if (moved.isArea() || unmoved.isArea()) return;
77617
77618                     cache.intersection[node.id] = {
77619                         nodeId: node.id,
77620                         movedId: moved.id,
77621                         unmovedId: unmoved.id,
77622                         movedIsEP: isEndpoint(moved, node.id),
77623                         unmovedIsEP: isEndpoint(unmoved, node.id)
77624                     };
77625                 });
77626             });
77627         }
77628
77629
77630         if (!cache) {
77631             cache = {};
77632         }
77633         if (!cache.ok) {
77634             cache.moving = {};
77635             cache.intersection = {};
77636             cache.replacedVertex = {};
77637             cache.startLoc = {};
77638             cache.nodes = [];
77639             cache.ways = [];
77640
77641             cacheEntities(moveIds);
77642             cacheIntersections(cache.ways);
77643             cache.nodes = lodash.filter(cache.nodes, canMove);
77644
77645             cache.ok = true;
77646         }
77647     }
77648
77649
77650     // Place a vertex where the moved vertex used to be, to preserve way shape..
77651     function replaceMovedVertex(nodeId, wayId, graph, delta) {
77652         var way = graph.entity(wayId),
77653             moved = graph.entity(nodeId),
77654             movedIndex = way.nodes.indexOf(nodeId),
77655             len, prevIndex, nextIndex;
77656
77657         if (way.isClosed()) {
77658             len = way.nodes.length - 1;
77659             prevIndex = (movedIndex + len - 1) % len;
77660             nextIndex = (movedIndex + len + 1) % len;
77661         } else {
77662             len = way.nodes.length;
77663             prevIndex = movedIndex - 1;
77664             nextIndex = movedIndex + 1;
77665         }
77666
77667         var prev = graph.hasEntity(way.nodes[prevIndex]),
77668             next = graph.hasEntity(way.nodes[nextIndex]);
77669
77670         // Don't add orig vertex at endpoint..
77671         if (!prev || !next) return graph;
77672
77673         var key = wayId + '_' + nodeId,
77674             orig = cache.replacedVertex[key];
77675         if (!orig) {
77676             orig = osmNode();
77677             cache.replacedVertex[key] = orig;
77678             cache.startLoc[orig.id] = cache.startLoc[nodeId];
77679         }
77680
77681         var start, end;
77682         if (delta) {
77683             start = projection(cache.startLoc[nodeId]);
77684             end = projection.invert(vecAdd(start, delta));
77685         } else {
77686             end = cache.startLoc[nodeId];
77687         }
77688         orig = orig.move(end);
77689
77690         var angle = Math.abs(geoAngle(orig, prev, projection) -
77691                 geoAngle(orig, next, projection)) * 180 / Math.PI;
77692
77693         // Don't add orig vertex if it would just make a straight line..
77694         if (angle > 175 && angle < 185) return graph;
77695
77696         // Don't add orig vertex if another point is already nearby (within 10m)
77697         if (geoSphericalDistance(prev.loc, orig.loc) < 10 ||
77698             geoSphericalDistance(orig.loc, next.loc) < 10) return graph;
77699
77700         // moving forward or backward along way?
77701         var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
77702             p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
77703             d1 = geoPathLength(p1),
77704             d2 = geoPathLength(p2),
77705             insertAt = (d1 < d2) ? movedIndex : nextIndex;
77706
77707         // moving around closed loop?
77708         if (way.isClosed() && insertAt === 0) insertAt = len;
77709
77710         way = way.addNode(orig.id, insertAt);
77711         return graph.replace(orig).replace(way);
77712     }
77713
77714
77715     // Reorder nodes around intersections that have moved..
77716     function unZorroIntersection(intersection, graph) {
77717         var vertex = graph.entity(intersection.nodeId),
77718             way1 = graph.entity(intersection.movedId),
77719             way2 = graph.entity(intersection.unmovedId),
77720             isEP1 = intersection.movedIsEP,
77721             isEP2 = intersection.unmovedIsEP;
77722
77723         // don't move the vertex if it is the endpoint of both ways.
77724         if (isEP1 && isEP2) return graph;
77725
77726         var nodes1 = lodash.without(graph.childNodes(way1), vertex),
77727             nodes2 = lodash.without(graph.childNodes(way2), vertex);
77728
77729         if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
77730         if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
77731
77732         var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection),
77733             edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection),
77734             loc;
77735
77736         // snap vertex to nearest edge (or some point between them)..
77737         if (!isEP1 && !isEP2) {
77738             var epsilon = 1e-4, maxIter = 10;
77739             for (var i = 0; i < maxIter; i++) {
77740                 loc = geoInterp(edge1.loc, edge2.loc, 0.5);
77741                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
77742                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
77743                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
77744             }
77745         } else if (!isEP1) {
77746             loc = edge1.loc;
77747         } else {
77748             loc = edge2.loc;
77749         }
77750
77751         graph = graph.replace(vertex.move(loc));
77752
77753         // if zorro happened, reorder nodes..
77754         if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
77755             way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
77756             graph = graph.replace(way1);
77757         }
77758         if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
77759             way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
77760             graph = graph.replace(way2);
77761         }
77762
77763         return graph;
77764     }
77765
77766
77767     function cleanupIntersections(graph) {
77768         lodash.each(cache.intersection, function(obj) {
77769             graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
77770             graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
77771             graph = unZorroIntersection(obj, graph);
77772         });
77773
77774         return graph;
77775     }
77776
77777
77778     // check if moving way endpoint can cross an unmoved way, if so limit delta..
77779     function limitDelta(graph) {
77780         lodash.each(cache.intersection, function(obj) {
77781             // Don't limit movement if this is vertex joins 2 endpoints..
77782             if (obj.movedIsEP && obj.unmovedIsEP) return;
77783             // Don't limit movement if this vertex is not an endpoint anyway..
77784             if (!obj.movedIsEP) return;
77785
77786             var node = graph.entity(obj.nodeId),
77787                 start = projection(node.loc),
77788                 end = vecAdd(start, delta),
77789                 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
77790                 movedPath = lodash.map(lodash.map(movedNodes, 'loc'),
77791                     function(loc) { return vecAdd(projection(loc), delta); }),
77792                 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
77793                 unmovedPath = lodash.map(lodash.map(unmovedNodes, 'loc'), projection),
77794                 hits = geoPathIntersections(movedPath, unmovedPath);
77795
77796             for (var i = 0; i < hits.length; i++) {
77797                 if (lodash.isEqual(hits[i], end)) continue;
77798                 var edge = geoChooseEdge(unmovedNodes, end, projection);
77799                 delta = vecSub(projection(edge.loc), start);
77800             }
77801         });
77802     }
77803
77804
77805     var action = function(graph) {
77806         if (delta[0] === 0 && delta[1] === 0) return graph;
77807
77808         setupCache(graph);
77809
77810         if (!lodash.isEmpty(cache.intersection)) {
77811             limitDelta(graph);
77812         }
77813
77814         lodash.each(cache.nodes, function(id) {
77815             var node = graph.entity(id),
77816                 start = projection(node.loc),
77817                 end = vecAdd(start, delta);
77818             graph = graph.replace(node.move(projection.invert(end)));
77819         });
77820
77821         if (!lodash.isEmpty(cache.intersection)) {
77822             graph = cleanupIntersections(graph);
77823         }
77824
77825         return graph;
77826     };
77827
77828
77829     action.delta = function() {
77830         return delta;
77831     };
77832
77833
77834     return action;
77835 }
77836
77837 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
77838 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
77839 function actionMoveNode(nodeId, loc) {
77840     return function(graph) {
77841         return graph.replace(graph.entity(nodeId).move(loc));
77842     };
77843 }
77844
77845 function actionNoop() {
77846     return function(graph) {
77847         return graph;
77848     };
77849 }
77850
77851 /*
77852  * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
77853  */
77854 function actionOrthogonalize(wayId, projection) {
77855     var threshold = 12, // degrees within right or straight to alter
77856         lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
77857         upperThreshold = Math.cos(threshold * Math.PI / 180);
77858
77859
77860     var action = function(graph, t) {
77861         if (t === null || !isFinite(t)) t = 1;
77862         t = Math.min(Math.max(+t, 0), 1);
77863
77864         var way = graph.entity(wayId),
77865             nodes = graph.childNodes(way),
77866             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); }),
77867             corner = {i: 0, dotp: 1},
77868             epsilon = 1e-4,
77869             node, loc, score, motions, i, j;
77870
77871         if (points.length === 3) {   // move only one vertex for right triangle
77872             for (i = 0; i < 1000; i++) {
77873                 motions = points.map(calcMotion);
77874                 points[corner.i] = addPoints(points[corner.i], motions[corner.i]);
77875                 score = corner.dotp;
77876                 if (score < epsilon) {
77877                     break;
77878                 }
77879             }
77880
77881             node = graph.entity(nodes[corner.i].id);
77882             loc = projection.invert(points[corner.i]);
77883             graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
77884
77885         } else {
77886             var best,
77887                 originalPoints = lodash.clone(points);
77888             score = Infinity;
77889
77890             for (i = 0; i < 1000; i++) {
77891                 motions = points.map(calcMotion);
77892                 for (j = 0; j < motions.length; j++) {
77893                     points[j] = addPoints(points[j],motions[j]);
77894                 }
77895                 var newScore = squareness(points);
77896                 if (newScore < score) {
77897                     best = lodash.clone(points);
77898                     score = newScore;
77899                 }
77900                 if (score < epsilon) {
77901                     break;
77902                 }
77903             }
77904
77905             points = best;
77906
77907             for (i = 0; i < points.length; i++) {
77908                 // only move the points that actually moved
77909                 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
77910                     loc = projection.invert(points[i]);
77911                     node = graph.entity(nodes[i].id);
77912                     graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
77913                 }
77914             }
77915
77916             // remove empty nodes on straight sections
77917             for (i = 0; t === 1 && i < points.length; i++) {
77918                 node = graph.entity(nodes[i].id);
77919
77920                 if (graph.parentWays(node).length > 1 ||
77921                     graph.parentRelations(node).length ||
77922                     node.hasInterestingTags()) {
77923                     continue;
77924                 }
77925
77926                 var dotp = normalizedDotProduct(i, points);
77927                 if (dotp < -1 + epsilon) {
77928                     graph = actionDeleteNode(node.id)(graph);
77929                 }
77930             }
77931         }
77932
77933         return graph;
77934
77935
77936         function calcMotion(b, i, array) {
77937             var a = array[(i - 1 + array.length) % array.length],
77938                 c = array[(i + 1) % array.length],
77939                 p = subtractPoints(a, b),
77940                 q = subtractPoints(c, b),
77941                 scale, dotp;
77942
77943             scale = 2 * Math.min(geoEuclideanDistance(p, [0, 0]), geoEuclideanDistance(q, [0, 0]));
77944             p = normalizePoint(p, 1.0);
77945             q = normalizePoint(q, 1.0);
77946
77947             dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
77948
77949             // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
77950             if (array.length > 3) {
77951                 if (dotp < -0.707106781186547) {
77952                     dotp += 1.0;
77953                 }
77954             } else if (dotp && Math.abs(dotp) < corner.dotp) {
77955                 corner.i = i;
77956                 corner.dotp = Math.abs(dotp);
77957             }
77958
77959             return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
77960         }
77961     };
77962
77963
77964     function squareness(points) {
77965         return points.reduce(function(sum, val, i, array) {
77966             var dotp = normalizedDotProduct(i, array);
77967
77968             dotp = filterDotProduct(dotp);
77969             return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
77970         }, 0);
77971     }
77972
77973
77974     function normalizedDotProduct(i, points) {
77975         var a = points[(i - 1 + points.length) % points.length],
77976             b = points[i],
77977             c = points[(i + 1) % points.length],
77978             p = subtractPoints(a, b),
77979             q = subtractPoints(c, b);
77980
77981         p = normalizePoint(p, 1.0);
77982         q = normalizePoint(q, 1.0);
77983
77984         return p[0] * q[0] + p[1] * q[1];
77985     }
77986
77987
77988     function subtractPoints(a, b) {
77989         return [a[0] - b[0], a[1] - b[1]];
77990     }
77991
77992
77993     function addPoints(a, b) {
77994         return [a[0] + b[0], a[1] + b[1]];
77995     }
77996
77997
77998     function normalizePoint(point, scale) {
77999         var vector = [0, 0];
78000         var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
78001         if (length !== 0) {
78002             vector[0] = point[0] / length;
78003             vector[1] = point[1] / length;
78004         }
78005
78006         vector[0] *= scale;
78007         vector[1] *= scale;
78008
78009         return vector;
78010     }
78011
78012
78013     function filterDotProduct(dotp) {
78014         if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
78015             return dotp;
78016         }
78017
78018         return 0;
78019     }
78020
78021
78022     action.disabled = function(graph) {
78023         var way = graph.entity(wayId),
78024             nodes = graph.childNodes(way),
78025             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); });
78026
78027         if (squareness(points)) {
78028             return false;
78029         }
78030
78031         return 'not_squarish';
78032     };
78033
78034
78035     action.transitionable = true;
78036
78037
78038     return action;
78039 }
78040
78041 // Split a way at the given node.
78042 //
78043 // Optionally, split only the given ways, if multiple ways share
78044 // the given node.
78045 //
78046 // This is the inverse of `iD.actionJoin`.
78047 //
78048 // For testing convenience, accepts an ID to assign to the new way.
78049 // Normally, this will be undefined and the way will automatically
78050 // be assigned a new ID.
78051 //
78052 // Reference:
78053 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
78054 //
78055 function actionSplit(nodeId, newWayIds) {
78056     var wayIds;
78057
78058     // if the way is closed, we need to search for a partner node
78059     // to split the way at.
78060     //
78061     // The following looks for a node that is both far away from
78062     // the initial node in terms of way segment length and nearby
78063     // in terms of beeline-distance. This assures that areas get
78064     // split on the most "natural" points (independent of the number
78065     // of nodes).
78066     // For example: bone-shaped areas get split across their waist
78067     // line, circles across the diameter.
78068     function splitArea(nodes, idxA, graph) {
78069         var lengths = new Array(nodes.length),
78070             length,
78071             i,
78072             best = 0,
78073             idxB;
78074
78075         function wrap(index) {
78076             return utilWrap(index, nodes.length);
78077         }
78078
78079         function dist(nA, nB) {
78080             return geoSphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
78081         }
78082
78083         // calculate lengths
78084         length = 0;
78085         for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
78086             length += dist(nodes[i], nodes[wrap(i-1)]);
78087             lengths[i] = length;
78088         }
78089
78090         length = 0;
78091         for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
78092             length += dist(nodes[i], nodes[wrap(i+1)]);
78093             if (length < lengths[i])
78094                 lengths[i] = length;
78095         }
78096
78097         // determine best opposite node to split
78098         for (i = 0; i < nodes.length; i++) {
78099             var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
78100             if (cost > best) {
78101                 idxB = i;
78102                 best = cost;
78103             }
78104         }
78105
78106         return idxB;
78107     }
78108
78109
78110     function split(graph, wayA, newWayId) {
78111         var wayB = osmWay({id: newWayId, tags: wayA.tags}),
78112             nodesA,
78113             nodesB,
78114             isArea = wayA.isArea(),
78115             isOuter = osmIsSimpleMultipolygonOuterMember(wayA, graph);
78116
78117         if (wayA.isClosed()) {
78118             var nodes = wayA.nodes.slice(0, -1),
78119                 idxA = lodash.indexOf(nodes, nodeId),
78120                 idxB = splitArea(nodes, idxA, graph);
78121
78122             if (idxB < idxA) {
78123                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
78124                 nodesB = nodes.slice(idxB, idxA + 1);
78125             } else {
78126                 nodesA = nodes.slice(idxA, idxB + 1);
78127                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
78128             }
78129         } else {
78130             var idx = lodash.indexOf(wayA.nodes, nodeId, 1);
78131             nodesA = wayA.nodes.slice(0, idx + 1);
78132             nodesB = wayA.nodes.slice(idx);
78133         }
78134
78135         wayA = wayA.update({nodes: nodesA});
78136         wayB = wayB.update({nodes: nodesB});
78137
78138         graph = graph.replace(wayA);
78139         graph = graph.replace(wayB);
78140
78141         graph.parentRelations(wayA).forEach(function(relation) {
78142             if (relation.isRestriction()) {
78143                 var via = relation.memberByRole('via');
78144                 if (via && wayB.contains(via.id)) {
78145                     relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
78146                     graph = graph.replace(relation);
78147                 }
78148             } else {
78149                 if (relation === isOuter) {
78150                     graph = graph.replace(relation.mergeTags(wayA.tags));
78151                     graph = graph.replace(wayA.update({tags: {}}));
78152                     graph = graph.replace(wayB.update({tags: {}}));
78153                 }
78154
78155                 var member = {
78156                     id: wayB.id,
78157                     type: 'way',
78158                     role: relation.memberById(wayA.id).role
78159                 };
78160
78161                 graph = actionAddMember(relation.id, member)(graph);
78162             }
78163         });
78164
78165         if (!isOuter && isArea) {
78166             var multipolygon = osmRelation({
78167                 tags: lodash.extend({}, wayA.tags, {type: 'multipolygon'}),
78168                 members: [
78169                     {id: wayA.id, role: 'outer', type: 'way'},
78170                     {id: wayB.id, role: 'outer', type: 'way'}
78171                 ]});
78172
78173             graph = graph.replace(multipolygon);
78174             graph = graph.replace(wayA.update({tags: {}}));
78175             graph = graph.replace(wayB.update({tags: {}}));
78176         }
78177
78178         return graph;
78179     }
78180
78181
78182     var action = function(graph) {
78183         var candidates = action.ways(graph);
78184         for (var i = 0; i < candidates.length; i++) {
78185             graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
78186         }
78187         return graph;
78188     };
78189
78190
78191     action.ways = function(graph) {
78192         var node = graph.entity(nodeId),
78193             parents = graph.parentWays(node),
78194             hasLines = lodash.some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
78195
78196         return parents.filter(function(parent) {
78197             if (wayIds && wayIds.indexOf(parent.id) === -1)
78198                 return false;
78199
78200             if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
78201                 return false;
78202
78203             if (parent.isClosed()) {
78204                 return true;
78205             }
78206
78207             for (var i = 1; i < parent.nodes.length - 1; i++) {
78208                 if (parent.nodes[i] === nodeId) {
78209                     return true;
78210                 }
78211             }
78212
78213             return false;
78214         });
78215     };
78216
78217
78218     action.disabled = function(graph) {
78219         var candidates = action.ways(graph);
78220         if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
78221             return 'not_eligible';
78222     };
78223
78224
78225     action.limitWays = function(_) {
78226         if (!arguments.length) return wayIds;
78227         wayIds = _;
78228         return action;
78229     };
78230
78231
78232     return action;
78233 }
78234
78235 // Create a restriction relation for `turn`, which must have the following structure:
78236 //
78237 //     {
78238 //         from: { node: <node ID>, way: <way ID> },
78239 //         via:  { node: <node ID> },
78240 //         to:   { node: <node ID>, way: <way ID> },
78241 //         restriction: <'no_right_turn', 'no_left_turn', etc.>
78242 //     }
78243 //
78244 // This specifies a restriction of type `restriction` when traveling from
78245 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
78246 // (The action does not check that these entities form a valid intersection.)
78247 //
78248 // If `restriction` is not provided, it is automatically determined by
78249 // osmInferRestriction.
78250 //
78251 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
78252 // and `to.node` are used to determine which portion of the split ways become
78253 // members of the restriction.
78254 //
78255 // For testing convenience, accepts an ID to assign to the new relation.
78256 // Normally, this will be undefined and the relation will automatically
78257 // be assigned a new ID.
78258 //
78259 function actionRestrictTurn(turn, projection, restrictionId) {
78260
78261     return function(graph) {
78262         var from = graph.entity(turn.from.way),
78263             via  = graph.entity(turn.via.node),
78264             to   = graph.entity(turn.to.way);
78265
78266         function isClosingNode(way, nodeId) {
78267             return nodeId === way.first() && nodeId === way.last();
78268         }
78269
78270         function split(toOrFrom) {
78271             var newID = toOrFrom.newID || osmWay().id;
78272             graph = actionSplit(via.id, [newID])
78273                 .limitWays([toOrFrom.way])(graph);
78274
78275             var a = graph.entity(newID),
78276                 b = graph.entity(toOrFrom.way);
78277
78278             if (a.nodes.indexOf(toOrFrom.node) !== -1) {
78279                 return [a, b];
78280             } else {
78281                 return [b, a];
78282             }
78283         }
78284
78285         if (!from.affix(via.id) || isClosingNode(from, via.id)) {
78286             if (turn.from.node === turn.to.node) {
78287                 // U-turn
78288                 from = to = split(turn.from)[0];
78289             } else if (turn.from.way === turn.to.way) {
78290                 // Straight-on or circular
78291                 var s = split(turn.from);
78292                 from = s[0];
78293                 to   = s[1];
78294             } else {
78295                 // Other
78296                 from = split(turn.from)[0];
78297             }
78298         }
78299
78300         if (!to.affix(via.id) || isClosingNode(to, via.id)) {
78301             to = split(turn.to)[0];
78302         }
78303
78304         return graph.replace(osmRelation({
78305             id: restrictionId,
78306             tags: {
78307                 type: 'restriction',
78308                 restriction: turn.restriction ||
78309                     osmInferRestriction(
78310                         graph,
78311                         turn.from,
78312                         turn.via,
78313                         turn.to,
78314                         projection)
78315             },
78316             members: [
78317                 {id: from.id, type: 'way',  role: 'from'},
78318                 {id: via.id,  type: 'node', role: 'via'},
78319                 {id: to.id,   type: 'way',  role: 'to'}
78320             ]
78321         }));
78322     };
78323 }
78324
78325 function actionRevert(id) {
78326     var action = function(graph) {
78327         var entity = graph.hasEntity(id),
78328             base = graph.base().entities[id];
78329
78330         if (entity && !base) {    // entity will be removed..
78331             if (entity.type === 'node') {
78332                 graph.parentWays(entity)
78333                     .forEach(function(parent) {
78334                         parent = parent.removeNode(id);
78335                         graph = graph.replace(parent);
78336
78337                         if (parent.isDegenerate()) {
78338                             graph = actionDeleteWay(parent.id)(graph);
78339                         }
78340                     });
78341             }
78342
78343             graph.parentRelations(entity)
78344                 .forEach(function(parent) {
78345                     parent = parent.removeMembersWithID(id);
78346                     graph = graph.replace(parent);
78347
78348                     if (parent.isDegenerate()) {
78349                         graph = actionDeleteRelation(parent.id)(graph);
78350                     }
78351                 });
78352         }
78353
78354         return graph.revert(id);
78355     };
78356
78357     return action;
78358 }
78359
78360 function actionRotate(rotateIds, pivot, angle, projection) {
78361
78362     var action = function(graph) {
78363         return graph.update(function(graph) {
78364             utilGetAllNodes(rotateIds, graph).forEach(function(node) {
78365                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
78366                 graph = graph.replace(node.move(projection.invert(point)));
78367             });
78368         });
78369     };
78370
78371     return action;
78372 }
78373
78374 /*
78375  * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
78376  */
78377 function actionStraighten(wayId, projection) {
78378
78379     function positionAlongWay(n, s, e) {
78380         return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1])) /
78381                 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
78382     }
78383
78384
78385     var action = function(graph, t) {
78386         if (t === null || !isFinite(t)) t = 1;
78387         t = Math.min(Math.max(+t, 0), 1);
78388
78389         var way = graph.entity(wayId),
78390             nodes = graph.childNodes(way),
78391             points = nodes.map(function(n) { return projection(n.loc); }),
78392             startPoint = points[0],
78393             endPoint = points[points.length-1],
78394             toDelete = [],
78395             i;
78396
78397         for (i = 1; i < points.length-1; i++) {
78398             var node = nodes[i],
78399                 point = points[i];
78400
78401             if (t < 1 || graph.parentWays(node).length > 1 ||
78402                 graph.parentRelations(node).length ||
78403                 node.hasInterestingTags()) {
78404
78405                 var u = positionAlongWay(point, startPoint, endPoint),
78406                     p = [
78407                         startPoint[0] + u * (endPoint[0] - startPoint[0]),
78408                         startPoint[1] + u * (endPoint[1] - startPoint[1])
78409                     ],
78410                     loc2 = projection.invert(p);
78411
78412                 graph = graph.replace(node.move(geoInterp(node.loc, loc2, t)));
78413
78414             } else {
78415                 // safe to delete
78416                 if (toDelete.indexOf(node) === -1) {
78417                     toDelete.push(node);
78418                 }
78419             }
78420         }
78421
78422         for (i = 0; i < toDelete.length; i++) {
78423             graph = actionDeleteNode(toDelete[i].id)(graph);
78424         }
78425
78426         return graph;
78427     };
78428
78429
78430     action.disabled = function(graph) {
78431         // check way isn't too bendy
78432         var way = graph.entity(wayId),
78433             nodes = graph.childNodes(way),
78434             points = nodes.map(function(n) { return projection(n.loc); }),
78435             startPoint = points[0],
78436             endPoint = points[points.length-1],
78437             threshold = 0.2 * geoEuclideanDistance(startPoint, endPoint),
78438             i;
78439
78440         if (threshold === 0) {
78441             return 'too_bendy';
78442         }
78443
78444         for (i = 1; i < points.length-1; i++) {
78445             var point = points[i],
78446                 u = positionAlongWay(point, startPoint, endPoint),
78447                 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
78448                 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
78449                 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
78450
78451             // to bendy if point is off by 20% of total start/end distance in projected space
78452             if (isNaN(dist) || dist > threshold) {
78453                 return 'too_bendy';
78454             }
78455         }
78456     };
78457
78458
78459     action.transitionable = true;
78460
78461
78462     return action;
78463 }
78464
78465 // Remove the effects of `turn.restriction` on `turn`, which must have the
78466 // following structure:
78467 //
78468 //     {
78469 //         from: { node: <node ID>, way: <way ID> },
78470 //         via:  { node: <node ID> },
78471 //         to:   { node: <node ID>, way: <way ID> },
78472 //         restriction: <relation ID>
78473 //     }
78474 //
78475 // In the simple case, `restriction` is a reference to a `no_*` restriction
78476 // on the turn itself. In this case, it is simply deleted.
78477 //
78478 // The more complex case is where `restriction` references an `only_*`
78479 // restriction on a different turn in the same intersection. In that case,
78480 // that restriction is also deleted, but at the same time restrictions on
78481 // the turns other than the first two are created.
78482 //
78483 function actionUnrestrictTurn(turn) {
78484     return function(graph) {
78485         return actionDeleteRelation(turn.restriction)(graph);
78486     };
78487 }
78488
78489 /* Reflect the given area around its axis of symmetry */
78490 function actionReflect(reflectIds, projection$$1) {
78491     var useLongAxis = true;
78492
78493
78494     // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
78495     // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
78496     function getSmallestSurroundingRectangle(graph, nodes) {
78497         var points = nodes.map(function(n) { return projection$$1(n.loc); }),
78498             hull = d3polygonHull(points),
78499             centroid = d3polygonCentroid(hull),
78500             minArea = Infinity,
78501             ssrExtent = [],
78502             ssrAngle = 0,
78503             c1 = hull[0];
78504
78505         for (var i = 0; i < hull.length - 1; i++) {
78506             var c2 = hull[i + 1],
78507                 angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]),
78508                 poly = geoRotate(hull, -angle, centroid),
78509                 extent$$1 = poly.reduce(function(extent$$1, point) {
78510                         return extent$$1.extend(geoExtent$$1(point));
78511                     }, geoExtent$$1()),
78512                 area$$1 = extent$$1.area();
78513
78514             if (area$$1 < minArea) {
78515                 minArea = area$$1;
78516                 ssrExtent = extent$$1;
78517                 ssrAngle = angle;
78518             }
78519             c1 = c2;
78520         }
78521
78522         return {
78523             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
78524             angle: ssrAngle
78525         };
78526     }
78527
78528
78529     var action = function(graph, t) {
78530         if (t === null || !isFinite(t)) t = 1;
78531         t = Math.min(Math.max(+t, 0), 1);
78532
78533         var nodes = utilGetAllNodes(reflectIds, graph),
78534             ssr = getSmallestSurroundingRectangle(graph, nodes);
78535
78536         // Choose line pq = axis of symmetry.
78537         // The shape's surrounding rectangle has 2 axes of symmetry.
78538         // Reflect across the longer axis by default.
78539         var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2 ],
78540             q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2 ],
78541             p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2 ],
78542             q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2 ],
78543             p, q;
78544
78545         var isLong = (geoEuclideanDistance(p1, q1) > geoEuclideanDistance(p2, q2));
78546         if ((useLongAxis && isLong) || (!useLongAxis && !isLong)) {
78547             p = p1;
78548             q = q1;
78549         } else {
78550             p = p2;
78551             q = q2;
78552         }
78553
78554         // reflect c across pq
78555         // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
78556         var dx = q[0] - p[0];
78557         var dy = q[1] - p[1];
78558         var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
78559         var b = 2 * dx * dy / (dx * dx + dy * dy);
78560         for (var i = 0; i < nodes.length; i++) {
78561             var node = nodes[i];
78562             var c = projection$$1(node.loc);
78563             var c2 = [
78564                 a * (c[0] - p[0]) + b * (c[1] - p[1]) + p[0],
78565                 b * (c[0] - p[0]) - a * (c[1] - p[1]) + p[1]
78566             ];
78567             var loc2 = projection$$1.invert(c2);
78568             node = node.move(geoInterp(node.loc, loc2, t));
78569             graph = graph.replace(node);
78570         }
78571
78572         return graph;
78573     };
78574
78575
78576     action.useLongAxis = function(_) {
78577         if (!arguments.length) return useLongAxis;
78578         useLongAxis = _;
78579         return action;
78580     };
78581
78582
78583     action.transitionable = true;
78584
78585
78586     return action;
78587 }
78588
78589
78590
78591 var index$17 = Object.freeze({
78592         d3combobox: d3combobox,
78593         d3geoTile: d3geoTile,
78594         d3keybinding: d3keybinding
78595 });
78596
78597 /* export some legacy symbols: */
78598 var Connection = services.osm;
78599 var debug = false;
78600
78601
78602
78603
78604 var iD = Object.freeze({
78605         Connection: Connection,
78606         debug: debug,
78607         d3: index$2,
78608         _: lodash$1,
78609         lib: index$17,
78610         Context: coreContext,
78611         setAreaKeys: setAreaKeys,
78612         Difference: coreDifference,
78613         Graph: coreGraph$$1,
78614         History: coreHistory,
78615         Tree: coreTree,
78616         Entity: osmEntity$$1,
78617         Node: osmNode,
78618         Relation: osmRelation,
78619         Way: osmWay,
78620         BackgroundSource: rendererBackgroundSource,
78621         Background: rendererBackground,
78622         Features: rendererFeatures,
78623         Map: rendererMap,
78624         TileLayer: rendererTileLayer,
78625         Detect: utilDetect,
78626         actionAddEntity: actionAddEntity,
78627         actionAddMember: actionAddMember,
78628         actionAddMidpoint: actionAddMidpoint,
78629         actionAddVertex: actionAddVertex,
78630         actionChangeMember: actionChangeMember,
78631         actionChangePreset: actionChangePreset,
78632         actionChangeTags: actionChangeTags,
78633         actionCircularize: actionCircularize,
78634         actionConnect: actionConnect,
78635         actionCopyEntities: actionCopyEntities,
78636         actionDeleteMember: actionDeleteMember,
78637         actionDeleteMultiple: actionDeleteMultiple,
78638         actionDeleteNode: actionDeleteNode,
78639         actionDeleteRelation: actionDeleteRelation,
78640         actionDeleteWay: actionDeleteWay,
78641         actionDeprecateTags: actionDeprecateTags,
78642         actionDiscardTags: actionDiscardTags,
78643         actionDisconnect: actionDisconnect,
78644         actionJoin: actionJoin,
78645         actionMerge: actionMerge,
78646         actionMergePolygon: actionMergePolygon,
78647         actionMergeRemoteChanges: actionMergeRemoteChanges,
78648         actionMove: actionMove,
78649         actionMoveNode: actionMoveNode,
78650         actionNoop: actionNoop,
78651         actionOrthogonalize: actionOrthogonalize,
78652         actionRestrictTurn: actionRestrictTurn,
78653         actionReverse: actionReverse,
78654         actionRevert: actionRevert,
78655         actionRotate: actionRotate,
78656         actionSplit: actionSplit,
78657         actionStraighten: actionStraighten,
78658         actionUnrestrictTurn: actionUnrestrictTurn,
78659         actionReflect: actionReflect,
78660         behaviorAddWay: behaviorAddWay,
78661         behaviorBreathe: behaviorBreathe,
78662         behaviorCopy: behaviorCopy,
78663         behaviorDrag: behaviorDrag,
78664         behaviorDrawWay: behaviorDrawWay,
78665         behaviorDraw: behaviorDraw,
78666         behaviorEdit: behaviorEdit,
78667         behaviorHash: behaviorHash,
78668         behaviorHover: behaviorHover,
78669         behaviorLasso: behaviorLasso,
78670         behaviorOperation: behaviorOperation,
78671         behaviorPaste: behaviorPaste,
78672         behaviorSelect: behaviorSelect,
78673         behaviorTail: behaviorTail,
78674         coreContext: coreContext,
78675         coreDifference: coreDifference,
78676         coreGraph: coreGraph$$1,
78677         coreHistory: coreHistory,
78678         coreTree: coreTree,
78679         dataFeatureIcons: dataFeatureIcons,
78680         data: data,
78681         dataWikipedia: dataWikipedia,
78682         dataSuggestions: dataSuggestions,
78683         dataAddressFormats: dataAddressFormats,
78684         dataDeprecated: dataDeprecated,
78685         dataDiscarded: dataDiscarded,
78686         dataLocales: dataLocales,
78687         dataPhoneFormats: dataPhoneFormats,
78688         dataShortcuts: dataShortcuts,
78689         dataImperial: dataImperial,
78690         dataDriveLeft: dataDriveLeft,
78691         dataEn: en,
78692         geoAngle: geoAngle,
78693         geoChooseEdge: geoChooseEdge,
78694         geoCross: geoCross,
78695         geoEdgeEqual: geoEdgeEqual,
78696         geoEuclideanDistance: geoEuclideanDistance,
78697         geoExtent: geoExtent$$1,
78698         geoInterp: geoInterp,
78699         geoRawMercator: geoRawMercator,
78700         geoRoundCoords: geoRoundCoords,
78701         geoRotate: geoRotate,
78702         geoLatToMeters: geoLatToMeters,
78703         geoLineIntersection: geoLineIntersection,
78704         geoLonToMeters: geoLonToMeters,
78705         geoMetersToLat: geoMetersToLat,
78706         geoMetersToLon: geoMetersToLon,
78707         geoMetersToOffset: geoMetersToOffset,
78708         geoOffsetToMeters: geoOffsetToMeters,
78709         geoPathIntersections: geoPathIntersections,
78710         geoPathLength: geoPathLength,
78711         geoPointInPolygon: geoPointInPolygon,
78712         geoPolygonContainsPolygon: geoPolygonContainsPolygon,
78713         geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
78714         geoSphericalDistance: geoSphericalDistance,
78715         modeAddArea: modeAddArea$$1,
78716         modeAddLine: modeAddLine$$1,
78717         modeAddPoint: modeAddPoint$$1,
78718         modeBrowse: modeBrowse,
78719         modeDragNode: modeDragNode$$1,
78720         modeDrawArea: modeDrawArea,
78721         modeDrawLine: modeDrawLine,
78722         modeMove: modeMove$$1,
78723         modeRotate: modeRotate$$1,
78724         modeSave: modeSave$$1,
78725         modeSelect: modeSelect,
78726         operationCircularize: operationCircularize,
78727         operationContinue: operationContinue,
78728         operationDelete: operationDelete,
78729         operationDisconnect: operationDisconnect,
78730         operationMerge: operationMerge,
78731         operationMove: operationMove,
78732         operationOrthogonalize: operationOrthogonalize,
78733         operationReflectShort: operationReflectShort,
78734         operationReflectLong: operationReflectLong,
78735         operationReverse: operationReverse,
78736         operationRotate: operationRotate,
78737         operationSplit: operationSplit,
78738         operationStraighten: operationStraighten,
78739         osmChangeset: osmChangeset,
78740         osmEntity: osmEntity$$1,
78741         osmNode: osmNode,
78742         osmRelation: osmRelation,
78743         osmWay: osmWay,
78744         osmIntersection: osmIntersection,
78745         osmTurn: osmTurn,
78746         osmInferRestriction: osmInferRestriction,
78747         osmLanes: osmLanes,
78748         osmIsSimpleMultipolygonOuterMember: osmIsSimpleMultipolygonOuterMember,
78749         osmSimpleMultipolygonOuterMember: osmSimpleMultipolygonOuterMember,
78750         osmJoinWays: osmJoinWays,
78751         osmOneWayTags: osmOneWayTags,
78752         osmPavedTags: osmPavedTags,
78753         osmIsInterestingTag: osmIsInterestingTag,
78754         presetCategory: presetCategory,
78755         presetCollection: presetCollection,
78756         presetField: presetField,
78757         presetPreset: presetPreset,
78758         presetIndex: presetIndex,
78759         rendererBackgroundSource: rendererBackgroundSource,
78760         rendererBackground: rendererBackground,
78761         rendererFeatures: rendererFeatures,
78762         rendererMap: rendererMap,
78763         rendererTileLayer: rendererTileLayer,
78764         services: services,
78765         svgAreas: svgAreas$$1,
78766         svgDebug: svgDebug,
78767         svgDefs: svgDefs,
78768         svgGpx: svgGpx,
78769         svgIcon: svgIcon,
78770         svgLabels: svgLabels,
78771         svgLayers: svgLayers,
78772         svgLines: svgLines$$1,
78773         svgMapillaryImages: svgMapillaryImages,
78774         svgMapillarySigns: svgMapillarySigns,
78775         svgMidpoints: svgMidpoints$$1,
78776         svgOneWaySegments: svgOneWaySegments,
78777         svgOsm: svgOsm,
78778         svgPath: svgPath,
78779         svgPointTransform: svgPointTransform,
78780         svgPoints: svgPoints$$1,
78781         svgRelationMemberTags: svgRelationMemberTags,
78782         svgTagClasses: svgTagClasses,
78783         svgTurns: svgTurns,
78784         svgVertices: svgVertices$$1,
78785         uiFields: uiFields,
78786         uiFieldDefaultCheck: uiFieldCheck,
78787         uiFieldOnewayCheck: uiFieldCheck,
78788         uiFieldCheck: uiFieldCheck,
78789         uiFieldMultiCombo: uiFieldCombo,
78790         uiFieldNetworkCombo: uiFieldCombo,
78791         uiFieldSemiCombo: uiFieldCombo,
78792         uiFieldTypeCombo: uiFieldCombo,
78793         uiFieldCombo: uiFieldCombo,
78794         uiFieldUrl: uiFieldText,
78795         uiFieldNumber: uiFieldText,
78796         uiFieldTel: uiFieldText,
78797         uiFieldEmail: uiFieldText,
78798         uiFieldText: uiFieldText,
78799         uiFieldAccess: uiFieldAccess,
78800         uiFieldAddress: uiFieldAddress,
78801         uiFieldCycleway: uiFieldCycleway,
78802         uiFieldLanes: uiFieldLanes,
78803         uiFieldLocalized: uiFieldLocalized,
78804         uiFieldMaxspeed: uiFieldMaxspeed,
78805         uiFieldStructureRadio: uiFieldRadio,
78806         uiFieldRadio: uiFieldRadio,
78807         uiFieldRestrictions: uiFieldRestrictions,
78808         uiFieldTextarea: uiFieldTextarea,
78809         uiFieldWikipedia: uiFieldWikipedia,
78810         uiIntro: uiIntro,
78811         uiInfoPanels: uiInfoPanels,
78812         uiPanelBackground: uiPanelBackground,
78813         uiPanelHistory: uiPanelHistory,
78814         uiPanelLocation: uiPanelLocation,
78815         uiPanelMeasurement: uiPanelMeasurement,
78816         uiInit: uiInit,
78817         uiAccount: uiAccount,
78818         uiAttribution: uiAttribution,
78819         uiBackground: uiBackground,
78820         uiCmd: uiCmd,
78821         uiCommit: uiCommit,
78822         uiConfirm: uiConfirm,
78823         uiConflicts: uiConflicts,
78824         uiContributors: uiContributors,
78825         uiCurtain: uiCurtain,
78826         uiDisclosure: uiDisclosure,
78827         uiEditMenu: uiEditMenu,
78828         uiEntityEditor: uiEntityEditor,
78829         uiFeatureInfo: uiFeatureInfo,
78830         uiFeatureList: uiFeatureList,
78831         uiFlash: uiFlash,
78832         uiFullScreen: uiFullScreen,
78833         uiGeolocate: uiGeolocate,
78834         uiHelp: uiHelp,
78835         uiInfo: uiInfo,
78836         uiInspector: uiInspector,
78837         uiLasso: uiLasso,
78838         uiLoading: uiLoading,
78839         uiMapData: uiMapData,
78840         uiMapInMap: uiMapInMap,
78841         uiModal: uiModal,
78842         uiModes: uiModes,
78843         uiNotice: uiNotice,
78844         uiPreset: uiPreset,
78845         uiPresetIcon: uiPresetIcon,
78846         uiPresetList: uiPresetList,
78847         uiRadialMenu: uiRadialMenu,
78848         uiRawMemberEditor: uiRawMemberEditor,
78849         uiRawMembershipEditor: uiRawMembershipEditor,
78850         uiRawTagEditor: uiRawTagEditor,
78851         uiRestore: uiRestore,
78852         uiSave: uiSave,
78853         uiScale: uiScale,
78854         uiSelectionList: uiSelectionList,
78855         uiSidebar: uiSidebar,
78856         uiSourceSwitch: uiSourceSwitch,
78857         uiSpinner: uiSpinner,
78858         uiSplash: uiSplash,
78859         uiStatus: uiStatus,
78860         uiSuccess: uiSuccess,
78861         uiTagReference: uiTagReference,
78862         uiToggle: uiToggle,
78863         uiTooltipHtml: uiTooltipHtml,
78864         uiUndoRedo: uiUndoRedo,
78865         uiVersion: uiVersion,
78866         uiViewOnOSM: uiViewOnOSM,
78867         uiZoom: uiZoom,
78868         utilAsyncMap: utilAsyncMap,
78869         utilDisplayName: utilDisplayName,
78870         utilDisplayNameForPath: utilDisplayNameForPath,
78871         utilDisplayType: utilDisplayType,
78872         utilEditDistance: utilEditDistance,
78873         utilEntitySelector: utilEntitySelector,
78874         utilEntityOrMemberSelector: utilEntityOrMemberSelector,
78875         utilFastMouse: utilFastMouse,
78876         utilFunctor: utilFunctor,
78877         utilGetAllNodes: utilGetAllNodes,
78878         utilGetPrototypeOf: utilGetPrototypeOf,
78879         utilGetSetValue: utilGetSetValue,
78880         utilNoAuto: utilNoAuto,
78881         utilPrefixCSSProperty: utilPrefixCSSProperty,
78882         utilPrefixDOMProperty: utilPrefixDOMProperty,
78883         utilQsString: utilQsString,
78884         utilRebind: utilRebind,
78885         utilSetTransform: utilSetTransform,
78886         utilSessionMutex: utilSessionMutex,
78887         utilStringQs: utilStringQs,
78888         utilSuggestNames: utilSuggestNames,
78889         utilTagText: utilTagText,
78890         utilTriggerEvent: utilTriggerEvent,
78891         utilWrap: utilWrap,
78892         d3combobox: d3combobox,
78893         d3geoTile: d3geoTile,
78894         d3keybinding: d3keybinding,
78895         validationDeprecatedTag: validationDeprecatedTag,
78896         validationDisconnectedHighway: validationDisconnectedHighway,
78897         validationManyDeletions: validationManyDeletions,
78898         validationMissingTag: validationMissingTag,
78899         validationOldMultipolygon: validationOldMultipolygon,
78900         validationTagSuggestsArea: validationTagSuggestsArea
78901 });
78902
78903 window.iD = iD;
78904
78905 }());
78906 //# sourceMappingURL=iD.js.map