]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Use a current_user helper for accessing the logged in user in all views.
[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":["Left-click","shortcuts.key.space"],"text":"shortcuts.editing.drawing.place_point"},{"shortcuts":["⌥"],"text":"shortcuts.editing.drawing.disable_snap"},{"shortcuts":["↵","⎋"],"text":"shortcuts.editing.drawing.stop_line"},{"section":"commands","text":"shortcuts.editing.commands.title"},{"modifiers":["⌘"],"shortcuts":["C"],"text":"shortcuts.editing.commands.copy"},{"modifiers":["⌘"],"shortcuts":["V"],"text":"shortcuts.editing.commands.paste"},{"modifiers":["⌘"],"shortcuts":["Z"],"text":"shortcuts.editing.commands.undo"},{"modifiers":["⌘","⇧"],"shortcuts":["Z"],"text":"shortcuts.editing.commands.redo"},{"modifiers":["⌘"],"shortcuts":["S"],"text":"shortcuts.editing.commands.save"}]},{"rows":[{"section":"operations","text":"shortcuts.editing.operations.title"},{"shortcuts":["operations.continue.key"],"text":"shortcuts.editing.operations.continue_line"},{"shortcuts":["operations.merge.key"],"text":"shortcuts.editing.operations.merge"},{"shortcuts":["operations.disconnect.key"],"text":"shortcuts.editing.operations.disconnect"},{"shortcuts":["operations.split.key"],"text":"shortcuts.editing.operations.split"},{"shortcuts":["operations.reverse.key"],"text":"shortcuts.editing.operations.reverse"},{"shortcuts":["operations.move.key"],"text":"shortcuts.editing.operations.move"},{"shortcuts":["operations.rotate.key"],"text":"shortcuts.editing.operations.rotate"},{"shortcuts":["operations.orthogonalize.key"],"text":"shortcuts.editing.operations.orthogonalize"},{"shortcuts":["operations.circularize.key"],"text":"shortcuts.editing.operations.circularize"},{"shortcuts":["operations.reflect.key.long"],"text":"shortcuts.editing.operations.reflect_long"},{"shortcuts":["operations.reflect.key.short"],"text":"shortcuts.editing.operations.reflect_short"},{"modifiers":["⌘"],"shortcuts":["⌫"],"text":"shortcuts.editing.operations.delete"}]}]},{"tab":"tools","text":"shortcuts.tools.title","columns":[{"rows":[{"section":"info","text":"shortcuts.tools.info.title"},{"modifiers":["⌘"],"shortcuts":["info_panels.key"],"text":"shortcuts.tools.info.all"},{"modifiers":["⌘","⇧"],"shortcuts":["info_panels.background.key"],"text":"shortcuts.tools.info.background"},{"modifiers":["⌘","⇧"],"shortcuts":["info_panels.history.key"],"text":"shortcuts.tools.info.history"},{"modifiers":["⌘","⇧"],"shortcuts":["info_panels.location.key"],"text":"shortcuts.tools.info.location"},{"modifiers":["⌘","⇧"],"shortcuts":["info_panels.measurement.key"],"text":"shortcuts.tools.info.measurement"}]}]}];
18610
18611 var type = "FeatureCollection";
18612 var features = [{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[1.97754,51.13111],[1.8457,63.45051],[-10.45898,57.01681],[-6.82251,55.26503],[-7.25583,55.06525],[-7.26546,55.0665],[-7.26992,55.06419],[-7.2725,55.06346],[-7.27818,55.05362],[-7.2893,55.04735],[-7.29939,55.0561],[-7.31835,55.04475],[-7.3447,55.05079],[-7.38831,55.02389],[-7.40547,55.00292],[-7.39157,54.99507],[-7.40075,54.98892],[-7.40706,54.98291],[-7.40363,54.97963],[-7.40633,54.97813],[-7.39835,54.97013],[-7.40745,54.96357],[-7.40178,54.95961],[-7.40727,54.95515],[-7.3944,54.94376],[-7.44444,54.93858],[-7.45216,54.89793],[-7.44204,54.87532],[-7.4713,54.83431],[-7.48092,54.83093],[-7.49216,54.82185],[-7.55121,54.79054],[-7.5443,54.78609],[-7.54958,54.75653],[-7.5349,54.74917],[-7.54881,54.74068],[-7.55941,54.74556],[-7.57894,54.74221],[-7.57507,54.7494],[-7.58606,54.75039],[-7.58872,54.74377],[-7.60031,54.74603],[-7.60632,54.74405],[-7.61662,54.74459],[-7.63593,54.75108],[-7.68854,54.72968],[-7.72064,54.72155],[-7.75094,54.70469],[-7.79094,54.71942],[-7.8051,54.71932],[-7.83497,54.73632],[-7.85419,54.72745],[-7.91496,54.67582],[-7.90174,54.66182],[-7.83832,54.63401],[-7.7433,54.6188],[-7.70863,54.63485],[-7.70682,54.6189],[-7.69386,54.6188],[-7.69631,54.61125],[-7.75845,54.59509],[-7.78708,54.58],[-7.79446,54.58141],[-7.79969,54.57704],[-7.79673,54.56915],[-7.8184,54.56315],[-7.83334,54.55227],[-7.82737,54.54299],[-7.85007,54.53363],[-7.90741,54.53722],[-7.93213,54.53388],[-8.00487,54.54568],[-8.03727,54.51162],[-8.04285,54.48759],[-8.08027,54.48829],[-8.09988,54.48395],[-8.09126,54.4765],[-8.111,54.47807],[-8.11512,54.46904],[-8.16542,54.46914],[-8.1776,54.46485],[-8.14293,54.45003],[-8.16284,54.4413],[-8.08731,54.4002],[-8.06062,54.37051],[-8.03289,54.35711],[-8.00054,54.34835],[-7.93333,54.30561],[-7.85849,54.29151],[-7.87067,54.28794],[-7.87265,54.26648],[-7.86123,54.25931],[-7.85917,54.21256],[-7.71043,54.20307],[-7.70193,54.20776],[-7.68828,54.202],[-7.67644,54.18906],[-7.66082,54.1871],[-7.62554,54.16545],[-7.62541,54.15319],[-7.61026,54.14353],[-7.57421,54.14142],[-7.57181,54.13287],[-7.56228,54.12704],[-7.51379,54.12998],[-7.47944,54.122],[-7.47169,54.12665],[-7.47075,54.13318],[-7.44684,54.15168],[-7.40792,54.156],[-7.42579,54.14092],[-7.41903,54.13629],[-7.3744,54.14172],[-7.37234,54.13881],[-7.39509,54.12624],[-7.39182,54.12017],[-7.36341,54.13157],[-7.34518,54.11577],[-7.32471,54.12123],[-7.32003,54.11379],[-7.3078,54.11718],[-7.30548,54.12347],[-7.31591,54.12697],[-7.31213,54.13162],[-7.3187,54.13411],[-7.31857,54.13745],[-7.32222,54.13836],[-7.32737,54.13544],[-7.3399,54.14585],[-7.30827,54.16716],[-7.30024,54.16625],[-7.29029,54.1715],[-7.28158,54.16839],[-7.2863,54.14919],[-7.29874,54.14904],[-7.30162,54.14411],[-7.28411,54.13971],[-7.29192,54.13071],[-7.29737,54.133],[-7.30883,54.13242],[-7.30333,54.12251],[-7.29218,54.11929],[-7.27844,54.12282],[-7.27707,54.12986],[-7.26613,54.13624],[-7.2566,54.16354],[-7.24015,54.17125],[-7.2575,54.17678],[-7.2581,54.19257],[-7.25179,54.19403],[-7.23608,54.1935],[-7.23338,54.19792],[-7.24317,54.20076],[-7.24892,54.1977],[-7.25183,54.20201],[-7.24119,54.20623],[-7.23094,54.20578],[-7.23269,54.20912],[-7.22188,54.21607],[-7.20643,54.2117],[-7.18506,54.22485],[-7.17055,54.21742],[-7.14721,54.22488],[-7.14633,54.23008],[-7.15051,54.23165],[-7.14613,54.23983],[-7.15802,54.24434],[-7.13985,54.25298],[-7.15255,54.26235],[-7.16064,54.27405],[-7.17991,54.27144],[-7.17201,54.28627],[-7.21252,54.2985],[-7.19888,54.31117],[-7.17918,54.30946],[-7.1812,54.3397],[-7.15339,54.33514],[-7.10253,54.35811],[-7.10811,54.36677],[-7.06927,54.3899],[-7.05593,54.41056],[-7.02898,54.42135],[-7.00198,54.40832],[-6.98683,54.40829],[-6.97562,54.40014],[-6.96774,54.40145],[-6.90682,54.36966],[-6.89772,54.35075],[-6.87527,54.33853],[-6.86512,54.32568],[-6.85163,54.29137],[-6.87452,54.28677],[-6.87791,54.27918],[-6.86673,54.27522],[-6.85177,54.26489],[-6.83693,54.26658],[-6.82165,54.24346],[-6.81633,54.22299],[-6.80045,54.22108],[-6.80122,54.21338],[-6.77599,54.19965],[-6.75573,54.1987],[-6.74316,54.18258],[-6.73406,54.18566],[-6.72445,54.18127],[-6.70295,54.20036],[-6.69166,54.20018],[-6.68673,54.19398],[-6.669,54.19584],[-6.65248,54.18102],[-6.6433,54.17801],[-6.63467,54.16449],[-6.63179,54.14766],[-6.64081,54.14238],[-6.63935,54.13599],[-6.66149,54.1205],[-6.6481,54.10153],[-6.66119,54.0934],[-6.66458,54.06629],[-6.64681,54.05873],[-6.62501,54.03737],[-6.59291,54.04755],[-6.58905,54.05808],[-6.5597,54.0481],[-6.52897,54.05888],[-6.50442,54.05566],[-6.47824,54.07004],[-6.47919,54.07762],[-6.43601,54.05959],[-6.36314,54.07057],[-6.36589,54.09338],[-6.36293,54.09758],[-6.37104,54.11497],[-6.3522,54.11084],[-6.34242,54.1114],[-6.33589,54.10833],[-6.33636,54.09469],[-6.31808,54.09096],[-6.30903,54.10463],[-6.29165,54.11235],[-6.28246,54.11145],[-6.26272,54.09786],[-5.35583,53.72597],[-7.0752,49.23912],[-1.83472,49.02346],[-2.12036,49.94415],[1.97754,51.13111]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-65.2,18.7],[-65,16.3],[-63.7,19.2],[-65.2,18.7]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-63,-50.5],[-55,-51],[-60,-54],[-63,-50.5]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-139.19952,60.08402],[-141,60.30621],[-141,76],[-169,68.63655],[-169,65.20147],[-180,61],[-180,-4],[-154,9],[-133.76404,54.54021],[-130.73868,54.71986],[-129.96277,55.29163],[-130.15228,55.7758],[-130.01787,55.90688],[-130.00362,56.00798],[-130.10284,56.12336],[-130.24498,56.09656],[-130.42625,56.14249],[-131.87439,56.79787],[-135.02884,59.56285],[-135.11759,59.62306],[-135.15827,59.6261],[-135.47928,59.79822],[-136.28677,59.57955],[-136.30531,59.46462],[-136.36836,59.44898],[-136.47697,59.46558],[-137.19727,59.01935],[-139.19952,60.08402]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-111.96064,48.99841],[-121.22623,49.00049],[-122.26513,49.00246],[-122.7565,49.00208],[-123.32218,49.00218],[-122.97821,48.76524],[-123.2666,48.69821],[-123.21991,48.21186],[-125.80444,48.60749],[-124.32129,31.54109],[-117.125,32.53429],[-116.82417,32.55996],[-115.88036,32.63735],[-115.49738,32.66486],[-114.71984,32.71877],[-114.7649,32.64602],[-114.80885,32.60959],[-114.81481,32.49451],[-112.81743,31.88004],[-111.07481,31.33224],[-109.56051,31.33402],[-108.20847,31.33384],[-108.20838,31.78363],[-106.52847,31.78391],[-106.52781,31.78086],[-106.52249,31.77501],[-106.51249,31.76933],[-106.50988,31.7612],[-106.50709,31.76123],[-106.48896,31.74806],[-106.48473,31.74769],[-106.4719,31.75101],[-106.46816,31.75897],[-106.45434,31.76466],[-106.45035,31.76426],[-106.43516,31.75492],[-106.41484,31.75101],[-106.37864,31.73021],[-106.37225,31.71174],[-106.34924,31.69633],[-106.33289,31.66178],[-106.3068,31.62459],[-106.28079,31.56179],[-106.24775,31.54226],[-106.2329,31.49982],[-106.2105,31.46857],[-106.08201,31.39863],[-106.00554,31.39233],[-105.76401,31.17051],[-105.58548,31.06117],[-105.56419,30.98526],[-104.99153,30.6639],[-104.97162,30.60896],[-104.90639,30.57822],[-104.83772,30.38117],[-104.70177,30.20567],[-104.68048,29.92399],[-104.57611,29.77838],[-104.51157,29.63674],[-104.39758,29.57047],[-104.39278,29.55293],[-104.05769,29.32173],[-103.79883,29.2581],[-103.78196,29.26555],[-103.76759,29.22799],[-103.14102,28.93666],[-102.86087,29.2217],[-102.65076,29.79418],[-101.41068,29.73457],[-101.26511,29.51372],[-101.05997,29.452],[-101.04083,29.38038],[-100.96303,29.34735],[-100.94406,29.34369],[-100.94071,29.33351],[-100.92775,29.32663],[-100.89814,29.30957],[-100.87818,29.28086],[-100.80076,29.2238],[-100.76437,29.15981],[-100.67047,29.08663],[-100.6412,28.91299],[-100.63236,28.90255],[-100.61296,28.89939],[-100.534,28.75622],[-100.51495,28.74531],[-100.50705,28.7143],[-100.51203,28.70666],[-100.51014,28.69127],[-100.50048,28.66186],[-100.45547,28.6381],[-100.44697,28.60743],[-100.35599,28.45239],[-100.34946,28.39653],[-100.29488,28.31315],[-100.29591,28.27324],[-100.17197,28.17493],[-99.93645,27.9568],[-99.87722,27.80173],[-99.79671,27.73338],[-99.772,27.72532],[-99.74556,27.69979],[-99.71947,27.65981],[-99.5957,27.59974],[-99.54094,27.60537],[-99.53055,27.57973],[-99.52034,27.55782],[-99.52802,27.49773],[-99.50141,27.49986],[-99.48755,27.49518],[-99.47897,27.48421],[-99.48661,27.46453],[-99.49534,27.44861],[-99.48927,27.40941],[-99.53957,27.31565],[-99.43588,27.19678],[-99.46404,27.01968],[-99.16698,26.56039],[-99.17474,26.53939],[-99.12698,26.51958],[-99.1135,26.42954],[-99.08355,26.39625],[-99.06007,26.39737],[-99.03634,26.41255],[-99.02042,26.40598],[-99.01291,26.39364],[-98.95686,26.38641],[-98.9566,26.37365],[-98.94523,26.36949],[-98.90013,26.36419],[-98.89905,26.35454],[-98.80305,26.36626],[-98.78254,26.30511],[-98.66667,26.23457],[-98.58496,26.24647],[-98.57951,26.23434],[-98.56519,26.23987],[-98.56294,26.22464],[-98.50599,26.20858],[-98.44806,26.21236],[-98.38617,26.15721],[-98.34176,26.15278],[-98.33579,26.1388],[-98.30626,26.10003],[-98.28841,26.10512],[-98.26524,26.0914],[-98.19898,26.06411],[-98.09577,26.05698],[-98.07568,26.06667],[-98.08302,26.03396],[-97.9771,26.04136],[-97.9532,26.06179],[-97.81643,26.04475],[-97.77017,26.02439],[-97.73884,26.02902],[-97.5289,25.90648],[-97.52151,25.88625],[-97.50615,25.89031],[-97.49851,25.89903],[-97.49637,25.89641],[-97.49748,25.88008],[-97.49422,25.87981],[-97.48847,25.88564],[-97.46409,25.88174],[-97.42607,25.842],[-97.36856,25.8396],[-97.26231,25.94724],[-80.81543,24.00633],[-66.87378,44.77794],[-67.16148,45.16715],[-67.2286,45.16739],[-67.26246,45.18797],[-67.28311,45.19175],[-67.28959,45.18784],[-67.29332,45.17568],[-67.29049,45.17317],[-67.3001,45.16776],[-67.3025,45.16122],[-67.29761,45.14766],[-67.33975,45.1255],[-67.40524,45.16122],[-67.40387,45.17139],[-67.4818,45.27682],[-67.42172,45.38543],[-67.45262,45.41008],[-67.50498,45.4889],[-67.41623,45.50105],[-67.42219,45.55661],[-67.42902,45.56833],[-67.42331,45.57154],[-67.42498,45.57836],[-67.45193,45.60323],[-67.77981,45.6738],[-67.79019,47.06776],[-67.88006,47.1067],[-67.91319,47.14793],[-67.92598,47.15418],[-67.95181,47.1875],[-68.02374,47.23915],[-68.13017,47.29309],[-68.17669,47.32893],[-68.24046,47.35354],[-68.32809,47.36005],[-68.36363,47.35476],[-68.38054,47.34167],[-68.38509,47.30321],[-68.37367,47.28796],[-68.4377,47.28232],[-68.47916,47.29623],[-68.51074,47.29885],[-68.54593,47.28441],[-68.58408,47.28482],[-68.59777,47.27134],[-68.59271,47.25762],[-68.61889,47.24148],[-68.68936,47.24125],[-68.71768,47.23676],[-68.80128,47.21423],[-68.89629,47.17676],[-69.05354,47.24847],[-69.04924,47.41798],[-69.22425,47.45961],[-69.99729,46.69558],[-70.0569,46.4149],[-70.25551,46.10871],[-70.29001,46.09431],[-70.39919,45.80667],[-70.83229,45.40062],[-70.80794,45.37878],[-70.82663,45.2367],[-70.87538,45.23453],[-70.92138,45.28099],[-70.90645,45.30918],[-71.0109,45.34798],[-71.08429,45.30556],[-71.1454,45.24226],[-71.20525,45.25278],[-71.28925,45.30097],[-71.41405,45.23513],[-71.43044,45.12381],[-71.49692,45.06991],[-71.50623,45.04878],[-71.49284,45.03629],[-71.50027,45.01372],[-71.79359,45.01075],[-72.08774,45.00581],[-72.14155,45.00568],[-72.15282,45.00609],[-72.17142,45.00584],[-72.25847,45.00436],[-72.38795,45.00626],[-72.4496,45.00863],[-72.5356,45.00936],[-72.66257,45.01523],[-72.82537,45.01642],[-73.08466,45.01561],[-73.45219,45.00875],[-74.14699,44.99145],[-74.33753,44.9923],[-74.50786,44.99798],[-74.66158,44.99949],[-74.71244,44.99734],[-74.75887,44.98708],[-74.76368,45.00632],[-74.78977,45.00365],[-74.82376,45.01773],[-74.94186,44.98229],[-75.30098,44.83883],[-75.30304,44.82836],[-75.59418,44.6457],[-75.97269,44.33502],[-75.97295,44.34595],[-76.00059,44.34797],[-76.17645,44.2865],[-76.18744,44.22158],[-76.88782,43.82759],[-79.16851,43.32168],[-79.05487,43.25371],[-79.05092,43.169],[-79.04603,43.16093],[-79.04208,43.13942],[-79.07002,43.12038],[-79.06015,43.114],[-79.0568,43.10474],[-79.0774,43.07861],[-78.9996,43.05484],[-79.02311,43.02071],[-79.02552,42.99473],[-78.96235,42.9573],[-78.91188,42.9426],[-78.90398,42.89181],[-82.42767,41.47978],[-83.14316,42.03807],[-83.12805,42.23843],[-83.09715,42.29052],[-83.07252,42.31515],[-82.94575,42.34332],[-82.59676,42.5479],[-82.51368,42.61785],[-82.5108,42.66464],[-82.4675,42.76415],[-82.48055,42.80573],[-82.45497,42.9284],[-82.41334,42.97099],[-82.42596,42.99536],[-82.15851,43.39507],[-83.53729,46.098],[-83.96301,46.05036],[-84.11021,46.23851],[-84.09794,46.25656],[-84.11613,46.26878],[-84.11905,46.31516],[-84.10721,46.3218],[-84.14394,46.41076],[-84.11682,46.51576],[-84.13536,46.53218],[-84.16162,46.5284],[-84.21621,46.53891],[-84.26994,46.49189],[-84.36092,46.50997],[-84.55284,46.4407],[-84.95178,46.77185],[-89.59179,48.00307],[-89.67547,48.00371],[-90.87204,48.25943],[-91.41312,48.06753],[-92.99377,48.62474],[-93.34877,48.62604],[-93.35529,48.61124],[-93.37074,48.60584],[-93.39812,48.60369],[-93.40542,48.61089],[-93.43846,48.59478],[-93.46859,48.59205],[-93.45735,48.56667],[-93.46533,48.54593],[-93.64763,48.51751],[-93.80625,48.51888],[-93.80642,48.58047],[-93.83328,48.62582],[-93.84865,48.63064],[-93.93388,48.6326],[-94.01327,48.64471],[-94.16176,48.64697],[-94.25025,48.65463],[-94.24931,48.67827],[-94.26046,48.69816],[-94.30578,48.71073],[-94.32758,48.70433],[-94.36123,48.70478],[-94.38406,48.71135],[-94.41629,48.71067],[-94.44294,48.69266],[-94.53615,48.7024],[-94.55031,48.71419],[-94.58894,48.71928],[-94.69425,48.77938],[-94.70129,48.83376],[-94.68996,48.83953],[-94.68395,48.99914],[-111.96064,48.99841]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[180,55],[170,53],[180,49],[180,55]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[143,22],[147,22],[147,12],[143,12],[143,22]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-171.5,-10],[-171,-15],[-167,-15],[-171.5,-10]]]}}];
18613 var dataImperial = {
18614         type: type,
18615         features: features
18616 };
18617
18618 var type$1 = "FeatureCollection";
18619 var features$1 = [{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[113.573,22.186],[114,22.5],[114.05534,22.503],[114.0595,22.51422],[114.07345,22.51934],[114.0786,22.53012],[114.08512,22.53228],[114.09034,22.53717],[114.09611,22.53486],[114.10602,22.53472],[114.1115,22.52929],[114.11522,22.5308],[114.11649,22.53418],[114.11979,22.53511],[114.1244,22.5393],[114.12729,22.53947],[114.13018,22.54132],[114.13807,22.5432],[114.14429,22.54176],[114.14441,22.54114],[114.14846,22.54179],[114.14855,22.54397],[114.15042,22.54593],[114.14964,22.54954],[114.15166,22.55168],[114.15192,22.55438],[114.15642,22.55495],[114.15841,22.55909],[114.16032,22.56153],[114.16162,22.56187],[114.1634,22.55931],[114.16553,22.5593],[114.16733,22.56119],[114.16934,22.56093],[114.17061,22.5597],[114.17702,22.56],[114.17798,22.55546],[114.18401,22.5552],[114.18673,22.55468],[114.1878,22.55545],[114.18979,22.55446],[114.1955,22.55564],[114.19674,22.55691],[114.20005,22.55717],[114.20376,22.55623],[114.20884,22.55672],[114.22438,22.55055],[114.2264,22.5476],[114.22545,22.54528],[114.22661,22.54339],[114.32,22.576],[114.45,22.43],[114.45,22.14],[113.9,22.14],[113.75,22.22],[113.553,22.095],[113.54678,22.1207],[113.5456,22.1207],[113.54076,22.12373],[113.54016,22.13618],[113.54701,22.13651],[113.5475,22.14583],[113.52456,22.17978],[113.53623,22.20191],[113.53299,22.21232],[113.53497,22.21351],[113.53735,22.21377],[113.54156,22.21315],[113.54385,22.21709],[113.55849,22.21565],[113.573,22.186]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-75,18],[-80,20.5],[-83,19],[-77,16],[-75,18]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-64.33594,32.86113],[-79.39819,27.21067],[-80.63965,23.71998],[-73.39966,20.40642],[-65.1709,19.20743],[-65.09399,16.23577],[-59.13391,16.80454],[-62.64404,15.16228],[-59.43054,14.85985],[-62.83081,13.64599],[-61.80359,10.73752],[-62.08649,10.04729],[-61.06201,9.85522],[-59.81369,8.31274],[-59.8027,8.27469],[-59.83498,8.22712],[-59.94141,8.21149],[-59.99771,8.15576],[-59.97986,8.13265],[-59.99771,8.12041],[-60.00183,8.07147],[-60.05127,8.02524],[-60.09933,8.03747],[-60.12268,8.02388],[-60.14053,7.98988],[-60.36163,7.83345],[-60.53467,7.81713],[-60.5896,7.6375],[-60.72144,7.54493],[-60.5896,7.31888],[-60.63904,7.24532],[-60.54703,7.12542],[-60.46875,7.20309],[-60.37262,7.18401],[-60.29984,7.1445],[-60.2916,7.06819],[-60.39871,6.95097],[-60.66513,6.83235],[-60.71869,6.75053],[-60.91232,6.81735],[-60.94254,6.72053],[-61.14441,6.72326],[-61.23093,6.5773],[-61.1554,6.45314],[-61.14441,6.20199],[-61.39709,5.95619],[-60.71045,5.20036],[-60.21606,5.23319],[-59.99634,5.06906],[-60.13916,4.51071],[-59.69971,4.40118],[-59.5459,3.93002],[-59.87549,3.56825],[-59.7876,3.37086],[-60.01831,2.83332],[-59.90845,2.38335],[-59.69971,2.2626],[-59.77661,1.87833],[-59.65302,1.85087],[-59.69147,1.75754],[-59.61456,1.71361],[-59.55139,1.73283],[-59.36188,1.49123],[-59.26575,1.39238],[-58.92242,1.30726],[-58.83728,1.17271],[-58.71918,1.23037],[-58.71094,1.29902],[-58.49121,1.26058],[-58.461,1.37591],[-58.50494,1.38689],[-58.51044,1.46102],[-58.38135,1.4775],[-58.32642,1.57359],[-58.00507,1.49946],[-57.99133,1.65321],[-57.79907,1.69165],[-57.70844,1.71087],[-57.54364,1.68341],[-57.41455,1.94421],[-57.10693,1.97715],[-56.8103,1.85636],[-56.48071,1.92225],[-55.90942,1.81244],[-55.90942,2.04302],[-56.14014,2.26534],[-55.94788,2.53701],[-55.70892,2.39981],[-55.37933,2.43274],[-55.19257,2.53976],[-54.98108,2.57268],[-54.88495,2.43548],[-54.71191,2.46293],[-54.69543,2.34767],[-54.58832,2.32846],[-54.43451,2.43548],[-54.20654,2.76748],[-54.17358,3.12955],[-53.96484,3.57921],[-54.33838,4.00674],[-54.44412,4.52577],[-54.46884,4.91036],[-54.36653,5.13061],[-54.27727,5.26191],[-54.19968,5.3084],[-54.01222,5.54457],[-54.0239,5.64605],[-53.86322,5.94936],[-64.33594,32.86113]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-14.5,-6],[11.79657,-17.27197],[12.03415,-17.14866],[12.38159,-17.22213],[12.58484,-17.22476],[13.01193,-16.97405],[13.24951,-17.00098],[13.38135,-16.98522],[13.93341,-17.38734],[18.42476,-17.38996],[18.47763,-17.46857],[18.62663,-17.64599],[18.79211,-17.76177],[18.92944,-17.82061],[19.33044,-17.84806],[19.66278,-17.8644],[19.74792,-17.90557],[19.85161,-17.87486],[20.10361,-17.90296],[20.18394,-17.88401],[20.34737,-17.88466],[20.44693,-17.91733],[20.51697,-17.96698],[20.83008,-18.03032],[20.95711,-17.97285],[21.16997,-17.93497],[21.42677,-18.0264],[23.45032,-17.63879],[22.00012,-16.38866],[21.99944,-13.00523],[24.03809,-12.99118],[24.03809,-10.91962],[24.43359,-11.09217],[24.45557,-11.48002],[25.37842,-11.19996],[25.42236,-11.60919],[26.96045,-11.97484],[27.18018,-11.60919],[28.125,-12.42048],[29.11377,-13.36824],[29.1687,-13.43771],[29.55872,-13.19716],[29.68506,-13.2239],[29.62463,-13.41099],[29.80591,-13.44305],[29.81415,-12.14809],[29.31152,-12.55456],[28.41064,-11.78133],[28.63037,-10.70379],[28.65234,-9.73071],[28.37219,-9.24309],[28.89748,-8.47916],[30.78644,-8.26857],[29.39941,-6.05316],[29.4873,-4.45595],[29.75922,-4.46759],[29.81415,-4.36421],[29.88007,-4.36832],[30.04074,-4.26699],[30.07919,-4.1629],[30.18356,-4.08311],[30.1918,-4.05126],[30.21566,-4.04595],[30.22923,-4.01136],[30.21326,-3.99612],[30.25978,-3.88755],[30.29274,-3.86288],[30.34424,-3.77245],[30.39848,-3.79095],[30.40878,-3.76765],[30.39548,-3.7304],[30.39054,-3.72821],[30.3896,-3.71918],[30.39093,-3.7101],[30.39514,-3.70444],[30.42028,-3.64963],[30.46886,-3.53501],[30.67108,-3.41335],[30.63297,-3.34892],[30.84206,-3.25535],[30.84549,-3.16108],[30.83485,-3.09698],[30.7933,-3.06235],[30.82111,-3.02258],[30.84515,-2.9739],[30.74764,-2.99618],[30.7037,-2.97013],[30.66422,-2.98967],[30.57632,-2.90738],[30.49393,-2.94441],[30.41016,-2.87172],[30.52002,-2.39432],[30.77545,-2.38883],[30.8606,-2.31199],[30.84961,-2.19398],[30.89081,-2.07322],[30.81116,-1.96068],[30.83862,-1.6587],[30.73425,-1.4418],[30.56259,-1.33884],[30.4541,-1.05737],[30.35797,-1.06287],[30.34149,-1.13152],[30.16571,-1.34296],[29.91852,-1.48024],[29.83887,-1.31824],[29.58344,-1.39238],[29.729,0.05493],[29.96796,0.5136],[29.9707,0.8569],[30.22339,0.92281],[30.24536,1.15349],[30.47745,1.20772],[31.30966,2.15693],[31.20255,2.22211],[31.20255,2.29278],[31.16409,2.27906],[31.13937,2.28318],[31.13113,2.26534],[31.07826,2.30033],[31.0714,2.34767],[31.00479,2.4005],[30.97183,2.40461],[30.94711,2.38746],[30.94849,2.36276],[30.9375,2.33532],[30.88531,2.34012],[30.83038,2.42176],[30.74112,2.43274],[30.76035,2.5864],[30.90179,2.88132],[30.76447,3.04178],[30.93613,3.40239],[30.94059,3.50588],[30.85236,3.48601],[30.90866,3.5936],[30.95055,3.63918],[30.94677,3.65391],[30.9866,3.70187],[31.00582,3.70701],[31.02058,3.69708],[31.16547,3.7954],[31.28838,3.79643],[31.52699,3.66282],[31.7038,3.72449],[31.82671,3.82794],[31.96198,3.65596],[31.95854,3.57099],[32.04987,3.59155],[32.07733,3.57099],[32.0842,3.53672],[32.20093,3.50657],[32.21672,3.56448],[32.19578,3.59977],[32.41516,3.74504],[32.72055,3.76782],[32.89307,3.81219],[33.02782,3.89371],[33.18146,3.7793],[33.51173,3.75258],[33.98758,4.23309],[34.05762,4.28342],[34.38721,4.61065],[35.94452,4.62023],[35.95688,4.53467],[36.04134,4.44568],[36.89621,4.4491],[38.14728,3.62992],[38.55927,3.62033],[38.92181,3.51068],[39.56039,3.43392],[39.87076,3.87522],[40.76752,4.28753],[41.16371,3.94372],[41.89774,3.97797],[41.31271,3.14463],[40.98896,2.82869],[40.99548,-0.84042],[41.7,-1.8],[41.7,-49],[-27,-60],[-65.7,-52.5],[-14.5,-6]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[31.33301,35.47856],[33.0249,33.75175],[35.44189,36.02245],[31.33301,35.47856]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[14,36.5],[15,36],[14,35],[14,36.5]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[0,62],[2.5,51.3],[-2,50],[-1.9,49],[-20,53],[0,62]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[180,-35],[161,-19],[167,-12],[180,-22],[180,4],[170,3.7],[127,5.7],[118,2.7],[119.5,5.4],[117.2,7.5],[102.6,8],[102.9158,11.74099],[102.76268,12.07357],[102.70226,12.17158],[102.74139,12.46474],[102.53128,12.68857],[102.49557,12.9256],[102.49763,13.0064],[102.4597,13.08199],[102.43412,13.09026],[102.39155,13.16407],[102.35481,13.29341],[102.35893,13.30945],[102.34503,13.34837],[102.35928,13.39797],[102.3567,13.48095],[102.36168,13.50582],[102.33559,13.53787],[102.33971,13.56023],[102.35498,13.5649],[102.36511,13.5785],[102.40047,13.5679],[102.42537,13.56891],[102.44614,13.56123],[102.48047,13.57091],[102.53849,13.56757],[102.5699,13.58526],[102.57806,13.60486],[102.62501,13.60845],[102.62132,13.61295],[102.60767,13.61562],[102.57231,13.63331],[102.56922,13.64082],[102.54879,13.658],[102.56252,13.68552],[102.5972,13.70803],[102.67084,13.74472],[102.68818,13.75172],[102.7014,13.7684],[102.73161,13.77082],[102.76543,13.85541],[102.78397,13.93207],[102.80388,13.94406],[102.81607,13.96639],[102.90705,14.02119],[102.89726,14.0535],[102.90095,14.0838],[102.92421,14.10744],[102.92378,14.12838],[102.94147,14.15035],[102.92953,14.17952],[103.17535,14.33774],[103.19939,14.32992],[103.68553,14.44],[103.94508,14.34157],[104.05756,14.34589],[104.06636,14.3419],[104.26025,14.37749],[104.50058,14.36984],[104.57817,14.36019],[104.6422,14.42387],[104.66632,14.40234],[104.68357,14.39877],[104.71138,14.43169],[104.72305,14.42188],[104.71687,14.40043],[104.75344,14.40459],[104.80408,14.43867],[104.83429,14.41573],[104.99239,14.3838],[105.05402,14.19783],[105.47905,14.49186],[105.60883,15.0005],[105.46703,15.13005],[105.48866,15.20237],[105.59269,15.2716],[105.58617,15.32823],[105.50308,15.31912],[105.46703,15.33948],[105.49175,15.37921],[105.59372,15.42869],[105.59372,15.50927],[105.60986,15.54871],[105.62616,15.56492],[105.62702,15.59129],[105.63518,15.62742],[105.63612,15.66056],[105.5975,15.72088],[105.49965,15.76681],[105.46291,15.74517],[105.43819,15.75459],[105.40489,15.79424],[105.34241,15.92039],[105.37811,15.98344],[105.39167,15.99136],[105.41931,15.98608],[105.42652,15.99764],[105.41468,16.01661],[105.21263,16.05076],[105.04955,16.10552],[105.01316,16.24401],[104.88235,16.37812],[104.8391,16.45782],[104.77936,16.49041],[104.73919,16.53287],[104.74228,16.62205],[104.76391,16.70953],[104.73953,16.80323],[104.76425,16.85088],[104.73782,16.90968],[104.744,17.0128],[104.81266,17.21853],[104.79841,17.39274],[104.70348,17.52833],[104.46384,17.65515],[104.34368,17.83564],[104.27776,17.8559],[104.22661,17.98069],[104.1116,18.10735],[104.06525,18.21174],[103.97392,18.33823],[103.9286,18.33237],[103.88809,18.29456],[103.85582,18.28673],[103.83659,18.32715],[103.79128,18.3467],[103.70201,18.34214],[103.60931,18.40405],[103.57292,18.40437],[103.51593,18.42978],[103.45963,18.42587],[103.41568,18.44802],[103.30479,18.43206],[103.24265,18.37082],[103.24333,18.34133],[103.29123,18.32357],[103.28899,18.29521],[103.23595,18.28299],[103.16608,18.25511],[103.02429,17.98135],[102.6535,17.83237],[102.40631,17.99963],[102.10968,18.22413],[101.548,17.81538],[101.30493,17.64991],[101.14563,17.46595],[100.95886,17.61654],[101.01757,17.88858],[101.18752,18.05121],[101.16863,18.10409],[101.18134,18.33595],[101.08727,18.38287],[101.05499,18.43988],[101.23215,18.73015],[101.35265,19.04524],[101.25927,19.12733],[101.2373,19.32637],[101.25824,19.58438],[101.11954,19.56836],[101.08898,19.58777],[101.08624,19.59715],[101.03165,19.6185],[100.89844,19.62125],[100.77827,19.49249],[100.63751,19.56432],[100.58258,19.49313],[100.47478,19.5944],[100.42929,19.67152],[100.43341,19.7024],[100.4147,19.7255],[100.40525,19.7646],[100.43907,19.80345],[100.45555,19.84843],[100.50636,19.87264],[100.51709,19.93027],[100.58653,20.1599],[100.56576,20.1757],[100.54945,20.17473],[100.52731,20.14379],[100.51065,20.14895],[100.48697,20.17956],[100.46774,20.196],[100.45246,20.20147],[100.45521,20.22129],[100.44783,20.23546],[100.41607,20.25286],[100.40594,20.28184],[100.38397,20.31082],[100.37556,20.35187],[100.36165,20.35638],[100.35736,20.37408],[100.33195,20.39902],[100.27805,20.40224],[100.25917,20.39677],[100.2475,20.37263],[100.22535,20.35509],[100.22346,20.31839],[100.16579,20.29988],[100.17162,20.24545],[100.10845,20.25221],[100.09266,20.2696],[100.09798,20.31485],[100.07961,20.3678],[99.9567,20.46417],[99.91636,20.44925],[99.90765,20.44977],[99.89121,20.44511],[99.87276,20.44406],[99.86212,20.44326],[99.80186,20.33948],[99.46472,20.3884],[99.56085,20.20035],[99.43691,20.08882],[99.27727,20.11623],[99.06921,20.1101],[98.97789,19.74538],[98.24387,19.68656],[97.85934,19.57014],[97.76733,18.57336],[97.39655,18.47179],[97.62451,18.30238],[97.73849,17.97743],[97.66502,17.87943],[97.90947,17.56745],[98.52951,16.82557],[98.51303,16.69276],[98.69293,16.26873],[98.87421,16.43609],[98.93394,16.3353],[98.84743,16.13356],[98.74512,16.12037],[98.58307,16.07287],[98.5762,15.79754],[98.54736,15.37557],[98.17383,15.15167],[98.3606,14.63674],[99.08295,13.89208],[99.16534,13.72204],[99.18182,13.00723],[99.39331,12.56797],[99.64153,11.78973],[99.32156,11.30266],[98.77859,10.67849],[98.80597,10.47642],[98.76657,10.40459],[98.74924,10.34194],[96.85547,6.40265],[92.42523,20.54794],[92.2728,20.96272],[92.187,21.16],[92.26,21.36],[92.27,21.4328],[92.62,21.43],[92.6,22],[93.22,22.25],[93.4,23.7],[93.34,23.95],[94.155,23.847],[94.17,23.92],[94.25171,24.07405],[94.28,24.23],[94.30175,24.2371],[94.3256,24.2731],[94.6,24.7],[94.78,25.47],[95.2,26],[95.1,26.6],[97.3,27.9],[96.14,29.38],[95.4,29.1],[94.8,29.2],[92.5,27.8],[91.64,27.76],[91.4,28],[89.58,28.18],[88.9,27.32],[88.74,27.47],[88.9,27.86],[88.7,28.1],[88.1,27.87],[85.93,27.942],[81.6,30.5],[81.2,30],[78.73,31.5],[78.77,31.99],[78.4,32.5],[79.3,32.5],[79,34.3],[78.3,34.6],[78,35.5],[76.1,35.8],[76,36.55],[75.15,37],[72.5,36.9],[71.1,36.1],[71.65,35.44],[71.45,35],[70.985,34.54],[71.18,34.36],[71.092,34.118],[70.88,33.97],[70.5,33.94],[69.908,34.04],[69.869,33.96],[70,33.75],[70.13,33.73],[70.34,33.34],[70.013,33.14],[69.57,33.09],[69.24,32.45],[69.3,31.9],[68.1,31.6],[66.393,30.934],[66.2,29.8],[62.5,29.4],[60.87,29.86],[61.53,29.0165],[61.66,28.77],[61.96,28.54],[62.43,28.42],[62.6,28.25],[62.795,28.28],[62.86,27.25],[63.24,27.25],[63.327,27.13],[63.25,27.1],[63.25,26.84],[63.18,26.83],[63.18,26.65],[62.3,26.5],[62.2,26.28],[61.85,26.22],[61.84,25.75],[61.68,25.67],[56.5,-21],[180,-65],[180,-35]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[138.7,46.7],[145.5,44.5],[145.2,43.7],[146,43.3],[142,18],[122,24.3],[138.7,46.7]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-180,7],[-148,7],[-151,-12],[-171.5,-10.75],[-171,-16],[-152,-19],[-180,-55],[-180,7]]]}}];
18620 var dataDriveLeft = {
18621         type: type$1,
18622         features: features$1
18623 };
18624
18625 var en = {"modes":{"add_area":{"title":"Area","description":"Add parks, buildings, lakes or other areas to the map.","tail":"Click on the map to start drawing an area, like a park, lake, or building."},"add_line":{"title":"Line","description":"Add highways, streets, pedestrian paths, canals or other lines to the map.","tail":"Click on the map to start drawing a road, path, or route."},"add_point":{"title":"Point","description":"Add restaurants, monuments, postal boxes or other points to the map.","tail":"Click on the map to add a point."},"browse":{"title":"Browse","description":"Pan and zoom the map."},"draw_area":{"tail":"Click to add nodes to your area. Click the first node to finish the area."},"draw_line":{"tail":"Click to add more nodes to the line. Click on other lines to connect to them, and double-click to end the line."}},"operations":{"add":{"annotation":{"point":"Added a point.","vertex":"Added a node to a way.","relation":"Added a relation."}},"start":{"annotation":{"line":"Started a line.","area":"Started an area."}},"continue":{"key":"A","title":"Continue","description":"Continue this line.","not_eligible":"No line can be continued here.","multiple":"Several lines can be continued here. To choose a line, press the Shift key and click on it to select it.","annotation":{"line":"Continued a line.","area":"Continued an area."}},"cancel_draw":{"annotation":"Canceled drawing."},"change_role":{"annotation":"Changed the role of a relation member."},"change_tags":{"annotation":"Changed tags."},"circularize":{"title":"Circularize","description":{"line":"Make this line circular.","area":"Make this area circular."},"key":"O","annotation":{"line":"Made a line circular.","area":"Made an area circular."},"not_closed":"This can't be made circular because it's not a loop.","too_large":"This can't be made circular because not enough of it is currently visible.","connected_to_hidden":"This can't be made circular because it is connected to a hidden feature."},"orthogonalize":{"title":"Square","description":{"line":"Square the corners of this line.","area":"Square the corners of this area."},"key":"S","annotation":{"line":"Squared the corners of a line.","area":"Squared the corners of an area."},"not_squarish":"This can't be made square because it is not squarish.","too_large":"This can't be made square because not enough of it is currently visible.","connected_to_hidden":"This can't be made square because it is connected to a hidden feature."},"straighten":{"title":"Straighten","description":"Straighten this line.","key":"S","annotation":"Straightened a line.","too_bendy":"This can't be straightened because it bends too much.","connected_to_hidden":"This line can't be straightened because it is connected to a hidden feature."},"delete":{"title":"Delete","description":{"single":"Delete this feature permanently.","multiple":"Delete these features permanently."},"annotation":{"point":"Deleted a point.","vertex":"Deleted a node from a way.","line":"Deleted a line.","area":"Deleted an area.","relation":"Deleted a relation.","multiple":"Deleted {n} features."},"too_large":{"single":"This feature can't be deleted because not enough of it is currently visible.","multiple":"These features can't be deleted because not enough of them are currently visible."},"incomplete_relation":{"single":"This feature can't be deleted because it hasn't been fully downloaded.","multiple":"These features can't be deleted because they haven't been fully downloaded."},"part_of_relation":{"single":"This feature can't be deleted because it is part of a larger relation. You must remove it from the relation first.","multiple":"These features can't be deleted because they are part of larger relations. You must remove them from the relations first."},"connected_to_hidden":{"single":"This feature can't be deleted because it is connected to a hidden feature.","multiple":"These features can't be deleted because some are connected to hidden features."}},"add_member":{"annotation":"Added a member to a relation."},"delete_member":{"annotation":"Removed a member from a relation."},"connect":{"annotation":{"point":"Connected a way to a point.","vertex":"Connected a way to another.","line":"Connected a way to a line.","area":"Connected a way to an area."}},"disconnect":{"title":"Disconnect","description":"Disconnect these lines/areas from each other.","key":"D","annotation":"Disconnected lines/areas.","not_connected":"There aren't enough lines/areas here to disconnect.","connected_to_hidden":"This can't be disconnected because it is connected to a hidden feature.","relation":"This can't be disconnected because it connects members of a relation."},"merge":{"title":"Merge","description":"Merge these features.","key":"C","annotation":"Merged {n} features.","not_eligible":"These features can't be merged.","not_adjacent":"These features can't be merged because their endpoints aren't connected.","restriction":"These features can't be merged because at least one is a member of a \"{relation}\" relation.","incomplete_relation":"These features can't be merged because at least one hasn't been fully downloaded.","conflicting_tags":"These features can't be merged because some of their tags have conflicting values."},"move":{"title":"Move","description":{"single":"Move this feature to a different location.","multiple":"Move these features to a different location."},"key":"M","annotation":{"point":"Moved a point.","vertex":"Moved a node in a way.","line":"Moved a line.","area":"Moved an area.","multiple":"Moved multiple features."},"incomplete_relation":{"single":"This feature can't be moved because it hasn't been fully downloaded.","multiple":"These features can't be moved because they haven't been fully downloaded."},"too_large":{"single":"This feature can't be moved because not enough of it is currently visible.","multiple":"These features can't be moved because not enough of them are currently visible."},"connected_to_hidden":{"single":"This feature can't be moved because it is connected to a hidden feature.","multiple":"These features can't be moved because some are connected to hidden features."}},"reflect":{"title":{"long":"Reflect Long","short":"Reflect Short"},"description":{"long":{"single":"Reflect this feature across its long axis.","multiple":"Reflect these features across their long axis."},"short":{"single":"Reflect this feature across its short axis.","multiple":"Reflect these features across their short axis."}},"key":{"long":"T","short":"Y"},"annotation":{"long":{"single":"Reflected a feature across its long axis.","multiple":"Reflected multiple features across their long axis."},"short":{"single":"Reflected a feature across its short axis.","multiple":"Reflected multiple features across their short axis."}},"incomplete_relation":{"single":"This feature can't be reflected because it hasn't been fully downloaded.","multiple":"These features can't be reflected because they haven't been fully downloaded."},"too_large":{"single":"This feature can't be reflected because not enough of it is currently visible.","multiple":"These features can't be reflected because not enough of them are currently visible."},"connected_to_hidden":{"single":"This feature can't be reflected because it is connected to a hidden feature.","multiple":"These features can't be reflected because some are connected to hidden features."}},"rotate":{"title":"Rotate","description":{"single":"Rotate this feature around its center point.","multiple":"Rotate these features around their center point."},"key":"R","annotation":{"line":"Rotated a line.","area":"Rotated an area.","multiple":"Rotated multiple features."},"incomplete_relation":{"single":"This feature can't be rotated because it hasn't been fully downloaded.","multiple":"These features can't be rotated because they haven't been fully downloaded."},"too_large":{"single":"This feature can't be rotated because not enough of it is currently visible.","multiple":"These features can't be rotated because not enough of them are currently visible."},"connected_to_hidden":{"single":"This feature can't be rotated because it is connected to a hidden feature.","multiple":"These features can't be rotated because some are connected to hidden features."}},"reverse":{"title":"Reverse","description":"Make this line go in the opposite direction.","key":"V","annotation":"Reversed a line."},"split":{"title":"Split","description":{"line":"Split this line into two at this node.","area":"Split the boundary of this area into two.","multiple":"Split the lines/area boundaries at this node into two."},"key":"X","annotation":{"line":"Split a line.","area":"Split an area boundary.","multiple":"Split {n} lines/area boundaries."},"not_eligible":"Lines can't be split at their beginning or end.","multiple_ways":"There are too many lines here to split.","connected_to_hidden":"This can't be split because it is connected to a hidden feature."},"restriction":{"help":{"select":"Click to select a road segment.","toggle":"Click to toggle turn restrictions.","toggle_on":"Click to add a \"{restriction}\" restriction.","toggle_off":"Click to remove the \"{restriction}\" restriction."},"annotation":{"create":"Added a turn restriction","delete":"Deleted a turn restriction"}}},"undo":{"tooltip":"Undo: {action}","nothing":"Nothing to undo."},"redo":{"tooltip":"Redo: {action}","nothing":"Nothing to redo."},"tooltip_keyhint":"Shortcut:","browser_notice":"This editor is supported in Firefox, Chrome, Safari, Opera, and Internet Explorer 11 and above. Please upgrade your browser or use Potlatch 2 to edit the map.","translate":{"translate":"Translate","localized_translation_label":"Multilingual name","localized_translation_language":"Choose language","localized_translation_name":"Name"},"zoom_in_edit":"Zoom in to Edit","login":"login","logout":"logout","loading_auth":"Connecting to OpenStreetMap...","report_a_bug":"Report a bug","help_translate":"Help translate","feature_info":{"hidden_warning":"{count} hidden features","hidden_details":"These features are currently hidden: {details}"},"status":{"error":"Unable to connect to API.","offline":"The API is offline. Please try editing later.","readonly":"The API is read-only. You will need to wait to save your changes.","rateLimit":"The API is limiting anonymous connections.  You can fix this by logging in."},"commit":{"title":"Upload to OpenStreetMap","description_placeholder":"Brief description of your contributions (required)","message_label":"Changeset Comment","upload_explanation":"The changes you upload will be visible on all maps that use OpenStreetMap data.","upload_explanation_with_user":"The changes you upload as {user} will be visible on all maps that use OpenStreetMap data.","save":"Upload","cancel":"Cancel","changes":"{count} Changes","warnings":"Warnings","modified":"Modified","deleted":"Deleted","created":"Created","about_changeset_comments":"About changeset comments","about_changeset_comments_link":"//wiki.openstreetmap.org/wiki/Good_changeset_comments","google_warning":"You mentioned Google in this comment: remember that copying from Google Maps is strictly forbidden.","google_warning_link":"http://www.openstreetmap.org/copyright"},"contributors":{"list":"Edits by {users}","truncated_list":"Edits by {users} and {count} others"},"info_panels":{"key":"I","background":{"key":"B","title":"Background","zoom":"Zoom","vintage":"Vintage","unknown":"Unknown","show_tiles":"Show Tiles","hide_tiles":"Hide Tiles"},"history":{"key":"H","title":"History","selected":"{n} selected","version":"Version","last_edit":"Last Edit","edited_by":"Edited By","changeset":"Changeset","unknown":"Unknown","link_text":"History on openstreetmap.org"},"location":{"key":"L","title":"Location","unknown_location":"Unknown Location"},"measurement":{"key":"M","title":"Measurement","selected":"{n} selected","geometry":"Geometry","closed":"closed","center":"Center","perimeter":"Perimeter","length":"Length","area":"Area","centroid":"Centroid","location":"Location","metric":"Metric","imperial":"Imperial"}},"geometry":{"point":"point","vertex":"vertex","line":"line","area":"area","relation":"relation"},"geocoder":{"search":"Search worldwide...","no_results_visible":"No results in visible map area","no_results_worldwide":"No results found"},"geolocate":{"title":"Show My Location","locating":"Locating, please wait..."},"inspector":{"no_documentation_combination":"There is no documentation available for this tag combination","no_documentation_key":"There is no documentation available for this key","documentation_redirect":"This documentation has been redirected to a new page","show_more":"Show More","view_on_osm":"View on openstreetmap.org","all_fields":"All fields","all_tags":"All tags","all_members":"All members","all_relations":"All relations","new_relation":"New relation...","role":"Role","choose":"Select feature type","results":"{n} results for {search}","reference":"View on OpenStreetMap Wiki","back_tooltip":"Change feature","remove":"Remove","search":"Search","multiselect":"Selected features","unknown":"Unknown","incomplete":"<not downloaded>","feature_list":"Search features","edit":"Edit feature","check":{"yes":"Yes","no":"No","reverser":"Change Direction"},"radio":{"structure":{"type":"Type","default":"Default","layer":"Layer"}},"add":"Add","none":"None","node":"Node","way":"Way","relation":"Relation","location":"Location","add_fields":"Add field:"},"background":{"title":"Background","description":"Background settings","key":"B","percent_brightness":"{opacity}% brightness","none":"None","best_imagery":"Best known imagery source for this location","switch":"Switch back to this background","custom":"Custom","custom_button":"Edit custom background","custom_prompt":"Enter a tile URL template. Valid tokens are:\n   - {zoom}/{z}, {x}, {y} for Z/X/Y tile scheme\n   - {ty} for flipped TMS-style Y coordinates\n   - {u} for quadtile scheme\n   - {switch:a,b,c} for DNS server multiplexing\n\nExample:\n{example}","fix_misalignment":"Adjust imagery offset","imagery_source_faq":"Where does this imagery come from?","reset":"reset","offset":"Drag anywhere in the gray area below to adjust the imagery offset, or enter the offset values in meters.","minimap":{"description":"Minimap","tooltip":"Show a zoomed out map to help locate the area currently displayed.","key":"/"}},"map_data":{"title":"Map Data","description":"Map Data","key":"F","data_layers":"Data Layers","fill_area":"Fill Areas","map_features":"Map Features","autohidden":"These features have been automatically hidden because too many would be shown on the screen.  You can zoom in to edit them."},"feature":{"points":{"description":"Points","tooltip":"Points of Interest"},"traffic_roads":{"description":"Traffic Roads","tooltip":"Highways, Streets, etc."},"service_roads":{"description":"Service Roads","tooltip":"Service Roads, Parking Aisles, Tracks, etc."},"paths":{"description":"Paths","tooltip":"Sidewalks, Foot Paths, Cycle Paths, etc."},"buildings":{"description":"Buildings","tooltip":"Buildings, Shelters, Garages, etc."},"landuse":{"description":"Landuse Features","tooltip":"Forests, Farmland, Parks, Residential, Commercial, etc."},"boundaries":{"description":"Boundaries","tooltip":"Administrative Boundaries"},"water":{"description":"Water Features","tooltip":"Rivers, Lakes, Ponds, Basins, etc."},"rail":{"description":"Rail Features","tooltip":"Railways"},"power":{"description":"Power Features","tooltip":"Power Lines, Power Plants, Substations, etc."},"past_future":{"description":"Past/Future","tooltip":"Proposed, Construction, Abandoned, Demolished, etc."},"others":{"description":"Others","tooltip":"Everything Else"}},"area_fill":{"wireframe":{"description":"No Fill (Wireframe)","tooltip":"Enabling wireframe mode makes it easy to see the background imagery.","key":"W"},"partial":{"description":"Partial Fill","tooltip":"Areas are drawn with fill only around their inner edges. (Recommended for beginner mappers)"},"full":{"description":"Full Fill","tooltip":"Areas are drawn fully filled."}},"restore":{"heading":"You have unsaved changes","description":"Do you wish to restore unsaved changes from a previous editing session?","restore":"Restore my changes","reset":"Discard my changes"},"save":{"title":"Save","help":"Review your changes and upload them to OpenStreetMap, making them visible to other users.","no_changes":"No changes to save.","error":"Errors occurred while trying to save","status_code":"Server returned status code {code}","unknown_error_details":"Please ensure you are connected to the internet.","uploading":"Uploading changes to OpenStreetMap...","unsaved_changes":"You have unsaved changes","conflict":{"header":"Resolve conflicting edits","count":"Conflict {num} of {total}","previous":"< Previous","next":"Next >","keep_local":"Keep mine","keep_remote":"Use theirs","restore":"Restore","delete":"Leave Deleted","download_changes":"Or download your changes.","done":"All conflicts resolved!","help":"Another user changed some of the same map features you changed.\nClick on each feature below for more details about the conflict, and choose whether to keep\nyour changes or the other user's changes.\n"}},"merge_remote_changes":{"conflict":{"deleted":"This feature has been deleted by {user}.","location":"This feature was moved by both you and {user}.","nodelist":"Nodes were changed by both you and {user}.","memberlist":"Relation members were changed by both you and {user}.","tags":"You changed the <b>{tag}</b> tag to \"{local}\" and {user} changed it to \"{remote}\"."}},"success":{"edited_osm":"Edited OSM!","just_edited":"You just edited OpenStreetMap!","view_on_osm":"View on OSM","facebook":"Share on Facebook","twitter":"Share on Twitter","google":"Share on Google+","help_html":"Your changes should appear in the \"Standard\" layer in a few minutes. Other layers, and certain features, may take longer.","help_link_text":"Details","help_link_url":"https://wiki.openstreetmap.org/wiki/FAQ#I_have_just_made_some_changes_to_the_map._How_do_I_get_to_see_my_changes.3F"},"confirm":{"okay":"OK","cancel":"Cancel"},"splash":{"welcome":"Welcome to the iD OpenStreetMap editor","text":"iD is a friendly but powerful tool for contributing to the world's best free world map. This is version {version}. For more information see {website} and report bugs at {github}.","walkthrough":"Start the Walkthrough","start":"Edit Now"},"source_switch":{"live":"live","lose_changes":"You have unsaved changes. Switching the map server will discard them. Are you sure you want to switch servers?","dev":"dev"},"version":{"whats_new":"What's new in iD {version}"},"tag_reference":{"description":"Description","on_wiki":"{tag} on wiki.osm.org","used_with":"used with {type}"},"validations":{"disconnected_highway":"Disconnected highway","disconnected_highway_tooltip":"Roads should be connected to other roads or building entrances.","old_multipolygon":"Multipolygon tags on outer way","old_multipolygon_tooltip":"This style of multipolygon is deprecated. Please assign the tags to the parent multipolygon instead of the outer way.","untagged_point":"Untagged point","untagged_point_tooltip":"Select a feature type that describes what this point is.","untagged_line":"Untagged line","untagged_line_tooltip":"Select a feature type that describes what this line is.","untagged_area":"Untagged area","untagged_area_tooltip":"Select a feature type that describes what this area is.","untagged_relation":"Untagged relation","untagged_relation_tooltip":"Select a feature type that describes what this relation is.","many_deletions":"You're deleting {n} features. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.","tag_suggests_area":"The tag {tag} suggests line should be area, but it is not an area","deprecated_tags":"Deprecated tags: {tags}"},"zoom":{"in":"Zoom In","out":"Zoom Out"},"cannot_zoom":"Cannot zoom out further in current mode.","full_screen":"Toggle Full Screen","gpx":{"local_layer":"Local file","drag_drop":"Drag and drop a .gpx, .geojson or .kml file on the page, or click the button to the right to browse","zoom":"Zoom to layer","browse":"Browse for a file"},"mapillary_images":{"tooltip":"Street-level photos from Mapillary","title":"Photo Overlay (Mapillary)"},"mapillary_signs":{"tooltip":"Traffic signs from Mapillary (must enable Photo Overlay)","title":"Traffic Sign Overlay (Mapillary)"},"mapillary":{"view_on_mapillary":"View this image on Mapillary"},"help":{"title":"Help","key":"H","help":"# Help\n\nThis is an editor for [OpenStreetMap](http://www.openstreetmap.org/), the\nfree and editable map of the world. You can use it to add and update\ndata in your area, making an open-source and open-data map of the world\nbetter for everyone.\n\nEdits that you make on this map will be visible to everyone who uses\nOpenStreetMap. In order to make an edit, you'll need to\n[log in](https://www.openstreetmap.org/login).\n\nThe [iD editor](http://ideditor.com/) is a collaborative project with [source\ncode available on GitHub](https://github.com/openstreetmap/iD).\n","editing_saving":"# Editing & Saving\n\nThis editor is designed to work primarily online, and you're accessing\nit through a website right now.\n\n### Selecting Features\n\nTo select a map feature, like a road or point of interest, click\non it on the map. This will highlight the selected feature, open a panel with\ndetails about it, and show a menu of things you can do with the feature.\n\nTo select multiple features, hold down the 'Shift' key. Then either click\non the features you want to select, or drag on the map to draw a rectangle.\nThis will draw a box and select all the points within it.\n\n### Saving Edits\n\nWhen you make changes like editing roads, buildings, and places, these are\nstored locally until you save them to the server. Don't worry if you make\na mistake - you can undo changes by clicking the undo button, and redo\nchanges by clicking the redo button.\n\nClick 'Save' to finish a group of edits - for instance, if you've completed\nan area of town and would like to start on a new area. You'll have a chance\nto review what you've done, and the editor supplies helpful suggestions\nand warnings if something doesn't seem right about the changes.\n\nIf everything looks good, you can enter a short comment explaining the change\nyou made, and click 'Save' again to post the changes\nto [OpenStreetMap.org](http://www.openstreetmap.org/), where they are visible\nto all other users and available for others to build and improve upon.\n\nIf you can't finish your edits in one sitting, you can leave the editor\nwindow and come back (on the same browser and computer), and the\neditor application will offer to restore your work.\n\n### Using the editor\n\nYou can view a list of keyboard shortcuts by pressing the `?` key.\n","roads":"# Roads\n\nYou can create, fix, and delete roads with this editor. Roads can be all\nkinds: paths, highways, trails, cycleways, and more - any often-crossed\nsegment should be mappable.\n\n### Selecting\n\nClick on a road to select it. An outline should become visible, along\nwith a small tools menu on the map and a sidebar showing more information\nabout the road.\n\n### Modifying\n\nOften you'll see roads that aren't aligned to the imagery behind them\nor to a GPS track. You can adjust these roads so they are in the correct\nplace.\n\nFirst click on the road you want to change. This will highlight it and show\ncontrol points along it that you can drag to better locations. If\nyou want to add new control points for more detail, double-click a part\nof the road without a node, and one will be added.\n\nIf the road connects to another road, but doesn't properly connect on\nthe map, you can drag one of its control points onto the other road in\norder to join them. Having roads connect is important for the map\nand essential for providing driving directions.\n\nYou can also click the 'Move' tool or press the `M` shortcut key to move the entire road at\none time, and then click again to save that movement.\n\n### Deleting\n\nIf a road is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the road could simply be newly built.\n\nYou can delete a road by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n\n### Creating\n\nFound somewhere there should be a road but there isn't? Click the 'Line'\nicon in the top-left of the editor or press the shortcut key `2` to start drawing\na line.\n\nClick on the start of the road on the map to start drawing. If the road\nbranches off from an existing road, start by clicking on the place where they connect.\n\nThen click on points along the road so that it follows the right path, according\nto satellite imagery or GPS. If the road you are drawing crosses another road, connect\nit by clicking on the intersection point. When you're done drawing, double-click\nor press 'Return' or 'Enter' on your keyboard.\n","gps":"# GPS\n\nCollected GPS traces are one valuable source of data for OpenStreetMap. This editor\nsupports local traces - `.gpx` files on your local computer. You can collect\nthis kind of GPS trace with a number of smartphone applications as well as\npersonal GPS hardware.\n\nFor information on how to perform a GPS survey, read\n[Mapping with a smartphone, GPS, or paper](http://learnosm.org/en/mobile-mapping/).\n\nTo use a GPX track for mapping, drag and drop the GPX file onto the map\neditor. If it's recognized, it will be added to the map as a bright purple\nline. Click on the 'Map Data' menu on the right side to enable,\ndisable, or zoom to this new GPX-powered layer.\n\nThe GPX track isn't directly uploaded to OpenStreetMap - the best way to\nuse it is to draw on the map, using it as a guide for the new features that\nyou add, and also to [upload it to OpenStreetMap](http://www.openstreetmap.org/trace/create)\nfor other users to use.\n","imagery":"# Imagery\n\nAerial imagery is an important resource for mapping. A combination of\nairplane flyovers, satellite views, and freely-compiled sources are available\nin the editor under the 'Background Settings' menu on the right.\n\nBy default a [Bing Maps](http://www.bing.com/maps/) satellite layer is\npresented in the editor, but as you pan and zoom the map to new geographical\nareas, new sources will become available. Some countries, like the United\nStates, France, and Denmark have very high-quality imagery available for some areas.\n\nImagery is sometimes offset from the map data because of a mistake on the\nimagery provider's side. If you see a lot of roads shifted from the background,\ndon't immediately move them all to match the background. Instead you can adjust\nthe imagery so that it matches the existing data by clicking 'Fix alignment' at\nthe bottom of the Background Settings UI.\n","addresses":"# Addresses\n\nAddresses are some of the most useful information for the map.\n\nAlthough addresses are often represented as parts of streets, in OpenStreetMap\nthey're recorded as attributes of buildings and places along streets.\n\nYou can add address information to places mapped as building outlines\nas well as those mapped as single points. The optimal source of address\ndata is from an on-the-ground survey or personal knowledge - as with any\nother feature, copying from commercial sources like Google Maps is strictly\nforbidden.\n","inspector":"# Using the Inspector\n\nThe inspector is the section on the left side of the page that allows you to\nedit the details of the selected feature.\n\n### Selecting a Feature Type\n\nAfter you add a point, line, or area, you can choose what type of feature it\nis, like whether it's a highway or residential road, supermarket or cafe.\nThe inspector will display buttons for common feature types, and you can\nfind others by typing what you're looking for in the search box.\n\nClick the 'i' in the bottom-right-hand corner of a feature type button to\nlearn more about it. Click a button to choose that type.\n\n### Using Forms and Editing Tags\n\nAfter you choose a feature type, or when you select a feature that already\nhas a type assigned, the inspector will display fields with details about\nthe feature like its name and address.\n\nBelow the fields you see, you can click the 'Add field' dropdown to add\nother details, like a Wikipedia link, wheelchair access, and more.\n\nAt the bottom of the inspector, click 'Additional tags' to add arbitrary\nother tags to the element. [Taginfo](http://taginfo.openstreetmap.org/) is a\ngreat resource for learn more about popular tag combinations.\n\nChanges you make in the inspector are automatically applied to the map.\nYou can undo them at any time by clicking the 'Undo' button.\n","buildings":"# Buildings\n\nOpenStreetMap is the world's largest database of buildings. You can create\nand improve this database.\n\n### Selecting\n\nYou can select a building by clicking on its border. This will highlight the\nbuilding and open a small tools menu and a sidebar showing more information\nabout the building.\n\n### Modifying\n\nSometimes buildings are incorrectly placed or have incorrect tags.\n\nTo move an entire building, select it, then click the 'Move' tool. Move your\nmouse to shift the building, and click when it's correctly placed.\n\nTo fix the specific shape of a building, click and drag the nodes that form\nits border into better places.\n\n### Creating\n\nOne of the main questions around adding buildings to the map is that\nOpenStreetMap records buildings both as shapes and points. The rule of thumb\nis to _map a building as a shape whenever possible_, and map companies, homes,\namenities, and other things that operate out of buildings as points placed\nwithin the building shape.\n\nStart drawing a building as a shape by clicking the 'Area' button in the top\nleft of the interface, and end it either by pressing 'Return' on your keyboard\nor clicking on the first node drawn to close the shape.\n\n### Deleting\n\nIf a building is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the building could simply be newly built.\n\nYou can delete a building by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n","relations":"# Relations\n\nA relation is a special type of feature in OpenStreetMap that groups together\nother features. For example, two common types of relations are *route relations*,\nwhich group together sections of road that belong to a specific freeway or\nhighway, and *multipolygons*, which group together several lines that define\na complex area (one with several pieces or holes in it like a donut).\n\nThe group of features in a relation are called *members*. In the sidebar, you can\nsee which relations a feature is a member of, and click on a relation there\nto select the it. When the relation is selected, you can see all of its\nmembers listed in the sidebar and highlighted on the map.\n\nFor the most part, iD will take care of maintaining relations automatically\nwhile you edit. The main thing you should be aware of is that if you delete a\nsection of road to redraw it more accurately, you should make sure that the\nnew section is a member of the same relations as the original.\n\n## Editing Relations\n\nIf you want to edit relations, here are the basics.\n\nTo add a feature to a relation, select the feature, click the \"+\" button in the\n\"All relations\" section of the sidebar, and select or type the name of the relation.\n\nTo create a new relation, select the first feature that should be a member,\nclick the \"+\" button in the \"All relations\" section, and select \"New relation...\".\n\nTo remove a feature from a relation, select the feature and click the trash\nbutton next to the relation you want to remove it from.\n\nYou can create multipolygons with holes using the \"Merge\" tool. Draw two areas (inner\nand outer), hold the Shift key and click on each of them to select them both, and then\nclick the \"Merge\" (+) button.\n"},"intro":{"done":"done","ok":"OK","graph":{"block_number":"<value for addr:block_number>","city":"Three Rivers","county":"<value for addr:county>","district":"<value for addr:district>","hamlet":"<value for addr:hamlet>","neighbourhood":"<value for addr:neighbourhood>","postcode":"49093","province":"<value for addr:province>","quarter":"<value for addr:quarter>","state":"MI","subdistrict":"<value for addr:subdistrict>","suburb":"<value for addr:suburb>","countrycode":"us","name":{"1st-avenue":"1st Avenue","2nd-avenue":"2nd Avenue","4th-avenue":"4th Avenue","5th-avenue":"5th Avenue","6th-avenue":"6th Avenue","6th-street":"6th Street","7th-avenue":"7th Avenue","8th-avenue":"8th Avenue","9th-avenue":"9th Avenue","10th-avenue":"10th Avenue","11th-avenue":"11th Avenue","12th-avenue":"12th Avenue","access-point-employment":"Access Point Employment","adams-street":"Adams Street","andrews-elementary-school":"Andrews Elementary School","andrews-street":"Andrews Street","armitage-street":"Armitage Street","barrows-school":"Barrows School","battle-street":"Battle Street","bennett-street":"Bennett Street","bowman-park":"Bowman Park","collins-drive":"Collins Drive","conrail-railroad":"Conrail Railroad","conservation-park":"Conservation Park","constantine-street":"Constantine Street","cushman-street":"Cushman Street","dollar-tree":"Dollar Tree","douglas-avenue":"Douglas Avenue","east-street":"East Street","elm-street":"Elm Street","flower-street":"Flower Street","foster-street":"Foster Street","french-street":"French Street","garden-street":"Garden Street","gem-pawnbroker":"Gem Pawnbroker","golden-finch-framing":"Golden Finch Framing","grant-avenue":"Grant Avenue","hoffman-pond":"Hoffman Pond","hoffman-street":"Hoffman Street","hook-avenue":"Hook Avenue","jefferson-street":"Jefferson Street","kelsey-street":"Kelsey Street","lafayette-park":"LaFayette Park","las-coffee-cafe":"L.A.'s Coffee Cafe","lincoln-avenue":"Lincoln Avenue","lowrys-books":"Lowry's Books","lynns-garage":"Lynn's Garage","main-street-barbell":"Main Street Barbell","main-street-cafe":"Main Street Cafe","main-street-fitness":"Main Street Fitness","main-street":"Main Street","maple-street":"Maple Street","marina-park":"Marina Park","market-street":"Market Street","memory-isle-park":"Memory Isle Park","memory-isle":"Memory Isle","michigan-avenue":"Michigan Avenue","middle-street":"Middle Street","millard-street":"Millard Street","moore-street":"Moore Street","morris-avenue":"Morris Avenue","mural-mall":"Mural Mall","paisanos-bar-and-grill":"Paisano's Bar and Grill","paisley-emporium":"Paisley Emporium","paparazzi-tattoo":"Paparazzi Tattoo","pealer-street":"Pealer Street","pine-street":"Pine Street","pizza-hut":"Pizza Hut","portage-avenue":"Portage Avenue","portage-river":"Portage River","preferred-insurance-services":"Preferred Insurance Services","railroad-drive":"Railroad Drive","river-city-appliance":"River City Appliance","river-drive":"River Drive","river-road":"River Road","river-street":"River Street","riverside-cemetery":"Riverside Cemetery","riverwalk-trail":"Riverwalk Trail","riviera-theatre":"Riviera Theatre","rocky-river":"Rocky River","saint-joseph-river":"Saint Joseph River","scidmore-park-petting-zoo":"Scidmore Park Petting Zoo","scidmore-park":"Scidmore Park","scouter-park":"Scouter Park","sherwin-williams":"Sherwin-Williams","south-street":"South Street","southern-michigan-bank":"Southern Michigan Bank","spring-street":"Spring Street","sturgeon-river-road":"Sturgeon River Road","three-rivers-city-hall":"Three Rivers City Hall","three-rivers-elementary-school":"Three Rivers Elementary School","three-rivers-fire-department":"Three Rivers Fire Department","three-rivers-high-school":"Three Rivers High School","three-rivers-middle-school":"Three Rivers Middle School","three-rivers-municipal-airport":"Three Rivers Municipal Airport","three-rivers-post-office":"Three Rivers Post Office","three-rivers-public-library":"Three Rivers Public Library","three-rivers":"Three Rivers","unique-jewelry":"Unique Jewelry","walnut-street":"Walnut Street","washington-street":"Washington Street","water-street":"Water Street","west-street":"West Street","wheeler-street":"Wheeler Street","william-towing":"William Towing","willow-drive":"Willow Drive","wood-street":"Wood Street","world-fare":"World Fare"}},"welcome":{"title":"Welcome","welcome":"Welcome! This walkthrough will teach you the basics of editing on OpenStreetMap.","practice":"All of the data in this walkthrough is just for practicing, and any edits that you make in the walkthrough will not be saved.","words":"This walkthrough will introduce some new words and concepts. When we introduce a new word, we'll use *italics*.","mouse":"You can use any input device to edit the map, but this walkthrough assumes you have a mouse with left and right buttons. **If you want to attach a mouse, do so now, then click OK.**","leftclick":"When this tutorial asks you to click or double-click, we mean with the left button. On a trackpad it might be a single-click or single-finger tap. **Left-click {num} times.**","rightclick":"Sometimes we'll also ask you to right-click. This might be the same as control-click, or two-finger tap on a trackpad. Your keyboard might even have a 'menu' key that works like right-click. **Right-click {num} times.**","chapters":"So far, so good! You can use the buttons below to skip chapters at any time or to restart a chapter if you get stuck. Let's begin! **Click '{next}' to continue.**"},"navigation":{"title":"Navigation","drag":"The main map area shows OpenStreetMap data on top of a background.{br}You can drag the map by pressing and holding the left mouse button while moving the mouse around. You can also use the arrow keys on your keyboard. **Drag the map!**","zoom":"You can zoom in or out by scrolling with the mouse wheel or trackpad, or by clicking the {plus} / {minus} buttons. **Zoom the map!**","features":"We use the word *features* to describe the things that appear on the map. Anything in the real world can be mapped as a feature on OpenStreetMap.","points_lines_areas":"Map features are represented using *points, lines, or areas.*","nodes_ways":"In OpenStreetMap, points are sometimes called *nodes*, and lines and areas are sometimes called *ways*.","click_townhall":"All features on the map can be selected by clicking on them. **Click on the point to select it.**","selected_townhall":"Great! The point is now selected. Selected features are drawn with a pulsing glow.","editor_townhall":"When a feature is selected, the *feature editor* is displayed alongside the map.","preset_townhall":"The top part of the feature editor shows the feature's type. This point is a {preset}.","fields_townhall":"The middle part of the feature editor contains *fields* showing the feature's attributes, such as its name and address.","close_townhall":"**Close the feature editor by hitting escape or pressing the {button} button in the upper corner.**","search_street":"You can also search for features in the current view, or worldwide. **Search for '{name}'.**","choose_street":"**Choose {name} from the list to select it.**","selected_street":"Great! {name} is now selected.","editor_street":"The fields shown for a street are different than the fields that were shown for the town hall.{br}For this selected street, the feature editor shows fields like '{field1}' and '{field2}'. **Close the feature editor by hitting escape or pressing the {button} button.**","play":"Try moving the map and clicking on some other features to see what kinds of things can be added to OpenStreetMap. **When you are ready to continue to the next chapter, click '{next}'.**"},"points":{"title":"Points","add_point":"*Points* can be used to represent features such as shops, restaurants, and monuments.{br}They mark a specific location, and describe what's there. **Click the {button} Point button to add a new point.**","place_point":"To place the new point on the map, position your mouse cursor where the point should go, then left-click or press the spacebar. **Move the mouse pointer over this building, then left-click or press the spacebar.**","search_cafe":"There are many different features that can be represented by points. The point you just added is a cafe. **Search for '{preset}'.**","choose_cafe":"**Choose {preset} from the list.**","feature_editor":"The point is now marked as a cafe. Using the feature editor, we can add more information about the cafe.","add_name":"In OpenStreetMap, all of the fields are optional, and it's OK to leave a field blank if you are unsure.{br}Let's pretend that you have local knowledge of this cafe, and you know its name. **Add a name for the cafe.**","add_close":"The feature editor will remember all of your changes automatically. **When you are finished adding the name, hit escape, enter, or click the {button} button to close the feature editor.**","reselect":"Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Click to select the cafe you just created.**","update":"Let's fill in some more details for this cafe. You can change its name, add a cuisine, or add an address. **Change the cafe details.**","update_close":"**When you are finished updating the cafe, hit escape, enter, or click the {button} button to close the feature editor.**","rightclick":"You can right-click on any feature to see the *edit menu*, which shows a list of editing operations that can be performed. **Right-click to select the point you created and show the edit menu.**","delete":"It's OK to delete features that don't exist in the real world.{br}Deleting a feature from OpenStreetMap removes it from the map that everyone uses, so you should make sure a feature is really gone before you delete it. **Click on the {button} button to delete the point.**","undo":"You can always undo any changes up until you save your edits to OpenStreetMap. **Click on the {button} button to undo the delete and get the point back.**","play":"Now that you know how to create and edit points, try creating a few more points for practice! **When you are ready to continue to the next chapter, click '{next}'.**"},"areas":{"title":"Areas","add_playground":"*Areas* are used to show the boundaries of features like lakes, buildings, and residential areas.{br}They can be also be used for more detailed mapping of many features you might normally map as points. **Click the {button} Area button to add a new area.**","start_playground":"Let's add this playground to the map by drawing an area. Areas are drawn by placing *nodes* along the outer edge of the feature. **Click or press spacebar to place a starting node on one of the corners of the playground.**","continue_playground":"Continue drawing the area by placing more nodes along the playground's edge. It is OK to connect the area to the existing walking paths.{br}Tip: You can hold down the '{alt}' key to prevent nodes from connecting to other features. **Continue drawing an area for the playground.**","finish_playground":"Finish the area by pressing enter, or clicking again on either the first or last node. **Finish drawing an area for the playground.**","search_playground":"**Search for '{preset}'.**","choose_playground":"**Choose {preset} from the list.**","add_field":"This playground doesn't have an official name, so we won't add anything in the Name field.{br}Instead let's add some additional details about the playground to the Description field. **Open the Add Field list.**","choose_field":"**Choose {field} from the list.**","retry_add_field":"You didn't select the {field} field. Let's try again.","describe_playground":"**Add a description, then click the {button} button to close the feature editor.**","play":"Good job! Try drawing a few more areas, and see what other kinds of area features you can add to OpenStreetMap. **When you are ready to continue to the next chapter, click '{next}'.**"},"lines":{"title":"Lines","add_line":"*Lines* are used to represent features such as roads, railroads, and rivers. **Click the {button} Line button to add a new line.**","start_line":"Here is a road that is missing. Let's add it!{br}In OpenStreetMap, lines should be drawn down the center of the road. You can drag and zoom the map while drawing if necessary. **Start a new line by clicking at the top end of this missing road.**","intersect":"Click or press spacebar to add more nodes to the line.{br}Roads, and many other types of lines, are part of a larger network. It is important for these lines to be connected properly in order for routing applications to work. **Click on {name} to create an intersection connecting the two lines.**","retry_intersect":"The road needs to intersect {name}. Let's try again!","continue_line":"Continue drawing the line for the new road. Remember that you can drag and zoom the map if needed.{br}When you are finished drawing, click on the last node again. **Finish drawing the road.**","choose_category_road":"**Select {category} from the list.**","choose_preset_residential":"There are many different types of roads, but this one is a residential road. **Choose the {preset} type.**","retry_preset_residential":"You didn't select the {preset} type. **Click here to choose again.**","name_road":"**Give this road a name, then hit escape, enter, or click the {button} button to close the feature editor.**","did_name_road":"Looks good! Next we will learn how to update the shape of a line.","update_line":"Sometimes you will need to change the shape of an existing line. Here is a road that doesn't look quite right.","add_node":"We can add some nodes to this line to improve its shape. One way to add a node is to double-click the line where you want to add a node. **Double-click on the line to create a new node.**","start_drag_endpoint":"When a line is selected, you can drag any of its nodes by clicking and holding down the left mouse button while you drag. **Drag the endpoint to the place where these roads should intersect.**","finish_drag_endpoint":"This spot looks good. **Release the left mouse button to finish dragging.**","start_drag_midpoint":"Small triangles are drawn at the *midpoints* between nodes. Another way to create a new node is to drag a midpoint to a new location. **Drag the midpoint triangle to create a new node along the curve of the road.**","continue_drag_midpoint":"This line is looking much better! Continue to adjust this line by double-clicking or dragging midpoints until the curve matches the road shape. **When you're happy with how the line looks, click OK.**","delete_lines":"It's OK to delete lines for roads that don't exist in the real world.{br}Here's an example where the city planned a {street} but never built it. We can improve this part of the map by deleting the extra lines.","rightclick_intersection":"The last real street is {street1}, so we will *split* {street2} at this intersection and remove everything above it. **Right click on the intersection node.**","split_intersection":"**Click on the {button} button to split {street}.**","retry_split":"You didn't click the Split button. Try again.","did_split_multi":"Good job! {street1} is now split into two pieces. The top part can be removed. **Click the top part of {street2} to select it.**","did_split_single":"**Click the top part of {street2} to select it.**","multi_select":"{selected} is now selected. Let's also select {other1}. You can shift-click to select multiple things. **Shift-click on {other2}.**","multi_rightclick":"Good! Both lines to delete are now selected. **Right-click on one of the lines to show the edit menu.**","multi_delete":"**Click on the {button} button to delete the extra lines.**","retry_delete":"You didn't click the Delete button. Try again.","play":"Great! Use the skills that you've learned in this chapter to practice editing some more lines. **When you are ready to continue to the next chapter, click '{next}'.**"},"buildings":{"title":"Buildings","add_building":"OpenStreetMap is the world's largest database of buildings.{br}You can help improve this database by tracing buildings that aren't already mapped. **Click the {button} Area button to add a new area.**","start_building":"Let's add this house to the map by tracing its outline.{br}Buildings should be traced around their footprint as accurately as possible. **Click or press spacebar to place a starting node on one of the corners of the building.**","continue_building":"Continue adding more nodes to trace the outline of the building. Remember that you can zoom in if you want to add more details.{br}Finish the building by pressing enter, or clicking again on either the first or last node. **Finish tracing the building.**","retry_building":"It looks like you had some trouble placing the nodes at the building corners. Try again!","choose_category_building":"**Choose {category} from the list.**","choose_preset_house":"There are many different types of buildings, but this one is clearly a house.{br}If you're not sure of the type, it's OK to just choose the generic Building type. **Choose the {preset} type.**","close":"**Hit escape or click the {button} button to close the feature editor.**","rightclick_building":"**Right-click to select the building you created and show the edit menu.**","square_building":"The house that you just added will look even better with perfectly square corners. **Click on the {button} button to square the building shape.**","retry_square":"You didn't click the Square button. Try again.","done_square":"See how the corners of the building moved into place? Let's learn another useful trick.","add_tank":"Next we'll trace this circular storage tank. **Click the {button} Area button to add a new area.**","start_tank":"Don't worry, you won't need to draw a perfect circle. Just draw an area inside the tank that touches its edge. **Click or press spacebar to place a starting node on the edge of the tank.**","continue_tank":"Add a few more nodes around the edge. The circle will be created outside the nodes that you draw.{br}Finish the area by pressing enter, or clicking again on either the first or last node. **Finish tracing the tank.**","search_tank":"**Search for '{preset}'.**","choose_tank":"**Choose {preset} from the list.**","rightclick_tank":"**Right-click to select the storage tank you created and show the edit menu.**","circle_tank":"**Click on the {button} button to make the tank a circle.**","retry_circle":"You didn't click the Circularize button. Try again.","play":"Great Job! Practice tracing a few more buildings, and try some of the other commands on the edit menu. **When you are ready to continue to the next chapter, click '{next}'.**"},"startediting":{"title":"Start Editing","help":"You're now ready to edit OpenStreetMap!{br}You can replay this walkthrough anytime or view more documentation by clicking the {button} Help button or pressing the '{key}' key.","shortcuts":"You can view a list of commands along with their keyboard shortcuts by pressing the '{key}' key.","save":"Don't forget to regularly save your changes!","start":"Start mapping!"}},"shortcuts":{"title":"Keyboard shortcuts","tooltip":"Show the keyboard shortcuts screen.","toggle":{"key":"?"},"key":{"alt":"Alt","backspace":"Backspace","cmd":"Cmd","ctrl":"Ctrl","delete":"Delete","del":"Del","end":"End","enter":"Enter","esc":"Esc","home":"Home","option":"Option","pause":"Pause","pgdn":"PgDn","pgup":"PgUp","return":"Return","shift":"Shift","space":"Space"},"gesture":{"drag":"drag"},"or":"-or-","browsing":{"title":"Browsing","navigation":{"title":"Navigation","pan":"Pan map","pan_more":"Pan map by one screenful","zoom":"Zoom in / Zoom out","zoom_more":"Zoom in / Zoom out by a lot"},"help":{"title":"Help","help":"Show help/documentation","keyboard":"Show keyboard shortcuts"},"display_options":{"title":"Display options","background":"Show background options","background_switch":"Switch back to last background","map_data":"Show map data options","fullscreen":"Enter full screen mode","wireframe":"Toggle wireframe mode","minimap":"Toggle minimap"},"selecting":{"title":"Selecting features","select_one":"Select a single feature","select_multi":"Select multiple features","lasso":"Draw a selection lasso around features"},"with_selected":{"title":"With feature selected","edit_menu":"Toggle edit menu"},"vertex_selected":{"title":"With node selected","previous":"Jump to previous node","next":"Jump to next node","first":"Jump to first node","last":"Jump to last node","change_parent":"Switch parent way"}},"editing":{"title":"Editing","drawing":{"title":"Drawing","add_point":"'Add point' mode","add_line":"'Add line' mode","add_area":"'Add area' mode","place_point":"Place a point","disable_snap":"Hold to disable point snapping","stop_line":"Finish drawing a line or area"},"operations":{"title":"Operations","continue_line":"Continue a line at the selected node","merge":"Combine (merge) selected features","disconnect":"Disconnect features at the selected node","split":"Split a line into two at the selected node","reverse":"Reverse a line","move":"Move selected features","rotate":"Rotate selected features","orthogonalize":"Straighten line / Square area corners","circularize":"Circularize a closed line or area","reflect_long":"Reflect features across the longer axis","reflect_short":"Reflect features across the shorter axis","delete":"Delete selected features"},"commands":{"title":"Commands","copy":"Copy selected features","paste":"Paste copied features","undo":"Undo last action","redo":"Redo last action","save":"Save changes"}},"tools":{"title":"Tools","info":{"title":"Information","all":"Toggle all information panels","background":"Toggle background panel","history":"Toggle history panel","location":"Toggle location panel","measurement":"Toggle measurement panel"}}},"presets":{"categories":{"category-barrier":{"name":"Barrier Features"},"category-building":{"name":"Building Features"},"category-golf":{"name":"Golf Features"},"category-landuse":{"name":"Land Use Features"},"category-natural-area":{"name":"Natural Features"},"category-natural-line":{"name":"Natural Features"},"category-natural-point":{"name":"Natural Features"},"category-path":{"name":"Path Features"},"category-rail":{"name":"Rail Features"},"category-restriction":{"name":"Restriction Features"},"category-road":{"name":"Road Features"},"category-route":{"name":"Route Features"},"category-water-area":{"name":"Water Features"},"category-water-line":{"name":"Water Features"}},"fields":{"access_simple":{"label":"Allowed Access"},"access_toilets":{"label":"Access"},"access":{"label":"Allowed Access","placeholder":"Not Specified","types":{"access":"All","foot":"Foot","motor_vehicle":"Motor Vehicles","bicycle":"Bicycles","horse":"Horses"},"options":{"yes":{"title":"Allowed","description":"Access permitted by law; a right of way"},"no":{"title":"Prohibited","description":"Access not permitted to the general public"},"permissive":{"title":"Permissive","description":"Access permitted until such time as the owner revokes the permission"},"private":{"title":"Private","description":"Access permitted only with permission of the owner on an individual basis"},"designated":{"title":"Designated","description":"Access permitted according to signs or specific local laws"},"destination":{"title":"Destination","description":"Access permitted only to reach a destination"},"dismount":{"title":"Dismount","description":"Access permitted but rider must dismount"}}},"address":{"label":"Address","placeholders":{"block_number":"Block Number","block_number!jp":"Block No.","city":"City","city!jp":"City/Town/Village/Tokyo Special Ward","city!vn":"City/Town","conscriptionnumber":"123","country":"Country","county":"County","county!jp":"District","district":"District","district!vn":"Arrondissement/Town/District","floor":"Floor","hamlet":"Hamlet","housename":"Housename","housenumber":"123","housenumber!jp":"Building No./Lot No.","neighbourhood":"Neighbourhood","neighbourhood!jp":"Chōme/Aza/Koaza","place":"Place","postcode":"Postcode","province":"Province","province!jp":"Prefecture","quarter":"Quarter","quarter!jp":"Ōaza/Machi","state":"State","street":"Street","subdistrict":"Subdistrict","subdistrict!vn":"Ward/Commune/Townlet","suburb":"Suburb","suburb!jp":"Ward"}},"admin_level":{"label":"Admin Level"},"aerialway":{"label":"Type"},"aerialway/access":{"label":"Access","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aerialway/bubble":{"label":"Bubble"},"aerialway/capacity":{"label":"Capacity (per hour)","placeholder":"500, 2500, 5000..."},"aerialway/duration":{"label":"Duration (minutes)","placeholder":"1, 2, 3..."},"aerialway/heating":{"label":"Heated"},"aerialway/occupancy":{"label":"Occupancy","placeholder":"2, 4, 8..."},"aerialway/summer/access":{"label":"Access (summer)","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aeroway":{"label":"Type"},"amenity":{"label":"Type"},"animal_boarding":{"label":"For Animals"},"animal_breeding":{"label":"For Animals"},"animal_shelter":{"label":"For Animals"},"area/highway":{"label":"Type"},"artist":{"label":"Artist"},"artwork_type":{"label":"Type"},"atm":{"label":"ATM"},"backrest":{"label":"Backrest"},"barrier":{"label":"Type"},"bath/open_air":{"label":"Open Air"},"bath/sand_bath":{"label":"Sand Bath"},"bath/type":{"label":"Specialty","options":{"onsen":"Japanese Onsen","foot_bath":"Foot Bath","hot_spring":"Hot Spring"}},"beauty":{"label":"Shop Type"},"bench":{"label":"Bench"},"bicycle_parking":{"label":"Type"},"bin":{"label":"Waste Bin"},"blood_components":{"label":"Blood Components","options":{"whole":"whole blood","plasma":"plasma","platelets":"platelets","stemcells":"stem cell samples"}},"board_type":{"label":"Type"},"boundary":{"label":"Type"},"brand":{"label":"Brand"},"building_area":{"label":"Building"},"building":{"label":"Building"},"bunker_type":{"label":"Type"},"camera/direction":{"label":"Direction (Degrees Clockwise)","placeholder":"45, 90, 180, 270"},"camera/mount":{"label":"Camera Mount"},"camera/type":{"label":"Camera Type","options":{"fixed":"Fixed","panning":"Panning","dome":"Dome"}},"capacity":{"label":"Capacity","placeholder":"50, 100, 200..."},"cardinal_direction":{"label":"Direction","options":{"N":"North","E":"East","S":"South","W":"West","NE":"Northeast","SE":"Southeast","SW":"Southwest","NW":"Northwest","NNE":"North-northeast","ENE":"East-northeast","ESE":"East-southeast","SSE":"South-southeast","SSW":"South-southwest","WSW":"West-southwest","WNW":"West-northwest","NNW":"North-northwest"}},"castle_type":{"label":"Type"},"clock_direction":{"label":"Direction","options":{"clockwise":"Clockwise","anticlockwise":"Counterclockwise"}},"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         template = source.template;
55401
55402     source.scaleExtent = data.scaleExtent || [0, 20];
55403     source.overzoom = data.overzoom !== false;
55404
55405
55406     source.offset = function(_) {
55407         if (!arguments.length) return offset;
55408         offset = _;
55409         return source;
55410     };
55411
55412
55413     source.nudge = function(_, zoomlevel) {
55414         offset[0] += _[0] / Math.pow(2, zoomlevel);
55415         offset[1] += _[1] / Math.pow(2, zoomlevel);
55416         return source;
55417     };
55418
55419
55420     source.name = function() {
55421         var id_safe = source.id.replace('.', '<TX_DOT>');
55422         return t('imagery.' + id_safe + '.name', { default: name });
55423     };
55424
55425
55426     source.description = function() {
55427         var id_safe = source.id.replace('.', '<TX_DOT>');
55428         return t('imagery.' + id_safe + '.description', { default: description });
55429     };
55430
55431
55432     source.best = function() {
55433         return best;
55434     };
55435
55436
55437     source.area = function() {
55438         if (!data.polygon) return Number.MAX_VALUE;  // worldwide
55439         var area$$1 = area({ type: 'MultiPolygon', coordinates: [ data.polygon ] });
55440         return isNaN(area$$1) ? 0 : area$$1;
55441     };
55442
55443
55444     source.imageryUsed = function() {
55445         return name || source.id;
55446     };
55447
55448
55449     source.template = function(_) {
55450         if (!arguments.length) return template;
55451         if (source.id === 'custom') template = _;
55452         return source;
55453     };
55454
55455
55456     source.url = function(coord) {
55457         return template
55458             .replace('{x}', coord[0])
55459             .replace('{y}', coord[1])
55460             // TMS-flipped y coordinate
55461             .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
55462             .replace(/\{z(oom)?\}/, coord[2])
55463             .replace(/\{switch:([^}]+)\}/, function(s, r) {
55464                 var subdomains = r.split(',');
55465                 return subdomains[(coord[0] + coord[1]) % subdomains.length];
55466             })
55467             .replace('{u}', function() {
55468                 var u = '';
55469                 for (var zoom$$1 = coord[2]; zoom$$1 > 0; zoom$$1--) {
55470                     var b = 0;
55471                     var mask = 1 << (zoom$$1 - 1);
55472                     if ((coord[0] & mask) !== 0) b++;
55473                     if ((coord[1] & mask) !== 0) b += 2;
55474                     u += b.toString();
55475                 }
55476                 return u;
55477             });
55478     };
55479
55480
55481     source.intersects = function(extent$$1) {
55482         extent$$1 = extent$$1.polygon();
55483         return !data.polygon || data.polygon.some(function(polygon) {
55484             return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
55485         });
55486     };
55487
55488
55489     source.validZoom = function(z) {
55490         return source.scaleExtent[0] <= z &&
55491             (source.overzoom || source.scaleExtent[1] > z);
55492     };
55493
55494
55495     source.isLocatorOverlay = function() {
55496         return source.id === 'mapbox_locator_overlay';
55497     };
55498
55499
55500     source.copyrightNotices = function() {};
55501
55502
55503     source.getVintage = function(center, tileCoord, callback) {
55504         var vintage = {
55505             start: localeDateString(source.startDate),
55506             end: localeDateString(source.endDate)
55507         };
55508         vintage.range = vintageRange(vintage);
55509         callback(null, vintage);
55510     };
55511
55512
55513     return source;
55514 }
55515
55516
55517 rendererBackgroundSource.Bing = function(data, dispatch$$1) {
55518     // http://msdn.microsoft.com/en-us/library/ff701716.aspx
55519     // http://msdn.microsoft.com/en-us/library/ff701701.aspx
55520
55521     data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
55522
55523     var bing = rendererBackgroundSource(data),
55524         key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
55525         url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
55526             key + '&jsonp={callback}',
55527         cache = {},
55528         providers = [];
55529
55530     jsonpRequest(url, function(json$$1) {
55531         providers = json$$1.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
55532             return {
55533                 attribution: provider.attribution,
55534                 areas: provider.coverageAreas.map(function(area$$1) {
55535                     return {
55536                         zoom: [area$$1.zoomMin, area$$1.zoomMax],
55537                         extent: geoExtent$$1([area$$1.bbox[1], area$$1.bbox[0]], [area$$1.bbox[3], area$$1.bbox[2]])
55538                     };
55539                 })
55540             };
55541         });
55542         dispatch$$1.call('change');
55543     });
55544
55545
55546     bing.copyrightNotices = function(zoom$$1, extent$$1) {
55547         zoom$$1 = Math.min(zoom$$1, 21);
55548         return providers.filter(function(provider) {
55549             return lodash.some(provider.areas, function(area$$1) {
55550                 return extent$$1.intersects(area$$1.extent) &&
55551                     area$$1.zoom[0] <= zoom$$1 &&
55552                     area$$1.zoom[1] >= zoom$$1;
55553             });
55554         }).map(function(provider) {
55555             return provider.attribution;
55556         }).join(', ');
55557     };
55558
55559
55560     bing.getVintage = function(center, tileCoord, callback) {
55561         var tileId = tileCoord.slice(0, 3).join('/'),
55562             zoom$$1 = Math.min(tileCoord[2], 21),
55563             centerPoint = center[1] + ',' + center[0],  // lat,lng
55564             url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint +
55565                 '?zl=' + zoom$$1 + '&key=' + key + '&jsonp={callback}';
55566
55567         if (!cache[tileId]) {
55568             cache[tileId] = {};
55569         }
55570         if (cache[tileId] && cache[tileId].vintage) {
55571             return callback(null, cache[tileId].vintage);
55572         }
55573
55574         jsonpRequest(url, function(result) {
55575             var err = (!result && 'Unknown Error') || result.errorDetails;
55576             if (err) {
55577                 return callback(err);
55578             } else {
55579                 var vintage = {
55580                     start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
55581                     end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
55582                 };
55583                 vintage.range = vintageRange(vintage);
55584                 cache[tileId].vintage = vintage;
55585                 return callback(null, vintage);
55586             }
55587         });
55588     };
55589
55590
55591     bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
55592
55593
55594     return bing;
55595 };
55596
55597
55598 rendererBackgroundSource.None = function() {
55599     var source = rendererBackgroundSource({ id: 'none', template: '' });
55600
55601
55602     source.name = function() {
55603         return t('background.none');
55604     };
55605
55606
55607     source.imageryUsed = function() {
55608         return 'None';
55609     };
55610
55611
55612     source.area = function() {
55613         return -1;  // sources in background pane are sorted by area
55614     };
55615
55616
55617     return source;
55618 };
55619
55620
55621 rendererBackgroundSource.Custom = function(template) {
55622     var source = rendererBackgroundSource({ id: 'custom', template: template });
55623
55624
55625     source.name = function() {
55626         return t('background.custom');
55627     };
55628
55629
55630     source.imageryUsed = function() {
55631         return 'Custom (' + source.template() + ')';
55632     };
55633
55634
55635     source.area = function() {
55636         return -2;  // sources in background pane are sorted by area
55637     };
55638
55639
55640     return source;
55641 };
55642
55643 function rendererTileLayer(context) {
55644     var tileSize = 256,
55645         tile = d3geoTile(),
55646         projection$$1,
55647         cache = {},
55648         tileOrigin,
55649         z,
55650         transformProp = utilPrefixCSSProperty('Transform'),
55651         source = rendererBackgroundSource.None();
55652
55653
55654     // blacklist overlay tiles around Null Island..
55655     function nearNullIsland(x, y, z) {
55656         if (z >= 7) {
55657             var center = Math.pow(2, z - 1),
55658                 width = Math.pow(2, z - 6),
55659                 min$$1 = center - (width / 2),
55660                 max$$1 = center + (width / 2) - 1;
55661             return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
55662         }
55663         return false;
55664     }
55665
55666
55667     function tileSizeAtZoom(d, z) {
55668         var epsilon = 0.002;
55669         return ((tileSize * Math.pow(2, z - d[2])) / tileSize) + epsilon;
55670     }
55671
55672
55673     function atZoom(t$$1, distance$$1) {
55674         var power = Math.pow(2, distance$$1);
55675         return [
55676             Math.floor(t$$1[0] * power),
55677             Math.floor(t$$1[1] * power),
55678             t$$1[2] + distance$$1];
55679     }
55680
55681
55682     function lookUp(d) {
55683         for (var up = -1; up > -d[2]; up--) {
55684             var tile = atZoom(d, up);
55685             if (cache[source.url(tile)] !== false) {
55686                 return tile;
55687             }
55688         }
55689     }
55690
55691
55692     function uniqueBy(a, n) {
55693         var o = [], seen = {};
55694         for (var i = 0; i < a.length; i++) {
55695             if (seen[a[i][n]] === undefined) {
55696                 o.push(a[i]);
55697                 seen[a[i][n]] = true;
55698             }
55699         }
55700         return o;
55701     }
55702
55703
55704     function addSource(d) {
55705         d.push(source.url(d));
55706         return d;
55707     }
55708
55709
55710     // Update tiles based on current state of `projection`.
55711     function background(selection$$1) {
55712         tile.scale(projection$$1.scale() * 2 * Math.PI)
55713             .translate(projection$$1.translate());
55714
55715         tileOrigin = [
55716             projection$$1.scale() * Math.PI - projection$$1.translate()[0],
55717             projection$$1.scale() * Math.PI - projection$$1.translate()[1]];
55718
55719         z = Math.max(Math.log(projection$$1.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
55720
55721         render(selection$$1);
55722     }
55723
55724
55725     // Derive the tiles onscreen, remove those offscreen and position them.
55726     // Important that this part not depend on `projection` because it's
55727     // rentered when tiles load/error (see #644).
55728     function render(selection$$1) {
55729         var requests = [];
55730         var showDebug = context.getDebug('tile') && !source.overlay;
55731
55732         if (source.validZoom(z)) {
55733             tile().forEach(function(d) {
55734                 addSource(d);
55735                 if (d[3] === '') return;
55736                 if (typeof d[3] !== 'string') return; // Workaround for #2295
55737                 requests.push(d);
55738                 if (cache[d[3]] === false && lookUp(d)) {
55739                     requests.push(addSource(lookUp(d)));
55740                 }
55741             });
55742
55743             requests = uniqueBy(requests, 3).filter(function(r) {
55744                 if (!!source.overlay && nearNullIsland(r[0], r[1], r[2])) {
55745                     return false;
55746                 }
55747                 // don't re-request tiles which have failed in the past
55748                 return cache[r[3]] !== false;
55749             });
55750         }
55751
55752         var pixelOffset = [
55753             source.offset()[0] * Math.pow(2, z),
55754             source.offset()[1] * Math.pow(2, z)
55755         ];
55756
55757
55758         function load(d) {
55759             cache[d[3]] = true;
55760             select(this)
55761                 .on('error', null)
55762                 .on('load', null)
55763                 .classed('tile-loaded', true);
55764             render(selection$$1);
55765         }
55766
55767         function error(d) {
55768             cache[d[3]] = false;
55769             select(this)
55770                 .on('error', null)
55771                 .on('load', null)
55772                 .remove();
55773             render(selection$$1);
55774         }
55775
55776         function imageTransform(d) {
55777             var _ts = tileSize * Math.pow(2, z - d[2]);
55778             var scale = tileSizeAtZoom(d, z);
55779             return 'translate(' +
55780                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
55781                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
55782                 'scale(' + scale + ',' + scale + ')';
55783         }
55784
55785         function tileCenter(d) {
55786             var _ts = tileSize * Math.pow(2, z - d[2]);
55787             return [
55788                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0] + (_ts / 2)),
55789                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1] + (_ts / 2))
55790             ];
55791         }
55792
55793         function debugTransform(d) {
55794             var coord = tileCenter(d);
55795             return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
55796         }
55797
55798
55799         // Pick a representative tile near the center of the viewport
55800         // (This is useful for sampling the imagery vintage)
55801         var dims = tile.size(),
55802             mapCenter = [dims[0] / 2, dims[1] / 2],
55803             minDist = Math.max(dims[0], dims[1]),
55804             nearCenter;
55805
55806         requests.forEach(function(d) {
55807             var c = tileCenter(d);
55808             var dist = geoEuclideanDistance(c, mapCenter);
55809             if (dist < minDist) {
55810                 minDist = dist;
55811                 nearCenter = d;
55812             }
55813         });
55814
55815
55816         var image = selection$$1.selectAll('img')
55817             .data(requests, function(d) { return d[3]; });
55818
55819         image.exit()
55820             .style(transformProp, imageTransform)
55821             .classed('tile-removing', true)
55822             .classed('tile-center', false)
55823             .each(function() {
55824                 var tile = select(this);
55825                 window.setTimeout(function() {
55826                     if (tile.classed('tile-removing')) {
55827                         tile.remove();
55828                     }
55829                 }, 300);
55830             });
55831
55832         image.enter()
55833           .append('img')
55834             .attr('class', 'tile')
55835             .attr('src', function(d) { return d[3]; })
55836             .on('error', error)
55837             .on('load', load)
55838           .merge(image)
55839             .style(transformProp, imageTransform)
55840             .classed('tile-debug', showDebug)
55841             .classed('tile-removing', false)
55842             .classed('tile-center', function(d) { return d === nearCenter; });
55843
55844
55845
55846         var debug = selection$$1.selectAll('.tile-label-debug')
55847             .data(showDebug ? requests : [], function(d) { return d[3]; });
55848
55849         debug.exit()
55850             .remove();
55851
55852         if (showDebug) {
55853             var debugEnter = debug.enter()
55854                 .append('div')
55855                 .attr('class', 'tile-label-debug');
55856
55857             debugEnter
55858                 .append('div')
55859                 .attr('class', 'tile-label-debug-coord');
55860
55861             debugEnter
55862                 .append('div')
55863                 .attr('class', 'tile-label-debug-vintage');
55864
55865             debug = debug.merge(debugEnter);
55866
55867             debug
55868                 .style(transformProp, debugTransform);
55869
55870             debug
55871                 .selectAll('.tile-label-debug-coord')
55872                 .text(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; });
55873
55874             debug
55875                 .selectAll('.tile-label-debug-vintage')
55876                 .each(function(d) {
55877                     var span = select(this);
55878                     var center = context.projection.invert(tileCenter(d));
55879                     source.getVintage(center, d, function(err, result) {
55880                         span.text((result && result.range) ||
55881                             t('info_panels.background.vintage') + ': ' + t('info_panels.background.unknown')
55882                         );
55883                     });
55884                 });
55885         }
55886
55887     }
55888
55889
55890     background.projection = function(_) {
55891         if (!arguments.length) return projection$$1;
55892         projection$$1 = _;
55893         return background;
55894     };
55895
55896
55897     background.dimensions = function(_) {
55898         if (!arguments.length) return tile.size();
55899         tile.size(_);
55900         return background;
55901     };
55902
55903
55904     background.source = function(_) {
55905         if (!arguments.length) return source;
55906         source = _;
55907         cache = {};
55908         tile.scaleExtent(source.scaleExtent);
55909         return background;
55910     };
55911
55912
55913     return background;
55914 }
55915
55916 function rendererBackground(context) {
55917     var dispatch$$1 = dispatch('change'),
55918         baseLayer = rendererTileLayer(context).projection(context.projection),
55919         overlayLayers = [],
55920         backgroundSources;
55921
55922
55923     function findSource(id) {
55924         return lodash.find(backgroundSources, function(d) {
55925             return d.id && d.id === id;
55926         });
55927     }
55928
55929
55930     function background(selection$$1) {
55931         var base = selection$$1.selectAll('.layer-background')
55932             .data([0]);
55933
55934         base.enter()
55935             .insert('div', '.layer-data')
55936             .attr('class', 'layer layer-background')
55937             .merge(base)
55938             .call(baseLayer);
55939
55940         var overlays = selection$$1.selectAll('.layer-overlay')
55941             .data(overlayLayers, function(d) { return d.source().name(); });
55942
55943         overlays.exit()
55944             .remove();
55945
55946         overlays.enter()
55947             .insert('div', '.layer-data')
55948             .attr('class', 'layer layer-overlay')
55949             .merge(overlays)
55950             .each(function(layer) { select(this).call(layer); });
55951     }
55952
55953
55954     background.updateImagery = function() {
55955         if (context.inIntro()) return;
55956
55957         var b = background.baseLayerSource(),
55958             o = overlayLayers
55959                 .filter(function (d) { return !d.source().isLocatorOverlay(); })
55960                 .map(function (d) { return d.source().id; })
55961                 .join(','),
55962             meters = geoOffsetToMeters(b.offset()),
55963             epsilon = 0.01,
55964             x = +meters[0].toFixed(2),
55965             y = +meters[1].toFixed(2),
55966             q = utilStringQs(window.location.hash.substring(1));
55967
55968         var id = b.id;
55969         if (id === 'custom') {
55970             id = 'custom:' + b.template();
55971         }
55972
55973         if (id) {
55974             q.background = id;
55975         } else {
55976             delete q.background;
55977         }
55978
55979         if (o) {
55980             q.overlays = o;
55981         } else {
55982             delete q.overlays;
55983         }
55984
55985         if (Math.abs(x) > epsilon || Math.abs(y) > epsilon) {
55986             q.offset = x + ',' + y;
55987         } else {
55988             delete q.offset;
55989         }
55990
55991         window.location.replace('#' + utilQsString(q, true));
55992
55993         var imageryUsed = [b.imageryUsed()];
55994
55995         overlayLayers
55996             .filter(function (d) { return !d.source().isLocatorOverlay(); })
55997             .forEach(function (d) { imageryUsed.push(d.source().imageryUsed()); });
55998
55999         var gpx = context.layers().layer('gpx');
56000         if (gpx && gpx.enabled() && gpx.hasGpx()) {
56001             imageryUsed.push('Local GPX');
56002         }
56003
56004         var mapillary_images = context.layers().layer('mapillary-images');
56005         if (mapillary_images && mapillary_images.enabled()) {
56006             imageryUsed.push('Mapillary Images');
56007         }
56008
56009         var mapillary_signs = context.layers().layer('mapillary-signs');
56010         if (mapillary_signs && mapillary_signs.enabled()) {
56011             imageryUsed.push('Mapillary Signs');
56012         }
56013
56014         context.history().imageryUsed(imageryUsed);
56015     };
56016
56017
56018     background.sources = function(extent$$1) {
56019         return backgroundSources.filter(function(source) {
56020             return source.intersects(extent$$1);
56021         });
56022     };
56023
56024
56025     background.dimensions = function(_) {
56026         if (!_) return;
56027         baseLayer.dimensions(_);
56028
56029         overlayLayers.forEach(function(layer) {
56030             layer.dimensions(_);
56031         });
56032     };
56033
56034
56035     background.baseLayerSource = function(d) {
56036         if (!arguments.length) return baseLayer.source();
56037
56038         // test source against OSM imagery blacklists..
56039         var blacklists = context.connection().imageryBlacklists();
56040
56041         var template = d.template(),
56042             fail = false,
56043             tested = 0,
56044             regex, i;
56045
56046         for (i = 0; i < blacklists.length; i++) {
56047             try {
56048                 regex = new RegExp(blacklists[i]);
56049                 fail = regex.test(template);
56050                 tested++;
56051                 if (fail) break;
56052             } catch (e) {
56053                 /* noop */
56054             }
56055         }
56056
56057         // ensure at least one test was run.
56058         if (!tested) {
56059             regex = new RegExp('.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*');
56060             fail = regex.test(template);
56061         }
56062
56063         baseLayer.source(!fail ? d : rendererBackgroundSource.None());
56064         dispatch$$1.call('change');
56065         background.updateImagery();
56066         return background;
56067     };
56068
56069
56070     background.bing = function() {
56071         background.baseLayerSource(findSource('Bing'));
56072     };
56073
56074
56075     background.showsLayer = function(d) {
56076         return d.id === baseLayer.source().id ||
56077             overlayLayers.some(function(layer) { return d.id === layer.source().id; });
56078     };
56079
56080
56081     background.overlayLayerSources = function() {
56082         return overlayLayers.map(function (l) { return l.source(); });
56083     };
56084
56085
56086     background.toggleOverlayLayer = function(d) {
56087         var layer;
56088
56089         for (var i = 0; i < overlayLayers.length; i++) {
56090             layer = overlayLayers[i];
56091             if (layer.source() === d) {
56092                 overlayLayers.splice(i, 1);
56093                 dispatch$$1.call('change');
56094                 background.updateImagery();
56095                 return;
56096             }
56097         }
56098
56099         layer = rendererTileLayer(context)
56100             .source(d)
56101             .projection(context.projection)
56102             .dimensions(baseLayer.dimensions());
56103
56104         overlayLayers.push(layer);
56105         dispatch$$1.call('change');
56106         background.updateImagery();
56107     };
56108
56109
56110     background.nudge = function(d, zoom$$1) {
56111         baseLayer.source().nudge(d, zoom$$1);
56112         dispatch$$1.call('change');
56113         background.updateImagery();
56114         return background;
56115     };
56116
56117
56118     background.offset = function(d) {
56119         if (!arguments.length) return baseLayer.source().offset();
56120         baseLayer.source().offset(d);
56121         dispatch$$1.call('change');
56122         background.updateImagery();
56123         return background;
56124     };
56125
56126
56127     background.init = function() {
56128         function parseMap(qmap) {
56129             if (!qmap) return false;
56130             var args = qmap.split('/').map(Number);
56131             if (args.length < 3 || args.some(isNaN)) return false;
56132             return geoExtent$$1([args[2], args[1]]);
56133         }
56134
56135         var dataImagery = data.imagery || [],
56136             q = utilStringQs(window.location.hash.substring(1)),
56137             chosen = q.background || q.layer,
56138             extent$$1 = parseMap(q.map),
56139             best;
56140
56141         backgroundSources = dataImagery.map(function(source) {
56142             if (source.type === 'bing') {
56143                 return rendererBackgroundSource.Bing(source, dispatch$$1);
56144             } else {
56145                 return rendererBackgroundSource(source);
56146             }
56147         });
56148
56149         backgroundSources.unshift(rendererBackgroundSource.None());
56150
56151         if (!chosen && extent$$1) {
56152             best = lodash.find(this.sources(extent$$1), function(s) { return s.best(); });
56153         }
56154
56155         if (chosen && chosen.indexOf('custom:') === 0) {
56156             background.baseLayerSource(rendererBackgroundSource.Custom(chosen.replace(/^custom:/, '')));
56157         } else {
56158             background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
56159         }
56160
56161         var locator = lodash.find(backgroundSources, function(d) {
56162             return d.overlay && d.default;
56163         });
56164
56165         if (locator) {
56166             background.toggleOverlayLayer(locator);
56167         }
56168
56169         var overlays = (q.overlays || '').split(',');
56170         overlays.forEach(function(overlay) {
56171             overlay = findSource(overlay);
56172             if (overlay) {
56173                 background.toggleOverlayLayer(overlay);
56174             }
56175         });
56176
56177         if (q.gpx) {
56178             var gpx = context.layers().layer('gpx');
56179             if (gpx) {
56180                 gpx.url(q.gpx);
56181             }
56182         }
56183
56184         if (q.offset) {
56185             var offset = q.offset.replace(/;/g, ',').split(',').map(function(n) {
56186                 return !isNaN(n) && n;
56187             });
56188
56189             if (offset.length === 2) {
56190                 background.offset(geoMetersToOffset(offset));
56191             }
56192         }
56193     };
56194
56195
56196     return utilRebind(background, dispatch$$1, 'on');
56197 }
56198
56199 function rendererFeatures(context) {
56200     var traffic_roads = {
56201         'motorway': true,
56202         'motorway_link': true,
56203         'trunk': true,
56204         'trunk_link': true,
56205         'primary': true,
56206         'primary_link': true,
56207         'secondary': true,
56208         'secondary_link': true,
56209         'tertiary': true,
56210         'tertiary_link': true,
56211         'residential': true,
56212         'unclassified': true,
56213         'living_street': true
56214     };
56215
56216     var service_roads = {
56217         'service': true,
56218         'road': true,
56219         'track': true
56220     };
56221
56222     var paths = {
56223         'path': true,
56224         'footway': true,
56225         'cycleway': true,
56226         'bridleway': true,
56227         'steps': true,
56228         'pedestrian': true,
56229         'corridor': true
56230     };
56231
56232     var past_futures = {
56233         'proposed': true,
56234         'construction': true,
56235         'abandoned': true,
56236         'dismantled': true,
56237         'disused': true,
56238         'razed': true,
56239         'demolished': true,
56240         'obliterated': true
56241     };
56242
56243     var dispatch$$1 = dispatch('change', 'redraw'),
56244         _cullFactor = 1,
56245         _cache = {},
56246         _features = {},
56247         _stats = {},
56248         _keys = [],
56249         _hidden = [];
56250
56251
56252     function update() {
56253         _hidden = features.hidden();
56254         dispatch$$1.call('change');
56255         dispatch$$1.call('redraw');
56256     }
56257
56258
56259     function defineFeature(k, filter, max$$1) {
56260         _keys.push(k);
56261         _features[k] = {
56262             filter: filter,
56263             enabled: true,   // whether the user wants it enabled..
56264             count: 0,
56265             currentMax: (max$$1 || Infinity),
56266             defaultMax: (max$$1 || Infinity),
56267             enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
56268             disable: function() { this.enabled = false; this.currentMax = 0; },
56269             hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
56270             autoHidden: function() { return this.hidden() && this.currentMax > 0; }
56271         };
56272     }
56273
56274
56275     defineFeature('points', function isPoint(entity, resolver, geometry) {
56276         return geometry === 'point';
56277     }, 200);
56278
56279     defineFeature('traffic_roads', function isTrafficRoad(entity) {
56280         return traffic_roads[entity.tags.highway];
56281     });
56282
56283     defineFeature('service_roads', function isServiceRoad(entity) {
56284         return service_roads[entity.tags.highway];
56285     });
56286
56287     defineFeature('paths', function isPath(entity) {
56288         return paths[entity.tags.highway];
56289     });
56290
56291     defineFeature('buildings', function isBuilding(entity) {
56292         return (
56293             !!entity.tags['building:part'] ||
56294             (!!entity.tags.building && entity.tags.building !== 'no') ||
56295             entity.tags.amenity === 'shelter' ||
56296             entity.tags.parking === 'multi-storey' ||
56297             entity.tags.parking === 'sheds' ||
56298             entity.tags.parking === 'carports' ||
56299             entity.tags.parking === 'garage_boxes'
56300         );
56301     }, 250);
56302
56303     defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
56304         return geometry === 'area' &&
56305             !_features.buildings.filter(entity) &&
56306             !_features.water.filter(entity);
56307     });
56308
56309     defineFeature('boundaries', function isBoundary(entity) {
56310         return !!entity.tags.boundary;
56311     });
56312
56313     defineFeature('water', function isWater(entity) {
56314         return (
56315             !!entity.tags.waterway ||
56316             entity.tags.natural === 'water' ||
56317             entity.tags.natural === 'coastline' ||
56318             entity.tags.natural === 'bay' ||
56319             entity.tags.landuse === 'pond' ||
56320             entity.tags.landuse === 'basin' ||
56321             entity.tags.landuse === 'reservoir' ||
56322             entity.tags.landuse === 'salt_pond'
56323         );
56324     });
56325
56326     defineFeature('rail', function isRail(entity) {
56327         return (
56328             !!entity.tags.railway ||
56329             entity.tags.landuse === 'railway'
56330         ) && !(
56331             traffic_roads[entity.tags.highway] ||
56332             service_roads[entity.tags.highway] ||
56333             paths[entity.tags.highway]
56334         );
56335     });
56336
56337     defineFeature('power', function isPower(entity) {
56338         return !!entity.tags.power;
56339     });
56340
56341     // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
56342     defineFeature('past_future', function isPastFuture(entity) {
56343         if (
56344             traffic_roads[entity.tags.highway] ||
56345             service_roads[entity.tags.highway] ||
56346             paths[entity.tags.highway]
56347         ) { return false; }
56348
56349         var strings = Object.keys(entity.tags);
56350
56351         for (var i = 0; i < strings.length; i++) {
56352             var s = strings[i];
56353             if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
56354         }
56355         return false;
56356     });
56357
56358     // Lines or areas that don't match another feature filter.
56359     // IMPORTANT: The 'others' feature must be the last one defined,
56360     //   so that code in getMatches can skip this test if `hasMatch = true`
56361     defineFeature('others', function isOther(entity, resolver, geometry) {
56362         return (geometry === 'line' || geometry === 'area');
56363     });
56364
56365
56366     function features() {}
56367
56368
56369     features.features = function() {
56370         return _features;
56371     };
56372
56373
56374     features.keys = function() {
56375         return _keys;
56376     };
56377
56378
56379     features.enabled = function(k) {
56380         if (!arguments.length) {
56381             return _keys.filter(function(k) { return _features[k].enabled; });
56382         }
56383         return _features[k] && _features[k].enabled;
56384     };
56385
56386
56387     features.disabled = function(k) {
56388         if (!arguments.length) {
56389             return _keys.filter(function(k) { return !_features[k].enabled; });
56390         }
56391         return _features[k] && !_features[k].enabled;
56392     };
56393
56394
56395     features.hidden = function(k) {
56396         if (!arguments.length) {
56397             return _keys.filter(function(k) { return _features[k].hidden(); });
56398         }
56399         return _features[k] && _features[k].hidden();
56400     };
56401
56402
56403     features.autoHidden = function(k) {
56404         if (!arguments.length) {
56405             return _keys.filter(function(k) { return _features[k].autoHidden(); });
56406         }
56407         return _features[k] && _features[k].autoHidden();
56408     };
56409
56410
56411     features.enable = function(k) {
56412         if (_features[k] && !_features[k].enabled) {
56413             _features[k].enable();
56414             update();
56415         }
56416     };
56417
56418
56419     features.disable = function(k) {
56420         if (_features[k] && _features[k].enabled) {
56421             _features[k].disable();
56422             update();
56423         }
56424     };
56425
56426
56427     features.toggle = function(k) {
56428         if (_features[k]) {
56429             (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
56430             update();
56431         }
56432     };
56433
56434
56435     features.resetStats = function() {
56436         for (var i = 0; i < _keys.length; i++) {
56437             _features[_keys[i]].count = 0;
56438         }
56439         dispatch$$1.call('change');
56440     };
56441
56442
56443     features.gatherStats = function(d, resolver, dimensions) {
56444         var needsRedraw = false,
56445             type = lodash.groupBy(d, function(ent) { return ent.type; }),
56446             entities = [].concat(type.relation || [], type.way || [], type.node || []),
56447             currHidden, geometry, matches, i, j;
56448
56449         for (i = 0; i < _keys.length; i++) {
56450             _features[_keys[i]].count = 0;
56451         }
56452
56453         // adjust the threshold for point/building culling based on viewport size..
56454         // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
56455         _cullFactor = dimensions[0] * dimensions[1] / 1000000;
56456
56457         for (i = 0; i < entities.length; i++) {
56458             geometry = entities[i].geometry(resolver);
56459             if (!(geometry === 'vertex' || geometry === 'relation')) {
56460                 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
56461                 for (j = 0; j < matches.length; j++) {
56462                     _features[matches[j]].count++;
56463                 }
56464             }
56465         }
56466
56467         currHidden = features.hidden();
56468         if (currHidden !== _hidden) {
56469             _hidden = currHidden;
56470             needsRedraw = true;
56471             dispatch$$1.call('change');
56472         }
56473
56474         return needsRedraw;
56475     };
56476
56477
56478     features.stats = function() {
56479         for (var i = 0; i < _keys.length; i++) {
56480             _stats[_keys[i]] = _features[_keys[i]].count;
56481         }
56482
56483         return _stats;
56484     };
56485
56486
56487     features.clear = function(d) {
56488         for (var i = 0; i < d.length; i++) {
56489             features.clearEntity(d[i]);
56490         }
56491     };
56492
56493
56494     features.clearEntity = function(entity) {
56495         delete _cache[osmEntity$$1.key(entity)];
56496     };
56497
56498
56499     features.reset = function() {
56500         _cache = {};
56501     };
56502
56503
56504     features.getMatches = function(entity, resolver, geometry) {
56505         if (geometry === 'vertex' || geometry === 'relation') return {};
56506
56507         var ent = osmEntity$$1.key(entity);
56508         if (!_cache[ent]) {
56509             _cache[ent] = {};
56510         }
56511
56512         if (!_cache[ent].matches) {
56513             var matches = {},
56514                 hasMatch = false;
56515
56516             for (var i = 0; i < _keys.length; i++) {
56517                 if (_keys[i] === 'others') {
56518                     if (hasMatch) continue;
56519
56520                     // Multipolygon members:
56521                     // If an entity...
56522                     //   1. is a way that hasn't matched other 'interesting' feature rules,
56523                     //   2. and it belongs to a single parent multipolygon relation
56524                     // ...then match whatever feature rules the parent multipolygon has matched.
56525                     // see #2548, #2887
56526                     //
56527                     // IMPORTANT:
56528                     // For this to work, getMatches must be called on relations before ways.
56529                     //
56530                     if (entity.type === 'way') {
56531                         var parents = features.getParents(entity, resolver, geometry);
56532                         if (parents.length === 1 && parents[0].isMultipolygon()) {
56533                             var pkey = osmEntity$$1.key(parents[0]);
56534                             if (_cache[pkey] && _cache[pkey].matches) {
56535                                 matches = lodash.clone(_cache[pkey].matches);
56536                                 continue;
56537                             }
56538                         }
56539                     }
56540                 }
56541
56542                 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
56543                     matches[_keys[i]] = hasMatch = true;
56544                 }
56545             }
56546             _cache[ent].matches = matches;
56547         }
56548
56549         return _cache[ent].matches;
56550     };
56551
56552
56553     features.getParents = function(entity, resolver, geometry) {
56554         if (geometry === 'point') return [];
56555
56556         var ent = osmEntity$$1.key(entity);
56557         if (!_cache[ent]) {
56558             _cache[ent] = {};
56559         }
56560
56561         if (!_cache[ent].parents) {
56562             var parents = [];
56563             if (geometry === 'vertex') {
56564                 parents = resolver.parentWays(entity);
56565             } else {   // 'line', 'area', 'relation'
56566                 parents = resolver.parentRelations(entity);
56567             }
56568             _cache[ent].parents = parents;
56569         }
56570         return _cache[ent].parents;
56571     };
56572
56573
56574     features.isHiddenFeature = function(entity, resolver, geometry) {
56575         if (!_hidden.length) return false;
56576         if (!entity.version) return false;
56577
56578         var matches = features.getMatches(entity, resolver, geometry);
56579
56580         for (var i = 0; i < _hidden.length; i++) {
56581             if (matches[_hidden[i]]) return true;
56582         }
56583         return false;
56584     };
56585
56586
56587     features.isHiddenChild = function(entity, resolver, geometry) {
56588         if (!_hidden.length) return false;
56589         if (!entity.version || geometry === 'point') return false;
56590
56591         var parents = features.getParents(entity, resolver, geometry);
56592         if (!parents.length) return false;
56593
56594         for (var i = 0; i < parents.length; i++) {
56595             if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
56596                 return false;
56597             }
56598         }
56599         return true;
56600     };
56601
56602
56603     features.hasHiddenConnections = function(entity, resolver) {
56604         if (!_hidden.length) return false;
56605         var childNodes, connections;
56606
56607         if (entity.type === 'midpoint') {
56608             childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
56609             connections = [];
56610         } else {
56611             childNodes = entity.nodes ? resolver.childNodes(entity) : [];
56612             connections = features.getParents(entity, resolver, entity.geometry(resolver));
56613         }
56614
56615         // gather ways connected to child nodes..
56616         connections = lodash.reduce(childNodes, function(result, e) {
56617             return resolver.isShared(e) ? lodash.union(result, resolver.parentWays(e)) : result;
56618         }, connections);
56619
56620         return connections.length ? lodash.some(connections, function(e) {
56621             return features.isHidden(e, resolver, e.geometry(resolver));
56622         }) : false;
56623     };
56624
56625
56626     features.isHidden = function(entity, resolver, geometry) {
56627         if (!_hidden.length) return false;
56628         if (!entity.version) return false;
56629
56630         var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
56631         return fn(entity, resolver, geometry);
56632     };
56633
56634
56635     features.filter = function(d, resolver) {
56636         if (!_hidden.length) return d;
56637
56638         var result = [];
56639         for (var i = 0; i < d.length; i++) {
56640             var entity = d[i];
56641             if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
56642                 result.push(entity);
56643             }
56644         }
56645         return result;
56646     };
56647
56648
56649     return utilRebind(features, dispatch$$1, 'on');
56650 }
56651
56652 function utilBindOnce(target, type, listener, capture) {
56653     var typeOnce = type + '.once';
56654     function one() {
56655         target.on(typeOnce, null);
56656         listener.apply(this, arguments);
56657     }
56658     target.on(typeOnce, one, capture);
56659     return this;
56660 }
56661
56662 function rendererMap(context) {
56663
56664     var dimensions = [1, 1],
56665         dispatch$$1 = dispatch('move', 'drawn'),
56666         projection$$1 = context.projection,
56667         curtainProjection = context.curtainProjection,
56668         dblclickEnabled = true,
56669         redrawEnabled = true,
56670         transformStart = projection$$1.transform(),
56671         transformLast,
56672         transformed = false,
56673         minzoom = 0,
56674         drawLayers = svgLayers(projection$$1, context),
56675         drawPoints = svgPoints$$1(projection$$1, context),
56676         drawVertices = svgVertices$$1(projection$$1, context),
56677         drawLines = svgLines$$1(projection$$1, context),
56678         drawAreas = svgAreas$$1(projection$$1, context),
56679         drawMidpoints = svgMidpoints$$1(projection$$1, context),
56680         drawLabels = svgLabels(projection$$1, context),
56681         supersurface = select(null),
56682         wrapper = select(null),
56683         surface = select(null),
56684         mouse$$1,
56685         mousemove;
56686
56687     var zoom$$1 = zoom()
56688             .scaleExtent([ztok(2), ztok(24)])
56689             .interpolate(interpolateValue)
56690             .filter(zoomEventFilter)
56691             .on('zoom', zoomPan);
56692
56693     var _selection = select(null);
56694
56695
56696     function map(selection$$1) {
56697
56698         _selection = selection$$1;
56699
56700         context
56701             .on('change.map', immediateRedraw);
56702
56703         context.connection()
56704             .on('change.map', immediateRedraw);
56705
56706         context.history()
56707             .on('change.map', immediateRedraw)
56708             .on('undone.map redone.map', function(stack$$1) {
56709                 var mode = context.mode().id;
56710                 if (mode !== 'browse' && mode !== 'select') return;
56711
56712                 var followSelected = false;
56713                 if (Array.isArray(stack$$1.selectedIDs)) {
56714                     followSelected = (stack$$1.selectedIDs.length === 1 && stack$$1.selectedIDs[0][0] === 'n');
56715                     context.enter(
56716                         modeSelect(context, stack$$1.selectedIDs).follow(followSelected)
56717                     );
56718                 }
56719                 if (!followSelected && stack$$1.transform) {
56720                     map.transformEase(stack$$1.transform);
56721                 }
56722             });
56723
56724         context.background()
56725             .on('change.map', immediateRedraw);
56726
56727         context.features()
56728             .on('redraw.map', immediateRedraw);
56729
56730         drawLayers
56731             .on('change.map', function() {
56732                 context.background().updateImagery();
56733                 immediateRedraw();
56734             });
56735
56736         selection$$1
56737             .on('dblclick.map', dblClick)
56738             .call(zoom$$1)
56739             .call(zoom$$1.transform, projection$$1.transform());
56740
56741         supersurface = selection$$1.append('div')
56742             .attr('id', 'supersurface')
56743             .call(utilSetTransform, 0, 0);
56744
56745         // Need a wrapper div because Opera can't cope with an absolutely positioned
56746         // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
56747         wrapper = supersurface
56748             .append('div')
56749             .attr('class', 'layer layer-data');
56750
56751         map.surface = surface = wrapper
56752             .call(drawLayers)
56753             .selectAll('.surface')
56754             .attr('id', 'surface');
56755
56756         surface
56757             .call(drawLabels.observe)
56758             .on('mousedown.zoom', function() {
56759                 if (event.button === 2) {
56760                     event.stopPropagation();
56761                 }
56762             }, true)
56763             .on('mouseup.zoom', function() {
56764                 if (resetTransform()) immediateRedraw();
56765             })
56766             .on('mousemove.map', function() {
56767                 mousemove = event;
56768             })
56769             .on('mouseover.vertices', function() {
56770                 if (map.editable() && !transformed) {
56771                     var hover = event.target.__data__;
56772                     surface.selectAll('.data-layer-osm')
56773                         .call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
56774                     dispatch$$1.call('drawn', this, {full: false});
56775                 }
56776             })
56777             .on('mouseout.vertices', function() {
56778                 if (map.editable() && !transformed) {
56779                     var hover = event.relatedTarget && event.relatedTarget.__data__;
56780                     surface.selectAll('.data-layer-osm')
56781                         .call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
56782                     dispatch$$1.call('drawn', this, {full: false});
56783                 }
56784             });
56785
56786         supersurface
56787             .call(context.background());
56788
56789         context.on('enter.map', function() {
56790             if (map.editable() && !transformed) {
56791                 var all = context.intersects(map.extent()),
56792                     filter = utilFunctor(true),
56793                     graph = context.graph();
56794
56795                 all = context.features().filter(all, graph);
56796                 surface.selectAll('.data-layer-osm')
56797                     .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
56798                     .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
56799                 dispatch$$1.call('drawn', this, {full: false});
56800             }
56801         });
56802
56803         map.dimensions(utilGetDimensions(selection$$1));
56804     }
56805
56806
56807     function zoomEventFilter() {
56808         // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
56809         // Intercept `mousedown` and check if there is an orphaned zoom gesture.
56810         // This can happen if a previous `mousedown` occurred without a `mouseup`.
56811         // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
56812         // so that d3-zoom won't stop propagation of new `mousedown` events.
56813         if (event.type === 'mousedown') {
56814             var hasOrphan = false;
56815             var listeners = window.__on;
56816             for (var i = 0; i < listeners.length; i++) {
56817                 var listener = listeners[i];
56818                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
56819                     hasOrphan = true;
56820                     break;
56821                 }
56822             }
56823             if (hasOrphan) {
56824                 var event$$1 = window.CustomEvent;
56825                 if (event$$1) {
56826                     event$$1 = new event$$1('mouseup');
56827                 } else {
56828                     event$$1 = window.document.createEvent('Event');
56829                     event$$1.initEvent('mouseup', false, false);
56830                 }
56831                 // Event needs to be dispatched with an event.view property.
56832                 event$$1.view = window;
56833                 window.dispatchEvent(event$$1);
56834             }
56835         }
56836
56837         return event.button !== 2;   // ignore right clicks
56838     }
56839
56840
56841     function ztok(z) {
56842         return 256 * Math.pow(2, z);
56843     }
56844
56845     function ktoz(k) {
56846         return Math.max(Math.log(k) / Math.LN2 - 8, 0);
56847     }
56848
56849     function pxCenter() {
56850         return [dimensions[0] / 2, dimensions[1] / 2];
56851     }
56852
56853
56854     function drawVector(difference, extent$$1) {
56855         var graph = context.graph(),
56856             features = context.features(),
56857             all = context.intersects(map.extent()),
56858             data, filter;
56859
56860         if (difference) {
56861             var complete = difference.complete(map.extent());
56862             data = lodash.compact(lodash.values(complete));
56863             filter = function(d) { return d.id in complete; };
56864             features.clear(data);
56865
56866         } else {
56867             // force a full redraw if gatherStats detects that a feature
56868             // should be auto-hidden (e.g. points or buildings)..
56869             if (features.gatherStats(all, graph, dimensions)) {
56870                 extent$$1 = undefined;
56871             }
56872
56873             if (extent$$1) {
56874                 data = context.intersects(map.extent().intersection(extent$$1));
56875                 var set = set$2(lodash.map(data, 'id'));
56876                 filter = function(d) { return set.has(d.id); };
56877
56878             } else {
56879                 data = all;
56880                 filter = utilFunctor(true);
56881             }
56882         }
56883
56884         data = features.filter(data, graph);
56885
56886         surface.selectAll('.data-layer-osm')
56887             .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
56888             .call(drawLines, graph, data, filter)
56889             .call(drawAreas, graph, data, filter)
56890             .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
56891             .call(drawLabels, graph, data, filter, dimensions, !difference && !extent$$1)
56892             .call(drawPoints, graph, data, filter);
56893
56894         dispatch$$1.call('drawn', this, {full: true});
56895     }
56896
56897
56898     function editOff() {
56899         context.features().resetStats();
56900         surface.selectAll('.layer-osm *').remove();
56901         dispatch$$1.call('drawn', this, {full: true});
56902     }
56903
56904
56905     function dblClick() {
56906         if (!dblclickEnabled) {
56907             event.preventDefault();
56908             event.stopImmediatePropagation();
56909         }
56910     }
56911
56912
56913     function zoomPan(manualEvent) {
56914         var event$$1 = (manualEvent || event),
56915             source = event$$1.sourceEvent,
56916             eventTransform = event$$1.transform;
56917
56918         if (transformStart.x === eventTransform.x &&
56919             transformStart.y === eventTransform.y &&
56920             transformStart.k === eventTransform.k) {
56921             return;  // no change
56922         }
56923
56924         // Normalize mousewheel - #3029
56925         // If wheel delta is provided in LINE units, recalculate it in PIXEL units
56926         // We are essentially redoing the calculations that occur here:
56927         //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
56928         // See this for more info:
56929         //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
56930         if (source && source.type === 'wheel' && source.deltaMode === 1 /* LINE */) {
56931             // pick sensible scroll amount if user scrolling fast or slow..
56932             var lines = Math.abs(source.deltaY),
56933                 scroll = lines > 2 ? 40 : lines * 10;
56934
56935             var t0 = transformed ? transformLast : transformStart,
56936                 p0 = mouse$$1(source),
56937                 p1 = t0.invert(p0),
56938                 k2 = t0.k * Math.pow(2, -source.deltaY * scroll / 500),
56939                 x2 = p0[0] - p1[0] * k2,
56940                 y2 = p0[1] - p1[1] * k2;
56941
56942             eventTransform = identity$8.translate(x2,y2).scale(k2);
56943             _selection.node().__zoom = eventTransform;
56944         }
56945
56946         if (ktoz(eventTransform.k * 2 * Math.PI) < minzoom) {
56947             surface.interrupt();
56948             uiFlash().text(t('cannot_zoom'));
56949             setZoom(context.minEditableZoom(), true);
56950             queueRedraw();
56951             dispatch$$1.call('move', this, map);
56952             return;
56953         }
56954
56955         projection$$1.transform(eventTransform);
56956
56957         var scale = eventTransform.k / transformStart.k,
56958             tX = (eventTransform.x / scale - transformStart.x) * scale,
56959             tY = (eventTransform.y / scale - transformStart.y) * scale;
56960
56961         if (context.inIntro()) {
56962             curtainProjection.transform({
56963                 x: eventTransform.x - tX,
56964                 y: eventTransform.y - tY,
56965                 k: eventTransform.k
56966             });
56967         }
56968
56969         transformed = true;
56970         transformLast = eventTransform;
56971         utilSetTransform(supersurface, tX, tY, scale);
56972         queueRedraw();
56973
56974         dispatch$$1.call('move', this, map);
56975     }
56976
56977
56978     function resetTransform() {
56979         if (!transformed) return false;
56980
56981         // deprecation warning - Radial Menu to be removed in iD v3
56982         surface.selectAll('.edit-menu, .radial-menu').interrupt().remove();
56983         utilSetTransform(supersurface, 0, 0);
56984         transformed = false;
56985         if (context.inIntro()) {
56986             curtainProjection.transform(projection$$1.transform());
56987         }
56988         return true;
56989     }
56990
56991
56992     function redraw(difference, extent$$1) {
56993         if (surface.empty() || !redrawEnabled) return;
56994
56995         // If we are in the middle of a zoom/pan, we can't do differenced redraws.
56996         // It would result in artifacts where differenced entities are redrawn with
56997         // one transform and unchanged entities with another.
56998         if (resetTransform()) {
56999             difference = extent$$1 = undefined;
57000         }
57001
57002         var z = String(~~map.zoom());
57003         if (surface.attr('data-zoom') !== z) {
57004             surface.attr('data-zoom', z)
57005                 .classed('low-zoom', z <= 16);
57006         }
57007
57008         if (!difference) {
57009             supersurface.call(context.background());
57010         }
57011
57012         wrapper
57013             .call(drawLayers);
57014
57015         // OSM
57016         if (map.editable()) {
57017             context.loadTiles(projection$$1, dimensions);
57018             drawVector(difference, extent$$1);
57019         } else {
57020             editOff();
57021         }
57022
57023         transformStart = projection$$1.transform();
57024
57025         return map;
57026     }
57027
57028
57029     var queueRedraw = lodash.throttle(redraw, 750);
57030
57031
57032     var immediateRedraw = function(difference, extent$$1) {
57033         if (!difference && !extent$$1) queueRedraw.cancel();
57034         redraw(difference, extent$$1);
57035     };
57036
57037
57038     function pointLocation(p) {
57039         var translate = projection$$1.translate(),
57040             scale = projection$$1.scale() * 2 * Math.PI;
57041         return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
57042     }
57043
57044
57045     function locationPoint(l) {
57046         var translate = projection$$1.translate(),
57047             scale = projection$$1.scale() * 2 * Math.PI;
57048         return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
57049     }
57050
57051
57052     map.mouse = function() {
57053         var event$$1 = mousemove || event;
57054         if (event$$1) {
57055             var s;
57056             while ((s = event$$1.sourceEvent)) { event$$1 = s; }
57057             return mouse$$1(event$$1);
57058         }
57059         return null;
57060     };
57061
57062
57063     map.mouseCoordinates = function() {
57064         return projection$$1.invert(map.mouse());
57065     };
57066
57067
57068     map.dblclickEnable = function(_) {
57069         if (!arguments.length) return dblclickEnabled;
57070         dblclickEnabled = _;
57071         return map;
57072     };
57073
57074
57075     map.redrawEnable = function(_) {
57076         if (!arguments.length) return redrawEnabled;
57077         redrawEnabled = _;
57078         return map;
57079     };
57080
57081
57082     function setTransform(t2, duration, force) {
57083         var t$$1 = projection$$1.transform();
57084         if (!force && t2.k === t$$1.k && t2.x === t$$1.x && t2.y === t$$1.y) {
57085             return false;
57086         }
57087
57088         if (duration) {
57089             _selection
57090                 .transition()
57091                 .duration(duration)
57092                 .on('start', function() { map.startEase(); })
57093                 .call(zoom$$1.transform, identity$8.translate(t2.x, t2.y).scale(t2.k));
57094         } else {
57095             projection$$1.transform(t2);
57096             transformStart = t2;
57097             _selection.call(zoom$$1.transform, transformStart);
57098         }
57099     }
57100
57101
57102     function setZoom(z2, force, duration) {
57103         if (z2 === map.zoom() && !force) {
57104             return false;
57105         }
57106
57107         var k = projection$$1.scale(),
57108             k2 = Math.max(ztok(2), Math.min(ztok(24), ztok(z2))) / (2 * Math.PI),
57109             center = pxCenter(),
57110             l = pointLocation(center);
57111
57112         projection$$1.scale(k2);
57113
57114         var t$$1 = projection$$1.translate();
57115         l = locationPoint(l);
57116
57117         t$$1[0] += center[0] - l[0];
57118         t$$1[1] += center[1] - l[1];
57119
57120         if (duration) {
57121             projection$$1.scale(k);  // reset scale
57122             _selection
57123                 .transition()
57124                 .duration(duration)
57125                 .on('start', function() { map.startEase(); })
57126                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k2));
57127         } else {
57128             projection$$1.translate(t$$1);
57129             transformStart = projection$$1.transform();
57130             _selection.call(zoom$$1.transform, transformStart);
57131         }
57132
57133         return true;
57134     }
57135
57136
57137     function setCenter(loc2, duration) {
57138         var c = map.center();
57139         if (loc2[0] === c[0] && loc2[1] === c[1]) {
57140             return false;
57141         }
57142
57143         var t$$1 = projection$$1.translate(),
57144             k = projection$$1.scale(),
57145             pxC = pxCenter(),
57146             ll = projection$$1(loc2);
57147
57148         t$$1[0] = t$$1[0] - ll[0] + pxC[0];
57149         t$$1[1] = t$$1[1] - ll[1] + pxC[1];
57150
57151         if (duration) {
57152             _selection
57153                 .transition()
57154                 .duration(duration)
57155                 .on('start', function() { map.startEase(); })
57156                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
57157         } else {
57158             projection$$1.translate(t$$1);
57159             transformStart = projection$$1.transform();
57160             _selection.call(zoom$$1.transform, transformStart);
57161         }
57162
57163         return true;
57164     }
57165
57166
57167     map.pan = function(delta, duration) {
57168         var t$$1 = projection$$1.translate(),
57169             k = projection$$1.scale();
57170
57171         t$$1[0] += delta[0];
57172         t$$1[1] += delta[1];
57173
57174         if (duration) {
57175             _selection
57176                 .transition()
57177                 .duration(duration)
57178                 .on('start', function() { map.startEase(); })
57179                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
57180         } else {
57181             projection$$1.translate(t$$1);
57182             transformStart = projection$$1.transform();
57183             _selection.call(zoom$$1.transform, transformStart);
57184             dispatch$$1.call('move', this, map);
57185             immediateRedraw();
57186         }
57187
57188         return map;
57189     };
57190
57191
57192     map.dimensions = function(_) {
57193         if (!arguments.length) return dimensions;
57194         var center = map.center();
57195         dimensions = _;
57196         drawLayers.dimensions(dimensions);
57197         context.background().dimensions(dimensions);
57198         projection$$1.clipExtent([[0, 0], dimensions]);
57199         mouse$$1 = utilFastMouse(supersurface.node());
57200         setCenter(center);
57201
57202         queueRedraw();
57203         return map;
57204     };
57205
57206
57207     function zoomIn(delta) {
57208         setZoom(~~map.zoom() + delta, true, 250);
57209     }
57210
57211     function zoomOut(delta) {
57212         setZoom(~~map.zoom() - delta, true, 250);
57213     }
57214
57215     map.zoomIn = function() { zoomIn(1); };
57216     map.zoomInFurther = function() { zoomIn(4); };
57217
57218     map.zoomOut = function() { zoomOut(1); };
57219     map.zoomOutFurther = function() { zoomOut(4); };
57220
57221
57222     map.center = function(loc2) {
57223         if (!arguments.length) {
57224             return projection$$1.invert(pxCenter());
57225         }
57226
57227         if (setCenter(loc2)) {
57228             dispatch$$1.call('move', this, map);
57229         }
57230
57231         queueRedraw();
57232         return map;
57233     };
57234
57235
57236     map.zoom = function(z2) {
57237         if (!arguments.length) {
57238             return Math.max(ktoz(projection$$1.scale() * 2 * Math.PI), 0);
57239         }
57240
57241         if (z2 < minzoom) {
57242             surface.interrupt();
57243             uiFlash().text(t('cannot_zoom'));
57244             z2 = context.minEditableZoom();
57245         }
57246
57247         if (setZoom(z2)) {
57248             dispatch$$1.call('move', this, map);
57249         }
57250
57251         queueRedraw();
57252         return map;
57253     };
57254
57255
57256     map.zoomTo = function(entity, zoomLimits) {
57257         var extent$$1 = entity.extent(context.graph());
57258         if (!isFinite(extent$$1.area())) return;
57259
57260         var z2 = map.trimmedExtentZoom(extent$$1);
57261         zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
57262         map.centerZoom(extent$$1.center(), Math.min(Math.max(z2, zoomLimits[0]), zoomLimits[1]));
57263     };
57264
57265
57266     map.centerZoom = function(loc2, z2) {
57267         var centered = setCenter(loc2),
57268             zoomed   = setZoom(z2);
57269
57270         if (centered || zoomed) {
57271             dispatch$$1.call('move', this, map);
57272         }
57273
57274         queueRedraw();
57275         return map;
57276     };
57277
57278
57279     map.centerEase = function(loc2, duration) {
57280         duration = duration || 250;
57281         setCenter(loc2, duration);
57282         return map;
57283     };
57284
57285
57286     map.zoomEase = function(z2, duration) {
57287         duration = duration || 250;
57288         setZoom(z2, false, duration);
57289         return map;
57290     };
57291
57292
57293     map.transformEase = function(t2, duration) {
57294         duration = duration || 250;
57295         setTransform(t2, duration, false);
57296         return map;
57297     };
57298
57299
57300     map.startEase = function() {
57301         utilBindOnce(surface, 'mousedown.ease', function() {
57302             map.cancelEase();
57303         });
57304         return map;
57305     };
57306
57307
57308     map.cancelEase = function() {
57309         _selection.interrupt();
57310         return map;
57311     };
57312
57313
57314     map.extent = function(_) {
57315         if (!arguments.length) {
57316             return new geoExtent$$1(projection$$1.invert([0, dimensions[1]]),
57317                                  projection$$1.invert([dimensions[0], 0]));
57318         } else {
57319             var extent$$1 = geoExtent$$1(_);
57320             map.centerZoom(extent$$1.center(), map.extentZoom(extent$$1));
57321         }
57322     };
57323
57324
57325     map.trimmedExtent = function(_) {
57326         if (!arguments.length) {
57327             var headerY = 60, footerY = 30, pad = 10;
57328             return new geoExtent$$1(projection$$1.invert([pad, dimensions[1] - footerY - pad]),
57329                                  projection$$1.invert([dimensions[0] - pad, headerY + pad]));
57330         } else {
57331             var extent$$1 = geoExtent$$1(_);
57332             map.centerZoom(extent$$1.center(), map.trimmedExtentZoom(extent$$1));
57333         }
57334     };
57335
57336
57337     function calcZoom(extent$$1, dim) {
57338         var tl = projection$$1([extent$$1[0][0], extent$$1[1][1]]),
57339             br = projection$$1([extent$$1[1][0], extent$$1[0][1]]);
57340
57341         // Calculate maximum zoom that fits extent
57342         var hFactor = (br[0] - tl[0]) / dim[0],
57343             vFactor = (br[1] - tl[1]) / dim[1],
57344             hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
57345             vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
57346             newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
57347
57348         return newZoom;
57349     }
57350
57351
57352     map.extentZoom = function(_) {
57353         return calcZoom(geoExtent$$1(_), dimensions);
57354     };
57355
57356
57357     map.trimmedExtentZoom = function(_) {
57358         var trimY = 120, trimX = 40,
57359             trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
57360         return calcZoom(geoExtent$$1(_), trimmed);
57361     };
57362
57363
57364     map.editable = function() {
57365         return map.zoom() >= context.minEditableZoom();
57366     };
57367
57368
57369     map.minzoom = function(_) {
57370         if (!arguments.length) return minzoom;
57371         minzoom = _;
57372         return map;
57373     };
57374
57375
57376     map.layers = drawLayers;
57377
57378
57379     return utilRebind(map, dispatch$$1, 'on');
57380 }
57381
57382 var TAU = 2 * Math.PI;
57383 function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
57384 function ktoz(k) { return Math.log(k * TAU) / Math.LN2 - 8; }
57385 function vecSub(a, b) { return [ a[0] - b[0], a[1] - b[1] ]; }
57386 function vecScale(a, b) { return [ a[0] * b, a[1] * b ]; }
57387
57388
57389 function uiMapInMap(context) {
57390
57391
57392     function map_in_map(selection$$1) {
57393         var backgroundLayer = rendererTileLayer(context),
57394             overlayLayers = {},
57395             projection$$1 = geoRawMercator(),
57396             gpxLayer = svgGpx(projection$$1, context).showLabels(false),
57397             debugLayer = svgDebug(projection$$1, context),
57398             zoom$$1 = zoom()
57399                 .scaleExtent([ztok(0.5), ztok(24)])
57400                 .on('start', zoomStarted)
57401                 .on('zoom', zoomed)
57402                 .on('end', zoomEnded),
57403             isTransformed = false,
57404             isHidden = true,
57405             skipEvents = false,
57406             gesture = null,
57407             zDiff = 6,    // by default, minimap renders at (main zoom - 6)
57408             wrap = select(null),
57409             tiles = select(null),
57410             viewport = select(null),
57411             tStart,  // transform at start of gesture
57412             tCurr,   // transform at most recent event
57413             timeoutId;
57414
57415
57416         function zoomStarted() {
57417             if (skipEvents) return;
57418             tStart = tCurr = projection$$1.transform();
57419             gesture = null;
57420         }
57421
57422
57423         function zoomed() {
57424             if (skipEvents) return;
57425
57426             var x = event.transform.x,
57427                 y = event.transform.y,
57428                 k = event.transform.k,
57429                 isZooming = (k !== tStart.k),
57430                 isPanning = (x !== tStart.x || y !== tStart.y);
57431
57432             if (!isZooming && !isPanning) {
57433                 return;  // no change
57434             }
57435
57436             // lock in either zooming or panning, don't allow both in minimap.
57437             if (!gesture) {
57438                 gesture = isZooming ? 'zoom' : 'pan';
57439             }
57440
57441             var tMini = projection$$1.transform(),
57442                 tX, tY, scale;
57443
57444             if (gesture === 'zoom') {
57445                 var dMini = utilGetDimensions(wrap),
57446                     cMini = vecScale(dMini, 0.5);
57447                 scale = k / tMini.k;
57448                 tX = (cMini[0] / scale - cMini[0]) * scale;
57449                 tY = (cMini[1] / scale - cMini[1]) * scale;
57450             } else {
57451                 k = tMini.k;
57452                 scale = 1;
57453                 tX = x - tMini.x;
57454                 tY = y - tMini.y;
57455             }
57456
57457             utilSetTransform(tiles, tX, tY, scale);
57458             utilSetTransform(viewport, 0, 0, scale);
57459             isTransformed = true;
57460             tCurr = identity$8.translate(x, y).scale(k);
57461
57462             var zMain = ktoz(context.projection.scale()),
57463                 zMini = ktoz(k);
57464
57465             zDiff = zMain - zMini;
57466
57467             queueRedraw();
57468         }
57469
57470
57471         function zoomEnded() {
57472             if (skipEvents) return;
57473             if (gesture !== 'pan') return;
57474
57475             updateProjection();
57476             gesture = null;
57477             var dMini = utilGetDimensions(wrap),
57478                 cMini = vecScale(dMini, 0.5);
57479             context.map().center(projection$$1.invert(cMini));   // recenter main map..
57480         }
57481
57482
57483         function updateProjection() {
57484             var loc = context.map().center(),
57485                 dMini = utilGetDimensions(wrap),
57486                 cMini = vecScale(dMini, 0.5),
57487                 tMain = context.projection.transform(),
57488                 zMain = ktoz(tMain.k),
57489                 zMini = Math.max(zMain - zDiff, 0.5),
57490                 kMini = ztok(zMini);
57491
57492             projection$$1
57493                 .translate([tMain.x, tMain.y])
57494                 .scale(kMini);
57495
57496             var point = projection$$1(loc),
57497                 mouse$$1 = (gesture === 'pan') ? vecSub([tCurr.x, tCurr.y], [tStart.x, tStart.y]) : [0, 0],
57498                 xMini = cMini[0] - point[0] + tMain.x + mouse$$1[0],
57499                 yMini = cMini[1] - point[1] + tMain.y + mouse$$1[1];
57500
57501             projection$$1
57502                 .translate([xMini, yMini])
57503                 .clipExtent([[0, 0], dMini]);
57504
57505             tCurr = projection$$1.transform();
57506
57507             if (isTransformed) {
57508                 utilSetTransform(tiles, 0, 0);
57509                 utilSetTransform(viewport, 0, 0);
57510                 isTransformed = false;
57511             }
57512
57513             zoom$$1
57514                 .scaleExtent([ztok(0.5), ztok(zMain - 3)]);
57515
57516             skipEvents = true;
57517             wrap.call(zoom$$1.transform, tCurr);
57518             skipEvents = false;
57519         }
57520
57521
57522         function redraw() {
57523             clearTimeout(timeoutId);
57524             if (isHidden) return;
57525
57526             updateProjection();
57527
57528             var dMini = utilGetDimensions(wrap),
57529                 zMini = ktoz(projection$$1.scale());
57530
57531             // setup tile container
57532             tiles = wrap
57533                 .selectAll('.map-in-map-tiles')
57534                 .data([0]);
57535
57536             tiles = tiles.enter()
57537                 .append('div')
57538                 .attr('class', 'map-in-map-tiles')
57539                 .merge(tiles);
57540
57541             // redraw background
57542             backgroundLayer
57543                 .source(context.background().baseLayerSource())
57544                 .projection(projection$$1)
57545                 .dimensions(dMini);
57546
57547             var background = tiles
57548                 .selectAll('.map-in-map-background')
57549                 .data([0]);
57550
57551             background.enter()
57552                 .append('div')
57553                 .attr('class', 'map-in-map-background')
57554                 .merge(background)
57555                 .call(backgroundLayer);
57556
57557
57558             // redraw overlay
57559             var overlaySources = context.background().overlayLayerSources();
57560             var activeOverlayLayers = [];
57561             for (var i = 0; i < overlaySources.length; i++) {
57562                 if (overlaySources[i].validZoom(zMini)) {
57563                     if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
57564                     activeOverlayLayers.push(overlayLayers[i]
57565                         .source(overlaySources[i])
57566                         .projection(projection$$1)
57567                         .dimensions(dMini));
57568                 }
57569             }
57570
57571             var overlay = tiles
57572                 .selectAll('.map-in-map-overlay')
57573                 .data([0]);
57574
57575             overlay = overlay.enter()
57576                 .append('div')
57577                 .attr('class', 'map-in-map-overlay')
57578                 .merge(overlay);
57579
57580
57581             var overlays = overlay
57582                 .selectAll('div')
57583                 .data(activeOverlayLayers, function(d) { return d.source().name(); });
57584
57585             overlays.exit()
57586                 .remove();
57587
57588             overlays = overlays.enter()
57589                 .append('div')
57590                 .merge(overlays)
57591                 .each(function(layer) { select(this).call(layer); });
57592
57593
57594             var dataLayers = tiles
57595                 .selectAll('.map-in-map-data')
57596                 .data([0]);
57597
57598             dataLayers.exit()
57599                 .remove();
57600
57601             dataLayers = dataLayers.enter()
57602                 .append('svg')
57603                 .attr('class', 'map-in-map-data')
57604                 .merge(dataLayers)
57605                 .call(gpxLayer)
57606                 .call(debugLayer);
57607
57608
57609             // redraw viewport bounding box
57610             if (gesture !== 'pan') {
57611                 var getPath = index$4(projection$$1),
57612                     bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
57613
57614                 viewport = wrap.selectAll('.map-in-map-viewport')
57615                     .data([0]);
57616
57617                 viewport = viewport.enter()
57618                     .append('svg')
57619                     .attr('class', 'map-in-map-viewport')
57620                     .merge(viewport);
57621
57622
57623                 var path$$1 = viewport.selectAll('.map-in-map-bbox')
57624                     .data([bbox]);
57625
57626                 path$$1.enter()
57627                     .append('path')
57628                     .attr('class', 'map-in-map-bbox')
57629                     .merge(path$$1)
57630                     .attr('d', getPath)
57631                     .classed('thick', function(d) { return getPath.area(d) < 30; });
57632             }
57633         }
57634
57635
57636         function queueRedraw() {
57637             clearTimeout(timeoutId);
57638             timeoutId = setTimeout(function() { redraw(); }, 750);
57639         }
57640
57641
57642         function toggle() {
57643             if (event) event.preventDefault();
57644
57645             isHidden = !isHidden;
57646
57647             var label = select('.minimap-toggle');
57648             label.classed('active', !isHidden)
57649                 .select('input').property('checked', !isHidden);
57650
57651             if (isHidden) {
57652                 wrap
57653                     .style('display', 'block')
57654                     .style('opacity', '1')
57655                     .transition()
57656                     .duration(200)
57657                     .style('opacity', '0')
57658                     .on('end', function() {
57659                         selection$$1.selectAll('.map-in-map')
57660                             .style('display', 'none');
57661                     });
57662             } else {
57663                 wrap
57664                     .style('display', 'block')
57665                     .style('opacity', '0')
57666                     .transition()
57667                     .duration(200)
57668                     .style('opacity', '1')
57669                     .on('end', function() {
57670                         redraw();
57671                     });
57672             }
57673         }
57674
57675
57676         uiMapInMap.toggle = toggle;
57677
57678         wrap = selection$$1.selectAll('.map-in-map')
57679             .data([0]);
57680
57681         wrap = wrap.enter()
57682             .append('div')
57683             .attr('class', 'map-in-map')
57684             .style('display', (isHidden ? 'none' : 'block'))
57685             .call(zoom$$1)
57686             .on('dblclick.zoom', null)
57687             .merge(wrap);
57688
57689         context.map()
57690             .on('drawn.map-in-map', function(drawn) {
57691                 if (drawn.full === true) {
57692                     redraw();
57693                 }
57694             });
57695
57696         redraw();
57697
57698         var keybinding = d3keybinding('map-in-map')
57699             .on(t('background.minimap.key'), toggle);
57700
57701         select(document)
57702             .call(keybinding);
57703     }
57704
57705     return map_in_map;
57706 }
57707
57708 function uiTooltipHtml(text, key, heading) {
57709     var s = '';
57710
57711     if (heading) {
57712         s += '<div class="tooltip-heading"><span>' + heading + '</span></div>';
57713     }
57714     if (text) {
57715         s += '<div class="tooltip-text"><span>' + text + '</span></div>';
57716     }
57717     if (key) {
57718         s += '<div class="keyhint-wrap"><span>' + t('tooltip_keyhint') + '</span>' +
57719             '<span class="keyhint">' + key + '</span></div>';
57720     }
57721
57722     return s;
57723 }
57724
57725 function uiBackground(context) {
57726     var key = t('background.key'),
57727         detected = utilDetect(),
57728         opacities = [1, 0.75, 0.5, 0.25],
57729         directions = [
57730             ['right', [0.5, 0]],
57731             ['top', [0, -0.5]],
57732             ['left', [-0.5, 0]],
57733             ['bottom', [0, 0.5]]],
57734         opacityDefault = (context.storage('background-opacity') !== null) ?
57735             (+context.storage('background-opacity')) : 1.0,
57736         customTemplate = context.storage('background-custom-template') || '',
57737         customSource = rendererBackgroundSource.Custom(customTemplate),
57738         previous;
57739
57740     // Can be 0 from <1.3.0 use or due to issue #1923.
57741     if (opacityDefault === 0) opacityDefault = 1.0;
57742
57743
57744     function background(selection$$1) {
57745
57746         function sortSources(a, b) {
57747             return a.best() && !b.best() ? -1
57748                 : b.best() && !a.best() ? 1
57749                 : descending(a.area(), b.area()) || ascending(a.name(), b.name()) || 0;
57750         }
57751
57752
57753         function setOpacity(d) {
57754             var bg = context.container().selectAll('.layer-background')
57755                 .transition()
57756                 .style('opacity', d)
57757                 .attr('data-opacity', d);
57758
57759             if (!detected.opera) {
57760                 utilSetTransform(bg, 0, 0);
57761             }
57762
57763             opacityList.selectAll('li')
57764                 .classed('active', function(_) { return _ === d; });
57765
57766             context.storage('background-opacity', d);
57767         }
57768
57769
57770         function setTooltips(selection$$1) {
57771             selection$$1.each(function(d, i, nodes) {
57772                 var item = select(this).select('label'),
57773                     span = item.select('span'),
57774                     placement = (i < nodes.length / 2) ? 'bottom' : 'top',
57775                     description = d.description(),
57776                     isOverflowing = (span.property('clientWidth') !== span.property('scrollWidth'));
57777
57778                 if (d === previous) {
57779                     item.call(tooltip()
57780                         .placement(placement)
57781                         .html(true)
57782                         .title(function() {
57783                             var tip = '<div>' + t('background.switch') + '</div>';
57784                             return uiTooltipHtml(tip, uiCmd('⌘' + key));
57785                         })
57786                     );
57787                 } else if (description || isOverflowing) {
57788                     item.call(tooltip()
57789                         .placement(placement)
57790                         .title(description || d.name())
57791                     );
57792                 } else {
57793                     item.call(tooltip().destroy);
57794                 }
57795             });
57796         }
57797
57798
57799         function selectLayer() {
57800             function active$$1(d) {
57801                 return context.background().showsLayer(d);
57802             }
57803
57804             content.selectAll('.layer, .custom_layer')
57805                 .classed('active', active$$1)
57806                 .classed('switch', function(d) { return d === previous; })
57807                 .call(setTooltips)
57808                 .selectAll('input')
57809                 .property('checked', active$$1);
57810         }
57811
57812
57813         function clickSetSource(d) {
57814             event.preventDefault();
57815             previous = context.background().baseLayerSource();
57816             context.background().baseLayerSource(d);
57817             selectLayer();
57818             document.activeElement.blur();
57819         }
57820
57821
57822         function editCustom() {
57823             event.preventDefault();
57824             var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
57825             var template = window.prompt(
57826                 t('background.custom_prompt', { example: example }),
57827                 customSource.template() || example
57828             );
57829
57830             if (template) {
57831                 context.storage('background-custom-template', template);
57832                 customTemplate = template;
57833                 customSource.template(template);
57834                 clickSetSource(customSource);
57835             } else {
57836                 selectLayer();
57837             }
57838         }
57839
57840
57841         function clickSetOverlay(d) {
57842             event.preventDefault();
57843             context.background().toggleOverlayLayer(d);
57844             selectLayer();
57845             document.activeElement.blur();
57846         }
57847
57848
57849         function drawList(layerList, type, change, filter) {
57850             var sources = context.background()
57851                 .sources(context.map().extent())
57852                 .filter(filter);
57853
57854             var layerLinks = layerList.selectAll('li.layer')
57855                 .data(sources, function(d) { return d.name(); });
57856
57857             layerLinks.exit()
57858                 .remove();
57859
57860             var enter = layerLinks.enter()
57861                 .insert('li', '.custom_layer')
57862                 .attr('class', 'layer')
57863                 .classed('best', function(d) { return d.best(); });
57864
57865             enter.filter(function(d) { return d.best(); })
57866                 .append('div')
57867                 .attr('class', 'best')
57868                 .call(tooltip()
57869                     .title(t('background.best_imagery'))
57870                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
57871                 .append('span')
57872                 .html('&#9733;');
57873
57874             var label = enter
57875                 .append('label');
57876
57877             label
57878                 .append('input')
57879                 .attr('type', type)
57880                 .attr('name', 'layers')
57881                 .on('change', change);
57882
57883             label
57884                 .append('span')
57885                 .text(function(d) { return d.name(); });
57886
57887
57888             layerList.selectAll('li.layer')
57889                 .sort(sortSources)
57890                 .style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
57891         }
57892
57893
57894         function update() {
57895             backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
57896             overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
57897
57898             selectLayer();
57899             updateOffsetVal();
57900         }
57901
57902
57903         function updateOffsetVal() {
57904             var meters = geoOffsetToMeters(context.background().offset()),
57905                 x = +meters[0].toFixed(2),
57906                 y = +meters[1].toFixed(2);
57907
57908             selectAll('.nudge-inner-rect')
57909                 .select('input')
57910                 .classed('error', false)
57911                 .property('value', x + ', ' + y);
57912
57913             selectAll('.nudge-reset')
57914                 .classed('disabled', function() {
57915                     return (x === 0 && y === 0);
57916                 });
57917         }
57918
57919
57920         function resetOffset() {
57921             if (event.button !== 0) return;
57922             context.background().offset([0, 0]);
57923             updateOffsetVal();
57924         }
57925
57926
57927         function nudge(d) {
57928             context.background().nudge(d, context.map().zoom());
57929             updateOffsetVal();
57930         }
57931
57932
57933         function buttonOffset(d) {
57934             if (event.button !== 0) return;
57935             var timeout = window.setTimeout(function() {
57936                     interval = window.setInterval(nudge.bind(null, d), 100);
57937                 }, 500),
57938                 interval;
57939
57940             function doneNudge() {
57941                 window.clearTimeout(timeout);
57942                 window.clearInterval(interval);
57943                 select(window)
57944                     .on('mouseup.buttonoffset', null, true)
57945                     .on('mousedown.buttonoffset', null, true);
57946             }
57947
57948             select(window)
57949                 .on('mouseup.buttonoffset', doneNudge, true)
57950                 .on('mousedown.buttonoffset', doneNudge, true);
57951
57952             nudge(d);
57953         }
57954
57955
57956         function inputOffset() {
57957             if (event.button !== 0) return;
57958             var input = select(this);
57959             var d = input.node().value;
57960
57961             if (d === '') return resetOffset();
57962
57963             d = d.replace(/;/g, ',').split(',').map(function(n) {
57964                 // if n is NaN, it will always get mapped to false.
57965                 return !isNaN(n) && n;
57966             });
57967
57968             if (d.length !== 2 || !d[0] || !d[1]) {
57969                 input.classed('error', true);
57970                 return;
57971             }
57972
57973             context.background().offset(geoMetersToOffset(d));
57974             updateOffsetVal();
57975         }
57976
57977
57978         function dragOffset() {
57979             if (event.button !== 0) return;
57980             var origin = [event.clientX, event.clientY];
57981
57982             context.container()
57983                 .append('div')
57984                 .attr('class', 'nudge-surface');
57985
57986             select(window)
57987                 .on('mousemove.offset', function() {
57988                     var latest = [event.clientX, event.clientY];
57989                     var d = [
57990                         -(origin[0] - latest[0]) / 4,
57991                         -(origin[1] - latest[1]) / 4
57992                     ];
57993
57994                     origin = latest;
57995                     nudge(d);
57996                 })
57997                 .on('mouseup.offset', function() {
57998                     if (event.button !== 0) return;
57999                     selectAll('.nudge-surface')
58000                         .remove();
58001
58002                     select(window)
58003                         .on('mousemove.offset', null)
58004                         .on('mouseup.offset', null);
58005                 });
58006
58007             event.preventDefault();
58008         }
58009
58010
58011         function hide() {
58012             setVisible(false);
58013         }
58014
58015
58016         function toggle() {
58017             if (event) event.preventDefault();
58018             tooltipBehavior.hide(button);
58019             setVisible(!button.classed('active'));
58020         }
58021
58022
58023         function quickSwitch() {
58024             if (previous) {
58025                 clickSetSource(previous);
58026             }
58027         }
58028
58029
58030         function setVisible(show) {
58031             if (show !== shown) {
58032                 button.classed('active', show);
58033                 shown = show;
58034
58035                 if (show) {
58036                     selection$$1
58037                         .on('mousedown.background-inside', function() {
58038                             event.stopPropagation();
58039                         });
58040
58041                     content
58042                         .style('display', 'block')
58043                         .style('right', '-300px')
58044                         .transition()
58045                         .duration(200)
58046                         .style('right', '0px');
58047
58048                     content.selectAll('.layer, .custom_layer')
58049                         .call(setTooltips);
58050
58051                 } else {
58052                     content
58053                         .style('display', 'block')
58054                         .style('right', '0px')
58055                         .transition()
58056                         .duration(200)
58057                         .style('right', '-300px')
58058                         .on('end', function() {
58059                             select(this).style('display', 'none');
58060                         });
58061
58062                     selection$$1
58063                         .on('mousedown.background-inside', null);
58064                 }
58065             }
58066         }
58067
58068
58069         var content = selection$$1
58070                 .append('div')
58071                 .attr('class', 'fillL map-overlay col3 content hide'),
58072             tooltipBehavior = tooltip()
58073                 .placement((textDirection === 'rtl') ? 'right' : 'left')
58074                 .html(true)
58075                 .title(uiTooltipHtml(t('background.description'), key)),
58076             button = selection$$1
58077                 .append('button')
58078                 .attr('tabindex', -1)
58079                 .on('click', toggle)
58080                 .call(svgIcon('#icon-layers', 'light'))
58081                 .call(tooltipBehavior),
58082             shown = false;
58083
58084
58085         /* opacity switcher */
58086
58087         var opawrap = content
58088                 .append('div')
58089                 .attr('class', 'opacity-options-wrapper');
58090
58091         opawrap
58092             .append('h4')
58093             .text(t('background.title'));
58094
58095         var opacityList = opawrap
58096             .append('ul')
58097             .attr('class', 'opacity-options');
58098
58099         opacityList.selectAll('div.opacity')
58100             .data(opacities)
58101             .enter()
58102             .append('li')
58103             .attr('data-original-title', function(d) {
58104                 return t('background.percent_brightness', { opacity: (d * 100) });
58105             })
58106             .on('click.set-opacity', setOpacity)
58107             .html('<div class="select-box"></div>')
58108             .call(tooltip()
58109                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
58110             .append('div')
58111             .attr('class', 'opacity')
58112             .style('opacity', function(d) { return 1.25 - d; });
58113
58114
58115         /* background switcher */
58116
58117         var backgroundList = content
58118             .append('ul')
58119             .attr('class', 'layer-list')
58120             .attr('dir', 'auto');
58121
58122         var custom = backgroundList
58123             .append('li')
58124             .attr('class', 'custom_layer')
58125             .datum(customSource);
58126
58127         custom
58128             .append('button')
58129             .attr('class', 'layer-browse')
58130             .call(tooltip()
58131                 .title(t('background.custom_button'))
58132                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
58133             .on('click', editCustom)
58134             .call(svgIcon('#icon-search'));
58135
58136         var label = custom
58137             .append('label');
58138
58139         label
58140             .append('input')
58141             .attr('type', 'radio')
58142             .attr('name', 'layers')
58143             .on('change', function () {
58144                 if (customSource.template()) {
58145                     clickSetSource(customSource);
58146                 } else {
58147                     editCustom();
58148                 }
58149             });
58150
58151         label
58152             .append('span')
58153             .text(t('background.custom'));
58154
58155         content
58156             .append('div')
58157             .attr('class', 'imagery-faq')
58158             .append('a')
58159             .attr('target', '_blank')
58160             .attr('tabindex', -1)
58161             .call(svgIcon('#icon-out-link', 'inline'))
58162             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
58163             .append('span')
58164             .text(t('background.imagery_source_faq'));
58165
58166         var overlayList = content
58167             .append('ul')
58168             .attr('class', 'layer-list');
58169
58170         var controls = content
58171             .append('div')
58172             .attr('class', 'controls-list');
58173
58174
58175         /* minimap toggle */
58176
58177         var minimapLabel = controls
58178             .append('label')
58179             .call(tooltip()
58180                 .html(true)
58181                 .title(uiTooltipHtml(t('background.minimap.tooltip'), t('background.minimap.key')))
58182                 .placement('top')
58183             );
58184
58185         minimapLabel
58186             .classed('minimap-toggle', true)
58187             .append('input')
58188             .attr('type', 'checkbox')
58189             .on('change', function() {
58190                 uiMapInMap.toggle();
58191                 event.preventDefault();
58192             });
58193
58194         minimapLabel
58195             .append('span')
58196             .text(t('background.minimap.description'));
58197
58198
58199         /* imagery offset controls */
58200
58201         var adjustments = content
58202             .append('div')
58203             .attr('class', 'adjustments');
58204
58205         adjustments
58206             .append('a')
58207             .text(t('background.fix_misalignment'))
58208             .attr('href', '#')
58209             .classed('hide-toggle', true)
58210             .classed('expanded', false)
58211             .on('click', function() {
58212                 if (event.button !== 0) return;
58213                 var exp = select(this).classed('expanded');
58214                 nudgeContainer.style('display', exp ? 'none' : 'block');
58215                 select(this).classed('expanded', !exp);
58216                 event.preventDefault();
58217             });
58218
58219         var nudgeContainer = adjustments
58220             .append('div')
58221             .attr('class', 'nudge-container cf')
58222             .style('display', 'none');
58223
58224         nudgeContainer
58225             .append('div')
58226             .attr('class', 'nudge-instructions')
58227             .text(t('background.offset'));
58228
58229         var nudgeRect = nudgeContainer
58230             .append('div')
58231             .attr('class', 'nudge-outer-rect')
58232             .on('mousedown', dragOffset);
58233
58234         nudgeRect
58235             .append('div')
58236             .attr('class', 'nudge-inner-rect')
58237             .append('input')
58238             .on('change', inputOffset)
58239             .on('mousedown', function() {
58240                 if (event.button !== 0) return;
58241                 event.stopPropagation();
58242             });
58243
58244         nudgeContainer
58245             .append('div')
58246             .selectAll('button')
58247             .data(directions).enter()
58248             .append('button')
58249             .attr('class', function(d) { return d[0] + ' nudge'; })
58250             .on('mousedown', function(d) {
58251                 if (event.button !== 0) return;
58252                 buttonOffset(d[1]);
58253             });
58254
58255         nudgeContainer
58256             .append('button')
58257             .attr('title', t('background.reset'))
58258             .attr('class', 'nudge-reset disabled')
58259             .on('click', resetOffset)
58260             .call(
58261                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
58262             );
58263
58264         context.map()
58265             .on('move.background-update', lodash.debounce(update, 1000));
58266
58267         context.background()
58268             .on('change.background-update', update);
58269
58270
58271         update();
58272         setOpacity(opacityDefault);
58273
58274         var keybinding = d3keybinding('background')
58275             .on(key, toggle)
58276             .on(uiCmd('⌘' + key), quickSwitch)
58277             .on([t('map_data.key'), t('help.key')], hide);
58278
58279         select(document)
58280             .call(keybinding);
58281
58282         context.surface().on('mousedown.background-outside', hide);
58283         context.container().on('mousedown.background-outside', hide);
58284     }
58285
58286     return background;
58287 }
58288
58289 function uiContributors(context) {
58290     var debouncedUpdate = lodash.debounce(function() { update(); }, 1000),
58291         limit = 4,
58292         hidden = false,
58293         wrap = select(null);
58294
58295
58296     function update() {
58297         var users = {},
58298             entities = context.intersects(context.map().extent());
58299
58300         entities.forEach(function(entity) {
58301             if (entity && entity.user) users[entity.user] = true;
58302         });
58303
58304         var u = Object.keys(users),
58305             subset = u.slice(0, u.length > limit ? limit - 1 : limit);
58306
58307         wrap.html('')
58308             .call(svgIcon('#icon-nearby', 'pre-text light'));
58309
58310         var userList = select(document.createElement('span'));
58311
58312         userList.selectAll()
58313             .data(subset)
58314             .enter()
58315             .append('a')
58316             .attr('class', 'user-link')
58317             .attr('href', function(d) { return context.connection().userURL(d); })
58318             .attr('target', '_blank')
58319             .attr('tabindex', -1)
58320             .text(String);
58321
58322         if (u.length > limit) {
58323             var count = select(document.createElement('span'));
58324
58325             count.append('a')
58326                 .attr('target', '_blank')
58327                 .attr('tabindex', -1)
58328                 .attr('href', function() {
58329                     return context.connection().changesetsURL(context.map().center(), context.map().zoom());
58330                 })
58331                 .text(u.length - limit + 1);
58332
58333             wrap.append('span')
58334                 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
58335
58336         } else {
58337             wrap.append('span')
58338                 .html(t('contributors.list', { users: userList.html() }));
58339         }
58340
58341         if (!u.length) {
58342             hidden = true;
58343             wrap
58344                 .transition()
58345                 .style('opacity', 0);
58346
58347         } else if (hidden) {
58348             wrap
58349                 .transition()
58350                 .style('opacity', 1);
58351         }
58352     }
58353
58354
58355     return function(selection$$1) {
58356         wrap = selection$$1;
58357         update();
58358
58359         context.connection().on('loaded.contributors', debouncedUpdate);
58360         context.map().on('move.contributors', debouncedUpdate);
58361     };
58362 }
58363
58364 function uiFeatureInfo(context) {
58365     function update(selection$$1) {
58366         var features = context.features(),
58367             stats = features.stats(),
58368             count = 0,
58369             hiddenList = lodash.compact(lodash.map(features.hidden(), function(k) {
58370                 if (stats[k]) {
58371                     count += stats[k];
58372                     return String(stats[k]) + ' ' + t('feature.' + k + '.description');
58373                 }
58374             }));
58375
58376         selection$$1.html('');
58377
58378         if (hiddenList.length) {
58379             var tooltipBehavior = tooltip()
58380                     .placement('top')
58381                     .html(true)
58382                     .title(function() {
58383                         return uiTooltipHtml(hiddenList.join('<br/>'));
58384                     });
58385
58386             var warning = selection$$1.append('a')
58387                 .attr('href', '#')
58388                 .attr('tabindex', -1)
58389                 .html(t('feature_info.hidden_warning', { count: count }))
58390                 .call(tooltipBehavior)
58391                 .on('click', function() {
58392                     tooltipBehavior.hide(warning);
58393                     // open map data panel?
58394                     event.preventDefault();
58395                 });
58396         }
58397
58398         selection$$1
58399             .classed('hide', !hiddenList.length);
58400     }
58401
58402
58403     return function(selection$$1) {
58404         update(selection$$1);
58405
58406         context.features().on('change.feature_info', function() {
58407             update(selection$$1);
58408         });
58409     };
58410 }
58411
58412 function uiFullScreen(context) {
58413     var element = context.container().node(),
58414         keybinding = d3keybinding('full-screen');
58415         // button;
58416
58417
58418     function getFullScreenFn() {
58419         if (element.requestFullscreen) {
58420             return element.requestFullscreen;
58421         } else if (element.msRequestFullscreen) {
58422             return element.msRequestFullscreen;
58423         } else if (element.mozRequestFullScreen) {
58424             return element.mozRequestFullScreen;
58425         } else if (element.webkitRequestFullscreen) {
58426             return element.webkitRequestFullscreen;
58427         }
58428     }
58429
58430
58431     function getExitFullScreenFn() {
58432         if (document.exitFullscreen) {
58433             return document.exitFullscreen;
58434         } else if (document.msExitFullscreen) {
58435             return document.msExitFullscreen;
58436         } else if (document.mozCancelFullScreen) {
58437             return document.mozCancelFullScreen;
58438         } else if (document.webkitExitFullscreen) {
58439             return document.webkitExitFullscreen;
58440         }
58441     }
58442
58443
58444     function isFullScreen() {
58445         return document.fullscreenElement ||
58446             document.mozFullScreenElement ||
58447             document.webkitFullscreenElement ||
58448             document.msFullscreenElement;
58449     }
58450
58451
58452     function isSupported() {
58453         return !!getFullScreenFn();
58454     }
58455
58456
58457     function fullScreen() {
58458         event.preventDefault();
58459         if (!isFullScreen()) {
58460             // button.classed('active', true);
58461             getFullScreenFn().apply(element);
58462         } else {
58463             // button.classed('active', false);
58464             getExitFullScreenFn().apply(document);
58465         }
58466     }
58467
58468
58469     return function() { // selection) {
58470         if (!isSupported())
58471             return;
58472
58473         // button = selection.append('button')
58474         //     .attr('title', t('full_screen'))
58475         //     .attr('tabindex', -1)
58476         //     .on('click', fullScreen)
58477         //     .call(tooltip);
58478
58479         // button.append('span')
58480         //     .attr('class', 'icon full-screen');
58481
58482         var detected = utilDetect();
58483         var keys$$1 = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
58484         keybinding.on(keys$$1, fullScreen);
58485
58486         select(document)
58487             .call(keybinding);
58488     };
58489 }
58490
58491 function uiModal(selection$$1, blocking) {
58492     var keybinding = d3keybinding('modal');
58493     var previous = selection$$1.select('div.modal');
58494     var animate = previous.empty();
58495
58496     previous.transition()
58497         .duration(200)
58498         .style('opacity', 0)
58499         .remove();
58500
58501     var shaded = selection$$1
58502         .append('div')
58503         .attr('class', 'shaded')
58504         .style('opacity', 0);
58505
58506     shaded.close = function() {
58507         shaded
58508             .transition()
58509             .duration(200)
58510             .style('opacity',0)
58511             .remove();
58512
58513         modal
58514             .transition()
58515             .duration(200)
58516             .style('top','0px');
58517
58518         keybinding.off();
58519     };
58520
58521
58522     var modal = shaded
58523         .append('div')
58524         .attr('class', 'modal fillL col6');
58525
58526     if (!blocking) {
58527         shaded.on('click.remove-modal', function() {
58528             if (event.target === this) {
58529                 shaded.close();
58530             }
58531         });
58532
58533         modal.append('button')
58534             .attr('class', 'close')
58535             .on('click', shaded.close)
58536             .call(svgIcon('#icon-close'));
58537
58538         keybinding
58539             .on('⌫', shaded.close)
58540             .on('⎋', shaded.close);
58541
58542         select(document)
58543             .call(keybinding);
58544     }
58545
58546     modal
58547         .append('div')
58548         .attr('class', 'content');
58549
58550     if (animate) {
58551         shaded.transition().style('opacity', 1);
58552     } else {
58553         shaded.style('opacity', 1);
58554     }
58555
58556
58557     return shaded;
58558 }
58559
58560 function uiLoading(context) {
58561     var message = '',
58562         blocking = false,
58563         modalSelection;
58564
58565
58566     var loading = function(selection) {
58567         modalSelection = uiModal(selection, blocking);
58568
58569         var loadertext = modalSelection.select('.content')
58570             .classed('loading-modal', true)
58571             .append('div')
58572             .attr('class', 'modal-section fillL');
58573
58574         loadertext
58575             .append('img')
58576             .attr('class', 'loader')
58577             .attr('src', context.imagePath('loader-white.gif'));
58578
58579         loadertext
58580             .append('h3')
58581             .text(message);
58582
58583         modalSelection.select('button.close')
58584             .attr('class', 'hide');
58585
58586         return loading;
58587     };
58588
58589
58590     loading.message = function(_) {
58591         if (!arguments.length) return message;
58592         message = _;
58593         return loading;
58594     };
58595
58596
58597     loading.blocking = function(_) {
58598         if (!arguments.length) return blocking;
58599         blocking = _;
58600         return loading;
58601     };
58602
58603
58604     loading.close = function() {
58605         modalSelection.remove();
58606     };
58607
58608
58609     return loading;
58610 }
58611
58612 function uiGeolocate(context) {
58613     var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
58614         locating = uiLoading(context).message(t('geolocate.locating')).blocking(true),
58615         timeoutId;
58616
58617
58618     function click() {
58619         if (context.inIntro()) return;
58620         context.enter(modeBrowse(context));
58621         context.container().call(locating);
58622         navigator.geolocation.getCurrentPosition(success, error, geoOptions);
58623
58624         // This timeout ensures that we still call finish() even if
58625         // the user declines to share their location in Firefox
58626         timeoutId = setTimeout(finish, 10000 /* 10sec */ );
58627     }
58628
58629
58630     function success(position) {
58631         var map = context.map(),
58632             extent = geoExtent$$1([position.coords.longitude, position.coords.latitude])
58633                 .padByMeters(position.coords.accuracy);
58634
58635         map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
58636         finish();
58637     }
58638
58639
58640     function error() {
58641         finish();
58642     }
58643
58644
58645     function finish() {
58646         locating.close();  // unblock ui
58647         if (timeoutId) { clearTimeout(timeoutId); }
58648         timeoutId = undefined;
58649     }
58650
58651
58652     return function(selection) {
58653         if (!navigator.geolocation) return;
58654
58655         selection
58656             .append('button')
58657             .attr('tabindex', -1)
58658             .attr('title', t('geolocate.title'))
58659             .on('click', click)
58660             .call(svgIcon('#icon-geolocate', 'light'))
58661             .call(tooltip()
58662                 .placement((textDirection === 'rtl') ? 'right' : 'left'));
58663     };
58664 }
58665
58666 var marked = createCommonjsModule(function (module, exports) {
58667 /**
58668  * marked - a markdown parser
58669  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
58670  * https://github.com/chjj/marked
58671  */
58672
58673 (function() {
58674
58675 /**
58676  * Block-Level Grammar
58677  */
58678
58679 var block = {
58680   newline: /^\n+/,
58681   code: /^( {4}[^\n]+\n*)+/,
58682   fences: noop,
58683   hr: /^( *[-*_]){3,} *(?:\n+|$)/,
58684   heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
58685   nptable: noop,
58686   lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
58687   blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
58688   list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
58689   html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
58690   def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
58691   table: noop,
58692   paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
58693   text: /^[^\n]+/
58694 };
58695
58696 block.bullet = /(?:[*+-]|\d+\.)/;
58697 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
58698 block.item = replace(block.item, 'gm')
58699   (/bull/g, block.bullet)
58700   ();
58701
58702 block.list = replace(block.list)
58703   (/bull/g, block.bullet)
58704   ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
58705   ('def', '\\n+(?=' + block.def.source + ')')
58706   ();
58707
58708 block.blockquote = replace(block.blockquote)
58709   ('def', block.def)
58710   ();
58711
58712 block._tag = '(?!(?:'
58713   + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
58714   + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
58715   + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
58716
58717 block.html = replace(block.html)
58718   ('comment', /<!--[\s\S]*?-->/)
58719   ('closed', /<(tag)[\s\S]+?<\/\1>/)
58720   ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
58721   (/tag/g, block._tag)
58722   ();
58723
58724 block.paragraph = replace(block.paragraph)
58725   ('hr', block.hr)
58726   ('heading', block.heading)
58727   ('lheading', block.lheading)
58728   ('blockquote', block.blockquote)
58729   ('tag', '<' + block._tag)
58730   ('def', block.def)
58731   ();
58732
58733 /**
58734  * Normal Block Grammar
58735  */
58736
58737 block.normal = merge({}, block);
58738
58739 /**
58740  * GFM Block Grammar
58741  */
58742
58743 block.gfm = merge({}, block.normal, {
58744   fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
58745   paragraph: /^/,
58746   heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
58747 });
58748
58749 block.gfm.paragraph = replace(block.paragraph)
58750   ('(?!', '(?!'
58751     + block.gfm.fences.source.replace('\\1', '\\2') + '|'
58752     + block.list.source.replace('\\1', '\\3') + '|')
58753   ();
58754
58755 /**
58756  * GFM + Tables Block Grammar
58757  */
58758
58759 block.tables = merge({}, block.gfm, {
58760   nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
58761   table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
58762 });
58763
58764 /**
58765  * Block Lexer
58766  */
58767
58768 function Lexer(options) {
58769   this.tokens = [];
58770   this.tokens.links = {};
58771   this.options = options || marked.defaults;
58772   this.rules = block.normal;
58773
58774   if (this.options.gfm) {
58775     if (this.options.tables) {
58776       this.rules = block.tables;
58777     } else {
58778       this.rules = block.gfm;
58779     }
58780   }
58781 }
58782
58783 /**
58784  * Expose Block Rules
58785  */
58786
58787 Lexer.rules = block;
58788
58789 /**
58790  * Static Lex Method
58791  */
58792
58793 Lexer.lex = function(src, options) {
58794   var lexer = new Lexer(options);
58795   return lexer.lex(src);
58796 };
58797
58798 /**
58799  * Preprocessing
58800  */
58801
58802 Lexer.prototype.lex = function(src) {
58803   src = src
58804     .replace(/\r\n|\r/g, '\n')
58805     .replace(/\t/g, '    ')
58806     .replace(/\u00a0/g, ' ')
58807     .replace(/\u2424/g, '\n');
58808
58809   return this.token(src, true);
58810 };
58811
58812 /**
58813  * Lexing
58814  */
58815
58816 Lexer.prototype.token = function(src, top, bq) {
58817   var src = src.replace(/^ +$/gm, '')
58818     , next
58819     , loose
58820     , cap
58821     , bull
58822     , b
58823     , item
58824     , space
58825     , i
58826     , l;
58827
58828   while (src) {
58829     // newline
58830     if (cap = this.rules.newline.exec(src)) {
58831       src = src.substring(cap[0].length);
58832       if (cap[0].length > 1) {
58833         this.tokens.push({
58834           type: 'space'
58835         });
58836       }
58837     }
58838
58839     // code
58840     if (cap = this.rules.code.exec(src)) {
58841       src = src.substring(cap[0].length);
58842       cap = cap[0].replace(/^ {4}/gm, '');
58843       this.tokens.push({
58844         type: 'code',
58845         text: !this.options.pedantic
58846           ? cap.replace(/\n+$/, '')
58847           : cap
58848       });
58849       continue;
58850     }
58851
58852     // fences (gfm)
58853     if (cap = this.rules.fences.exec(src)) {
58854       src = src.substring(cap[0].length);
58855       this.tokens.push({
58856         type: 'code',
58857         lang: cap[2],
58858         text: cap[3] || ''
58859       });
58860       continue;
58861     }
58862
58863     // heading
58864     if (cap = this.rules.heading.exec(src)) {
58865       src = src.substring(cap[0].length);
58866       this.tokens.push({
58867         type: 'heading',
58868         depth: cap[1].length,
58869         text: cap[2]
58870       });
58871       continue;
58872     }
58873
58874     // table no leading pipe (gfm)
58875     if (top && (cap = this.rules.nptable.exec(src))) {
58876       src = src.substring(cap[0].length);
58877
58878       item = {
58879         type: 'table',
58880         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
58881         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
58882         cells: cap[3].replace(/\n$/, '').split('\n')
58883       };
58884
58885       for (i = 0; i < item.align.length; i++) {
58886         if (/^ *-+: *$/.test(item.align[i])) {
58887           item.align[i] = 'right';
58888         } else if (/^ *:-+: *$/.test(item.align[i])) {
58889           item.align[i] = 'center';
58890         } else if (/^ *:-+ *$/.test(item.align[i])) {
58891           item.align[i] = 'left';
58892         } else {
58893           item.align[i] = null;
58894         }
58895       }
58896
58897       for (i = 0; i < item.cells.length; i++) {
58898         item.cells[i] = item.cells[i].split(/ *\| */);
58899       }
58900
58901       this.tokens.push(item);
58902
58903       continue;
58904     }
58905
58906     // lheading
58907     if (cap = this.rules.lheading.exec(src)) {
58908       src = src.substring(cap[0].length);
58909       this.tokens.push({
58910         type: 'heading',
58911         depth: cap[2] === '=' ? 1 : 2,
58912         text: cap[1]
58913       });
58914       continue;
58915     }
58916
58917     // hr
58918     if (cap = this.rules.hr.exec(src)) {
58919       src = src.substring(cap[0].length);
58920       this.tokens.push({
58921         type: 'hr'
58922       });
58923       continue;
58924     }
58925
58926     // blockquote
58927     if (cap = this.rules.blockquote.exec(src)) {
58928       src = src.substring(cap[0].length);
58929
58930       this.tokens.push({
58931         type: 'blockquote_start'
58932       });
58933
58934       cap = cap[0].replace(/^ *> ?/gm, '');
58935
58936       // Pass `top` to keep the current
58937       // "toplevel" state. This is exactly
58938       // how markdown.pl works.
58939       this.token(cap, top, true);
58940
58941       this.tokens.push({
58942         type: 'blockquote_end'
58943       });
58944
58945       continue;
58946     }
58947
58948     // list
58949     if (cap = this.rules.list.exec(src)) {
58950       src = src.substring(cap[0].length);
58951       bull = cap[2];
58952
58953       this.tokens.push({
58954         type: 'list_start',
58955         ordered: bull.length > 1
58956       });
58957
58958       // Get each top-level item.
58959       cap = cap[0].match(this.rules.item);
58960
58961       next = false;
58962       l = cap.length;
58963       i = 0;
58964
58965       for (; i < l; i++) {
58966         item = cap[i];
58967
58968         // Remove the list item's bullet
58969         // so it is seen as the next token.
58970         space = item.length;
58971         item = item.replace(/^ *([*+-]|\d+\.) +/, '');
58972
58973         // Outdent whatever the
58974         // list item contains. Hacky.
58975         if (~item.indexOf('\n ')) {
58976           space -= item.length;
58977           item = !this.options.pedantic
58978             ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
58979             : item.replace(/^ {1,4}/gm, '');
58980         }
58981
58982         // Determine whether the next list item belongs here.
58983         // Backpedal if it does not belong in this list.
58984         if (this.options.smartLists && i !== l - 1) {
58985           b = block.bullet.exec(cap[i + 1])[0];
58986           if (bull !== b && !(bull.length > 1 && b.length > 1)) {
58987             src = cap.slice(i + 1).join('\n') + src;
58988             i = l - 1;
58989           }
58990         }
58991
58992         // Determine whether item is loose or not.
58993         // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
58994         // for discount behavior.
58995         loose = next || /\n\n(?!\s*$)/.test(item);
58996         if (i !== l - 1) {
58997           next = item.charAt(item.length - 1) === '\n';
58998           if (!loose) loose = next;
58999         }
59000
59001         this.tokens.push({
59002           type: loose
59003             ? 'loose_item_start'
59004             : 'list_item_start'
59005         });
59006
59007         // Recurse.
59008         this.token(item, false, bq);
59009
59010         this.tokens.push({
59011           type: 'list_item_end'
59012         });
59013       }
59014
59015       this.tokens.push({
59016         type: 'list_end'
59017       });
59018
59019       continue;
59020     }
59021
59022     // html
59023     if (cap = this.rules.html.exec(src)) {
59024       src = src.substring(cap[0].length);
59025       this.tokens.push({
59026         type: this.options.sanitize
59027           ? 'paragraph'
59028           : 'html',
59029         pre: !this.options.sanitizer
59030           && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
59031         text: cap[0]
59032       });
59033       continue;
59034     }
59035
59036     // def
59037     if ((!bq && top) && (cap = this.rules.def.exec(src))) {
59038       src = src.substring(cap[0].length);
59039       this.tokens.links[cap[1].toLowerCase()] = {
59040         href: cap[2],
59041         title: cap[3]
59042       };
59043       continue;
59044     }
59045
59046     // table (gfm)
59047     if (top && (cap = this.rules.table.exec(src))) {
59048       src = src.substring(cap[0].length);
59049
59050       item = {
59051         type: 'table',
59052         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
59053         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
59054         cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
59055       };
59056
59057       for (i = 0; i < item.align.length; i++) {
59058         if (/^ *-+: *$/.test(item.align[i])) {
59059           item.align[i] = 'right';
59060         } else if (/^ *:-+: *$/.test(item.align[i])) {
59061           item.align[i] = 'center';
59062         } else if (/^ *:-+ *$/.test(item.align[i])) {
59063           item.align[i] = 'left';
59064         } else {
59065           item.align[i] = null;
59066         }
59067       }
59068
59069       for (i = 0; i < item.cells.length; i++) {
59070         item.cells[i] = item.cells[i]
59071           .replace(/^ *\| *| *\| *$/g, '')
59072           .split(/ *\| */);
59073       }
59074
59075       this.tokens.push(item);
59076
59077       continue;
59078     }
59079
59080     // top-level paragraph
59081     if (top && (cap = this.rules.paragraph.exec(src))) {
59082       src = src.substring(cap[0].length);
59083       this.tokens.push({
59084         type: 'paragraph',
59085         text: cap[1].charAt(cap[1].length - 1) === '\n'
59086           ? cap[1].slice(0, -1)
59087           : cap[1]
59088       });
59089       continue;
59090     }
59091
59092     // text
59093     if (cap = this.rules.text.exec(src)) {
59094       // Top-level should never reach here.
59095       src = src.substring(cap[0].length);
59096       this.tokens.push({
59097         type: 'text',
59098         text: cap[0]
59099       });
59100       continue;
59101     }
59102
59103     if (src) {
59104       throw new
59105         Error('Infinite loop on byte: ' + src.charCodeAt(0));
59106     }
59107   }
59108
59109   return this.tokens;
59110 };
59111
59112 /**
59113  * Inline-Level Grammar
59114  */
59115
59116 var inline = {
59117   escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
59118   autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
59119   url: noop,
59120   tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
59121   link: /^!?\[(inside)\]\(href\)/,
59122   reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
59123   nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
59124   strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
59125   em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
59126   code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
59127   br: /^ {2,}\n(?!\s*$)/,
59128   del: noop,
59129   text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
59130 };
59131
59132 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
59133 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
59134
59135 inline.link = replace(inline.link)
59136   ('inside', inline._inside)
59137   ('href', inline._href)
59138   ();
59139
59140 inline.reflink = replace(inline.reflink)
59141   ('inside', inline._inside)
59142   ();
59143
59144 /**
59145  * Normal Inline Grammar
59146  */
59147
59148 inline.normal = merge({}, inline);
59149
59150 /**
59151  * Pedantic Inline Grammar
59152  */
59153
59154 inline.pedantic = merge({}, inline.normal, {
59155   strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
59156   em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
59157 });
59158
59159 /**
59160  * GFM Inline Grammar
59161  */
59162
59163 inline.gfm = merge({}, inline.normal, {
59164   escape: replace(inline.escape)('])', '~|])')(),
59165   url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
59166   del: /^~~(?=\S)([\s\S]*?\S)~~/,
59167   text: replace(inline.text)
59168     (']|', '~]|')
59169     ('|', '|https?://|')
59170     ()
59171 });
59172
59173 /**
59174  * GFM + Line Breaks Inline Grammar
59175  */
59176
59177 inline.breaks = merge({}, inline.gfm, {
59178   br: replace(inline.br)('{2,}', '*')(),
59179   text: replace(inline.gfm.text)('{2,}', '*')()
59180 });
59181
59182 /**
59183  * Inline Lexer & Compiler
59184  */
59185
59186 function InlineLexer(links, options) {
59187   this.options = options || marked.defaults;
59188   this.links = links;
59189   this.rules = inline.normal;
59190   this.renderer = this.options.renderer || new Renderer;
59191   this.renderer.options = this.options;
59192
59193   if (!this.links) {
59194     throw new
59195       Error('Tokens array requires a `links` property.');
59196   }
59197
59198   if (this.options.gfm) {
59199     if (this.options.breaks) {
59200       this.rules = inline.breaks;
59201     } else {
59202       this.rules = inline.gfm;
59203     }
59204   } else if (this.options.pedantic) {
59205     this.rules = inline.pedantic;
59206   }
59207 }
59208
59209 /**
59210  * Expose Inline Rules
59211  */
59212
59213 InlineLexer.rules = inline;
59214
59215 /**
59216  * Static Lexing/Compiling Method
59217  */
59218
59219 InlineLexer.output = function(src, links, options) {
59220   var inline = new InlineLexer(links, options);
59221   return inline.output(src);
59222 };
59223
59224 /**
59225  * Lexing/Compiling
59226  */
59227
59228 InlineLexer.prototype.output = function(src) {
59229   var out = ''
59230     , link
59231     , text
59232     , href
59233     , cap;
59234
59235   while (src) {
59236     // escape
59237     if (cap = this.rules.escape.exec(src)) {
59238       src = src.substring(cap[0].length);
59239       out += cap[1];
59240       continue;
59241     }
59242
59243     // autolink
59244     if (cap = this.rules.autolink.exec(src)) {
59245       src = src.substring(cap[0].length);
59246       if (cap[2] === '@') {
59247         text = cap[1].charAt(6) === ':'
59248           ? this.mangle(cap[1].substring(7))
59249           : this.mangle(cap[1]);
59250         href = this.mangle('mailto:') + text;
59251       } else {
59252         text = escape(cap[1]);
59253         href = text;
59254       }
59255       out += this.renderer.link(href, null, text);
59256       continue;
59257     }
59258
59259     // url (gfm)
59260     if (!this.inLink && (cap = this.rules.url.exec(src))) {
59261       src = src.substring(cap[0].length);
59262       text = escape(cap[1]);
59263       href = text;
59264       out += this.renderer.link(href, null, text);
59265       continue;
59266     }
59267
59268     // tag
59269     if (cap = this.rules.tag.exec(src)) {
59270       if (!this.inLink && /^<a /i.test(cap[0])) {
59271         this.inLink = true;
59272       } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
59273         this.inLink = false;
59274       }
59275       src = src.substring(cap[0].length);
59276       out += this.options.sanitize
59277         ? this.options.sanitizer
59278           ? this.options.sanitizer(cap[0])
59279           : escape(cap[0])
59280         : cap[0];
59281       continue;
59282     }
59283
59284     // link
59285     if (cap = this.rules.link.exec(src)) {
59286       src = src.substring(cap[0].length);
59287       this.inLink = true;
59288       out += this.outputLink(cap, {
59289         href: cap[2],
59290         title: cap[3]
59291       });
59292       this.inLink = false;
59293       continue;
59294     }
59295
59296     // reflink, nolink
59297     if ((cap = this.rules.reflink.exec(src))
59298         || (cap = this.rules.nolink.exec(src))) {
59299       src = src.substring(cap[0].length);
59300       link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
59301       link = this.links[link.toLowerCase()];
59302       if (!link || !link.href) {
59303         out += cap[0].charAt(0);
59304         src = cap[0].substring(1) + src;
59305         continue;
59306       }
59307       this.inLink = true;
59308       out += this.outputLink(cap, link);
59309       this.inLink = false;
59310       continue;
59311     }
59312
59313     // strong
59314     if (cap = this.rules.strong.exec(src)) {
59315       src = src.substring(cap[0].length);
59316       out += this.renderer.strong(this.output(cap[2] || cap[1]));
59317       continue;
59318     }
59319
59320     // em
59321     if (cap = this.rules.em.exec(src)) {
59322       src = src.substring(cap[0].length);
59323       out += this.renderer.em(this.output(cap[2] || cap[1]));
59324       continue;
59325     }
59326
59327     // code
59328     if (cap = this.rules.code.exec(src)) {
59329       src = src.substring(cap[0].length);
59330       out += this.renderer.codespan(escape(cap[2], true));
59331       continue;
59332     }
59333
59334     // br
59335     if (cap = this.rules.br.exec(src)) {
59336       src = src.substring(cap[0].length);
59337       out += this.renderer.br();
59338       continue;
59339     }
59340
59341     // del (gfm)
59342     if (cap = this.rules.del.exec(src)) {
59343       src = src.substring(cap[0].length);
59344       out += this.renderer.del(this.output(cap[1]));
59345       continue;
59346     }
59347
59348     // text
59349     if (cap = this.rules.text.exec(src)) {
59350       src = src.substring(cap[0].length);
59351       out += this.renderer.text(escape(this.smartypants(cap[0])));
59352       continue;
59353     }
59354
59355     if (src) {
59356       throw new
59357         Error('Infinite loop on byte: ' + src.charCodeAt(0));
59358     }
59359   }
59360
59361   return out;
59362 };
59363
59364 /**
59365  * Compile Link
59366  */
59367
59368 InlineLexer.prototype.outputLink = function(cap, link) {
59369   var href = escape(link.href)
59370     , title = link.title ? escape(link.title) : null;
59371
59372   return cap[0].charAt(0) !== '!'
59373     ? this.renderer.link(href, title, this.output(cap[1]))
59374     : this.renderer.image(href, title, escape(cap[1]));
59375 };
59376
59377 /**
59378  * Smartypants Transformations
59379  */
59380
59381 InlineLexer.prototype.smartypants = function(text) {
59382   if (!this.options.smartypants) return text;
59383   return text
59384     // em-dashes
59385     .replace(/---/g, '\u2014')
59386     // en-dashes
59387     .replace(/--/g, '\u2013')
59388     // opening singles
59389     .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
59390     // closing singles & apostrophes
59391     .replace(/'/g, '\u2019')
59392     // opening doubles
59393     .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
59394     // closing doubles
59395     .replace(/"/g, '\u201d')
59396     // ellipses
59397     .replace(/\.{3}/g, '\u2026');
59398 };
59399
59400 /**
59401  * Mangle Links
59402  */
59403
59404 InlineLexer.prototype.mangle = function(text) {
59405   if (!this.options.mangle) return text;
59406   var out = ''
59407     , l = text.length
59408     , i = 0
59409     , ch;
59410
59411   for (; i < l; i++) {
59412     ch = text.charCodeAt(i);
59413     if (Math.random() > 0.5) {
59414       ch = 'x' + ch.toString(16);
59415     }
59416     out += '&#' + ch + ';';
59417   }
59418
59419   return out;
59420 };
59421
59422 /**
59423  * Renderer
59424  */
59425
59426 function Renderer(options) {
59427   this.options = options || {};
59428 }
59429
59430 Renderer.prototype.code = function(code, lang, escaped) {
59431   if (this.options.highlight) {
59432     var out = this.options.highlight(code, lang);
59433     if (out != null && out !== code) {
59434       escaped = true;
59435       code = out;
59436     }
59437   }
59438
59439   if (!lang) {
59440     return '<pre><code>'
59441       + (escaped ? code : escape(code, true))
59442       + '\n</code></pre>';
59443   }
59444
59445   return '<pre><code class="'
59446     + this.options.langPrefix
59447     + escape(lang, true)
59448     + '">'
59449     + (escaped ? code : escape(code, true))
59450     + '\n</code></pre>\n';
59451 };
59452
59453 Renderer.prototype.blockquote = function(quote) {
59454   return '<blockquote>\n' + quote + '</blockquote>\n';
59455 };
59456
59457 Renderer.prototype.html = function(html) {
59458   return html;
59459 };
59460
59461 Renderer.prototype.heading = function(text, level, raw) {
59462   return '<h'
59463     + level
59464     + ' id="'
59465     + this.options.headerPrefix
59466     + raw.toLowerCase().replace(/[^\w]+/g, '-')
59467     + '">'
59468     + text
59469     + '</h'
59470     + level
59471     + '>\n';
59472 };
59473
59474 Renderer.prototype.hr = function() {
59475   return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
59476 };
59477
59478 Renderer.prototype.list = function(body, ordered) {
59479   var type = ordered ? 'ol' : 'ul';
59480   return '<' + type + '>\n' + body + '</' + type + '>\n';
59481 };
59482
59483 Renderer.prototype.listitem = function(text) {
59484   return '<li>' + text + '</li>\n';
59485 };
59486
59487 Renderer.prototype.paragraph = function(text) {
59488   return '<p>' + text + '</p>\n';
59489 };
59490
59491 Renderer.prototype.table = function(header, body) {
59492   return '<table>\n'
59493     + '<thead>\n'
59494     + header
59495     + '</thead>\n'
59496     + '<tbody>\n'
59497     + body
59498     + '</tbody>\n'
59499     + '</table>\n';
59500 };
59501
59502 Renderer.prototype.tablerow = function(content) {
59503   return '<tr>\n' + content + '</tr>\n';
59504 };
59505
59506 Renderer.prototype.tablecell = function(content, flags) {
59507   var type = flags.header ? 'th' : 'td';
59508   var tag = flags.align
59509     ? '<' + type + ' style="text-align:' + flags.align + '">'
59510     : '<' + type + '>';
59511   return tag + content + '</' + type + '>\n';
59512 };
59513
59514 // span level renderer
59515 Renderer.prototype.strong = function(text) {
59516   return '<strong>' + text + '</strong>';
59517 };
59518
59519 Renderer.prototype.em = function(text) {
59520   return '<em>' + text + '</em>';
59521 };
59522
59523 Renderer.prototype.codespan = function(text) {
59524   return '<code>' + text + '</code>';
59525 };
59526
59527 Renderer.prototype.br = function() {
59528   return this.options.xhtml ? '<br/>' : '<br>';
59529 };
59530
59531 Renderer.prototype.del = function(text) {
59532   return '<del>' + text + '</del>';
59533 };
59534
59535 Renderer.prototype.link = function(href, title, text) {
59536   if (this.options.sanitize) {
59537     try {
59538       var prot = decodeURIComponent(unescape(href))
59539         .replace(/[^\w:]/g, '')
59540         .toLowerCase();
59541     } catch (e) {
59542       return '';
59543     }
59544     if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
59545       return '';
59546     }
59547   }
59548   var out = '<a href="' + href + '"';
59549   if (title) {
59550     out += ' title="' + title + '"';
59551   }
59552   out += '>' + text + '</a>';
59553   return out;
59554 };
59555
59556 Renderer.prototype.image = function(href, title, text) {
59557   var out = '<img src="' + href + '" alt="' + text + '"';
59558   if (title) {
59559     out += ' title="' + title + '"';
59560   }
59561   out += this.options.xhtml ? '/>' : '>';
59562   return out;
59563 };
59564
59565 Renderer.prototype.text = function(text) {
59566   return text;
59567 };
59568
59569 /**
59570  * Parsing & Compiling
59571  */
59572
59573 function Parser(options) {
59574   this.tokens = [];
59575   this.token = null;
59576   this.options = options || marked.defaults;
59577   this.options.renderer = this.options.renderer || new Renderer;
59578   this.renderer = this.options.renderer;
59579   this.renderer.options = this.options;
59580 }
59581
59582 /**
59583  * Static Parse Method
59584  */
59585
59586 Parser.parse = function(src, options, renderer) {
59587   var parser = new Parser(options, renderer);
59588   return parser.parse(src);
59589 };
59590
59591 /**
59592  * Parse Loop
59593  */
59594
59595 Parser.prototype.parse = function(src) {
59596   this.inline = new InlineLexer(src.links, this.options, this.renderer);
59597   this.tokens = src.reverse();
59598
59599   var out = '';
59600   while (this.next()) {
59601     out += this.tok();
59602   }
59603
59604   return out;
59605 };
59606
59607 /**
59608  * Next Token
59609  */
59610
59611 Parser.prototype.next = function() {
59612   return this.token = this.tokens.pop();
59613 };
59614
59615 /**
59616  * Preview Next Token
59617  */
59618
59619 Parser.prototype.peek = function() {
59620   return this.tokens[this.tokens.length - 1] || 0;
59621 };
59622
59623 /**
59624  * Parse Text Tokens
59625  */
59626
59627 Parser.prototype.parseText = function() {
59628   var body = this.token.text;
59629
59630   while (this.peek().type === 'text') {
59631     body += '\n' + this.next().text;
59632   }
59633
59634   return this.inline.output(body);
59635 };
59636
59637 /**
59638  * Parse Current Token
59639  */
59640
59641 Parser.prototype.tok = function() {
59642   switch (this.token.type) {
59643     case 'space': {
59644       return '';
59645     }
59646     case 'hr': {
59647       return this.renderer.hr();
59648     }
59649     case 'heading': {
59650       return this.renderer.heading(
59651         this.inline.output(this.token.text),
59652         this.token.depth,
59653         this.token.text);
59654     }
59655     case 'code': {
59656       return this.renderer.code(this.token.text,
59657         this.token.lang,
59658         this.token.escaped);
59659     }
59660     case 'table': {
59661       var header = ''
59662         , body = ''
59663         , i
59664         , row
59665         , cell
59666         , flags
59667         , j;
59668
59669       // header
59670       cell = '';
59671       for (i = 0; i < this.token.header.length; i++) {
59672         flags = { header: true, align: this.token.align[i] };
59673         cell += this.renderer.tablecell(
59674           this.inline.output(this.token.header[i]),
59675           { header: true, align: this.token.align[i] }
59676         );
59677       }
59678       header += this.renderer.tablerow(cell);
59679
59680       for (i = 0; i < this.token.cells.length; i++) {
59681         row = this.token.cells[i];
59682
59683         cell = '';
59684         for (j = 0; j < row.length; j++) {
59685           cell += this.renderer.tablecell(
59686             this.inline.output(row[j]),
59687             { header: false, align: this.token.align[j] }
59688           );
59689         }
59690
59691         body += this.renderer.tablerow(cell);
59692       }
59693       return this.renderer.table(header, body);
59694     }
59695     case 'blockquote_start': {
59696       var body = '';
59697
59698       while (this.next().type !== 'blockquote_end') {
59699         body += this.tok();
59700       }
59701
59702       return this.renderer.blockquote(body);
59703     }
59704     case 'list_start': {
59705       var body = ''
59706         , ordered = this.token.ordered;
59707
59708       while (this.next().type !== 'list_end') {
59709         body += this.tok();
59710       }
59711
59712       return this.renderer.list(body, ordered);
59713     }
59714     case 'list_item_start': {
59715       var body = '';
59716
59717       while (this.next().type !== 'list_item_end') {
59718         body += this.token.type === 'text'
59719           ? this.parseText()
59720           : this.tok();
59721       }
59722
59723       return this.renderer.listitem(body);
59724     }
59725     case 'loose_item_start': {
59726       var body = '';
59727
59728       while (this.next().type !== 'list_item_end') {
59729         body += this.tok();
59730       }
59731
59732       return this.renderer.listitem(body);
59733     }
59734     case 'html': {
59735       var html = !this.token.pre && !this.options.pedantic
59736         ? this.inline.output(this.token.text)
59737         : this.token.text;
59738       return this.renderer.html(html);
59739     }
59740     case 'paragraph': {
59741       return this.renderer.paragraph(this.inline.output(this.token.text));
59742     }
59743     case 'text': {
59744       return this.renderer.paragraph(this.parseText());
59745     }
59746   }
59747 };
59748
59749 /**
59750  * Helpers
59751  */
59752
59753 function escape(html, encode) {
59754   return html
59755     .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
59756     .replace(/</g, '&lt;')
59757     .replace(/>/g, '&gt;')
59758     .replace(/"/g, '&quot;')
59759     .replace(/'/g, '&#39;');
59760 }
59761
59762 function unescape(html) {
59763         // explicitly match decimal, hex, and named HTML entities 
59764   return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
59765     n = n.toLowerCase();
59766     if (n === 'colon') return ':';
59767     if (n.charAt(0) === '#') {
59768       return n.charAt(1) === 'x'
59769         ? String.fromCharCode(parseInt(n.substring(2), 16))
59770         : String.fromCharCode(+n.substring(1));
59771     }
59772     return '';
59773   });
59774 }
59775
59776 function replace(regex, opt) {
59777   regex = regex.source;
59778   opt = opt || '';
59779   return function self(name, val) {
59780     if (!name) return new RegExp(regex, opt);
59781     val = val.source || val;
59782     val = val.replace(/(^|[^\[])\^/g, '$1');
59783     regex = regex.replace(name, val);
59784     return self;
59785   };
59786 }
59787
59788 function noop() {}
59789 noop.exec = noop;
59790
59791 function merge(obj) {
59792   var i = 1
59793     , target
59794     , key;
59795
59796   for (; i < arguments.length; i++) {
59797     target = arguments[i];
59798     for (key in target) {
59799       if (Object.prototype.hasOwnProperty.call(target, key)) {
59800         obj[key] = target[key];
59801       }
59802     }
59803   }
59804
59805   return obj;
59806 }
59807
59808
59809 /**
59810  * Marked
59811  */
59812
59813 function marked(src, opt, callback) {
59814   if (callback || typeof opt === 'function') {
59815     if (!callback) {
59816       callback = opt;
59817       opt = null;
59818     }
59819
59820     opt = merge({}, marked.defaults, opt || {});
59821
59822     var highlight = opt.highlight
59823       , tokens
59824       , pending
59825       , i = 0;
59826
59827     try {
59828       tokens = Lexer.lex(src, opt);
59829     } catch (e) {
59830       return callback(e);
59831     }
59832
59833     pending = tokens.length;
59834
59835     var done = function(err) {
59836       if (err) {
59837         opt.highlight = highlight;
59838         return callback(err);
59839       }
59840
59841       var out;
59842
59843       try {
59844         out = Parser.parse(tokens, opt);
59845       } catch (e) {
59846         err = e;
59847       }
59848
59849       opt.highlight = highlight;
59850
59851       return err
59852         ? callback(err)
59853         : callback(null, out);
59854     };
59855
59856     if (!highlight || highlight.length < 3) {
59857       return done();
59858     }
59859
59860     delete opt.highlight;
59861
59862     if (!pending) return done();
59863
59864     for (; i < tokens.length; i++) {
59865       (function(token) {
59866         if (token.type !== 'code') {
59867           return --pending || done();
59868         }
59869         return highlight(token.text, token.lang, function(err, code) {
59870           if (err) return done(err);
59871           if (code == null || code === token.text) {
59872             return --pending || done();
59873           }
59874           token.text = code;
59875           token.escaped = true;
59876           --pending || done();
59877         });
59878       })(tokens[i]);
59879     }
59880
59881     return;
59882   }
59883   try {
59884     if (opt) opt = merge({}, marked.defaults, opt);
59885     return Parser.parse(Lexer.lex(src, opt), opt);
59886   } catch (e) {
59887     e.message += '\nPlease report this to https://github.com/chjj/marked.';
59888     if ((opt || marked.defaults).silent) {
59889       return '<p>An error occured:</p><pre>'
59890         + escape(e.message + '', true)
59891         + '</pre>';
59892     }
59893     throw e;
59894   }
59895 }
59896
59897 /**
59898  * Options
59899  */
59900
59901 marked.options =
59902 marked.setOptions = function(opt) {
59903   merge(marked.defaults, opt);
59904   return marked;
59905 };
59906
59907 marked.defaults = {
59908   gfm: true,
59909   tables: true,
59910   breaks: false,
59911   pedantic: false,
59912   sanitize: false,
59913   sanitizer: null,
59914   mangle: true,
59915   smartLists: false,
59916   silent: false,
59917   highlight: null,
59918   langPrefix: 'lang-',
59919   smartypants: false,
59920   headerPrefix: '',
59921   renderer: new Renderer,
59922   xhtml: false
59923 };
59924
59925 /**
59926  * Expose
59927  */
59928
59929 marked.Parser = Parser;
59930 marked.parser = Parser.parse;
59931
59932 marked.Renderer = Renderer;
59933
59934 marked.Lexer = Lexer;
59935 marked.lexer = Lexer.lex;
59936
59937 marked.InlineLexer = InlineLexer;
59938 marked.inlineLexer = InlineLexer.output;
59939
59940 marked.parse = marked;
59941
59942 {
59943   module.exports = marked;
59944 }
59945
59946 }).call(function() {
59947   return this || (typeof window !== 'undefined' ? window : commonjsGlobal);
59948 }());
59949 });
59950
59951 function pointBox(loc, context) {
59952     var rect = context.surfaceRect();
59953     var point = context.curtainProjection(loc);
59954     return {
59955         left: point[0] + rect.left - 40,
59956         top: point[1] + rect.top - 60,
59957         width: 80,
59958         height: 90
59959     };
59960 }
59961
59962
59963 function pad$1(locOrBox, padding, context) {
59964     var box;
59965     if (locOrBox instanceof Array) {
59966         var rect = context.surfaceRect();
59967         var point = context.curtainProjection(locOrBox);
59968         box = {
59969             left: point[0] + rect.left,
59970             top: point[1] + rect.top
59971         };
59972     } else {
59973         box = locOrBox;
59974     }
59975
59976     return {
59977         left: box.left - padding,
59978         top: box.top - padding,
59979         width: (box.width || 0) + 2 * padding,
59980         height: (box.width || 0) + 2 * padding
59981     };
59982 }
59983
59984
59985 function icon(name, svgklass) {
59986     return '<svg class="icon ' + (svgklass || '') + '">' +
59987          '<use xlink:href="' + name + '"></use></svg>';
59988 }
59989
59990
59991 function slugify(text$$1) {
59992     return text$$1.toString().toLowerCase()
59993         .replace(/\s+/g, '-')           // Replace spaces with -
59994         .replace(/[^\w\-]+/g, '')       // Remove all non-word chars
59995         .replace(/\-\-+/g, '-')         // Replace multiple - with single -
59996         .replace(/^-+/, '')             // Trim - from start of text
59997         .replace(/-+$/, '');            // Trim - from end of text
59998 }
59999
60000
60001 // console warning for missing walkthrough names
60002 var missingStrings = {};
60003 function checkKey(key, text$$1) {
60004     if (t(key, { default: undefined}) === undefined) {
60005         if (missingStrings.hasOwnProperty(key)) return;  // warn once
60006         missingStrings[key] = text$$1;
60007         var missing = key + ': ' + text$$1;
60008         if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
60009     }
60010 }
60011
60012
60013 function localize(obj) {
60014     var key;
60015
60016     // Assign name if entity has one..
60017     var name = obj.tags && obj.tags.name;
60018     if (name) {
60019         key = 'intro.graph.name.' + slugify(name);
60020         obj.tags.name = t(key, { default: name });
60021         checkKey(key, name);
60022     }
60023
60024     // Assign street name if entity has one..
60025     var street = obj.tags && obj.tags['addr:street'];
60026     if (street) {
60027         key = 'intro.graph.name.' + slugify(street);
60028         obj.tags['addr:street'] = t(key, { default: street });
60029         checkKey(key, street);
60030
60031         // Add address details common across walkthrough..
60032         var addrTags = [
60033             'block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood',
60034             'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'
60035         ];
60036         addrTags.forEach(function(k) {
60037             var key = 'intro.graph.' + k,
60038                 tag = 'addr:' + k,
60039                 val = obj.tags && obj.tags[tag],
60040                 str = t(key, { default: val });
60041
60042             if (str) {
60043                 if (str.match(/^<.*>$/) !== null) {
60044                     delete obj.tags[tag];
60045                 } else {
60046                     obj.tags[tag] = str;
60047                 }
60048             }
60049         });
60050     }
60051
60052     return obj;
60053 }
60054
60055
60056 // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
60057 function isMostlySquare(points) {
60058     // note: uses 15 here instead of the 12 from actionOrthogonalize because
60059     // actionOrthogonalize can actually straighten some larger angles as it iterates
60060     var threshold$$1 = 15, // degrees within right or straight
60061         lowerBound = Math.cos((90 - threshold$$1) * Math.PI / 180),  // near right
60062         upperBound = Math.cos(threshold$$1 * Math.PI / 180),         // near straight
60063         mag;
60064
60065     for (var i = 0; i < points.length; i++) {
60066         mag = Math.abs(normalizedDotProduct(i, points));
60067         if (mag > lowerBound && mag < upperBound) {
60068             return false;
60069         }
60070     }
60071
60072     return true;
60073
60074
60075     function normalizedDotProduct(i, points) {
60076         var a = points[(i - 1 + points.length) % points.length],
60077             b = points[i],
60078             c = points[(i + 1) % points.length],
60079             p = subtractPoints(a, b),
60080             q = subtractPoints(c, b);
60081
60082         p = normalizePoint(p);
60083         q = normalizePoint(q);
60084
60085         return p[0] * q[0] + p[1] * q[1];
60086
60087
60088         function subtractPoints(a, b) {
60089             return [a[0] - b[0], a[1] - b[1]];
60090         }
60091
60092         function normalizePoint(point) {
60093             var vector = [0, 0];
60094             var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
60095             if (length !== 0) {
60096                 vector[0] = point[0] / length;
60097                 vector[1] = point[1] / length;
60098             }
60099             return vector;
60100         }
60101     }
60102 }
60103
60104
60105 function selectMenuItem(operation) {
60106     var selector$$1 = '.edit-menu .edit-menu-item-' + operation +
60107         ', .radial-menu .radial-menu-item-' + operation;
60108     return select(selector$$1);
60109 }
60110
60111
60112 function transitionTime(point1, point2) {
60113     var distance$$1 = geoSphericalDistance(point1, point2);
60114     if (distance$$1 === 0)
60115         return 0;
60116     else if (distance$$1 < 80)
60117         return 500;
60118     else
60119         return 1000;
60120 }
60121
60122 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"}}};
60123
60124 // toggles the visibility of ui elements, using a combination of the
60125 // hide class, which sets display=none, and a d3 transition for opacity.
60126 // this will cause blinking when called repeatedly, so check that the
60127 // value actually changes between calls.
60128 function uiToggle(show, callback) {
60129     return function(selection$$1) {
60130         selection$$1
60131             .style('opacity', show ? 0 : 1)
60132             .classed('hide', false)
60133             .transition()
60134             .style('opacity', show ? 1 : 0)
60135             .on('end', function() {
60136                 select(this)
60137                     .classed('hide', !show)
60138                     .style('opacity', null);
60139                 if (callback) callback.apply(this);
60140             });
60141     };
60142 }
60143
60144 // Tooltips and svg mask used to highlight certain features
60145 function uiCurtain() {
60146
60147     var surface = select(null),
60148         tooltip = select(null),
60149         darkness = select(null);
60150
60151     function curtain(selection$$1) {
60152         surface = selection$$1
60153             .append('svg')
60154             .attr('id', 'curtain')
60155             .style('z-index', 1000)
60156             .style('pointer-events', 'none')
60157             .style('position', 'absolute')
60158             .style('top', 0)
60159             .style('left', 0);
60160
60161         darkness = surface.append('path')
60162             .attr('x', 0)
60163             .attr('y', 0)
60164             .attr('class', 'curtain-darkness');
60165
60166         select(window).on('resize.curtain', resize);
60167
60168         tooltip = selection$$1.append('div')
60169             .attr('class', 'tooltip')
60170             .style('z-index', 1002);
60171
60172         tooltip
60173             .append('div')
60174             .attr('class', 'tooltip-arrow');
60175
60176         tooltip
60177             .append('div')
60178             .attr('class', 'tooltip-inner');
60179
60180         resize();
60181
60182
60183         function resize() {
60184             surface
60185                 .attr('width', window.innerWidth)
60186                 .attr('height', window.innerHeight);
60187             curtain.cut(darkness.datum());
60188         }
60189     }
60190
60191
60192     /**
60193      * Reveal cuts the curtain to highlight the given box,
60194      * and shows a tooltip with instructions next to the box.
60195      *
60196      * @param  {String|ClientRect} [box]   box used to cut the curtain
60197      * @param  {String}    [text]          text for a tooltip
60198      * @param  {Object}    [options]
60199      * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
60200      * @param  {integer}   [options.duration]        transition time in milliseconds
60201      * @param  {string}    [options.buttonText]      if set, create a button with this text label
60202      * @param  {function}  [options.buttonCallback]  if set, the callback for the button
60203      * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
60204      */
60205     curtain.reveal = function(box, text$$1, options) {
60206         if (typeof box === 'string') {
60207             box = select(box).node();
60208         }
60209         if (box && box.getBoundingClientRect) {
60210             box = copyBox(box.getBoundingClientRect());
60211         }
60212
60213         options = options || {};
60214
60215         var tooltipBox;
60216         if (options.tooltipBox) {
60217             tooltipBox = options.tooltipBox;
60218             if (typeof tooltipBox === 'string') {
60219                 tooltipBox = select(tooltipBox).node();
60220             }
60221             if (tooltipBox && tooltipBox.getBoundingClientRect) {
60222                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
60223             }
60224         } else {
60225             tooltipBox = box;
60226         }
60227
60228         if (tooltipBox && text$$1) {
60229             // pseudo markdown bold text for the instruction section..
60230             var parts = text$$1.split('**');
60231             var html$$1 = parts[0] ? '<span>' + parts[0] + '</span>' : '';
60232             if (parts[1]) {
60233                 html$$1 += '<span class="instruction">' + parts[1] + '</span>';
60234             }
60235
60236             html$$1 = html$$1.replace(/\*(.*?)\*/g, '<em>$1</em>');   // emphasis
60237             html$$1 = html$$1.replace(/\{br\}/g, '<br/><br/>');       // linebreak
60238
60239             if (options.buttonText && options.buttonCallback) {
60240                 html$$1 += '<div class="button-section">' +
60241                     '<button href="#" class="button action col8">' + options.buttonText + '</button></div>';
60242             }
60243
60244             var classes = 'curtain-tooltip tooltip in ' + (options.tooltipClass || '');
60245             tooltip
60246                 .classed(classes, true)
60247                 .selectAll('.tooltip-inner')
60248                 .html(html$$1);
60249
60250             if (options.buttonText && options.buttonCallback) {
60251                 var button = tooltip.selectAll('.button-section .button.action');
60252                 button
60253                     .on('click', function() {
60254                         event.preventDefault();
60255                         options.buttonCallback();
60256                     });
60257             }
60258
60259             var tip = copyBox(tooltip.node().getBoundingClientRect()),
60260                 w = window.innerWidth,
60261                 h = window.innerHeight,
60262                 tooltipWidth = 200,
60263                 tooltipArrow = 5,
60264                 side, pos;
60265
60266
60267             // hack: this will have bottom placement,
60268             // so need to reserve extra space for the tooltip illustration.
60269             if (options.tooltipClass === 'intro-mouse') {
60270                 tip.height += 80;
60271             }
60272
60273             // trim box dimensions to just the portion that fits in the window..
60274             if (tooltipBox.top + tooltipBox.height > h) {
60275                 tooltipBox.height -= (tooltipBox.top + tooltipBox.height - h);
60276             }
60277             if (tooltipBox.left + tooltipBox.width > w) {
60278                 tooltipBox.width -= (tooltipBox.left + tooltipBox.width - w);
60279             }
60280
60281             // determine tooltip placement..
60282
60283             if (tooltipBox.top + tooltipBox.height < 100) {
60284                 // tooltip below box..
60285                 side = 'bottom';
60286                 pos = [
60287                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
60288                     tooltipBox.top + tooltipBox.height
60289                 ];
60290
60291             } else if (tooltipBox.top > h - 140) {
60292                 // tooltip above box..
60293                 side = 'top';
60294                 pos = [
60295                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
60296                     tooltipBox.top - tip.height
60297                 ];
60298
60299             } else {
60300                 // tooltip to the side of the tooltipBox..
60301                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
60302
60303                 if (textDirection === 'rtl') {
60304                     if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
60305                         side = 'right';
60306                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
60307
60308                     } else {
60309                         side = 'left';
60310                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
60311                     }
60312
60313                 } else {
60314                     if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
60315                         side = 'left';
60316                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
60317                     }
60318                     else {
60319                         side = 'right';
60320                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
60321                     }
60322                 }
60323             }
60324
60325             if (options.duration !== 0 || !tooltip.classed(side)) {
60326                 tooltip.call(uiToggle(true));
60327             }
60328
60329             tooltip
60330                 .style('top', pos[1] + 'px')
60331                 .style('left', pos[0] + 'px')
60332                 .attr('class', classes + ' ' + side);
60333
60334
60335             // shift tooltip-inner if it is very close to the top or bottom edge
60336             // (doesn't affect the placement of the tooltip-arrow)
60337             var shiftY = 0;
60338             if (side === 'left' || side === 'right') {
60339                 if (pos[1] < 60) {
60340                     shiftY = 60 - pos[1];
60341                 }
60342                 else if (pos[1] + tip.height > h - 100) {
60343                     shiftY = h - pos[1] - tip.height - 100;
60344                 }
60345             }
60346             tooltip.selectAll('.tooltip-inner')
60347                 .style('top', shiftY + 'px');
60348
60349         } else {
60350             tooltip
60351                 .classed('in', false)
60352                 .call(uiToggle(false));
60353         }
60354
60355         curtain.cut(box, options.duration);
60356
60357         return tooltip;
60358     };
60359
60360
60361     curtain.cut = function(datum, duration) {
60362         darkness.datum(datum)
60363             .interrupt();
60364
60365         var selection$$1;
60366         if (duration === 0) {
60367             selection$$1 = darkness;
60368         } else {
60369             selection$$1 = darkness
60370                 .transition()
60371                 .duration(duration || 600)
60372                 .ease(linear$1);
60373         }
60374
60375         selection$$1
60376             .attr('d', function(d) {
60377                 var string = 'M 0,0 L 0,' + window.innerHeight + ' L ' +
60378                     window.innerWidth + ',' + window.innerHeight + 'L' +
60379                     window.innerWidth + ',0 Z';
60380
60381                 if (!d) return string;
60382                 return string + 'M' +
60383                     d.left + ',' + d.top + 'L' +
60384                     d.left + ',' + (d.top + d.height) + 'L' +
60385                     (d.left + d.width) + ',' + (d.top + d.height) + 'L' +
60386                     (d.left + d.width) + ',' + (d.top) + 'Z';
60387
60388             });
60389     };
60390
60391
60392     curtain.remove = function() {
60393         surface.remove();
60394         tooltip.remove();
60395         select(window).on('resize.curtain', null);
60396     };
60397
60398
60399     // ClientRects are immutable, so copy them to an object,
60400     // in case we need to trim the height/width.
60401     function copyBox(src) {
60402         return {
60403             top: src.top,
60404             right: src.right,
60405             bottom: src.bottom,
60406             left: src.left,
60407             width: src.width,
60408             height: src.height
60409         };
60410     }
60411
60412
60413     return curtain;
60414 }
60415
60416 function uiIntroWelcome(context, reveal) {
60417     var dispatch$$1 = dispatch('done'),
60418         listener = clickListener();
60419
60420     var chapter = {
60421         title: 'intro.welcome.title'
60422     };
60423
60424
60425     function welcome() {
60426         context.map().centerZoom([-85.63591, 41.94285], 19);
60427         reveal('.intro-nav-wrap .chapter-welcome',
60428             t('intro.welcome.welcome'),
60429             { buttonText: t('intro.ok'), buttonCallback: practice }
60430         );
60431     }
60432
60433     function practice() {
60434         reveal('.intro-nav-wrap .chapter-welcome',
60435             t('intro.welcome.practice'),
60436             { buttonText: t('intro.ok'), buttonCallback: words }
60437         );
60438     }
60439
60440     function words() {
60441         reveal('.intro-nav-wrap .chapter-welcome',
60442             t('intro.welcome.words'),
60443             { buttonText: t('intro.ok'), buttonCallback: mouse$$1 }
60444         );
60445     }
60446
60447
60448     function mouse$$1() {
60449         reveal('.intro-nav-wrap .chapter-welcome',
60450             t('intro.welcome.mouse'),
60451             { buttonText: t('intro.ok'), buttonCallback: leftClick }
60452         );
60453     }
60454
60455
60456     function leftClick() {
60457         var counter = 0,
60458             times = 5;
60459
60460         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
60461             t('intro.welcome.leftclick', { num: times }),
60462             { tooltipClass: 'intro-mouse' }
60463         );
60464
60465         tooltip.selectAll('.tooltip-inner')
60466             .insert('svg', 'span')
60467             .attr('class', 'tooltip-illustration')
60468             .append('use')
60469             .attr('xlink:href', '#walkthrough-mouse');
60470
60471         tooltip
60472             .append('div')
60473             .attr('class', 'counter');
60474
60475         tooltip.call(listener);
60476
60477         listener.on('click', function(which) {
60478             if (which === 'left') {
60479                 select('.curtain-tooltip.intro-mouse .counter')
60480                     .text(String(++counter));
60481
60482                 if (counter === times) {
60483                     window.setTimeout(function() { continueTo(rightClick); }, 1000);
60484                 }
60485             }
60486         });
60487
60488         function continueTo(nextStep) {
60489             listener.on('click', null);
60490             tooltip.call(listener.off);
60491             tooltip.select('.counter').remove();
60492             nextStep();
60493         }
60494     }
60495
60496
60497     function rightClick() {
60498         var counter = 0,
60499             times = 5;
60500
60501         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
60502             t('intro.welcome.rightclick', { num: times }),
60503             { tooltipClass: 'intro-mouse' }
60504         );
60505
60506         tooltip.selectAll('.tooltip-inner')
60507             .insert('svg', 'span')
60508             .attr('class', 'tooltip-illustration')
60509             .append('use')
60510             .attr('xlink:href', '#walkthrough-mouse');
60511
60512         tooltip
60513             .append('div')
60514             .attr('class', 'counter');
60515
60516         tooltip.call(listener);
60517
60518         listener.on('click', function(which) {
60519             if (which === 'right') {
60520                 select('.curtain-tooltip.intro-mouse .counter')
60521                     .text(String(++counter));
60522
60523                 if (counter === times) {
60524                     window.setTimeout(function() { continueTo(chapters); }, 1000);
60525                 }
60526             }
60527         });
60528
60529         function continueTo(nextStep) {
60530             listener.on('click', null);
60531             tooltip.call(listener.off);
60532             tooltip.select('.counter').remove();
60533             nextStep();
60534         }
60535     }
60536
60537
60538     function chapters() {
60539         dispatch$$1.call('done');
60540         reveal('.intro-nav-wrap .chapter-navigation',
60541             t('intro.welcome.chapters', { next: t('intro.navigation.title') })
60542         );
60543     }
60544
60545
60546     chapter.enter = function() {
60547         welcome();
60548     };
60549
60550
60551     chapter.exit = function() {
60552         listener.off();
60553     };
60554
60555
60556     chapter.restart = function() {
60557         chapter.exit();
60558         chapter.enter();
60559     };
60560
60561
60562     return utilRebind(chapter, dispatch$$1, 'on');
60563 }
60564
60565
60566
60567 function clickListener() {
60568     var dispatch$$1 = dispatch('click'),
60569         minTime = 120,
60570         tooltip = select(null),
60571         down = {};
60572
60573     // `down` keeps track of which buttons/keys are down.
60574     // Setting a property in `down` happens immediately.
60575     // Unsetting a property in `down` is delayed because
60576     //   on Windows a contextmenu event happens after keyup/mouseup
60577
60578     function keydown() {
60579         if (event.keyCode === 93)  {   // context menu
60580             event.preventDefault();
60581             event.stopPropagation();
60582             down.menu = event.timeStamp;
60583             tooltip.classed('rightclick', true);
60584         }
60585     }
60586
60587
60588     function keyup() {
60589         if (event.keyCode === 93)  {   // context menu
60590             event.preventDefault();
60591             event.stopPropagation();
60592             var endTime = event.timeStamp,
60593                 startTime = down.menu || endTime,
60594                 delay = (endTime - startTime < minTime) ? minTime : 0;
60595
60596             window.setTimeout(function() {
60597                 tooltip.classed('rightclick', false);
60598                 down.menu = undefined;  // delayed, for Windows
60599             }, delay);
60600
60601             dispatch$$1.call('click', this, 'right');
60602         }
60603     }
60604
60605
60606     function mousedown() {
60607         var button = event.button;
60608         if (button === 0 && !event.ctrlKey) {
60609             tooltip.classed('leftclick', true);
60610         } else if (button === 2) {
60611             tooltip.classed('rightclick', true);
60612         }
60613         down[button] = event.timeStamp;
60614     }
60615
60616
60617     function mouseup() {
60618         var button = event.button,
60619             endTime = event.timeStamp,
60620             startTime = down[button] || endTime,
60621             delay = (endTime - startTime < minTime) ? minTime : 0;
60622
60623         if (button === 0 && !event.ctrlKey) {
60624             window.setTimeout(function() {
60625                 tooltip.classed('leftclick', false);
60626                 down[button] = undefined;  // delayed, for Windows
60627             }, delay);
60628
60629             dispatch$$1.call('click', this, 'left');
60630
60631         } else if (button === 2) {
60632             window.setTimeout(function() {
60633                 tooltip.classed('rightclick', false);
60634                 down[button] = undefined;  // delayed, for Windows
60635             }, delay);
60636
60637             dispatch$$1.call('click', this, 'right');
60638
60639         } else {
60640             window.setTimeout(function() {
60641                 down[button] = undefined;  // delayed, for Windows
60642             }, delay);
60643         }
60644     }
60645
60646
60647     function contextmenu() {
60648         event.preventDefault();
60649         event.stopPropagation();
60650         if (!down[2] && !down.menu) {
60651             tooltip.classed('rightclick', true);
60652             window.setTimeout(function() {
60653                 tooltip.classed('rightclick', false);
60654             }, minTime);
60655             dispatch$$1.call('click', this, 'right');
60656         }
60657     }
60658
60659
60660     var behavior = function(selection$$1) {
60661         tooltip = selection$$1;
60662         down = {};
60663
60664         select(window)
60665             .on('keydown.intro', keydown)
60666             .on('keyup.intro', keyup)
60667             .on('mousedown.intro', mousedown)
60668             .on('mouseup.intro', mouseup)
60669             .on('contextmenu.intro', contextmenu);
60670     };
60671
60672
60673     behavior.off = function() {
60674         select(window)
60675             .on('keydown.intro', null)
60676             .on('keyup.intro', null)
60677             .on('mousedown.intro', null)
60678             .on('mouseup.intro', null)
60679             .on('contextmenu.intro', null);
60680
60681         tooltip
60682             .classed('leftclick', false)
60683             .classed('rightclick', false);
60684     };
60685
60686     return utilRebind(behavior, dispatch$$1, 'on');
60687 }
60688
60689 function uiIntroNavigation(context, reveal) {
60690     var dispatch$$1 = dispatch('done'),
60691         timeouts = [],
60692         hallId = 'n2061',
60693         townHall = [-85.63591, 41.94285],
60694         springStreetId = 'w397',
60695         springStreetEndId = 'n1834',
60696         springStreet = [-85.63582, 41.94255],
60697         onewayField = context.presets().field('oneway'),
60698         maxspeedField = context.presets().field('maxspeed');
60699
60700
60701     var chapter = {
60702         title: 'intro.navigation.title'
60703     };
60704
60705
60706     function timeout(f, t$$1) {
60707         timeouts.push(window.setTimeout(f, t$$1));
60708     }
60709
60710
60711     function eventCancel() {
60712         event.stopPropagation();
60713         event.preventDefault();
60714     }
60715
60716
60717     function isTownHallSelected() {
60718         var ids = context.selectedIDs();
60719         return ids.length === 1 && ids[0] === hallId;
60720     }
60721
60722
60723     function dragMap() {
60724         context.enter(modeBrowse(context));
60725         context.history().reset('initial');
60726
60727         var msec = transitionTime(townHall, context.map().center());
60728         if (msec) { reveal(null, null, { duration: 0 }); }
60729         context.map().zoom(19).centerEase(townHall, msec);
60730
60731         timeout(function() {
60732             var centerStart = context.map().center();
60733
60734             reveal('#surface', t('intro.navigation.drag'));
60735             context.map().on('drawn.intro', function() {
60736                 reveal('#surface', t('intro.navigation.drag'), { duration: 0 });
60737             });
60738
60739             context.map().on('move.intro', function() {
60740                 var centerNow = context.map().center();
60741                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
60742                     context.map().on('move.intro', null);
60743                     timeout(function() { continueTo(zoomMap); }, 3000);
60744                 }
60745             });
60746
60747         }, msec + 100);
60748
60749         function continueTo(nextStep) {
60750             context.map().on('move.intro drawn.intro', null);
60751             nextStep();
60752         }
60753     }
60754
60755
60756     function zoomMap() {
60757         var zoomStart = context.map().zoom();
60758
60759         reveal('#surface',
60760             t('intro.navigation.zoom', {
60761                 plus: icon('#icon-plus', 'pre-text'),
60762                 minus: icon('#icon-minus', 'pre-text')
60763             })
60764         );
60765
60766         context.map().on('drawn.intro', function() {
60767             reveal('#surface',
60768                 t('intro.navigation.zoom', {
60769                     plus: icon('#icon-plus', 'pre-text'),
60770                     minus: icon('#icon-minus', 'pre-text')
60771                 }), { duration: 0 }
60772             );
60773         });
60774
60775         context.map().on('move.intro', function() {
60776             if (context.map().zoom() !== zoomStart) {
60777                 context.map().on('move.intro', null);
60778                 timeout(function() { continueTo(features); }, 3000);
60779             }
60780         });
60781
60782         function continueTo(nextStep) {
60783             context.map().on('move.intro drawn.intro', null);
60784             nextStep();
60785         }
60786     }
60787
60788
60789     function features() {
60790         var onClick = function() { continueTo(pointsLinesAreas); };
60791
60792         reveal('#surface', t('intro.navigation.features'),
60793             { buttonText: t('intro.ok'), buttonCallback: onClick }
60794         );
60795
60796         context.map().on('drawn.intro', function() {
60797             reveal('#surface', t('intro.navigation.features'),
60798                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
60799             );
60800         });
60801
60802         function continueTo(nextStep) {
60803             context.map().on('drawn.intro', null);
60804             nextStep();
60805         }
60806     }
60807
60808     function pointsLinesAreas() {
60809         var onClick = function() { continueTo(nodesWays); };
60810
60811         reveal('#surface', t('intro.navigation.points_lines_areas'),
60812             { buttonText: t('intro.ok'), buttonCallback: onClick }
60813         );
60814
60815         context.map().on('drawn.intro', function() {
60816             reveal('#surface', t('intro.navigation.points_lines_areas'),
60817                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
60818             );
60819         });
60820
60821         function continueTo(nextStep) {
60822             context.map().on('drawn.intro', null);
60823             nextStep();
60824         }
60825     }
60826
60827     function nodesWays() {
60828         var onClick = function() { continueTo(clickTownHall); };
60829
60830         reveal('#surface', t('intro.navigation.nodes_ways'),
60831             { buttonText: t('intro.ok'), buttonCallback: onClick }
60832         );
60833
60834         context.map().on('drawn.intro', function() {
60835             reveal('#surface', t('intro.navigation.nodes_ways'),
60836                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
60837             );
60838         });
60839
60840         function continueTo(nextStep) {
60841             context.map().on('drawn.intro', null);
60842             nextStep();
60843         }
60844     }
60845
60846     function clickTownHall() {
60847         context.enter(modeBrowse(context));
60848         context.history().reset('initial');
60849
60850         reveal(null, null, { duration: 0 });
60851         context.map().zoomEase(19, 500);
60852
60853         timeout(function() {
60854             var entity = context.hasEntity(hallId);
60855             if (!entity) return;
60856             context.map().centerEase(entity.loc, 500);
60857
60858             timeout(function() {
60859                 var entity = context.hasEntity(hallId);
60860                 if (!entity) return;
60861                 var box = pointBox(entity.loc, context);
60862                 reveal(box, t('intro.navigation.click_townhall'));
60863
60864                 context.map().on('move.intro drawn.intro', function() {
60865                     var entity = context.hasEntity(hallId);
60866                     if (!entity) return;
60867                     var box = pointBox(entity.loc, context);
60868                     reveal(box, t('intro.navigation.click_townhall'), { duration: 0 });
60869                 });
60870
60871                 context.on('enter.intro', function() {
60872                     if (isTownHallSelected()) continueTo(selectedTownHall);
60873                 });
60874
60875             }, 550);  // after centerEase
60876
60877         }, 550); // after zoomEase
60878
60879         context.history().on('change.intro', function() {
60880             if (!context.hasEntity(hallId)) {
60881                 continueTo(clickTownHall);
60882             }
60883         });
60884
60885         function continueTo(nextStep) {
60886             context.on('enter.intro', null);
60887             context.map().on('move.intro drawn.intro', null);
60888             context.history().on('change.intro', null);
60889             nextStep();
60890         }
60891     }
60892
60893
60894     function selectedTownHall() {
60895         if (!isTownHallSelected()) return clickTownHall();
60896
60897         var entity = context.hasEntity(hallId);
60898         if (!entity) return clickTownHall();
60899
60900         var box = pointBox(entity.loc, context);
60901         var onClick = function() { continueTo(editorTownHall); };
60902
60903         reveal(box, t('intro.navigation.selected_townhall'),
60904             { buttonText: t('intro.ok'), buttonCallback: onClick }
60905         );
60906
60907         context.map().on('move.intro drawn.intro', function() {
60908             var entity = context.hasEntity(hallId);
60909             if (!entity) return;
60910             var box = pointBox(entity.loc, context);
60911             reveal(box, t('intro.navigation.selected_townhall'),
60912                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
60913             );
60914         });
60915
60916         context.history().on('change.intro', function() {
60917             if (!context.hasEntity(hallId)) {
60918                 continueTo(clickTownHall);
60919             }
60920         });
60921
60922         function continueTo(nextStep) {
60923             context.map().on('move.intro drawn.intro', null);
60924             context.history().on('change.intro', null);
60925             nextStep();
60926         }
60927     }
60928
60929
60930     function editorTownHall() {
60931         if (!isTownHallSelected()) return clickTownHall();
60932
60933         // disallow scrolling
60934         select('.inspector-wrap').on('wheel.intro', eventCancel);
60935
60936         var onClick = function() { continueTo(presetTownHall); };
60937
60938         reveal('.entity-editor-pane',
60939             t('intro.navigation.editor_townhall'),
60940             { buttonText: t('intro.ok'), buttonCallback: onClick }
60941         );
60942
60943         context.on('exit.intro', function() {
60944             continueTo(clickTownHall);
60945         });
60946
60947         context.history().on('change.intro', function() {
60948             if (!context.hasEntity(hallId)) {
60949                 continueTo(clickTownHall);
60950             }
60951         });
60952
60953         function continueTo(nextStep) {
60954             context.on('exit.intro', null);
60955             context.history().on('change.intro', null);
60956             select('.inspector-wrap').on('wheel.intro', null);
60957             nextStep();
60958         }
60959     }
60960
60961
60962     function presetTownHall() {
60963         if (!isTownHallSelected()) return clickTownHall();
60964
60965         // reset pane, in case user happened to change it..
60966         select('.inspector-wrap .panewrap').style('right', '0%');
60967         // disallow scrolling
60968         select('.inspector-wrap').on('wheel.intro', eventCancel);
60969
60970         // preset match, in case the user happened to change it.
60971         var entity = context.entity(context.selectedIDs()[0]);
60972         var preset = context.presets().match(entity, context.graph());
60973
60974         var onClick = function() { continueTo(fieldsTownHall); };
60975
60976         context.on('exit.intro', function() {
60977             continueTo(clickTownHall);
60978         });
60979
60980         context.history().on('change.intro', function() {
60981             if (!context.hasEntity(hallId)) {
60982                 continueTo(clickTownHall);
60983             }
60984         });
60985
60986         reveal('.inspector-body .preset-list-item.inspector-inner',
60987             t('intro.navigation.preset_townhall', { preset: preset.name() }),
60988             { buttonText: t('intro.ok'), buttonCallback: onClick }
60989         );
60990
60991         function continueTo(nextStep) {
60992             context.on('exit.intro', null);
60993             context.history().on('change.intro', null);
60994             select('.inspector-wrap').on('wheel.intro', null);
60995             nextStep();
60996         }
60997     }
60998
60999
61000     function fieldsTownHall() {
61001         if (!isTownHallSelected()) return clickTownHall();
61002
61003         // reset pane, in case user happened to change it..
61004         select('.inspector-wrap .panewrap').style('right', '0%');
61005         // disallow scrolling
61006         select('.inspector-wrap').on('wheel.intro', eventCancel);
61007
61008         var onClick = function() { continueTo(closeTownHall); };
61009
61010         reveal('.inspector-body .inspector-preset',
61011             t('intro.navigation.fields_townhall'),
61012             { buttonText: t('intro.ok'), buttonCallback: onClick }
61013         );
61014
61015         context.on('exit.intro', function() {
61016             continueTo(clickTownHall);
61017         });
61018
61019         context.history().on('change.intro', function() {
61020             if (!context.hasEntity(hallId)) {
61021                 continueTo(clickTownHall);
61022             }
61023         });
61024
61025         function continueTo(nextStep) {
61026             context.on('exit.intro', null);
61027             context.history().on('change.intro', null);
61028             select('.inspector-wrap').on('wheel.intro', null);
61029             nextStep();
61030         }
61031     }
61032
61033
61034     function closeTownHall() {
61035         if (!isTownHallSelected()) return clickTownHall();
61036
61037         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61038         var href = select(selector$$1).attr('href') || '#icon-close';
61039
61040         reveal('.entity-editor-pane',
61041             t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') })
61042         );
61043
61044         context.on('exit.intro', function() {
61045             continueTo(searchStreet);
61046         });
61047
61048         context.history().on('change.intro', function() {
61049             // update the close icon in the tooltip if the user edits something.
61050             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61051             var href = select(selector$$1).attr('href') || '#icon-close';
61052
61053             reveal('.entity-editor-pane',
61054                 t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') }),
61055                 { duration: 0 }
61056             );
61057         });
61058
61059         function continueTo(nextStep) {
61060             context.on('exit.intro', null);
61061             context.history().on('change.intro', null);
61062             nextStep();
61063         }
61064     }
61065
61066
61067     function searchStreet() {
61068         context.enter(modeBrowse(context));
61069         context.history().reset('initial');  // ensure spring street exists
61070
61071         var msec = transitionTime(springStreet, context.map().center());
61072         if (msec) { reveal(null, null, { duration: 0 }); }
61073         context.map().zoom(19).centerEase(springStreet, msec);  // ..and user can see it
61074
61075         timeout(function() {
61076             reveal('.search-header input',
61077                 t('intro.navigation.search_street', { name: t('intro.graph.name.spring-street') })
61078             );
61079
61080             select('.search-header input')
61081                 .on('keyup.intro', checkSearchResult);
61082         }, msec + 100);
61083     }
61084
61085
61086     function checkSearchResult() {
61087         var first = select('.feature-list-item:nth-child(0n+2)'),  // skip "No Results" item
61088             firstName = first.select('.entity-name'),
61089             name = t('intro.graph.name.spring-street');
61090
61091         if (!firstName.empty() && firstName.text() === name) {
61092             reveal(first.node(),
61093                 t('intro.navigation.choose_street', { name: name }),
61094                 { duration: 300 }
61095             );
61096
61097             context.on('exit.intro', function() {
61098                 continueTo(selectedStreet);
61099             });
61100
61101             select('.search-header input')
61102                 .on('keydown.intro', eventCancel, true)
61103                 .on('keyup.intro', null);
61104         }
61105
61106         function continueTo(nextStep) {
61107             context.on('exit.intro', null);
61108             select('.search-header input')
61109                 .on('keydown.intro', null)
61110                 .on('keyup.intro', null);
61111             nextStep();
61112         }
61113     }
61114
61115
61116     function selectedStreet() {
61117         if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
61118             return searchStreet();
61119         }
61120
61121         var onClick = function() { continueTo(editorStreet); };
61122         var entity = context.entity(springStreetEndId);
61123         var box = pointBox(entity.loc, context);
61124         box.height = 500;
61125
61126         reveal(box,
61127             t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
61128             { duration: 600, buttonText: t('intro.ok'), buttonCallback: onClick }
61129         );
61130
61131         timeout(function() {
61132             context.map().on('move.intro drawn.intro', function() {
61133                 var entity = context.hasEntity(springStreetEndId);
61134                 if (!entity) return;
61135                 var box = pointBox(entity.loc, context);
61136                 box.height = 500;
61137                 reveal(box,
61138                     t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
61139                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
61140                 );
61141             });
61142         }, 600);  // after reveal.
61143
61144         context.on('enter.intro', function(mode) {
61145             if (!context.hasEntity(springStreetId)) {
61146                 return continueTo(searchStreet);
61147             }
61148             var ids = context.selectedIDs();
61149             if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
61150                 // keep Spring Street selected..
61151                 context.enter(modeSelect(context, [springStreetId]));
61152             }
61153         });
61154
61155         context.history().on('change.intro', function() {
61156             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
61157                 timeout(function() {
61158                     continueTo(searchStreet);
61159                 }, 300);  // after any transition (e.g. if user deleted intersection)
61160             }
61161         });
61162
61163         function continueTo(nextStep) {
61164             context.map().on('move.intro drawn.intro', null);
61165             context.on('enter.intro', null);
61166             context.history().on('change.intro', null);
61167             nextStep();
61168         }
61169     }
61170
61171
61172     function editorStreet() {
61173         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61174         var href = select(selector$$1).attr('href') || '#icon-close';
61175
61176         reveal('.entity-editor-pane',
61177             t('intro.navigation.editor_street', {
61178                 button: icon(href, 'pre-text'),
61179                 field1: onewayField.label(),
61180                 field2: maxspeedField.label()
61181             })
61182         );
61183
61184         context.on('exit.intro', function() {
61185             continueTo(play);
61186         });
61187
61188         context.history().on('change.intro', function() {
61189             // update the close icon in the tooltip if the user edits something.
61190             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61191             var href = select(selector$$1).attr('href') || '#icon-close';
61192
61193             reveal('.entity-editor-pane',
61194                 t('intro.navigation.editor_street', {
61195                     button: icon(href, 'pre-text'),
61196                     field1: onewayField.label().toLowerCase(),
61197                     field2: maxspeedField.label().toLowerCase()
61198                 }), { duration: 0 }
61199             );
61200         });
61201
61202         function continueTo(nextStep) {
61203             context.on('exit.intro', null);
61204             context.history().on('change.intro', null);
61205             nextStep();
61206         }
61207     }
61208
61209
61210     function play() {
61211         dispatch$$1.call('done');
61212         reveal('#id-container',
61213             t('intro.navigation.play', { next: t('intro.points.title') }), {
61214                 tooltipBox: '.intro-nav-wrap .chapter-point',
61215                 buttonText: t('intro.ok'),
61216                 buttonCallback: function() { reveal('#id-container'); }
61217             }
61218         );
61219     }
61220
61221
61222     chapter.enter = function() {
61223         dragMap();
61224     };
61225
61226
61227     chapter.exit = function() {
61228         timeouts.forEach(window.clearTimeout);
61229         context.on('enter.intro exit.intro', null);
61230         context.map().on('move.intro drawn.intro', null);
61231         context.history().on('change.intro', null);
61232         select('.inspector-wrap').on('wheel.intro', null);
61233         select('.search-header input').on('keydown.intro keyup.intro', null);
61234     };
61235
61236
61237     chapter.restart = function() {
61238         chapter.exit();
61239         chapter.enter();
61240     };
61241
61242
61243     return utilRebind(chapter, dispatch$$1, 'on');
61244 }
61245
61246 function uiIntroPoint(context, reveal) {
61247     var dispatch$$1 = dispatch('done'),
61248         timeouts = [],
61249         intersection = [-85.63279, 41.94394],
61250         building = [-85.632422, 41.944045],
61251         cafePreset = context.presets().item('amenity/cafe'),
61252         pointId = null;
61253
61254
61255     var chapter = {
61256         title: 'intro.points.title'
61257     };
61258
61259
61260     function timeout(f, t$$1) {
61261         timeouts.push(window.setTimeout(f, t$$1));
61262     }
61263
61264
61265     function revealEditMenu(loc, text$$1, options) {
61266         var rect = context.surfaceRect();
61267         var point = context.curtainProjection(loc);
61268         var pad = 40;
61269         var width = 250 + (2 * pad);
61270         var height = 250;
61271         var startX = rect.left + point[0];
61272         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
61273         var box = {
61274             left: left,
61275             top: point[1] + rect.top - 60,
61276             width: width,
61277             height: height
61278         };
61279         reveal(box, text$$1, options);
61280     }
61281
61282
61283     function eventCancel() {
61284         event.stopPropagation();
61285         event.preventDefault();
61286     }
61287
61288
61289     function addPoint() {
61290         context.enter(modeBrowse(context));
61291         context.history().reset('initial');
61292
61293         var msec = transitionTime(intersection, context.map().center());
61294         if (msec) { reveal(null, null, { duration: 0 }); }
61295         context.map().zoom(19).centerEase(intersection, msec);
61296
61297         timeout(function() {
61298             var tooltip = reveal('button.add-point',
61299                 t('intro.points.add_point', { button: icon('#icon-point', 'pre-text') }));
61300
61301             pointId = null;
61302
61303             tooltip.selectAll('.tooltip-inner')
61304                 .insert('svg', 'span')
61305                 .attr('class', 'tooltip-illustration')
61306                 .append('use')
61307                 .attr('xlink:href', '#poi-images');
61308
61309             context.on('enter.intro', function(mode) {
61310                 if (mode.id !== 'add-point') return;
61311                 continueTo(placePoint);
61312             });
61313         }, msec + 100);
61314
61315         function continueTo(nextStep) {
61316             context.on('enter.intro', null);
61317             nextStep();
61318         }
61319     }
61320
61321
61322     function placePoint() {
61323         if (context.mode().id !== 'add-point') {
61324             return chapter.restart();
61325         }
61326
61327         var pointBox$$1 = pad$1(building, 150, context);
61328         reveal(pointBox$$1, t('intro.points.place_point'));
61329
61330         context.map().on('move.intro drawn.intro', function() {
61331             pointBox$$1 = pad$1(building, 150, context);
61332             reveal(pointBox$$1, t('intro.points.place_point'), { duration: 0 });
61333         });
61334
61335         context.on('enter.intro', function(mode) {
61336             if (mode.id !== 'select') return chapter.restart();
61337             pointId = context.mode().selectedIDs()[0];
61338             continueTo(searchPreset);
61339         });
61340
61341         function continueTo(nextStep) {
61342             context.map().on('move.intro drawn.intro', null);
61343             context.on('enter.intro', null);
61344             nextStep();
61345         }
61346     }
61347
61348
61349     function searchPreset() {
61350         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61351             return addPoint();
61352         }
61353
61354         // disallow scrolling
61355         select('.inspector-wrap').on('wheel.intro', eventCancel);
61356
61357         select('.preset-search-input')
61358             .on('keydown.intro', null)
61359             .on('keyup.intro', checkPresetSearch);
61360
61361         reveal('.preset-search-input',
61362             t('intro.points.search_cafe', { preset: cafePreset.name() })
61363         );
61364
61365         context.on('enter.intro', function(mode) {
61366             if (!pointId || !context.hasEntity(pointId)) {
61367                 return continueTo(addPoint);
61368             }
61369
61370             var ids = context.selectedIDs();
61371             if (mode.id !== 'select' || !ids.length || ids[0] !== pointId) {
61372                 // keep the user's point selected..
61373                 context.enter(modeSelect(context, [pointId]));
61374
61375                 // disallow scrolling
61376                 select('.inspector-wrap').on('wheel.intro', eventCancel);
61377
61378                 select('.preset-search-input')
61379                     .on('keydown.intro', null)
61380                     .on('keyup.intro', checkPresetSearch);
61381
61382                 reveal('.preset-search-input',
61383                     t('intro.points.search_cafe', { preset: cafePreset.name() })
61384                 );
61385
61386                 context.history().on('change.intro', null);
61387             }
61388         });
61389
61390
61391         function checkPresetSearch() {
61392             var first = select('.preset-list-item:first-child');
61393
61394             if (first.classed('preset-amenity-cafe')) {
61395                 select('.preset-search-input')
61396                     .on('keydown.intro', eventCancel, true)
61397                     .on('keyup.intro', null);
61398
61399                 reveal(first.select('.preset-list-button').node(),
61400                     t('intro.points.choose_cafe', { preset: cafePreset.name() }),
61401                     { duration: 300 }
61402                 );
61403
61404                 context.history().on('change.intro', function() {
61405                     continueTo(aboutFeatureEditor);
61406                 });
61407             }
61408         }
61409
61410         function continueTo(nextStep) {
61411             context.on('enter.intro', null);
61412             context.history().on('change.intro', null);
61413             select('.inspector-wrap').on('wheel.intro', null);
61414             select('.preset-search-input').on('keydown.intro keyup.intro', null);
61415             nextStep();
61416         }
61417     }
61418
61419
61420     function aboutFeatureEditor() {
61421         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61422             return addPoint();
61423         }
61424
61425         timeout(function() {
61426             reveal('.entity-editor-pane', t('intro.points.feature_editor'), {
61427                 tooltipClass: 'intro-points-describe',
61428                 buttonText: t('intro.ok'),
61429                 buttonCallback: function() { continueTo(addName); }
61430             });
61431         }, 400);
61432
61433         context.on('exit.intro', function() {
61434             // if user leaves select mode here, just continue with the tutorial.
61435             continueTo(reselectPoint);
61436         });
61437
61438         function continueTo(nextStep) {
61439             context.on('exit.intro', null);
61440             nextStep();
61441         }
61442     }
61443
61444
61445     function addName() {
61446         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61447             return addPoint();
61448         }
61449
61450         // reset pane, in case user happened to change it..
61451         select('.inspector-wrap .panewrap').style('right', '0%');
61452
61453         timeout(function() {
61454             // It's possible for the user to add a name in a previous step..
61455             // If so, don't tell them to add the name in this step.
61456             // Give them an OK button instead.
61457             var entity = context.entity(pointId);
61458             if (entity.tags.name) {
61459                 var tooltip = reveal('.entity-editor-pane', t('intro.points.add_name'), {
61460                     tooltipClass: 'intro-points-describe',
61461                     buttonText: t('intro.ok'),
61462                     buttonCallback: function() { continueTo(addCloseEditor); }
61463                 });
61464                 tooltip.select('.instruction').style('display', 'none');
61465
61466             } else {
61467                 reveal('.entity-editor-pane', t('intro.points.add_name'),
61468                     { tooltipClass: 'intro-points-describe' }
61469                 );
61470             }
61471         }, 400);
61472
61473         context.history().on('change.intro', function() {
61474             continueTo(addCloseEditor);
61475         });
61476
61477         context.on('exit.intro', function() {
61478             // if user leaves select mode here, just continue with the tutorial.
61479             continueTo(reselectPoint);
61480         });
61481
61482         function continueTo(nextStep) {
61483             context.on('exit.intro', null);
61484             context.history().on('change.intro', null);
61485             nextStep();
61486         }
61487     }
61488
61489
61490     function addCloseEditor() {
61491         // reset pane, in case user happened to change it..
61492         select('.inspector-wrap .panewrap').style('right', '0%');
61493
61494         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61495         var href = select(selector$$1).attr('href') || '#icon-close';
61496
61497         context.on('exit.intro', function() {
61498             continueTo(reselectPoint);
61499         });
61500
61501         reveal('.entity-editor-pane',
61502             t('intro.points.add_close', { button: icon(href, 'pre-text') })
61503         );
61504
61505         function continueTo(nextStep) {
61506             context.on('exit.intro', null);
61507             nextStep();
61508         }
61509     }
61510
61511
61512     function reselectPoint() {
61513         if (!pointId) return chapter.restart();
61514         var entity = context.hasEntity(pointId);
61515         if (!entity) return chapter.restart();
61516
61517         // make sure it's still a cafe, in case user somehow changed it..
61518         var oldPreset = context.presets().match(entity, context.graph());
61519         context.replace(actionChangePreset(pointId, oldPreset, cafePreset));
61520
61521         context.enter(modeBrowse(context));
61522
61523         var msec = transitionTime(entity.loc, context.map().center());
61524         if (msec) { reveal(null, null, { duration: 0 }); }
61525         context.map().centerEase(entity.loc, msec);
61526
61527         timeout(function() {
61528             var box = pointBox(entity.loc, context);
61529             reveal(box, t('intro.points.reselect'), { duration: 600 });
61530
61531             timeout(function() {
61532                 context.map().on('move.intro drawn.intro', function() {
61533                     var entity = context.hasEntity(pointId);
61534                     if (!entity) return chapter.restart();
61535                     var box = pointBox(entity.loc, context);
61536                     reveal(box, t('intro.points.reselect'), { duration: 0 });
61537                 });
61538             }, 600); // after reveal..
61539
61540             context.on('enter.intro', function(mode) {
61541                 if (mode.id !== 'select') return;
61542                 continueTo(updatePoint);
61543             });
61544
61545         }, msec + 100);
61546
61547         function continueTo(nextStep) {
61548             context.map().on('move.intro drawn.intro', null);
61549             context.on('enter.intro', null);
61550             nextStep();
61551         }
61552     }
61553
61554
61555     function updatePoint() {
61556         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61557             return continueTo(reselectPoint);
61558         }
61559
61560         // reset pane, in case user happened to untag the point..
61561         select('.inspector-wrap .panewrap').style('right', '0%');
61562
61563         context.on('exit.intro', function() {
61564             continueTo(reselectPoint);
61565         });
61566
61567         context.history().on('change.intro', function() {
61568             continueTo(updateCloseEditor);
61569         });
61570
61571         timeout(function() {
61572             reveal('.entity-editor-pane', t('intro.points.update'),
61573                 { tooltipClass: 'intro-points-describe' }
61574             );
61575         }, 400);
61576
61577         function continueTo(nextStep) {
61578             context.on('exit.intro', null);
61579             context.history().on('change.intro', null);
61580             nextStep();
61581         }
61582     }
61583
61584
61585     function updateCloseEditor() {
61586         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61587             return continueTo(reselectPoint);
61588         }
61589
61590         // reset pane, in case user happened to change it..
61591         select('.inspector-wrap .panewrap').style('right', '0%');
61592
61593         context.on('exit.intro', function() {
61594             continueTo(rightClickPoint);
61595         });
61596
61597         timeout(function() {
61598             reveal('.entity-editor-pane',
61599                 t('intro.points.update_close', { button: icon('#icon-apply', 'pre-text') })
61600             );
61601         }, 500);
61602
61603         function continueTo(nextStep) {
61604             context.on('exit.intro', null);
61605             nextStep();
61606         }
61607     }
61608
61609
61610     function rightClickPoint() {
61611         if (!pointId) return chapter.restart();
61612         var entity = context.hasEntity(pointId);
61613         if (!entity) return chapter.restart();
61614
61615         context.enter(modeBrowse(context));
61616
61617         var box = pointBox(entity.loc, context);
61618         reveal(box, t('intro.points.rightclick'), { duration: 600 });
61619
61620         timeout(function() {
61621             context.map().on('move.intro drawn.intro', function() {
61622                 var entity = context.hasEntity(pointId);
61623                 if (!entity) return chapter.restart();
61624                 var box = pointBox(entity.loc, context);
61625                 reveal(box, t('intro.points.rightclick'), { duration: 0 });
61626             });
61627         }, 600); // after reveal
61628
61629         context.on('enter.intro', function(mode) {
61630             if (mode.id !== 'select') return;
61631             var ids = context.selectedIDs();
61632             if (ids.length !== 1 || ids[0] !== pointId) return;
61633
61634             timeout(function() {
61635                 var node = selectMenuItem('delete').node();
61636                 if (!node) return;
61637                 continueTo(enterDelete);
61638             }, 300);  // after menu visible
61639         });
61640
61641         function continueTo(nextStep) {
61642             context.on('enter.intro', null);
61643             context.map().on('move.intro drawn.intro', null);
61644             nextStep();
61645         }
61646     }
61647
61648
61649     function enterDelete() {
61650         if (!pointId) return chapter.restart();
61651         var entity = context.hasEntity(pointId);
61652         if (!entity) return chapter.restart();
61653
61654         var node = selectMenuItem('delete').node();
61655         if (!node) { return continueTo(rightClickPoint); }
61656
61657         revealEditMenu(entity.loc,
61658             t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') })
61659         );
61660
61661         timeout(function() {
61662             context.map().on('move.intro drawn.intro', function() {
61663                 revealEditMenu(entity.loc,
61664                     t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') }),
61665                     { duration: 0}
61666                 );
61667             });
61668         }, 300); // after menu visible
61669
61670         context.on('exit.intro', function() {
61671             if (!pointId) return chapter.restart();
61672             var entity = context.hasEntity(pointId);
61673             if (entity) return continueTo(rightClickPoint);  // point still exists
61674         });
61675
61676         context.history().on('change.intro', function(changed) {
61677             if (changed.deleted().length) {
61678                 continueTo(undo);
61679             }
61680         });
61681
61682         function continueTo(nextStep) {
61683             context.map().on('move.intro drawn.intro', null);
61684             context.history().on('change.intro', null);
61685             context.on('exit.intro', null);
61686             nextStep();
61687         }
61688     }
61689
61690
61691     function undo() {
61692         context.history().on('change.intro', function() {
61693             continueTo(play);
61694         });
61695
61696         var iconName = '#icon-' + (textDirection === 'rtl' ? 'redo' : 'undo');
61697         reveal('#bar button.undo-button',
61698             t('intro.points.undo', { button: icon(iconName, 'pre-text') })
61699         );
61700
61701         function continueTo(nextStep) {
61702             context.history().on('change.intro', null);
61703             nextStep();
61704         }
61705     }
61706
61707
61708     function play() {
61709         dispatch$$1.call('done');
61710         reveal('#id-container',
61711             t('intro.points.play', { next: t('intro.areas.title') }), {
61712                 tooltipBox: '.intro-nav-wrap .chapter-area',
61713                 buttonText: t('intro.ok'),
61714                 buttonCallback: function() { reveal('#id-container'); }
61715             }
61716         );
61717     }
61718
61719
61720     chapter.enter = function() {
61721         addPoint();
61722     };
61723
61724
61725     chapter.exit = function() {
61726         timeouts.forEach(window.clearTimeout);
61727         context.on('enter.intro exit.intro', null);
61728         context.map().on('move.intro drawn.intro', null);
61729         context.history().on('change.intro', null);
61730         select('.inspector-wrap').on('wheel.intro', eventCancel);
61731         select('.preset-search-input').on('keydown.intro keyup.intro', null);
61732     };
61733
61734
61735     chapter.restart = function() {
61736         chapter.exit();
61737         chapter.enter();
61738     };
61739
61740
61741     return utilRebind(chapter, dispatch$$1, 'on');
61742 }
61743
61744 function uiIntroArea(context, reveal) {
61745     var dispatch$$1 = dispatch('done'),
61746         playground = [-85.63552, 41.94159],
61747         playgroundPreset = context.presets().item('leisure/playground'),
61748         descriptionField = context.presets().field('description'),
61749         timeouts = [],
61750         areaId;
61751
61752
61753     var chapter = {
61754         title: 'intro.areas.title'
61755     };
61756
61757
61758     function timeout(f, t$$1) {
61759         timeouts.push(window.setTimeout(f, t$$1));
61760     }
61761
61762
61763     function eventCancel() {
61764         event.stopPropagation();
61765         event.preventDefault();
61766     }
61767
61768
61769     function revealPlayground(center, text$$1, options) {
61770         var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
61771         var box = pad$1(center, padding, context);
61772         reveal(box, text$$1, options);
61773     }
61774
61775
61776     function addArea() {
61777         context.enter(modeBrowse(context));
61778         context.history().reset('initial');
61779         areaId = null;
61780
61781         var msec = transitionTime(playground, context.map().center());
61782         if (msec) { reveal(null, null, { duration: 0 }); }
61783         context.map().zoom(19).centerEase(playground, msec);
61784
61785         timeout(function() {
61786             var tooltip = reveal('button.add-area',
61787                 t('intro.areas.add_playground', { button: icon('#icon-area', 'pre-text') }));
61788
61789             tooltip.selectAll('.tooltip-inner')
61790                 .insert('svg', 'span')
61791                 .attr('class', 'tooltip-illustration')
61792                 .append('use')
61793                 .attr('xlink:href', '#landuse-images');
61794
61795             context.on('enter.intro', function(mode) {
61796                 if (mode.id !== 'add-area') return;
61797                 continueTo(startPlayground);
61798             });
61799         }, msec + 100);
61800
61801         function continueTo(nextStep) {
61802             context.on('enter.intro', null);
61803             nextStep();
61804         }
61805     }
61806
61807
61808     function startPlayground() {
61809         if (context.mode().id !== 'add-area') {
61810             return chapter.restart();
61811         }
61812
61813         areaId = null;
61814         context.map().zoomEase(19.5, 500);
61815
61816         timeout(function() {
61817             revealPlayground(playground,
61818                 t('intro.areas.start_playground'), { duration: 250 }
61819             );
61820
61821             timeout(function() {
61822                 context.map().on('move.intro drawn.intro', function() {
61823                     revealPlayground(playground,
61824                         t('intro.areas.start_playground'), { duration: 0 }
61825                     );
61826                 });
61827                 context.on('enter.intro', function(mode) {
61828                     if (mode.id !== 'draw-area') return chapter.restart();
61829                     continueTo(continuePlayground);
61830                 });
61831             }, 250);  // after reveal
61832
61833         }, 550);  // after easing
61834
61835         function continueTo(nextStep) {
61836             context.map().on('move.intro drawn.intro', null);
61837             context.on('enter.intro', null);
61838             nextStep();
61839         }
61840     }
61841
61842
61843     function continuePlayground() {
61844         if (context.mode().id !== 'draw-area') {
61845             return chapter.restart();
61846         }
61847
61848         areaId = null;
61849         revealPlayground(playground,
61850             t('intro.areas.continue_playground', { alt: uiCmd.display('⌥') }),
61851             { duration: 250 }
61852         );
61853
61854         timeout(function() {
61855             context.map().on('move.intro drawn.intro', function() {
61856                 revealPlayground(playground,
61857                     t('intro.areas.continue_playground', { alt: uiCmd.display('⌥') }),
61858                     { duration: 0 }
61859                 );
61860             });
61861         }, 250);  // after reveal
61862
61863         context.on('enter.intro', function(mode) {
61864             if (mode.id === 'draw-area') {
61865                 var entity = context.hasEntity(context.selectedIDs()[0]);
61866                 if (entity && entity.nodes.length >= 6) {
61867                     return continueTo(finishPlayground);
61868                 } else {
61869                     return;
61870                 }
61871             } else if (mode.id === 'select') {
61872                 areaId = context.selectedIDs()[0];
61873                 return continueTo(searchPresets);
61874             } else {
61875                 return chapter.restart();
61876             }
61877         });
61878
61879         function continueTo(nextStep) {
61880             context.map().on('move.intro drawn.intro', null);
61881             context.on('enter.intro', null);
61882             nextStep();
61883         }
61884     }
61885
61886
61887     function finishPlayground() {
61888         if (context.mode().id !== 'draw-area') {
61889             return chapter.restart();
61890         }
61891
61892         areaId = null;
61893         revealPlayground(playground,
61894             t('intro.areas.finish_playground'), { duration: 250 }
61895         );
61896
61897         timeout(function() {
61898             context.map().on('move.intro drawn.intro', function() {
61899                 revealPlayground(playground,
61900                     t('intro.areas.finish_playground'), { duration: 0 }
61901                 );
61902             });
61903         }, 250);  // after reveal
61904
61905         context.on('enter.intro', function(mode) {
61906             if (mode.id === 'draw-area') {
61907                 return;
61908             } else if (mode.id === 'select') {
61909                 areaId = context.selectedIDs()[0];
61910                 return continueTo(searchPresets);
61911             } else {
61912                 return chapter.restart();
61913             }
61914         });
61915
61916         function continueTo(nextStep) {
61917             context.map().on('move.intro drawn.intro', null);
61918             context.on('enter.intro', null);
61919             nextStep();
61920         }
61921     }
61922
61923
61924     function searchPresets() {
61925         if (!areaId || !context.hasEntity(areaId)) {
61926             return addArea();
61927         }
61928         var ids = context.selectedIDs();
61929         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
61930             context.enter(modeSelect(context, [areaId]));
61931         }
61932
61933         // disallow scrolling
61934         select('.inspector-wrap').on('wheel.intro', eventCancel);
61935
61936         timeout(function() {
61937             // reset pane, in case user somehow happened to change it..
61938             select('.inspector-wrap .panewrap').style('right', '-100%');
61939
61940             select('.preset-search-input')
61941                 .on('keydown.intro', null)
61942                 .on('keyup.intro', checkPresetSearch);
61943
61944             reveal('.preset-search-input',
61945                 t('intro.areas.search_playground', { preset: playgroundPreset.name() })
61946             );
61947         }, 400);  // after preset list pane visible..
61948
61949         context.on('enter.intro', function(mode) {
61950             if (!areaId || !context.hasEntity(areaId)) {
61951                 return continueTo(addArea);
61952             }
61953
61954             var ids = context.selectedIDs();
61955             if (mode.id !== 'select' || !ids.length || ids[0] !== areaId) {
61956                 // keep the user's area selected..
61957                 context.enter(modeSelect(context, [areaId]));
61958
61959                 // reset pane, in case user somehow happened to change it..
61960                 select('.inspector-wrap .panewrap').style('right', '-100%');
61961                 // disallow scrolling
61962                 select('.inspector-wrap').on('wheel.intro', eventCancel);
61963
61964                 select('.preset-search-input')
61965                     .on('keydown.intro', null)
61966                     .on('keyup.intro', checkPresetSearch);
61967
61968                 reveal('.preset-search-input',
61969                     t('intro.areas.search_playground', { preset: playgroundPreset.name() })
61970                 );
61971
61972                 context.history().on('change.intro', null);
61973             }
61974         });
61975
61976         function checkPresetSearch() {
61977             var first = select('.preset-list-item:first-child');
61978
61979             if (first.classed('preset-leisure-playground')) {
61980                 reveal(first.select('.preset-list-button').node(),
61981                     t('intro.areas.choose_playground', { preset: playgroundPreset.name() }),
61982                     { duration: 300 }
61983                 );
61984
61985                 select('.preset-search-input')
61986                     .on('keydown.intro', eventCancel, true)
61987                     .on('keyup.intro', null);
61988
61989                 context.history().on('change.intro', function() {
61990                     continueTo(clickAddField);
61991                 });
61992             }
61993         }
61994
61995         function continueTo(nextStep) {
61996             select('.inspector-wrap').on('wheel.intro', null);
61997             context.on('enter.intro', null);
61998             context.history().on('change.intro', null);
61999             select('.preset-search-input').on('keydown.intro keyup.intro', null);
62000             nextStep();
62001         }
62002     }
62003
62004
62005     function clickAddField() {
62006         if (!areaId || !context.hasEntity(areaId)) {
62007             return addArea();
62008         }
62009         var ids = context.selectedIDs();
62010         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62011             return searchPresets();
62012         }
62013
62014         if (!select('.form-field-description').empty()) {
62015             return continueTo(describePlayground);
62016         }
62017
62018         // disallow scrolling
62019         select('.inspector-wrap').on('wheel.intro', eventCancel);
62020
62021         timeout(function() {
62022             // reset pane, in case user somehow happened to change it..
62023             select('.inspector-wrap .panewrap').style('right', '0%');
62024
62025             // It's possible for the user to add a description in a previous step..
62026             // If they did this already, just continue to next step.
62027             var entity = context.entity(areaId);
62028             if (entity.tags.description) {
62029                 return continueTo(play);
62030             }
62031
62032             reveal('.more-fields .combobox-input',
62033                 t('intro.areas.add_field'),
62034                 { duration: 300 }
62035             );
62036
62037             select('.more-fields .combobox-input')
62038                 .on('click.intro', function() {
62039                     continueTo(chooseDescriptionField);
62040                 });
62041         }, 400);  // after editor pane visible
62042
62043         context.on('exit.intro', function() {
62044             return continueTo(searchPresets);
62045         });
62046
62047         function continueTo(nextStep) {
62048             select('.inspector-wrap').on('wheel.intro', null);
62049             select('.more-fields .combobox-input').on('click.intro', null);
62050             context.on('exit.intro', null);
62051             nextStep();
62052         }
62053     }
62054
62055
62056     function chooseDescriptionField() {
62057         if (!areaId || !context.hasEntity(areaId)) {
62058             return addArea();
62059         }
62060         var ids = context.selectedIDs();
62061         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62062             return searchPresets();
62063         }
62064
62065         if (!select('.form-field-description').empty()) {
62066             return continueTo(describePlayground);
62067         }
62068
62069         // Make sure combobox is ready..
62070         if (select('div.combobox').empty()) {
62071             return continueTo(clickAddField);
62072         }
62073         // Watch for the combobox to go away..
62074         var watcher;
62075         watcher = window.setInterval(function() {
62076             if (select('div.combobox').empty()) {
62077                 window.clearInterval(watcher);
62078                 timeout(function() {
62079                     if (select('.form-field-description').empty()) {
62080                         continueTo(retryChooseDescription);
62081                     } else {
62082                         continueTo(describePlayground);
62083                     }
62084                 }, 300);  // after description field added.
62085             }
62086         }, 300);
62087
62088         reveal('div.combobox',
62089             t('intro.areas.choose_field', { field: descriptionField.label() }),
62090             { duration: 300 }
62091         );
62092
62093         context.on('exit.intro', function() {
62094             return continueTo(searchPresets);
62095         });
62096
62097         function continueTo(nextStep) {
62098             if (watcher) window.clearInterval(watcher);
62099             context.on('exit.intro', null);
62100             nextStep();
62101         }
62102     }
62103
62104
62105     function describePlayground() {
62106         if (!areaId || !context.hasEntity(areaId)) {
62107             return addArea();
62108         }
62109         var ids = context.selectedIDs();
62110         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62111             return searchPresets();
62112         }
62113
62114         // reset pane, in case user happened to change it..
62115         select('.inspector-wrap .panewrap').style('right', '0%');
62116
62117         if (select('.form-field-description').empty()) {
62118             return continueTo(retryChooseDescription);
62119         }
62120
62121         context.on('exit.intro', function() {
62122             continueTo(play);
62123         });
62124
62125         reveal('.entity-editor-pane',
62126             t('intro.areas.describe_playground', { button: icon('#icon-apply', 'pre-text') }),
62127             { duration: 300 }
62128         );
62129
62130         function continueTo(nextStep) {
62131             context.on('exit.intro', null);
62132             nextStep();
62133         }
62134     }
62135
62136
62137     function retryChooseDescription() {
62138         if (!areaId || !context.hasEntity(areaId)) {
62139             return addArea();
62140         }
62141         var ids = context.selectedIDs();
62142         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62143             return searchPresets();
62144         }
62145
62146         // reset pane, in case user happened to change it..
62147         select('.inspector-wrap .panewrap').style('right', '0%');
62148
62149         reveal('.entity-editor-pane',
62150             t('intro.areas.retry_add_field', { field: descriptionField.label() }), {
62151             buttonText: t('intro.ok'),
62152             buttonCallback: function() { continueTo(clickAddField); }
62153         });
62154
62155         context.on('exit.intro', function() {
62156             return continueTo(searchPresets);
62157         });
62158
62159         function continueTo(nextStep) {
62160             context.on('exit.intro', null);
62161             nextStep();
62162         }
62163     }
62164
62165
62166     function play() {
62167         dispatch$$1.call('done');
62168         reveal('#id-container',
62169             t('intro.areas.play', { next: t('intro.lines.title') }), {
62170                 tooltipBox: '.intro-nav-wrap .chapter-line',
62171                 buttonText: t('intro.ok'),
62172                 buttonCallback: function() { reveal('#id-container'); }
62173             }
62174         );
62175     }
62176
62177
62178     chapter.enter = function() {
62179         addArea();
62180     };
62181
62182
62183     chapter.exit = function() {
62184         timeouts.forEach(window.clearTimeout);
62185         context.on('enter.intro exit.intro', null);
62186         context.map().on('move.intro drawn.intro', null);
62187         context.history().on('change.intro', null);
62188         select('.inspector-wrap').on('wheel.intro', null);
62189         select('.preset-search-input').on('keydown.intro keyup.intro', null);
62190         select('.more-fields .combobox-input').on('click.intro', null);
62191     };
62192
62193
62194     chapter.restart = function() {
62195         chapter.exit();
62196         chapter.enter();
62197     };
62198
62199
62200     return utilRebind(chapter, dispatch$$1, 'on');
62201 }
62202
62203 function uiIntroLine(context, reveal) {
62204     var dispatch$$1 = dispatch('done'),
62205         timeouts = [],
62206         tulipRoadId = null,
62207         flowerRoadId = 'w646',
62208         tulipRoadStart = [-85.6297754121684, 41.95805253325314],
62209         tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204],
62210         tulipRoadIntersection = [-85.62974496187628, 41.95742515554585],
62211         roadCategory = context.presets().item('category-road'),
62212         residentialPreset = context.presets().item('highway/residential'),
62213         woodRoadId = 'w525',
62214         woodRoadEndId = 'n2862',
62215         woodRoadAddNode = [-85.62390110349587, 41.95397111462291],
62216         woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487],
62217         woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872],
62218         washingtonStreetId = 'w522',
62219         twelfthAvenueId = 'w1',
62220         eleventhAvenueEndId = 'n3550',
62221         twelfthAvenueEndId = 'n5',
62222         washingtonSegmentId = null,
62223         eleventhAvenueEnd = context.entity(eleventhAvenueEndId).loc,
62224         twelfthAvenueEnd = context.entity(twelfthAvenueEndId).loc,
62225         deleteLinesLoc = [-85.6219395542764, 41.95228033922477],
62226         twelfthAvenue = [-85.62219310052491, 41.952505413152956];
62227
62228
62229     var chapter = {
62230         title: 'intro.lines.title'
62231     };
62232
62233
62234     function timeout(f, t$$1) {
62235         timeouts.push(window.setTimeout(f, t$$1));
62236     }
62237
62238
62239     function eventCancel() {
62240         event.stopPropagation();
62241         event.preventDefault();
62242     }
62243
62244
62245     function revealEditMenu(loc, text$$1, options) {
62246         var rect = context.surfaceRect();
62247         var point = context.curtainProjection(loc);
62248         var pad = 40;
62249         var width = 250 + (2 * pad);
62250         var height = 350;
62251         var startX = rect.left + point[0];
62252         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
62253         var box = {
62254             left: left,
62255             top: point[1] + rect.top - 60,
62256             width: width,
62257             height: height
62258         };
62259         reveal(box, text$$1, options);
62260     }
62261
62262
62263     function addLine() {
62264         context.enter(modeBrowse(context));
62265         context.history().reset('initial');
62266
62267         var msec = transitionTime(tulipRoadStart, context.map().center());
62268         if (msec) { reveal(null, null, { duration: 0 }); }
62269         context.map().zoom(18.5).centerEase(tulipRoadStart, msec);
62270
62271         timeout(function() {
62272             var tooltip = reveal('button.add-line',
62273                 t('intro.lines.add_line', { button: icon('#icon-line', 'pre-text') }));
62274
62275             tooltip.selectAll('.tooltip-inner')
62276                 .insert('svg', 'span')
62277                 .attr('class', 'tooltip-illustration')
62278                 .append('use')
62279                 .attr('xlink:href', '#feature-images');
62280
62281             context.on('enter.intro', function(mode) {
62282                 if (mode.id !== 'add-line') return;
62283                 continueTo(startLine);
62284             });
62285         }, msec + 100);
62286
62287         function continueTo(nextStep) {
62288             context.on('enter.intro', null);
62289             nextStep();
62290         }
62291     }
62292
62293
62294     function startLine() {
62295         if (context.mode().id !== 'add-line') {
62296             return chapter.restart();
62297         }
62298
62299         tulipRoadId = null;
62300
62301         var padding = 70 * Math.pow(2, context.map().zoom() - 18);
62302         var box = pad$1(tulipRoadStart, padding, context);
62303         box.height = box.height + 100;
62304         reveal(box, t('intro.lines.start_line'));
62305
62306         context.map().on('move.intro drawn.intro', function() {
62307             padding = 70 * Math.pow(2, context.map().zoom() - 18);
62308             box = pad$1(tulipRoadStart, padding, context);
62309             box.height = box.height + 100;
62310             reveal(box, t('intro.lines.start_line'), { duration: 0 });
62311         });
62312
62313         context.on('enter.intro', function(mode) {
62314             if (mode.id !== 'draw-line') return chapter.restart();
62315             continueTo(drawLine);
62316         });
62317
62318         function continueTo(nextStep) {
62319             context.map().on('move.intro drawn.intro', null);
62320             context.on('enter.intro', null);
62321             nextStep();
62322         }
62323     }
62324
62325
62326     function drawLine() {
62327         if (context.mode().id !== 'draw-line') {
62328             return chapter.restart();
62329         }
62330
62331         tulipRoadId = context.mode().selectedIDs()[0];
62332         context.map().centerEase(tulipRoadMidpoint, 500);
62333
62334         timeout(function() {
62335             var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
62336             var box = pad$1(tulipRoadMidpoint, padding, context);
62337             box.height = box.height * 2;
62338             reveal(box,
62339                 t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') })
62340             );
62341
62342             context.map().on('move.intro drawn.intro', function() {
62343                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
62344                 box = pad$1(tulipRoadMidpoint, padding, context);
62345                 box.height = box.height * 2;
62346                 reveal(box,
62347                     t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') }),
62348                     { duration: 0 }
62349                 );
62350             });
62351         }, 550);  // after easing..
62352
62353         context.history().on('change.intro', function() {
62354             var entity = tulipRoadId && context.hasEntity(tulipRoadId);
62355             if (!entity) return chapter.restart();
62356
62357             if (isLineConnected()) {
62358                 continueTo(continueLine);
62359             }
62360         });
62361
62362         context.on('enter.intro', function(mode) {
62363             if (mode.id === 'draw-line')
62364                 return;
62365             else if (mode.id === 'select') {
62366                 continueTo(retryIntersect);
62367                 return;
62368             }
62369             else
62370                 return chapter.restart();
62371         });
62372
62373         function continueTo(nextStep) {
62374             context.map().on('move.intro drawn.intro', null);
62375             context.history().on('change.intro', null);
62376             context.on('enter.intro', null);
62377             nextStep();
62378         }
62379     }
62380
62381
62382     function isLineConnected() {
62383         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
62384         if (!entity) return false;
62385
62386         var drawNodes = context.graph().childNodes(entity);
62387         return lodash.some(drawNodes, function(node) {
62388             return lodash.some(context.graph().parentWays(node), function(parent) {
62389                 return parent.id === flowerRoadId;
62390             });
62391         });
62392     }
62393
62394
62395     function retryIntersect() {
62396         select(window).on('mousedown.intro', eventCancel, true);
62397
62398         var box = pad$1(tulipRoadIntersection, 80, context);
62399         reveal(box,
62400             t('intro.lines.retry_intersect', { name: t('intro.graph.name.flower-street') })
62401         );
62402
62403         timeout(chapter.restart, 3000);
62404     }
62405
62406
62407     function continueLine() {
62408         if (context.mode().id !== 'draw-line') return chapter.restart();
62409         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
62410         if (!entity) return chapter.restart();
62411
62412         context.map().centerEase(tulipRoadIntersection, 500);
62413
62414         reveal('#surface', t('intro.lines.continue_line'));
62415
62416         context.on('enter.intro', function(mode) {
62417             if (mode.id === 'draw-line')
62418                 return;
62419             else if (mode.id === 'select')
62420                 return continueTo(chooseCategoryRoad);
62421             else
62422                 return chapter.restart();
62423         });
62424
62425         function continueTo(nextStep) {
62426             context.on('enter.intro', null);
62427             nextStep();
62428         }
62429     }
62430
62431
62432     function chooseCategoryRoad() {
62433         if (context.mode().id !== 'select') {
62434             return chapter.restart();
62435         }
62436
62437         context.on('exit.intro', function() {
62438             return chapter.restart();
62439         });
62440
62441         var button = select('.preset-category-road .preset-list-button');
62442         if (button.empty()) return chapter.restart();
62443
62444         // disallow scrolling
62445         select('.inspector-wrap').on('wheel.intro', eventCancel);
62446
62447         timeout(function() {
62448             // reset pane, in case user somehow happened to change it..
62449             select('.inspector-wrap .panewrap').style('right', '-100%');
62450
62451             reveal(button.node(),
62452                 t('intro.lines.choose_category_road', { category: roadCategory.name() })
62453             );
62454
62455             button.on('click.intro', function() {
62456                 continueTo(choosePresetResidential);
62457             });
62458
62459         }, 400);  // after editor pane visible
62460
62461         function continueTo(nextStep) {
62462             select('.inspector-wrap').on('wheel.intro', null);
62463             select('.preset-list-button').on('click.intro', null);
62464             context.on('exit.intro', null);
62465             nextStep();
62466         }
62467     }
62468
62469
62470     function choosePresetResidential() {
62471         if (context.mode().id !== 'select') {
62472             return chapter.restart();
62473         }
62474
62475         context.on('exit.intro', function() {
62476             return chapter.restart();
62477         });
62478
62479         var subgrid = select('.preset-category-road .subgrid');
62480         if (subgrid.empty()) return chapter.restart();
62481
62482         subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button')
62483             .on('click.intro', function() {
62484                 continueTo(retryPresetResidential);
62485             });
62486
62487         subgrid.selectAll('.preset-highway-residential .preset-list-button')
62488             .on('click.intro', function() {
62489                 continueTo(nameRoad);
62490             });
62491
62492         timeout(function() {
62493             reveal(subgrid.node(),
62494                 t('intro.lines.choose_preset_residential', { preset: residentialPreset.name() }),
62495                 { tooltipBox: '.preset-highway-residential .preset-list-button', duration: 300 }
62496             );
62497         }, 300);
62498
62499         function continueTo(nextStep) {
62500             select('.preset-list-button').on('click.intro', null);
62501             context.on('exit.intro', null);
62502             nextStep();
62503         }
62504     }
62505
62506
62507     // selected wrong road type
62508     function retryPresetResidential() {
62509         if (context.mode().id !== 'select') {
62510             return chapter.restart();
62511         }
62512
62513         context.on('exit.intro', function() {
62514             return chapter.restart();
62515         });
62516
62517         // disallow scrolling
62518         select('.inspector-wrap').on('wheel.intro', eventCancel);
62519
62520         timeout(function() {
62521             var button = select('.entity-editor-pane .preset-list-button');
62522
62523             reveal(button.node(),
62524                 t('intro.lines.retry_preset_residential', { preset: residentialPreset.name() })
62525             );
62526
62527             button.on('click.intro', function() {
62528                 continueTo(chooseCategoryRoad);
62529             });
62530
62531         }, 500);
62532
62533         function continueTo(nextStep) {
62534             select('.inspector-wrap').on('wheel.intro', null);
62535             select('.preset-list-button').on('click.intro', null);
62536             context.on('exit.intro', null);
62537             nextStep();
62538         }
62539     }
62540
62541
62542     function nameRoad() {
62543         context.on('exit.intro', function() {
62544             continueTo(didNameRoad);
62545         });
62546
62547         timeout(function() {
62548             reveal('.entity-editor-pane',
62549                 t('intro.lines.name_road', { button: icon('#icon-apply', 'pre-text') }),
62550                 { tooltipClass: 'intro-lines-name_road' }
62551             );
62552         }, 500);
62553
62554         function continueTo(nextStep) {
62555             context.on('exit.intro', null);
62556             nextStep();
62557         }
62558     }
62559
62560
62561     function didNameRoad() {
62562         context.history().checkpoint('doneAddLine');
62563
62564         timeout(function() {
62565             reveal('#surface', t('intro.lines.did_name_road'), {
62566                 buttonText: t('intro.ok'),
62567                 buttonCallback: function() { continueTo(updateLine); }
62568             });
62569         }, 500);
62570
62571         function continueTo(nextStep) {
62572             nextStep();
62573         }
62574     }
62575
62576
62577     function updateLine() {
62578         context.history().reset('doneAddLine');
62579         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62580             return chapter.restart();
62581         }
62582
62583         var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
62584         if (msec) { reveal(null, null, { duration: 0 }); }
62585         context.map().zoom(19).centerEase(woodRoadDragMidpoint, msec);
62586
62587         timeout(function() {
62588             var padding = 250 * Math.pow(2, context.map().zoom() - 19);
62589             var box = pad$1(woodRoadDragMidpoint, padding, context);
62590             var advance = function() { continueTo(addNode); };
62591
62592             reveal(box, t('intro.lines.update_line'),
62593                 { buttonText: t('intro.ok'), buttonCallback: advance }
62594             );
62595
62596             context.map().on('move.intro drawn.intro', function() {
62597                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
62598                 var box = pad$1(woodRoadDragMidpoint, padding, context);
62599                 reveal(box, t('intro.lines.update_line'),
62600                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
62601                 );
62602             });
62603         }, msec + 100);
62604
62605         function continueTo(nextStep) {
62606             context.map().on('move.intro drawn.intro', null);
62607             nextStep();
62608         }
62609     }
62610
62611
62612     function addNode() {
62613         context.history().reset('doneAddLine');
62614         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62615             return chapter.restart();
62616         }
62617
62618         var padding = 40 * Math.pow(2, context.map().zoom() - 19);
62619         var box = pad$1(woodRoadAddNode, padding, context);
62620         reveal(box, t('intro.lines.add_node'));
62621
62622         context.map().on('move.intro drawn.intro', function() {
62623             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
62624             var box = pad$1(woodRoadAddNode, padding, context);
62625             reveal(box, t('intro.lines.add_node'), { duration: 0 });
62626         });
62627
62628         context.history().on('change.intro', function(changed) {
62629             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62630                 return continueTo(updateLine);
62631             }
62632             if (changed.created().length === 1) {
62633                 timeout(function() { continueTo(startDragEndpoint); }, 500);
62634             }
62635         });
62636
62637         context.on('enter.intro', function(mode) {
62638             if (mode.id !== 'select') {
62639                 continueTo(updateLine);
62640             }
62641         });
62642
62643         function continueTo(nextStep) {
62644             context.map().on('move.intro drawn.intro', null);
62645             context.history().on('change.intro', null);
62646             context.on('enter.intro', null);
62647             nextStep();
62648         }
62649     }
62650
62651
62652     function startDragEndpoint() {
62653         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62654             return continueTo(updateLine);
62655         }
62656         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
62657             context.enter(modeSelect(context, [woodRoadId]));
62658         }
62659
62660         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62661         var box = pad$1(woodRoadDragEndpoint, padding, context);
62662         reveal(box, t('intro.lines.start_drag_endpoint'));
62663
62664         context.map().on('move.intro drawn.intro', function() {
62665             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62666                 return continueTo(updateLine);
62667             }
62668             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62669             var box = pad$1(woodRoadDragEndpoint, padding, context);
62670             reveal(box, t('intro.lines.start_drag_endpoint'), { duration: 0 });
62671
62672             var entity = context.entity(woodRoadEndId);
62673             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
62674                 continueTo(finishDragEndpoint);
62675             }
62676         });
62677
62678         context.on('enter.intro', function(mode) {
62679             if (mode.id !== 'select') {
62680                 // keep Wood Road selected so endpoint stays draggable..
62681                 context.enter(modeSelect(context, [woodRoadId]));
62682             }
62683         });
62684
62685         function continueTo(nextStep) {
62686             context.map().on('move.intro drawn.intro', null);
62687             context.on('enter.intro', null);
62688             nextStep();
62689         }
62690     }
62691
62692
62693     function finishDragEndpoint() {
62694         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62695             return continueTo(updateLine);
62696         }
62697
62698         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62699         var box = pad$1(woodRoadDragEndpoint, padding, context);
62700         reveal(box, t('intro.lines.finish_drag_endpoint'));
62701
62702         context.map().on('move.intro drawn.intro', function() {
62703             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62704                 return continueTo(updateLine);
62705             }
62706             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62707             var box = pad$1(woodRoadDragEndpoint, padding, context);
62708             reveal(box, t('intro.lines.finish_drag_endpoint'), { duration: 0 });
62709
62710             var entity = context.entity(woodRoadEndId);
62711             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
62712                 continueTo(startDragEndpoint);
62713             }
62714         });
62715
62716         context.on('enter.intro', function() {
62717             continueTo(startDragMidpoint);
62718         });
62719
62720         function continueTo(nextStep) {
62721             context.map().on('move.intro drawn.intro', null);
62722             context.on('enter.intro', null);
62723             nextStep();
62724         }
62725     }
62726
62727
62728     function startDragMidpoint() {
62729         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62730             return continueTo(updateLine);
62731         }
62732         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
62733             context.enter(modeSelect(context, [woodRoadId]));
62734         }
62735
62736         var padding = 80 * Math.pow(2, context.map().zoom() - 19);
62737         var box = pad$1(woodRoadDragMidpoint, padding, context);
62738         reveal(box, t('intro.lines.start_drag_midpoint'));
62739
62740         context.map().on('move.intro drawn.intro', function() {
62741             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62742                 return continueTo(updateLine);
62743             }
62744             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
62745             var box = pad$1(woodRoadDragMidpoint, padding, context);
62746             reveal(box, t('intro.lines.start_drag_midpoint'), { duration: 0 });
62747         });
62748
62749         context.history().on('change.intro', function(changed) {
62750             if (changed.created().length === 1) {
62751                 continueTo(continueDragMidpoint);
62752             }
62753         });
62754
62755         context.on('enter.intro', function(mode) {
62756             if (mode.id !== 'select') {
62757                 // keep Wood Road selected so midpoint triangles are drawn..
62758                 context.enter(modeSelect(context, [woodRoadId]));
62759             }
62760         });
62761
62762         function continueTo(nextStep) {
62763             context.map().on('move.intro drawn.intro', null);
62764             context.history().on('change.intro', null);
62765             context.on('enter.intro', null);
62766             nextStep();
62767         }
62768     }
62769
62770
62771     function continueDragMidpoint() {
62772         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62773             return continueTo(updateLine);
62774         }
62775
62776         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62777         var box = pad$1(woodRoadDragEndpoint, padding, context);
62778         box.height += 400;
62779
62780         var advance = function() {
62781             context.history().checkpoint('doneUpdateLine');
62782             continueTo(deleteLines);
62783         };
62784
62785         reveal(box, t('intro.lines.continue_drag_midpoint'),
62786             { buttonText: t('intro.ok'), buttonCallback: advance }
62787         );
62788
62789         context.map().on('move.intro drawn.intro', function() {
62790             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62791                 return continueTo(updateLine);
62792             }
62793             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62794             var box = pad$1(woodRoadDragEndpoint, padding, context);
62795             box.height += 400;
62796             reveal(box, t('intro.lines.continue_drag_midpoint'),
62797                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
62798             );
62799         });
62800
62801         function continueTo(nextStep) {
62802             context.map().on('move.intro drawn.intro', null);
62803             nextStep();
62804         }
62805     }
62806
62807
62808     function deleteLines() {
62809         context.history().reset('doneUpdateLine');
62810         context.enter(modeBrowse(context));
62811
62812         if (!context.hasEntity(washingtonStreetId) ||
62813             !context.hasEntity(twelfthAvenueId) ||
62814             !context.hasEntity(eleventhAvenueEndId)) {
62815             return chapter.restart();
62816         }
62817
62818         var msec = transitionTime(deleteLinesLoc, context.map().center());
62819         if (msec) { reveal(null, null, { duration: 0 }); }
62820         context.map().zoom(18).centerEase(deleteLinesLoc, msec);
62821
62822         timeout(function() {
62823             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
62824             var box = pad$1(deleteLinesLoc, padding, context);
62825             box.top -= 200;
62826             box.height += 400;
62827             var advance = function() { continueTo(rightClickIntersection); };
62828
62829             reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
62830                 { buttonText: t('intro.ok'), buttonCallback: advance }
62831             );
62832
62833             context.map().on('move.intro drawn.intro', function() {
62834                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
62835                 var box = pad$1(deleteLinesLoc, padding, context);
62836                 box.top -= 200;
62837                 box.height += 400;
62838                 reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
62839                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
62840                 );
62841             });
62842
62843             context.history().on('change.intro', function() {
62844                 timeout(function() {
62845                     continueTo(deleteLines);
62846                 }, 500);  // after any transition (e.g. if user deleted intersection)
62847             });
62848
62849         }, msec + 100);
62850
62851         function continueTo(nextStep) {
62852             context.map().on('move.intro drawn.intro', null);
62853             context.history().on('change.intro', null);
62854             nextStep();
62855         }
62856     }
62857
62858
62859     function rightClickIntersection() {
62860         context.history().reset('doneUpdateLine');
62861         context.enter(modeBrowse(context));
62862
62863         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
62864
62865         timeout(function() {
62866             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
62867             var box = pad$1(eleventhAvenueEnd, padding, context);
62868             reveal(box, t('intro.lines.rightclick_intersection',
62869                 { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') })
62870             );
62871
62872             context.map().on('move.intro drawn.intro', function() {
62873                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
62874                 var box = pad$1(eleventhAvenueEnd, padding, context);
62875                 reveal(box, t('intro.lines.rightclick_intersection',
62876                     { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') }),
62877                     { duration: 0 }
62878                 );
62879             });
62880
62881             context.on('enter.intro', function(mode) {
62882                 if (mode.id !== 'select') return;
62883                 var ids = context.selectedIDs();
62884                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndId) return;
62885
62886                 timeout(function() {
62887                     var node = selectMenuItem('split').node();
62888                     if (!node) return;
62889                     continueTo(splitIntersection);
62890                 }, 300);  // after menu visible
62891             });
62892
62893             context.history().on('change.intro', function() {
62894                 timeout(function() {
62895                     continueTo(deleteLines);
62896                 }, 300);  // after any transition (e.g. if user deleted intersection)
62897             });
62898
62899         }, 600);
62900
62901         function continueTo(nextStep) {
62902             context.map().on('move.intro drawn.intro', null);
62903             context.on('enter.intro', null);
62904             context.history().on('change.intro', null);
62905             nextStep();
62906         }
62907     }
62908
62909
62910     function splitIntersection() {
62911         if (!context.hasEntity(washingtonStreetId) ||
62912             !context.hasEntity(twelfthAvenueId) ||
62913             !context.hasEntity(eleventhAvenueEndId)) {
62914             return continueTo(deleteLines);
62915         }
62916
62917         var node = selectMenuItem('split').node();
62918         if (!node) { return continueTo(rightClickIntersection); }
62919
62920         var wasChanged = false;
62921         var menuCoords = context.map().mouseCoordinates();
62922         washingtonSegmentId = null;
62923
62924         revealEditMenu(menuCoords, t('intro.lines.split_intersection',
62925             { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') })
62926         );
62927
62928         context.map().on('move.intro drawn.intro', function() {
62929             var node = selectMenuItem('split').node();
62930             if (!wasChanged && !node) { return continueTo(rightClickIntersection); }
62931
62932             revealEditMenu(menuCoords, t('intro.lines.split_intersection',
62933                 { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') }),
62934                 { duration: 0 }
62935             );
62936         });
62937
62938         context.history().on('change.intro', function(changed) {
62939             wasChanged = true;
62940             timeout(function() {
62941                 if (context.history().undoAnnotation() === t('operations.split.annotation.line')) {
62942                     washingtonSegmentId = changed.created()[0].id;
62943                     continueTo(didSplit);
62944                 } else {
62945                     washingtonSegmentId = null;
62946                     continueTo(retrySplit);
62947                 }
62948             }, 300);  // after any transition (e.g. if user deleted intersection)
62949         });
62950
62951         function continueTo(nextStep) {
62952             context.map().on('move.intro drawn.intro', null);
62953             context.history().on('change.intro', null);
62954             nextStep();
62955         }
62956     }
62957
62958
62959     function retrySplit() {
62960         context.enter(modeBrowse(context));
62961         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
62962         var advance = function() { continueTo(rightClickIntersection); };
62963
62964         var padding = 60 * Math.pow(2, context.map().zoom() - 18);
62965         var box = pad$1(eleventhAvenueEnd, padding, context);
62966         reveal(box, t('intro.lines.retry_split'),
62967             { buttonText: t('intro.ok'), buttonCallback: advance }
62968         );
62969
62970         context.map().on('move.intro drawn.intro', function() {
62971             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
62972             var box = pad$1(eleventhAvenueEnd, padding, context);
62973             reveal(box, t('intro.lines.retry_split'),
62974                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
62975             );
62976         });
62977
62978         function continueTo(nextStep) {
62979             context.map().on('move.intro drawn.intro', null);
62980             nextStep();
62981         }
62982     }
62983
62984
62985     function didSplit() {
62986         if (!washingtonSegmentId ||
62987             !context.hasEntity(washingtonSegmentId) ||
62988             !context.hasEntity(washingtonStreetId) ||
62989             !context.hasEntity(twelfthAvenueId) ||
62990             !context.hasEntity(eleventhAvenueEndId)) {
62991             return continueTo(rightClickIntersection);
62992         }
62993
62994         var ids = context.selectedIDs();
62995         var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
62996         var street = t('intro.graph.name.washington-street');
62997
62998         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
62999         var box = pad$1(twelfthAvenue, padding, context);
63000         box.width = box.width / 2;
63001         reveal(box, t(string, { street1: street, street2: street }),
63002             { duration: 500 }
63003         );
63004
63005         timeout(function() {
63006             context.map().zoom(18).centerEase(twelfthAvenue, 500);
63007
63008             context.map().on('move.intro drawn.intro', function() {
63009                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63010                 var box = pad$1(twelfthAvenue, padding, context);
63011                 box.width = box.width / 2;
63012                 reveal(box, t(string, { street1: street, street2: street }),
63013                     { duration: 0 }
63014                 );
63015             });
63016         }, 600);  // after initial reveal and curtain cut
63017
63018         context.on('enter.intro', function() {
63019             var ids = context.selectedIDs();
63020             if (ids.length === 1 && ids[0] === washingtonSegmentId) {
63021                 continueTo(multiSelect);
63022             }
63023         });
63024
63025         context.history().on('change.intro', function() {
63026             if (!washingtonSegmentId ||
63027                 !context.hasEntity(washingtonSegmentId) ||
63028                 !context.hasEntity(washingtonStreetId) ||
63029                 !context.hasEntity(twelfthAvenueId) ||
63030                 !context.hasEntity(eleventhAvenueEndId)) {
63031                 return continueTo(rightClickIntersection);
63032             }
63033         });
63034
63035         function continueTo(nextStep) {
63036             context.map().on('move.intro drawn.intro', null);
63037             context.on('enter.intro', null);
63038             context.history().on('change.intro', null);
63039             nextStep();
63040         }
63041     }
63042
63043
63044     function multiSelect() {
63045         if (!washingtonSegmentId ||
63046             !context.hasEntity(washingtonSegmentId) ||
63047             !context.hasEntity(washingtonStreetId) ||
63048             !context.hasEntity(twelfthAvenueId) ||
63049             !context.hasEntity(eleventhAvenueEndId)) {
63050             return continueTo(rightClickIntersection);
63051         }
63052
63053         var ids = context.selectedIDs();
63054         var hasWashington = ids.indexOf(washingtonSegmentId) !== -1;
63055         var hasTwelfth = ids.indexOf(twelfthAvenueId) !== -1;
63056
63057         if (hasWashington && hasTwelfth) {
63058             return continueTo(multiRightClick);
63059         } else if (!hasWashington && !hasTwelfth) {
63060             return continueTo(didSplit);
63061         }
63062
63063         context.map().zoom(18).centerEase(twelfthAvenue, 500);
63064
63065         timeout(function() {
63066             var selected, other, padding, box;
63067             if (hasWashington) {
63068                 selected = t('intro.graph.name.washington-street');
63069                 other = t('intro.graph.name.12th-avenue');
63070                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
63071                 box = pad$1(twelfthAvenueEnd, padding, context);
63072                 box.width *= 3;
63073             } else {
63074                 selected = t('intro.graph.name.12th-avenue');
63075                 other = t('intro.graph.name.washington-street');
63076                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
63077                 box = pad$1(twelfthAvenue, padding, context);
63078                 box.width /= 2;
63079             }
63080
63081             reveal(box,
63082                 t('intro.lines.multi_select', { selected: selected, other1: other, other2: other })
63083             );
63084
63085             context.map().on('move.intro drawn.intro', function() {
63086                 if (hasWashington) {
63087                     selected = t('intro.graph.name.washington-street');
63088                     other = t('intro.graph.name.12th-avenue');
63089                     padding = 60 * Math.pow(2, context.map().zoom() - 18);
63090                     box = pad$1(twelfthAvenueEnd, padding, context);
63091                     box.width *= 3;
63092                 } else {
63093                     selected = t('intro.graph.name.12th-avenue');
63094                     other = t('intro.graph.name.washington-street');
63095                     padding = 200 * Math.pow(2, context.map().zoom() - 18);
63096                     box = pad$1(twelfthAvenue, padding, context);
63097                     box.width /= 2;
63098                 }
63099
63100                 reveal(box,
63101                     t('intro.lines.multi_select', { selected: selected, other1: other, other2: other }),
63102                     { duration: 0 }
63103                 );
63104             });
63105
63106             context.on('enter.intro', function() {
63107                 continueTo(multiSelect);
63108             });
63109
63110             context.history().on('change.intro', function() {
63111                 if (!washingtonSegmentId ||
63112                     !context.hasEntity(washingtonSegmentId) ||
63113                     !context.hasEntity(washingtonStreetId) ||
63114                     !context.hasEntity(twelfthAvenueId) ||
63115                     !context.hasEntity(eleventhAvenueEndId)) {
63116                     return continueTo(rightClickIntersection);
63117                 }
63118             });
63119         }, 600);
63120
63121         function continueTo(nextStep) {
63122             context.map().on('move.intro drawn.intro', null);
63123             context.on('enter.intro', null);
63124             context.history().on('change.intro', null);
63125             nextStep();
63126         }
63127     }
63128
63129
63130     function multiRightClick() {
63131         if (!washingtonSegmentId ||
63132             !context.hasEntity(washingtonSegmentId) ||
63133             !context.hasEntity(washingtonStreetId) ||
63134             !context.hasEntity(twelfthAvenueId) ||
63135             !context.hasEntity(eleventhAvenueEndId)) {
63136             return continueTo(rightClickIntersection);
63137         }
63138
63139         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63140         var box = pad$1(twelfthAvenue, padding, context);
63141         reveal(box, t('intro.lines.multi_rightclick'));
63142
63143         context.map().on('move.intro drawn.intro', function() {
63144             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63145             var box = pad$1(twelfthAvenue, padding, context);
63146             reveal(box, t('intro.lines.multi_rightclick'), { duration: 0 });
63147         });
63148
63149         select(window).on('click.intro contextmenu.intro', function() {
63150             timeout(function() {
63151                 var ids = context.selectedIDs();
63152                 if (ids.length === 2 &&
63153                     ids.indexOf(twelfthAvenueId) !== -1 &&
63154                     ids.indexOf(washingtonSegmentId) !== -1) {
63155                         var node = selectMenuItem('delete').node();
63156                         if (!node) return;
63157                         continueTo(multiDelete);
63158                 } else if (ids.length === 1 &&
63159                     ids.indexOf(washingtonSegmentId) !== -1) {
63160                     return continueTo(multiSelect);
63161                 } else {
63162                     return continueTo(didSplit);
63163                 }
63164             }, 300);  // after edit menu visible
63165         }, true);
63166
63167         context.history().on('change.intro', function() {
63168             if (!washingtonSegmentId ||
63169                 !context.hasEntity(washingtonSegmentId) ||
63170                 !context.hasEntity(washingtonStreetId) ||
63171                 !context.hasEntity(twelfthAvenueId) ||
63172                 !context.hasEntity(eleventhAvenueEndId)) {
63173                 return continueTo(rightClickIntersection);
63174             }
63175         });
63176
63177         function continueTo(nextStep) {
63178             context.map().on('move.intro drawn.intro', null);
63179             select(window).on('click.intro contextmenu.intro', null, true);
63180             context.history().on('change.intro', null);
63181             nextStep();
63182         }
63183     }
63184
63185
63186     function multiDelete() {
63187         if (!washingtonSegmentId ||
63188             !context.hasEntity(washingtonSegmentId) ||
63189             !context.hasEntity(washingtonStreetId) ||
63190             !context.hasEntity(twelfthAvenueId) ||
63191             !context.hasEntity(eleventhAvenueEndId)) {
63192             return continueTo(rightClickIntersection);
63193         }
63194
63195         var node = selectMenuItem('delete').node();
63196         if (!node) return continueTo(multiRightClick);
63197
63198         var menuCoords = context.map().mouseCoordinates();
63199         revealEditMenu(menuCoords,
63200             t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') })
63201         );
63202
63203         context.map().on('move.intro drawn.intro', function() {
63204             revealEditMenu(menuCoords,
63205                 t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') }),
63206                 { duration: 0 }
63207             );
63208         });
63209
63210         context.on('exit.intro', function() {
63211             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
63212                 return continueTo(multiSelect);  // left select mode but roads still exist
63213             }
63214         });
63215
63216         context.history().on('change.intro', function() {
63217             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
63218                 continueTo(retryDelete);         // changed something but roads still exist
63219             } else {
63220                 continueTo(play);
63221             }
63222         });
63223
63224         function continueTo(nextStep) {
63225             context.map().on('move.intro drawn.intro', null);
63226             context.on('exit.intro', null);
63227             context.history().on('change.intro', null);
63228             nextStep();
63229         }
63230     }
63231
63232
63233     function retryDelete() {
63234         context.enter(modeBrowse(context));
63235
63236         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63237         var box = pad$1(twelfthAvenue, padding, context);
63238         reveal(box, t('intro.lines.retry_delete'), {
63239             buttonText: t('intro.ok'),
63240             buttonCallback: function() { continueTo(multiSelect); }
63241         });
63242
63243         function continueTo(nextStep) {
63244             nextStep();
63245         }
63246     }
63247
63248
63249     function play() {
63250         dispatch$$1.call('done');
63251         reveal('#id-container',
63252             t('intro.lines.play', { next: t('intro.buildings.title') }), {
63253                 tooltipBox: '.intro-nav-wrap .chapter-building',
63254                 buttonText: t('intro.ok'),
63255                 buttonCallback: function() { reveal('#id-container'); }
63256             }
63257         );
63258    }
63259
63260
63261     chapter.enter = function() {
63262         addLine();
63263     };
63264
63265
63266     chapter.exit = function() {
63267         timeouts.forEach(window.clearTimeout);
63268         select(window).on('mousedown.intro', null, true);
63269         context.on('enter.intro exit.intro', null);
63270         context.map().on('move.intro drawn.intro', null);
63271         context.history().on('change.intro', null);
63272         select('.inspector-wrap').on('wheel.intro', null);
63273         select('.preset-list-button').on('click.intro', null);
63274     };
63275
63276
63277     chapter.restart = function() {
63278         chapter.exit();
63279         chapter.enter();
63280     };
63281
63282
63283     return utilRebind(chapter, dispatch$$1, 'on');
63284 }
63285
63286 function uiIntroBuilding(context, reveal) {
63287     var dispatch$$1 = dispatch('done'),
63288         house = [-85.62815, 41.95638],
63289         tank = [-85.62732, 41.95347],
63290         buildingCatetory = context.presets().item('category-building'),
63291         housePreset = context.presets().item('building/house'),
63292         tankPreset = context.presets().item('man_made/storage_tank'),
63293         timeouts = [],
63294         houseId = null,
63295         tankId = null;
63296
63297
63298     var chapter = {
63299         title: 'intro.buildings.title'
63300     };
63301
63302
63303     function timeout(f, t$$1) {
63304         timeouts.push(window.setTimeout(f, t$$1));
63305     }
63306
63307
63308     function eventCancel() {
63309         event.stopPropagation();
63310         event.preventDefault();
63311     }
63312
63313
63314     function revealHouse(center, text$$1, options) {
63315         var padding = 160 * Math.pow(2, context.map().zoom() - 20);
63316         var box = pad$1(center, padding, context);
63317         reveal(box, text$$1, options);
63318     }
63319
63320
63321     function revealTank(center, text$$1, options) {
63322         var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
63323         var box = pad$1(center, padding, context);
63324         reveal(box, text$$1, options);
63325     }
63326
63327
63328     function revealEditMenu(loc, text$$1, options) {
63329         var rect = context.surfaceRect();
63330         var point = context.curtainProjection(loc);
63331         var pad = 40;
63332         var width = 250 + (2 * pad);
63333         var height = 350;
63334         var startX = rect.left + point[0];
63335         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
63336         var box = {
63337             left: left,
63338             top: point[1] + rect.top - 60,
63339             width: width,
63340             height: height
63341         };
63342         reveal(box, text$$1, options);
63343     }
63344
63345
63346     function addHouse() {
63347         context.enter(modeBrowse(context));
63348         context.history().reset('initial');
63349         houseId = null;
63350
63351         var msec = transitionTime(house, context.map().center());
63352         if (msec) { reveal(null, null, { duration: 0 }); }
63353         context.map().zoom(19).centerEase(house, msec);
63354
63355         timeout(function() {
63356             var tooltip = reveal('button.add-area',
63357                 t('intro.buildings.add_building', { button: icon('#icon-area', 'pre-text') }));
63358
63359             tooltip.selectAll('.tooltip-inner')
63360                 .insert('svg', 'span')
63361                 .attr('class', 'tooltip-illustration')
63362                 .append('use')
63363                 .attr('xlink:href', '#building-images');
63364
63365             context.on('enter.intro', function(mode) {
63366                 if (mode.id !== 'add-area') return;
63367                 continueTo(startHouse);
63368             });
63369         }, msec + 100);
63370
63371         function continueTo(nextStep) {
63372             context.on('enter.intro', null);
63373             nextStep();
63374         }
63375     }
63376
63377
63378     function startHouse() {
63379         if (context.mode().id !== 'add-area') {
63380             return continueTo(addHouse);
63381         }
63382
63383         houseId = null;
63384         context.map().zoomEase(20, 500);
63385
63386         timeout(function() {
63387             revealHouse(house, t('intro.buildings.start_building'));
63388
63389             context.map().on('move.intro drawn.intro', function() {
63390                 revealHouse(house, t('intro.buildings.start_building'), { duration: 0 });
63391             });
63392
63393             context.on('enter.intro', function(mode) {
63394                 if (mode.id !== 'draw-area') return chapter.restart();
63395                 continueTo(continueHouse);
63396             });
63397
63398         }, 550);  // after easing
63399
63400         function continueTo(nextStep) {
63401             context.map().on('move.intro drawn.intro', null);
63402             context.on('enter.intro', null);
63403             nextStep();
63404         }
63405     }
63406
63407
63408     function continueHouse() {
63409         if (context.mode().id !== 'draw-area') {
63410             return continueTo(addHouse);
63411         }
63412
63413         houseId = null;
63414
63415         revealHouse(house, t('intro.buildings.continue_building'));
63416
63417         context.map().on('move.intro drawn.intro', function() {
63418             revealHouse(house, t('intro.buildings.continue_building'), { duration: 0 });
63419         });
63420
63421         context.on('enter.intro', function(mode) {
63422             if (mode.id === 'draw-area') {
63423                 return;
63424             } else if (mode.id === 'select') {
63425                 var graph = context.graph(),
63426                     way = context.entity(context.selectedIDs()[0]),
63427                     nodes = graph.childNodes(way),
63428                     points = lodash.uniq(nodes).map(function(n) { return context.projection(n.loc); });
63429
63430                 if (isMostlySquare(points)) {
63431                     houseId = way.id;
63432                     return continueTo(chooseCategoryBuilding);
63433                 } else {
63434                     return continueTo(retryHouse);
63435                 }
63436
63437             } else {
63438                 return chapter.restart();
63439             }
63440         });
63441
63442         function continueTo(nextStep) {
63443             context.map().on('move.intro drawn.intro', null);
63444             context.on('enter.intro', null);
63445             nextStep();
63446         }
63447     }
63448
63449
63450     function retryHouse() {
63451         var onClick = function() { continueTo(addHouse); };
63452
63453         revealHouse(house, t('intro.buildings.retry_building'),
63454             { buttonText: t('intro.ok'), buttonCallback: onClick }
63455         );
63456
63457         context.map().on('move.intro drawn.intro', function() {
63458             revealHouse(house, t('intro.buildings.retry_building'),
63459                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
63460             );
63461         });
63462
63463         function continueTo(nextStep) {
63464             context.map().on('move.intro drawn.intro', null);
63465             nextStep();
63466         }
63467     }
63468
63469
63470     function chooseCategoryBuilding() {
63471         if (!houseId || !context.hasEntity(houseId)) {
63472             return addHouse();
63473         }
63474         var ids = context.selectedIDs();
63475         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
63476             context.enter(modeSelect(context, [houseId]));
63477         }
63478
63479         // disallow scrolling
63480         select('.inspector-wrap').on('wheel.intro', eventCancel);
63481
63482         timeout(function() {
63483             // reset pane, in case user somehow happened to change it..
63484             select('.inspector-wrap .panewrap').style('right', '-100%');
63485
63486             var button = select('.preset-category-building .preset-list-button');
63487
63488             reveal(button.node(),
63489                 t('intro.buildings.choose_category_building', { category: buildingCatetory.name() })
63490             );
63491
63492             button.on('click.intro', function() {
63493                 button.on('click.intro', null);
63494                 continueTo(choosePresetHouse);
63495             });
63496
63497         }, 400);  // after preset list pane visible..
63498
63499
63500         context.on('enter.intro', function(mode) {
63501             if (!houseId || !context.hasEntity(houseId)) {
63502                 return continueTo(addHouse);
63503             }
63504             var ids = context.selectedIDs();
63505             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
63506                 return continueTo(chooseCategoryBuilding);
63507             }
63508         });
63509
63510         function continueTo(nextStep) {
63511             select('.inspector-wrap').on('wheel.intro', null);
63512             select('.preset-list-button').on('click.intro', null);
63513             context.on('enter.intro', null);
63514             nextStep();
63515         }
63516     }
63517
63518
63519     function choosePresetHouse() {
63520         if (!houseId || !context.hasEntity(houseId)) {
63521             return addHouse();
63522         }
63523         var ids = context.selectedIDs();
63524         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
63525             context.enter(modeSelect(context, [houseId]));
63526         }
63527
63528         // disallow scrolling
63529         select('.inspector-wrap').on('wheel.intro', eventCancel);
63530
63531         timeout(function() {
63532             // reset pane, in case user somehow happened to change it..
63533             select('.inspector-wrap .panewrap').style('right', '-100%');
63534
63535             var button = select('.preset-building-house .preset-list-button');
63536
63537             reveal(button.node(),
63538                 t('intro.buildings.choose_preset_house', { preset: housePreset.name() }),
63539                 { duration: 300 }
63540             );
63541
63542             button.on('click.intro', function() {
63543                 button.on('click.intro', null);
63544                 continueTo(closeEditorHouse);
63545             });
63546
63547
63548         }, 400);  // after preset list pane visible..
63549
63550         context.on('enter.intro', function(mode) {
63551             if (!houseId || !context.hasEntity(houseId)) {
63552                 return continueTo(addHouse);
63553             }
63554             var ids = context.selectedIDs();
63555             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
63556                 return continueTo(chooseCategoryBuilding);
63557             }
63558         });
63559
63560         function continueTo(nextStep) {
63561             select('.inspector-wrap').on('wheel.intro', null);
63562             select('.preset-list-button').on('click.intro', null);
63563             context.on('enter.intro', null);
63564             nextStep();
63565         }
63566     }
63567
63568
63569     function closeEditorHouse() {
63570         if (!houseId || !context.hasEntity(houseId)) {
63571             return addHouse();
63572         }
63573         var ids = context.selectedIDs();
63574         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
63575             context.enter(modeSelect(context, [houseId]));
63576         }
63577
63578         context.history().checkpoint('hasHouse');
63579
63580         context.on('exit.intro', function() {
63581             continueTo(rightClickHouse);
63582         });
63583
63584         timeout(function() {
63585             reveal('.entity-editor-pane',
63586                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
63587             );
63588         }, 500);
63589
63590         function continueTo(nextStep) {
63591             context.on('exit.intro', null);
63592             nextStep();
63593         }
63594     }
63595
63596
63597     function rightClickHouse() {
63598         if (!houseId) return chapter.restart();
63599
63600         context.enter(modeBrowse(context));
63601         context.history().reset('hasHouse');
63602         context.map().centerEase(house, 500);
63603
63604         timeout(function() {
63605             if (context.map().zoom() < 20) {
63606                 context.map().zoomEase(20, 500);
63607             }
63608         }, 520);
63609
63610         context.on('enter.intro', function(mode) {
63611             if (mode.id !== 'select') return;
63612             var ids = context.selectedIDs();
63613             if (ids.length !== 1 || ids[0] !== houseId) return;
63614
63615             timeout(function() {
63616                 var node = selectMenuItem('orthogonalize').node();
63617                 if (!node) return;
63618                 continueTo(clickSquare);
63619             }, 300);  // after menu visible
63620         });
63621
63622         context.map().on('move.intro drawn.intro', function() {
63623             revealHouse(house, t('intro.buildings.rightclick_building'), { duration: 0 });
63624         });
63625
63626         context.history().on('change.intro', function() {
63627             continueTo(rightClickHouse);
63628         });
63629
63630         function continueTo(nextStep) {
63631             context.on('enter.intro', null);
63632             context.map().on('move.intro drawn.intro', null);
63633             context.history().on('change.intro', null);
63634             nextStep();
63635         }
63636     }
63637
63638
63639     function clickSquare() {
63640         if (!houseId) return chapter.restart();
63641         var entity = context.hasEntity(houseId);
63642         if (!entity) return continueTo(rightClickHouse);
63643
63644         var node = selectMenuItem('orthogonalize').node();
63645         if (!node) { return continueTo(rightClickHouse); }
63646
63647         var wasChanged = false;
63648         var menuCoords = context.map().mouseCoordinates();
63649
63650         revealEditMenu(menuCoords,
63651             t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') })
63652         );
63653
63654         context.on('enter.intro', function(mode) {
63655             if (mode.id === 'browse') {
63656                 continueTo(rightClickHouse);
63657             } else if (mode.id === 'move' || mode.id === 'rotate') {
63658                 continueTo(retryClickSquare);
63659             }
63660         });
63661
63662         context.map().on('move.intro drawn.intro', function() {
63663             var node = selectMenuItem('orthogonalize').node();
63664             if (!wasChanged && !node) { return continueTo(rightClickHouse); }
63665
63666             revealEditMenu(menuCoords,
63667                 t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') }),
63668                 { duration: 0 }
63669             );
63670         });
63671
63672         context.history().on('change.intro', function() {
63673             wasChanged = true;
63674             context.history().on('change.intro', null);
63675
63676             // Something changed.  Wait for transition to complete and check undo annotation.
63677             timeout(function() {
63678                 if (context.history().undoAnnotation() === t('operations.orthogonalize.annotation.area')) {
63679                     continueTo(doneSquare);
63680                 } else {
63681                     continueTo(retryClickSquare);
63682                 }
63683             }, 500);  // after transitioned actions
63684         });
63685
63686         function continueTo(nextStep) {
63687             context.on('enter.intro', null);
63688             context.map().on('move.intro drawn.intro', null);
63689             context.history().on('change.intro', null);
63690             nextStep();
63691         }
63692     }
63693
63694
63695     function retryClickSquare() {
63696         context.enter(modeBrowse(context));
63697
63698         revealHouse(house, t('intro.buildings.retry_square'), {
63699             buttonText: t('intro.ok'),
63700             buttonCallback: function() { continueTo(rightClickHouse); }
63701         });
63702
63703         function continueTo(nextStep) {
63704             nextStep();
63705         }
63706     }
63707
63708
63709     function doneSquare() {
63710         context.history().checkpoint('doneSquare');
63711
63712         revealHouse(house, t('intro.buildings.done_square'), {
63713             buttonText: t('intro.ok'),
63714             buttonCallback: function() { continueTo(addTank); }
63715         });
63716
63717         function continueTo(nextStep) {
63718             nextStep();
63719         }
63720     }
63721
63722
63723     function addTank() {
63724         context.enter(modeBrowse(context));
63725         context.history().reset('doneSquare');
63726         tankId = null;
63727
63728         var msec = transitionTime(tank, context.map().center());
63729         if (msec) { reveal(null, null, { duration: 0 }); }
63730         context.map().zoom(19.5).centerEase(tank, msec);
63731
63732         timeout(function() {
63733             reveal('button.add-area',
63734                 t('intro.buildings.add_tank', { button: icon('#icon-area', 'pre-text') })
63735             );
63736
63737             context.on('enter.intro', function(mode) {
63738                 if (mode.id !== 'add-area') return;
63739                 continueTo(startTank);
63740             });
63741         }, msec + 100);
63742
63743         function continueTo(nextStep) {
63744             context.on('enter.intro', null);
63745             nextStep();
63746         }
63747     }
63748
63749
63750     function startTank() {
63751         if (context.mode().id !== 'add-area') {
63752             return continueTo(addTank);
63753         }
63754
63755         tankId = null;
63756
63757         timeout(function() {
63758             revealTank(tank, t('intro.buildings.start_tank'));
63759
63760             context.map().on('move.intro drawn.intro', function() {
63761                 revealTank(tank, t('intro.buildings.start_tank'), { duration: 0 });
63762             });
63763
63764             context.on('enter.intro', function(mode) {
63765                 if (mode.id !== 'draw-area') return chapter.restart();
63766                 continueTo(continueTank);
63767             });
63768
63769         }, 550);  // after easing
63770
63771         function continueTo(nextStep) {
63772             context.map().on('move.intro drawn.intro', null);
63773             context.on('enter.intro', null);
63774             nextStep();
63775         }
63776     }
63777
63778
63779     function continueTank() {
63780         if (context.mode().id !== 'draw-area') {
63781             return continueTo(addTank);
63782         }
63783
63784         tankId = null;
63785
63786         revealTank(tank, t('intro.buildings.continue_tank'));
63787
63788         context.map().on('move.intro drawn.intro', function() {
63789             revealTank(tank, t('intro.buildings.continue_tank'), { duration: 0 });
63790         });
63791
63792         context.on('enter.intro', function(mode) {
63793             if (mode.id === 'draw-area') {
63794                 return;
63795             } else if (mode.id === 'select') {
63796                 tankId = context.selectedIDs()[0];
63797                 return continueTo(searchPresetTank);
63798             } else {
63799                 return continueTo(addTank);
63800             }
63801         });
63802
63803         function continueTo(nextStep) {
63804             context.map().on('move.intro drawn.intro', null);
63805             context.on('enter.intro', null);
63806             nextStep();
63807         }
63808     }
63809
63810
63811     function searchPresetTank() {
63812         if (!tankId || !context.hasEntity(tankId)) {
63813             return addTank();
63814         }
63815         var ids = context.selectedIDs();
63816         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
63817             context.enter(modeSelect(context, [tankId]));
63818         }
63819
63820         // disallow scrolling
63821         select('.inspector-wrap').on('wheel.intro', eventCancel);
63822
63823         timeout(function() {
63824             // reset pane, in case user somehow happened to change it..
63825             select('.inspector-wrap .panewrap').style('right', '-100%');
63826
63827             select('.preset-search-input')
63828                 .on('keydown.intro', null)
63829                 .on('keyup.intro', checkPresetSearch);
63830
63831             reveal('.preset-search-input',
63832                 t('intro.buildings.search_tank', { preset: tankPreset.name() })
63833             );
63834         }, 400);  // after preset list pane visible..
63835
63836         context.on('enter.intro', function(mode) {
63837             if (!tankId || !context.hasEntity(tankId)) {
63838                 return continueTo(addTank);
63839             }
63840
63841             var ids = context.selectedIDs();
63842             if (mode.id !== 'select' || !ids.length || ids[0] !== tankId) {
63843                 // keep the user's area selected..
63844                 context.enter(modeSelect(context, [tankId]));
63845
63846                 // reset pane, in case user somehow happened to change it..
63847                 select('.inspector-wrap .panewrap').style('right', '-100%');
63848                 // disallow scrolling
63849                 select('.inspector-wrap').on('wheel.intro', eventCancel);
63850
63851                 select('.preset-search-input')
63852                     .on('keydown.intro', null)
63853                     .on('keyup.intro', checkPresetSearch);
63854
63855                 reveal('.preset-search-input',
63856                     t('intro.buildings.search_tank', { preset: tankPreset.name() })
63857                 );
63858
63859                 context.history().on('change.intro', null);
63860             }
63861         });
63862
63863         function checkPresetSearch() {
63864             var first = select('.preset-list-item:first-child');
63865
63866             if (first.classed('preset-man_made-storage_tank')) {
63867                 reveal(first.select('.preset-list-button').node(),
63868                     t('intro.buildings.choose_tank', { preset: tankPreset.name() }),
63869                     { duration: 300 }
63870                 );
63871
63872                 select('.preset-search-input')
63873                     .on('keydown.intro', eventCancel, true)
63874                     .on('keyup.intro', null);
63875
63876                 context.history().on('change.intro', function() {
63877                     continueTo(closeEditorTank);
63878                 });
63879             }
63880         }
63881
63882         function continueTo(nextStep) {
63883             select('.inspector-wrap').on('wheel.intro', null);
63884             context.on('enter.intro', null);
63885             context.history().on('change.intro', null);
63886             select('.preset-search-input').on('keydown.intro keyup.intro', null);
63887             nextStep();
63888         }
63889     }
63890
63891
63892     function closeEditorTank() {
63893         if (!tankId || !context.hasEntity(tankId)) {
63894             return addTank();
63895         }
63896         var ids = context.selectedIDs();
63897         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
63898             context.enter(modeSelect(context, [tankId]));
63899         }
63900
63901         context.history().checkpoint('hasTank');
63902
63903         context.on('exit.intro', function() {
63904             continueTo(rightClickTank);
63905         });
63906
63907         timeout(function() {
63908             reveal('.entity-editor-pane',
63909                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
63910             );
63911         }, 500);
63912
63913         function continueTo(nextStep) {
63914             context.on('exit.intro', null);
63915             nextStep();
63916         }
63917     }
63918
63919
63920     function rightClickTank() {
63921         if (!tankId) return continueTo(addTank);
63922
63923         context.enter(modeBrowse(context));
63924         context.history().reset('hasTank');
63925         context.map().centerEase(tank, 500);
63926
63927         timeout(function() {
63928             context.on('enter.intro', function(mode) {
63929                 if (mode.id !== 'select') return;
63930                 var ids = context.selectedIDs();
63931                 if (ids.length !== 1 || ids[0] !== tankId) return;
63932
63933                 timeout(function() {
63934                     var node = selectMenuItem('circularize').node();
63935                     if (!node) return;
63936                     continueTo(clickCircle);
63937                 }, 300);  // after menu visible
63938             });
63939
63940             revealTank(tank, t('intro.buildings.rightclick_tank'));
63941
63942             context.map().on('move.intro drawn.intro', function() {
63943                 revealTank(tank, t('intro.buildings.rightclick_tank'), { duration: 0 });
63944             });
63945
63946             context.history().on('change.intro', function() {
63947                 continueTo(rightClickTank);
63948             });
63949
63950         }, 600);
63951
63952         function continueTo(nextStep) {
63953             context.on('enter.intro', null);
63954             context.map().on('move.intro drawn.intro', null);
63955             context.history().on('change.intro', null);
63956             nextStep();
63957         }
63958     }
63959
63960
63961     function clickCircle() {
63962         if (!tankId) return chapter.restart();
63963         var entity = context.hasEntity(tankId);
63964         if (!entity) return continueTo(rightClickTank);
63965
63966         var node = selectMenuItem('circularize').node();
63967         if (!node) { return continueTo(rightClickTank); }
63968
63969         var wasChanged = false;
63970         var menuCoords = context.map().mouseCoordinates();
63971
63972         revealEditMenu(menuCoords,
63973             t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') })
63974         );
63975
63976         context.on('enter.intro', function(mode) {
63977             if (mode.id === 'browse') {
63978                 continueTo(rightClickTank);
63979             } else if (mode.id === 'move' || mode.id === 'rotate') {
63980                 continueTo(retryClickCircle);
63981             }
63982         });
63983
63984         context.map().on('move.intro drawn.intro', function() {
63985             var node = selectMenuItem('circularize').node();
63986             if (!wasChanged && !node) { return continueTo(rightClickTank); }
63987
63988             revealEditMenu(menuCoords,
63989                 t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') }),
63990                 { duration: 0 }
63991             );
63992         });
63993
63994         context.history().on('change.intro', function() {
63995             wasChanged = true;
63996             context.history().on('change.intro', null);
63997
63998             // Something changed.  Wait for transition to complete and check undo annotation.
63999             timeout(function() {
64000                 if (context.history().undoAnnotation() === t('operations.circularize.annotation.area')) {
64001                     continueTo(play);
64002                 } else {
64003                     continueTo(retryClickCircle);
64004                 }
64005             }, 500);  // after transitioned actions
64006         });
64007
64008         function continueTo(nextStep) {
64009             context.on('enter.intro', null);
64010             context.map().on('move.intro drawn.intro', null);
64011             context.history().on('change.intro', null);
64012             nextStep();
64013         }
64014     }
64015
64016
64017     function retryClickCircle() {
64018         context.enter(modeBrowse(context));
64019
64020         revealTank(tank, t('intro.buildings.retry_circle'), {
64021             buttonText: t('intro.ok'),
64022             buttonCallback: function() { continueTo(rightClickTank); }
64023         });
64024
64025         function continueTo(nextStep) {
64026             nextStep();
64027         }
64028     }
64029
64030
64031     function play() {
64032         dispatch$$1.call('done');
64033         reveal('#id-container',
64034             t('intro.buildings.play', { next: t('intro.startediting.title') }), {
64035                 tooltipBox: '.intro-nav-wrap .chapter-startEditing',
64036                 buttonText: t('intro.ok'),
64037                 buttonCallback: function() { reveal('#id-container'); }
64038             }
64039         );
64040     }
64041
64042
64043     chapter.enter = function() {
64044         addHouse();
64045     };
64046
64047
64048     chapter.exit = function() {
64049         timeouts.forEach(window.clearTimeout);
64050         context.on('enter.intro exit.intro', null);
64051         context.map().on('move.intro drawn.intro', null);
64052         context.history().on('change.intro', null);
64053         select('.inspector-wrap').on('wheel.intro', null);
64054         select('.preset-search-input').on('keydown.intro keyup.intro', null);
64055         select('.more-fields .combobox-input').on('click.intro', null);
64056     };
64057
64058
64059     chapter.restart = function() {
64060         chapter.exit();
64061         chapter.enter();
64062     };
64063
64064
64065     return utilRebind(chapter, dispatch$$1, 'on');
64066 }
64067
64068 function uiIntroStartEditing(context, reveal) {
64069     var dispatch$$1 = dispatch('done', 'startEditing'),
64070         modalSelection = select(null);
64071
64072
64073     var chapter = {
64074         title: 'intro.startediting.title'
64075     };
64076
64077     function showHelp() {
64078         reveal('.map-control.help-control',
64079             t('intro.startediting.help', { button: icon('#icon-help', 'pre-text'), key: t('help.key') }), {
64080                 buttonText: t('intro.ok'),
64081                 buttonCallback: function() { shortcuts(); }
64082             }
64083         );
64084     }
64085
64086     function shortcuts() {
64087         reveal('.map-control.help-control',
64088             t('intro.startediting.shortcuts', { key: t('shortcuts.toggle.key') }), {
64089                 buttonText: t('intro.ok'),
64090                 buttonCallback: function() { showSave(); }
64091             }
64092         );
64093     }
64094
64095     function showSave() {
64096         selectAll('.shaded').remove();  // in case user opened keyboard shortcuts
64097         reveal('#bar button.save',
64098             t('intro.startediting.save'), {
64099                 buttonText: t('intro.ok'),
64100                 buttonCallback: function() { showStart(); }
64101             }
64102         );
64103     }
64104
64105     function showStart() {
64106         selectAll('.shaded').remove();  // in case user opened keyboard shortcuts
64107
64108         modalSelection = uiModal(context.container());
64109
64110         modalSelection.select('.modal')
64111             .attr('class', 'modal-splash modal col6');
64112
64113         modalSelection.selectAll('.close').remove();
64114
64115         var startbutton = modalSelection.select('.content')
64116             .attr('class', 'fillL')
64117             .append('button')
64118                 .attr('class', 'modal-section huge-modal-button')
64119                 .on('click', function() {
64120                     modalSelection.remove();
64121                 });
64122
64123             startbutton
64124                 .append('svg')
64125                 .attr('class', 'illustration')
64126                 .append('use')
64127                 .attr('xlink:href', '#logo-walkthrough');
64128
64129             startbutton
64130                 .append('h2')
64131                 .text(t('intro.startediting.start'));
64132
64133         dispatch$$1.call('startEditing');
64134     }
64135
64136
64137     chapter.enter = function() {
64138         showHelp();
64139     };
64140
64141
64142     chapter.exit = function() {
64143         modalSelection.remove();
64144         selectAll('.shaded').remove();  // in case user opened keyboard shortcuts
64145     };
64146
64147
64148     return utilRebind(chapter, dispatch$$1, 'on');
64149 }
64150
64151 var chapterUi = {
64152     welcome: uiIntroWelcome,
64153     navigation: uiIntroNavigation,
64154     point: uiIntroPoint,
64155     area: uiIntroArea,
64156     line: uiIntroLine,
64157     building: uiIntroBuilding,
64158     startEditing: uiIntroStartEditing
64159 };
64160
64161 var chapterFlow = [
64162     'welcome',
64163     'navigation',
64164     'point',
64165     'area',
64166     'line',
64167     'building',
64168     'startEditing'
64169 ];
64170
64171
64172 function uiIntro(context) {
64173     var introGraph = {},
64174         currChapter;
64175
64176
64177     // create entities for intro graph and localize names
64178     for (var id in dataIntroGraph) {
64179         introGraph[id] = osmEntity$$1(localize(dataIntroGraph[id]));
64180     }
64181
64182
64183     function intro(selection$$1) {
64184         context.enter(modeBrowse(context));
64185
64186         // Save current map state
64187         var history = context.history().toJSON(),
64188             hash = window.location.hash,
64189             center = context.map().center(),
64190             zoom$$1 = context.map().zoom(),
64191             background = context.background().baseLayerSource(),
64192             overlays = context.background().overlayLayerSources(),
64193             opacity = selectAll('#map .layer-background').style('opacity'),
64194             loadedTiles = context.connection().loadedTiles(),
64195             baseEntities = context.history().graph().base().entities,
64196             countryCode = services.geocoder.countryCode;
64197
64198         // Block saving
64199         context.inIntro(true);
64200
64201         // Load semi-real data used in intro
64202         context.connection().toggle(false).reset();
64203         context.history().reset();
64204         context.history().merge(values(coreGraph$$1().load(introGraph).entities));
64205         context.history().checkpoint('initial');
64206         context.background().bing();
64207         overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
64208
64209         // Mock geocoder
64210         services.geocoder.countryCode = function(location, callback) {
64211             callback(null, t('intro.graph.countrycode'));
64212         };
64213
64214         selectAll('#map .layer-background').style('opacity', 1);
64215
64216         var curtain = uiCurtain();
64217         selection$$1.call(curtain);
64218
64219         var chapters = chapterFlow.map(function(chapter, i) {
64220             var s = chapterUi[chapter](context, curtain.reveal)
64221                 .on('done', function() {
64222                     context.presets().init();  // clear away "recent" presets
64223
64224                     buttons.filter(function(d) {
64225                         return d.title === s.title;
64226                     }).classed('finished', true);
64227
64228                     if (i < chapterFlow.length - 1) {
64229                         var next = chapterFlow[i + 1];
64230                         select('button.chapter-' + next)
64231                             .classed('next', true);
64232                     }
64233                 });
64234             return s;
64235         });
64236
64237         chapters[chapters.length - 1].on('startEditing', function() {
64238             curtain.remove();
64239             navwrap.remove();
64240             selectAll('#map .layer-background').style('opacity', opacity);
64241             context.connection().toggle(true).reset().loadedTiles(loadedTiles);
64242             context.history().reset().merge(values(baseEntities));
64243             context.background().baseLayerSource(background);
64244             overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
64245             if (history) context.history().fromJSON(history, false);
64246             context.map().centerZoom(center, zoom$$1);
64247             window.location.replace(hash);
64248             services.geocoder.countryCode = countryCode;
64249             context.inIntro(false);
64250         });
64251
64252         var navwrap = selection$$1
64253             .append('div')
64254             .attr('class', 'intro-nav-wrap fillD');
64255
64256         navwrap
64257             .append('svg')
64258             .attr('class', 'intro-nav-wrap-logo')
64259             .append('use')
64260             .attr('xlink:href', '#logo-walkthrough');
64261
64262         var buttonwrap = navwrap
64263             .append('div')
64264             .attr('class', 'joined')
64265             .selectAll('button.chapter');
64266
64267         var buttons = buttonwrap
64268             .data(chapters)
64269             .enter()
64270             .append('button')
64271             .attr('class', function(d, i) { return 'chapter chapter-' + chapterFlow[i]; })
64272             .on('click', enterChapter);
64273
64274         buttons
64275             .append('span')
64276             .text(function(d) { return t(d.title); });
64277
64278         buttons
64279             .append('span')
64280             .attr('class', 'status')
64281             .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'));
64282
64283         enterChapter(chapters[0]);
64284
64285
64286         function enterChapter(newChapter) {
64287             if (currChapter) { currChapter.exit(); }
64288             context.enter(modeBrowse(context));
64289
64290             currChapter = newChapter;
64291             currChapter.enter();
64292
64293             buttons
64294                 .classed('next', false)
64295                 .classed('active', function(d) {
64296                     return d.title === currChapter.title;
64297                 });
64298         }
64299     }
64300
64301
64302     return intro;
64303 }
64304
64305 function uiShortcuts() {
64306     var detected = utilDetect();
64307     var activeTab = 0;
64308     var modalSelection;
64309     var savedSelection;
64310
64311
64312     var keybinding = d3keybinding('shortcuts')
64313         .on(t('shortcuts.toggle.key'), function () {
64314             if (selectAll('.modal-shortcuts').size()) {  // already showing
64315                 if (modalSelection) {
64316                     modalSelection.close();
64317                     modalSelection = null;
64318                 }
64319             } else {
64320                 modalSelection = uiModal(savedSelection);
64321                 shortcutsModal(modalSelection);
64322             }
64323         });
64324
64325     select(document)
64326         .call(keybinding);
64327
64328
64329
64330     function shortcutsModal(modalSelection) {
64331         modalSelection.select('.modal')
64332             .classed('modal-shortcuts', true);
64333
64334         var shortcutsModal = modalSelection.select('.content');
64335
64336         shortcutsModal
64337             .append('div')
64338             .attr('class', 'modal-section')
64339             .append('h3')
64340             .text(t('shortcuts.title'));
64341
64342         shortcutsModal
64343             .call(render);
64344     }
64345
64346
64347     function render(selection$$1) {
64348         var wrapper = selection$$1
64349             .selectAll('.wrapper')
64350             .data([0]);
64351
64352         var wrapperEnter = wrapper
64353             .enter()
64354             .append('div')
64355             .attr('class', 'wrapper modal-section');
64356
64357         var tabsBar = wrapperEnter
64358             .append('div')
64359             .attr('class', 'tabs-bar');
64360
64361         var shortcutsList = wrapperEnter
64362             .append('div')
64363             .attr('class', 'shortcuts-list');
64364
64365         wrapper = wrapper.merge(wrapperEnter);
64366
64367         var tabs = tabsBar
64368             .selectAll('.tab')
64369             .data(dataShortcuts);
64370
64371         var tabsEnter = tabs
64372             .enter()
64373             .append('div')
64374             .attr('class', 'tab')
64375             .on('click', function (d, i) {
64376                 activeTab = i;
64377                 render(selection$$1);
64378             });
64379
64380         tabsEnter
64381             .append('span')
64382             .text(function (d) { return t(d.text); });
64383
64384         tabs = tabs
64385             .merge(tabsEnter);
64386
64387         // Update
64388         wrapper.selectAll('.tab')
64389             .classed('active', function (d, i) {
64390                 return i === activeTab;
64391             });
64392
64393
64394         var shortcuts = shortcutsList
64395             .selectAll('.shortcut-tab')
64396             .data(dataShortcuts);
64397
64398         var shortcutsEnter = shortcuts
64399             .enter()
64400             .append('div')
64401             .attr('class', function(d) { return 'shortcut-tab shortcut-tab-' + d.tab; });
64402
64403         var columnsEnter = shortcutsEnter
64404             .selectAll('.shortcut-column')
64405             .data(function (d) { return d.columns; })
64406             .enter()
64407             .append('table')
64408             .attr('class', 'shortcut-column');
64409
64410         var rowsEnter = columnsEnter
64411             .selectAll('.shortcut-row')
64412             .data(function (d) { return d.rows; })
64413             .enter()
64414             .append('tr')
64415             .attr('class', 'shortcut-row');
64416
64417
64418         var sectionRows = rowsEnter
64419             .filter(function (d) { return !d.shortcuts; });
64420
64421         sectionRows
64422             .append('td');
64423
64424         sectionRows
64425             .append('td')
64426             .attr('class', 'shortcut-section')
64427             .append('h3')
64428             .text(function (d) { return t(d.text); });
64429
64430
64431         var shortcutRows = rowsEnter
64432             .filter(function (d) { return d.shortcuts; });
64433
64434         var shortcutKeys = shortcutRows
64435             .append('td')
64436             .attr('class', 'shortcut-keys');
64437
64438         var modifierKeys = shortcutKeys
64439             .filter(function (d) { return d.modifiers; });
64440
64441         modifierKeys
64442             .selectAll('kbd.modifier')
64443             .data(function (d) {
64444                 if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
64445                     return ['⌘'];
64446                 } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
64447                     return [];
64448                 } else {
64449                     return d.modifiers;
64450                 }
64451             })
64452             .enter()
64453             .each(function () {
64454                 var selection$$1 = select(this);
64455
64456                 selection$$1
64457                     .append('kbd')
64458                     .attr('class', 'modifier')
64459                     .text(function (d) { return uiCmd.display(d); });
64460
64461                 selection$$1
64462                     .append('span')
64463                     .text('+');
64464             });
64465
64466
64467         shortcutKeys
64468             .selectAll('kbd.shortcut')
64469             .data(function (d) {
64470                 var arr = d.shortcuts;
64471                 if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
64472                     arr = ['Y'];
64473                 } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
64474                     arr = ['F11'];
64475                 }
64476
64477                 return arr.map(function(s) {
64478                     return {
64479                         shortcut: s,
64480                         separator: d.separator
64481                     };
64482                 });
64483             })
64484             .enter()
64485             .each(function (d, i, nodes) {
64486                 var selection$$1 = select(this);
64487                 var click = d.shortcut.toLowerCase().match(/(.*).click/);
64488
64489                 if (click && click[1]) {
64490                     selection$$1
64491                         .call(svgIcon('#walkthrough-mouse', 'mouseclick', click[1]));
64492                 } else {
64493                     selection$$1
64494                         .append('kbd')
64495                         .attr('class', 'shortcut')
64496                         .text(function (d) {
64497                             var key = d.shortcut;
64498                             return key.indexOf('.') !== -1 ? uiCmd.display(t(key)) : uiCmd.display(key);
64499                         });
64500                 }
64501
64502                 if (i < nodes.length - 1) {
64503                     selection$$1
64504                         .append('span')
64505                         .text(d.separator || '\u00a0' + t('shortcuts.or') + '\u00a0');
64506                 }
64507             });
64508
64509
64510         shortcutKeys
64511             .filter(function(d) { return d.gesture; })
64512             .each(function () {
64513                 var selection$$1 = select(this);
64514
64515                 selection$$1
64516                     .append('span')
64517                     .text('+');
64518
64519                 selection$$1
64520                     .append('span')
64521                     .attr('class', 'gesture')
64522                     .text(function (d) { return t(d.gesture); });
64523             });
64524
64525
64526         shortcutRows
64527             .append('td')
64528             .attr('class', 'shortcut-desc')
64529             .text(function (d) { return d.text ? t(d.text) : '\u00a0'; });
64530
64531
64532         shortcuts = shortcuts
64533             .merge(shortcutsEnter);
64534
64535         // Update
64536         wrapper.selectAll('.shortcut-tab')
64537             .style('display', function (d, i) {
64538                 return i === activeTab ? 'flex' : 'none';
64539             });
64540     }
64541
64542
64543     return function(selection$$1, show) {
64544         savedSelection = selection$$1;
64545         if (show) {
64546             modalSelection = uiModal(selection$$1);
64547             shortcutsModal(modalSelection);
64548         }
64549     };
64550 }
64551
64552 function uiHelp(context) {
64553     var key = t('help.key');
64554
64555     var docKeys = [
64556         'help.help',
64557         'help.editing_saving',
64558         'help.roads',
64559         'help.gps',
64560         'help.imagery',
64561         'help.addresses',
64562         'help.inspector',
64563         'help.buildings',
64564         'help.relations'];
64565
64566     var docs = docKeys.map(function(key) {
64567         var text$$1 = t(key);
64568         return {
64569             title: text$$1.split('\n')[0].replace('#', '').trim(),
64570             html: marked(text$$1.split('\n').slice(1).join('\n'))
64571         };
64572     });
64573
64574
64575     function help(selection$$1) {
64576
64577         function hide() {
64578             setVisible(false);
64579         }
64580
64581
64582         function toggle() {
64583             if (event) event.preventDefault();
64584             tooltipBehavior.hide(button);
64585             setVisible(!button.classed('active'));
64586         }
64587
64588
64589         function setVisible(show) {
64590             if (show !== shown) {
64591                 button.classed('active', show);
64592                 shown = show;
64593
64594                 if (show) {
64595                     selection$$1.on('mousedown.help-inside', function() {
64596                         return event.stopPropagation();
64597                     });
64598                     pane.style('display', 'block')
64599                         .style('right', '-500px')
64600                         .transition()
64601                         .duration(200)
64602                         .style('right', '0px');
64603                 } else {
64604                     pane.style('right', '0px')
64605                         .transition()
64606                         .duration(200)
64607                         .style('right', '-500px')
64608                         .on('end', function() {
64609                             select(this).style('display', 'none');
64610                         });
64611                     selection$$1.on('mousedown.help-inside', null);
64612                 }
64613             }
64614         }
64615
64616
64617         function clickHelp(d, i) {
64618             var rtl = (textDirection === 'rtl');
64619             pane.property('scrollTop', 0);
64620             doctitle.html(d.title);
64621
64622             body.html(d.html);
64623             body.selectAll('a')
64624                 .attr('target', '_blank');
64625             menuItems.classed('selected', function(m) {
64626                 return m.title === d.title;
64627             });
64628
64629             nav.html('');
64630             if (rtl) {
64631                 nav.call(drawNext).call(drawPrevious);
64632             } else {
64633                 nav.call(drawPrevious).call(drawNext);
64634             }
64635
64636
64637             function drawNext(selection$$1) {
64638                 if (i < docs.length - 1) {
64639                     var nextLink = selection$$1
64640                         .append('a')
64641                         .attr('class', 'next')
64642                         .on('click', function() {
64643                             clickHelp(docs[i + 1], i + 1);
64644                         });
64645
64646                     nextLink
64647                         .append('span')
64648                         .text(docs[i + 1].title)
64649                         .call(svgIcon((rtl ? '#icon-backward' : '#icon-forward'), 'inline'));
64650                 }
64651             }
64652
64653
64654             function drawPrevious(selection$$1) {
64655                 if (i > 0) {
64656                     var prevLink = selection$$1
64657                         .append('a')
64658                         .attr('class', 'previous')
64659                         .on('click', function() {
64660                             clickHelp(docs[i - 1], i - 1);
64661                         });
64662
64663                     prevLink
64664                         .call(svgIcon((rtl ? '#icon-forward' : '#icon-backward'), 'inline'))
64665                         .append('span')
64666                         .text(docs[i - 1].title);
64667                 }
64668             }
64669         }
64670
64671
64672         function clickWalkthrough() {
64673             if (context.inIntro()) return;
64674             context.container().call(uiIntro(context));
64675             setVisible(false);
64676         }
64677
64678
64679         function clickShortcuts() {
64680             context.container().call(uiShortcuts(context), true);
64681         }
64682
64683
64684         var pane = selection$$1.append('div')
64685                 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
64686             tooltipBehavior = tooltip()
64687                 .placement((textDirection === 'rtl') ? 'right' : 'left')
64688                 .html(true)
64689                 .title(uiTooltipHtml(t('help.title'), key)),
64690             button = selection$$1.append('button')
64691                 .attr('tabindex', -1)
64692                 .on('click', toggle)
64693                 .call(svgIcon('#icon-help', 'light'))
64694                 .call(tooltipBehavior),
64695             shown = false;
64696
64697
64698         var toc = pane.append('ul')
64699             .attr('class', 'toc');
64700
64701         var menuItems = toc.selectAll('li')
64702             .data(docs)
64703             .enter()
64704             .append('li')
64705             .append('a')
64706             .html(function(d) { return d.title; })
64707             .on('click', clickHelp);
64708
64709         var shortcuts = toc
64710             .append('li')
64711             .attr('class', 'shortcuts')
64712             .call(tooltip()
64713                 .html(true)
64714                 .title(uiTooltipHtml(t('shortcuts.tooltip'), '?'))
64715                 .placement('top')
64716             )
64717             .append('a')
64718             .on('click', clickShortcuts);
64719
64720         shortcuts
64721             .append('div')
64722             .text(t('shortcuts.title'));
64723
64724         var walkthrough = toc
64725             .append('li')
64726             .attr('class', 'walkthrough')
64727             .append('a')
64728             .on('click', clickWalkthrough);
64729
64730         walkthrough
64731             .append('svg')
64732             .attr('class', 'logo logo-walkthrough')
64733             .append('use')
64734             .attr('xlink:href', '#logo-walkthrough');
64735
64736         walkthrough
64737             .append('div')
64738             .text(t('splash.walkthrough'));
64739
64740
64741         var content = pane.append('div')
64742             .attr('class', 'left-content');
64743
64744         var doctitle = content.append('h2')
64745             .text(t('help.title'));
64746
64747         var body = content.append('div')
64748             .attr('class', 'body');
64749
64750         var nav = content.append('div')
64751             .attr('class', 'nav');
64752
64753         clickHelp(docs[0], 0);
64754
64755         var keybinding = d3keybinding('help')
64756             .on(key, toggle)
64757             .on([t('background.key'), t('map_data.key')], hide);
64758
64759         select(document)
64760             .call(keybinding);
64761
64762         context.surface().on('mousedown.help-outside', hide);
64763         context.container().on('mousedown.help-outside', hide);
64764     }
64765
64766     return help;
64767 }
64768
64769 function uiPanelBackground(context) {
64770     var background = context.background();
64771     var currSource = null;
64772     var currZoom = '';
64773     var currVintage = '';
64774
64775
64776     function redraw(selection$$1) {
64777         if (currSource !== background.baseLayerSource().name()) {
64778             currSource = background.baseLayerSource().name();
64779             currZoom = '';
64780             currVintage = '';
64781         }
64782
64783         selection$$1.html('');
64784
64785         var list = selection$$1
64786             .append('ul')
64787             .attr('class', 'background-info');
64788
64789         list
64790             .append('li')
64791             .text(currSource);
64792
64793         list
64794             .append('li')
64795             .text(t('info_panels.background.zoom') + ': ')
64796             .append('span')
64797             .attr('class', 'zoom')
64798             .text(currZoom);
64799
64800         list
64801             .append('li')
64802             .text(t('info_panels.background.vintage') + ': ')
64803             .append('span')
64804             .attr('class', 'vintage')
64805             .text(currVintage);
64806
64807         if (!currVintage) {
64808             debouncedGetVintage(selection$$1);
64809         }
64810
64811         var toggle = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles';
64812
64813         selection$$1
64814             .append('a')
64815             .text(t('info_panels.background.' + toggle))
64816             .attr('href', '#')
64817             .attr('class', 'button button-toggle-tiles')
64818             .on('click', function() {
64819                 event.preventDefault();
64820                 context.setDebug('tile', !context.getDebug('tile'));
64821                 selection$$1.call(redraw);
64822             });
64823     }
64824
64825
64826     var debouncedGetVintage = lodash.debounce(getVintage, 250);
64827     function getVintage(selection$$1) {
64828         var tile = select('.layer-background img.tile-center');   // tile near viewport center
64829         if (tile.empty()) return;
64830
64831         var d = tile.datum(),
64832             zoom$$1 = (d && d.length >= 3 && d[2]) || Math.floor(context.map().zoom()),
64833             center = context.map().center();
64834
64835         currZoom = String(zoom$$1);
64836         selection$$1.selectAll('.zoom')
64837             .text(currZoom);
64838
64839         if (!d || !d.length >= 3) return;
64840         background.baseLayerSource().getVintage(center, d, function(err, result) {
64841             currVintage = (result && result.range) || t('info_panels.background.unknown');
64842             selection$$1.selectAll('.vintage')
64843                 .text(currVintage);
64844         });
64845     }
64846
64847
64848     var panel = function(selection$$1) {
64849         selection$$1.call(redraw);
64850
64851         context.map()
64852             .on('drawn.info-background', function() {
64853                 selection$$1.call(redraw);
64854             })
64855             .on('move.info-background', function() {
64856                 selection$$1.call(debouncedGetVintage);
64857             });
64858
64859     };
64860
64861     panel.off = function() {
64862         context.map()
64863             .on('drawn.info-background', null)
64864             .on('move.info-background', null);
64865     };
64866
64867     panel.id = 'background';
64868     panel.title = t('info_panels.background.title');
64869     panel.key = t('info_panels.background.key');
64870
64871
64872     return panel;
64873 }
64874
64875 function uiPanelHistory(context) {
64876
64877
64878     function displayTimestamp(entity) {
64879         if (!entity.timestamp) return t('info_panels.history.unknown');
64880
64881         var d = new Date(entity.timestamp);
64882         if (isNaN(d.getTime())) return t('info_panels.history.unknown');
64883
64884         return d.toLocaleString();
64885     }
64886
64887
64888     function displayUser(selection, entity) {
64889         if (!entity.user) {
64890             selection
64891                 .append('span')
64892                 .text(t('info_panels.history.unknown'));
64893             return;
64894         }
64895
64896         selection
64897             .append('span')
64898             .attr('class', 'user-name')
64899             .text(entity.user);
64900
64901         var links = selection
64902             .append('div')
64903             .attr('class', 'links');
64904
64905         links
64906             .append('a')
64907             .attr('class', 'user-osm-link')
64908             .attr('href', context.connection().userURL(entity.user))
64909             .attr('target', '_blank')
64910             .attr('tabindex', -1)
64911             .text('OSM');
64912
64913         links
64914             .append('a')
64915             .attr('class', 'user-hdyc-link')
64916             .attr('href', 'https://hdyc.neis-one.org/?' + entity.user)
64917             .attr('target', '_blank')
64918             .attr('tabindex', -1)
64919             .text('HDYC');
64920     }
64921
64922
64923     function displayChangeset(selection, entity) {
64924         if (!entity.changeset) {
64925             selection
64926                 .append('span')
64927                 .text(t('info_panels.history.unknown'));
64928             return;
64929         }
64930
64931         selection
64932             .append('span')
64933             .attr('class', 'changeset-id')
64934             .text(entity.changeset);
64935
64936         var links = selection
64937             .append('div')
64938             .attr('class', 'links');
64939
64940         links
64941             .append('a')
64942             .attr('class', 'changeset-osm-link')
64943             .attr('href', context.connection().changesetURL(entity.changeset))
64944             .attr('target', '_blank')
64945             .attr('tabindex', -1)
64946             .text('OSM');
64947
64948         links
64949             .append('a')
64950             .attr('class', 'changeset-osmcha-link')
64951             .attr('href', 'https://osmcha.mapbox.com/changesets/' + entity.changeset)
64952             .attr('target', '_blank')
64953             .attr('tabindex', -1)
64954             .text('OSMCha');
64955     }
64956
64957
64958     function redraw(selection) {
64959         var selected = lodash.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
64960             singular = selected.length === 1 ? selected[0] : null;
64961
64962         selection.html('');
64963
64964         selection
64965             .append('h4')
64966             .attr('class', 'history-heading')
64967             .text(singular || t('info_panels.history.selected', { n: selected.length }));
64968
64969         if (!singular) return;
64970
64971         var entity = context.entity(singular);
64972
64973         var list = selection
64974             .append('ul');
64975
64976         list
64977             .append('li')
64978             .text(t('info_panels.history.version') + ': ' + entity.version);
64979
64980         list
64981             .append('li')
64982             .text(t('info_panels.history.last_edit') + ': ' + displayTimestamp(entity));
64983
64984         list
64985             .append('li')
64986             .text(t('info_panels.history.edited_by') + ': ')
64987             .call(displayUser, entity);
64988
64989         list
64990             .append('li')
64991             .text(t('info_panels.history.changeset') + ': ')
64992             .call(displayChangeset, entity);
64993
64994         selection
64995             .append('a')
64996             .attr('class', 'view-history-on-osm')
64997             .attr('target', '_blank')
64998             .attr('tabindex', -1)
64999             .attr('href', context.connection().historyURL(entity))
65000             .call(svgIcon('#icon-out-link', 'inline'))
65001             .append('span')
65002             .text(t('info_panels.history.link_text'));
65003     }
65004
65005
65006     var panel = function(selection) {
65007         selection.call(redraw);
65008
65009         context.map()
65010             .on('drawn.info-history', function() {
65011                 selection.call(redraw);
65012             });
65013     };
65014
65015     panel.off = function() {
65016         context.map()
65017             .on('drawn.info-history', null);
65018     };
65019
65020     panel.id = 'history';
65021     panel.title = t('info_panels.history.title');
65022     panel.key = t('info_panels.history.key');
65023
65024
65025     return panel;
65026 }
65027
65028 function uiPanelLocation(context) {
65029     var currLocation = '';
65030     var OSM_PRECISION = 7;
65031
65032
65033     function wrap(x, min, max) {
65034         var d = max - min;
65035         return ((x - min) % d + d) % d + min;
65036     }
65037
65038
65039     function clamp(x, min, max) {
65040         return Math.max(min, Math.min(x, max));
65041     }
65042
65043
65044     function redraw(selection) {
65045         selection.html('');
65046
65047         var list = selection
65048             .append('ul');
65049
65050         // Mouse coordinates
65051         var coord = context.map().mouseCoordinates();
65052         if (coord.some(isNaN)) {
65053             coord = context.map().center();
65054         }
65055
65056         var coordStr =
65057             clamp(coord[1], -90, 90).toFixed(OSM_PRECISION) + ', ' +
65058             wrap(coord[0], -180, 180).toFixed(OSM_PRECISION);
65059
65060         list
65061             .append('li')
65062             .text(coordStr);
65063
65064         // Location Info
65065         selection
65066             .append('div')
65067             .attr('class', 'location-info')
65068             .text(currLocation || ' ');
65069
65070         debouncedGetLocation(selection, coord);
65071     }
65072
65073
65074     var debouncedGetLocation = lodash.debounce(getLocation, 250);
65075     function getLocation(selection, coord) {
65076         if (!services.geocoder) {
65077             currLocation = t('info_panels.location.unknown_location');
65078             selection.selectAll('.location-info')
65079                 .text(currLocation);
65080         } else {
65081             services.geocoder.reverse(coord, function(err, result) {
65082                 currLocation = result ? result.display_name : t('info_panels.location.unknown_location');
65083                 selection.selectAll('.location-info')
65084                     .text(currLocation);
65085             });
65086         }
65087     }
65088
65089
65090     var panel = function(selection) {
65091         selection.call(redraw);
65092
65093         context.surface()
65094             .on('mousemove.info-location', function() {
65095                 selection.call(redraw);
65096             });
65097     };
65098
65099     panel.off = function() {
65100         context.surface()
65101             .on('mousemove.info-location', null);
65102     };
65103
65104     panel.id = 'location';
65105     panel.title = t('info_panels.location.title');
65106     panel.key = t('info_panels.location.key');
65107
65108
65109     return panel;
65110 }
65111
65112 function uiPanelMeasurement(context) {
65113     var isImperial = (utilDetect().locale.toLowerCase() === 'en-us');
65114     var OSM_PRECISION = 7;
65115
65116
65117     function radiansToMeters(r) {
65118         // using WGS84 authalic radius (6371007.1809 m)
65119         return r * 6371007.1809;
65120     }
65121
65122     function steradiansToSqmeters(r) {
65123         // http://gis.stackexchange.com/a/124857/40446
65124         return r / (4 * Math.PI) * 510065621724000;
65125     }
65126
65127
65128     function toLineString(feature) {
65129         if (feature.type === 'LineString') return feature;
65130
65131         var result = { type: 'LineString', coordinates: [] };
65132         if (feature.type === 'Polygon') {
65133             result.coordinates = feature.coordinates[0];
65134         } else if (feature.type === 'MultiPolygon') {
65135             result.coordinates = feature.coordinates[0][0];
65136         }
65137
65138         return result;
65139     }
65140
65141
65142     function displayLength(m) {
65143         var d = m * (isImperial ? 3.28084 : 1),
65144             p, unit;
65145
65146         if (isImperial) {
65147             if (d >= 5280) {
65148                 d /= 5280;
65149                 unit = 'mi';
65150             } else {
65151                 unit = 'ft';
65152             }
65153         } else {
65154             if (d >= 1000) {
65155                 d /= 1000;
65156                 unit = 'km';
65157             } else {
65158                 unit = 'm';
65159             }
65160         }
65161
65162         // drop unnecessary precision
65163         p = d > 1000 ? 0 : d > 100 ? 1 : 2;
65164
65165         return String(d.toFixed(p)) + ' ' + unit;
65166     }
65167
65168
65169     function displayArea(m2) {
65170         var d = m2 * (isImperial ? 10.7639111056 : 1),
65171             d1, d2, p1, p2, unit1, unit2;
65172
65173         if (isImperial) {
65174             if (d >= 6969600) {     // > 0.25mi² show mi²
65175                 d1 = d / 27878400;
65176                 unit1 = 'mi²';
65177             } else {
65178                 d1 = d;
65179                 unit1 = 'ft²';
65180             }
65181
65182             if (d > 4356 && d < 43560000) {   // 0.1 - 1000 acres
65183                 d2 = d / 43560;
65184                 unit2 = 'ac';
65185             }
65186
65187         } else {
65188             if (d >= 250000) {    // > 0.25km² show km²
65189                 d1 = d / 1000000;
65190                 unit1 = 'km²';
65191             } else {
65192                 d1 = d;
65193                 unit1 = 'm²';
65194             }
65195
65196             if (d > 1000 && d < 10000000) {   // 0.1 - 1000 hectares
65197                 d2 = d / 10000;
65198                 unit2 = 'ha';
65199             }
65200         }
65201
65202         // drop unnecessary precision
65203         p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
65204         p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
65205
65206         return String(d1.toFixed(p1)) + ' ' + unit1 +
65207             (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
65208     }
65209
65210
65211     function redraw(selection$$1) {
65212         var resolver = context.graph(),
65213             selected = lodash.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
65214             singular = selected.length === 1 ? selected[0] : null,
65215             extent$$1 = geoExtent$$1(),
65216             entity;
65217
65218         selection$$1.html('');
65219
65220         selection$$1
65221             .append('h4')
65222             .attr('class', 'measurement-heading')
65223             .text(singular || t('info_panels.measurement.selected', { n: selected.length }));
65224
65225         if (!selected.length) return;
65226
65227         var center;
65228         for (var i = 0; i < selected.length; i++) {
65229             entity = context.entity(selected[i]);
65230             extent$$1._extend(entity.extent(resolver));
65231         }
65232         center = extent$$1.center();
65233
65234
65235         var list = selection$$1
65236             .append('ul');
65237
65238         // multiple features, just display extent center..
65239         if (!singular) {
65240             list
65241                 .append('li')
65242                 .text(t('info_panels.measurement.center') + ': ' +
65243                     center[1].toFixed(OSM_PRECISION) + ', ' + center[0].toFixed(OSM_PRECISION)
65244                 );
65245             return;
65246         }
65247
65248         // single feature, display details..
65249         if (!entity) return;
65250         var geometry = entity.geometry(resolver);
65251
65252         if (geometry === 'line' || geometry === 'area') {
65253             var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
65254                 feature = entity.asGeoJSON(resolver),
65255                 length = radiansToMeters(d3GeoLength(toLineString(feature))),
65256                 lengthLabel = t('info_panels.measurement.' + (closed ? 'perimeter' : 'length')),
65257                 centroid = d3GeoCentroid(feature);
65258
65259             list
65260                 .append('li')
65261                 .text(t('info_panels.measurement.geometry') + ': ' +
65262                     (closed ? t('info_panels.measurement.closed') + ' ' : '') + t('geometry.' + geometry) );
65263
65264             if (closed) {
65265                 var area$$1 = steradiansToSqmeters(entity.area(resolver));
65266                 list
65267                     .append('li')
65268                     .text(t('info_panels.measurement.area') + ': ' + displayArea(area$$1));
65269             }
65270
65271             list
65272                 .append('li')
65273                 .text(lengthLabel + ': ' + displayLength(length));
65274
65275             list
65276                 .append('li')
65277                 .text(t('info_panels.measurement.centroid') + ': ' +
65278                     centroid[1].toFixed(OSM_PRECISION) + ', ' + centroid[0].toFixed(OSM_PRECISION)
65279                 );
65280
65281
65282             var toggle  = isImperial ? 'imperial' : 'metric';
65283
65284             selection$$1
65285                 .append('a')
65286                 .text(t('info_panels.measurement.' + toggle))
65287                 .attr('href', '#')
65288                 .attr('class', 'button button-toggle-units')
65289                 .on('click', function() {
65290                     event.preventDefault();
65291                     isImperial = !isImperial;
65292                     selection$$1.call(redraw);
65293                 });
65294
65295         } else {
65296             var centerLabel = t('info_panels.measurement.' + (entity.type === 'node' ? 'location' : 'center'));
65297
65298             list
65299                 .append('li')
65300                 .text(t('info_panels.measurement.geometry') + ': ' + t('geometry.' + geometry));
65301
65302             list
65303                 .append('li')
65304                 .text(centerLabel + ': ' +
65305                     center[1].toFixed(OSM_PRECISION) + ', ' + center[0].toFixed(OSM_PRECISION)
65306                 );
65307         }
65308     }
65309
65310
65311     var panel = function(selection$$1) {
65312         selection$$1.call(redraw);
65313
65314         context.map()
65315             .on('drawn.info-measurement', function() {
65316                 selection$$1.call(redraw);
65317             });
65318     };
65319
65320     panel.off = function() {
65321         context.map()
65322             .on('drawn.info-measurement', null);
65323     };
65324
65325     panel.id = 'measurement';
65326     panel.title = t('info_panels.measurement.title');
65327     panel.key = t('info_panels.measurement.key');
65328
65329
65330     return panel;
65331 }
65332
65333 var uiInfoPanels = {
65334     background: uiPanelBackground,
65335     history: uiPanelHistory,
65336     location: uiPanelLocation,
65337     measurement: uiPanelMeasurement,
65338 };
65339
65340 function uiInfo(context) {
65341     var ids = Object.keys(uiInfoPanels),
65342         wasActive = ['measurement'],
65343         panels = {},
65344         active$$1 = {};
65345
65346     // create panels
65347     ids.forEach(function(k) {
65348         if (!panels[k]) {
65349             panels[k] = uiInfoPanels[k](context);
65350             active$$1[k] = false;
65351         }
65352     });
65353
65354
65355     function info(selection$$1) {
65356
65357         function redraw() {
65358             var activeids = ids.filter(function(k) { return active$$1[k]; }).sort();
65359
65360             var containers = infoPanels.selectAll('.panel-container')
65361                 .data(activeids, function(k) { return k; });
65362
65363             containers.exit()
65364                 .style('opacity', 1)
65365                 .transition()
65366                 .duration(200)
65367                 .style('opacity', 0)
65368                 .on('end', function(d) {
65369                     select(this)
65370                         .call(panels[d].off)
65371                         .remove();
65372                 });
65373
65374             var enter = containers.enter()
65375                 .append('div')
65376                 .attr('class', function(d) { return 'fillD2 panel-container panel-container-' + d; });
65377
65378             enter
65379                 .style('opacity', 0)
65380                 .transition()
65381                 .duration(200)
65382                 .style('opacity', 1);
65383
65384             var title = enter
65385                 .append('div')
65386                 .attr('class', 'panel-title fillD2');
65387
65388             title
65389                 .append('h3')
65390                 .text(function(d) { return panels[d].title; });
65391
65392             title
65393                 .append('button')
65394                 .attr('class', 'close')
65395                 .on('click', function (d) { toggle(d); })
65396                 .call(svgIcon('#icon-close'));
65397
65398             enter
65399                 .append('div')
65400                 .attr('class', function(d) { return 'panel-content panel-content-' + d; });
65401
65402
65403             // redraw the panels
65404             infoPanels.selectAll('.panel-content')
65405                 .each(function(d) {
65406                     select(this).call(panels[d]);
65407                 });
65408         }
65409
65410
65411         function toggle(which) {
65412             if (event) event.preventDefault();
65413
65414             var activeids = ids.filter(function(k) { return active$$1[k]; });
65415
65416             if (which) {  // toggle one
65417                 active$$1[which] = !active$$1[which];
65418                 if (activeids.length === 1 && activeids[0] === which) {  // none active anymore
65419                     wasActive = [which];
65420                 }
65421             } else {      // toggle all
65422                 if (activeids.length) {
65423                     wasActive = activeids;
65424                     activeids.forEach(function(k) { active$$1[k] = false; });
65425                 } else {
65426                     wasActive.forEach(function(k) { active$$1[k] = true; });
65427                 }
65428             }
65429
65430             redraw();
65431         }
65432
65433
65434         var infoPanels = selection$$1.selectAll('.info-panels')
65435             .data([0]);
65436
65437         infoPanels = infoPanels.enter()
65438             .append('div')
65439             .attr('class', 'info-panels')
65440             .merge(infoPanels);
65441
65442         redraw();
65443
65444         var keybinding = d3keybinding('info')
65445             .on(uiCmd('⌘' + t('info_panels.key')), toggle);
65446
65447         ids.forEach(function(k) {
65448             var key = t('info_panels.' + k + '.key', { default: null });
65449             if (!key) return;
65450             keybinding
65451                 .on(uiCmd('⌘⇧' + key), function() { toggle(k); });
65452         });
65453
65454         select(document)
65455             .call(keybinding);
65456     }
65457
65458     return info;
65459 }
65460
65461 function uiMapData(context) {
65462     var key = t('map_data.key'),
65463         features = context.features().keys(),
65464         layers = context.layers(),
65465         fills = ['wireframe', 'partial', 'full'],
65466         fillDefault = context.storage('area-fill') || 'partial',
65467         fillSelected = fillDefault;
65468
65469
65470     function map_data(selection$$1) {
65471
65472         function showsFeature(d) {
65473             return context.features().enabled(d);
65474         }
65475
65476
65477         function autoHiddenFeature(d) {
65478             return context.features().autoHidden(d);
65479         }
65480
65481
65482         function clickFeature(d) {
65483             context.features().toggle(d);
65484             update();
65485         }
65486
65487
65488         function showsFill(d) {
65489             return fillSelected === d;
65490         }
65491
65492
65493         function setFill(d) {
65494             lodash.each(fills, function(opt) {
65495                 context.surface().classed('fill-' + opt, Boolean(opt === d));
65496             });
65497
65498             fillSelected = d;
65499             if (d !== 'wireframe') {
65500                 fillDefault = d;
65501                 context.storage('area-fill', d);
65502             }
65503             update();
65504         }
65505
65506
65507         function showsLayer(which) {
65508             var layer = layers.layer(which);
65509             if (layer) {
65510                 return layer.enabled();
65511             }
65512             return false;
65513         }
65514
65515
65516         function setLayer(which, enabled) {
65517             var layer = layers.layer(which);
65518             if (layer) {
65519                 layer.enabled(enabled);
65520                 update();
65521             }
65522         }
65523
65524
65525         function toggleLayer(which) {
65526             setLayer(which, !showsLayer(which));
65527         }
65528
65529
65530         function clickGpx() {
65531             toggleLayer('gpx');
65532         }
65533
65534
65535         function clickMapillaryImages() {
65536             toggleLayer('mapillary-images');
65537             if (!showsLayer('mapillary-images')) {
65538                 setLayer('mapillary-signs', false);
65539             }
65540         }
65541
65542
65543         function clickMapillarySigns() {
65544             toggleLayer('mapillary-signs');
65545         }
65546
65547
65548         function drawMapillaryItems(selection$$1) {
65549             var mapillaryImages = layers.layer('mapillary-images'),
65550                 mapillarySigns = layers.layer('mapillary-signs'),
65551                 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
65552                 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
65553                 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
65554                 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
65555
65556             var mapillaryList = selection$$1
65557                 .selectAll('.layer-list-mapillary')
65558                 .data([0]);
65559
65560             mapillaryList = mapillaryList.enter()
65561                 .append('ul')
65562                 .attr('class', 'layer-list layer-list-mapillary')
65563                 .merge(mapillaryList);
65564
65565
65566             var mapillaryImageLayerItem = mapillaryList
65567                 .selectAll('.list-item-mapillary-images')
65568                 .data(supportsMapillaryImages ? [0] : []);
65569
65570             mapillaryImageLayerItem.exit()
65571                 .remove();
65572
65573             var enterImages = mapillaryImageLayerItem.enter()
65574                 .append('li')
65575                 .attr('class', 'list-item-mapillary-images');
65576
65577             var labelImages = enterImages
65578                 .append('label')
65579                 .call(tooltip()
65580                     .title(t('mapillary_images.tooltip'))
65581                     .placement('top'));
65582
65583             labelImages
65584                 .append('input')
65585                 .attr('type', 'checkbox')
65586                 .on('change', clickMapillaryImages);
65587
65588             labelImages
65589                 .append('span')
65590                 .text(t('mapillary_images.title'));
65591
65592
65593             var mapillarySignLayerItem = mapillaryList
65594                 .selectAll('.list-item-mapillary-signs')
65595                 .data(supportsMapillarySigns ? [0] : []);
65596
65597             mapillarySignLayerItem.exit()
65598                 .remove();
65599
65600             var enterSigns = mapillarySignLayerItem.enter()
65601                 .append('li')
65602                 .attr('class', 'list-item-mapillary-signs');
65603
65604             var labelSigns = enterSigns
65605                 .append('label')
65606                 .call(tooltip()
65607                     .title(t('mapillary_signs.tooltip'))
65608                     .placement('top'));
65609
65610             labelSigns
65611                 .append('input')
65612                 .attr('type', 'checkbox')
65613                 .on('change', clickMapillarySigns);
65614
65615             labelSigns
65616                 .append('span')
65617                 .text(t('mapillary_signs.title'));
65618
65619
65620             // Updates
65621             mapillaryImageLayerItem = mapillaryImageLayerItem
65622                 .merge(enterImages);
65623
65624             mapillaryImageLayerItem
65625                 .classed('active', showsMapillaryImages)
65626                 .selectAll('input')
65627                 .property('checked', showsMapillaryImages);
65628
65629
65630             mapillarySignLayerItem = mapillarySignLayerItem
65631                 .merge(enterSigns);
65632
65633             mapillarySignLayerItem
65634                 .classed('active', showsMapillarySigns)
65635                 .selectAll('input')
65636                 .property('disabled', !showsMapillaryImages)
65637                 .property('checked', showsMapillarySigns);
65638
65639             mapillarySignLayerItem
65640                 .selectAll('label')
65641                 .classed('deemphasize', !showsMapillaryImages);
65642         }
65643
65644
65645         function drawGpxItem(selection$$1) {
65646             var gpx = layers.layer('gpx'),
65647                 hasGpx = gpx && gpx.hasGpx(),
65648                 showsGpx = hasGpx && gpx.enabled();
65649
65650             var gpxLayerItem = selection$$1
65651                 .selectAll('.layer-list-gpx')
65652                 .data(gpx ? [0] : []);
65653
65654             // Exit
65655             gpxLayerItem.exit()
65656                 .remove();
65657
65658             // Enter
65659             var enter = gpxLayerItem.enter()
65660                 .append('ul')
65661                 .attr('class', 'layer-list layer-list-gpx')
65662                 .append('li')
65663                 .classed('list-item-gpx', true);
65664
65665             enter
65666                 .append('button')
65667                 .attr('class', 'list-item-gpx-extent')
65668                 .call(tooltip()
65669                     .title(t('gpx.zoom'))
65670                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
65671                 .on('click', function() {
65672                     event.preventDefault();
65673                     event.stopPropagation();
65674                     gpx.fitZoom();
65675                 })
65676                 .call(svgIcon('#icon-search'));
65677
65678             enter
65679                 .append('button')
65680                 .attr('class', 'list-item-gpx-browse')
65681                 .call(tooltip()
65682                     .title(t('gpx.browse'))
65683                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
65684                 .on('click', function() {
65685                     select(document.createElement('input'))
65686                         .attr('type', 'file')
65687                         .on('change', function() {
65688                             gpx.files(event.target.files);
65689                         })
65690                         .node().click();
65691                 })
65692                 .call(svgIcon('#icon-geolocate'));
65693
65694             var labelGpx = enter
65695                 .append('label')
65696                 .call(tooltip().title(t('gpx.drag_drop')).placement('top'));
65697
65698             labelGpx
65699                 .append('input')
65700                 .attr('type', 'checkbox')
65701                 .on('change', clickGpx);
65702
65703             labelGpx
65704                 .append('span')
65705                 .text(t('gpx.local_layer'));
65706
65707
65708             // Update
65709             gpxLayerItem = gpxLayerItem
65710                 .merge(enter);
65711
65712             gpxLayerItem
65713                 .classed('active', showsGpx)
65714                 .selectAll('input')
65715                 .property('disabled', !hasGpx)
65716                 .property('checked', showsGpx);
65717
65718             gpxLayerItem
65719                 .selectAll('label')
65720                 .classed('deemphasize', !hasGpx);
65721         }
65722
65723
65724         function drawList(selection$$1, data, type, name, change, active$$1) {
65725             var items = selection$$1.selectAll('li')
65726                 .data(data);
65727
65728             // Exit
65729             items.exit()
65730                 .remove();
65731
65732             // Enter
65733             var enter = items.enter()
65734                 .append('li')
65735                 .attr('class', 'layer')
65736                 .call(tooltip()
65737                     .html(true)
65738                     .title(function(d) {
65739                         var tip = t(name + '.' + d + '.tooltip'),
65740                             key = (d === 'wireframe' ? t('area_fill.wireframe.key') : null);
65741
65742                         if (name === 'feature' && autoHiddenFeature(d)) {
65743                             tip += '<div>' + t('map_data.autohidden') + '</div>';
65744                         }
65745                         return uiTooltipHtml(tip, key);
65746                     })
65747                     .placement('top')
65748                 );
65749
65750             var label = enter
65751                 .append('label');
65752
65753             label
65754                 .append('input')
65755                 .attr('type', type)
65756                 .attr('name', name)
65757                 .on('change', change);
65758
65759             label
65760                 .append('span')
65761                 .text(function(d) { return t(name + '.' + d + '.description'); });
65762
65763             // Update
65764             items = items
65765                 .merge(enter);
65766
65767             items
65768                 .classed('active', active$$1)
65769                 .selectAll('input')
65770                 .property('checked', active$$1)
65771                 .property('indeterminate', function(d) {
65772                     return (name === 'feature' && autoHiddenFeature(d));
65773                 });
65774         }
65775
65776
65777         function update() {
65778             dataLayerContainer.call(drawMapillaryItems);
65779             dataLayerContainer.call(drawGpxItem);
65780
65781             fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
65782             featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
65783         }
65784
65785
65786         function hidePanel() {
65787             setVisible(false);
65788         }
65789
65790
65791         function togglePanel() {
65792             if (event) event.preventDefault();
65793             tooltipBehavior.hide(button);
65794             setVisible(!button.classed('active'));
65795         }
65796
65797
65798         function toggleWireframe() {
65799             if (event) {
65800                 event.preventDefault();
65801                 event.stopPropagation();
65802             }
65803             setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
65804             context.map().pan([0,0]);  // trigger a redraw
65805         }
65806
65807
65808         function setVisible(show) {
65809             if (show !== shown) {
65810                 button.classed('active', show);
65811                 shown = show;
65812
65813                 if (show) {
65814                     update();
65815                     selection$$1.on('mousedown.map_data-inside', function() {
65816                         return event.stopPropagation();
65817                     });
65818                     content.style('display', 'block')
65819                         .style('right', '-300px')
65820                         .transition()
65821                         .duration(200)
65822                         .style('right', '0px');
65823                 } else {
65824                     content.style('display', 'block')
65825                         .style('right', '0px')
65826                         .transition()
65827                         .duration(200)
65828                         .style('right', '-300px')
65829                         .on('end', function() {
65830                             select(this).style('display', 'none');
65831                         });
65832                     selection$$1.on('mousedown.map_data-inside', null);
65833                 }
65834             }
65835         }
65836
65837
65838         var content = selection$$1
65839                 .append('div')
65840                 .attr('class', 'fillL map-overlay col3 content hide'),
65841             tooltipBehavior = tooltip()
65842                 .placement((textDirection === 'rtl') ? 'right' : 'left')
65843                 .html(true)
65844                 .title(uiTooltipHtml(t('map_data.description'), key)),
65845             button = selection$$1
65846                 .append('button')
65847                 .attr('tabindex', -1)
65848                 .on('click', togglePanel)
65849                 .call(svgIcon('#icon-data', 'light'))
65850                 .call(tooltipBehavior),
65851             shown = false;
65852
65853         content
65854             .append('h4')
65855             .text(t('map_data.title'));
65856
65857
65858         // data layers
65859         content
65860             .append('a')
65861             .text(t('map_data.data_layers'))
65862             .attr('href', '#')
65863             .classed('hide-toggle', true)
65864             .classed('expanded', true)
65865             .on('click', function() {
65866                 var exp = select(this).classed('expanded');
65867                 dataLayerContainer.style('display', exp ? 'none' : 'block');
65868                 select(this).classed('expanded', !exp);
65869                 event.preventDefault();
65870             });
65871
65872         var dataLayerContainer = content
65873             .append('div')
65874             .attr('class', 'data-data-layers')
65875             .style('display', 'block');
65876
65877
65878         // area fills
65879         content
65880             .append('a')
65881             .text(t('map_data.fill_area'))
65882             .attr('href', '#')
65883             .classed('hide-toggle', true)
65884             .classed('expanded', false)
65885             .on('click', function() {
65886                 var exp = select(this).classed('expanded');
65887                 fillContainer.style('display', exp ? 'none' : 'block');
65888                 select(this).classed('expanded', !exp);
65889                 event.preventDefault();
65890             });
65891
65892         var fillContainer = content
65893             .append('div')
65894             .attr('class', 'data-area-fills')
65895             .style('display', 'none');
65896
65897         var fillList = fillContainer
65898             .append('ul')
65899             .attr('class', 'layer-list layer-fill-list');
65900
65901
65902         // feature filters
65903         content
65904             .append('a')
65905             .text(t('map_data.map_features'))
65906             .attr('href', '#')
65907             .classed('hide-toggle', true)
65908             .classed('expanded', false)
65909             .on('click', function() {
65910                 var exp = select(this).classed('expanded');
65911                 featureContainer.style('display', exp ? 'none' : 'block');
65912                 select(this).classed('expanded', !exp);
65913                 event.preventDefault();
65914             });
65915
65916         var featureContainer = content
65917             .append('div')
65918             .attr('class', 'data-feature-filters')
65919             .style('display', 'none');
65920
65921         var featureList = featureContainer
65922             .append('ul')
65923             .attr('class', 'layer-list layer-feature-list');
65924
65925
65926         context.features()
65927             .on('change.map_data-update', update);
65928
65929         setFill(fillDefault);
65930
65931         var keybinding = d3keybinding('features')
65932             .on(key, togglePanel)
65933             .on(t('area_fill.wireframe.key'), toggleWireframe)
65934             .on([t('background.key'), t('help.key')], hidePanel);
65935
65936         select(document)
65937             .call(keybinding);
65938
65939         context.surface().on('mousedown.map_data-outside', hidePanel);
65940         context.container().on('mousedown.map_data-outside', hidePanel);
65941     }
65942
65943
65944     return map_data;
65945 }
65946
65947 function uiModes(context) {
65948     var modes = [
65949         modeAddPoint$$1(context),
65950         modeAddLine$$1(context),
65951         modeAddArea$$1(context)
65952     ];
65953
65954
65955     function editable() {
65956         return context.editable() && context.mode().id !== 'save';
65957     }
65958
65959
65960     return function(selection$$1) {
65961         var buttons = selection$$1.selectAll('button.add-button')
65962             .data(modes);
65963
65964         buttons = buttons.enter()
65965             .append('button')
65966             .attr('tabindex', -1)
65967             .attr('class', function(mode) { return mode.id + ' add-button col4'; })
65968             .on('click.mode-buttons', function(mode) {
65969                 if (mode.id === context.mode().id) {
65970                     context.enter(modeBrowse(context));
65971                 } else {
65972                     context.enter(mode);
65973                 }
65974             })
65975             .call(tooltip()
65976                 .placement('bottom')
65977                 .html(true)
65978                 .title(function(mode) {
65979                     return uiTooltipHtml(mode.description, mode.key);
65980                 })
65981             );
65982
65983         context.map()
65984             .on('move.modes', lodash.debounce(update, 500));
65985
65986         context
65987             .on('enter.modes', update);
65988
65989         buttons
65990             .each(function(d) {
65991                 select(this)
65992                     .call(svgIcon('#icon-' + d.button, 'pre-text'));
65993             });
65994
65995         buttons
65996             .append('span')
65997             .attr('class', 'label')
65998             .text(function(mode) { return mode.title; });
65999
66000         context
66001             .on('enter.editor', function(entered) {
66002                 selection$$1.selectAll('button.add-button')
66003                     .classed('active', function(mode) { return entered.button === mode.button; });
66004                 context.container()
66005                     .classed('mode-' + entered.id, true);
66006             });
66007
66008         context
66009             .on('exit.editor', function(exited) {
66010                 context.container()
66011                     .classed('mode-' + exited.id, false);
66012             });
66013
66014         var keybinding = d3keybinding('mode-buttons');
66015
66016         modes.forEach(function(mode) {
66017             keybinding.on(mode.key, function() {
66018                 if (editable()) {
66019                     if (mode.id === context.mode().id) {
66020                         context.enter(modeBrowse(context));
66021                     } else {
66022                         context.enter(mode);
66023                     }
66024                 }
66025             });
66026         });
66027
66028         select(document)
66029             .call(keybinding);
66030
66031
66032         function update() {
66033             selection$$1.selectAll('button.add-button')
66034                 .property('disabled', !editable());
66035         }
66036     };
66037 }
66038
66039 function uiRestore(context) {
66040
66041     return function(selection) {
66042         if (!context.history().lock() || !context.history().restorableChanges())
66043             return;
66044
66045         var modalSelection = uiModal(selection, true);
66046
66047         modalSelection.select('.modal')
66048             .attr('class', 'modal fillL col6');
66049
66050         var introModal = modalSelection.select('.content');
66051
66052         introModal
66053             .attr('class','cf');
66054
66055         introModal
66056             .append('div')
66057             .attr('class', 'modal-section')
66058             .append('h3')
66059             .text(t('restore.heading'));
66060
66061         introModal
66062             .append('div')
66063             .attr('class','modal-section')
66064             .append('p')
66065             .text(t('restore.description'));
66066
66067         var buttonWrap = introModal
66068             .append('div')
66069             .attr('class', 'modal-actions cf');
66070
66071         var restore = buttonWrap
66072             .append('button')
66073             .attr('class', 'restore col6')
66074             .on('click', function() {
66075                 context.history().restore();
66076                 modalSelection.remove();
66077             });
66078
66079         restore
66080             .append('svg')
66081             .attr('class', 'logo logo-restore')
66082             .append('use')
66083             .attr('xlink:href', '#logo-restore');
66084
66085         restore
66086             .append('div')
66087             .text(t('restore.restore'));
66088
66089         var reset = buttonWrap
66090             .append('button')
66091             .attr('class', 'reset col6')
66092             .on('click', function() {
66093                 context.history().clearSaved();
66094                 modalSelection.remove();
66095             });
66096
66097         reset
66098             .append('svg')
66099             .attr('class', 'logo logo-reset')
66100             .append('use')
66101             .attr('xlink:href', '#logo-reset');
66102
66103         reset
66104             .append('div')
66105             .text(t('restore.reset'));
66106
66107         restore.node().focus();
66108     };
66109 }
66110
66111 function uiSave(context) {
66112     var history = context.history(),
66113         key = uiCmd('⌘S');
66114
66115
66116     function saving() {
66117         return context.mode().id === 'save';
66118     }
66119
66120
66121     function save() {
66122         event.preventDefault();
66123         if (!context.inIntro() && !saving() && history.hasChanges()) {
66124             context.enter(modeSave$$1(context));
66125         }
66126     }
66127
66128
66129     function getBackground(numChanges) {
66130         var step$$1;
66131         if (numChanges === 0) {
66132             return null;
66133         } else if (numChanges <= 50) {
66134             step$$1 = numChanges / 50;
66135             return interpolateRgb('#fff', '#ff8')(step$$1);  // white -> yellow
66136         } else {
66137             step$$1 = Math.min((numChanges - 50) / 50, 1.0);
66138             return interpolateRgb('#ff8', '#f88')(step$$1);  // yellow -> red
66139         }
66140     }
66141
66142
66143     return function(selection$$1) {
66144         var numChanges = 0;
66145
66146         function updateCount() {
66147             var _ = history.difference().summary().length;
66148             if (_ === numChanges) return;
66149             numChanges = _;
66150
66151             tooltipBehavior
66152                 .title(uiTooltipHtml(
66153                     t(numChanges > 0 ? 'save.help' : 'save.no_changes'), key)
66154                 );
66155
66156             var background = getBackground(numChanges);
66157
66158             button
66159                 .classed('disabled', numChanges === 0)
66160                 .classed('has-count', numChanges > 0)
66161                 .style('background', background);
66162
66163             button.select('span.count')
66164                 .text(numChanges)
66165                 .style('background', background)
66166                 .style('border-color', background);
66167         }
66168
66169
66170         var tooltipBehavior = tooltip()
66171             .placement('bottom')
66172             .html(true)
66173             .title(uiTooltipHtml(t('save.no_changes'), key));
66174
66175         var button = selection$$1
66176             .append('button')
66177             .attr('class', 'save col12 disabled')
66178             .attr('tabindex', -1)
66179             .on('click', save)
66180             .call(tooltipBehavior);
66181
66182         button
66183             .call(svgIcon('#icon-save', 'pre-text'))
66184             .append('span')
66185             .attr('class', 'label')
66186             .text(t('save.title'));
66187
66188         button
66189             .append('span')
66190             .attr('class', 'count')
66191             .text('0');
66192
66193         updateCount();
66194
66195
66196         var keybinding = d3keybinding('save')
66197             .on(key, save, true);
66198
66199         select(document)
66200             .call(keybinding);
66201
66202         context.history()
66203             .on('change.save', updateCount);
66204
66205         context
66206             .on('enter.save', function() {
66207                 button.property('disabled', saving());
66208                 if (saving()) button.call(tooltipBehavior.hide);
66209             });
66210     };
66211 }
66212
66213 function uiScale(context) {
66214     var projection = context.projection,
66215         isImperial = (utilDetect().locale.toLowerCase() === 'en-us'),
66216         maxLength = 180,
66217         tickHeight = 8;
66218
66219
66220     function scaleDefs(loc1, loc2) {
66221         var lat = (loc2[1] + loc1[1]) / 2,
66222             conversion = (isImperial ? 3.28084 : 1),
66223             dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
66224             scale = { dist: 0, px: 0, text: '' },
66225             buckets, i, val, dLon;
66226
66227         if (isImperial) {
66228             buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
66229         } else {
66230             buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
66231         }
66232
66233         // determine a user-friendly endpoint for the scale
66234         for (i = 0; i < buckets.length; i++) {
66235             val = buckets[i];
66236             if (dist >= val) {
66237                 scale.dist = Math.floor(dist / val) * val;
66238                 break;
66239             } else {
66240                 scale.dist = +dist.toFixed(2);
66241             }
66242         }
66243
66244         dLon = geoMetersToLon(scale.dist / conversion, lat);
66245         scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
66246
66247         if (isImperial) {
66248             if (scale.dist >= 5280) {
66249                 scale.dist /= 5280;
66250                 scale.text = String(scale.dist) + ' mi';
66251             } else {
66252                 scale.text = String(scale.dist) + ' ft';
66253             }
66254         } else {
66255             if (scale.dist >= 1000) {
66256                 scale.dist /= 1000;
66257                 scale.text = String(scale.dist) + ' km';
66258             } else {
66259                 scale.text = String(scale.dist) + ' m';
66260             }
66261         }
66262
66263         return scale;
66264     }
66265
66266
66267     function update(selection) {
66268         // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
66269         var dims = context.map().dimensions(),
66270             loc1 = projection.invert([0, dims[1]]),
66271             loc2 = projection.invert([maxLength, dims[1]]),
66272             scale = scaleDefs(loc1, loc2);
66273
66274         selection.select('#scale-path')
66275             .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
66276
66277         selection.select('#scale-textgroup')
66278             .attr('transform', 'translate(' + (scale.px + 8) + ',' + tickHeight + ')');
66279
66280         selection.select('#scale-text')
66281             .text(scale.text);
66282     }
66283
66284
66285     return function(selection) {
66286         function switchUnits() {
66287             isImperial = !isImperial;
66288             selection.call(update);
66289         }
66290
66291         var scalegroup = selection.append('svg')
66292             .attr('id', 'scale')
66293             .on('click', switchUnits)
66294             .append('g')
66295             .attr('transform', 'translate(10,11)');
66296
66297         scalegroup
66298             .append('path')
66299             .attr('id', 'scale-path');
66300
66301         scalegroup
66302             .append('g')
66303             .attr('id', 'scale-textgroup')
66304             .append('text')
66305             .attr('id', 'scale-text');
66306
66307         selection.call(update);
66308
66309         context.map().on('move.scale', function() {
66310             update(selection);
66311         });
66312     };
66313 }
66314
66315 var pair_1 = pair$1;
66316 function search(x, dims, r) {
66317   if (!dims) dims = 'NSEW';
66318   if (typeof x !== 'string') return { val: null, regex: r };
66319   r = r || /[\s\,]*([\-|\—|\―]?[0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/gi;
66320   var m = r.exec(x);
66321   if (!m) return { val: null, regex: r };
66322   else if (m[4] && dims.indexOf(m[4]) === -1) return { val: null, regex: r };
66323   else return {
66324     val: (((m[1]) ? parseFloat(m[1]) : 0) +
66325           ((m[2] ? parseFloat(m[2]) / 60 : 0)) +
66326           ((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
66327           ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1),
66328     regex: r,
66329     raw: m[0],
66330     dim: m[4]
66331   };
66332 }
66333
66334 function pair$1(x, dims) {
66335   x = x.trim();
66336   var one = search(x, dims);
66337   if (one.val === null) return null;
66338   var two = search(x, dims, one.regex);
66339   if (two.val === null) return null;
66340   // null if one/two are not contiguous.
66341   if (one.raw + two.raw !== x) return null;
66342   if (one.dim) {
66343     return swapdim(one.val, two.val, one.dim);
66344   } else {
66345     return [one.val, two.val];
66346   }
66347 }
66348
66349 function swapdim(a, b, dim) {
66350   if (dim === 'N' || dim === 'S') return [a, b];
66351   if (dim === 'W' || dim === 'E') return [b, a];
66352 }
66353
66354 function uiFeatureList(context) {
66355     var geocodeResults;
66356
66357
66358     function featureList(selection$$1) {
66359         var header = selection$$1
66360             .append('div')
66361             .attr('class', 'header fillL cf');
66362
66363         header.append('h3')
66364             .text(t('inspector.feature_list'));
66365
66366         var searchWrap = selection$$1
66367             .append('div')
66368             .attr('class', 'search-header');
66369
66370         var search = searchWrap
66371             .append('input')
66372             .attr('placeholder', t('inspector.search'))
66373             .attr('type', 'search')
66374             .call(utilNoAuto)
66375             .on('keypress', keypress)
66376             .on('input', inputevent);
66377
66378         searchWrap
66379             .call(svgIcon('#icon-search', 'pre-text'));
66380
66381         var listWrap = selection$$1
66382             .append('div')
66383             .attr('class', 'inspector-body');
66384
66385         var list = listWrap
66386             .append('div')
66387             .attr('class', 'feature-list cf');
66388
66389         context
66390             .on('exit.feature-list', clearSearch);
66391         context.map()
66392             .on('drawn.feature-list', mapDrawn);
66393
66394
66395         function keypress() {
66396             var q = search.property('value'),
66397                 items = list.selectAll('.feature-list-item');
66398             if (event.keyCode === 13 && q.length && items.size()) {
66399                 click(items.datum());
66400             }
66401         }
66402
66403
66404         function inputevent() {
66405             geocodeResults = undefined;
66406             drawList();
66407         }
66408
66409
66410         function clearSearch() {
66411             search.property('value', '');
66412             drawList();
66413         }
66414
66415
66416         function mapDrawn(e) {
66417             if (e.full) {
66418                 drawList();
66419             }
66420         }
66421
66422
66423         function features() {
66424             var entities = {},
66425                 result = [],
66426                 graph = context.graph(),
66427                 q = search.property('value').toLowerCase();
66428
66429             if (!q) return result;
66430
66431             var idMatch = q.match(/^([nwr])([0-9]+)$/);
66432
66433             if (idMatch) {
66434                 result.push({
66435                     id: idMatch[0],
66436                     geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
66437                     type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
66438                     name: idMatch[2]
66439                 });
66440             }
66441
66442             var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
66443
66444             if (locationMatch) {
66445                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
66446                 result.push({
66447                     id: -1,
66448                     geometry: 'point',
66449                     type: t('inspector.location'),
66450                     name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
66451                     location: loc
66452                 });
66453             }
66454
66455             function addEntity(entity) {
66456                 if (entity.id in entities || result.length > 200)
66457                     return;
66458
66459                 entities[entity.id] = true;
66460
66461                 var name = utilDisplayName(entity) || '';
66462                 if (name.toLowerCase().indexOf(q) >= 0) {
66463                     var matched = context.presets().match(entity, graph),
66464                         type = (matched && matched.name()) || utilDisplayType(entity.id);
66465                     result.push({
66466                         id: entity.id,
66467                         entity: entity,
66468                         geometry: context.geometry(entity.id),
66469                         type: type,
66470                         name: name
66471                     });
66472                 }
66473
66474                 graph.parentRelations(entity).forEach(function(parent) {
66475                     addEntity(parent);
66476                 });
66477             }
66478
66479             var visible = context.surface().selectAll('.point, .line, .area').nodes();
66480             for (var i = 0; i < visible.length && result.length <= 200; i++) {
66481                 addEntity(visible[i].__data__);
66482             }
66483
66484             (geocodeResults || []).forEach(function(d) {
66485                 // https://github.com/openstreetmap/iD/issues/1890
66486                 if (d.osm_type && d.osm_id) {
66487                     result.push({
66488                         id: osmEntity$$1.id.fromOSM(d.osm_type, d.osm_id),
66489                         geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
66490                         type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
66491                                                : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
66492                         name: d.display_name,
66493                         extent: new geoExtent$$1(
66494                             [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
66495                             [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
66496                     });
66497                 }
66498             });
66499
66500             return result;
66501         }
66502
66503
66504         function drawList() {
66505             var value = search.property('value'),
66506                 results = features();
66507
66508             list.classed('filtered', value.length);
66509
66510             var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
66511
66512             var resultsIndicator = list.selectAll('.no-results-item')
66513                 .data([0])
66514                 .enter().append('button')
66515                 .property('disabled', true)
66516                 .attr('class', 'no-results-item')
66517                 .call(svgIcon('#icon-alert', 'pre-text'));
66518
66519             resultsIndicator.append('span')
66520                 .attr('class', 'entity-name');
66521
66522             list.selectAll('.no-results-item .entity-name')
66523                 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
66524
66525             if (services.geocoder) {
66526               list.selectAll('.geocode-item')
66527                   .data([0])
66528                   .enter().append('button')
66529                   .attr('class', 'geocode-item')
66530                   .on('click', geocoderSearch)
66531                   .append('div')
66532                   .attr('class', 'label')
66533                   .append('span')
66534                   .attr('class', 'entity-name')
66535                   .text(t('geocoder.search'));
66536             }
66537
66538             list.selectAll('.no-results-item')
66539                 .style('display', (value.length && !results.length) ? 'block' : 'none');
66540
66541             list.selectAll('.geocode-item')
66542                 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
66543
66544             list.selectAll('.feature-list-item')
66545                 .data([-1])
66546                 .remove();
66547
66548             var items = list.selectAll('.feature-list-item')
66549                 .data(results, function(d) { return d.id; });
66550
66551             var enter = items.enter()
66552                 .insert('button', '.geocode-item')
66553                 .attr('class', 'feature-list-item')
66554                 .on('mouseover', mouseover)
66555                 .on('mouseout', mouseout)
66556                 .on('click', click);
66557
66558             var label = enter
66559                 .append('div')
66560                 .attr('class', 'label');
66561
66562             label.each(function(d) {
66563                 select(this)
66564                     .call(svgIcon('#icon-' + d.geometry, 'pre-text'));
66565             });
66566
66567             label.append('span')
66568                 .attr('class', 'entity-type')
66569                 .text(function(d) { return d.type; });
66570
66571             label.append('span')
66572                 .attr('class', 'entity-name')
66573                 .text(function(d) { return d.name; });
66574
66575             enter.style('opacity', 0)
66576                 .transition()
66577                 .style('opacity', 1);
66578
66579             items.order();
66580
66581             items.exit()
66582                 .remove();
66583         }
66584
66585
66586         function mouseover(d) {
66587             if (d.id === -1) return;
66588
66589             context.surface().selectAll(utilEntityOrMemberSelector([d.id], context.graph()))
66590                 .classed('hover', true);
66591         }
66592
66593
66594         function mouseout() {
66595             context.surface().selectAll('.hover')
66596                 .classed('hover', false);
66597         }
66598
66599
66600         function click(d) {
66601             event.preventDefault();
66602             if (d.location) {
66603                 context.map().centerZoom([d.location[1], d.location[0]], 20);
66604             }
66605             else if (d.entity) {
66606                 if (d.entity.type === 'node') {
66607                     context.map().center(d.entity.loc);
66608                 } else if (d.entity.type === 'way') {
66609                     var center = context.projection(context.map().center()),
66610                         edge = geoChooseEdge(context.childNodes(d.entity), center, context.projection);
66611                     context.map().center(edge.loc);
66612                 }
66613                 context.enter(modeSelect(context, [d.entity.id]));
66614             } else {
66615                 context.zoomToEntity(d.id);
66616             }
66617         }
66618
66619
66620         function geocoderSearch() {
66621             services.geocoder.search(search.property('value'), function (err, resp) {
66622                 geocodeResults = resp || [];
66623                 drawList();
66624             });
66625         }
66626     }
66627
66628
66629     return featureList;
66630 }
66631
66632 function uiPresetIcon() {
66633     var preset, geometry;
66634
66635
66636     function presetIcon(selection$$1) {
66637         selection$$1.each(render);
66638     }
66639
66640
66641     function getIcon(p, geom) {
66642         if (p.icon)
66643             return p.icon;
66644         else if (geom === 'line')
66645             return 'other-line';
66646         else if (geom === 'vertex')
66647             return p.isFallback() ? '' : 'poi-vertex';
66648         else
66649             return 'marker-stroked';
66650     }
66651
66652
66653     function render() {
66654         var selection$$1 = select(this),
66655             p = preset.apply(this, arguments),
66656             geom = geometry.apply(this, arguments),
66657             picon = getIcon(p, geom),
66658             isPoi = picon.match(/^poi-/) !== null,
66659             isMaki = dataFeatureIcons.indexOf(picon) !== -1,
66660             isFramed = (geom === 'area' || geom === 'verex');
66661
66662
66663         function tag_classes(p) {
66664             var s = '';
66665             for (var i in p.tags) {
66666                 s += ' tag-' + i;
66667                 if (p.tags[i] !== '*') {
66668                     s += ' tag-' + i + '-' + p.tags[i];
66669                 }
66670             }
66671             return s;
66672         }
66673
66674
66675         var fill = selection$$1.selectAll('.preset-icon-fill')
66676             .data([0]);
66677
66678         fill = fill.enter()
66679             .append('div')
66680             .merge(fill);
66681
66682         fill
66683             .attr('class', function() {
66684                 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
66685             });
66686
66687
66688         var areaFrame = selection$$1.selectAll('.preset-icon-frame')
66689             .data((geom === 'area') ? [0] : []);
66690
66691         areaFrame.exit()
66692             .remove();
66693
66694         areaFrame = areaFrame.enter()
66695             .append('div')
66696             .attr('class', 'preset-icon-frame')
66697             .call(svgIcon('#preset-icon-frame'));
66698
66699
66700         var icon = selection$$1.selectAll('.preset-icon')
66701             .data([0]);
66702
66703         icon = icon.enter()
66704             .append('div')
66705             .attr('class', 'preset-icon')
66706             .call(svgIcon(''))
66707             .merge(icon);
66708
66709         icon
66710             .attr('class', 'preset-icon preset-icon-' +
66711                 ((isMaki || isPoi) ? (isFramed ? '24' : '28') : (isFramed ? '44' : '60'))
66712             );
66713
66714         icon.selectAll('svg')
66715             .attr('class', function() {
66716                 return 'icon ' + picon + (isMaki || isPoi ? '' : tag_classes(p));
66717             });
66718
66719         icon.selectAll('use')
66720             .attr('href', '#' + picon + (isMaki ? '-15' : ''));
66721     }
66722
66723
66724     presetIcon.preset = function(_) {
66725         if (!arguments.length) return preset;
66726         preset = utilFunctor(_);
66727         return presetIcon;
66728     };
66729
66730
66731     presetIcon.geometry = function(_) {
66732         if (!arguments.length) return geometry;
66733         geometry = utilFunctor(_);
66734         return presetIcon;
66735     };
66736
66737     return presetIcon;
66738 }
66739
66740 function d3combobox() {
66741     var dispatch$$1 = dispatch('accept'),
66742         container = select(document.body),
66743         data = [],
66744         suggestions = [],
66745         minItems = 2,
66746         caseSensitive = false;
66747
66748     var fetcher = function(val, cb) {
66749         cb(data.filter(function(d) {
66750             return d.value
66751                 .toString()
66752                 .toLowerCase()
66753                 .indexOf(val.toLowerCase()) !== -1;
66754         }));
66755     };
66756
66757     var combobox = function(input, attachTo) {
66758         var idx = -1,
66759             wrapper = container
66760                 .selectAll('div.combobox')
66761                 .filter(function(d) { return d === input.node(); }),
66762             shown = !wrapper.empty();
66763
66764         input
66765             .classed('combobox-input', true)
66766             .on('focus.typeahead', focus)
66767             .on('blur.typeahead', blur)
66768             .on('keydown.typeahead', keydown)
66769             .on('keyup.typeahead', keyup)
66770             .on('input.typeahead', change)
66771             .each(function() {
66772                 var parent = this.parentNode,
66773                     sibling = this.nextSibling;
66774
66775                 var caret = select(parent).selectAll('.combobox-caret')
66776                     .filter(function(d) { return d === input.node(); })
66777                     .data([input.node()]);
66778
66779                 caret = caret.enter()
66780                   .insert('div', function() { return sibling; })
66781                     .attr('class', 'combobox-caret')
66782                   .merge(caret);
66783
66784                 caret
66785                     .on('mousedown', function () {
66786                         // prevent the form element from blurring. it blurs
66787                         // on mousedown
66788                         event.stopPropagation();
66789                         event.preventDefault();
66790                         if (!shown) {
66791                             input.node().focus();
66792                             fetch('', render);
66793                         } else {
66794                             hide();
66795                         }
66796                     });
66797             });
66798
66799         function focus() {
66800             fetch(value(), render);
66801         }
66802
66803         function blur() {
66804             window.setTimeout(hide, 150);
66805         }
66806
66807         function show() {
66808             if (!shown) {
66809                 wrapper = container
66810                     .insert('div', ':first-child')
66811                     .datum(input.node())
66812                     .attr('class', 'combobox')
66813                     .style('position', 'absolute')
66814                     .style('display', 'block')
66815                     .style('left', '0px')
66816                     .on('mousedown', function () {
66817                         // prevent moving focus out of the text field
66818                         event.preventDefault();
66819                     });
66820
66821                 select('body')
66822                     .on('scroll.combobox', render, true);
66823
66824                 shown = true;
66825             }
66826         }
66827
66828         function hide() {
66829             if (shown) {
66830                 idx = -1;
66831                 wrapper.remove();
66832
66833                 select('body')
66834                     .on('scroll.combobox', null);
66835
66836                 shown = false;
66837             }
66838         }
66839
66840         function keydown() {
66841            switch (event.keyCode) {
66842                // backspace, delete
66843                case 8:
66844                case 46:
66845                    input.on('input.typeahead', function() {
66846                        idx = -1;
66847                        render();
66848                        var start = input.property('selectionStart');
66849                        input.node().setSelectionRange(start, start);
66850                        input.on('input.typeahead', change);
66851                    });
66852                    break;
66853                // tab
66854                case 9:
66855                    wrapper.selectAll('a.selected').each(function (d) {
66856                        dispatch$$1.call('accept', this, d);
66857                    });
66858                    hide();
66859                    break;
66860                // return
66861                case 13:
66862                    event.preventDefault();
66863                    break;
66864                // up arrow
66865                case 38:
66866                    nav(-1);
66867                    event.preventDefault();
66868                    break;
66869                // down arrow
66870                case 40:
66871                    nav(+1);
66872                    event.preventDefault();
66873                    break;
66874            }
66875            event.stopPropagation();
66876         }
66877
66878         function keyup() {
66879             switch (event.keyCode) {
66880                 // escape
66881                 case 27:
66882                     hide();
66883                     break;
66884                 // return
66885                 case 13:
66886                     wrapper.selectAll('a.selected').each(function (d) {
66887                        dispatch$$1.call('accept', this, d);
66888                     });
66889                     hide();
66890                     break;
66891             }
66892         }
66893
66894         function change() {
66895             fetch(value(), function() {
66896                 if (input.property('selectionEnd') === input.property('value').length) {
66897                     autocomplete();
66898                 }
66899                 render();
66900             });
66901         }
66902
66903         function nav(dir) {
66904             if (!suggestions.length) return;
66905             idx = Math.max(Math.min(idx + dir, suggestions.length - 1), 0);
66906             input.property('value', suggestions[idx].value);
66907             render();
66908             ensureVisible();
66909         }
66910
66911         function value() {
66912             var value = input.property('value'),
66913                 start = input.property('selectionStart'),
66914                 end = input.property('selectionEnd');
66915
66916             if (start && end) {
66917                 value = value.substring(0, start);
66918             }
66919
66920             return value;
66921         }
66922
66923         function fetch(v, cb) {
66924             fetcher.call(input, v, function(_) {
66925                 suggestions = _;
66926                 cb();
66927             });
66928         }
66929
66930         function autocomplete() {
66931             var v = caseSensitive ? value() : value().toLowerCase();
66932             idx = -1;
66933             if (!v) return;
66934
66935             for (var i = 0; i < suggestions.length; i++) {
66936                 var suggestion = suggestions[i].value,
66937                     compare = caseSensitive ? suggestion : suggestion.toLowerCase();
66938
66939                 if (compare.indexOf(v) === 0) {
66940                     idx = i;
66941                     input.property('value', suggestion);
66942                     input.node().setSelectionRange(v.length, suggestion.length);
66943                     return;
66944                 }
66945             }
66946         }
66947
66948         function render() {
66949             if (suggestions.length >= minItems && document.activeElement === input.node()) {
66950                 show();
66951             } else {
66952                 hide();
66953                 return;
66954             }
66955
66956             var options = wrapper
66957                 .selectAll('a.combobox-option')
66958                 .data(suggestions, function(d) { return d.value; });
66959
66960             options.exit()
66961                 .remove();
66962
66963             options.enter()
66964                 .append('a')
66965                 .attr('class', 'combobox-option')
66966                 .text(function(d) { return d.value; })
66967                 .merge(options)
66968                 .attr('title', function(d) { return d.title; })
66969                 .classed('selected', function(d, i) { return i === idx; })
66970                 .on('mouseover', select$$1)
66971                 .on('click', accept)
66972                 .order();
66973
66974
66975             var node = attachTo ? attachTo.node() : input.node(),
66976                 rect = node.getBoundingClientRect();
66977
66978             wrapper
66979                 .style('left', rect.left + 'px')
66980                 .style('width', rect.width + 'px')
66981                 .style('top', rect.height + rect.top + 'px');
66982         }
66983
66984         function select$$1(d, i) {
66985             idx = i;
66986             render();
66987         }
66988
66989         function ensureVisible() {
66990             var node = wrapper.selectAll('a.selected').node();
66991             if (node) node.scrollIntoView();
66992         }
66993
66994         function accept(d) {
66995             if (!shown) return;
66996             input.property('value', d.value);
66997             utilTriggerEvent(input, 'change');
66998             dispatch$$1.call('accept', this, d);
66999             hide();
67000         }
67001     };
67002
67003     combobox.fetcher = function(_) {
67004         if (!arguments.length) return fetcher;
67005         fetcher = _;
67006         return combobox;
67007     };
67008
67009     combobox.data = function(_) {
67010         if (!arguments.length) return data;
67011         data = _;
67012         return combobox;
67013     };
67014
67015     combobox.minItems = function(_) {
67016         if (!arguments.length) return minItems;
67017         minItems = _;
67018         return combobox;
67019     };
67020
67021     combobox.caseSensitive = function(_) {
67022         if (!arguments.length) return caseSensitive;
67023         caseSensitive = _;
67024         return combobox;
67025     };
67026
67027     combobox.container = function(_) {
67028         if (!arguments.length) return container;
67029         container = _;
67030         return combobox;
67031     };
67032
67033     return utilRebind(combobox, dispatch$$1, 'on');
67034 }
67035
67036
67037 d3combobox.off = function(input) {
67038     input
67039         .on('focus.typeahead', null)
67040         .on('blur.typeahead', null)
67041         .on('keydown.typeahead', null)
67042         .on('keyup.typeahead', null)
67043         .on('input.typeahead', null)
67044         .each(function() {
67045             select(this.parentNode).selectAll('.combobox-caret')
67046                 .filter(function(d) { return d === input.node(); })
67047                 .on('mousedown', null);
67048         });
67049
67050     select('body')
67051         .on('scroll.combobox', null);
67052 };
67053
67054 function uiDisclosure() {
67055     var dispatch$$1 = dispatch('toggled'),
67056         title,
67057         expanded = false,
67058         content = function () {};
67059
67060
67061     var disclosure = function(selection$$1) {
67062         var hideToggle = selection$$1.selectAll('.hide-toggle')
67063             .data([0]);
67064
67065         hideToggle = hideToggle.enter()
67066             .append('a')
67067             .attr('href', '#')
67068             .attr('class', 'hide-toggle')
67069             .merge(hideToggle);
67070
67071         hideToggle
67072             .text(title)
67073             .on('click', toggle)
67074             .classed('expanded', expanded);
67075
67076
67077         var wrap = selection$$1.selectAll('div')
67078             .data([0]);
67079
67080         wrap = wrap.enter()
67081             .append('div')
67082             .merge(wrap);
67083
67084         wrap
67085             .classed('hide', !expanded)
67086             .call(content);
67087
67088
67089         function toggle() {
67090             expanded = !expanded;
67091             hideToggle.classed('expanded', expanded);
67092             wrap.call(uiToggle(expanded));
67093             dispatch$$1.call('toggled', this, expanded);
67094         }
67095     };
67096
67097
67098     disclosure.title = function(_) {
67099         if (!arguments.length) return title;
67100         title = _;
67101         return disclosure;
67102     };
67103
67104
67105     disclosure.expanded = function(_) {
67106         if (!arguments.length) return expanded;
67107         expanded = _;
67108         return disclosure;
67109     };
67110
67111
67112     disclosure.content = function(_) {
67113         if (!arguments.length) return content;
67114         content = _;
67115         return disclosure;
67116     };
67117
67118
67119     return utilRebind(disclosure, dispatch$$1, 'on');
67120 }
67121
67122 function uiRawMemberEditor(context) {
67123     var id,
67124         taginfo = services.taginfo;
67125
67126
67127     function selectMember(d) {
67128         event.preventDefault();
67129         context.enter(modeSelect(context, [d.id]));
67130     }
67131
67132
67133     function changeRole(d) {
67134         var role = select(this).property('value');
67135         var member = { id: d.id, type: d.type, role: role };
67136         context.perform(
67137             actionChangeMember(d.relation.id, member, d.index),
67138             t('operations.change_role.annotation')
67139         );
67140     }
67141
67142
67143     function deleteMember(d) {
67144         context.perform(
67145             actionDeleteMember(d.relation.id, d.index),
67146             t('operations.delete_member.annotation')
67147         );
67148
67149         if (!context.hasEntity(d.relation.id)) {
67150             context.enter(modeBrowse(context));
67151         }
67152     }
67153
67154
67155     function rawMemberEditor(selection$$1) {
67156         var entity = context.entity(id),
67157             memberships = [];
67158
67159         entity.members.slice(0, 1000).forEach(function(member, index) {
67160             memberships.push({
67161                 index: index,
67162                 id: member.id,
67163                 type: member.type,
67164                 role: member.role,
67165                 relation: entity,
67166                 member: context.hasEntity(member.id)
67167             });
67168         });
67169
67170         var gt = entity.members.length > 1000 ? '>' : '';
67171         selection$$1.call(uiDisclosure()
67172             .title(t('inspector.all_members') + ' (' + gt + memberships.length + ')')
67173             .expanded(true)
67174             .on('toggled', toggled)
67175             .content(content)
67176         );
67177
67178
67179         function toggled(expanded) {
67180             if (expanded) {
67181                 selection$$1.node().parentNode.scrollTop += 200;
67182             }
67183         }
67184
67185
67186         function content(wrap) {
67187             var list = wrap.selectAll('.member-list')
67188                 .data([0]);
67189
67190             list = list.enter()
67191                 .append('ul')
67192                 .attr('class', 'member-list')
67193                 .merge(list);
67194
67195
67196             var items = list.selectAll('li')
67197                 .data(memberships, function(d) {
67198                     return osmEntity$$1.key(d.relation) + ',' + d.index + ',' +
67199                         (d.member ? osmEntity$$1.key(d.member) : 'incomplete');
67200                 });
67201
67202             items.exit()
67203                 .each(unbind)
67204                 .remove();
67205
67206             var enter = items.enter()
67207                 .append('li')
67208                 .attr('class', 'member-row form-field')
67209                 .classed('member-incomplete', function(d) { return !d.member; });
67210
67211             enter
67212                 .each(function(d) {
67213                     if (d.member) {
67214                         var label = select(this).append('label')
67215                             .attr('class', 'form-label')
67216                             .append('a')
67217                             .attr('href', '#')
67218                             .on('click', selectMember);
67219
67220                         label.append('span')
67221                             .attr('class', 'member-entity-type')
67222                             .text(function(d) {
67223                                 var matched = context.presets().match(d.member, context.graph());
67224                                 return (matched && matched.name()) || utilDisplayType(d.member.id);
67225                             });
67226
67227                         label.append('span')
67228                             .attr('class', 'member-entity-name')
67229                             .text(function(d) { return utilDisplayName(d.member); });
67230
67231                     } else {
67232                         select(this).append('label')
67233                             .attr('class', 'form-label')
67234                             .text(t('inspector.incomplete', { id: d.id }));
67235                     }
67236                 });
67237
67238             enter
67239                 .append('input')
67240                 .attr('class', 'member-role')
67241                 .property('type', 'text')
67242                 .attr('maxlength', 255)
67243                 .attr('placeholder', t('inspector.role'))
67244                 .call(utilNoAuto)
67245                 .property('value', function(d) { return d.role; })
67246                 .on('change', changeRole);
67247
67248             enter
67249                 .append('button')
67250                 .attr('tabindex', -1)
67251                 .attr('class', 'remove button-input-action member-delete minor')
67252                 .on('click', deleteMember)
67253                 .call(svgIcon('#operation-delete'));
67254
67255             if (taginfo) {
67256                 enter.each(bindTypeahead);
67257             }
67258
67259
67260             function bindTypeahead(d) {
67261                 var row = select(this),
67262                     role = row.selectAll('input.member-role');
67263
67264                 function sort(value, data) {
67265                     var sameletter = [],
67266                         other = [];
67267                     for (var i = 0; i < data.length; i++) {
67268                         if (data[i].value.substring(0, value.length) === value) {
67269                             sameletter.push(data[i]);
67270                         } else {
67271                             other.push(data[i]);
67272                         }
67273                     }
67274                     return sameletter.concat(other);
67275                 }
67276
67277                 role.call(d3combobox()
67278                     .container(context.container())
67279                     .fetcher(function(role, callback) {
67280                         var rtype = entity.tags.type;
67281                         taginfo.roles({
67282                             debounce: true,
67283                             rtype: rtype || '',
67284                             geometry: context.geometry(d.member.id),
67285                             query: role
67286                         }, function(err, data) {
67287                             if (!err) callback(sort(role, data));
67288                         });
67289                     }));
67290             }
67291
67292
67293             function unbind() {
67294                 var row = select(this);
67295
67296                 row.selectAll('input.member-role')
67297                     .call(d3combobox.off);
67298             }
67299         }
67300     }
67301
67302
67303     rawMemberEditor.entityID = function(_) {
67304         if (!arguments.length) return id;
67305         id = _;
67306         return rawMemberEditor;
67307     };
67308
67309
67310     return rawMemberEditor;
67311 }
67312
67313 function uiRawMembershipEditor(context) {
67314     var taginfo = services.taginfo,
67315         id, showBlank;
67316
67317
67318     function selectRelation(d) {
67319         event.preventDefault();
67320         context.enter(modeSelect(context, [d.relation.id]));
67321     }
67322
67323
67324     function changeRole(d) {
67325         var role = select(this).property('value');
67326         context.perform(
67327             actionChangeMember(d.relation.id, lodash.extend({}, d.member, { role: role }), d.index),
67328             t('operations.change_role.annotation')
67329         );
67330     }
67331
67332
67333     function addMembership(d, role) {
67334         showBlank = false;
67335
67336         if (d.relation) {
67337             context.perform(
67338                 actionAddMember(d.relation.id, { id: id, type: context.entity(id).type, role: role }),
67339                 t('operations.add_member.annotation')
67340             );
67341
67342         } else {
67343             var relation = osmRelation();
67344             context.perform(
67345                 actionAddEntity(relation),
67346                 actionAddMember(relation.id, { id: id, type: context.entity(id).type, role: role }),
67347                 t('operations.add.annotation.relation')
67348             );
67349
67350             context.enter(modeSelect(context, [relation.id]));
67351         }
67352     }
67353
67354
67355     function deleteMembership(d) {
67356         context.perform(
67357             actionDeleteMember(d.relation.id, d.index),
67358             t('operations.delete_member.annotation')
67359         );
67360     }
67361
67362
67363     function relations(q) {
67364         var newRelation = {
67365                 relation: null,
67366                 value: t('inspector.new_relation')
67367             },
67368             result = [],
67369             graph = context.graph();
67370
67371         context.intersects(context.extent()).forEach(function(entity) {
67372             if (entity.type !== 'relation' || entity.id === id)
67373                 return;
67374
67375             var matched = context.presets().match(entity, graph),
67376                 presetName = (matched && matched.name()) || t('inspector.relation'),
67377                 entityName = utilDisplayName(entity) || '';
67378
67379             var value = presetName + ' ' + entityName;
67380             if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
67381                 return;
67382
67383             result.push({
67384                 relation: entity,
67385                 value: value
67386             });
67387         });
67388
67389         result.sort(function(a, b) {
67390             return osmRelation.creationOrder(a.relation, b.relation);
67391         });
67392
67393         // Dedupe identical names by appending relation id - see #2891
67394         var dupeGroups = lodash(result)
67395             .groupBy('value')
67396             .filter(function(v) { return v.length > 1; })
67397             .value();
67398
67399         dupeGroups.forEach(function(group) {
67400             group.forEach(function(obj) {
67401                 obj.value += ' ' + obj.relation.id;
67402             });
67403         });
67404
67405         result.unshift(newRelation);
67406         return result;
67407     }
67408
67409
67410     function rawMembershipEditor(selection$$1) {
67411         var entity = context.entity(id),
67412             parents = context.graph().parentRelations(entity),
67413             memberships = [];
67414
67415         parents.slice(0, 1000).forEach(function(relation) {
67416             relation.members.forEach(function(member, index) {
67417                 if (member.id === entity.id) {
67418                     memberships.push({ relation: relation, member: member, index: index });
67419                 }
67420             });
67421         });
67422
67423         var gt = parents.length > 1000 ? '>' : '';
67424         selection$$1.call(uiDisclosure()
67425             .title(t('inspector.all_relations') + ' (' + gt + memberships.length + ')')
67426             .expanded(true)
67427             .on('toggled', toggled)
67428             .content(content)
67429         );
67430
67431
67432         function toggled(expanded) {
67433             if (expanded) {
67434                 selection$$1.node().parentNode.scrollTop += 200;
67435             }
67436         }
67437
67438
67439         function content(wrap) {
67440             var list = wrap.selectAll('.member-list')
67441                 .data([0]);
67442
67443             list = list.enter()
67444                 .append('ul')
67445                 .attr('class', 'member-list')
67446                 .merge(list);
67447
67448
67449             var items = list.selectAll('li.member-row-normal')
67450                 .data(memberships, function(d) {
67451                     return osmEntity$$1.key(d.relation) + ',' + d.index;
67452                 });
67453
67454             items.exit()
67455                 .each(unbind)
67456                 .remove();
67457
67458             var enter = items.enter()
67459                 .append('li')
67460                 .attr('class', 'member-row member-row-normal form-field');
67461
67462             var label = enter
67463                 .append('label')
67464                 .attr('class', 'form-label')
67465                 .append('a')
67466                 .attr('href', '#')
67467                 .on('click', selectRelation);
67468
67469             label
67470                 .append('span')
67471                 .attr('class', 'member-entity-type')
67472                 .text(function(d) {
67473                     var matched = context.presets().match(d.relation, context.graph());
67474                     return (matched && matched.name()) || t('inspector.relation');
67475                 });
67476
67477             label
67478                 .append('span')
67479                 .attr('class', 'member-entity-name')
67480                 .text(function(d) { return utilDisplayName(d.relation); });
67481
67482             enter
67483                 .append('input')
67484                 .attr('class', 'member-role')
67485                 .property('type', 'text')
67486                 .attr('maxlength', 255)
67487                 .attr('placeholder', t('inspector.role'))
67488                 .call(utilNoAuto)
67489                 .property('value', function(d) { return d.member.role; })
67490                 .on('change', changeRole);
67491
67492             enter
67493                 .append('button')
67494                 .attr('tabindex', -1)
67495                 .attr('class', 'remove button-input-action member-delete minor')
67496                 .on('click', deleteMembership)
67497                 .call(svgIcon('#operation-delete'));
67498
67499             if (taginfo) {
67500                 enter.each(bindTypeahead);
67501             }
67502
67503
67504             var newrow = list.selectAll('.member-row-new')
67505                 .data(showBlank ? [0] : []);
67506
67507             newrow.exit()
67508                 .remove();
67509
67510             enter = newrow.enter()
67511                 .append('li')
67512                 .attr('class', 'member-row member-row-new form-field');
67513
67514             enter
67515                 .append('input')
67516                 .attr('type', 'text')
67517                 .attr('class', 'member-entity-input')
67518                 .call(utilNoAuto);
67519
67520             enter
67521                 .append('input')
67522                 .attr('class', 'member-role')
67523                 .property('type', 'text')
67524                 .attr('maxlength', 255)
67525                 .attr('placeholder', t('inspector.role'))
67526                 .call(utilNoAuto)
67527                 .on('change', changeRole);
67528
67529             enter
67530                 .append('button')
67531                 .attr('tabindex', -1)
67532                 .attr('class', 'remove button-input-action member-delete minor')
67533                 .on('click', deleteMembership)
67534                 .call(svgIcon('#operation-delete'));
67535
67536             newrow = newrow
67537                 .merge(enter);
67538
67539             newrow.selectAll('.member-entity-input')
67540                 .call(d3combobox()
67541                     .container(context.container())
67542                     .minItems(1)
67543                     .fetcher(function(value, callback) { callback(relations(value)); })
67544                     .on('accept', onAccept)
67545                 );
67546
67547
67548             var addrel = wrap.selectAll('.add-relation')
67549                 .data([0]);
67550
67551             addrel = addrel.enter()
67552                 .append('button')
67553                 .attr('class', 'add-relation')
67554                 .merge(addrel);
67555
67556             addrel
67557                 .call(svgIcon('#icon-plus', 'light'))
67558                 .on('click', function() {
67559                     showBlank = true;
67560                     content(wrap);
67561                     list.selectAll('.member-entity-input').node().focus();
67562                 });
67563
67564
67565             function onAccept(d) {
67566                 var role = list.selectAll('.member-row-new .member-role').property('value');
67567                 addMembership(d, role);
67568             }
67569
67570
67571             function bindTypeahead(d) {
67572                 var row = select(this),
67573                     role = row.selectAll('input.member-role');
67574
67575                 function sort(value, data) {
67576                     var sameletter = [],
67577                         other = [];
67578                     for (var i = 0; i < data.length; i++) {
67579                         if (data[i].value.substring(0, value.length) === value) {
67580                             sameletter.push(data[i]);
67581                         } else {
67582                             other.push(data[i]);
67583                         }
67584                     }
67585                     return sameletter.concat(other);
67586                 }
67587
67588                 role.call(d3combobox()
67589                     .container(context.container())
67590                     .fetcher(function(role, callback) {
67591                         var rtype = d.relation.tags.type;
67592                         taginfo.roles({
67593                             debounce: true,
67594                             rtype: rtype || '',
67595                             geometry: context.geometry(id),
67596                             query: role
67597                         }, function(err, data) {
67598                             if (!err) callback(sort(role, data));
67599                         });
67600                     }));
67601             }
67602
67603
67604             function unbind() {
67605                 var row = select(this);
67606
67607                 row.selectAll('input.member-role')
67608                     .call(d3combobox.off);
67609             }
67610         }
67611     }
67612
67613
67614     rawMembershipEditor.entityID = function(_) {
67615         if (!arguments.length) return id;
67616         id = _;
67617         return rawMembershipEditor;
67618     };
67619
67620
67621     return rawMembershipEditor;
67622 }
67623
67624 function uiTagReference(tag) {
67625     var taginfo = services.taginfo,
67626         tagReference = {},
67627         button,
67628         body,
67629         loaded,
67630         showing;
67631
67632
67633     function findLocal(data) {
67634         var locale = utilDetect().locale.toLowerCase(),
67635             localized;
67636
67637         if (locale !== 'pt-br') {  // see #3776, prefer 'pt' over 'pt-br'
67638             localized = lodash.find(data, function(d) {
67639                 return d.lang.toLowerCase() === locale;
67640             });
67641             if (localized) return localized;
67642         }
67643
67644         // try the non-regional version of a language, like
67645         // 'en' if the language is 'en-US'
67646         if (locale.indexOf('-') !== -1) {
67647             var first = locale.split('-')[0];
67648             localized = lodash.find(data, function(d) {
67649                 return d.lang.toLowerCase() === first;
67650             });
67651             if (localized) return localized;
67652         }
67653
67654         // finally fall back to english
67655         return lodash.find(data, function(d) {
67656             return d.lang.toLowerCase() === 'en';
67657         });
67658     }
67659
67660
67661     function load(param) {
67662         if (!taginfo) return;
67663
67664         button.classed('tag-reference-loading', true);
67665
67666         taginfo.docs(param, function show(err, data) {
67667             var docs;
67668             if (!err && data) {
67669                 docs = findLocal(data);
67670             }
67671
67672             body.html('');
67673
67674
67675             if (!docs || !docs.title) {
67676                 if (param.hasOwnProperty('value')) {
67677                     load(lodash.omit(param, 'value'));   // retry with key only
67678                 } else {
67679                     body.append('p').text(t('inspector.no_documentation_key'));
67680                     done();
67681                 }
67682                 return;
67683             }
67684
67685
67686             if (docs.image && docs.image.thumb_url_prefix) {
67687                 body
67688                     .append('img')
67689                     .attr('class', 'wiki-image')
67690                     .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
67691                     .on('load', function() { done(); })
67692                     .on('error', function() { select(this).remove(); done(); });
67693             } else {
67694                 done();
67695             }
67696
67697             body
67698                 .append('p')
67699                 .text(docs.description || t('inspector.documentation_redirect'));
67700
67701             body
67702                 .append('a')
67703                 .attr('target', '_blank')
67704                 .attr('tabindex', -1)
67705                 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
67706                 .call(svgIcon('#icon-out-link', 'inline'))
67707                 .append('span')
67708                 .text(t('inspector.reference'));
67709         });
67710     }
67711
67712
67713     function done() {
67714         loaded = true;
67715
67716         button.classed('tag-reference-loading', false);
67717
67718         body.transition()
67719             .duration(200)
67720             .style('max-height', '200px')
67721             .style('opacity', '1');
67722
67723         showing = true;
67724     }
67725
67726
67727     function hide(selection$$1) {
67728         selection$$1 = selection$$1 || body.transition().duration(200);
67729
67730         selection$$1
67731             .style('max-height', '0px')
67732             .style('opacity', '0');
67733
67734         showing = false;
67735     }
67736
67737
67738     tagReference.button = function(selection$$1) {
67739         button = selection$$1.selectAll('.tag-reference-button')
67740             .data([0]);
67741
67742         button = button.enter()
67743             .append('button')
67744             .attr('class', 'tag-reference-button')
67745             .attr('tabindex', -1)
67746             .call(svgIcon('#icon-inspect'))
67747             .merge(button);
67748
67749         button
67750             .on('click', function () {
67751                 event.stopPropagation();
67752                 event.preventDefault();
67753                 if (showing) {
67754                     hide();
67755                 } else if (loaded) {
67756                     done();
67757                 } else {
67758                     load(tag);
67759                 }
67760             });
67761     };
67762
67763
67764     tagReference.body = function(selection$$1) {
67765         body = selection$$1.selectAll('.tag-reference-body')
67766             .data([0]);
67767
67768         body = body.enter()
67769             .append('div')
67770             .attr('class', 'tag-reference-body cf')
67771             .style('max-height', '0')
67772             .style('opacity', '0')
67773             .merge(body);
67774
67775         if (showing === false) {
67776             hide(body);
67777         }
67778     };
67779
67780
67781     tagReference.showing = function(_) {
67782         if (!arguments.length) return showing;
67783         showing = _;
67784         return tagReference;
67785     };
67786
67787
67788     return tagReference;
67789 }
67790
67791 function uiRawTagEditor(context) {
67792     var taginfo = services.taginfo,
67793         dispatch$$1 = dispatch('change'),
67794         expanded = context.storage('raw_tag_editor.expanded') === 'true',
67795         readOnlyTags = [],
67796         updatePreference = true,
67797         showBlank = false,
67798         newRow,
67799         state,
67800         preset,
67801         tags,
67802         id;
67803
67804
67805     function rawTagEditor(selection$$1) {
67806         var count = Object.keys(tags).filter(function(d) { return d; }).length;
67807
67808         selection$$1.call(uiDisclosure()
67809             .title(t('inspector.all_tags') + ' (' + count + ')')
67810             .expanded(expanded)
67811             .on('toggled', toggled)
67812             .content(content)
67813         );
67814
67815         function toggled(expanded) {
67816             if (updatePreference) {
67817                 context.storage('raw_tag_editor.expanded', expanded);
67818             }
67819             if (expanded) {
67820                 selection$$1.node().parentNode.scrollTop += 200;
67821             }
67822         }
67823     }
67824
67825
67826     function content(wrap) {
67827         var entries$$1 = entries(tags);
67828
67829         if (!entries$$1.length || showBlank) {
67830             showBlank = false;
67831             entries$$1.push({key: '', value: ''});
67832             newRow = '';
67833         }
67834
67835         var list = wrap.selectAll('.tag-list')
67836             .data([0]);
67837
67838         list = list.enter()
67839             .append('ul')
67840             .attr('class', 'tag-list')
67841             .merge(list);
67842
67843         var newTag = wrap.selectAll('.add-tag')
67844             .data([0]);
67845
67846         newTag.enter()
67847             .append('button')
67848             .attr('class', 'add-tag')
67849             .on('click', addTag)
67850             .call(svgIcon('#icon-plus', 'light'));
67851
67852
67853         var items = list.selectAll('.tag-row')
67854             .data(entries$$1, function(d) { return d.key; });
67855
67856         items.exit()
67857             .each(unbind)
67858             .remove();
67859
67860         // Enter
67861
67862         var enter = items.enter()
67863             .append('li')
67864             .attr('class', 'tag-row cf')
67865             .classed('readonly', isReadOnly);
67866
67867         enter
67868             .append('div')
67869             .attr('class', 'key-wrap')
67870             .append('input')
67871             .property('type', 'text')
67872             .attr('class', 'key')
67873             .attr('maxlength', 255)
67874             .call(utilNoAuto)
67875             .on('blur', keyChange)
67876             .on('change', keyChange);
67877
67878         enter
67879             .append('div')
67880             .attr('class', 'input-wrap-position')
67881             .append('input')
67882             .property('type', 'text')
67883             .attr('class', 'value')
67884             .attr('maxlength', 255)
67885             .call(utilNoAuto)
67886             .on('blur', valueChange)
67887             .on('change', valueChange)
67888             .on('keydown.push-more', pushMore);
67889
67890         enter
67891             .append('button')
67892             .attr('tabindex', -1)
67893             .attr('class', 'remove minor')
67894             .call(svgIcon('#operation-delete'));
67895
67896
67897         // Update
67898
67899         items = items
67900             .merge(enter)
67901             .sort(function(a, b) {
67902                 return (a.key === newRow && b.key !== newRow) ? 1
67903                     : (a.key !== newRow && b.key === newRow) ? -1
67904                     : ascending(a.key, b.key);
67905             });
67906
67907         items
67908             .each(function(tag) {
67909                 var row = select(this),
67910                     key = row.select('input.key'),      // propagate bound data to child
67911                     value = row.select('input.value');  // propagate bound data to child
67912
67913                 if (id && taginfo) {
67914                     bindTypeahead(key, value);
67915                 }
67916
67917                 var isRelation = (id && context.entity(id).type === 'relation'),
67918                     reference;
67919
67920                 if (isRelation && tag.key === 'type') {
67921                     reference = uiTagReference({ rtype: tag.value }, context);
67922                 } else {
67923                     reference = uiTagReference({ key: tag.key, value: tag.value }, context);
67924                 }
67925
67926                 if (state === 'hover') {
67927                     reference.showing(false);
67928                 }
67929
67930                 row
67931                     .call(reference.button)
67932                     .call(reference.body);
67933             });
67934
67935         items.selectAll('input.key')
67936             .attr('title', function(d) { return d.key; })
67937             .call(utilGetSetValue, function(d) { return d.key; })
67938             .property('disabled', isReadOnly);
67939
67940         items.selectAll('input.value')
67941             .attr('title', function(d) { return d.value; })
67942             .call(utilGetSetValue, function(d) { return d.value; })
67943             .property('disabled', isReadOnly);
67944
67945         items.selectAll('button.remove')
67946             .on('click', removeTag);
67947
67948
67949
67950         function isReadOnly(d) {
67951             return readOnlyTags.indexOf(d.key) !== -1;
67952         }
67953
67954
67955         function pushMore() {
67956             if (event.keyCode === 9 && !event.shiftKey &&
67957                 list.selectAll('li:last-child input.value').node() === this) {
67958                 addTag();
67959             }
67960         }
67961
67962
67963         function bindTypeahead(key, value) {
67964             if (isReadOnly({ key: key })) return;
67965             var geometry = context.geometry(id);
67966
67967             key.call(d3combobox()
67968                 .container(context.container())
67969                 .fetcher(function(value, callback) {
67970                     taginfo.keys({
67971                         debounce: true,
67972                         geometry: geometry,
67973                         query: value
67974                     }, function(err, data) {
67975                         if (!err) callback(sort(value, data));
67976                     });
67977                 }));
67978
67979             value.call(d3combobox()
67980                 .container(context.container())
67981                 .fetcher(function(value, callback) {
67982                     taginfo.values({
67983                         debounce: true,
67984                         key: utilGetSetValue(key),
67985                         geometry: geometry,
67986                         query: value
67987                     }, function(err, data) {
67988                         if (!err) callback(sort(value, data));
67989                     });
67990                 }));
67991
67992
67993             function sort(value, data) {
67994                 var sameletter = [],
67995                     other = [];
67996                 for (var i = 0; i < data.length; i++) {
67997                     if (data[i].value.substring(0, value.length) === value) {
67998                         sameletter.push(data[i]);
67999                     } else {
68000                         other.push(data[i]);
68001                     }
68002                 }
68003                 return sameletter.concat(other);
68004             }
68005         }
68006
68007
68008         function unbind() {
68009             var row = select(this);
68010
68011             row.selectAll('input.key')
68012                 .call(d3combobox.off);
68013
68014             row.selectAll('input.value')
68015                 .call(d3combobox.off);
68016         }
68017
68018
68019         function keyChange(d) {
68020             var kOld = d.key,
68021                 kNew = this.value.trim(),
68022                 tag = {};
68023
68024
68025             if (isReadOnly({ key: kNew })) {
68026                 this.value = kOld;
68027                 return;
68028             }
68029
68030             if (kNew && kNew !== kOld) {
68031                 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
68032                     base = match[1],
68033                     suffix = +(match[2] || 1);
68034                 while (tags[kNew]) {  // rename key if already in use
68035                     kNew = base + '_' + suffix++;
68036                 }
68037             }
68038             tag[kOld] = undefined;
68039             tag[kNew] = d.value;
68040
68041             d.key = kNew; // Maintain DOM identity through the subsequent update.
68042
68043             if (newRow === kOld) {  // see if this row is still a new row
68044                 newRow = ((d.value === '' || kNew === '') ? kNew : undefined);
68045             }
68046
68047             this.value = kNew;
68048             dispatch$$1.call('change', this, tag);
68049         }
68050
68051
68052         function valueChange(d) {
68053             if (isReadOnly(d)) return;
68054             var tag = {};
68055             tag[d.key] = this.value;
68056
68057             if (newRow === d.key && d.key !== '' && d.value !== '') {   // not a new row anymore
68058                 newRow = undefined;
68059             }
68060
68061             dispatch$$1.call('change', this, tag);
68062         }
68063
68064
68065         function removeTag(d) {
68066             if (isReadOnly(d)) return;
68067             var tag = {};
68068             tag[d.key] = undefined;
68069             dispatch$$1.call('change', this, tag);
68070             select(this.parentNode).remove();
68071         }
68072
68073
68074         function addTag() {
68075             // Wrapped in a setTimeout in case it's being called from a blur
68076             // handler. Without the setTimeout, the call to `content` would
68077             // wipe out the pending value change.
68078             setTimeout(function() {
68079                 showBlank = true;
68080                 content(wrap);
68081                 list.selectAll('li:last-child input.key').node().focus();
68082             }, 0);
68083         }
68084     }
68085
68086
68087     rawTagEditor.state = function(_) {
68088         if (!arguments.length) return state;
68089         state = _;
68090         return rawTagEditor;
68091     };
68092
68093
68094     rawTagEditor.preset = function(_) {
68095         if (!arguments.length) return preset;
68096         preset = _;
68097         if (preset.isFallback()) {
68098             expanded = true;
68099             updatePreference = false;
68100         } else {
68101             expanded = context.storage('raw_tag_editor.expanded') === 'true';
68102             updatePreference = true;
68103         }
68104         return rawTagEditor;
68105     };
68106
68107
68108     rawTagEditor.tags = function(_) {
68109         if (!arguments.length) return tags;
68110         tags = _;
68111         return rawTagEditor;
68112     };
68113
68114
68115     rawTagEditor.entityID = function(_) {
68116         if (!arguments.length) return id;
68117         id = _;
68118         return rawTagEditor;
68119     };
68120
68121
68122     rawTagEditor.expanded = function(_) {
68123         if (!arguments.length) return expanded;
68124         expanded = _;
68125         updatePreference = false;
68126         return rawTagEditor;
68127     };
68128
68129
68130     rawTagEditor.readOnlyTags = function(_) {
68131         if (!arguments.length) return readOnlyTags;
68132         readOnlyTags = _;
68133         return rawTagEditor;
68134     };
68135
68136
68137     return utilRebind(rawTagEditor, dispatch$$1, 'on');
68138 }
68139
68140 function uiFieldCheck(field, context) {
68141     var dispatch$$1 = dispatch('change'),
68142         options = field.strings && field.strings.options,
68143         values$$1 = [],
68144         texts = [],
68145         input = select(null),
68146         text$$1 = select(null),
68147         label = select(null),
68148         reverser = select(null),
68149         impliedYes,
68150         entityId,
68151         value;
68152
68153
68154     if (options) {
68155         for (var k in options) {
68156             values$$1.push(k === 'undefined' ? undefined : k);
68157             texts.push(field.t('options.' + k, { 'default': options[k] }));
68158         }
68159     } else {
68160         values$$1 = [undefined, 'yes'];
68161         texts = [t('inspector.unknown'), t('inspector.check.yes')];
68162         if (field.type !== 'defaultCheck') {
68163             values$$1.push('no');
68164             texts.push(t('inspector.check.no'));
68165         }
68166     }
68167
68168
68169     // Checks tags to see whether an undefined value is "Assumed to be Yes"
68170     function checkImpliedYes() {
68171         impliedYes = (field.id === 'oneway_yes');
68172
68173         // hack: pretend `oneway` field is a `oneway_yes` field
68174         // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
68175         if (field.id === 'oneway') {
68176             var entity = context.entity(entityId);
68177             for (var key in entity.tags) {
68178                 if (key in osmOneWayTags && (entity.tags[key] in osmOneWayTags[key])) {
68179                     impliedYes = true;
68180                     texts[0] = t('presets.fields.oneway_yes.options.undefined');
68181                     break;
68182                 }
68183             }
68184         }
68185     }
68186
68187
68188     function reverserHidden() {
68189         if (!select('div.inspector-hover').empty()) return true;
68190         return !(value === 'yes' || (impliedYes && !value));
68191     }
68192
68193
68194     function reverserSetText(selection$$1) {
68195         var entity = context.hasEntity(entityId);
68196         if (reverserHidden() || !entity) return selection$$1;
68197
68198         var first = entity.first(),
68199             last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last(),
68200             pseudoDirection = first < last,
68201             icon = pseudoDirection ? '#icon-forward' : '#icon-backward';
68202
68203         selection$$1.selectAll('.reverser-span')
68204             .text(t('inspector.check.reverser'))
68205             .call(svgIcon(icon, 'inline'));
68206
68207         return selection$$1;
68208     }
68209
68210
68211     var check = function(selection$$1) {
68212         checkImpliedYes();
68213         selection$$1.classed('checkselect', 'true');
68214
68215         label = selection$$1.selectAll('.preset-input-wrap')
68216             .data([0]);
68217
68218         var enter = label.enter()
68219             .append('label')
68220             .attr('class', 'preset-input-wrap');
68221
68222         enter
68223             .append('input')
68224             .property('indeterminate', field.type !== 'defaultCheck')
68225             .attr('type', 'checkbox')
68226             .attr('id', 'preset-input-' + field.id);
68227
68228         enter
68229             .append('span')
68230             .text(texts[0])
68231             .attr('class', 'value');
68232
68233         if (field.type === 'onewayCheck') {
68234             enter
68235                 .append('a')
68236                 .attr('id', 'preset-input-' + field.id + '-reverser')
68237                 .attr('class', 'reverser button' + (reverserHidden() ? ' hide' : ''))
68238                 .attr('href', '#')
68239                 .append('span')
68240                 .attr('class', 'reverser-span');
68241         }
68242
68243         label = label.merge(enter);
68244         input = label.selectAll('input');
68245         text$$1 = label.selectAll('span.value');
68246
68247         input
68248             .on('click', function() {
68249                 var t$$1 = {};
68250                 t$$1[field.key] = values$$1[(values$$1.indexOf(value) + 1) % values$$1.length];
68251                 dispatch$$1.call('change', this, t$$1);
68252                 event.stopPropagation();
68253             });
68254
68255         if (field.type === 'onewayCheck') {
68256             reverser = label.selectAll('.reverser');
68257
68258             reverser
68259                 .call(reverserSetText)
68260                 .on('click', function() {
68261                     event.preventDefault();
68262                     event.stopPropagation();
68263                     context.perform(
68264                         actionReverse(entityId),
68265                         t('operations.reverse.annotation')
68266                     );
68267                     select(this)
68268                         .call(reverserSetText);
68269                 });
68270         }
68271     };
68272
68273
68274     check.entity = function(_) {
68275         if (!arguments.length) return context.hasEntity(entityId);
68276         entityId = _.id;
68277         return check;
68278     };
68279
68280
68281     check.tags = function(tags) {
68282         checkImpliedYes();
68283         value = tags[field.key] && tags[field.key].toLowerCase();
68284
68285         if (field.type === 'onewayCheck' && (value === '1' || value === '-1')) {
68286             value = 'yes';
68287         }
68288
68289         input
68290             .property('indeterminate', field.type !== 'defaultCheck' && !value)
68291             .property('checked', value === 'yes');
68292
68293         text$$1
68294             .text(texts[values$$1.indexOf(value)]);
68295
68296         label
68297             .classed('set', !!value);
68298
68299         if (field.type === 'onewayCheck') {
68300             reverser
68301                 .classed('hide', reverserHidden())
68302                 .call(reverserSetText);
68303         }
68304     };
68305
68306
68307     check.focus = function() {
68308         input.node().focus();
68309     };
68310
68311     return utilRebind(check, dispatch$$1, 'on');
68312 }
68313
68314 function uiFieldCombo(field, context) {
68315     var dispatch$$1 = dispatch('change'),
68316         nominatim = services.geocoder,
68317         taginfo = services.taginfo,
68318         isMulti = (field.type === 'multiCombo'),
68319         isNetwork = (field.type === 'networkCombo'),
68320         isSemi = (field.type === 'semiCombo'),
68321         optstrings = field.strings && field.strings.options,
68322         optarray = field.options,
68323         snake_case = (field.snake_case || (field.snake_case === undefined)),
68324         combobox = d3combobox()
68325             .container(context.container())
68326             .minItems(isMulti || isSemi ? 1 : 2),
68327         comboData = [],
68328         multiData = [],
68329         container,
68330         input,
68331         entity,
68332         country;
68333
68334     // ensure multiCombo field.key ends with a ':'
68335     if (isMulti && field.key.match(/:$/) === null) {
68336         field.key += ':';
68337     }
68338
68339
68340     function snake(s) {
68341         return s.replace(/\s+/g, '_');
68342     }
68343
68344     function unsnake(s) {
68345         return s.replace(/_+/g, ' ');
68346     }
68347
68348     function clean(s) {
68349         return s.split(';')
68350             .map(function(s) { return s.trim(); })
68351             .join(';');
68352     }
68353
68354
68355     // returns the tag value for a display value
68356     // (for multiCombo, dval should be the key suffix, not the entire key)
68357     function tagValue(dval) {
68358         dval = clean(dval || '');
68359
68360         if (optstrings) {
68361             var match = lodash.find(comboData, function(o) {
68362                 return o.key && clean(o.value) === dval;
68363             });
68364             if (match) {
68365                 return match.key;
68366             }
68367         }
68368
68369         if (field.type === 'typeCombo' && !dval) {
68370             return 'yes';
68371         }
68372
68373         return (snake_case ? snake(dval) : dval) || undefined;
68374     }
68375
68376
68377     // returns the display value for a tag value
68378     // (for multiCombo, tval should be the key suffix, not the entire key)
68379     function displayValue(tval) {
68380         tval = tval || '';
68381
68382         if (optstrings) {
68383             var match = lodash.find(comboData, function(o) { return o.key === tval && o.value; });
68384             if (match) {
68385                 return match.value;
68386             }
68387         }
68388
68389         if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
68390             return '';
68391         }
68392
68393         return snake_case ? unsnake(tval) : tval;
68394     }
68395
68396
68397     function objectDifference(a, b) {
68398         return lodash.reject(a, function(d1) {
68399             return lodash.some(b, function(d2) { return d1.value === d2.value; });
68400         });
68401     }
68402
68403
68404     function initCombo(selection$$1, attachTo) {
68405         if (optstrings) {
68406             selection$$1.attr('readonly', 'readonly');
68407             selection$$1.call(combobox, attachTo);
68408             setStaticValues(setPlaceholder);
68409
68410         } else if (optarray) {
68411             selection$$1.call(combobox, attachTo);
68412             setStaticValues(setPlaceholder);
68413
68414         } else if (taginfo) {
68415             selection$$1.call(combobox.fetcher(setTaginfoValues), attachTo);
68416             setTaginfoValues('', setPlaceholder);
68417         }
68418     }
68419
68420
68421     function setStaticValues(callback) {
68422         if (!(optstrings || optarray)) return;
68423
68424         if (optstrings) {
68425             comboData = Object.keys(optstrings).map(function(k) {
68426                 var v = field.t('options.' + k, { 'default': optstrings[k] });
68427                 return {
68428                     key: k,
68429                     value: v,
68430                     title: v
68431                 };
68432             });
68433
68434         } else if (optarray) {
68435             comboData = optarray.map(function(k) {
68436                 var v = snake_case ? unsnake(k) : k;
68437                 return {
68438                     key: k,
68439                     value: v,
68440                     title: v
68441                 };
68442             });
68443         }
68444
68445         combobox.data(objectDifference(comboData, multiData));
68446         if (callback) callback(comboData);
68447     }
68448
68449
68450     function setTaginfoValues(q, callback) {
68451         var fn = isMulti ? 'multikeys' : 'values';
68452         var query = (isMulti ? field.key : '') + q;
68453         var hasCountryPrefix = isNetwork && country && country.indexOf(q.toLowerCase()) === 0;
68454         if (hasCountryPrefix) {
68455             query = country + ':';
68456         }
68457
68458         taginfo[fn]({
68459             debounce: (q !== ''),
68460             key: field.key,
68461             geometry: context.geometry(entity.id),
68462             query: query
68463         }, function(err, data) {
68464             if (err) return;
68465             if (hasCountryPrefix) {
68466                 data = lodash.filter(data, function(d) {
68467                     return d.value.toLowerCase().indexOf(country + ':') === 0;
68468                 });
68469             }
68470
68471             comboData = lodash.map(data, function(d) {
68472                 var k = d.value;
68473                 if (isMulti) k = k.replace(field.key, '');
68474                 var v = snake_case ? unsnake(k) : k;
68475                 return {
68476                     key: k,
68477                     value: v,
68478                     title: isMulti ? v : d.title
68479                 };
68480             });
68481
68482             comboData = objectDifference(comboData, multiData);
68483             if (callback) callback(comboData);
68484         });
68485     }
68486
68487
68488     function setPlaceholder(d) {
68489         var ph;
68490
68491         if (isMulti || isSemi) {
68492             ph = field.placeholder() || t('inspector.add');
68493         } else {
68494             var vals = lodash.map(d, 'value').filter(function(s) { return s.length < 20; }),
68495                 placeholders = vals.length > 1 ? vals : lodash.map(d, 'key');
68496             ph = field.placeholder() || placeholders.slice(0, 3).join(', ');
68497         }
68498
68499         if (ph.match(/(…|\.\.\.)$/) === null) {
68500             ph += '…';
68501         }
68502
68503         container.selectAll('input')
68504             .attr('placeholder', ph);
68505     }
68506
68507
68508     function change() {
68509         var val = tagValue(utilGetSetValue(input)),
68510             t$$1 = {};
68511
68512         if (isMulti || isSemi) {
68513             if (!val) return;
68514             container.classed('active', false);
68515             utilGetSetValue(input, '');
68516             if (isMulti) {
68517                 field.keys.push(field.key + val);
68518                 t$$1[field.key + val] = 'yes';
68519             } else if (isSemi) {
68520                 var arr = multiData.map(function(d) { return d.key; });
68521                 arr.push(val);
68522                 t$$1[field.key] = lodash.compact(lodash.uniq(arr)).join(';');
68523             }
68524             window.setTimeout(function() { input.node().focus(); }, 10);
68525
68526         } else {
68527             t$$1[field.key] = val;
68528         }
68529
68530         dispatch$$1.call('change', this, t$$1);
68531     }
68532
68533
68534     function removeMultikey(d) {
68535         event.stopPropagation();
68536         var t$$1 = {};
68537         if (isMulti) {
68538             t$$1[d.key] = undefined;
68539         } else if (isSemi) {
68540             lodash.remove(multiData, function(md) { return md.key === d.key; });
68541             var arr = multiData.map(function(md) { return md.key; });
68542             arr = lodash.compact(lodash.uniq(arr));
68543             t$$1[field.key] = arr.length ? arr.join(';') : undefined;
68544         }
68545         dispatch$$1.call('change', this, t$$1);
68546     }
68547
68548
68549     function combo(selection$$1) {
68550         if (isMulti || isSemi) {
68551             container = selection$$1.selectAll('ul').data([0]);
68552
68553             container = container.enter()
68554                 .append('ul')
68555                 .attr('class', 'form-field-multicombo')
68556                 .on('click', function() {
68557                     window.setTimeout(function() { input.node().focus(); }, 10);
68558                 })
68559                 .merge(container);
68560
68561         } else {
68562             container = selection$$1;
68563         }
68564
68565         input = container.selectAll('input')
68566             .data([0]);
68567
68568         input = input.enter()
68569             .append('input')
68570             .attr('type', 'text')
68571             .attr('id', 'preset-input-' + field.id)
68572             .call(utilNoAuto)
68573             .call(initCombo, selection$$1)
68574             .merge(input);
68575
68576         if (isNetwork && nominatim && entity) {
68577             var center = entity.extent(context.graph()).center();
68578             nominatim.countryCode(center, function (err, code) {
68579                 country = code;
68580             });
68581         }
68582
68583         input
68584             .on('change', change)
68585             .on('blur', change);
68586
68587         if (isMulti || isSemi) {
68588             combobox
68589                 .on('accept', function() {
68590                     input.node().blur();
68591                     input.node().focus();
68592                 });
68593
68594             input
68595                 .on('focus', function() { container.classed('active', true); });
68596         }
68597     }
68598
68599
68600     combo.tags = function(tags) {
68601         if (isMulti || isSemi) {
68602             multiData = [];
68603
68604             if (isMulti) {
68605                 // Build multiData array containing keys already set..
68606                 Object.keys(tags).forEach(function(key) {
68607                     if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return;
68608
68609                     var suffix = key.substring(field.key.length);
68610                     multiData.push({
68611                         key: key,
68612                         value: displayValue(suffix)
68613                     });
68614                 });
68615
68616                 // Set keys for form-field modified (needed for undo and reset buttons)..
68617                 field.keys = lodash.map(multiData, 'key');
68618
68619             } else if (isSemi) {
68620                 var arr = lodash.compact(lodash.uniq((tags[field.key] || '').split(';')));
68621                 multiData = arr.map(function(key) {
68622                     return {
68623                         key: key,
68624                         value: displayValue(key)
68625                     };
68626                 });
68627             }
68628
68629             // Exclude existing multikeys from combo options..
68630             var available = objectDifference(comboData, multiData);
68631             combobox.data(available);
68632
68633             // Hide 'Add' button if this field uses fixed set of
68634             // translateable optstrings and they're all currently used..
68635             container.selectAll('.combobox-input, .combobox-caret')
68636                 .classed('hide', optstrings && !available.length);
68637
68638
68639             // Render chips
68640             var chips = container.selectAll('.chips')
68641                 .data(multiData);
68642
68643             chips.exit()
68644                 .remove();
68645
68646             var enter = chips.enter()
68647                 .insert('li', 'input')
68648                 .attr('class', 'chips');
68649
68650             enter.append('span');
68651             enter.append('a');
68652
68653             chips = chips.merge(enter);
68654
68655             chips.select('span')
68656                 .text(function(d) { return d.value; });
68657
68658             chips.select('a')
68659                 .on('click', removeMultikey)
68660                 .attr('class', 'remove')
68661                 .text('×');
68662
68663         } else {
68664             utilGetSetValue(input, displayValue(tags[field.key]));
68665         }
68666     };
68667
68668
68669     combo.focus = function() {
68670         input.node().focus();
68671     };
68672
68673
68674     combo.entity = function(_) {
68675         if (!arguments.length) return entity;
68676         entity = _;
68677         return combo;
68678     };
68679
68680
68681     return utilRebind(combo, dispatch$$1, 'on');
68682 }
68683
68684 function uiFieldText(field, context) {
68685     var dispatch$$1 = dispatch('change'),
68686         nominatim = services.geocoder,
68687         input,
68688         entity;
68689
68690
68691     function i(selection$$1) {
68692         var fieldId = 'preset-input-' + field.id;
68693
68694         input = selection$$1.selectAll('input')
68695             .data([0]);
68696
68697         input = input.enter()
68698             .append('input')
68699             .attr('type', field.type)
68700             .attr('id', fieldId)
68701             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
68702             .call(utilNoAuto)
68703             .merge(input);
68704
68705         input
68706             .on('input', change(true))
68707             .on('blur', change())
68708             .on('change', change());
68709
68710         if (field.type === 'tel' && nominatim && entity) {
68711             var center = entity.extent(context.graph()).center();
68712             nominatim.countryCode(center, function (err, countryCode) {
68713                 if (err || !dataPhoneFormats[countryCode]) return;
68714                 selection$$1.selectAll('#' + fieldId)
68715                     .attr('placeholder', dataPhoneFormats[countryCode]);
68716             });
68717
68718         } else if (field.type === 'number') {
68719             input.attr('type', 'text');
68720
68721             var spinControl = selection$$1.selectAll('.spin-control')
68722                 .data([0]);
68723
68724             var enter = spinControl.enter()
68725                 .append('div')
68726                 .attr('class', 'spin-control');
68727
68728             enter
68729                 .append('button')
68730                 .datum(-1)
68731                 .attr('class', 'decrement')
68732                 .attr('tabindex', -1);
68733
68734             enter
68735                 .append('button')
68736                 .datum(1)
68737                 .attr('class', 'increment')
68738                 .attr('tabindex', -1);
68739
68740             spinControl = spinControl
68741                 .merge(enter);
68742
68743             spinControl.selectAll('button')
68744                 .on('click', function(d) {
68745                     event.preventDefault();
68746                     var num = parseInt(input.node().value || 0, 10);
68747                     if (!isNaN(num)) input.node().value = num + d;
68748                     change()();
68749                 });
68750         }
68751     }
68752
68753
68754     function change(onInput) {
68755         return function() {
68756             var t$$1 = {};
68757             t$$1[field.key] = utilGetSetValue(input) || undefined;
68758             dispatch$$1.call('change', this, t$$1, onInput);
68759         };
68760     }
68761
68762
68763     i.entity = function(_) {
68764         if (!arguments.length) return entity;
68765         entity = _;
68766         return i;
68767     };
68768
68769
68770     i.tags = function(tags) {
68771         utilGetSetValue(input, tags[field.key] || '');
68772     };
68773
68774
68775     i.focus = function() {
68776         var node = input.node();
68777         if (node) node.focus();
68778     };
68779
68780     return utilRebind(i, dispatch$$1, 'on');
68781 }
68782
68783 function uiFieldAccess(field, context) {
68784     var dispatch$$1 = dispatch('change'),
68785         items;
68786
68787     function access(selection$$1) {
68788         var wrap = selection$$1.selectAll('.preset-input-wrap')
68789             .data([0]);
68790
68791         wrap = wrap.enter()
68792             .append('div')
68793             .attr('class', 'cf preset-input-wrap')
68794             .append('ul')
68795             .merge(wrap);
68796
68797         var list = wrap.selectAll('ul')
68798             .data([0]);
68799
68800         list = list.enter()
68801             .append('ul')
68802             .merge(list);
68803
68804
68805         items = list.selectAll('li')
68806             .data(field.keys);
68807
68808         // Enter
68809         var enter = items.enter()
68810             .append('li')
68811             .attr('class', function(d) { return 'cf preset-access-' + d; });
68812
68813         enter
68814             .append('span')
68815             .attr('class', 'col6 label preset-label-access')
68816             .attr('for', function(d) { return 'preset-input-access-' + d; })
68817             .text(function(d) { return field.t('types.' + d); });
68818
68819         enter
68820             .append('div')
68821             .attr('class', 'col6 preset-input-access-wrap')
68822             .append('input')
68823             .attr('type', 'text')
68824             .attr('class', 'preset-input-access')
68825             .attr('id', function(d) { return 'preset-input-access-' + d; })
68826             .call(utilNoAuto)
68827             .each(function(d) {
68828                 select(this)
68829                     .call(d3combobox()
68830                         .container(context.container())
68831                         .data(access.options(d))
68832                     );
68833             });
68834
68835
68836         // Update
68837         items = items.merge(enter);
68838
68839         wrap.selectAll('.preset-input-access')
68840             .on('change', change)
68841             .on('blur', change);
68842     }
68843
68844
68845     function change(d) {
68846         var tag = {};
68847         tag[d] = utilGetSetValue(select(this)) || undefined;
68848         dispatch$$1.call('change', this, tag);
68849     }
68850
68851
68852     access.options = function(type) {
68853         var options = ['no', 'permissive', 'private', 'destination'];
68854
68855         if (type !== 'access') {
68856             options.unshift('yes');
68857             options.push('designated');
68858
68859             if (type === 'bicycle') {
68860                 options.push('dismount');
68861             }
68862         }
68863
68864         return options.map(function(option) {
68865             return {
68866                 title: field.t('options.' + option + '.description'),
68867                 value: option
68868             };
68869         });
68870     };
68871
68872
68873     var placeholders = {
68874         footway: {
68875             foot: 'designated',
68876             motor_vehicle: 'no'
68877         },
68878         steps: {
68879             foot: 'yes',
68880             motor_vehicle: 'no',
68881             bicycle: 'no',
68882             horse: 'no'
68883         },
68884         pedestrian: {
68885             foot: 'yes',
68886             motor_vehicle: 'no'
68887         },
68888         cycleway: {
68889             motor_vehicle: 'no',
68890             bicycle: 'designated'
68891         },
68892         bridleway: {
68893             motor_vehicle: 'no',
68894             horse: 'designated'
68895         },
68896         path: {
68897             foot: 'yes',
68898             motor_vehicle: 'no',
68899             bicycle: 'yes',
68900             horse: 'yes'
68901         },
68902         motorway: {
68903             foot: 'no',
68904             motor_vehicle: 'yes',
68905             bicycle: 'no',
68906             horse: 'no'
68907         },
68908         trunk: {
68909             motor_vehicle: 'yes'
68910         },
68911         primary: {
68912             foot: 'yes',
68913             motor_vehicle: 'yes',
68914             bicycle: 'yes',
68915             horse: 'yes'
68916         },
68917         secondary: {
68918             foot: 'yes',
68919             motor_vehicle: 'yes',
68920             bicycle: 'yes',
68921             horse: 'yes'
68922         },
68923         tertiary: {
68924             foot: 'yes',
68925             motor_vehicle: 'yes',
68926             bicycle: 'yes',
68927             horse: 'yes'
68928         },
68929         residential: {
68930             foot: 'yes',
68931             motor_vehicle: 'yes',
68932             bicycle: 'yes',
68933             horse: 'yes'
68934         },
68935         unclassified: {
68936             foot: 'yes',
68937             motor_vehicle: 'yes',
68938             bicycle: 'yes',
68939             horse: 'yes'
68940         },
68941         service: {
68942             foot: 'yes',
68943             motor_vehicle: 'yes',
68944             bicycle: 'yes',
68945             horse: 'yes'
68946         },
68947         motorway_link: {
68948             foot: 'no',
68949             motor_vehicle: 'yes',
68950             bicycle: 'no',
68951             horse: 'no'
68952         },
68953         trunk_link: {
68954             motor_vehicle: 'yes'
68955         },
68956         primary_link: {
68957             foot: 'yes',
68958             motor_vehicle: 'yes',
68959             bicycle: 'yes',
68960             horse: 'yes'
68961         },
68962         secondary_link: {
68963             foot: 'yes',
68964             motor_vehicle: 'yes',
68965             bicycle: 'yes',
68966             horse: 'yes'
68967         },
68968         tertiary_link: {
68969             foot: 'yes',
68970             motor_vehicle: 'yes',
68971             bicycle: 'yes',
68972             horse: 'yes'
68973         }
68974     };
68975
68976
68977     access.tags = function(tags) {
68978         utilGetSetValue(items.selectAll('.preset-input-access'),
68979             function(d) { return tags[d] || ''; })
68980             .attr('placeholder', function() {
68981                 return tags.access ? tags.access : field.placeholder();
68982             });
68983
68984         items.selectAll('#preset-input-access-access')
68985             .attr('placeholder', 'yes');
68986
68987         lodash.forEach(placeholders[tags.highway], function(v, k) {
68988             items.selectAll('#preset-input-access-' + k)
68989                 .attr('placeholder', function() { return (tags.access || v); });
68990         });
68991     };
68992
68993
68994     access.focus = function() {
68995         items.selectAll('.preset-input-access')
68996             .node().focus();
68997     };
68998
68999
69000     return utilRebind(access, dispatch$$1, 'on');
69001 }
69002
69003 function uiFieldAddress(field, context) {
69004     var dispatch$$1 = dispatch('init', 'change'),
69005         nominatim = services.geocoder,
69006         wrap = select(null),
69007         isInitialized = false,
69008         entity;
69009
69010     function getNearStreets() {
69011         var extent$$1 = entity.extent(context.graph()),
69012             l = extent$$1.center(),
69013             box = geoExtent$$1(l).padByMeters(200);
69014
69015         var streets = context.intersects(box)
69016             .filter(isAddressable)
69017             .map(function(d) {
69018                 var loc = context.projection([
69019                     (extent$$1[0][0] + extent$$1[1][0]) / 2,
69020                     (extent$$1[0][1] + extent$$1[1][1]) / 2]),
69021                     choice = geoChooseEdge(context.childNodes(d), loc, context.projection);
69022                 return {
69023                     title: d.tags.name,
69024                     value: d.tags.name,
69025                     dist: choice.distance
69026                 };
69027             })
69028             .sort(function(a, b) {
69029                 return a.dist - b.dist;
69030             });
69031
69032         return lodash.uniqBy(streets, 'value');
69033
69034         function isAddressable(d) {
69035             return d.tags.highway && d.tags.name && d.type === 'way';
69036         }
69037     }
69038
69039
69040     function getNearCities() {
69041         var extent$$1 = entity.extent(context.graph()),
69042             l = extent$$1.center(),
69043             box = geoExtent$$1(l).padByMeters(200);
69044
69045         var cities = context.intersects(box)
69046             .filter(isAddressable)
69047             .map(function(d) {
69048                 return {
69049                     title: d.tags['addr:city'] || d.tags.name,
69050                     value: d.tags['addr:city'] || d.tags.name,
69051                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
69052                 };
69053             })
69054             .sort(function(a, b) {
69055                 return a.dist - b.dist;
69056             });
69057
69058         return lodash.uniqBy(cities, 'value');
69059
69060
69061         function isAddressable(d) {
69062             if (d.tags.name &&
69063                 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
69064                 return true;
69065
69066             if (d.tags.place && d.tags.name && (
69067                     d.tags.place === 'city' ||
69068                     d.tags.place === 'town' ||
69069                     d.tags.place === 'village'))
69070                 return true;
69071
69072             if (d.tags['addr:city']) return true;
69073
69074             return false;
69075         }
69076     }
69077
69078     function getNearValues(key) {
69079         var extent$$1 = entity.extent(context.graph()),
69080             l = extent$$1.center(),
69081             box = geoExtent$$1(l).padByMeters(200);
69082
69083         var results = context.intersects(box)
69084             .filter(function hasTag(d) {
69085                 return d.tags[key];
69086             })
69087             .map(function(d) {
69088                 return {
69089                     title: d.tags[key],
69090                     value: d.tags[key],
69091                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
69092                 };
69093             })
69094             .sort(function(a, b) {
69095                 return a.dist - b.dist;
69096             });
69097
69098         return lodash.uniqBy(results, 'value');
69099     }
69100
69101
69102     function initCallback(err, countryCode) {
69103         if (err) return;
69104
69105         var addressFormat = lodash.find(dataAddressFormats, function (a) {
69106             return a && a.countryCodes && lodash.includes(a.countryCodes, countryCode.toLowerCase());
69107         }) || lodash.first(dataAddressFormats);
69108
69109         var widths = addressFormat.widths || {
69110             housenumber: 1/3, street: 2/3,
69111             city: 2/3, state: 1/4, postcode: 1/3
69112         };
69113
69114         function row(r) {
69115             // Normalize widths.
69116             var total = lodash.reduce(r, function(sum$$1, field) {
69117                 return sum$$1 + (widths[field] || 0.5);
69118             }, 0);
69119
69120             return r.map(function (field) {
69121                 return {
69122                     id: field,
69123                     width: (widths[field] || 0.5) / total
69124                 };
69125             });
69126         }
69127
69128         wrap.selectAll('div.addr-row')
69129             .data(addressFormat.format)
69130             .enter()
69131             .append('div')
69132             .attr('class', 'addr-row')
69133             .selectAll('input')
69134             .data(row)
69135             .enter()
69136             .append('input')
69137             .property('type', 'text')
69138             .attr('placeholder', function (d) {
69139                 var localkey = d.id + '!' + countryCode.toLowerCase(),
69140                     tkey = field.strings.placeholders[localkey] ? localkey : d.id;
69141                 return field.t('placeholders.' + tkey);
69142             })
69143             .attr('class', function (d) { return 'addr-' + d.id; })
69144             .call(utilNoAuto)
69145             .style('width', function (d) { return d.width * 100 + '%'; });
69146
69147         // Update
69148
69149         // setup dropdowns for common address tags
69150         var dropdowns = addressFormat.dropdowns || [
69151             'city', 'county', 'country', 'district', 'hamlet',
69152             'neighbourhood', 'place', 'postcode', 'province',
69153             'quarter', 'state', 'street', 'subdistrict', 'suburb'
69154         ];
69155
69156         // If fields exist for any of these tags, create dropdowns to pick nearby values..
69157         dropdowns.forEach(function(tag) {
69158             var nearValues = (tag === 'street') ? getNearStreets
69159                     : (tag === 'city') ? getNearCities
69160                     : getNearValues;
69161
69162             wrap.selectAll('input.addr-' + tag)
69163                 .call(d3combobox()
69164                     .container(context.container())
69165                     .minItems(1)
69166                     .fetcher(function(value, callback) {
69167                         callback(nearValues('addr:' + tag));
69168                     })
69169                 );
69170         });
69171
69172         wrap.selectAll('input')
69173             .on('blur', change())
69174             .on('change', change());
69175
69176         wrap.selectAll('input:not(.combobox-input)')
69177             .on('input', change(true));
69178
69179         dispatch$$1.call('init');
69180         isInitialized = true;
69181     }
69182
69183
69184     function address(selection$$1) {
69185         isInitialized = false;
69186
69187         wrap = selection$$1.selectAll('.preset-input-wrap')
69188             .data([0]);
69189
69190         wrap = wrap.enter()
69191             .append('div')
69192             .attr('class', 'preset-input-wrap')
69193             .merge(wrap);
69194
69195         if (nominatim && entity) {
69196             var center = entity.extent(context.graph()).center();
69197             nominatim.countryCode(center, initCallback);
69198         }
69199     }
69200
69201
69202     function change(onInput) {
69203         return function() {
69204             var tags = {};
69205
69206             wrap.selectAll('input')
69207                 .each(function (field) {
69208                     tags['addr:' + field.id] = this.value || undefined;
69209                 });
69210
69211             dispatch$$1.call('change', this, tags, onInput);
69212         };
69213     }
69214
69215
69216     function updateTags(tags) {
69217         utilGetSetValue(wrap.selectAll('input'), function (field) {
69218             return tags['addr:' + field.id] || '';
69219         });
69220     }
69221
69222
69223     address.entity = function(_) {
69224         if (!arguments.length) return entity;
69225         entity = _;
69226         return address;
69227     };
69228
69229
69230     address.tags = function(tags) {
69231         if (isInitialized) {
69232             updateTags(tags);
69233         } else {
69234             dispatch$$1.on('init', function () {
69235                 dispatch$$1.on('init', null);
69236                 updateTags(tags);
69237             });
69238         }
69239     };
69240
69241
69242     address.focus = function() {
69243         var node = wrap.selectAll('input').node();
69244         if (node) node.focus();
69245     };
69246
69247
69248     return utilRebind(address, dispatch$$1, 'on');
69249 }
69250
69251 function uiFieldCycleway(field, context) {
69252     var dispatch$$1 = dispatch('change'),
69253         items = select(null);
69254
69255
69256     function cycleway(selection$$1) {
69257
69258         function stripcolon(s) {
69259             return s.replace(':', '');
69260         }
69261
69262
69263         var wrap = selection$$1.selectAll('.preset-input-wrap')
69264             .data([0]);
69265
69266         wrap = wrap.enter()
69267             .append('div')
69268             .attr('class', 'cf preset-input-wrap')
69269             .merge(wrap);
69270
69271
69272         var div = wrap.selectAll('ul')
69273             .data([0]);
69274
69275         div = div.enter()
69276             .append('ul')
69277             .merge(div);
69278
69279
69280         items = div.selectAll('li')
69281             .data(field.keys);
69282
69283         var enter = items.enter()
69284             .append('li')
69285             .attr('class', function(d) { return 'cf preset-cycleway-' + stripcolon(d); });
69286
69287         enter
69288             .append('span')
69289             .attr('class', 'col6 label preset-label-cycleway')
69290             .attr('for', function(d) { return 'preset-input-cycleway-' + stripcolon(d); })
69291             .text(function(d) { return field.t('types.' + d); });
69292
69293         enter
69294             .append('div')
69295             .attr('class', 'col6 preset-input-cycleway-wrap')
69296             .append('input')
69297             .attr('type', 'text')
69298             .attr('class', function(d) { return 'preset-input-cycleway preset-input-' + stripcolon(d); })
69299             .call(utilNoAuto)
69300             .each(function(d) {
69301                 select(this)
69302                     .call(d3combobox()
69303                         .container(context.container())
69304                         .data(cycleway.options(d))
69305                     );
69306             });
69307
69308
69309         // Update
69310         wrap.selectAll('.preset-input-cycleway')
69311             .on('change', change)
69312             .on('blur', change);
69313     }
69314
69315
69316     function change() {
69317         var left = utilGetSetValue(select('.preset-input-cyclewayleft')),
69318             right = utilGetSetValue(select('.preset-input-cyclewayright')),
69319             tag = {};
69320
69321         if (left === 'none' || left === '') { left = undefined; }
69322         if (right === 'none' || right === '') { right = undefined; }
69323
69324         // Always set both left and right as changing one can affect the other
69325         tag = {
69326             cycleway: undefined,
69327             'cycleway:left': left,
69328             'cycleway:right': right
69329         };
69330
69331         // If the left and right tags match, use the cycleway tag to tag both
69332         // sides the same way
69333         if (left === right) {
69334             tag = {
69335                 cycleway: left,
69336                 'cycleway:left': undefined,
69337                 'cycleway:right': undefined
69338             };
69339         }
69340
69341         dispatch$$1.call('change', this, tag);
69342     }
69343
69344
69345     cycleway.options = function() {
69346         return keys(field.strings.options).map(function(option) {
69347             return {
69348                 title: field.t('options.' + option + '.description'),
69349                 value: option
69350             };
69351         });
69352     };
69353
69354
69355     cycleway.tags = function(tags) {
69356         utilGetSetValue(items.selectAll('.preset-input-cycleway'), function(d) {
69357                 // If cycleway is set, always return that
69358                 if (tags.cycleway) {
69359                     return tags.cycleway;
69360                 }
69361                 return tags[d] || '';
69362             })
69363             .attr('placeholder', field.placeholder());
69364     };
69365
69366
69367     cycleway.focus = function() {
69368         items.selectAll('.preset-input-cycleway')
69369             .node().focus();
69370     };
69371
69372
69373     return utilRebind(cycleway, dispatch$$1, 'on');
69374 }
69375
69376 function uiFieldLanes(field, context) {
69377     var dispatch$$1 = dispatch('change'),
69378         LANE_WIDTH = 40,
69379         LANE_HEIGHT = 200,
69380         wayID,
69381         lanesData;
69382
69383     function lanes(selection$$1) {
69384         lanesData = context.entity(wayID).lanes();
69385
69386         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
69387             selection$$1.call(lanes.off);
69388             return;
69389         }
69390
69391         var wrap = selection$$1.selectAll('.preset-input-wrap')
69392             .data([0]);
69393
69394         wrap = wrap.enter()
69395             .append('div')
69396             .attr('class', 'preset-input-wrap')
69397             .merge(wrap);
69398
69399         var surface =  wrap.selectAll('.surface')
69400             .data([0]);
69401
69402         var d = utilGetDimensions(wrap);
69403         var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
69404
69405         surface = surface.enter()
69406             .append('svg')
69407             .attr('width', d[0])
69408             .attr('height', 300)
69409             .attr('class', 'surface')
69410             .merge(surface);
69411
69412
69413         var lanesSelection = surface.selectAll('.lanes')
69414             .data([0]);
69415
69416         lanesSelection = lanesSelection.enter()
69417             .append('g')
69418             .attr('class', 'lanes')
69419             .merge(lanesSelection);
69420
69421         lanesSelection
69422             .attr('transform', function () {
69423                 return 'translate(' + (freeSpace / 2) + ', 0)';
69424             });
69425
69426
69427         var lane = lanesSelection.selectAll('.lane')
69428            .data(lanesData.lanes);
69429
69430         lane.exit()
69431             .remove();
69432
69433         var enter = lane.enter()
69434             .append('g')
69435             .attr('class', 'lane');
69436
69437         enter
69438             .append('g')
69439             .append('rect')
69440             .attr('y', 50)
69441             .attr('width', LANE_WIDTH)
69442             .attr('height', LANE_HEIGHT);
69443
69444         enter
69445             .append('g')
69446             .attr('class', 'forward')
69447             .append('text')
69448             .attr('y', 40)
69449             .attr('x', 14)
69450             .text('▲');
69451
69452         enter
69453             .append('g')
69454             .attr('class', 'bothways')
69455             .append('text')
69456             .attr('y', 40)
69457             .attr('x', 14)
69458             .text('▲▼');
69459
69460         enter
69461             .append('g')
69462             .attr('class', 'backward')
69463             .append('text')
69464             .attr('y', 40)
69465             .attr('x', 14)
69466             .text('▼');
69467
69468
69469         lane = lane
69470             .merge(enter);
69471
69472         lane
69473             .attr('transform', function(d) {
69474                 return 'translate(' + (LANE_WIDTH * d.index * 1.5) + ', 0)';
69475             });
69476
69477         lane.select('.forward')
69478             .style('visibility', function(d) {
69479                 return d.direction === 'forward' ? 'visible' : 'hidden';
69480             });
69481
69482         lane.select('.bothways')
69483             .style('visibility', function(d) {
69484                 return d.direction === 'bothways' ? 'visible' : 'hidden';
69485             });
69486
69487         lane.select('.backward')
69488             .style('visibility', function(d) {
69489                 return d.direction === 'backward' ? 'visible' : 'hidden';
69490             });
69491     }
69492
69493
69494     lanes.entity = function(_) {
69495         if (!wayID || wayID !== _.id) {
69496             wayID = _.id;
69497         }
69498     };
69499
69500     lanes.tags = function() {};
69501     lanes.focus = function() {};
69502     lanes.off = function() {};
69503
69504     return utilRebind(lanes, dispatch$$1, 'on');
69505 }
69506
69507 function uiFieldLocalized(field, context) {
69508     var dispatch$$1 = dispatch('change', 'input'),
69509         wikipedia = services.wikipedia,
69510         input = select(null),
69511         localizedInputs = select(null),
69512         wikiTitles,
69513         entity;
69514
69515
69516     function localized(selection$$1) {
69517         input = selection$$1.selectAll('.localized-main')
69518             .data([0]);
69519
69520         input = input.enter()
69521             .append('input')
69522             .attr('type', 'text')
69523             .attr('id', 'preset-input-' + field.id)
69524             .attr('class', 'localized-main')
69525             .attr('placeholder', field.placeholder())
69526             .call(utilNoAuto)
69527             .merge(input);
69528
69529         if (field.id === 'name') {
69530             var preset = context.presets().match(entity, context.graph());
69531             input
69532                 .call(d3combobox()
69533                     .container(context.container())
69534                     .fetcher(utilSuggestNames(preset, dataSuggestions))
69535                 );
69536         }
69537
69538         input
69539             .on('input', change(true))
69540             .on('blur', change())
69541             .on('change', change());
69542
69543
69544         var translateButton = selection$$1.selectAll('.localized-add')
69545             .data([0]);
69546
69547         translateButton = translateButton.enter()
69548             .append('button')
69549             .attr('class', 'button-input-action localized-add minor')
69550             .attr('tabindex', -1)
69551             .call(svgIcon('#icon-plus'))
69552             .call(tooltip()
69553                 .title(t('translate.translate'))
69554                 .placement('left'))
69555             .merge(translateButton);
69556
69557         translateButton
69558             .on('click', addNew);
69559
69560
69561         localizedInputs = selection$$1.selectAll('.localized-wrap')
69562             .data([0]);
69563
69564         localizedInputs = localizedInputs.enter().append('div')
69565             .attr('class', 'localized-wrap')
69566             .merge(localizedInputs);
69567     }
69568
69569
69570     function addNew() {
69571         event.preventDefault();
69572         var data$$1 = localizedInputs.selectAll('div.entry').data();
69573         var defaultLang = utilDetect().locale.toLowerCase().split('-')[0];
69574         var langExists = lodash.find(data$$1, function(datum) { return datum.lang === defaultLang;});
69575         var isLangEn = defaultLang.indexOf('en') > -1;
69576         if (isLangEn || langExists) {
69577             defaultLang = '';
69578         }
69579         data$$1.push({ lang: defaultLang, value: '' });
69580         localizedInputs.call(render, data$$1);
69581     }
69582
69583
69584     function change(onInput) {
69585         return function() {
69586             var t$$1 = {};
69587             t$$1[field.key] = utilGetSetValue(select(this)) || undefined;
69588             dispatch$$1.call('change', this, t$$1, onInput);
69589         };
69590     }
69591
69592
69593     function key(lang) {
69594         return field.key + ':' + lang;
69595     }
69596
69597
69598     function changeLang(d) {
69599         var lang = utilGetSetValue(select(this)),
69600             t$$1 = {},
69601             language = lodash.find(dataWikipedia, function(d) {
69602                 return d[0].toLowerCase() === lang.toLowerCase() ||
69603                     d[1].toLowerCase() === lang.toLowerCase();
69604             });
69605
69606         if (language) lang = language[2];
69607
69608         if (d.lang && d.lang !== lang) {
69609             t$$1[key(d.lang)] = undefined;
69610         }
69611
69612         var value = utilGetSetValue(select(this.parentNode)
69613             .selectAll('.localized-value'));
69614
69615         if (lang && value) {
69616             t$$1[key(lang)] = value;
69617         } else if (lang && wikiTitles && wikiTitles[d.lang]) {
69618             t$$1[key(lang)] = wikiTitles[d.lang];
69619         }
69620
69621         d.lang = lang;
69622         dispatch$$1.call('change', this, t$$1);
69623     }
69624
69625
69626     function changeValue(d) {
69627         if (!d.lang) return;
69628         var t$$1 = {};
69629         t$$1[key(d.lang)] = utilGetSetValue(select(this)) || undefined;
69630         dispatch$$1.call('change', this, t$$1);
69631     }
69632
69633
69634     function fetcher(value, cb) {
69635         var v = value.toLowerCase();
69636
69637         cb(dataWikipedia.filter(function(d) {
69638             return d[0].toLowerCase().indexOf(v) >= 0 ||
69639             d[1].toLowerCase().indexOf(v) >= 0 ||
69640             d[2].toLowerCase().indexOf(v) >= 0;
69641         }).map(function(d) {
69642             return { value: d[1] };
69643         }));
69644     }
69645
69646
69647     function render(selection$$1, data$$1) {
69648         var wraps = selection$$1.selectAll('div.entry').
69649             data(data$$1, function(d) { return d.lang; });
69650
69651         wraps.exit()
69652             .transition()
69653             .duration(200)
69654             .style('max-height','0px')
69655             .style('opacity', '0')
69656             .style('top','-10px')
69657             .remove();
69658
69659         var innerWrap = wraps.enter()
69660             .insert('div', ':first-child');
69661
69662         innerWrap.attr('class', 'entry')
69663             .each(function() {
69664                 var wrap = select(this);
69665                 var langcombo = d3combobox()
69666                     .container(context.container())
69667                     .fetcher(fetcher)
69668                     .minItems(0);
69669
69670                 var label = wrap
69671                     .append('label')
69672                     .attr('class','form-label')
69673                     .text(t('translate.localized_translation_label'))
69674                     .attr('for','localized-lang');
69675
69676                 label
69677                     .append('button')
69678                     .attr('class', 'minor remove')
69679                     .on('click', function(d){
69680                         event.preventDefault();
69681                         var t$$1 = {};
69682                         t$$1[key(d.lang)] = undefined;
69683                         dispatch$$1.call('change', this, t$$1);
69684                         select(this.parentNode.parentNode)
69685                             .style('top','0')
69686                             .style('max-height','240px')
69687                             .transition()
69688                             .style('opacity', '0')
69689                             .style('max-height','0px')
69690                             .remove();
69691                     })
69692                     .call(svgIcon('#operation-delete'));
69693
69694                 wrap
69695                     .append('input')
69696                     .attr('class', 'localized-lang')
69697                     .attr('type', 'text')
69698                     .attr('placeholder',t('translate.localized_translation_language'))
69699                     .on('blur', changeLang)
69700                     .on('change', changeLang)
69701                     .call(langcombo);
69702
69703                 wrap
69704                     .append('input')
69705                     .on('blur', changeValue)
69706                     .on('change', changeValue)
69707                     .attr('type', 'text')
69708                     .attr('placeholder', t('translate.localized_translation_name'))
69709                     .attr('class', 'localized-value');
69710             });
69711
69712         innerWrap
69713             .style('margin-top', '0px')
69714             .style('max-height', '0px')
69715             .style('opacity', '0')
69716             .transition()
69717             .duration(200)
69718             .style('margin-top', '10px')
69719             .style('max-height', '240px')
69720             .style('opacity', '1')
69721             .on('end', function() {
69722                 select(this)
69723                     .style('max-height', '')
69724                     .style('overflow', 'visible');
69725             });
69726
69727
69728         var entry = selection$$1.selectAll('.entry');
69729
69730         utilGetSetValue(entry.select('.localized-lang'), function(d) {
69731                 var lang = lodash.find(dataWikipedia, function(lang) { return lang[2] === d.lang; });
69732                 return lang ? lang[1] : d.lang;
69733             });
69734
69735         utilGetSetValue(entry.select('.localized-value'),
69736             function(d) { return d.value; });
69737     }
69738
69739
69740     localized.tags = function(tags) {
69741         // Fetch translations from wikipedia
69742         if (tags.wikipedia && !wikiTitles) {
69743             wikiTitles = {};
69744             var wm = tags.wikipedia.match(/([^:]+):(.+)/);
69745             if (wm && wm[0] && wm[1]) {
69746                 wikipedia.translations(wm[1], wm[2], function(d) {
69747                     wikiTitles = d;
69748                 });
69749             }
69750         }
69751
69752         utilGetSetValue(input, tags[field.key] || '');
69753
69754         var postfixed = [], k, m;
69755         for (k in tags) {
69756             m = k.match(/^(.*):([a-zA-Z_-]+)$/);
69757             if (m && m[1] === field.key && m[2]) {
69758                 postfixed.push({ lang: m[2], value: tags[k] });
69759             }
69760         }
69761
69762         localizedInputs.call(render, postfixed.reverse());
69763     };
69764
69765
69766     localized.focus = function() {
69767         input.node().focus();
69768     };
69769
69770
69771     localized.entity = function(_) {
69772         if (!arguments.length) return entity;
69773         entity = _;
69774         return localized;
69775     };
69776
69777     return utilRebind(localized, dispatch$$1, 'on');
69778 }
69779
69780 function uiFieldMaxspeed(field, context) {
69781     var dispatch$$1 = dispatch('change'),
69782         entity,
69783         isImperial,
69784         unitInput = select(null),
69785         input = select(null),
69786         combobox;
69787
69788     var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
69789         imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
69790
69791
69792     function maxspeed(selection$$1) {
69793         combobox = d3combobox()
69794             .container(context.container());
69795
69796         var unitCombobox = d3combobox()
69797             .container(context.container())
69798             .data(['km/h', 'mph'].map(comboValues));
69799
69800         input = selection$$1.selectAll('#preset-input-' + field.id)
69801             .data([0]);
69802
69803         input = input.enter()
69804             .append('input')
69805             .attr('type', 'text')
69806             .attr('id', 'preset-input-' + field.id)
69807             .attr('placeholder', field.placeholder())
69808             .call(utilNoAuto)
69809             .call(combobox)
69810             .merge(input);
69811
69812         input
69813             .on('change', change)
69814             .on('blur', change);
69815
69816         var childNodes = context.graph().childNodes(context.entity(entity.id)),
69817             loc = childNodes[~~(childNodes.length/2)].loc;
69818
69819         isImperial = lodash.some(dataImperial.features, function(f) {
69820             return lodash.some(f.geometry.coordinates, function(d) {
69821                 return geoPointInPolygon(loc, d);
69822             });
69823         });
69824
69825         unitInput = selection$$1.selectAll('input.maxspeed-unit')
69826             .data([0]);
69827
69828         unitInput = unitInput.enter()
69829             .append('input')
69830             .attr('type', 'text')
69831             .attr('class', 'maxspeed-unit')
69832             .call(unitCombobox)
69833             .merge(unitInput);
69834
69835         unitInput
69836             .on('blur', changeUnits)
69837             .on('change', changeUnits);
69838
69839
69840         function changeUnits() {
69841             isImperial = utilGetSetValue(unitInput) === 'mph';
69842             utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
69843             setSuggestions();
69844             change();
69845         }
69846     }
69847
69848
69849     function setSuggestions() {
69850         combobox.data((isImperial ? imperialValues : metricValues).map(comboValues));
69851         utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
69852     }
69853
69854
69855     function comboValues(d) {
69856         return {
69857             value: d.toString(),
69858             title: d.toString()
69859         };
69860     }
69861
69862
69863     function change() {
69864         var tag = {},
69865             value = utilGetSetValue(input);
69866
69867         if (!value) {
69868             tag[field.key] = undefined;
69869         } else if (isNaN(value) || !isImperial) {
69870             tag[field.key] = value;
69871         } else {
69872             tag[field.key] = value + ' mph';
69873         }
69874
69875         dispatch$$1.call('change', this, tag);
69876     }
69877
69878
69879     maxspeed.tags = function(tags) {
69880         var value = tags[field.key];
69881
69882         if (value && value.indexOf('mph') >= 0) {
69883             value = parseInt(value, 10);
69884             isImperial = true;
69885         } else if (value) {
69886             isImperial = false;
69887         }
69888
69889         setSuggestions();
69890         utilGetSetValue(input, value || '');
69891     };
69892
69893
69894     maxspeed.focus = function() {
69895         input.node().focus();
69896     };
69897
69898
69899     maxspeed.entity = function(_) {
69900         entity = _;
69901     };
69902
69903
69904     return utilRebind(maxspeed, dispatch$$1, 'on');
69905 }
69906
69907 function uiFieldRadio(field, context) {
69908     var dispatch$$1 = dispatch('change'),
69909         taginfo = services.taginfo,
69910         placeholder = select(null),
69911         wrap = select(null),
69912         labels = select(null),
69913         radios = select(null),
69914         typeInput = select(null),
69915         layerInput = select(null),
69916         oldType = {},
69917         entity;
69918
69919
69920     function selectedKey() {
69921         var selector$$1 = '.form-field-structure .toggle-list label.active input',
69922             node = selectAll(selector$$1);
69923         return !node.empty() && node.datum();
69924     }
69925
69926     // returns the tag value for a display value
69927     function tagValue(dispVal) {
69928         dispVal = snake(clean(dispVal || ''));
69929         return dispVal.toLowerCase() || 'yes';
69930     }
69931
69932     // returns the display value for a tag value
69933     function displayValue(tagVal) {
69934         tagVal = tagVal || '';
69935         return tagVal.toLowerCase() === 'yes' ? '' : unsnake(tagVal);
69936     }
69937
69938     function snake(s) {
69939         return s.replace(/\s+/g, '_');
69940     }
69941
69942     function unsnake(s) {
69943         return s.replace(/_+/g, ' ');
69944     }
69945
69946     function clean(s) {
69947         return s.split(';')
69948             .map(function(s) { return s.trim(); })
69949             .join(';');
69950     }
69951
69952
69953     function radio(selection$$1) {
69954         selection$$1.classed('preset-radio', true);
69955
69956         wrap = selection$$1.selectAll('.preset-input-wrap')
69957             .data([0]);
69958
69959         var enter = wrap.enter()
69960             .append('div')
69961             .attr('class', 'preset-input-wrap toggle-list');
69962
69963         enter
69964             .append('span')
69965             .attr('class', 'placeholder');
69966
69967         wrap = wrap
69968             .merge(enter);
69969
69970
69971         placeholder = wrap.selectAll('.placeholder');
69972
69973         labels = wrap.selectAll('label')
69974             .data(field.options || field.keys);
69975
69976         enter = labels.enter()
69977             .append('label');
69978
69979         enter
69980             .append('input')
69981             .attr('type', 'radio')
69982             .attr('name', field.id)
69983             .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
69984             .attr('checked', false);
69985
69986         enter
69987             .append('span')
69988             .text(function(d) { return field.t('options.' + d, { 'default': d }); });
69989
69990         labels = labels
69991             .merge(enter);
69992
69993         radios = labels.selectAll('input')
69994             .on('change', changeRadio);
69995     }
69996
69997
69998     function structureExtras(selection$$1) {
69999         var selected = selectedKey();
70000
70001         var extrasWrap = selection$$1.selectAll('.structure-extras-wrap')
70002                 .data(selected ? [0] : []);
70003
70004         extrasWrap.exit()
70005             .remove();
70006
70007         extrasWrap = extrasWrap.enter()
70008             .append('div')
70009             .attr('class', 'structure-extras-wrap')
70010             .merge(extrasWrap);
70011
70012         var list = extrasWrap.selectAll('ul')
70013             .data([0]);
70014
70015         list = list.enter()
70016             .append('ul')
70017             .merge(list);
70018
70019
70020         // Type
70021         var typeItem = list.selectAll('.structure-type-item')
70022             .data([0]);
70023
70024         var typeEnter = typeItem.enter()
70025             .append('li')
70026             .attr('class', 'cf structure-type-item');
70027
70028         typeEnter
70029             .append('span')
70030             .attr('class', 'col6 label structure-label-type')
70031             .attr('for', 'structure-input-type')
70032             .text(t('inspector.radio.structure.type'));
70033
70034         typeEnter
70035             .append('div')
70036             .attr('class', 'col6 structure-input-type-wrap')
70037             .append('input')
70038             .attr('type', 'text')
70039             .attr('class', 'structure-input-type')
70040             .attr('placeholder', t('inspector.radio.structure.default'))
70041             .call(utilNoAuto);
70042
70043         typeItem = typeItem
70044             .merge(typeEnter);
70045
70046         typeInput = typeItem.selectAll('.structure-input-type');
70047
70048         if (taginfo) {
70049             typeInput
70050                 .call(d3combobox()
70051                     .container(context.container())
70052                     .fetcher(typeFetcher)
70053                 );
70054         }
70055
70056         typeInput
70057             .on('change', changeType)
70058             .on('blur', changeType);
70059
70060
70061         // Layer
70062         var showLayer = (selected === 'bridge' || selected === 'tunnel');
70063
70064         var layerItem = list.selectAll('.structure-layer-item')
70065             .data(showLayer ? [0] : []);
70066
70067         layerItem.exit()
70068             .remove();
70069
70070         var layerEnter = layerItem.enter()
70071             .append('li')
70072             .attr('class', 'cf structure-layer-item');
70073
70074         layerEnter
70075             .append('span')
70076             .attr('class', 'col6 label structure-label-layer')
70077             .attr('for', 'structure-input-layer')
70078             .text(t('inspector.radio.structure.layer'));
70079
70080         layerEnter
70081             .append('div')
70082             .attr('class', 'col6 structure-input-layer-wrap')
70083             .append('input')
70084             .attr('type', 'text')
70085             .attr('class', 'structure-input-layer')
70086             .attr('placeholder', '0')
70087             .call(utilNoAuto);
70088
70089         var spin = layerEnter
70090             .append('div')
70091             .attr('class', 'spin-control');
70092
70093         spin
70094             .append('button')
70095             .datum(-1)
70096             .attr('class', 'decrement')
70097             .attr('tabindex', -1);
70098
70099         spin
70100             .append('button')
70101             .datum(1)
70102             .attr('class', 'increment')
70103             .attr('tabindex', -1);
70104
70105         layerItem = layerItem
70106             .merge(layerEnter);
70107
70108         layerInput = layerItem.selectAll('.structure-input-layer')
70109             .on('change', changeLayer)
70110             .on('blur', changeLayer);
70111
70112         layerItem.selectAll('button')
70113             .on('click', function(d) {
70114                 event.preventDefault();
70115                 var num = parseInt(layerInput.node().value || 0, 10);
70116                 if (!isNaN(num)) layerInput.node().value = num + d;
70117                 changeLayer();
70118             });
70119
70120     }
70121
70122
70123     function typeFetcher(q, callback) {
70124         taginfo.values({
70125             debounce: true,
70126             key: selectedKey(),
70127             query: q
70128         }, function(err, data) {
70129             if (err) return;
70130             var comboData = data.map(function(d) {
70131                 return {
70132                     key: d.value,
70133                     value: unsnake(d.value),
70134                     title: d.title
70135                 };
70136             });
70137             if (callback) callback(comboData);
70138         });
70139     }
70140
70141
70142     function changeType() {
70143         var key = selectedKey(),
70144             t$$1 = {};
70145
70146         if (!key) return;
70147         var val = tagValue(utilGetSetValue(typeInput));
70148         t$$1[key] = val;
70149         if (val !== 'no') oldType[key] = val;
70150         dispatch$$1.call('change', this, t$$1);
70151     }
70152
70153
70154     function changeLayer() {
70155         // note: don't use utilGetSetValue here because we want 0 to be falsy.
70156         var t$$1 = { layer: layerInput.node().value || undefined };
70157         dispatch$$1.call('change', this, t$$1);
70158     }
70159
70160
70161     function changeRadio() {
70162         var t$$1 = {},
70163             activeKey;
70164
70165         if (field.key) {
70166             t$$1[field.key] = undefined;
70167         }
70168
70169         radios.each(function(d) {
70170             var active$$1 = select(this).property('checked');
70171             if (active$$1) activeKey = d;
70172
70173             if (field.key) {
70174                 if (active$$1) t$$1[field.key] = d;
70175             } else {
70176                 var val = oldType[activeKey] || 'yes';
70177                 t$$1[d] = active$$1 ? val : undefined;
70178             }
70179         });
70180
70181         if (field.type === 'structureRadio') {
70182             if (activeKey === 'bridge') {
70183                 t$$1.layer = '1';
70184             } else if (activeKey === 'tunnel') {
70185                 t$$1.layer = '-1';
70186             } else {
70187                 t$$1.layer = undefined;
70188             }
70189         }
70190
70191         dispatch$$1.call('change', this, t$$1);
70192     }
70193
70194
70195     radio.tags = function(tags) {
70196         function checked(d) {
70197             if (field.key) {
70198                 return tags[field.key] === d;
70199             } else {
70200                 return !!(tags[d] && tags[d].toLowerCase() !== 'no');
70201             }
70202         }
70203
70204         labels.classed('active', checked);
70205         radios.property('checked', checked);
70206
70207         var selection$$1 = radios.filter(function() { return this.checked; });
70208         var typeVal = '';
70209
70210         if (selection$$1.empty()) {
70211             placeholder.text(t('inspector.none'));
70212         } else {
70213             placeholder.text(selection$$1.attr('value'));
70214             typeVal = oldType[selection$$1.datum()] = tags[selection$$1.datum()];
70215         }
70216
70217         if (field.type === 'structureRadio') {
70218             wrap.call(structureExtras);
70219             utilGetSetValue(typeInput, displayValue(typeVal) || '');
70220             utilGetSetValue(layerInput, tags.layer || '');
70221         }
70222     };
70223
70224
70225     radio.focus = function() {
70226         radios.node().focus();
70227     };
70228
70229
70230     radio.entity = function(_) {
70231         if (!arguments.length) return entity;
70232         entity = _;
70233         oldType = {};
70234         return radio;
70235     };
70236
70237
70238     return utilRebind(radio, dispatch$$1, 'on');
70239 }
70240
70241 function uiFieldRestrictions(field, context) {
70242     var dispatch$$1 = dispatch('change'),
70243         breathe = behaviorBreathe(context),
70244         hover = behaviorHover(context),
70245         initialized = false,
70246         vertexID,
70247         fromNodeID;
70248
70249
70250     function restrictions(selection$$1) {
70251         // if form field is hidden or has detached from dom, clean up.
70252         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
70253             selection$$1.call(restrictions.off);
70254             return;
70255         }
70256
70257         var wrap = selection$$1.selectAll('.preset-input-wrap')
70258             .data([0]);
70259
70260         var enter = wrap.enter()
70261             .append('div')
70262             .attr('class', 'preset-input-wrap');
70263
70264         enter
70265             .append('div')
70266             .attr('class', 'restriction-help');
70267
70268
70269         var intersection = osmIntersection(context.graph(), vertexID),
70270             graph = intersection.graph,
70271             vertex = graph.entity(vertexID),
70272             filter = utilFunctor(true),
70273             extent$$1 = geoExtent$$1(),
70274             projection$$1 = geoRawMercator();
70275
70276         var d = utilGetDimensions(wrap.merge(enter)),
70277             c = [d[0] / 2, d[1] / 2],
70278             z = 24;
70279
70280         projection$$1
70281             .scale(256 * Math.pow(2, z) / (2 * Math.PI));
70282
70283         var s = projection$$1(vertex.loc);
70284
70285         projection$$1
70286             .translate([c[0] - s[0], c[1] - s[1]])
70287             .clipExtent([[0, 0], d]);
70288
70289         var drawLayers = svgLayers(projection$$1, context).only('osm').dimensions(d),
70290             drawVertices = svgVertices$$1(projection$$1, context),
70291             drawLines = svgLines$$1(projection$$1, context),
70292             drawTurns = svgTurns(projection$$1, context);
70293
70294         enter
70295             .call(drawLayers);
70296
70297         wrap = wrap
70298             .merge(enter);
70299
70300         var surface = wrap.selectAll('.surface');
70301
70302         if (!enter.empty()) {
70303             initialized = true;
70304             surface
70305                 .call(breathe)
70306                 .call(hover);
70307         }
70308
70309         surface
70310             .call(utilSetDimensions, d)
70311             .call(drawVertices, graph, [vertex], filter, extent$$1, z)
70312             .call(drawLines, graph, intersection.ways, filter)
70313             .call(drawTurns, graph, intersection.turns(fromNodeID));
70314
70315         surface
70316             .on('click.restrictions', click)
70317             .on('mouseover.restrictions', mouseover)
70318             .on('mouseout.restrictions', mouseout);
70319
70320         surface
70321             .selectAll('.selected')
70322             .classed('selected', false);
70323
70324         if (fromNodeID) {
70325             surface
70326                 .selectAll('.' + intersection.highways[fromNodeID].id)
70327                 .classed('selected', true);
70328         }
70329
70330         mouseout();
70331
70332         context.history()
70333             .on('change.restrictions', render);
70334
70335         select(window)
70336             .on('resize.restrictions', function() {
70337                 utilSetDimensions(wrap, null);
70338                 render();
70339             });
70340
70341
70342         function click() {
70343             surface
70344                 .call(breathe.off)
70345                 .call(breathe);
70346
70347             var datum = event.target.__data__;
70348             if (datum instanceof osmEntity$$1) {
70349                 fromNodeID = intersection.adjacentNodeId(datum.id);
70350                 render();
70351             } else if (datum instanceof osmTurn) {
70352                 if (datum.restriction) {
70353                     context.perform(
70354                         actionUnrestrictTurn(datum, projection$$1),
70355                         t('operations.restriction.annotation.delete')
70356                     );
70357                 } else {
70358                     context.perform(
70359                         actionRestrictTurn(datum, projection$$1),
70360                         t('operations.restriction.annotation.create')
70361                     );
70362                 }
70363             }
70364         }
70365
70366
70367         function mouseover() {
70368             var datum = event.target.__data__;
70369             if (datum instanceof osmTurn) {
70370                 var graph = context.graph(),
70371                     presets = context.presets(),
70372                     preset;
70373
70374                 if (datum.restriction) {
70375                     preset = presets.match(graph.entity(datum.restriction), graph);
70376                 } else {
70377                     preset = presets.item('type/restriction/' +
70378                         osmInferRestriction(
70379                             graph,
70380                             datum.from,
70381                             datum.via,
70382                             datum.to,
70383                             projection$$1
70384                         )
70385                     );
70386                 }
70387
70388                 wrap.selectAll('.restriction-help')
70389                     .text(t('operations.restriction.help.' +
70390                         (datum.restriction ? 'toggle_off' : 'toggle_on'),
70391                         { restriction: preset.name() })
70392                     );
70393             }
70394         }
70395
70396
70397         function mouseout() {
70398             wrap.selectAll('.restriction-help')
70399                 .text(t('operations.restriction.help.' +
70400                     (fromNodeID ? 'toggle' : 'select'))
70401                 );
70402         }
70403
70404
70405         function render() {
70406             if (context.hasEntity(vertexID)) {
70407                 restrictions(selection$$1);
70408             }
70409         }
70410     }
70411
70412
70413     restrictions.entity = function(_) {
70414         if (!vertexID || vertexID !== _.id) {
70415             fromNodeID = null;
70416             vertexID = _.id;
70417         }
70418     };
70419
70420
70421     restrictions.tags = function() {};
70422     restrictions.focus = function() {};
70423
70424
70425     restrictions.off = function(selection$$1) {
70426         if (!initialized) return;
70427
70428         selection$$1.selectAll('.surface')
70429             .call(hover.off)
70430             .call(breathe.off)
70431             .on('click.restrictions', null)
70432             .on('mouseover.restrictions', null)
70433             .on('mouseout.restrictions', null);
70434
70435         context.history()
70436             .on('change.restrictions', null);
70437
70438         select(window)
70439             .on('resize.restrictions', null);
70440     };
70441
70442
70443     return utilRebind(restrictions, dispatch$$1, 'on');
70444 }
70445
70446 function uiFieldTextarea(field) {
70447     var dispatch$$1 = dispatch('change'),
70448         input = select(null);
70449
70450
70451     function textarea(selection$$1) {
70452         input = selection$$1.selectAll('textarea')
70453             .data([0]);
70454
70455         input = input.enter()
70456             .append('textarea')
70457             .attr('id', 'preset-input-' + field.id)
70458             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
70459             .attr('maxlength', 255)
70460             .call(utilNoAuto)
70461             .on('input', change(true))
70462             .on('blur', change())
70463             .on('change', change())
70464             .merge(input);
70465     }
70466
70467
70468     function change(onInput) {
70469         return function() {
70470             var t$$1 = {};
70471             t$$1[field.key] = utilGetSetValue(input) || undefined;
70472             dispatch$$1.call('change', this, t$$1, onInput);
70473         };
70474     }
70475
70476
70477     textarea.tags = function(tags) {
70478         utilGetSetValue(input, tags[field.key] || '');
70479     };
70480
70481
70482     textarea.focus = function() {
70483         input.node().focus();
70484     };
70485
70486
70487     return utilRebind(textarea, dispatch$$1, 'on');
70488 }
70489
70490 function uiFieldWikipedia(field, context) {
70491     var dispatch$$1 = dispatch('change'),
70492         wikipedia = services.wikipedia,
70493         wikidata = services.wikidata,
70494         link$$1 = select(null),
70495         lang = select(null),
70496         title = select(null),
70497         wikiURL = '',
70498         entity;
70499
70500
70501     function wiki(selection$$1) {
70502         var langcombo = d3combobox()
70503             .container(context.container())
70504             .fetcher(function(value, cb) {
70505                 var v = value.toLowerCase();
70506
70507                 cb(dataWikipedia.filter(function(d) {
70508                     return d[0].toLowerCase().indexOf(v) >= 0 ||
70509                         d[1].toLowerCase().indexOf(v) >= 0 ||
70510                         d[2].toLowerCase().indexOf(v) >= 0;
70511                 }).map(function(d) {
70512                     return { value: d[1] };
70513                 }));
70514             });
70515
70516         var titlecombo = d3combobox()
70517             .container(context.container())
70518             .fetcher(function(value, cb) {
70519                 if (!value) {
70520                     value = context.entity(entity.id).tags.name || '';
70521                 }
70522
70523                 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
70524                 searchfn(language()[2], value, function(query, data$$1) {
70525                     cb(data$$1.map(function(d) {
70526                         return { value: d };
70527                     }));
70528                 });
70529             });
70530
70531
70532         lang = selection$$1.selectAll('input.wiki-lang')
70533             .data([0]);
70534
70535         lang = lang.enter()
70536             .append('input')
70537             .attr('type', 'text')
70538             .attr('class', 'wiki-lang')
70539             .attr('placeholder', t('translate.localized_translation_language'))
70540             .call(utilNoAuto)
70541             .merge(lang);
70542
70543         utilGetSetValue(lang, language()[1]);
70544
70545         lang
70546             .call(langcombo)
70547             .on('blur', changeLang)
70548             .on('change', changeLang);
70549
70550
70551         title = selection$$1.selectAll('input.wiki-title')
70552             .data([0]);
70553
70554         title = title.enter()
70555             .append('input')
70556             .attr('type', 'text')
70557             .attr('class', 'wiki-title')
70558             .attr('id', 'preset-input-' + field.id)
70559             .call(utilNoAuto)
70560             .merge(title);
70561
70562         title
70563             .call(titlecombo)
70564             .on('blur', blur)
70565             .on('change', change);
70566
70567
70568         link$$1 = selection$$1.selectAll('.wiki-link')
70569             .data([0]);
70570
70571         link$$1 = link$$1.enter()
70572             .append('button')
70573             .attr('class', 'button-input-action wiki-link minor')
70574             .attr('tabindex', -1)
70575             .call(svgIcon('#icon-out-link'))
70576             .merge(link$$1);
70577
70578         link$$1
70579             .on('click', function() {
70580                 event.preventDefault();
70581                 if (wikiURL) window.open(wikiURL, '_blank');
70582             });
70583     }
70584
70585
70586     function language() {
70587         var value = utilGetSetValue(lang).toLowerCase();
70588         var locale = utilDetect().locale.toLowerCase();
70589         var localeLanguage;
70590         return lodash.find(dataWikipedia, function(d) {
70591             if (d[2] === locale) localeLanguage = d;
70592             return d[0].toLowerCase() === value ||
70593                 d[1].toLowerCase() === value ||
70594                 d[2] === value;
70595         }) || localeLanguage || ['English', 'English', 'en'];
70596     }
70597
70598
70599     function changeLang() {
70600         utilGetSetValue(lang, language()[1]);
70601         change(true);
70602     }
70603
70604
70605     function blur() {
70606         change(true);
70607     }
70608
70609
70610     function change(skipWikidata) {
70611         var value = utilGetSetValue(title),
70612             m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
70613             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
70614             syncTags = {};
70615
70616         if (l) {
70617             // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
70618             value = decodeURIComponent(m[2]).replace(/_/g, ' ');
70619             if (m[3]) {
70620                 var anchor;
70621                 try {
70622                     // Best-effort `anchordecode:` implementation
70623                     anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
70624                 } catch (e) {
70625                     anchor = decodeURIComponent(m[3]);
70626                 }
70627                 value += '#' + anchor.replace(/_/g, ' ');
70628             }
70629             value = value.slice(0, 1).toUpperCase() + value.slice(1);
70630             utilGetSetValue(lang, l[1]);
70631             utilGetSetValue(title, value);
70632         }
70633
70634         if (value) {
70635             syncTags.wikipedia = language()[2] + ':' + value;
70636         } else {
70637             syncTags.wikipedia = undefined;
70638             syncTags.wikidata = undefined;
70639         }
70640
70641         dispatch$$1.call('change', this, syncTags);
70642
70643
70644         if (skipWikidata || !value || !language()[2]) return;
70645
70646         // attempt asynchronous update of wikidata tag..
70647         var initGraph = context.graph(),
70648             initEntityId = entity.id;
70649
70650         wikidata.itemsByTitle(language()[2], value, function(title, data$$1) {
70651             // If graph has changed, we can't apply this update.
70652             if (context.graph() !== initGraph) return;
70653
70654             if (!data$$1 || !Object.keys(data$$1).length) return;
70655
70656             var qids = Object.keys(data$$1);
70657             var value = qids && lodash.find(qids, function(id) { return id.match(/^Q\d+$/); });
70658             var currTags = lodash.clone(context.entity(initEntityId).tags);
70659
70660             currTags.wikidata = value;
70661
70662             // Coalesce the update of wikidata tag into the previous tag change
70663             context.overwrite(
70664                 actionChangeTags(initEntityId, currTags),
70665                 context.history().undoAnnotation()
70666             );
70667
70668             // do not dispatch.call('change') here, because entity_editor
70669             // changeTags() is not intended to be called asynchronously
70670         });
70671     }
70672
70673
70674     wiki.tags = function(tags) {
70675         var value = tags[field.key] || '',
70676             m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
70677             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
70678             anchor = m && m[3];
70679
70680         // value in correct format
70681         if (l) {
70682             utilGetSetValue(lang, l[1]);
70683             utilGetSetValue(title, m[2] + (anchor ? ('#' + anchor) : ''));
70684             if (anchor) {
70685                 try {
70686                     // Best-effort `anchorencode:` implementation
70687                     anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
70688                 } catch (e) {
70689                     anchor = anchor.replace(/ /g, '_');
70690                 }
70691             }
70692             wikiURL = 'https://' + m[1] + '.wikipedia.org/wiki/' +
70693                 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : '');
70694
70695         // unrecognized value format
70696         } else {
70697             utilGetSetValue(title, value);
70698             if (value && value !== '') {
70699                 utilGetSetValue(lang, '');
70700                 wikiURL = 'https://en.wikipedia.org/wiki/Special:Search?search=' + value;
70701             } else {
70702                 wikiURL = '';
70703             }
70704         }
70705     };
70706
70707
70708     wiki.entity = function(_) {
70709         if (!arguments.length) return entity;
70710         entity = _;
70711         return wiki;
70712     };
70713
70714
70715     wiki.focus = function() {
70716         title.node().focus();
70717     };
70718
70719
70720     return utilRebind(wiki, dispatch$$1, 'on');
70721 }
70722
70723 var uiFields = {
70724     access: uiFieldAccess,
70725     address: uiFieldAddress,
70726     check: uiFieldCheck,
70727     combo: uiFieldCombo,
70728     cycleway: uiFieldCycleway,
70729     defaultCheck: uiFieldCheck,
70730     email: uiFieldText,
70731     lanes: uiFieldLanes,
70732     localized: uiFieldLocalized,
70733     maxspeed: uiFieldMaxspeed,
70734     multiCombo: uiFieldCombo,
70735     networkCombo: uiFieldCombo,
70736     number: uiFieldText,
70737     onewayCheck: uiFieldCheck,
70738     radio: uiFieldRadio,
70739     restrictions: uiFieldRestrictions,
70740     semiCombo: uiFieldCombo,
70741     structureRadio: uiFieldRadio,
70742     tel: uiFieldText,
70743     text: uiFieldText,
70744     textarea: uiFieldTextarea,
70745     typeCombo: uiFieldCombo,
70746     url: uiFieldText,
70747     wikipedia: uiFieldWikipedia
70748 };
70749
70750 function uiPreset(context) {
70751     var dispatch$$1 = dispatch('change'),
70752         state,
70753         fieldsArr,
70754         preset,
70755         tags,
70756         id;
70757
70758
70759     // Field Constructor
70760     function UIField(field, entity, show) {
70761         field = lodash.clone(field);
70762
70763         field.input = uiFields[field.type](field, context)
70764             .on('change', function(t$$1, onInput) {
70765                 dispatch$$1.call('change', field, t$$1, onInput);
70766             });
70767
70768         if (field.input.entity) field.input.entity(entity);
70769
70770         field.keys = field.keys || [field.key];
70771
70772         field.show = show;
70773
70774         field.shown = function() {
70775             return field.id === 'name' || field.show || lodash.some(field.keys, function(key) { return !!tags[key]; });
70776         };
70777
70778         field.modified = function() {
70779             var original = context.graph().base().entities[entity.id];
70780             return lodash.some(field.keys, function(key) {
70781                 return original ? tags[key] !== original.tags[key] : tags[key];
70782             });
70783         };
70784
70785         field.revert = function() {
70786             var original = context.graph().base().entities[entity.id],
70787                 t$$1 = {};
70788             field.keys.forEach(function(key) {
70789                 t$$1[key] = original ? original.tags[key] : undefined;
70790             });
70791             return t$$1;
70792         };
70793
70794         field.present = function() {
70795             return lodash.some(field.keys, function(key) {
70796                 return tags[key];
70797             });
70798         };
70799
70800         field.remove = function() {
70801             var t$$1 = {};
70802             field.keys.forEach(function(key) {
70803                 t$$1[key] = undefined;
70804             });
70805             return t$$1;
70806         };
70807
70808         return field;
70809     }
70810
70811
70812     function fieldKey(field) {
70813         return field.id;
70814     }
70815
70816
70817     function presets(selection$$1) {
70818         selection$$1.call(uiDisclosure()
70819             .title(t('inspector.all_fields'))
70820             .expanded(context.storage('preset_fields.expanded') !== 'false')
70821             .on('toggled', toggled)
70822             .content(content)
70823         );
70824
70825         function toggled(expanded) {
70826             context.storage('preset_fields.expanded', expanded);
70827         }
70828     }
70829
70830
70831     function content(selection$$1) {
70832         if (!fieldsArr) {
70833             var entity = context.entity(id),
70834                 geometry = context.geometry(id),
70835                 presets = context.presets();
70836
70837             fieldsArr = [];
70838
70839             if (presets.field('name')) {
70840                 fieldsArr.push(UIField(presets.field('name'), entity));
70841             }
70842
70843             preset.fields.forEach(function(field) {
70844                 if (field.matchGeometry(geometry)) {
70845                     fieldsArr.push(UIField(field, entity, true));
70846                 }
70847             });
70848
70849             if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) {
70850                 fieldsArr.push(UIField(presets.field('restrictions'), entity, true));
70851             }
70852
70853             presets.universal().forEach(function(field) {
70854                 if (preset.fields.indexOf(field) < 0) {
70855                     fieldsArr.push(UIField(field, entity));
70856                 }
70857             });
70858         }
70859
70860         var shown = fieldsArr.filter(function(field) { return field.shown(); }),
70861             notShown = fieldsArr.filter(function(field) { return !field.shown(); });
70862
70863
70864         var form = selection$$1.selectAll('.preset-form')
70865             .data([0]);
70866
70867         form = form.enter()
70868             .append('div')
70869             .attr('class', 'preset-form inspector-inner fillL3')
70870             .merge(form);
70871
70872
70873         var fields = form.selectAll('.form-field')
70874             .data(shown, fieldKey);
70875
70876         fields.exit()
70877             .remove();
70878
70879         // Enter
70880         var enter = fields.enter()
70881             .append('div')
70882             .attr('class', function(field) {
70883                 return 'form-field form-field-' + field.id;
70884             });
70885
70886         var label = enter
70887             .append('label')
70888             .attr('class', 'form-label')
70889             .attr('for', function(field) { return 'preset-input-' + field.id; })
70890             .text(function(field) { return field.label(); });
70891
70892         var wrap = label
70893             .append('div')
70894             .attr('class', 'form-label-button-wrap');
70895
70896         wrap.append('button')
70897             .attr('class', 'remove-icon')
70898             .attr('tabindex', -1)
70899             .call(svgIcon('#operation-delete'));
70900
70901         wrap.append('button')
70902             .attr('class', 'modified-icon')
70903             .attr('tabindex', -1)
70904             .call(
70905                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
70906             );
70907
70908
70909         // Update
70910         fields = fields
70911             .merge(enter);
70912
70913         fields.selectAll('.form-label-button-wrap .remove-icon')
70914             .on('click', remove);
70915
70916         fields.selectAll('.modified-icon')
70917             .on('click', revert);
70918
70919         fields
70920             .order()
70921             .classed('modified', function(field) { return field.modified(); })
70922             .classed('present', function(field) { return field.present(); })
70923             .each(function(field) {
70924                 var referenceKey = field.key;
70925                 if (field.type === 'multiCombo') {   // lookup key without the trailing ':'
70926                     referenceKey = referenceKey.replace(/:$/, '');
70927                 }
70928                 var reference = uiTagReference(field.reference || { key: referenceKey }, context);
70929
70930                 if (state === 'hover') {
70931                     reference.showing(false);
70932                 }
70933
70934                 select(this)
70935                     .call(field.input)
70936                     .selectAll('input')
70937                     .on('keydown', function() {
70938                         // if user presses enter, and combobox is not active, accept edits..
70939                         if (event.keyCode === 13 && select('.combobox').empty()) {
70940                             context.enter(modeBrowse(context));
70941                         }
70942                     });
70943
70944                 select(this)
70945                     .call(reference.body)
70946                     .select('.form-label-button-wrap')
70947                     .call(reference.button);
70948
70949                 field.input.tags(tags);
70950             });
70951
70952         notShown = notShown.map(function(field) {
70953             return {
70954                 title: field.label(),
70955                 value: field.label(),
70956                 field: field
70957             };
70958         });
70959
70960
70961         var more = selection$$1.selectAll('.more-fields')
70962             .data((notShown.length > 0) ? [0] : []);
70963
70964         more.exit()
70965             .remove();
70966
70967         more = more.enter()
70968             .append('div')
70969             .attr('class', 'more-fields')
70970             .append('label')
70971             .text(t('inspector.add_fields'))
70972             .merge(more);
70973
70974
70975         var input = more.selectAll('.value')
70976             .data([0]);
70977
70978         input.exit()
70979             .remove();
70980
70981         input = input.enter()
70982             .append('input')
70983             .attr('class', 'value')
70984             .attr('type', 'text')
70985             .call(utilNoAuto)
70986             .merge(input);
70987
70988         input
70989             .call(utilGetSetValue, '')
70990             .attr('placeholder', function() {
70991                 var placeholder = [];
70992                 for (var field in notShown) {
70993                     placeholder.push(notShown[field].title);
70994                 }
70995                 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
70996             })
70997             .call(d3combobox()
70998                 .container(context.container())
70999                 .data(notShown)
71000                 .minItems(1)
71001                 .on('accept', show)
71002             );
71003
71004
71005         function show(field) {
71006             field = field.field;
71007             field.show = true;
71008             content(selection$$1);
71009             field.input.focus();
71010         }
71011
71012
71013         function revert(field) {
71014             event.stopPropagation();
71015             event.preventDefault();
71016             dispatch$$1.call('change', field, field.revert());
71017         }
71018
71019
71020         function remove(field) {
71021             event.stopPropagation();
71022             event.preventDefault();
71023             dispatch$$1.call('change', field, field.remove());
71024         }
71025     }
71026
71027
71028     presets.preset = function(_) {
71029         if (!arguments.length) return preset;
71030         if (preset && preset.id === _.id) return presets;
71031         preset = _;
71032         fieldsArr = null;
71033         return presets;
71034     };
71035
71036
71037     presets.state = function(_) {
71038         if (!arguments.length) return state;
71039         state = _;
71040         return presets;
71041     };
71042
71043
71044     presets.tags = function(_) {
71045         if (!arguments.length) return tags;
71046         tags = _;
71047         // Don't reset fieldsArr here.
71048         return presets;
71049     };
71050
71051
71052     presets.entityID = function(_) {
71053         if (!arguments.length) return id;
71054         if (id === _) return presets;
71055         id = _;
71056         fieldsArr = null;
71057         return presets;
71058     };
71059
71060
71061     return utilRebind(presets, dispatch$$1, 'on');
71062 }
71063
71064 function uiEntityEditor(context) {
71065     var dispatch$$1 = dispatch('choose'),
71066         state = 'select',
71067         coalesceChanges = false,
71068         modified = false,
71069         base,
71070         id,
71071         activePreset,
71072         reference;
71073
71074     var presetEditor = uiPreset(context)
71075         .on('change', changeTags);
71076     var rawTagEditor = uiRawTagEditor(context)
71077         .on('change', changeTags);
71078
71079
71080     function entityEditor(selection$$1) {
71081         var entity = context.entity(id),
71082             tags = lodash.clone(entity.tags);
71083
71084         // Header
71085         var header = selection$$1.selectAll('.header')
71086             .data([0]);
71087
71088         // Enter
71089         var enter = header.enter()
71090             .append('div')
71091             .attr('class', 'header fillL cf');
71092
71093         enter
71094             .append('button')
71095             .attr('class', 'fl preset-reset preset-choose')
71096             .call(svgIcon((textDirection === 'rtl') ? '#icon-forward' : '#icon-backward'));
71097
71098         enter
71099             .append('button')
71100             .attr('class', 'fr preset-close')
71101             .on('click', function() { context.enter(modeBrowse(context)); })
71102             .call(svgIcon(modified ? '#icon-apply' : '#icon-close'));
71103
71104         enter
71105             .append('h3')
71106             .text(t('inspector.edit'));
71107
71108         // Update
71109         header = header
71110             .merge(enter);
71111
71112         header.selectAll('.preset-reset')
71113             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
71114
71115
71116         // Body
71117         var body = selection$$1.selectAll('.inspector-body')
71118             .data([0]);
71119
71120         // Enter
71121         enter = body.enter()
71122             .append('div')
71123             .attr('class', 'inspector-body');
71124
71125         enter
71126             .append('div')
71127             .attr('class', 'preset-list-item inspector-inner')
71128             .append('div')
71129             .attr('class', 'preset-list-button-wrap')
71130             .append('button')
71131             .attr('class', 'preset-list-button preset-reset')
71132             .call(tooltip().title(t('inspector.back_tooltip')).placement('bottom'))
71133             .append('div')
71134             .attr('class', 'label');
71135
71136         enter
71137             .append('div')
71138             .attr('class', 'inspector-border inspector-preset');
71139
71140         enter
71141             .append('div')
71142             .attr('class', 'inspector-border raw-tag-editor inspector-inner');
71143
71144         enter
71145             .append('div')
71146             .attr('class', 'inspector-border raw-member-editor inspector-inner');
71147
71148         enter
71149             .append('div')
71150             .attr('class', 'raw-membership-editor inspector-inner');
71151
71152         // Update
71153         body = body
71154             .merge(enter);
71155
71156         body.selectAll('.preset-list-button-wrap')
71157             .call(reference.button);
71158
71159         body.selectAll('.preset-list-item')
71160             .call(reference.body);
71161
71162         body.selectAll('.preset-reset')
71163             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
71164
71165         body.select('.preset-list-item button')
71166             .call(uiPresetIcon()
71167                 .geometry(context.geometry(id))
71168                 .preset(activePreset));
71169
71170         body.select('.preset-list-item .label')
71171             .text(activePreset.name());
71172
71173         body.select('.inspector-preset')
71174             .call(presetEditor
71175                 .preset(activePreset)
71176                 .entityID(id)
71177                 .tags(tags)
71178                 .state(state));
71179
71180         body.select('.raw-tag-editor')
71181             .call(rawTagEditor
71182                 .preset(activePreset)
71183                 .entityID(id)
71184                 .tags(tags)
71185                 .state(state));
71186
71187         if (entity.type === 'relation') {
71188             body.select('.raw-member-editor')
71189                 .style('display', 'block')
71190                 .call(uiRawMemberEditor(context)
71191                     .entityID(id));
71192         } else {
71193             body.select('.raw-member-editor')
71194                 .style('display', 'none');
71195         }
71196
71197         body.select('.raw-membership-editor')
71198             .call(uiRawMembershipEditor(context)
71199                 .entityID(id));
71200
71201
71202         context.history()
71203             .on('change.entity-editor', historyChanged);
71204
71205
71206         function historyChanged() {
71207             if (state === 'hide') return;
71208
71209             var entity = context.hasEntity(id),
71210                 graph = context.graph();
71211             if (!entity) return;
71212
71213             entityEditor.preset(context.presets().match(entity, graph));
71214             entityEditor.modified(base !== graph);
71215             entityEditor(selection$$1);
71216         }
71217     }
71218
71219
71220     function clean(o) {
71221
71222         function cleanVal(k, v) {
71223             function keepSpaces(k) {
71224                 return k.match(/_hours|_times/) !== null;
71225             }
71226
71227             var blacklist = ['description', 'note', 'fixme'];
71228             if (lodash.some(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
71229
71230             var cleaned = v.split(';')
71231                 .map(function(s) { return s.trim(); })
71232                 .join(keepSpaces(k) ? '; ' : ';');
71233
71234             // The code below is not intended to validate websites and emails.
71235             // It is only intended to prevent obvious copy-paste errors. (#2323)
71236             // clean website- and email-like tags
71237             if (k.indexOf('website') !== -1 ||
71238                 k.indexOf('email') !== -1 ||
71239                 cleaned.indexOf('http') === 0) {
71240                 cleaned = cleaned
71241                     .replace(/[\u200B-\u200F\uFEFF]/g, '');  // strip LRM and other zero width chars
71242
71243             }
71244
71245             return cleaned;
71246         }
71247
71248         var out = {}, k, v;
71249         for (k in o) {
71250             if (k && (v = o[k]) !== undefined) {
71251                 out[k] = cleanVal(k, v);
71252             }
71253         }
71254         return out;
71255     }
71256
71257
71258     // Tag changes that fire on input can all get coalesced into a single
71259     // history operation when the user leaves the field.  #2342
71260     function changeTags(changed, onInput) {
71261         var entity = context.entity(id),
71262             annotation = t('operations.change_tags.annotation'),
71263             tags = lodash.clone(entity.tags);
71264
71265         lodash.forEach(changed, function(v, k) {
71266             if (v !== undefined || tags.hasOwnProperty(k)) {
71267                 tags[k] = v;
71268             }
71269         });
71270
71271         if (!onInput) {
71272             tags = clean(tags);
71273         }
71274
71275         if (!lodash.isEqual(entity.tags, tags)) {
71276             if (coalesceChanges) {
71277                 context.overwrite(actionChangeTags(id, tags), annotation);
71278             } else {
71279                 context.perform(actionChangeTags(id, tags), annotation);
71280                 coalesceChanges = !!onInput;
71281             }
71282         }
71283     }
71284
71285
71286     entityEditor.modified = function(_) {
71287         if (!arguments.length) return modified;
71288         modified = _;
71289         selectAll('button.preset-close use')
71290             .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
71291     };
71292
71293
71294     entityEditor.state = function(_) {
71295         if (!arguments.length) return state;
71296         state = _;
71297         return entityEditor;
71298     };
71299
71300
71301     entityEditor.entityID = function(_) {
71302         if (!arguments.length) return id;
71303         id = _;
71304         base = context.graph();
71305         entityEditor.preset(context.presets().match(context.entity(id), base));
71306         entityEditor.modified(false);
71307         coalesceChanges = false;
71308         return entityEditor;
71309     };
71310
71311
71312     entityEditor.preset = function(_) {
71313         if (!arguments.length) return activePreset;
71314         if (_ !== activePreset) {
71315             activePreset = _;
71316             reference = uiTagReference(activePreset.reference(context.geometry(id)), context)
71317                 .showing(false);
71318         }
71319         return entityEditor;
71320     };
71321
71322
71323     return utilRebind(entityEditor, dispatch$$1, 'on');
71324 }
71325
71326 function uiPresetList(context) {
71327     var dispatch$$1 = dispatch('choose'),
71328         id,
71329         currentPreset,
71330         autofocus = false;
71331
71332
71333     function presetList(selection$$1) {
71334         var entity = context.entity(id),
71335             geometry = context.geometry(id);
71336
71337         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
71338         if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
71339             geometry = 'point';
71340         }
71341
71342         var presets = context.presets().matchGeometry(geometry);
71343
71344         selection$$1.html('');
71345
71346         var messagewrap = selection$$1
71347             .append('div')
71348             .attr('class', 'header fillL cf');
71349
71350         var message = messagewrap
71351             .append('h3')
71352             .text(t('inspector.choose'));
71353
71354         if (context.entity(id).isUsed(context.graph())) {
71355             messagewrap
71356                 .append('button')
71357                 .attr('class', 'preset-choose')
71358                 .on('click', function() { dispatch$$1.call('choose', this, currentPreset); })
71359                 .call(svgIcon((textDirection === 'rtl') ? '#icon-backward' : '#icon-forward'));
71360         } else {
71361             messagewrap
71362                 .append('button')
71363                 .attr('class', 'close')
71364                 .on('click', function() {
71365                     context.enter(modeBrowse(context));
71366                 })
71367                 .call(svgIcon('#icon-close'));
71368         }
71369
71370         function keydown() {
71371             // hack to let delete shortcut work when search is autofocused
71372             if (search.property('value').length === 0 &&
71373                 (event.keyCode === d3keybinding.keyCodes['⌫'] ||
71374                  event.keyCode === d3keybinding.keyCodes['⌦'])) {
71375                 event.preventDefault();
71376                 event.stopPropagation();
71377                 operationDelete([id], context)();
71378             } else if (search.property('value').length === 0 &&
71379                 (event.ctrlKey || event.metaKey) &&
71380                 event.keyCode === d3keybinding.keyCodes.z) {
71381                 event.preventDefault();
71382                 event.stopPropagation();
71383                 context.undo();
71384             } else if (!event.ctrlKey && !event.metaKey) {
71385                 select(this).on('keydown', null);
71386             }
71387         }
71388
71389         function keypress() {
71390             // enter
71391             var value = search.property('value');
71392             if (event.keyCode === 13 && value.length) {
71393                 list.selectAll('.preset-list-item:first-child').datum().choose();
71394             }
71395         }
71396
71397         function inputevent() {
71398             var value = search.property('value');
71399             list.classed('filtered', value.length);
71400             if (value.length) {
71401                 var results = presets.search(value, geometry);
71402                 message.text(t('inspector.results', {
71403                     n: results.collection.length,
71404                     search: value
71405                 }));
71406                 list.call(drawList, results);
71407             } else {
71408                 list.call(drawList, context.presets().defaults(geometry, 36));
71409                 message.text(t('inspector.choose'));
71410             }
71411         }
71412
71413         var searchWrap = selection$$1
71414             .append('div')
71415             .attr('class', 'search-header');
71416
71417         var search = searchWrap
71418             .append('input')
71419             .attr('class', 'preset-search-input')
71420             .attr('placeholder', t('inspector.search'))
71421             .attr('type', 'search')
71422             .call(utilNoAuto)
71423             .on('keydown', keydown)
71424             .on('keypress', keypress)
71425             .on('input', inputevent);
71426
71427         searchWrap
71428             .call(svgIcon('#icon-search', 'pre-text'));
71429
71430         if (autofocus) {
71431             search.node().focus();
71432         }
71433
71434         var listWrap = selection$$1
71435             .append('div')
71436             .attr('class', 'inspector-body');
71437
71438         var list = listWrap
71439             .append('div')
71440             .attr('class', 'preset-list fillL cf')
71441             .call(drawList, context.presets().defaults(geometry, 36));
71442     }
71443
71444
71445     function drawList(list, presets) {
71446         var collection = presets.collection.map(function(preset) {
71447             return preset.members ? CategoryItem(preset) : PresetItem(preset);
71448         });
71449
71450         var items = list.selectAll('.preset-list-item')
71451             .data(collection, function(d) { return d.preset.id; });
71452
71453         items.order();
71454
71455         items.exit()
71456             .remove();
71457
71458         items.enter()
71459             .append('div')
71460             .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
71461             .classed('current', function(item) { return item.preset === currentPreset; })
71462             .each(function(item) { select(this).call(item); })
71463             .style('opacity', 0)
71464             .transition()
71465             .style('opacity', 1);
71466     }
71467
71468
71469     function CategoryItem(preset) {
71470         var box, sublist, shown = false;
71471
71472         function item(selection$$1) {
71473             var wrap = selection$$1.append('div')
71474                 .attr('class', 'preset-list-button-wrap category col12');
71475
71476             var button = wrap
71477                 .append('button')
71478                 .attr('class', 'preset-list-button')
71479                 .classed('expanded', false)
71480                 .call(uiPresetIcon()
71481                     .geometry(context.geometry(id))
71482                     .preset(preset))
71483                 .on('click', function() {
71484                     var isExpanded = select(this).classed('expanded');
71485                     var iconName = isExpanded ?
71486                         (textDirection === 'rtl' ? '#icon-backward' : '#icon-forward') : '#icon-down';
71487                     select(this)
71488                         .classed('expanded', !isExpanded);
71489                     select(this).selectAll('div.label svg.icon use')
71490                         .attr('href', iconName);
71491                     item.choose();
71492                 });
71493
71494             var label = button
71495                 .append('div')
71496                 .attr('class', 'label');
71497
71498             label
71499                 .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'))
71500                 .append('span')
71501                 .html(function() { return preset.name() + '&hellip;'; });
71502
71503             box = selection$$1.append('div')
71504                 .attr('class', 'subgrid col12')
71505                 .style('max-height', '0px')
71506                 .style('opacity', 0);
71507
71508             box.append('div')
71509                 .attr('class', 'arrow');
71510
71511             sublist = box.append('div')
71512                 .attr('class', 'preset-list fillL3 cf fl');
71513         }
71514
71515
71516         item.choose = function() {
71517             if (!box || !sublist) return;
71518
71519             if (shown) {
71520                 shown = false;
71521                 box.transition()
71522                     .duration(200)
71523                     .style('opacity', '0')
71524                     .style('max-height', '0px')
71525                     .style('padding-bottom', '0px');
71526             } else {
71527                 shown = true;
71528                 sublist.call(drawList, preset.members);
71529                 box.transition()
71530                     .duration(200)
71531                     .style('opacity', '1')
71532                     .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
71533                     .style('padding-bottom', '20px');
71534             }
71535         };
71536
71537         item.preset = preset;
71538
71539         return item;
71540     }
71541
71542
71543     function PresetItem(preset) {
71544         function item(selection$$1) {
71545             var wrap = selection$$1.append('div')
71546                 .attr('class', 'preset-list-button-wrap col12');
71547
71548             wrap.append('button')
71549                 .attr('class', 'preset-list-button')
71550                 .call(uiPresetIcon()
71551                     .geometry(context.geometry(id))
71552                     .preset(preset))
71553                 .on('click', item.choose)
71554                 .append('div')
71555                 .attr('class', 'label')
71556                 .text(preset.name());
71557
71558             wrap.call(item.reference.button);
71559             selection$$1.call(item.reference.body);
71560         }
71561
71562         item.choose = function() {
71563             context.presets().choose(preset);
71564
71565             context.perform(
71566                 actionChangePreset(id, currentPreset, preset),
71567                 t('operations.change_tags.annotation')
71568             );
71569
71570             dispatch$$1.call('choose', this, preset);
71571         };
71572
71573         item.help = function() {
71574             event.stopPropagation();
71575             item.reference.toggle();
71576         };
71577
71578         item.preset = preset;
71579         item.reference = uiTagReference(preset.reference(context.geometry(id)), context);
71580
71581         return item;
71582     }
71583
71584
71585     presetList.autofocus = function(_) {
71586         if (!arguments.length) return autofocus;
71587         autofocus = _;
71588         return presetList;
71589     };
71590
71591
71592     presetList.entityID = function(_) {
71593         if (!arguments.length) return id;
71594         id = _;
71595         presetList.preset(context.presets().match(context.entity(id), context.graph()));
71596         return presetList;
71597     };
71598
71599
71600     presetList.preset = function(_) {
71601         if (!arguments.length) return currentPreset;
71602         currentPreset = _;
71603         return presetList;
71604     };
71605
71606
71607     return utilRebind(presetList, dispatch$$1, 'on');
71608 }
71609
71610 function uiViewOnOSM(context) {
71611     var id;
71612
71613     function viewOnOSM(selection) {
71614         var entity = context.entity(id);
71615
71616         selection.style('display', entity.isNew() ? 'none' : null);
71617
71618         var link = selection.selectAll('.view-on-osm')
71619             .data([0]);
71620
71621         var enter = link.enter()
71622             .append('a')
71623             .attr('class', 'view-on-osm')
71624             .attr('target', '_blank')
71625             .call(svgIcon('#icon-out-link', 'inline'));
71626
71627         enter
71628             .append('span')
71629             .text(t('inspector.view_on_osm'));
71630
71631         link
71632             .merge(enter)
71633             .attr('href', context.connection().entityURL(entity));
71634     }
71635
71636
71637     viewOnOSM.entityID = function(_) {
71638         if (!arguments.length) return id;
71639         id = _;
71640         return viewOnOSM;
71641     };
71642
71643     return viewOnOSM;
71644 }
71645
71646 function uiInspector(context) {
71647     var presetList = uiPresetList(context),
71648         entityEditor = uiEntityEditor(context),
71649         state = 'select',
71650         entityID,
71651         newFeature = false;
71652
71653
71654     function inspector(selection$$1) {
71655         presetList
71656             .entityID(entityID)
71657             .autofocus(newFeature)
71658             .on('choose', setPreset);
71659
71660         entityEditor
71661             .state(state)
71662             .entityID(entityID)
71663             .on('choose', showList);
71664
71665         var wrap = selection$$1.selectAll('.panewrap')
71666             .data([0]);
71667
71668         var enter = wrap.enter()
71669             .append('div')
71670             .attr('class', 'panewrap');
71671
71672         enter
71673             .append('div')
71674             .attr('class', 'preset-list-pane pane');
71675
71676         enter
71677             .append('div')
71678             .attr('class', 'entity-editor-pane pane');
71679
71680         wrap = wrap.merge(enter);
71681         var presetPane = wrap.selectAll('.preset-list-pane');
71682         var editorPane = wrap.selectAll('.entity-editor-pane');
71683
71684         var graph = context.graph(),
71685             entity = context.entity(entityID),
71686             showEditor = state === 'hover' ||
71687                 entity.isUsed(graph) ||
71688                 entity.isHighwayIntersection(graph);
71689
71690         if (showEditor) {
71691             wrap.style('right', '0%');
71692             editorPane.call(entityEditor);
71693         } else {
71694             wrap.style('right', '-100%');
71695             presetPane.call(presetList);
71696         }
71697
71698         var footer = selection$$1.selectAll('.footer')
71699             .data([0]);
71700
71701         footer = footer.enter()
71702             .append('div')
71703             .attr('class', 'footer')
71704             .merge(footer);
71705
71706         footer
71707             .call(uiViewOnOSM(context).entityID(entityID));
71708
71709
71710         function showList(preset) {
71711             wrap.transition()
71712                 .styleTween('right', function() { return interpolateValue('0%', '-100%'); });
71713
71714             presetPane
71715                 .call(presetList.preset(preset).autofocus(true));
71716         }
71717
71718
71719         function setPreset(preset) {
71720             wrap.transition()
71721                 .styleTween('right', function() { return interpolateValue('-100%', '0%'); });
71722
71723             editorPane
71724                 .call(entityEditor.preset(preset));
71725         }
71726     }
71727
71728
71729     inspector.state = function(_) {
71730         if (!arguments.length) return state;
71731         state = _;
71732         entityEditor.state(state);
71733         return inspector;
71734     };
71735
71736
71737     inspector.entityID = function(_) {
71738         if (!arguments.length) return entityID;
71739         entityID = _;
71740         return inspector;
71741     };
71742
71743
71744     inspector.newFeature = function(_) {
71745         if (!arguments.length) return newFeature;
71746         newFeature = _;
71747         return inspector;
71748     };
71749
71750
71751     return inspector;
71752 }
71753
71754 function uiNotice(context) {
71755
71756     return function(selection) {
71757         var div = selection
71758             .append('div')
71759             .attr('class', 'notice');
71760
71761         var button = div
71762             .append('button')
71763             .attr('class', 'zoom-to notice')
71764             .on('click', function() { context.map().zoom(context.minEditableZoom()); });
71765
71766         button
71767             .call(svgIcon('#icon-plus', 'pre-text'))
71768             .append('span')
71769             .attr('class', 'label')
71770             .text(t('zoom_in_edit'));
71771
71772
71773         function disableTooHigh() {
71774             div.style('display', context.editable() ? 'none' : 'block');
71775         }
71776
71777         context.map()
71778             .on('move.notice', lodash.debounce(disableTooHigh, 500));
71779
71780         disableTooHigh();
71781     };
71782 }
71783
71784 function uiSidebar(context) {
71785     var inspector = uiInspector(context),
71786         current;
71787
71788
71789     function sidebar(selection) {
71790         var featureListWrap = selection
71791             .append('div')
71792             .attr('class', 'feature-list-pane')
71793             .call(uiFeatureList(context));
71794
71795         selection
71796             .call(uiNotice(context));
71797
71798         var inspectorWrap = selection
71799             .append('div')
71800             .attr('class', 'inspector-hidden inspector-wrap fr');
71801
71802
71803         function hover(id) {
71804             if (!current && context.hasEntity(id)) {
71805                 featureListWrap
71806                     .classed('inspector-hidden', true);
71807
71808                 inspectorWrap
71809                     .classed('inspector-hidden', false)
71810                     .classed('inspector-hover', true);
71811
71812                 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
71813                     inspector
71814                         .state('hover')
71815                         .entityID(id);
71816
71817                     inspectorWrap
71818                         .call(inspector);
71819                 }
71820
71821             } else if (!current) {
71822                 featureListWrap
71823                     .classed('inspector-hidden', false);
71824                 inspectorWrap
71825                     .classed('inspector-hidden', true);
71826                 inspector
71827                     .state('hide');
71828             }
71829         }
71830
71831
71832         sidebar.hover = lodash.throttle(hover, 200);
71833
71834
71835         sidebar.select = function(id, newFeature) {
71836             if (!current && id) {
71837                 featureListWrap
71838                     .classed('inspector-hidden', true);
71839
71840                 inspectorWrap
71841                     .classed('inspector-hidden', false)
71842                     .classed('inspector-hover', false);
71843
71844                 if (inspector.entityID() !== id || inspector.state() !== 'select') {
71845                     inspector
71846                         .state('select')
71847                         .entityID(id)
71848                         .newFeature(newFeature);
71849
71850                     inspectorWrap
71851                         .call(inspector);
71852                 }
71853
71854             } else if (!current) {
71855                 featureListWrap
71856                     .classed('inspector-hidden', false);
71857                 inspectorWrap
71858                     .classed('inspector-hidden', true);
71859                 inspector
71860                     .state('hide');
71861             }
71862         };
71863
71864
71865         sidebar.show = function(component) {
71866             featureListWrap
71867                 .classed('inspector-hidden', true);
71868             inspectorWrap
71869                 .classed('inspector-hidden', true);
71870
71871             if (current) current.remove();
71872             current = selection
71873                 .append('div')
71874                 .attr('class', 'sidebar-component')
71875                 .call(component);
71876         };
71877
71878
71879         sidebar.hide = function() {
71880             featureListWrap
71881                 .classed('inspector-hidden', false);
71882             inspectorWrap
71883                 .classed('inspector-hidden', true);
71884
71885             if (current) current.remove();
71886             current = null;
71887         };
71888     }
71889
71890
71891     sidebar.hover = function() {};
71892     sidebar.hover.cancel = function() {};
71893     sidebar.select = function() {};
71894     sidebar.show = function() {};
71895     sidebar.hide = function() {};
71896
71897     return sidebar;
71898 }
71899
71900 function uiSpinner(context) {
71901     var connection = context.connection();
71902
71903
71904     return function(selection) {
71905         var img = selection
71906             .append('img')
71907             .attr('src', context.imagePath('loader-black.gif'))
71908             .style('opacity', 0);
71909
71910         connection
71911             .on('loading.spinner', function() {
71912                 img.transition()
71913                     .style('opacity', 1);
71914             });
71915
71916         connection
71917             .on('loaded.spinner', function() {
71918                 img.transition()
71919                     .style('opacity', 0);
71920             });
71921     };
71922 }
71923
71924 function uiSplash(context) {
71925
71926     return function(selection) {
71927         if (context.storage('sawSplash'))
71928              return;
71929
71930         context.storage('sawSplash', true);
71931
71932         var modalSelection = uiModal(selection);
71933
71934         modalSelection.select('.modal')
71935             .attr('class', 'modal-splash modal col6');
71936
71937         var introModal = modalSelection.select('.content')
71938             .append('div')
71939             .attr('class', 'fillL');
71940
71941         introModal
71942             .append('div')
71943             .attr('class','modal-section cf')
71944             .append('h3').text(t('splash.welcome'));
71945
71946         introModal
71947             .append('div')
71948             .attr('class','modal-section')
71949             .append('p')
71950             .html(t('splash.text', {
71951                 version: context.version,
71952                 website: '<a href="http://ideditor.com/">ideditor.com</a>',
71953                 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
71954             }));
71955
71956         var buttonWrap = introModal
71957             .append('div')
71958             .attr('class', 'modal-actions cf');
71959
71960         var walkthrough = buttonWrap
71961             .append('button')
71962             .attr('class', 'walkthrough col6')
71963             .on('click', function() {
71964                 context.container().call(uiIntro(context));
71965                 modalSelection.close();
71966             });
71967
71968         walkthrough
71969             .append('svg')
71970             .attr('class', 'logo logo-walkthrough')
71971             .append('use')
71972             .attr('xlink:href', '#logo-walkthrough');
71973
71974         walkthrough
71975             .append('div')
71976             .text(t('splash.walkthrough'));
71977
71978         var startEditing = buttonWrap
71979             .append('button')
71980             .attr('class', 'start-editing col6')
71981             .on('click', modalSelection.close);
71982
71983         startEditing
71984             .append('svg')
71985             .attr('class', 'logo logo-features')
71986             .append('use')
71987             .attr('xlink:href', '#logo-features');
71988
71989         startEditing
71990             .append('div')
71991             .text(t('splash.start'));
71992
71993
71994         modalSelection.select('button.close')
71995             .attr('class','hide');
71996
71997     };
71998 }
71999
72000 function uiStatus(context) {
72001     var connection = context.connection();
72002
72003     return function(selection$$1) {
72004
72005         function update() {
72006             connection.status(function(err, apiStatus) {
72007                 selection$$1.html('');
72008
72009                 if (err) {
72010                     if (apiStatus === 'rateLimited') {
72011                         selection$$1
72012                             .text(t('status.rateLimit'))
72013                             .append('a')
72014                             .attr('class', 'api-status-login')
72015                             .attr('target', '_blank')
72016                             .call(svgIcon('#icon-out-link', 'inline'))
72017                             .append('span')
72018                             .text(t('login'))
72019                             .on('click.login', function() {
72020                                 event.preventDefault();
72021                                 connection.authenticate();
72022                             });
72023                     } else {
72024                         // TODO: nice messages for different error types
72025                         selection$$1.text(t('status.error'));
72026                     }
72027
72028                 } else if (apiStatus === 'readonly') {
72029                     selection$$1.text(t('status.readonly'));
72030                 } else if (apiStatus === 'offline') {
72031                     selection$$1.text(t('status.offline'));
72032                 }
72033
72034                 selection$$1.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
72035             });
72036         }
72037
72038         connection
72039             .on('change', function() { update(selection$$1); });
72040
72041         window.setInterval(update, 90000);
72042         update(selection$$1);
72043     };
72044 }
72045
72046 function uiUndoRedo(context) {
72047     var commands = [{
72048         id: 'undo',
72049         cmd: uiCmd('⌘Z'),
72050         action: function() { if (!saving()) context.undo(); },
72051         annotation: function() { return context.history().undoAnnotation(); }
72052     }, {
72053         id: 'redo',
72054         cmd: uiCmd('⌘⇧Z'),
72055         action: function() { if (!saving()) context.redo(); },
72056         annotation: function() { return context.history().redoAnnotation(); }
72057     }];
72058
72059
72060     function saving() {
72061         return context.mode().id === 'save';
72062     }
72063
72064
72065     return function(selection$$1) {
72066         var tooltipBehavior = tooltip()
72067             .placement('bottom')
72068             .html(true)
72069             .title(function (d) {
72070                 return uiTooltipHtml(d.annotation() ?
72071                     t(d.id + '.tooltip', {action: d.annotation()}) :
72072                     t(d.id + '.nothing'), d.cmd);
72073             });
72074
72075         var buttons = selection$$1.selectAll('button')
72076             .data(commands)
72077             .enter()
72078             .append('button')
72079             .attr('class', function(d) { return 'col6 disabled ' + d.id + '-button'; })
72080             .on('click', function(d) { return d.action(); })
72081             .call(tooltipBehavior);
72082
72083         buttons.each(function(d) {
72084             var iconName = d.id;
72085             if (textDirection === 'rtl') {
72086                 if (iconName === 'undo') {
72087                     iconName = 'redo';
72088                 } else if (iconName === 'redo') {
72089                     iconName = 'undo';
72090                 }
72091             }
72092             select(this)
72093                 .call(svgIcon('#icon-' + iconName));
72094         });
72095
72096         var keybinding = d3keybinding('undo')
72097             .on(commands[0].cmd, function() { event.preventDefault(); commands[0].action(); })
72098             .on(commands[1].cmd, function() { event.preventDefault(); commands[1].action(); });
72099
72100         select(document)
72101             .call(keybinding);
72102
72103         context.history()
72104             .on('change.undo_redo', update);
72105
72106         context
72107             .on('enter.undo_redo', update);
72108
72109         function update() {
72110             buttons
72111                 .property('disabled', saving())
72112                 .classed('disabled', function(d) { return !d.annotation(); })
72113                 .each(function() {
72114                     var selection$$1 = select(this);
72115                     if (selection$$1.property('tooltipVisible')) {
72116                         selection$$1.call(tooltipBehavior.show);
72117                     }
72118                 });
72119         }
72120     };
72121 }
72122
72123 // these are module variables so they are preserved through a ui.restart()
72124 var sawVersion = null;
72125 var isNewVersion = false;
72126 var isNewUser = false;
72127
72128
72129 function uiVersion(context) {
72130
72131     var currVersion = context.version,
72132         matchedVersion = currVersion.match(/\d\.\d\.\d.*/);
72133
72134     if (sawVersion === null && matchedVersion !== null) {
72135         isNewVersion = (context.storage('sawVersion') !== currVersion);
72136         isNewUser = !context.storage('sawSplash');
72137         context.storage('sawVersion', currVersion);
72138         sawVersion = currVersion;
72139     }
72140
72141     return function(selection) {
72142         selection
72143             .append('a')
72144             .attr('target', '_blank')
72145             .attr('tabindex', -1)
72146             .attr('href', 'https://github.com/openstreetmap/iD')
72147             .text(currVersion);
72148
72149         // only show new version indicator to users that have used iD before
72150         if (isNewVersion && !isNewUser) {
72151             selection
72152                 .append('div')
72153                 .attr('class', 'badge')
72154                 .append('a')
72155                 .attr('target', '_blank')
72156                 .attr('tabindex', -1)
72157                 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CHANGELOG.md#whats-new')
72158                 .call(svgIcon('#gift-11'))
72159                 .call(tooltip()
72160                     .title(t('version.whats_new', { version: currVersion }))
72161                     .placement('top')
72162                 );
72163         }
72164     };
72165 }
72166
72167 function uiZoom(context) {
72168     var zooms = [{
72169         id: 'zoom-in',
72170         icon: 'plus',
72171         title: t('zoom.in'),
72172         action: context.zoomIn,
72173         key: '+'
72174     }, {
72175         id: 'zoom-out',
72176         icon: 'minus',
72177         title: t('zoom.out'),
72178         action: context.zoomOut,
72179         key: '-'
72180     }];
72181
72182
72183     function zoomIn() {
72184         event.preventDefault();
72185         context.zoomIn();
72186     }
72187
72188
72189     function zoomOut() {
72190         event.preventDefault();
72191         context.zoomOut();
72192     }
72193
72194
72195     function zoomInFurther() {
72196         event.preventDefault();
72197         context.zoomInFurther();
72198     }
72199
72200
72201     function zoomOutFurther() {
72202         event.preventDefault();
72203         context.zoomOutFurther();
72204     }
72205
72206
72207     return function(selection$$1) {
72208         var button = selection$$1.selectAll('button')
72209             .data(zooms)
72210             .enter()
72211             .append('button')
72212             .attr('tabindex', -1)
72213             .attr('class', function(d) { return d.id; })
72214             .on('click.editor', function(d) { d.action(); })
72215             .call(tooltip()
72216                 .placement((textDirection === 'rtl') ? 'right' : 'left')
72217                 .html(true)
72218                 .title(function(d) {
72219                     return uiTooltipHtml(d.title, d.key);
72220                 })
72221             );
72222
72223         button.each(function(d) {
72224             select(this)
72225                 .call(svgIcon('#icon-' + d.icon, 'light'));
72226         });
72227
72228         var keybinding = d3keybinding('zoom');
72229
72230        lodash.each(['plus', 'ffplus', '=', 'ffequals'], function(key) {
72231             keybinding.on([key], zoomIn);
72232             keybinding.on([uiCmd('⌘' + key)], zoomInFurther);
72233         });
72234
72235         lodash.each(['_', '-', 'ffminus', 'dash'], function(key) {
72236             keybinding.on([key], zoomOut);
72237             keybinding.on([uiCmd('⌘' + key)], zoomOutFurther);
72238         });
72239
72240         select(document)
72241             .call(keybinding);
72242     };
72243 }
72244
72245 function uiInit(context) {
72246     var uiInitCounter = 0;
72247
72248
72249     function render(container) {
72250         container
72251             .attr('dir', textDirection);
72252
72253         var map = context.map();
72254
72255         var hash = behaviorHash(context);
72256         hash();
72257
72258         if (!hash.hadHash) {
72259             map.centerZoom([0, 0], 2);
72260         }
72261
72262         container
72263             .append('svg')
72264             .attr('id', 'defs')
72265             .call(svgDefs(context));
72266
72267         container
72268             .append('div')
72269             .attr('id', 'sidebar')
72270             .attr('class', 'col4')
72271             .call(ui.sidebar);
72272
72273         var content = container
72274             .append('div')
72275             .attr('id', 'content')
72276             .attr('class', 'active');
72277
72278         var bar = content
72279             .append('div')
72280             .attr('id', 'bar')
72281             .attr('class', 'fillD');
72282
72283         content
72284             .append('div')
72285             .attr('id', 'map')
72286             .attr('dir', 'ltr')
72287             .call(map);
72288
72289         content
72290             .call(uiMapInMap(context))
72291             .call(uiInfo(context));
72292
72293         bar
72294             .append('div')
72295             .attr('class', 'spacer col4');
72296
72297         var limiter = bar.append('div')
72298             .attr('class', 'limiter');
72299
72300         limiter
72301             .append('div')
72302             .attr('class', 'button-wrap joined col3')
72303             .call(uiModes(context), limiter);
72304
72305         limiter
72306             .append('div')
72307             .attr('class', 'button-wrap joined col1')
72308             .call(uiUndoRedo(context));
72309
72310         limiter
72311             .append('div')
72312             .attr('class', 'button-wrap col1')
72313             .call(uiSave(context));
72314
72315         bar
72316             .append('div')
72317             .attr('class', 'full-screen')
72318             .call(uiFullScreen(context));
72319
72320         bar
72321             .append('div')
72322             .attr('class', 'spinner')
72323             .call(uiSpinner(context));
72324
72325
72326         var controls = bar
72327             .append('div')
72328             .attr('class', 'map-controls');
72329
72330         controls
72331             .append('div')
72332             .attr('class', 'map-control zoombuttons')
72333             .call(uiZoom(context));
72334
72335         controls
72336             .append('div')
72337             .attr('class', 'map-control geolocate-control')
72338             .call(uiGeolocate(context));
72339
72340         controls
72341             .append('div')
72342             .attr('class', 'map-control background-control')
72343             .call(uiBackground(context));
72344
72345         controls
72346             .append('div')
72347             .attr('class', 'map-control map-data-control')
72348             .call(uiMapData(context));
72349
72350         controls
72351             .append('div')
72352             .attr('class', 'map-control help-control')
72353             .call(uiHelp(context));
72354
72355
72356         var about = content
72357             .append('div')
72358             .attr('id', 'about');
72359
72360         about
72361             .append('div')
72362             .attr('id', 'attrib')
72363             .attr('dir', 'ltr')
72364             .call(uiAttribution(context));
72365
72366         about
72367             .append('div')
72368             .attr('class', 'api-status')
72369             .call(uiStatus(context));
72370
72371
72372         var footer = about
72373             .append('div')
72374             .attr('id', 'footer')
72375             .attr('class', 'fillD');
72376
72377         footer
72378             .append('div')
72379             .attr('id', 'flash-wrap')
72380             .attr('class', 'footer-hide');
72381
72382         var footerWrap = footer
72383             .append('div')
72384             .attr('id', 'footer-wrap')
72385             .attr('class', 'footer-show');
72386
72387         footerWrap
72388             .append('div')
72389             .attr('id', 'scale-block')
72390             .call(uiScale(context));
72391
72392         var aboutList = footerWrap
72393             .append('div')
72394             .attr('id', 'info-block')
72395             .append('ul')
72396             .attr('id', 'about-list');
72397
72398         if (!context.embed()) {
72399             aboutList
72400                 .call(uiAccount(context));
72401         }
72402
72403         aboutList
72404             .append('li')
72405             .attr('class', 'version')
72406             .call(uiVersion(context));
72407
72408         var issueLinks = aboutList
72409             .append('li');
72410
72411         issueLinks
72412             .append('a')
72413             .attr('target', '_blank')
72414             .attr('tabindex', -1)
72415             .attr('href', 'https://github.com/openstreetmap/iD/issues')
72416             .call(svgIcon('#icon-bug', 'light'))
72417             .call(tooltip().title(t('report_a_bug')).placement('top'));
72418
72419         issueLinks
72420             .append('a')
72421             .attr('target', '_blank')
72422             .attr('tabindex', -1)
72423             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
72424             .call(svgIcon('#icon-translate', 'light'))
72425             .call(tooltip().title(t('help_translate')).placement('top'));
72426
72427         aboutList
72428             .append('li')
72429             .attr('class', 'feature-warning')
72430             .attr('tabindex', -1)
72431             .call(uiFeatureInfo(context));
72432
72433         aboutList
72434             .append('li')
72435             .attr('class', 'user-list')
72436             .attr('tabindex', -1)
72437             .call(uiContributors(context));
72438
72439
72440         window.onbeforeunload = function() {
72441             return context.save();
72442         };
72443
72444         window.onunload = function() {
72445             context.history().unlock();
72446         };
72447
72448         var mapDimensions = map.dimensions();
72449
72450
72451         function onResize() {
72452             mapDimensions = utilGetDimensions(content, true);
72453             map.dimensions(mapDimensions);
72454         }
72455
72456         select(window)
72457             .on('resize.editor', onResize);
72458
72459         onResize();
72460
72461         function pan(d) {
72462             return function() {
72463                 event.preventDefault();
72464                 context.pan(d, 100);
72465             };
72466         }
72467
72468
72469         // pan amount
72470         var pa = 10;
72471
72472         var keybinding = d3keybinding('main')
72473             .on('⌫', function() { event.preventDefault(); })
72474             .on('←', pan([pa, 0]))
72475             .on('↑', pan([0, pa]))
72476             .on('→', pan([-pa, 0]))
72477             .on('↓', pan([0, -pa]))
72478             .on(['⇧←', uiCmd('⌘←')], pan([mapDimensions[0], 0]))
72479             .on(['⇧↑', uiCmd('⌘↑')], pan([0, mapDimensions[1]]))
72480             .on(['⇧→', uiCmd('⌘→')], pan([-mapDimensions[0], 0]))
72481             .on(['⇧↓', uiCmd('⌘↓')], pan([0, -mapDimensions[1]]));
72482
72483         select(document)
72484             .call(keybinding);
72485
72486         context.enter(modeBrowse(context));
72487
72488         if (!uiInitCounter++) {
72489             if (!hash.startWalkthrough) {
72490                 context.container()
72491                     .call(uiSplash(context))
72492                     .call(uiRestore(context));
72493             }
72494
72495             context.container()
72496                 .call(uiShortcuts(context));
72497         }
72498
72499         var authenticating = uiLoading(context)
72500             .message(t('loading_auth'))
72501             .blocking(true);
72502
72503         context.connection()
72504             .on('authLoading.ui', function() {
72505                 context.container()
72506                     .call(authenticating);
72507             })
72508             .on('authDone.ui', function() {
72509                 authenticating.close();
72510             });
72511
72512         uiInitCounter++;
72513
72514         if (hash.startWalkthrough) {
72515             hash.startWalkthrough = false;
72516             context.container().call(uiIntro(context));
72517         }
72518     }
72519
72520
72521     var renderCallback;
72522
72523     function ui(node, callback) {
72524         renderCallback = callback;
72525         var container = select(node);
72526         context.container(container);
72527         context.loadLocale(function(err) {
72528             if (!err) {
72529                 render(container);
72530             }
72531             if (callback) {
72532                 callback(err);
72533             }
72534         });
72535     }
72536
72537
72538     ui.restart = function(arg) {
72539         context.locale(arg);
72540         context.loadLocale(function(err) {
72541             if (!err) {
72542                 context.container().selectAll('*').remove();
72543                 render(context.container());
72544                 if (renderCallback) renderCallback();
72545             }
72546         });
72547     };
72548
72549
72550     ui.sidebar = uiSidebar(context);
72551
72552     return ui;
72553 }
72554
72555 var changeset;
72556 var readOnlyTags = ['created_by', 'imagery_used', 'host', 'locale'];
72557
72558
72559 function uiCommit(context) {
72560     var dispatch$$1 = dispatch('cancel', 'save');
72561
72562
72563     function commit(selection$$1) {
72564         if (!changeset) {
72565             var detected = utilDetect(),
72566                 tags = {
72567                     created_by: ('iD ' + context.version).substr(0, 255),
72568                     imagery_used: context.history().imageryUsed().join(';').substr(0, 255),
72569                     host: detected.host.substr(0, 255),
72570                     locale: detected.locale.substr(0, 255)
72571                 };
72572
72573             changeset = new osmChangeset({ tags: tags });
72574         }
72575
72576
72577         var changes = context.history().changes(),
72578             summary = context.history().difference().summary(),
72579             rawTagEditor = uiRawTagEditor(context).on('change', changeTags),
72580             comment = context.storage('comment') || '',
72581             commentDate = +context.storage('commentDate') || 0,
72582             currDate = Date.now(),
72583             cutoff = 2 * 86400 * 1000;   // 2 days
72584
72585         // expire the stored comment if it is too old - #3947
72586         if (commentDate > currDate || currDate - commentDate > cutoff) {
72587             comment = '';
72588         }
72589
72590         selection$$1
72591             .append('div')
72592             .attr('class', 'header fillL')
72593             .append('h3')
72594             .text(t('commit.title'));
72595
72596         var body = selection$$1
72597             .append('div')
72598             .attr('class', 'body');
72599
72600         var commentSection = body
72601             .append('div')
72602             .attr('class', 'modal-section form-field commit-form');
72603
72604         commentSection
72605             .append('label')
72606             .attr('class', 'form-label')
72607             .text(t('commit.message_label'));
72608
72609         var commentField = commentSection
72610             .append('textarea')
72611             .attr('class', 'commit-form-comment')
72612             .attr('placeholder', t('commit.description_placeholder'))
72613             .attr('maxlength', 255)
72614             .property('value', comment)
72615             .on('input.save', change(true))
72616             .on('change.save', change())
72617             .on('blur.save', function() {
72618                 context.storage('comment', this.value);
72619                 context.storage('commentDate', Date.now());
72620             });
72621
72622
72623         commentField.node().select();
72624
72625         context.connection().userChangesets(function (err, changesets) {
72626             if (err) return;
72627
72628             var comments = changesets.map(function(changeset) {
72629                 return {
72630                     title: changeset.tags.comment,
72631                     value: changeset.tags.comment
72632                 };
72633             });
72634
72635             commentField
72636                 .call(d3combobox()
72637                     .container(context.container())
72638                     .caseSensitive(true)
72639                     .data(lodash.uniqBy(comments, 'title'))
72640                 );
72641         });
72642
72643         var clippyArea = commentSection.append('div')
72644             .attr('class', 'clippy-area');
72645
72646         var changeSetInfo = commentSection.append('div')
72647             .attr('class', 'changeset-info');
72648
72649         changeSetInfo.append('a')
72650             .attr('target', '_blank')
72651             .attr('tabindex', -1)
72652             .call(svgIcon('#icon-out-link', 'inline'))
72653             .attr('href', t('commit.about_changeset_comments_link'))
72654             .append('span')
72655             .text(t('commit.about_changeset_comments'));
72656
72657
72658         // Warnings
72659         var warnings = body.selectAll('div.warning-section')
72660             .data([context.history().validate(changes)]);
72661
72662         warnings = warnings.enter()
72663             .append('div')
72664             .attr('class', 'modal-section warning-section fillL2')
72665             .style('display', function(d) { return lodash.isEmpty(d) ? 'none' : null; })
72666             .style('background', '#ffb')
72667             .merge(warnings);
72668
72669         warnings
72670             .append('h3')
72671             .text(t('commit.warnings'));
72672
72673         warnings
72674             .append('ul')
72675             .attr('class', 'changeset-list');
72676
72677         var warningLi = warnings.select('ul').selectAll('li')
72678             .data(function(d) { return d; });
72679
72680         warningLi = warningLi.enter()
72681             .append('li')
72682             .on('mouseover', mouseover)
72683             .on('mouseout', mouseout)
72684             .on('click', warningClick)
72685             .merge(warningLi);
72686
72687         warningLi
72688             .call(svgIcon('#icon-alert', 'pre-text'));
72689
72690         warningLi
72691             .append('strong')
72692             .text(function(d) { return d.message; });
72693
72694         warningLi.filter(function(d) { return d.tooltip; })
72695             .call(tooltip()
72696                 .title(function(d) { return d.tooltip; })
72697                 .placement('top')
72698             );
72699
72700
72701         // Upload Explanation
72702         var saveSection = body
72703             .append('div')
72704             .attr('class','modal-section save-section fillL cf');
72705
72706         var prose = saveSection
72707             .append('p')
72708             .attr('class', 'commit-info')
72709             .html(t('commit.upload_explanation'));
72710
72711
72712         context.connection().userDetails(function(err, user) {
72713             if (err) return;
72714
72715             var userLink = select(document.createElement('div'));
72716
72717             if (user.image_url) {
72718                 userLink
72719                     .append('img')
72720                     .attr('src', user.image_url)
72721                     .attr('class', 'icon pre-text user-icon');
72722             }
72723
72724             userLink
72725                 .append('a')
72726                 .attr('class','user-info')
72727                 .text(user.display_name)
72728                 .attr('href', context.connection().userURL(user.display_name))
72729                 .attr('tabindex', -1)
72730                 .attr('target', '_blank');
72731
72732             prose
72733                 .html(t('commit.upload_explanation_with_user', { user: userLink.html() }));
72734         });
72735
72736
72737         // Buttons
72738         var buttonSection = saveSection
72739             .append('div')
72740             .attr('class', 'buttons fillL cf');
72741
72742         var cancelButton = buttonSection
72743             .append('button')
72744             .attr('class', 'secondary-action col5 button cancel-button')
72745             .on('click.cancel', function() {
72746                 dispatch$$1.call('cancel');
72747             });
72748
72749         cancelButton
72750             .append('span')
72751             .attr('class', 'label')
72752             .text(t('commit.cancel'));
72753
72754         var saveButton = buttonSection
72755             .append('button')
72756             .attr('class', 'action col5 button save-button')
72757             .attr('disabled', function() {
72758                 var n = select('.commit-form textarea').node();
72759                 return (n && n.value.length) ? null : true;
72760             })
72761             .on('click.save', function() {
72762                 dispatch$$1.call('save', this, changeset);
72763             });
72764
72765         saveButton
72766             .append('span')
72767             .attr('class', 'label')
72768             .text(t('commit.save'));
72769
72770
72771         // Raw Tag Editor
72772         var tagSection = body
72773             .append('div')
72774             .attr('class', 'modal-section tag-section raw-tag-editor');
72775
72776
72777         // Changes
72778         var changeSection = body
72779             .append('div')
72780             .attr('class', 'commit-section modal-section fillL2');
72781
72782         changeSection.append('h3')
72783             .text(t('commit.changes', { count: summary.length }));
72784
72785         var li = changeSection
72786             .append('ul')
72787             .attr('class', 'changeset-list')
72788             .selectAll('li')
72789             .data(summary);
72790
72791         li = li.enter()
72792             .append('li')
72793             .on('mouseover', mouseover)
72794             .on('mouseout', mouseout)
72795             .on('click', zoomToEntity)
72796             .merge(li);
72797
72798         li.each(function(d) {
72799             select(this)
72800                 .call(svgIcon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
72801         });
72802
72803         li.append('span')
72804             .attr('class', 'change-type')
72805             .text(function(d) { return t('commit.' + d.changeType) + ' '; });
72806
72807         li.append('strong')
72808             .attr('class', 'entity-type')
72809             .text(function(d) {
72810                 var matched = context.presets().match(d.entity, d.graph);
72811                 return (matched && matched.name()) || utilDisplayType(d.entity.id);
72812             });
72813
72814         li.append('span')
72815             .attr('class', 'entity-name')
72816             .text(function(d) {
72817                 var name = utilDisplayName(d.entity) || '',
72818                     string = '';
72819                 if (name !== '') string += ':';
72820                 return string += ' ' + name;
72821             });
72822
72823         li.style('opacity', 0)
72824             .transition()
72825             .style('opacity', 1);
72826
72827
72828         // Call change() off the bat, in case a changeset
72829         // comment is recovered from localStorage
72830         utilTriggerEvent(commentField, 'input');
72831
72832
72833         function mouseover(d) {
72834             if (d.entity) {
72835                 context.surface().selectAll(
72836                     utilEntityOrMemberSelector([d.entity.id], context.graph())
72837                 ).classed('hover', true);
72838             }
72839         }
72840
72841
72842         function mouseout() {
72843             context.surface().selectAll('.hover')
72844                 .classed('hover', false);
72845         }
72846
72847
72848         function warningClick(d) {
72849             if (d.entity) {
72850                 context.map().zoomTo(d.entity);
72851                 context.enter(modeSelect(context, [d.entity.id]));
72852             }
72853         }
72854
72855
72856         function zoomToEntity(change) {
72857             var entity = change.entity;
72858             if (change.changeType !== 'deleted' &&
72859                 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
72860                 context.map().zoomTo(entity);
72861                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph()))
72862                     .classed('hover', true);
72863             }
72864         }
72865
72866
72867         function checkComment(comment) {
72868             // Save button disabled if there is no comment..
72869             selectAll('.save-section .save-button')
72870                 .attr('disabled', (comment.length ? null : true));
72871
72872             // Warn if comment mentions Google..
72873             var googleWarning = clippyArea
72874                .html('')
72875                .selectAll('a')
72876                .data(comment.match(/google/i) ? [true] : []);
72877
72878             googleWarning.exit()
72879                 .remove();
72880
72881             googleWarning.enter()
72882                .append('a')
72883                .attr('target', '_blank')
72884                .attr('tabindex', -1)
72885                .call(svgIcon('#icon-alert', 'inline'))
72886                .attr('href', t('commit.google_warning_link'))
72887                .append('span')
72888                .text(t('commit.google_warning'));
72889         }
72890
72891
72892         function change(onInput) {
72893             return function() {
72894                 var comment = commentField.property('value').trim();
72895                 if (!onInput) {
72896                     commentField.property('value', comment);
72897                 }
72898
72899                 checkComment(comment);
72900
72901                 var changeset = updateChangeset({ comment: comment });
72902                 var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
72903
72904                 tagSection
72905                     .call(rawTagEditor
72906                         .expanded(expanded)
72907                         .readOnlyTags(readOnlyTags)
72908                         .tags(lodash.clone(changeset.tags))
72909                     );
72910             };
72911         }
72912
72913
72914         function changeTags(changed) {
72915             if (changed.hasOwnProperty('comment')) {
72916                 if (changed.comment === undefined) {
72917                     changed.comment = '';
72918                 }
72919                 changed.comment = changed.comment.trim();
72920                 commentField.property('value', changed.comment);
72921             }
72922             updateChangeset(changed);
72923             utilTriggerEvent(commentField, 'input');
72924         }
72925
72926
72927         function updateChangeset(changed) {
72928             var tags = lodash.clone(changeset.tags);
72929
72930             lodash.forEach(changed, function(v, k) {
72931                 k = k.trim().substr(0, 255);
72932                 if (readOnlyTags.indexOf(k) !== -1) return;
72933
72934                 if (k !== '' && v !== undefined) {
72935                     tags[k] = v.trim().substr(0, 255);
72936                 } else {
72937                     delete tags[k];
72938                 }
72939             });
72940
72941             if (!lodash.isEqual(changeset.tags, tags)) {
72942                 changeset = changeset.update({ tags: tags });
72943             }
72944
72945             return changeset;
72946         }
72947
72948     }
72949
72950
72951     commit.reset = function() {
72952         changeset = null;
72953     };
72954
72955
72956     return utilRebind(commit, dispatch$$1, 'on');
72957 }
72958
72959 function uiConfirm(selection) {
72960     var modalSelection = uiModal(selection);
72961
72962     modalSelection.select('.modal')
72963         .classed('modal-alert', true);
72964
72965     var section = modalSelection.select('.content');
72966
72967     section.append('div')
72968         .attr('class', 'modal-section header');
72969
72970     section.append('div')
72971         .attr('class', 'modal-section message-text');
72972
72973     var buttons = section.append('div')
72974         .attr('class', 'modal-section buttons cf');
72975
72976
72977     modalSelection.okButton = function() {
72978         buttons
72979             .append('button')
72980             .attr('class', 'action col4')
72981             .on('click.confirm', function() {
72982                 modalSelection.remove();
72983             })
72984             .text(t('confirm.okay'));
72985
72986         return modalSelection;
72987     };
72988
72989
72990     return modalSelection;
72991 }
72992
72993 function uiConflicts(context) {
72994     var dispatch$$1 = dispatch('download', 'cancel', 'save'),
72995         list;
72996
72997
72998     function conflicts(selection$$1) {
72999         var header = selection$$1
73000             .append('div')
73001             .attr('class', 'header fillL');
73002
73003         header
73004             .append('button')
73005             .attr('class', 'fr')
73006             .on('click', function() { dispatch$$1.call('cancel'); })
73007             .call(svgIcon('#icon-close'));
73008
73009         header
73010             .append('h3')
73011             .text(t('save.conflict.header'));
73012
73013         var body = selection$$1
73014             .append('div')
73015             .attr('class', 'body fillL');
73016
73017         body
73018             .append('div')
73019             .attr('class', 'conflicts-help')
73020             .text(t('save.conflict.help'))
73021             .append('a')
73022             .attr('class', 'conflicts-download')
73023             .text(t('save.conflict.download_changes'))
73024             .on('click.download', function() { dispatch$$1.call('download'); });
73025
73026         body
73027             .append('div')
73028             .attr('class', 'conflict-container fillL3')
73029             .call(showConflict, 0);
73030
73031         body
73032             .append('div')
73033             .attr('class', 'conflicts-done')
73034             .attr('opacity', 0)
73035             .style('display', 'none')
73036             .text(t('save.conflict.done'));
73037
73038         var buttons = body
73039             .append('div')
73040             .attr('class','buttons col12 joined conflicts-buttons');
73041
73042         buttons
73043             .append('button')
73044             .attr('disabled', list.length > 1)
73045             .attr('class', 'action conflicts-button col6')
73046             .text(t('save.title'))
73047             .on('click.try_again', function() { dispatch$$1.call('save'); });
73048
73049         buttons
73050             .append('button')
73051             .attr('class', 'secondary-action conflicts-button col6')
73052             .text(t('confirm.cancel'))
73053             .on('click.cancel', function() { dispatch$$1.call('cancel'); });
73054     }
73055
73056
73057     function showConflict(selection$$1, index) {
73058         if (index < 0 || index >= list.length) return;
73059
73060         var parent = select(selection$$1.node().parentNode);
73061
73062         // enable save button if this is the last conflict being reviewed..
73063         if (index === list.length - 1) {
73064             window.setTimeout(function() {
73065                 parent.select('.conflicts-button')
73066                     .attr('disabled', null);
73067
73068                 parent.select('.conflicts-done')
73069                     .transition()
73070                     .attr('opacity', 1)
73071                     .style('display', 'block');
73072             }, 250);
73073         }
73074
73075         var item = selection$$1
73076             .selectAll('.conflict')
73077             .data([list[index]]);
73078
73079         var enter = item.enter()
73080             .append('div')
73081             .attr('class', 'conflict');
73082
73083         enter
73084             .append('h4')
73085             .attr('class', 'conflict-count')
73086             .text(t('save.conflict.count', { num: index + 1, total: list.length }));
73087
73088         enter
73089             .append('a')
73090             .attr('class', 'conflict-description')
73091             .attr('href', '#')
73092             .text(function(d) { return d.name; })
73093             .on('click', function(d) {
73094                 zoomToEntity(d.id);
73095                 event.preventDefault();
73096             });
73097
73098         var details = enter
73099             .append('div')
73100             .attr('class', 'conflict-detail-container');
73101
73102         details
73103             .append('ul')
73104             .attr('class', 'conflict-detail-list')
73105             .selectAll('li')
73106             .data(function(d) { return d.details || []; })
73107             .enter()
73108             .append('li')
73109             .attr('class', 'conflict-detail-item')
73110             .html(function(d) { return d; });
73111
73112         details
73113             .append('div')
73114             .attr('class', 'conflict-choices')
73115             .call(addChoices);
73116
73117         details
73118             .append('div')
73119             .attr('class', 'conflict-nav-buttons joined cf')
73120             .selectAll('button')
73121             .data(['previous', 'next'])
73122             .enter()
73123             .append('button')
73124             .text(function(d) { return t('save.conflict.' + d); })
73125             .attr('class', 'conflict-nav-button action col6')
73126             .attr('disabled', function(d, i) {
73127                 return (i === 0 && index === 0) ||
73128                     (i === 1 && index === list.length - 1) || null;
73129             })
73130             .on('click', function(d, i) {
73131                 var container = parent.select('.conflict-container'),
73132                 sign = (i === 0 ? -1 : 1);
73133
73134                 container
73135                     .selectAll('.conflict')
73136                     .remove();
73137
73138                 container
73139                     .call(showConflict, index + sign);
73140
73141                 event.preventDefault();
73142             });
73143
73144         item.exit()
73145             .remove();
73146     }
73147
73148
73149     function addChoices(selection$$1) {
73150         var choices = selection$$1
73151             .append('ul')
73152             .attr('class', 'layer-list')
73153             .selectAll('li')
73154             .data(function(d) { return d.choices || []; });
73155
73156         var enter = choices.enter()
73157             .append('li')
73158             .attr('class', 'layer');
73159
73160         var label = enter
73161             .append('label');
73162
73163         label
73164             .append('input')
73165             .attr('type', 'radio')
73166             .attr('name', function(d) { return d.id; })
73167             .on('change', function(d, i) {
73168                 var ul = this.parentNode.parentNode.parentNode;
73169                 ul.__data__.chosen = i;
73170                 choose(ul, d);
73171             });
73172
73173         label
73174             .append('span')
73175             .text(function(d) { return d.text; });
73176
73177         choices
73178             .each(function(d, i) {
73179                 var ul = this.parentNode;
73180                 if (ul.__data__.chosen === i) choose(ul, d);
73181             });
73182     }
73183
73184
73185     function choose(ul, datum) {
73186         if (event) event.preventDefault();
73187
73188         select(ul)
73189             .selectAll('li')
73190             .classed('active', function(d) { return d === datum; })
73191             .selectAll('input')
73192             .property('checked', function(d) { return d === datum; });
73193
73194         var extent$$1 = geoExtent$$1(),
73195             entity;
73196
73197         entity = context.graph().hasEntity(datum.id);
73198         if (entity) extent$$1._extend(entity.extent(context.graph()));
73199
73200         datum.action();
73201
73202         entity = context.graph().hasEntity(datum.id);
73203         if (entity) extent$$1._extend(entity.extent(context.graph()));
73204
73205         zoomToEntity(datum.id, extent$$1);
73206     }
73207
73208
73209     function zoomToEntity(id, extent$$1) {
73210         context.surface().selectAll('.hover')
73211             .classed('hover', false);
73212
73213         var entity = context.graph().hasEntity(id);
73214         if (entity) {
73215             if (extent$$1) {
73216                 context.map().trimmedExtent(extent$$1);
73217             } else {
73218                 context.map().zoomTo(entity);
73219             }
73220             context.surface().selectAll(
73221                 utilEntityOrMemberSelector([entity.id], context.graph()))
73222                 .classed('hover', true);
73223         }
73224     }
73225
73226
73227     // The conflict list should be an array of objects like:
73228     // {
73229     //     id: id,
73230     //     name: entityName(local),
73231     //     details: merge.conflicts(),
73232     //     chosen: 1,
73233     //     choices: [
73234     //         choice(id, keepMine, forceLocal),
73235     //         choice(id, keepTheirs, forceRemote)
73236     //     ]
73237     // }
73238     conflicts.list = function(_) {
73239         if (!arguments.length) return list;
73240         list = _;
73241         return conflicts;
73242     };
73243
73244
73245     return utilRebind(conflicts, dispatch$$1, 'on');
73246 }
73247
73248 function uiEditMenu(context, operations) {
73249     var menu,
73250         center = [0, 0],
73251         offset = [0, 0],
73252         tooltip;
73253
73254     var p = 8,               // top padding
73255         m = 4,               // top margin
73256         h = 15,              // height of icon
73257         vpBottomMargin = 45, // viewport bottom margin
73258         vpSideMargin = 35,   // viewport side margin
73259         buttonWidth = 44,
73260         buttonHeight = (2 * p + h),
73261         menuWidth = buttonWidth,
73262         menuHeight = (2 * m) + operations.length * buttonHeight,
73263         menuSideMargin = 10,
73264         tooltipWidth = 200,
73265         tooltipHeight = 200;  // a reasonable guess, real height depends on tooltip contents
73266
73267
73268     var editMenu = function (selection$$1) {
73269         if (!operations.length) return;
73270
73271         selection$$1.node().parentNode.focus();
73272
73273         var isRTL = textDirection === 'rtl',
73274             viewport = context.surfaceRect();
73275
73276         if (!isRTL && (center[0] + menuSideMargin + menuWidth) > (viewport.width - vpSideMargin)) {
73277             // menu is going left-to-right and near right viewport edge, go left instead
73278             isRTL = true;
73279         } else if (isRTL && (center[0] - menuSideMargin - menuWidth) < vpSideMargin) {
73280             // menu is going right-to-left and near left viewport edge, go right instead
73281             isRTL = false;
73282         }
73283
73284         offset[0] = (isRTL ? -1 * (menuSideMargin + menuWidth) : menuSideMargin);
73285
73286         if (center[1] + menuHeight > (viewport.height - vpBottomMargin)) {
73287             // menu is near bottom viewport edge, shift upwards
73288             offset[1] = -1 * (center[1] + menuHeight - viewport.height + vpBottomMargin);
73289         }
73290
73291         var origin = [ center[0] + offset[0], center[1] + offset[1] ];
73292
73293         menu = selection$$1
73294             .append('g')
73295             .attr('class', 'edit-menu')
73296             .attr('transform', 'translate(' + origin + ')')
73297             .attr('opacity', 0);
73298
73299         menu
73300             .transition()
73301             .attr('opacity', 1);
73302
73303         menu
73304             .append('rect')
73305             .attr('class', 'edit-menu-background')
73306             .attr('x', 4)
73307             .attr('rx', 4)
73308             .attr('ry', 4)
73309             .attr('width', menuWidth)
73310             .attr('height', menuHeight)
73311             .attr('stroke-linecap', 'round');
73312
73313
73314         var button = menu.selectAll('.edit-menu-item')
73315             .data(operations)
73316             .enter()
73317             .append('g')
73318             .attr('class', function (d) { return 'edit-menu-item edit-menu-item-' + d.id; })
73319             .classed('disabled', function (d) { return d.disabled(); })
73320             .attr('transform', function (d, i) {
73321                 return 'translate(' + geoRoundCoords([
73322                     0,
73323                     m + i * buttonHeight
73324                 ]).join(',') + ')';
73325             });
73326
73327         button
73328             .append('rect')
73329             .attr('x', 4)
73330             .attr('width', buttonWidth)
73331             .attr('height', buttonHeight)
73332             .on('click', click)
73333             .on('mousedown', mousedown)
73334             .on('mouseover', mouseover)
73335             .on('mouseout', mouseout);
73336
73337         button
73338             .append('use')
73339             .attr('width', '20')
73340             .attr('height', '20')
73341             .attr('transform', function () {
73342                 return 'translate(' + [2 * p, 5] + ')';
73343             })
73344             .attr('xlink:href', function (d) { return '#operation-' + d.id; });
73345
73346         tooltip = select(document.body)
73347             .append('div')
73348             .attr('class', 'tooltip-inner edit-menu-tooltip');
73349
73350
73351         function click(operation) {
73352             event.stopPropagation();
73353             if (operation.disabled()) return;
73354             operation();
73355             editMenu.close();
73356         }
73357
73358         function mousedown() {
73359             event.stopPropagation();  // https://github.com/openstreetmap/iD/issues/1869
73360         }
73361
73362         function mouseover(d, i) {
73363             var tipX, tipY;
73364
73365             if (!isRTL) {
73366                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
73367             } else {
73368                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
73369             }
73370
73371             if (tipX + tooltipWidth > viewport.right) {
73372                 // tip is going left-to-right and near right viewport edge, go left instead
73373                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
73374             } else if (tipX < viewport.left) {
73375                 // tip is going right-to-left and near left viewport edge, go right instead
73376                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
73377             }
73378
73379             tipY = viewport.top + origin[1] + (i * buttonHeight);
73380             if (tipY + tooltipHeight > viewport.bottom) {
73381                 // tip is near bottom viewport edge, shift upwards
73382                 tipY -= tipY + tooltipHeight - viewport.bottom;
73383             }
73384
73385             tooltip
73386                 .style('left', tipX + 'px')
73387                 .style('top', tipY + 'px')
73388                 .style('display', 'block')
73389                 .html(uiTooltipHtml(d.tooltip(), d.keys[0], d.title));
73390         }
73391
73392         function mouseout() {
73393             tooltip.style('display', 'none');
73394         }
73395     };
73396
73397
73398     editMenu.close = function () {
73399         if (menu) {
73400             menu
73401                 .style('pointer-events', 'none')
73402                 .transition()
73403                 .attr('opacity', 0)
73404                 .remove();
73405         }
73406
73407         if (tooltip) {
73408             tooltip.remove();
73409         }
73410     };
73411
73412
73413     editMenu.center = function (_) {
73414         if (!arguments.length) return center;
73415         center = _;
73416         return editMenu;
73417     };
73418
73419
73420     return editMenu;
73421 }
73422
73423 var timer$1;
73424
73425 function uiFlash(showDuration) {
73426     showDuration = showDuration || 1500;
73427
73428     if (timer$1) {
73429         timer$1.stop();
73430     }
73431
73432     select('#footer-wrap')
73433         .attr('class', 'footer-hide');
73434     select('#flash-wrap')
73435         .attr('class', 'footer-show');
73436
73437     var content = select('#flash-wrap').selectAll('.content')
73438         .data([0]);
73439
73440     content = content.enter()
73441         .append('div')
73442         .attr('class', 'content')
73443         .merge(content);
73444
73445     timer$1 = timeout$1(function() {
73446         timer$1 = null;
73447         select('#footer-wrap')
73448             .attr('class', 'footer-show');
73449         select('#flash-wrap')
73450             .attr('class', 'footer-hide');
73451     }, showDuration);
73452
73453
73454     return content;
73455 }
73456
73457 function uiLasso(context) {
73458     var group, polygon;
73459
73460     lasso.coordinates = [];
73461
73462     function lasso(selection$$1) {
73463         context.container()
73464             .classed('lasso', true);
73465
73466         group = selection$$1
73467             .append('g')
73468             .attr('class', 'lasso hide');
73469
73470         polygon = group
73471             .append('path')
73472             .attr('class', 'lasso-path');
73473
73474         group
73475             .call(uiToggle(true));
73476     }
73477
73478
73479     function draw() {
73480         if (polygon) {
73481             polygon.data([lasso.coordinates])
73482                 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
73483         }
73484     }
73485
73486
73487     lasso.extent = function () {
73488         return lasso.coordinates.reduce(function(extent$$1, point) {
73489             return extent$$1.extend(geoExtent$$1(point));
73490         }, geoExtent$$1());
73491     };
73492
73493
73494     lasso.p = function(_) {
73495         if (!arguments.length) return lasso;
73496         lasso.coordinates.push(_);
73497         draw();
73498         return lasso;
73499     };
73500
73501
73502     lasso.close = function() {
73503         if (group) {
73504             group.call(uiToggle(false, function() {
73505                 select(this).remove();
73506             }));
73507         }
73508         context.container().classed('lasso', false);
73509     };
73510
73511
73512     return lasso;
73513 }
73514
73515 function uiRadialMenu(context, operations) {
73516     var menu,
73517         center = [0, 0],
73518         tooltip;
73519
73520
73521     var radialMenu = function(selection$$1) {
73522         if (!operations.length) return;
73523
73524         selection$$1.node().parentNode.focus();
73525
73526         function click(operation) {
73527             event.stopPropagation();
73528             if (operation.disabled()) return;
73529             operation();
73530             radialMenu.close();
73531         }
73532
73533         menu = selection$$1
73534             .append('g')
73535             .attr('class', 'radial-menu')
73536             .attr('transform', 'translate(' + center + ')')
73537             .attr('opacity', 0);
73538
73539         menu
73540             .transition()
73541             .attr('opacity', 1);
73542
73543         var r = 50,
73544             a = Math.PI / 4,
73545             a0 = -Math.PI / 4,
73546             a1 = a0 + (operations.length - 1) * a;
73547
73548         menu
73549             .append('path')
73550             .attr('class', 'radial-menu-background')
73551             .attr('d', 'M' + r * Math.sin(a0) + ',' +
73552                              r * Math.cos(a0) +
73553                       ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
73554                              (r * Math.sin(a1) + 1e-3) + ',' +
73555                              (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
73556             .attr('stroke-width', 50)
73557             .attr('stroke-linecap', 'round');
73558
73559         var button = menu.selectAll()
73560             .data(operations)
73561             .enter()
73562             .append('g')
73563             .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
73564             .classed('disabled', function(d) { return d.disabled(); })
73565             .attr('transform', function(d, i) {
73566                 return 'translate(' + geoRoundCoords([
73567                         r * Math.sin(a0 + i * a),
73568                         r * Math.cos(a0 + i * a)]).join(',') + ')';
73569             });
73570
73571         button
73572             .append('circle')
73573             .attr('r', 15)
73574             .on('click', click)
73575             .on('mousedown', mousedown)
73576             .on('mouseover', mouseover)
73577             .on('mouseout', mouseout);
73578
73579         button
73580             .append('use')
73581             .attr('transform', 'translate(-10,-10)')
73582             .attr('width', '20')
73583             .attr('height', '20')
73584             .attr('xlink:href', function(d) { return '#operation-' + d.id; });
73585
73586         tooltip = select(document.body)
73587             .append('div')
73588             .attr('class', 'tooltip-inner radial-menu-tooltip');
73589
73590         function mousedown() {
73591             event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
73592         }
73593
73594         function mouseover(d, i) {
73595             var rect = context.surfaceRect(),
73596                 angle = a0 + i * a,
73597                 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
73598                 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
73599                 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
73600                 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
73601
73602             tooltip
73603                 .style('top', null)
73604                 .style('left', null)
73605                 .style('bottom', null)
73606                 .style('right', null)
73607                 .style('display', 'block')
73608                 .html(uiTooltipHtml(d.tooltip(), d.keys[0]));
73609
73610             if (i === 0) {
73611                 tooltip
73612                     .style('right', right)
73613                     .style('top', top);
73614             } else if (i >= 4) {
73615                 tooltip
73616                     .style('left', left)
73617                     .style('bottom', bottom);
73618             } else {
73619                 tooltip
73620                     .style('left', left)
73621                     .style('top', top);
73622             }
73623         }
73624
73625         function mouseout() {
73626             tooltip.style('display', 'none');
73627         }
73628     };
73629
73630
73631     radialMenu.close = function() {
73632         if (menu) {
73633             menu
73634                 .style('pointer-events', 'none')
73635                 .transition()
73636                 .attr('opacity', 0)
73637                 .remove();
73638         }
73639
73640         if (tooltip) {
73641             tooltip.remove();
73642         }
73643     };
73644
73645
73646     radialMenu.center = function(_) {
73647         if (!arguments.length) return center;
73648         center = _;
73649         return radialMenu;
73650     };
73651
73652
73653     return radialMenu;
73654 }
73655
73656 function uiSelectionList(context, selectedIDs) {
73657
73658     function selectEntity(entity) {
73659         context.enter(modeSelect(context, [entity.id]));
73660     }
73661
73662
73663     function deselectEntity(entity) {
73664         event.stopPropagation();
73665         var index = selectedIDs.indexOf(entity.id);
73666         if (index > -1) {
73667             selectedIDs.splice(index, 1);
73668         }
73669         context.enter(modeSelect(context, selectedIDs));
73670     }
73671
73672
73673     function selectionList(selection$$1) {
73674         selection$$1.classed('selection-list-pane', true);
73675
73676         var header = selection$$1
73677             .append('div')
73678             .attr('class', 'header fillL cf');
73679
73680         header
73681             .append('h3')
73682             .text(t('inspector.multiselect'));
73683
73684         var listWrap = selection$$1
73685             .append('div')
73686             .attr('class', 'inspector-body');
73687
73688         var list = listWrap
73689             .append('div')
73690             .attr('class', 'feature-list cf');
73691
73692         context.history().on('change.selection-list', drawList);
73693         drawList();
73694
73695
73696         function drawList() {
73697             var entities = selectedIDs
73698                 .map(function(id) { return context.hasEntity(id); })
73699                 .filter(function(entity) { return entity; });
73700
73701             var items = list.selectAll('.feature-list-item')
73702                 .data(entities, osmEntity$$1.key);
73703
73704             items.exit()
73705                 .remove();
73706
73707             // Enter
73708             var enter = items.enter()
73709                 .append('div')
73710                 .attr('class', 'feature-list-item')
73711                 .on('click', selectEntity);
73712
73713             var label = enter
73714                 .append('button')
73715                 .attr('class', 'label');
73716
73717             enter
73718                 .append('button')
73719                 .attr('class', 'close')
73720                 .on('click', deselectEntity)
73721                 .call(svgIcon('#icon-close'));
73722
73723             label
73724                 .append('span')
73725                 .attr('class', 'entity-geom-icon')
73726                 .call(svgIcon('', 'pre-text'));
73727
73728             label
73729                 .append('span')
73730                 .attr('class', 'entity-type');
73731
73732             label
73733                 .append('span')
73734                 .attr('class', 'entity-name');
73735
73736             // Update
73737             items = items.merge(enter);
73738
73739             items.selectAll('.entity-geom-icon use')
73740                 .attr('href', function() {
73741                     var entity = this.parentNode.parentNode.__data__;
73742                     return '#icon-' + context.geometry(entity.id);
73743                 });
73744
73745             items.selectAll('.entity-type')
73746                 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
73747
73748             items.selectAll('.entity-name')
73749                 .text(function(entity) { return utilDisplayName(entity); });
73750         }
73751     }
73752
73753     return selectionList;
73754 }
73755
73756 function uiSourceSwitch(context) {
73757     var keys$$1;
73758
73759
73760     function click() {
73761         event.preventDefault();
73762
73763         if (context.history().hasChanges() &&
73764             !window.confirm(t('source_switch.lose_changes'))) return;
73765
73766         var live = select(this)
73767             .classed('live');
73768
73769         context.connection()
73770             .switch(live ? keys$$1[1] : keys$$1[0]);
73771
73772         context.enter(modeBrowse(context));
73773         context.flush();
73774
73775         select(this)
73776             .text(live ? t('source_switch.dev') : t('source_switch.live'))
73777             .classed('live', !live);
73778     }
73779
73780     var sourceSwitch = function(selection$$1) {
73781         selection$$1
73782             .append('a')
73783             .attr('href', '#')
73784             .text(t('source_switch.live'))
73785             .classed('live', true)
73786             .attr('tabindex', -1)
73787             .on('click', click);
73788     };
73789
73790
73791     sourceSwitch.keys = function(_) {
73792         if (!arguments.length) return keys$$1;
73793         keys$$1 = _;
73794         return sourceSwitch;
73795     };
73796
73797
73798     return sourceSwitch;
73799 }
73800
73801 function uiSuccess(context) {
73802     var dispatch$$1 = dispatch('cancel'),
73803         changeset;
73804
73805
73806     function success(selection$$1) {
73807         var header = selection$$1
73808             .append('div')
73809             .attr('class', 'header fillL');
73810
73811         header
73812             .append('button')
73813             .attr('class', 'fr')
73814             .on('click', function() { dispatch$$1.call('cancel'); })
73815             .call(svgIcon('#icon-close'));
73816
73817         header
73818             .append('h3')
73819             .text(t('success.just_edited'));
73820
73821         var body = selection$$1
73822             .append('div')
73823             .attr('class', 'body save-success fillL');
73824
73825         body
73826             .append('p')
73827             .html(t('success.help_html'));
73828
73829         body
73830             .append('a')
73831             .attr('class', 'details')
73832             .attr('target', '_blank')
73833             .attr('tabindex', -1)
73834             .call(svgIcon('#icon-out-link', 'inline'))
73835             .attr('href', t('success.help_link_url'))
73836             .append('span')
73837             .text(t('success.help_link_text'));
73838
73839         var changesetURL = context.connection().changesetURL(changeset.id);
73840
73841
73842         var viewOnOsm = body
73843             .append('a')
73844             .attr('class', 'button col12 osm')
73845             .attr('target', '_blank')
73846             .attr('href', changesetURL);
73847
73848         viewOnOsm
73849             .append('svg')
73850             .attr('class', 'logo logo-osm')
73851             .append('use')
73852             .attr('xlink:href', '#logo-osm');
73853
73854         viewOnOsm
73855             .append('div')
73856             .text(t('success.view_on_osm'));
73857
73858
73859         var message = (changeset.tags.comment || t('success.edited_osm')).substring(0, 130) +
73860             ' ' + context.connection().changesetURL(changeset.id);
73861
73862         var sharing = {
73863             facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
73864             twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
73865             google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
73866         };
73867
73868         body.selectAll('.button.social')
73869             .data(entries(sharing))
73870             .enter()
73871             .append('a')
73872             .attr('class', 'button social col4')
73873             .attr('target', '_blank')
73874             .attr('href', function(d) { return d.value; })
73875             .call(tooltip()
73876                 .title(function(d) { return t('success.' + d.key); })
73877                 .placement('bottom'))
73878             .each(function(d) { select(this).call(svgIcon('#logo-' + d.key, 'social')); });
73879     }
73880
73881
73882     success.changeset = function(_) {
73883         if (!arguments.length) return changeset;
73884         changeset = _;
73885         return success;
73886     };
73887
73888
73889     return utilRebind(success, dispatch$$1, 'on');
73890 }
73891
73892 function coreHistory(context) {
73893     var imageryUsed = ['Bing'],
73894         dispatch$$1 = dispatch('change', 'undone', 'redone'),
73895         lock = utilSessionMutex('lock'),
73896         duration = 150,
73897         checkpoints = {},
73898         stack$$1, index, tree$$1;
73899
73900
73901     // internal _act, accepts list of actions and eased time
73902     function _act(actions, t) {
73903         actions = Array.prototype.slice.call(actions);
73904
73905         var annotation;
73906
73907         if (!lodash.isFunction(lodash.last(actions))) {
73908             annotation = actions.pop();
73909         }
73910
73911         stack$$1[index].transform = context.projection.transform();
73912         stack$$1[index].selectedIDs = context.selectedIDs();
73913
73914         var graph = stack$$1[index].graph;
73915         for (var i = 0; i < actions.length; i++) {
73916             graph = actions[i](graph, t);
73917         }
73918
73919         return {
73920             graph: graph,
73921             annotation: annotation,
73922             imageryUsed: imageryUsed
73923         };
73924     }
73925
73926
73927     // internal _perform with eased time
73928     function _perform(args, t) {
73929         var previous = stack$$1[index].graph;
73930         stack$$1 = stack$$1.slice(0, index + 1);
73931         stack$$1.push(_act(args, t));
73932         index++;
73933         return change(previous);
73934     }
73935
73936
73937     // internal _replace with eased time
73938     function _replace(args, t) {
73939         var previous = stack$$1[index].graph;
73940         // assert(index == stack.length - 1)
73941         stack$$1[index] = _act(args, t);
73942         return change(previous);
73943     }
73944
73945
73946     // internal _overwrite with eased time
73947     function _overwrite(args, t) {
73948         var previous = stack$$1[index].graph;
73949         if (index > 0) {
73950             index--;
73951             stack$$1.pop();
73952         }
73953         stack$$1 = stack$$1.slice(0, index + 1);
73954         stack$$1.push(_act(args, t));
73955         index++;
73956         return change(previous);
73957     }
73958
73959
73960     // determine diffrence and dispatch a change event
73961     function change(previous) {
73962         var difference = coreDifference(previous, history.graph());
73963         dispatch$$1.call('change', this, difference);
73964         return difference;
73965     }
73966
73967
73968     // iD uses namespaced keys so multiple installations do not conflict
73969     function getKey(n) {
73970         return 'iD_' + window.location.origin + '_' + n;
73971     }
73972
73973
73974     var history = {
73975
73976         graph: function() {
73977             return stack$$1[index].graph;
73978         },
73979
73980
73981         base: function() {
73982             return stack$$1[0].graph;
73983         },
73984
73985
73986         merge: function(entities, extent$$1) {
73987             stack$$1[0].graph.rebase(entities, lodash.map(stack$$1, 'graph'), false);
73988             tree$$1.rebase(entities, false);
73989
73990             dispatch$$1.call('change', this, undefined, extent$$1);
73991         },
73992
73993
73994         perform: function() {
73995             // complete any transition already in progress
73996             select(document).interrupt('history.perform');
73997
73998             var transitionable = false,
73999                 action0 = arguments[0];
74000
74001             if (arguments.length === 1 ||
74002                 arguments.length === 2 && !lodash.isFunction(arguments[1])) {
74003                 transitionable = !!action0.transitionable;
74004             }
74005
74006             if (transitionable) {
74007                 var origArguments = arguments;
74008                 select(document)
74009                     .transition('history.perform')
74010                     .duration(duration)
74011                     .ease(linear$1)
74012                     .tween('history.tween', function() {
74013                         return function(t) {
74014                             if (t < 1) _overwrite([action0], t);
74015                         };
74016                     })
74017                     .on('start', function() {
74018                         _perform([action0], 0);
74019                     })
74020                     .on('end interrupt', function() {
74021                         _overwrite(origArguments, 1);
74022                     });
74023
74024             } else {
74025                 return _perform(arguments);
74026             }
74027         },
74028
74029
74030         replace: function() {
74031             select(document).interrupt('history.perform');
74032             return _replace(arguments, 1);
74033         },
74034
74035
74036         // Same as calling pop and then perform
74037         overwrite: function() {
74038             select(document).interrupt('history.perform');
74039             return _overwrite(arguments, 1);
74040         },
74041
74042
74043         pop: function(n) {
74044             select(document).interrupt('history.perform');
74045
74046             var previous = stack$$1[index].graph;
74047             if (isNaN(+n) || +n < 0) {
74048                 n = 1;
74049             }
74050             while (n-- > 0 && index > 0) {
74051                 index--;
74052                 stack$$1.pop();
74053             }
74054             return change(previous);
74055         },
74056
74057
74058         // Back to the previous annotated state or index = 0.
74059         undo: function() {
74060             select(document).interrupt('history.perform');
74061
74062             var previous = stack$$1[index].graph;
74063             while (index > 0) {
74064                 index--;
74065                 if (stack$$1[index].annotation) break;
74066             }
74067
74068             dispatch$$1.call('undone', this, stack$$1[index]);
74069             return change(previous);
74070         },
74071
74072
74073         // Forward to the next annotated state.
74074         redo: function() {
74075             select(document).interrupt('history.perform');
74076
74077             var previous = stack$$1[index].graph;
74078             var tryIndex = index;
74079             while (tryIndex < stack$$1.length - 1) {
74080                 tryIndex++;
74081                 if (stack$$1[tryIndex].annotation) {
74082                     index = tryIndex;
74083                     dispatch$$1.call('redone', this, stack$$1[index]);
74084                     break;
74085                 }
74086             }
74087
74088             return change(previous);
74089         },
74090
74091
74092         undoAnnotation: function() {
74093             var i = index;
74094             while (i >= 0) {
74095                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
74096                 i--;
74097             }
74098         },
74099
74100
74101         redoAnnotation: function() {
74102             var i = index + 1;
74103             while (i <= stack$$1.length - 1) {
74104                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
74105                 i++;
74106             }
74107         },
74108
74109
74110         intersects: function(extent$$1) {
74111             return tree$$1.intersects(extent$$1, stack$$1[index].graph);
74112         },
74113
74114
74115         difference: function() {
74116             var base = stack$$1[0].graph,
74117                 head = stack$$1[index].graph;
74118             return coreDifference(base, head);
74119         },
74120
74121
74122         changes: function(action) {
74123             var base = stack$$1[0].graph,
74124                 head = stack$$1[index].graph;
74125
74126             if (action) {
74127                 head = action(head);
74128             }
74129
74130             var difference = coreDifference(base, head);
74131
74132             return {
74133                 modified: difference.modified(),
74134                 created: difference.created(),
74135                 deleted: difference.deleted()
74136             };
74137         },
74138
74139
74140         validate: function(changes) {
74141             return lodash(Validations)
74142                 .map(function(fn) { return fn()(changes, stack$$1[index].graph); })
74143                 .flatten()
74144                 .value();
74145         },
74146
74147
74148         hasChanges: function() {
74149             return this.difference().length() > 0;
74150         },
74151
74152
74153         imageryUsed: function(sources) {
74154             if (sources) {
74155                 imageryUsed = sources;
74156                 return history;
74157             } else {
74158                 return lodash(stack$$1.slice(1, index + 1))
74159                     .map('imageryUsed')
74160                     .flatten()
74161                     .uniq()
74162                     .without(undefined, 'Custom')
74163                     .value();
74164             }
74165         },
74166
74167
74168         // save the current history state
74169         checkpoint: function(key) {
74170             checkpoints[key] = {
74171                 stack: lodash.cloneDeep(stack$$1),
74172                 index: index
74173             };
74174             return history;
74175         },
74176
74177
74178         // restore history state to a given checkpoint or reset completely
74179         reset: function(key) {
74180             if (key !== undefined && checkpoints.hasOwnProperty(key)) {
74181                 stack$$1 = lodash.cloneDeep(checkpoints[key].stack);
74182                 index = checkpoints[key].index;
74183             } else {
74184                 stack$$1 = [{graph: coreGraph$$1()}];
74185                 index = 0;
74186                 tree$$1 = coreTree(stack$$1[0].graph);
74187                 checkpoints = {};
74188             }
74189             dispatch$$1.call('change');
74190             return history;
74191         },
74192
74193
74194         toIntroGraph: function() {
74195             var nextId = { n: 0, r: 0, w: 0 },
74196                 permIds = {},
74197                 graph = this.graph(),
74198                 baseEntities = {};
74199
74200             // clone base entities..
74201             lodash.forEach(graph.base().entities, function(entity) {
74202                 var copy = lodash.cloneDeepWith(entity, customizer);
74203                 baseEntities[copy.id] = copy;
74204             });
74205
74206             // replace base entities with head entities..
74207             lodash.forEach(graph.entities, function(entity, id) {
74208                 if (entity) {
74209                     var copy = lodash.cloneDeepWith(entity, customizer);
74210                     baseEntities[copy.id] = copy;
74211                 } else {
74212                     delete baseEntities[id];
74213                 }
74214             });
74215
74216             // swap temporary for permanent ids..
74217             lodash.forEach(baseEntities, function(entity) {
74218                 if (Array.isArray(entity.nodes)) {
74219                     entity.nodes = entity.nodes.map(function(node) {
74220                         return permIds[node] || node;
74221                     });
74222                 }
74223                 if (Array.isArray(entity.members)) {
74224                     entity.members = entity.members.map(function(member) {
74225                         member.id = permIds[member.id] || member.id;
74226                         return member;
74227                     });
74228                 }
74229             });
74230
74231             return JSON.stringify({ dataIntroGraph: baseEntities });
74232
74233
74234             function customizer(src) {
74235                 var copy = lodash.omit(lodash.cloneDeep(src), ['type', 'user', 'v', 'version', 'visible']);
74236                 if (lodash.isEmpty(copy.tags)) {
74237                     delete copy.tags;
74238                 }
74239
74240                 if (Array.isArray(copy.loc)) {
74241                     copy.loc[0] = +copy.loc[0].toFixed(6);
74242                     copy.loc[1] = +copy.loc[1].toFixed(6);
74243                 }
74244
74245                 var match = src.id.match(/([nrw])-\d*/);  // temporary id
74246                 if (match !== null) {
74247                     var nrw = match[1], permId;
74248                     do { permId = nrw + (++nextId[nrw]); }
74249                     while (baseEntities.hasOwnProperty(permId));
74250
74251                     copy.id = permIds[src.id] = permId;
74252                 }
74253                 return copy;
74254             }
74255         },
74256
74257
74258         toJSON: function() {
74259             if (!this.hasChanges()) return;
74260
74261             var allEntities = {},
74262                 baseEntities = {},
74263                 base = stack$$1[0];
74264
74265             var s = stack$$1.map(function(i) {
74266                 var modified = [], deleted = [];
74267
74268                 lodash.forEach(i.graph.entities, function(entity, id) {
74269                     if (entity) {
74270                         var key = osmEntity$$1.key(entity);
74271                         allEntities[key] = entity;
74272                         modified.push(key);
74273                     } else {
74274                         deleted.push(id);
74275                     }
74276
74277                     // make sure that the originals of changed or deleted entities get merged
74278                     // into the base of the stack after restoring the data from JSON.
74279                     if (id in base.graph.entities) {
74280                         baseEntities[id] = base.graph.entities[id];
74281                     }
74282                     // get originals of parent entities too
74283                     lodash.forEach(base.graph._parentWays[id], function(parentId) {
74284                         if (parentId in base.graph.entities) {
74285                             baseEntities[parentId] = base.graph.entities[parentId];
74286                         }
74287                     });
74288                 });
74289
74290                 var x = {};
74291
74292                 if (modified.length) x.modified = modified;
74293                 if (deleted.length) x.deleted = deleted;
74294                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
74295                 if (i.annotation) x.annotation = i.annotation;
74296
74297                 return x;
74298             });
74299
74300             return JSON.stringify({
74301                 version: 3,
74302                 entities: lodash.values(allEntities),
74303                 baseEntities: lodash.values(baseEntities),
74304                 stack: s,
74305                 nextIDs: osmEntity$$1.id.next,
74306                 index: index
74307             });
74308         },
74309
74310
74311         fromJSON: function(json$$1, loadChildNodes) {
74312             var h = JSON.parse(json$$1),
74313                 loadComplete = true;
74314
74315             osmEntity$$1.id.next = h.nextIDs;
74316             index = h.index;
74317
74318             if (h.version === 2 || h.version === 3) {
74319                 var allEntities = {};
74320
74321                 h.entities.forEach(function(entity) {
74322                     allEntities[osmEntity$$1.key(entity)] = osmEntity$$1(entity);
74323                 });
74324
74325                 if (h.version === 3) {
74326                     // This merges originals for changed entities into the base of
74327                     // the stack even if the current stack doesn't have them (for
74328                     // example when iD has been restarted in a different region)
74329                     var baseEntities = h.baseEntities.map(function(d) { return osmEntity$$1(d); });
74330                     stack$$1[0].graph.rebase(baseEntities, lodash.map(stack$$1, 'graph'), true);
74331                     tree$$1.rebase(baseEntities, true);
74332
74333                     // When we restore a modified way, we also need to fetch any missing
74334                     // childnodes that would normally have been downloaded with it.. #2142
74335                     if (loadChildNodes) {
74336                         var missing =  lodash(baseEntities)
74337                                 .filter({ type: 'way' })
74338                                 .map('nodes')
74339                                 .flatten()
74340                                 .uniq()
74341                                 .reject(function(n) { return stack$$1[0].graph.hasEntity(n); })
74342                                 .value();
74343
74344                         if (!lodash.isEmpty(missing)) {
74345                             loadComplete = false;
74346                             context.redrawEnable(false);
74347
74348                             var loading = uiLoading(context).blocking(true);
74349                             context.container().call(loading);
74350
74351                             var childNodesLoaded = function(err, result) {
74352                                 if (!err) {
74353                                     var visible = lodash.groupBy(result.data, 'visible');
74354                                     if (!lodash.isEmpty(visible.true)) {
74355                                         missing = lodash.difference(missing, lodash.map(visible.true, 'id'));
74356                                         stack$$1[0].graph.rebase(visible.true, lodash.map(stack$$1, 'graph'), true);
74357                                         tree$$1.rebase(visible.true, true);
74358                                     }
74359
74360                                     // fetch older versions of nodes that were deleted..
74361                                     lodash.each(visible.false, function(entity) {
74362                                         context.connection()
74363                                             .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
74364                                     });
74365                                 }
74366
74367                                 if (err || lodash.isEmpty(missing)) {
74368                                     loading.close();
74369                                     context.redrawEnable(true);
74370                                     dispatch$$1.call('change');
74371                                 }
74372                             };
74373
74374                             context.connection().loadMultiple(missing, childNodesLoaded);
74375                         }
74376                     }
74377                 }
74378
74379                 stack$$1 = h.stack.map(function(d) {
74380                     var entities = {}, entity;
74381
74382                     if (d.modified) {
74383                         d.modified.forEach(function(key) {
74384                             entity = allEntities[key];
74385                             entities[entity.id] = entity;
74386                         });
74387                     }
74388
74389                     if (d.deleted) {
74390                         d.deleted.forEach(function(id) {
74391                             entities[id] = undefined;
74392                         });
74393                     }
74394
74395                     return {
74396                         graph: coreGraph$$1(stack$$1[0].graph).load(entities),
74397                         annotation: d.annotation,
74398                         imageryUsed: d.imageryUsed
74399                     };
74400                 });
74401
74402             } else { // original version
74403                 stack$$1 = h.stack.map(function(d) {
74404                     var entities = {};
74405
74406                     for (var i in d.entities) {
74407                         var entity = d.entities[i];
74408                         entities[i] = entity === 'undefined' ? undefined : osmEntity$$1(entity);
74409                     }
74410
74411                     d.graph = coreGraph$$1(stack$$1[0].graph).load(entities);
74412                     return d;
74413                 });
74414             }
74415
74416             if (loadComplete) {
74417                 dispatch$$1.call('change');
74418             }
74419
74420             return history;
74421         },
74422
74423
74424         save: function() {
74425             if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
74426             return history;
74427         },
74428
74429
74430         clearSaved: function() {
74431             context.debouncedSave.cancel();
74432             if (lock.locked()) context.storage(getKey('saved_history'), null);
74433             return history;
74434         },
74435
74436
74437         lock: function() {
74438             return lock.lock();
74439         },
74440
74441
74442         unlock: function() {
74443             lock.unlock();
74444         },
74445
74446
74447         // is iD not open in another window and it detects that
74448         // there's a history stored in localStorage that's recoverable?
74449         restorableChanges: function() {
74450             return lock.locked() && !!context.storage(getKey('saved_history'));
74451         },
74452
74453
74454         // load history from a version stored in localStorage
74455         restore: function() {
74456             if (!lock.locked()) return;
74457
74458             var json$$1 = context.storage(getKey('saved_history'));
74459             if (json$$1) history.fromJSON(json$$1, true);
74460         },
74461
74462
74463         _getKey: getKey
74464
74465     };
74466
74467
74468     history.reset();
74469
74470     return utilRebind(history, dispatch$$1, 'on');
74471 }
74472
74473 function presetCollection(collection) {
74474     var maxSearchResults = 50,
74475         maxSuggestionResults = 10;
74476
74477     var presets = {
74478
74479         collection: collection,
74480
74481
74482         item: function(id) {
74483             return lodash.find(this.collection, function(d) {
74484                 return d.id === id;
74485             });
74486         },
74487
74488
74489         matchGeometry: function(geometry) {
74490             return presetCollection(this.collection.filter(function(d) {
74491                 return d.matchGeometry(geometry);
74492             }));
74493         },
74494
74495
74496         search: function(value, geometry) {
74497             if (!value) return this;
74498
74499             function leading(a) {
74500                 var index = a.indexOf(value);
74501                 return index === 0 || a[index - 1] === ' ';
74502             }
74503
74504             function suggestionName(name) {
74505                 var nameArray = name.split(' - ');
74506                 if (nameArray.length > 1) {
74507                     name = nameArray.slice(0, nameArray.length - 1).join(' - ');
74508                 }
74509                 return name.toLowerCase();
74510             }
74511
74512
74513             value = value.toLowerCase();
74514
74515             var searchable = lodash.filter(this.collection, function(a) {
74516                     return a.searchable !== false && a.suggestion !== true;
74517                 }),
74518                 suggestions = lodash.filter(this.collection, function(a) {
74519                     return a.suggestion === true;
74520                 });
74521
74522
74523             // matches value to preset.name
74524             var leading_name = lodash.filter(searchable, function(a) {
74525                     return leading(a.name().toLowerCase());
74526                 }).sort(function(a, b) {
74527                     var i;
74528                     i = b.originalScore - a.originalScore;
74529                     if (i !== 0) return i;
74530
74531                     i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
74532                     if (i !== 0) return i;
74533
74534                     return a.name().length - b.name().length;
74535                 });
74536
74537             // matches value to preset.terms values
74538             var leading_terms = lodash.filter(searchable, function(a) {
74539                     return lodash.some(a.terms() || [], leading);
74540                 });
74541
74542             // matches value to preset.tags values
74543             var leading_tag_values = lodash.filter(searchable, function(a) {
74544                     return lodash.some(lodash.without(lodash.values(a.tags || {}), '*'), leading);
74545                 });
74546
74547
74548             // finds close matches to value in preset.name
74549             var similar_name = searchable.map(function(a) {
74550                     return {
74551                         preset: a,
74552                         dist: utilEditDistance(value, a.name())
74553                     };
74554                 }).filter(function(a) {
74555                     return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
74556                 }).sort(function(a, b) {
74557                     return a.dist - b.dist;
74558                 }).map(function(a) {
74559                     return a.preset;
74560                 });
74561
74562             // finds close matches to value in preset.terms
74563             var similar_terms = lodash.filter(searchable, function(a) {
74564                     return lodash.some(a.terms() || [], function(b) {
74565                         return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
74566                     });
74567                 });
74568
74569             var leading_suggestions = lodash.filter(suggestions, function(a) {
74570                     return leading(suggestionName(a.name()));
74571                 }).sort(function(a, b) {
74572                     a = suggestionName(a.name());
74573                     b = suggestionName(b.name());
74574                     var i = a.indexOf(value) - b.indexOf(value);
74575                     if (i === 0) return a.length - b.length;
74576                     else return i;
74577                 });
74578
74579             var similar_suggestions = suggestions.map(function(a) {
74580                     return {
74581                         preset: a,
74582                         dist: utilEditDistance(value, suggestionName(a.name()))
74583                     };
74584                 }).filter(function(a) {
74585                     return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
74586                 }).sort(function(a, b) {
74587                     return a.dist - b.dist;
74588                 }).map(function(a) {
74589                     return a.preset;
74590                 });
74591
74592             var other = presets.item(geometry);
74593
74594             var results = leading_name.concat(
74595                     leading_terms,
74596                     leading_tag_values,
74597                     leading_suggestions.slice(0, maxSuggestionResults + 5),
74598                     similar_name,
74599                     similar_terms,
74600                     similar_suggestions.slice(0, maxSuggestionResults)
74601                 ).slice(0, maxSearchResults - 1);
74602
74603             return presetCollection(lodash.uniq(results.concat(other)));
74604         }
74605     };
74606
74607
74608     return presets;
74609 }
74610
74611 function presetCategory(id, category, all) {
74612     category = lodash.clone(category);
74613
74614     category.id = id;
74615
74616
74617     category.members = presetCollection(category.members.map(function(id) {
74618         return all.item(id);
74619     }));
74620
74621
74622     category.matchGeometry = function(geometry) {
74623         return category.geometry.indexOf(geometry) >= 0;
74624     };
74625
74626
74627     category.matchScore = function() {
74628         return -1;
74629     };
74630
74631
74632     category.name = function() {
74633         return t('presets.categories.' + id + '.name', {'default': id});
74634     };
74635
74636
74637     category.terms = function() {
74638         return [];
74639     };
74640
74641
74642     return category;
74643 }
74644
74645 function presetField(id, field) {
74646     field = lodash.clone(field);
74647
74648     field.id = id;
74649
74650
74651     field.matchGeometry = function(geometry) {
74652         return !field.geometry || field.geometry === geometry;
74653     };
74654
74655
74656     field.t = function(scope, options) {
74657         return t('presets.fields.' + id + '.' + scope, options);
74658     };
74659
74660
74661     field.label = function() {
74662         return field.t('label', {'default': id});
74663     };
74664
74665
74666     var placeholder = field.placeholder;
74667     field.placeholder = function() {
74668         return field.t('placeholder', {'default': placeholder});
74669     };
74670
74671
74672     return field;
74673 }
74674
74675 function presetPreset(id, preset, fields) {
74676     preset = lodash.clone(preset);
74677
74678     preset.id = id;
74679     preset.fields = (preset.fields || []).map(getFields);
74680     preset.geometry = (preset.geometry || []);
74681
74682
74683     function getFields(f) {
74684         return fields[f];
74685     }
74686
74687
74688     preset.matchGeometry = function(geometry) {
74689         return preset.geometry.indexOf(geometry) >= 0;
74690     };
74691
74692
74693     preset.originalScore = preset.matchScore || 1;
74694
74695
74696     preset.matchScore = function(entity) {
74697         var tags = preset.tags,
74698             score = 0;
74699
74700         for (var t$$1 in tags) {
74701             if (entity.tags[t$$1] === tags[t$$1]) {
74702                 score += preset.originalScore;
74703             } else if (tags[t$$1] === '*' && t$$1 in entity.tags) {
74704                 score += preset.originalScore / 2;
74705             } else {
74706                 return -1;
74707             }
74708         }
74709
74710         return score;
74711     };
74712
74713
74714     preset.t = function(scope, options) {
74715         return t('presets.presets.' + id + '.' + scope, options);
74716     };
74717
74718
74719     var name = preset.name || '';
74720     preset.name = function() {
74721         if (preset.suggestion) {
74722             id = id.split('/');
74723             id = id[0] + '/' + id[1];
74724             return name + ' - ' + t('presets.presets.' + id + '.name');
74725         }
74726         return preset.t('name', {'default': name});
74727     };
74728
74729
74730     preset.terms = function() {
74731         return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
74732     };
74733
74734
74735     preset.isFallback = function() {
74736         var tagCount = Object.keys(preset.tags).length;
74737         return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
74738     };
74739
74740
74741     var reference = preset.reference || {};
74742     preset.reference = function(geometry) {
74743         var key = reference.key || Object.keys(lodash.omit(preset.tags, 'name'))[0],
74744             value = reference.value || preset.tags[key];
74745
74746         if (geometry === 'relation' && key === 'type') {
74747             if (value in preset.tags) {
74748                 key = value;
74749                 value = preset.tags[key];
74750             } else {
74751                 return { rtype: value };
74752             }
74753         }
74754
74755         if (value === '*') {
74756             return { key: key };
74757         } else {
74758             return { key: key, value: value };
74759         }
74760     };
74761
74762
74763     var removeTags = preset.removeTags || preset.tags;
74764     preset.removeTags = function(tags, geometry) {
74765         tags = lodash.omit(tags, lodash.keys(removeTags));
74766
74767         for (var f in preset.fields) {
74768             var field = preset.fields[f];
74769             if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
74770                 delete tags[field.key];
74771             }
74772         }
74773
74774         delete tags.area;
74775         return tags;
74776     };
74777
74778
74779     var applyTags = preset.addTags || preset.tags;
74780     preset.applyTags = function(tags, geometry) {
74781         var k;
74782
74783         tags = lodash.clone(tags);
74784
74785         for (k in applyTags) {
74786             if (applyTags[k] === '*') {
74787                 tags[k] = 'yes';
74788             } else {
74789                 tags[k] = applyTags[k];
74790             }
74791         }
74792
74793         // Add area=yes if necessary.
74794         // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
74795         // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
74796         // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
74797         delete tags.area;
74798         if (geometry === 'area') {
74799             var needsAreaTag = true;
74800             if (preset.geometry.indexOf('line') === -1) {
74801                 for (k in applyTags) {
74802                     if (k in areaKeys) {
74803                         needsAreaTag = false;
74804                         break;
74805                     }
74806                 }
74807             }
74808             if (needsAreaTag) {
74809                 tags.area = 'yes';
74810             }
74811         }
74812
74813         for (var f in preset.fields) {
74814             var field = preset.fields[f];
74815             if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
74816                 tags[field.key] = field.default;
74817             }
74818         }
74819
74820         return tags;
74821     };
74822
74823
74824     return preset;
74825 }
74826
74827 function presetIndex() {
74828     // a presetCollection with methods for
74829     // loading new data and returning defaults
74830
74831     var all = presetCollection([]),
74832         defaults = { area: all, line: all, point: all, vertex: all, relation: all },
74833         fields = {},
74834         universal = [],
74835         recent = presetCollection([]);
74836
74837     // Index of presets by (geometry, tag key).
74838     var index = {
74839         point: {},
74840         vertex: {},
74841         line: {},
74842         area: {},
74843         relation: {}
74844     };
74845
74846     all.match = function(entity, resolver) {
74847         var geometry = entity.geometry(resolver);
74848
74849         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
74850         if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
74851             geometry = 'point';
74852         }
74853
74854         var geometryMatches = index[geometry],
74855             best = -1,
74856             match;
74857
74858         for (var k in entity.tags) {
74859             var keyMatches = geometryMatches[k];
74860             if (!keyMatches) continue;
74861
74862             for (var i = 0; i < keyMatches.length; i++) {
74863                 var score = keyMatches[i].matchScore(entity);
74864                 if (score > best) {
74865                     best = score;
74866                     match = keyMatches[i];
74867                 }
74868             }
74869         }
74870
74871         return match || all.item(geometry);
74872     };
74873
74874
74875     // Because of the open nature of tagging, iD will never have a complete
74876     // list of tags used in OSM, so we want it to have logic like "assume
74877     // that a closed way with an amenity tag is an area, unless the amenity
74878     // is one of these specific types". This function computes a structure
74879     // that allows testing of such conditions, based on the presets designated
74880     // as as supporting (or not supporting) the area geometry.
74881     //
74882     // The returned object L is a whitelist/blacklist of tags. A closed way
74883     // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
74884     // (see `Way#isArea()`). In other words, the keys of L form the whitelist,
74885     // and the subkeys form the blacklist.
74886     all.areaKeys = function() {
74887         var areaKeys = {},
74888             ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],  // probably a line..
74889             presets = lodash.reject(all.collection, 'suggestion');
74890
74891         // whitelist
74892         presets.forEach(function(d) {
74893             for (var key in d.tags) break;
74894             if (!key) return;
74895             if (ignore.indexOf(key) !== -1) return;
74896
74897             if (d.geometry.indexOf('area') !== -1) {    // probably an area..
74898                 areaKeys[key] = areaKeys[key] || {};
74899             }
74900         });
74901
74902         // blacklist
74903         presets.forEach(function(d) {
74904             for (var key in d.tags) break;
74905             if (!key) return;
74906             if (ignore.indexOf(key) !== -1) return;
74907
74908             var value = d.tags[key];
74909             if (key in areaKeys &&                      // probably an area...
74910                 d.geometry.indexOf('line') !== -1 &&    // but sometimes a line
74911                 value !== '*') {
74912                 areaKeys[key][value] = true;
74913             }
74914         });
74915
74916         return areaKeys;
74917     };
74918
74919
74920     all.init = function() {
74921         var d = data.presets;
74922
74923         all.collection = [];
74924         recent.collection = [];
74925         fields = {};
74926         universal = [];
74927         index = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
74928
74929         if (d.fields) {
74930             lodash.forEach(d.fields, function(d, id) {
74931                 fields[id] = presetField(id, d);
74932                 if (d.universal) universal.push(fields[id]);
74933             });
74934         }
74935
74936         if (d.presets) {
74937             lodash.forEach(d.presets, function(d, id) {
74938                 all.collection.push(presetPreset(id, d, fields));
74939             });
74940         }
74941
74942         if (d.categories) {
74943             lodash.forEach(d.categories, function(d, id) {
74944                 all.collection.push(presetCategory(id, d, all));
74945             });
74946         }
74947
74948         if (d.defaults) {
74949             var getItem = lodash.bind(all.item, all);
74950             defaults = {
74951                 area: presetCollection(d.defaults.area.map(getItem)),
74952                 line: presetCollection(d.defaults.line.map(getItem)),
74953                 point: presetCollection(d.defaults.point.map(getItem)),
74954                 vertex: presetCollection(d.defaults.vertex.map(getItem)),
74955                 relation: presetCollection(d.defaults.relation.map(getItem))
74956             };
74957         }
74958
74959         for (var i = 0; i < all.collection.length; i++) {
74960             var preset = all.collection[i],
74961                 geometry = preset.geometry;
74962
74963             for (var j = 0; j < geometry.length; j++) {
74964                 var g = index[geometry[j]];
74965                 for (var k in preset.tags) {
74966                     (g[k] = g[k] || []).push(preset);
74967                 }
74968             }
74969         }
74970
74971         return all;
74972     };
74973
74974     all.field = function(id) {
74975         return fields[id];
74976     };
74977
74978     all.universal = function() {
74979         return universal;
74980     };
74981
74982     all.defaults = function(geometry, n) {
74983         var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
74984             def = lodash.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
74985         return presetCollection(lodash.uniq(rec.concat(def).concat(all.item(geometry))));
74986     };
74987
74988     all.choose = function(preset) {
74989         if (!preset.isFallback()) {
74990             recent = presetCollection(lodash.uniq([preset].concat(recent.collection)));
74991         }
74992         return all;
74993     };
74994
74995     return all;
74996 }
74997
74998 var areaKeys = {};
74999
75000 function setAreaKeys(value) {
75001     areaKeys = value;
75002 }
75003
75004
75005 function coreContext() {
75006     var context = {};
75007     context.version = '2.3.1';
75008
75009     // create a special translation that contains the keys in place of the strings
75010     var tkeys = lodash.cloneDeep(en);
75011     var parents = [];
75012
75013     function traverser(v, k, obj) {
75014         parents.push(k);
75015         if (lodash.isObject(v)) {
75016             lodash.forOwn(v, traverser);
75017         } else if (lodash.isString(v)) {
75018             obj[k] = parents.join('.');
75019         }
75020         parents.pop();
75021     }
75022
75023     lodash.forOwn(tkeys, traverser);
75024     addTranslation('_tkeys_', tkeys);
75025
75026     addTranslation('en', en);
75027     setLocale('en');
75028
75029     var dispatch$$1 = dispatch('enter', 'exit', 'change');
75030
75031     // https://github.com/openstreetmap/iD/issues/772
75032     // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
75033     var storage;
75034     try { storage = localStorage; } catch (e) {}  // eslint-disable-line no-empty
75035     storage = storage || (function() {
75036         var s = {};
75037         return {
75038             getItem: function(k) { return s[k]; },
75039             setItem: function(k, v) { s[k] = v; },
75040             removeItem: function(k) { delete s[k]; }
75041         };
75042     })();
75043
75044     context.storage = function(k, v) {
75045         try {
75046             if (arguments.length === 1) return storage.getItem(k);
75047             else if (v === null) storage.removeItem(k);
75048             else storage.setItem(k, v);
75049         } catch (e) {
75050             // localstorage quota exceeded
75051             /* eslint-disable no-console */
75052             if (typeof console !== 'undefined') console.error('localStorage quota exceeded');
75053             /* eslint-enable no-console */
75054         }
75055     };
75056
75057
75058     /* Straight accessors. Avoid using these if you can. */
75059     var ui, connection, history;
75060     context.ui = function() { return ui; };
75061     context.connection = function() { return connection; };
75062     context.history = function() { return history; };
75063
75064
75065     /* Connection */
75066     function entitiesLoaded(err, result) {
75067         if (!err) history.merge(result.data, result.extent);
75068     }
75069
75070     context.preauth = function(options) {
75071         connection.switch(options);
75072         return context;
75073     };
75074
75075     context.loadTiles = function(projection$$1, dimensions, callback) {
75076         function done(err, result) {
75077             entitiesLoaded(err, result);
75078             if (callback) callback(err, result);
75079         }
75080         connection.loadTiles(projection$$1, dimensions, done);
75081     };
75082
75083     context.loadEntity = function(id, callback) {
75084         function done(err, result) {
75085             entitiesLoaded(err, result);
75086             if (callback) callback(err, result);
75087         }
75088         connection.loadEntity(id, done);
75089     };
75090
75091     context.zoomToEntity = function(id, zoomTo) {
75092         if (zoomTo !== false) {
75093             this.loadEntity(id, function(err, result) {
75094                 if (err) return;
75095                 var entity = lodash.find(result.data, function(e) { return e.id === id; });
75096                 if (entity) { map.zoomTo(entity); }
75097             });
75098         }
75099
75100         map.on('drawn.zoomToEntity', function() {
75101             if (!context.hasEntity(id)) return;
75102             map.on('drawn.zoomToEntity', null);
75103             context.on('enter.zoomToEntity', null);
75104             context.enter(modeSelect(context, [id]));
75105         });
75106
75107         context.on('enter.zoomToEntity', function() {
75108             if (mode.id !== 'browse') {
75109                 map.on('drawn.zoomToEntity', null);
75110                 context.on('enter.zoomToEntity', null);
75111             }
75112         });
75113     };
75114
75115     var minEditableZoom = 16;
75116     context.minEditableZoom = function(_) {
75117         if (!arguments.length) return minEditableZoom;
75118         minEditableZoom = _;
75119         connection.tileZoom(_);
75120         return context;
75121     };
75122
75123
75124     /* History */
75125     var inIntro = false;
75126     context.inIntro = function(_) {
75127         if (!arguments.length) return inIntro;
75128         inIntro = _;
75129         return context;
75130     };
75131
75132     context.save = function() {
75133         // no history save, no message onbeforeunload
75134         if (inIntro || select('.modal').size()) return;
75135
75136         var canSave;
75137         if (mode && mode.id === 'save') {
75138             canSave = false;
75139         } else {
75140             canSave = context.selectedIDs().every(function(id) {
75141                 var entity = context.hasEntity(id);
75142                 return entity && !entity.isDegenerate();
75143             });
75144         }
75145
75146         if (canSave) {
75147             history.save();
75148         }
75149         if (history.hasChanges()) {
75150             return t('save.unsaved_changes');
75151         }
75152     };
75153
75154
75155     /* Graph */
75156     context.hasEntity = function(id) {
75157         return history.graph().hasEntity(id);
75158     };
75159     context.entity = function(id) {
75160         return history.graph().entity(id);
75161     };
75162     context.childNodes = function(way) {
75163         return history.graph().childNodes(way);
75164     };
75165     context.geometry = function(id) {
75166         return context.entity(id).geometry(history.graph());
75167     };
75168
75169
75170     /* Modes */
75171     var mode;
75172     context.mode = function() {
75173         return mode;
75174     };
75175     context.enter = function(newMode) {
75176         if (mode) {
75177             mode.exit();
75178             dispatch$$1.call('exit', this, mode);
75179         }
75180
75181         mode = newMode;
75182         mode.enter();
75183         dispatch$$1.call('enter', this, mode);
75184     };
75185
75186     context.selectedIDs = function() {
75187         if (mode && mode.selectedIDs) {
75188             return mode.selectedIDs();
75189         } else {
75190             return [];
75191         }
75192     };
75193
75194
75195     /* Behaviors */
75196     context.install = function(behavior) {
75197         context.surface().call(behavior);
75198     };
75199     context.uninstall = function(behavior) {
75200         context.surface().call(behavior.off);
75201     };
75202
75203
75204     /* Copy/Paste */
75205     var copyIDs = [], copyGraph;
75206     context.copyGraph = function() { return copyGraph; };
75207     context.copyIDs = function(_) {
75208         if (!arguments.length) return copyIDs;
75209         copyIDs = _;
75210         copyGraph = history.graph();
75211         return context;
75212     };
75213
75214
75215     /* Background */
75216     var background;
75217     context.background = function() { return background; };
75218
75219
75220     /* Features */
75221     var features;
75222     context.features = function() { return features; };
75223     context.hasHiddenConnections = function(id) {
75224         var graph = history.graph(),
75225             entity = graph.entity(id);
75226         return features.hasHiddenConnections(entity, graph);
75227     };
75228
75229
75230     /* Presets */
75231     var presets;
75232     context.presets = function() { return presets; };
75233
75234
75235     /* Map */
75236     var map;
75237     context.map = function() { return map; };
75238     context.layers = function() { return map.layers; };
75239     context.surface = function() { return map.surface; };
75240     context.editable = function() { return map.editable(); };
75241     context.surfaceRect = function() {
75242         return map.surface.node().getBoundingClientRect();
75243     };
75244
75245
75246     /* Debug */
75247     var debugFlags = {
75248         tile: false,
75249         collision: false,
75250         imagery: false,
75251         imperial: false,
75252         driveLeft: false
75253     };
75254     context.debugFlags = function() {
75255         return debugFlags;
75256     };
75257     context.setDebug = function(flag, val) {
75258         if (arguments.length === 1) val = true;
75259         debugFlags[flag] = val;
75260         dispatch$$1.call('change');
75261         return context;
75262     };
75263     context.getDebug = function(flag) {
75264         return flag && debugFlags[flag];
75265     };
75266
75267
75268     /* Container */
75269     var container = select(document.body);
75270     context.container = function(_) {
75271         if (!arguments.length) return container;
75272         container = _;
75273         container.classed('id-container', true);
75274         return context;
75275     };
75276     var embed;
75277     context.embed = function(_) {
75278         if (!arguments.length) return embed;
75279         embed = _;
75280         return context;
75281     };
75282
75283
75284     /* Assets */
75285     var assetPath = '';
75286     context.assetPath = function(_) {
75287         if (!arguments.length) return assetPath;
75288         assetPath = _;
75289         return context;
75290     };
75291
75292     var assetMap = {};
75293     context.assetMap = function(_) {
75294         if (!arguments.length) return assetMap;
75295         assetMap = _;
75296         return context;
75297     };
75298
75299     context.asset = function(_) {
75300         var filename = assetPath + _;
75301         return assetMap[filename] || filename;
75302     };
75303
75304     context.imagePath = function(_) {
75305         return context.asset('img/' + _);
75306     };
75307
75308
75309     /* locales */
75310     // `locale` variable contains a "requested locale".
75311     // It won't become the `currentLocale` until after loadLocale() is called.
75312     var locale, localePath;
75313
75314     context.locale = function(loc, path$$1) {
75315         if (!arguments.length) return currentLocale;
75316         locale = loc;
75317         localePath = path$$1;
75318         return context;
75319     };
75320
75321     context.loadLocale = function(callback) {
75322         if (locale && locale !== 'en' && dataLocales.hasOwnProperty(locale)) {
75323             localePath = localePath || context.asset('locales/' + locale + '.json');
75324             json(localePath, function(err, result) {
75325                 if (!err) {
75326                     addTranslation(locale, result[locale]);
75327                     setLocale(locale);
75328                     utilDetect(true);
75329                 }
75330                 if (callback) {
75331                     callback(err);
75332                 }
75333             });
75334         } else {
75335             if (locale) {
75336                 setLocale(locale);
75337                 utilDetect(true);
75338             }
75339             if (callback) {
75340                 callback();
75341             }
75342         }
75343     };
75344
75345
75346     /* reset (aka flush) */
75347     context.reset = context.flush = function() {
75348         context.debouncedSave.cancel();
75349         lodash.each(services, function(service) {
75350             if (service && typeof service.reset === 'function') {
75351                 service.reset(context);
75352             }
75353         });
75354         features.reset();
75355         history.reset();
75356         return context;
75357     };
75358
75359
75360     /* Init */
75361
75362     context.projection = geoRawMercator();
75363     context.curtainProjection = geoRawMercator();
75364
75365     locale = utilDetect().locale;
75366     if (locale && !dataLocales.hasOwnProperty(locale)) {
75367         locale = locale.split('-')[0];
75368     }
75369
75370     history = coreHistory(context);
75371     context.graph = history.graph;
75372     context.changes = history.changes;
75373     context.intersects = history.intersects;
75374
75375     // Debounce save, since it's a synchronous localStorage write,
75376     // and history changes can happen frequently (e.g. when dragging).
75377     context.debouncedSave = lodash.debounce(context.save, 350);
75378     function withDebouncedSave(fn) {
75379         return function() {
75380             var result = fn.apply(history, arguments);
75381             context.debouncedSave();
75382             return result;
75383         };
75384     }
75385
75386     context.perform = withDebouncedSave(history.perform);
75387     context.replace = withDebouncedSave(history.replace);
75388     context.pop = withDebouncedSave(history.pop);
75389     context.overwrite = withDebouncedSave(history.overwrite);
75390     context.undo = withDebouncedSave(history.undo);
75391     context.redo = withDebouncedSave(history.redo);
75392
75393     ui = uiInit(context);
75394
75395     connection = services.osm;
75396     background = rendererBackground(context);
75397     features = rendererFeatures(context);
75398     presets = presetIndex();
75399
75400     map = rendererMap(context);
75401     context.mouse = map.mouse;
75402     context.extent = map.extent;
75403     context.pan = map.pan;
75404     context.zoomIn = map.zoomIn;
75405     context.zoomOut = map.zoomOut;
75406     context.zoomInFurther = map.zoomInFurther;
75407     context.zoomOutFurther = map.zoomOutFurther;
75408     context.redrawEnable = map.redrawEnable;
75409
75410     lodash.each(services, function(service) {
75411         if (service && typeof service.init === 'function') {
75412             service.init(context);
75413         }
75414     });
75415
75416     background.init();
75417     presets.init();
75418     areaKeys = presets.areaKeys();
75419
75420
75421     return utilRebind(context, dispatch$$1, 'on');
75422 }
75423
75424 function osmWay() {
75425     if (!(this instanceof osmWay)) {
75426         return (new osmWay()).initialize(arguments);
75427     } else if (arguments.length) {
75428         this.initialize(arguments);
75429     }
75430 }
75431
75432
75433 osmEntity$$1.way = osmWay;
75434
75435 osmWay.prototype = Object.create(osmEntity$$1.prototype);
75436
75437
75438 lodash.extend(osmWay.prototype, {
75439     type: 'way',
75440     nodes: [],
75441
75442
75443     copy: function(resolver, copies) {
75444         if (copies[this.id])
75445             return copies[this.id];
75446
75447         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
75448
75449         var nodes = this.nodes.map(function(id) {
75450             return resolver.entity(id).copy(resolver, copies).id;
75451         });
75452
75453         copy = copy.update({ nodes: nodes });
75454         copies[this.id] = copy;
75455
75456         return copy;
75457     },
75458
75459
75460     extent: function(resolver) {
75461         return resolver.transient(this, 'extent', function() {
75462             var extent$$1 = geoExtent$$1();
75463             for (var i = 0; i < this.nodes.length; i++) {
75464                 var node = resolver.hasEntity(this.nodes[i]);
75465                 if (node) {
75466                     extent$$1._extend(node.extent());
75467                 }
75468             }
75469             return extent$$1;
75470         });
75471     },
75472
75473
75474     first: function() {
75475         return this.nodes[0];
75476     },
75477
75478
75479     last: function() {
75480         return this.nodes[this.nodes.length - 1];
75481     },
75482
75483
75484     contains: function(node) {
75485         return this.nodes.indexOf(node) >= 0;
75486     },
75487
75488
75489     affix: function(node) {
75490         if (this.nodes[0] === node) return 'prefix';
75491         if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
75492     },
75493
75494
75495     layer: function() {
75496         // explicit layer tag, clamp between -10, 10..
75497         if (isFinite(this.tags.layer)) {
75498             return Math.max(-10, Math.min(+(this.tags.layer), 10));
75499         }
75500
75501         // implied layer tag..
75502         if (this.tags.location === 'overground') return 1;
75503         if (this.tags.location === 'underground') return -1;
75504         if (this.tags.location === 'underwater') return -10;
75505
75506         if (this.tags.power === 'line') return 10;
75507         if (this.tags.power === 'minor_line') return 10;
75508         if (this.tags.aerialway) return 10;
75509         if (this.tags.bridge) return 1;
75510         if (this.tags.cutting) return -1;
75511         if (this.tags.tunnel) return -1;
75512         if (this.tags.waterway) return -1;
75513         if (this.tags.man_made === 'pipeline') return -10;
75514         if (this.tags.boundary) return -10;
75515         return 0;
75516     },
75517
75518
75519     isOneWay: function() {
75520         // explicit oneway tag..
75521         if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
75522         if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
75523
75524         // implied oneway tag..
75525         for (var key in this.tags) {
75526             if (key in osmOneWayTags && (this.tags[key] in osmOneWayTags[key]))
75527                 return true;
75528         }
75529         return false;
75530     },
75531
75532
75533     lanes: function() {
75534         return osmLanes(this);
75535     },
75536
75537
75538     isClosed: function() {
75539         return this.nodes.length > 1 && this.first() === this.last();
75540     },
75541
75542
75543     isConvex: function(resolver) {
75544         if (!this.isClosed() || this.isDegenerate()) return null;
75545
75546         var nodes = lodash.uniq(resolver.childNodes(this)),
75547             coords = lodash.map(nodes, 'loc'),
75548             curr = 0, prev = 0;
75549
75550         for (var i = 0; i < coords.length; i++) {
75551             var o = coords[(i+1) % coords.length],
75552                 a = coords[i],
75553                 b = coords[(i+2) % coords.length],
75554                 res = geoCross(o, a, b);
75555
75556             curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
75557             if (curr === 0) {
75558                 continue;
75559             } else if (prev && curr !== prev) {
75560                 return false;
75561             }
75562             prev = curr;
75563         }
75564         return true;
75565     },
75566
75567
75568     isArea: function() {
75569         if (this.tags.area === 'yes')
75570             return true;
75571         if (!this.isClosed() || this.tags.area === 'no')
75572             return false;
75573         for (var key in this.tags) {
75574             if (key in areaKeys && !(this.tags[key] in areaKeys[key])) {
75575                 return true;
75576             }
75577         }
75578         return false;
75579     },
75580
75581
75582     isDegenerate: function() {
75583         return lodash.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
75584     },
75585
75586
75587     areAdjacent: function(n1, n2) {
75588         for (var i = 0; i < this.nodes.length; i++) {
75589             if (this.nodes[i] === n1) {
75590                 if (this.nodes[i - 1] === n2) return true;
75591                 if (this.nodes[i + 1] === n2) return true;
75592             }
75593         }
75594         return false;
75595     },
75596
75597
75598     geometry: function(graph) {
75599         return graph.transient(this, 'geometry', function() {
75600             return this.isArea() ? 'area' : 'line';
75601         });
75602     },
75603
75604
75605     // If this way is not closed, append the beginning node to the end of the nodelist to close it.
75606     close: function() {
75607         if (this.isClosed() || !this.nodes.length) return this;
75608
75609         var nodes = this.nodes.slice();
75610         nodes = nodes.filter(noRepeatNodes);
75611         nodes.push(nodes[0]);
75612         return this.update({ nodes: nodes });
75613     },
75614
75615
75616     // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
75617     unclose: function() {
75618         if (!this.isClosed()) return this;
75619
75620         var nodes = this.nodes.slice(),
75621             connector = this.first(),
75622             i = nodes.length - 1;
75623
75624         // remove trailing connectors..
75625         while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
75626             nodes.splice(i, 1);
75627             i = nodes.length - 1;
75628         }
75629
75630         nodes = nodes.filter(noRepeatNodes);
75631         return this.update({ nodes: nodes });
75632     },
75633
75634
75635     // Adds a node (id) in front of the node which is currently at position index.
75636     // If index is undefined, the node will be added to the end of the way for linear ways,
75637     //   or just before the final connecting node for circular ways.
75638     // Consecutive duplicates are eliminated including existing ones.
75639     // Circularity is always preserved when adding a node.
75640     addNode: function(id, index) {
75641         var nodes = this.nodes.slice(),
75642             isClosed = this.isClosed(),
75643             max$$1 = isClosed ? nodes.length - 1 : nodes.length;
75644
75645         if (index === undefined) {
75646             index = max$$1;
75647         }
75648
75649         if (index < 0 || index > max$$1) {
75650             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
75651         }
75652
75653         // If this is a closed way, remove all connector nodes except the first one
75654         // (there may be duplicates) and adjust index if necessary..
75655         if (isClosed) {
75656             var connector = this.first();
75657
75658             // leading connectors..
75659             var i = 1;
75660             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
75661                 nodes.splice(i, 1);
75662                 if (index > i) index--;
75663             }
75664
75665             // trailing connectors..
75666             i = nodes.length - 1;
75667             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
75668                 nodes.splice(i, 1);
75669                 if (index > i) index--;
75670                 i = nodes.length - 1;
75671             }
75672         }
75673
75674         nodes.splice(index, 0, id);
75675         nodes = nodes.filter(noRepeatNodes);
75676
75677         // If the way was closed before, append a connector node to keep it closed..
75678         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
75679             nodes.push(nodes[0]);
75680         }
75681
75682         return this.update({ nodes: nodes });
75683     },
75684
75685
75686     // Replaces the node which is currently at position index with the given node (id).
75687     // Consecutive duplicates are eliminated including existing ones.
75688     // Circularity is preserved when updating a node.
75689     updateNode: function(id, index) {
75690         var nodes = this.nodes.slice(),
75691             isClosed = this.isClosed(),
75692             max$$1 = nodes.length - 1;
75693
75694         if (index === undefined || index < 0 || index > max$$1) {
75695             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
75696         }
75697
75698         // If this is a closed way, remove all connector nodes except the first one
75699         // (there may be duplicates) and adjust index if necessary..
75700         if (isClosed) {
75701             var connector = this.first();
75702
75703             // leading connectors..
75704             var i = 1;
75705             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
75706                 nodes.splice(i, 1);
75707                 if (index > i) index--;
75708             }
75709
75710             // trailing connectors..
75711             i = nodes.length - 1;
75712             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
75713                 nodes.splice(i, 1);
75714                 if (index === i) index = 0;  // update leading connector instead
75715                 i = nodes.length - 1;
75716             }
75717         }
75718
75719         nodes.splice(index, 1, id);
75720         nodes = nodes.filter(noRepeatNodes);
75721
75722         // If the way was closed before, append a connector node to keep it closed..
75723         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
75724             nodes.push(nodes[0]);
75725         }
75726
75727         return this.update({nodes: nodes});
75728     },
75729
75730
75731     // Replaces each occurrence of node id needle with replacement.
75732     // Consecutive duplicates are eliminated including existing ones.
75733     // Circularity is preserved.
75734     replaceNode: function(needle, replacement) {
75735         var nodes = this.nodes.slice(),
75736             isClosed = this.isClosed();
75737
75738         for (var i = 0; i < nodes.length; i++) {
75739             if (nodes[i] === needle) {
75740                 nodes[i] = replacement;
75741             }
75742         }
75743
75744         nodes = nodes.filter(noRepeatNodes);
75745
75746         // If the way was closed before, append a connector node to keep it closed..
75747         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
75748             nodes.push(nodes[0]);
75749         }
75750
75751         return this.update({nodes: nodes});
75752     },
75753
75754
75755     // Removes each occurrence of node id needle with replacement.
75756     // Consecutive duplicates are eliminated including existing ones.
75757     // Circularity is preserved.
75758     removeNode: function(id) {
75759         var nodes = this.nodes.slice(),
75760             isClosed = this.isClosed();
75761
75762         nodes = nodes
75763             .filter(function(node) { return node !== id; })
75764             .filter(noRepeatNodes);
75765
75766         // If the way was closed before, append a connector node to keep it closed..
75767         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
75768             nodes.push(nodes[0]);
75769         }
75770
75771         return this.update({nodes: nodes});
75772     },
75773
75774
75775     asJXON: function(changeset_id) {
75776         var r = {
75777             way: {
75778                 '@id': this.osmId(),
75779                 '@version': this.version || 0,
75780                 nd: lodash.map(this.nodes, function(id) {
75781                     return { keyAttributes: { ref: osmEntity$$1.id.toOSM(id) } };
75782                 }),
75783                 tag: lodash.map(this.tags, function(v, k) {
75784                     return { keyAttributes: { k: k, v: v } };
75785                 })
75786             }
75787         };
75788         if (changeset_id) {
75789             r.way['@changeset'] = changeset_id;
75790         }
75791         return r;
75792     },
75793
75794
75795     asGeoJSON: function(resolver) {
75796         return resolver.transient(this, 'GeoJSON', function() {
75797             var coordinates = lodash.map(resolver.childNodes(this), 'loc');
75798             if (this.isArea() && this.isClosed()) {
75799                 return {
75800                     type: 'Polygon',
75801                     coordinates: [coordinates]
75802                 };
75803             } else {
75804                 return {
75805                     type: 'LineString',
75806                     coordinates: coordinates
75807                 };
75808             }
75809         });
75810     },
75811
75812
75813     area: function(resolver) {
75814         return resolver.transient(this, 'area', function() {
75815             var nodes = resolver.childNodes(this);
75816
75817             var json$$1 = {
75818                 type: 'Polygon',
75819                 coordinates: [lodash.map(nodes, 'loc')]
75820             };
75821
75822             if (!this.isClosed() && nodes.length) {
75823                 json$$1.coordinates[0].push(nodes[0].loc);
75824             }
75825
75826             var area$$1 = area(json$$1);
75827
75828             // Heuristic for detecting counterclockwise winding order. Assumes
75829             // that OpenStreetMap polygons are not hemisphere-spanning.
75830             if (area$$1 > 2 * Math.PI) {
75831                 json$$1.coordinates[0] = json$$1.coordinates[0].reverse();
75832                 area$$1 = area(json$$1);
75833             }
75834
75835             return isNaN(area$$1) ? 0 : area$$1;
75836         });
75837     }
75838 });
75839
75840
75841 // Filter function to eliminate consecutive duplicates.
75842 function noRepeatNodes(node, i, arr) {
75843     return i === 0 || node !== arr[i - 1];
75844 }
75845
75846 function osmTurn(turn) {
75847     if (!(this instanceof osmTurn))
75848         return new osmTurn(turn);
75849     lodash.extend(this, turn);
75850 }
75851
75852
75853 function osmIntersection(graph, vertexId) {
75854     var vertex = graph.entity(vertexId),
75855         parentWays = graph.parentWays(vertex),
75856         coincident = [],
75857         highways = {};
75858
75859     function addHighway(way, adjacentNodeId) {
75860         if (highways[adjacentNodeId]) {
75861             coincident.push(adjacentNodeId);
75862         } else {
75863             highways[adjacentNodeId] = way;
75864         }
75865     }
75866
75867     // Pre-split ways that would need to be split in
75868     // order to add a restriction. The real split will
75869     // happen when the restriction is added.
75870     parentWays.forEach(function(way) {
75871         if (!way.tags.highway || way.isArea() || way.isDegenerate())
75872             return;
75873
75874         var isFirst = (vertexId === way.first()),
75875             isLast = (vertexId === way.last()),
75876             isAffix = (isFirst || isLast),
75877             isClosingNode = (isFirst && isLast);
75878
75879         if (isAffix && !isClosingNode) {
75880             var index = (isFirst ? 1 : way.nodes.length - 2);
75881             addHighway(way, way.nodes[index]);
75882
75883         } else {
75884             var splitIndex, wayA, wayB, indexA, indexB;
75885             if (isClosingNode) {
75886                 splitIndex = Math.ceil(way.nodes.length / 2);  // split at midpoint
75887                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
75888                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
75889                 indexA = 1;
75890                 indexB = way.nodes.length - 2;
75891             } else {
75892                 splitIndex = lodash.indexOf(way.nodes, vertex.id, 1);  // split at vertexid
75893                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
75894                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
75895                 indexA = splitIndex - 1;
75896                 indexB = splitIndex + 1;
75897             }
75898             graph = graph.replace(wayA).replace(wayB);
75899             addHighway(wayA, way.nodes[indexA]);
75900             addHighway(wayB, way.nodes[indexB]);
75901         }
75902     });
75903
75904     // remove any ways from this intersection that are coincident
75905     // (i.e. any adjacent node used by more than one intersecting way)
75906     coincident.forEach(function (n) {
75907         delete highways[n];
75908     });
75909
75910
75911     var intersection = {
75912         highways: highways,
75913         ways: lodash.values(highways),
75914         graph: graph
75915     };
75916
75917
75918     intersection.adjacentNodeId = function(fromWayId) {
75919         return lodash.find(lodash.keys(highways), function(k) {
75920             return highways[k].id === fromWayId;
75921         });
75922     };
75923
75924
75925     intersection.turns = function(fromNodeId) {
75926         var start = highways[fromNodeId];
75927         if (!start)
75928             return [];
75929
75930         if (start.first() === vertex.id && start.tags.oneway === 'yes')
75931             return [];
75932         if (start.last() === vertex.id && start.tags.oneway === '-1')
75933             return [];
75934
75935         function withRestriction(turn) {
75936             graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
75937                 if (relation.tags.type !== 'restriction')
75938                     return;
75939
75940                 var f = relation.memberByRole('from'),
75941                     t = relation.memberByRole('to'),
75942                     v = relation.memberByRole('via');
75943
75944                 if (f && f.id === turn.from.way &&
75945                     v && v.id === turn.via.node &&
75946                     t && t.id === turn.to.way) {
75947                     turn.restriction = relation.id;
75948                 } else if (/^only_/.test(relation.tags.restriction) &&
75949                     f && f.id === turn.from.way &&
75950                     v && v.id === turn.via.node &&
75951                     t && t.id !== turn.to.way) {
75952                     turn.restriction = relation.id;
75953                     turn.indirect_restriction = true;
75954                 }
75955             });
75956
75957             return osmTurn(turn);
75958         }
75959
75960
75961         var from = {
75962                 node: fromNodeId,
75963                 way: start.id.split(/-(a|b)/)[0]
75964             },
75965             via = { node: vertex.id },
75966             turns = [];
75967
75968         lodash.each(highways, function(end, adjacentNodeId) {
75969             if (end === start)
75970                 return;
75971
75972             // backward
75973             if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
75974                 turns.push(withRestriction({
75975                     from: from,
75976                     via: via,
75977                     to: {
75978                         node: adjacentNodeId,
75979                         way: end.id.split(/-(a|b)/)[0]
75980                     }
75981                 }));
75982             }
75983
75984             // forward
75985             if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
75986                 turns.push(withRestriction({
75987                     from: from,
75988                     via: via,
75989                     to: {
75990                         node: adjacentNodeId,
75991                         way: end.id.split(/-(a|b)/)[0]
75992                     }
75993                 }));
75994             }
75995
75996         });
75997
75998         // U-turn
75999         if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
76000             turns.push(withRestriction({
76001                 from: from,
76002                 via: via,
76003                 to: from,
76004                 u: true
76005             }));
76006         }
76007
76008         return turns;
76009     };
76010
76011     return intersection;
76012 }
76013
76014
76015 function osmInferRestriction(graph, from, via, to, projection) {
76016     var fromWay = graph.entity(from.way),
76017         fromNode = graph.entity(from.node),
76018         toWay = graph.entity(to.way),
76019         toNode = graph.entity(to.node),
76020         viaNode = graph.entity(via.node),
76021         fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
76022             (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
76023         toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
76024             (toWay.tags.oneway === '-1' && toWay.last() === via.node),
76025         angle = geoAngle(viaNode, fromNode, projection) -
76026                 geoAngle(viaNode, toNode, projection);
76027
76028     angle = angle * 180 / Math.PI;
76029
76030     while (angle < 0)
76031         angle += 360;
76032
76033     if (fromNode === toNode)
76034         return 'no_u_turn';
76035     if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
76036         return 'no_u_turn';
76037     if (angle < 158)
76038         return 'no_right_turn';
76039     if (angle > 202)
76040         return 'no_left_turn';
76041
76042     return 'no_straight_on';
76043 }
76044
76045 function actionAddMember(relationId, member, memberIndex) {
76046     return function(graph) {
76047         var relation = graph.entity(relationId);
76048
76049         if (isNaN(memberIndex) && member.type === 'way') {
76050             var members = relation.indexedMembers();
76051             members.push(member);
76052
76053             var joined = osmJoinWays(members, graph);
76054             for (var i = 0; i < joined.length; i++) {
76055                 var segment = joined[i];
76056                 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
76057                     if (segment[j] !== member)
76058                         continue;
76059
76060                     if (j === 0) {
76061                         memberIndex = segment[j + 1].index;
76062                     } else if (j === segment.length - 1) {
76063                         memberIndex = segment[j - 1].index + 1;
76064                     } else {
76065                         memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
76066                     }
76067                 }
76068             }
76069         }
76070
76071         return graph.replace(relation.addMember(member, memberIndex));
76072     };
76073 }
76074
76075 function actionAddMidpoint(midpoint, node) {
76076     return function(graph) {
76077         graph = graph.replace(node.move(midpoint.loc));
76078
76079         var parents = lodash.intersection(
76080             graph.parentWays(graph.entity(midpoint.edge[0])),
76081             graph.parentWays(graph.entity(midpoint.edge[1])));
76082
76083         parents.forEach(function(way) {
76084             for (var i = 0; i < way.nodes.length - 1; i++) {
76085                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
76086                     graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
76087
76088                     // Add only one midpoint on doubled-back segments,
76089                     // turning them into self-intersections.
76090                     return;
76091                 }
76092             }
76093         });
76094
76095         return graph;
76096     };
76097 }
76098
76099 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
76100 function actionAddVertex(wayId, nodeId, index) {
76101     return function(graph) {
76102         return graph.replace(graph.entity(wayId).addNode(nodeId, index));
76103     };
76104 }
76105
76106 function actionChangeMember(relationId, member, memberIndex) {
76107     return function(graph) {
76108         return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
76109     };
76110 }
76111
76112 function actionChangePreset(entityId, oldPreset, newPreset) {
76113     return function(graph) {
76114         var entity = graph.entity(entityId),
76115             geometry = entity.geometry(graph),
76116             tags = entity.tags;
76117
76118         if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
76119         if (newPreset) tags = newPreset.applyTags(tags, geometry);
76120
76121         return graph.replace(entity.update({tags: tags}));
76122     };
76123 }
76124
76125 function actionChangeTags(entityId, tags) {
76126     return function(graph) {
76127         var entity = graph.entity(entityId);
76128         return graph.replace(entity.update({tags: tags}));
76129     };
76130 }
76131
76132 function actionCircularize(wayId, projection$$1, maxAngle) {
76133     maxAngle = (maxAngle || 20) * Math.PI / 180;
76134
76135
76136     var action = function(graph, t) {
76137         if (t === null || !isFinite(t)) t = 1;
76138         t = Math.min(Math.max(+t, 0), 1);
76139
76140         var way = graph.entity(wayId),
76141             origNodes = {};
76142
76143         graph.childNodes(way).forEach(function(node) {
76144             if (!origNodes[node.id]) origNodes[node.id] = node;
76145         });
76146
76147         if (!way.isConvex(graph)) {
76148             graph = action.makeConvex(graph);
76149         }
76150
76151         var nodes = lodash.uniq(graph.childNodes(way)),
76152             keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
76153             points = nodes.map(function(n) { return projection$$1(n.loc); }),
76154             keyPoints = keyNodes.map(function(n) { return projection$$1(n.loc); }),
76155             centroid = (points.length === 2) ? geoInterp(points[0], points[1], 0.5) : d3polygonCentroid(points),
76156             radius = median(points, function(p) { return geoEuclideanDistance(centroid, p); }),
76157             sign = d3polygonArea(points) > 0 ? 1 : -1,
76158             ids;
76159
76160         // we need atleast two key nodes for the algorithm to work
76161         if (!keyNodes.length) {
76162             keyNodes = [nodes[0]];
76163             keyPoints = [points[0]];
76164         }
76165
76166         if (keyNodes.length === 1) {
76167             var index = nodes.indexOf(keyNodes[0]),
76168                 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
76169
76170             keyNodes.push(nodes[oppositeIndex]);
76171             keyPoints.push(points[oppositeIndex]);
76172         }
76173
76174         // key points and nodes are those connected to the ways,
76175         // they are projected onto the circle, inbetween nodes are moved
76176         // to constant intervals between key nodes, extra inbetween nodes are
76177         // added if necessary.
76178         for (var i = 0; i < keyPoints.length; i++) {
76179             var nextKeyNodeIndex = (i + 1) % keyNodes.length,
76180                 startNode = keyNodes[i],
76181                 endNode = keyNodes[nextKeyNodeIndex],
76182                 startNodeIndex = nodes.indexOf(startNode),
76183                 endNodeIndex = nodes.indexOf(endNode),
76184                 numberNewPoints = -1,
76185                 indexRange = endNodeIndex - startNodeIndex,
76186                 nearNodes = {},
76187                 inBetweenNodes = [],
76188                 startAngle, endAngle, totalAngle, eachAngle,
76189                 angle, loc, node, origNode, j;
76190
76191             if (indexRange < 0) {
76192                 indexRange += nodes.length;
76193             }
76194
76195             // position this key node
76196             var distance$$1 = geoEuclideanDistance(centroid, keyPoints[i]);
76197             if (distance$$1 === 0) { distance$$1 = 1e-4; }
76198             keyPoints[i] = [
76199                 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance$$1 * radius,
76200                 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance$$1 * radius
76201             ];
76202             loc = projection$$1.invert(keyPoints[i]);
76203             node = keyNodes[i];
76204             origNode = origNodes[node.id];
76205             node = node.move(geoInterp(origNode.loc, loc, t));
76206             graph = graph.replace(node);
76207
76208             // figure out the between delta angle we want to match to
76209             startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
76210             endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
76211             totalAngle = endAngle - startAngle;
76212
76213             // detects looping around -pi/pi
76214             if (totalAngle * sign > 0) {
76215                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
76216             }
76217
76218             do {
76219                 numberNewPoints++;
76220                 eachAngle = totalAngle / (indexRange + numberNewPoints);
76221             } while (Math.abs(eachAngle) > maxAngle);
76222
76223
76224             // move existing nodes
76225             for (j = 1; j < indexRange; j++) {
76226                 angle = startAngle + j * eachAngle;
76227                 loc = projection$$1.invert([
76228                     centroid[0] + Math.cos(angle) * radius,
76229                     centroid[1] + Math.sin(angle) * radius
76230                 ]);
76231
76232                 node = nodes[(j + startNodeIndex) % nodes.length];
76233                 origNode = origNodes[node.id];
76234                 nearNodes[node.id] = angle;
76235
76236                 node = node.move(geoInterp(origNode.loc, loc, t));
76237                 graph = graph.replace(node);
76238             }
76239
76240             // add new inbetween nodes if necessary
76241             for (j = 0; j < numberNewPoints; j++) {
76242                 angle = startAngle + (indexRange + j) * eachAngle;
76243                 loc = projection$$1.invert([
76244                     centroid[0] + Math.cos(angle) * radius,
76245                     centroid[1] + Math.sin(angle) * radius
76246                 ]);
76247
76248                 // choose a nearnode to use as the original
76249                 var min$$1 = Infinity;
76250                 for (var nodeId in nearNodes) {
76251                     var nearAngle = nearNodes[nodeId],
76252                         dist = Math.abs(nearAngle - angle);
76253                     if (dist < min$$1) {
76254                         dist = min$$1;
76255                         origNode = origNodes[nodeId];
76256                     }
76257                 }
76258
76259                 node = osmNode({ loc: geoInterp(origNode.loc, loc, t) });
76260                 graph = graph.replace(node);
76261
76262                 nodes.splice(endNodeIndex + j, 0, node);
76263                 inBetweenNodes.push(node.id);
76264             }
76265
76266             // Check for other ways that share these keyNodes..
76267             // If keyNodes are adjacent in both ways,
76268             // we can add inBetween nodes to that shared way too..
76269             if (indexRange === 1 && inBetweenNodes.length) {
76270                 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
76271                     endIndex1 = way.nodes.lastIndexOf(endNode.id),
76272                     wayDirection1 = (endIndex1 - startIndex1);
76273                 if (wayDirection1 < -1) { wayDirection1 = 1; }
76274
76275                 /* eslint-disable no-loop-func */
76276                 lodash.each(lodash.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
76277                     if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
76278                         var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
76279                             endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
76280                             wayDirection2 = (endIndex2 - startIndex2),
76281                             insertAt = endIndex2;
76282                         if (wayDirection2 < -1) { wayDirection2 = 1; }
76283
76284                         if (wayDirection1 !== wayDirection2) {
76285                             inBetweenNodes.reverse();
76286                             insertAt = startIndex2;
76287                         }
76288                         for (j = 0; j < inBetweenNodes.length; j++) {
76289                             sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
76290                         }
76291                         graph = graph.replace(sharedWay);
76292                     }
76293                 });
76294                 /* eslint-enable no-loop-func */
76295             }
76296
76297         }
76298
76299         // update the way to have all the new nodes
76300         ids = nodes.map(function(n) { return n.id; });
76301         ids.push(ids[0]);
76302
76303         way = way.update({nodes: ids});
76304         graph = graph.replace(way);
76305
76306         return graph;
76307     };
76308
76309
76310     action.makeConvex = function(graph) {
76311         var way = graph.entity(wayId),
76312             nodes = lodash.uniq(graph.childNodes(way)),
76313             points = nodes.map(function(n) { return projection$$1(n.loc); }),
76314             sign = d3polygonArea(points) > 0 ? 1 : -1,
76315             hull = d3polygonHull(points);
76316
76317         // D3 convex hulls go counterclockwise..
76318         if (sign === -1) {
76319             nodes.reverse();
76320             points.reverse();
76321         }
76322
76323         for (var i = 0; i < hull.length - 1; i++) {
76324             var startIndex = points.indexOf(hull[i]),
76325                 endIndex = points.indexOf(hull[i+1]),
76326                 indexRange = (endIndex - startIndex);
76327
76328             if (indexRange < 0) {
76329                 indexRange += nodes.length;
76330             }
76331
76332             // move interior nodes to the surface of the convex hull..
76333             for (var j = 1; j < indexRange; j++) {
76334                 var point = geoInterp(hull[i], hull[i+1], j / indexRange),
76335                     node = nodes[(j + startIndex) % nodes.length].move(projection$$1.invert(point));
76336                 graph = graph.replace(node);
76337             }
76338         }
76339         return graph;
76340     };
76341
76342
76343     action.disabled = function(graph) {
76344         if (!graph.entity(wayId).isClosed())
76345             return 'not_closed';
76346     };
76347
76348
76349     action.transitionable = true;
76350
76351
76352     return action;
76353 }
76354
76355 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
76356 function actionDeleteWay(wayId) {
76357
76358
76359     function canDeleteNode(node, graph) {
76360         return !graph.parentWays(node).length &&
76361             !graph.parentRelations(node).length &&
76362             !node.hasInterestingTags();
76363     }
76364
76365
76366     var action = function(graph) {
76367         var way = graph.entity(wayId);
76368
76369         graph.parentRelations(way)
76370             .forEach(function(parent) {
76371                 parent = parent.removeMembersWithID(wayId);
76372                 graph = graph.replace(parent);
76373
76374                 if (parent.isDegenerate()) {
76375                     graph = actionDeleteRelation(parent.id)(graph);
76376                 }
76377             });
76378
76379         lodash.uniq(way.nodes).forEach(function(nodeId) {
76380             graph = graph.replace(way.removeNode(nodeId));
76381
76382             var node = graph.entity(nodeId);
76383             if (canDeleteNode(node, graph)) {
76384                 graph = graph.remove(node);
76385             }
76386         });
76387
76388         return graph.remove(way);
76389     };
76390
76391
76392     return action;
76393 }
76394
76395 function actionDeleteMultiple(ids) {
76396     var actions = {
76397         way: actionDeleteWay,
76398         node: actionDeleteNode,
76399         relation: actionDeleteRelation
76400     };
76401
76402
76403     var action = function(graph) {
76404         ids.forEach(function(id) {
76405             if (graph.hasEntity(id)) { // It may have been deleted aready.
76406                 graph = actions[graph.entity(id).type](id)(graph);
76407             }
76408         });
76409
76410         return graph;
76411     };
76412
76413
76414     return action;
76415 }
76416
76417 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
76418 function actionDeleteRelation(relationId) {
76419
76420
76421     function canDeleteEntity(entity, graph) {
76422         return !graph.parentWays(entity).length &&
76423             !graph.parentRelations(entity).length &&
76424             !entity.hasInterestingTags();
76425     }
76426
76427
76428     var action = function(graph) {
76429         var relation = graph.entity(relationId);
76430
76431         graph.parentRelations(relation)
76432             .forEach(function(parent) {
76433                 parent = parent.removeMembersWithID(relationId);
76434                 graph = graph.replace(parent);
76435
76436                 if (parent.isDegenerate()) {
76437                     graph = actionDeleteRelation(parent.id)(graph);
76438                 }
76439             });
76440
76441         lodash.uniq(lodash.map(relation.members, 'id')).forEach(function(memberId) {
76442             graph = graph.replace(relation.removeMembersWithID(memberId));
76443
76444             var entity = graph.entity(memberId);
76445             if (canDeleteEntity(entity, graph)) {
76446                 graph = actionDeleteMultiple([memberId])(graph);
76447             }
76448         });
76449
76450         return graph.remove(relation);
76451     };
76452
76453
76454     return action;
76455 }
76456
76457 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
76458 function actionDeleteNode(nodeId) {
76459     var action = function(graph) {
76460         var node = graph.entity(nodeId);
76461
76462         graph.parentWays(node)
76463             .forEach(function(parent) {
76464                 parent = parent.removeNode(nodeId);
76465                 graph = graph.replace(parent);
76466
76467                 if (parent.isDegenerate()) {
76468                     graph = actionDeleteWay(parent.id)(graph);
76469                 }
76470             });
76471
76472         graph.parentRelations(node)
76473             .forEach(function(parent) {
76474                 parent = parent.removeMembersWithID(nodeId);
76475                 graph = graph.replace(parent);
76476
76477                 if (parent.isDegenerate()) {
76478                     graph = actionDeleteRelation(parent.id)(graph);
76479                 }
76480             });
76481
76482         return graph.remove(node);
76483     };
76484
76485
76486     return action;
76487 }
76488
76489 // Connect the ways at the given nodes.
76490 //
76491 // The last node will survive. All other nodes will be replaced with
76492 // the surviving node in parent ways, and then removed.
76493 //
76494 // Tags and relation memberships of of non-surviving nodes are merged
76495 // to the survivor.
76496 //
76497 // This is the inverse of `iD.actionDisconnect`.
76498 //
76499 // Reference:
76500 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
76501 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
76502 //
76503 function actionConnect(nodeIds) {
76504     return function(graph) {
76505         var survivor = graph.entity(lodash.last(nodeIds));
76506
76507         for (var i = 0; i < nodeIds.length - 1; i++) {
76508             var node = graph.entity(nodeIds[i]);
76509
76510             /* eslint-disable no-loop-func */
76511             graph.parentWays(node).forEach(function(parent) {
76512                 if (!parent.areAdjacent(node.id, survivor.id)) {
76513                     graph = graph.replace(parent.replaceNode(node.id, survivor.id));
76514                 }
76515             });
76516
76517             graph.parentRelations(node).forEach(function(parent) {
76518                 graph = graph.replace(parent.replaceMember(node, survivor));
76519             });
76520             /* eslint-enable no-loop-func */
76521
76522             survivor = survivor.mergeTags(node.tags);
76523             graph = actionDeleteNode(node.id)(graph);
76524         }
76525
76526         graph = graph.replace(survivor);
76527
76528         return graph;
76529     };
76530 }
76531
76532 function actionCopyEntities(ids, fromGraph) {
76533     var copies = {};
76534
76535
76536     var action = function(graph) {
76537         ids.forEach(function(id) {
76538             fromGraph.entity(id).copy(fromGraph, copies);
76539         });
76540
76541         for (var id in copies) {
76542             graph = graph.replace(copies[id]);
76543         }
76544
76545         return graph;
76546     };
76547
76548
76549     action.copies = function() {
76550         return copies;
76551     };
76552
76553
76554     return action;
76555 }
76556
76557 function actionDeleteMember(relationId, memberIndex) {
76558     return function(graph) {
76559         var relation = graph.entity(relationId)
76560             .removeMember(memberIndex);
76561
76562         graph = graph.replace(relation);
76563
76564         if (relation.isDegenerate())
76565             graph = actionDeleteRelation(relation.id)(graph);
76566
76567         return graph;
76568     };
76569 }
76570
76571 function actionDeprecateTags(entityId) {
76572
76573     return function(graph) {
76574         var entity = graph.entity(entityId),
76575             newtags = lodash.clone(entity.tags),
76576             change = false,
76577             rule;
76578
76579         // This handles dataDeprecated tags with a single condition
76580         for (var i = 0; i < dataDeprecated.length; i++) {
76581
76582             rule = dataDeprecated[i];
76583             var match = lodash.toPairs(rule.old)[0],
76584                 replacements = rule.replace ? lodash.toPairs(rule.replace) : null;
76585
76586             if (entity.tags[match[0]] && match[1] === '*') {
76587
76588                 var value = entity.tags[match[0]];
76589                 if (replacements && !newtags[replacements[0][0]]) {
76590                     newtags[replacements[0][0]] = value;
76591                 }
76592                 delete newtags[match[0]];
76593                 change = true;
76594
76595             } else if (entity.tags[match[0]] === match[1]) {
76596                 newtags = lodash.assign({}, rule.replace || {}, lodash.omit(newtags, match[0]));
76597                 change = true;
76598             }
76599         }
76600
76601         if (change) {
76602             return graph.replace(entity.update({tags: newtags}));
76603         } else {
76604             return graph;
76605         }
76606     };
76607 }
76608
76609 function actionDiscardTags(difference) {
76610
76611     return function(graph) {
76612         function discardTags(entity) {
76613             if (!lodash.isEmpty(entity.tags)) {
76614                 var tags = {};
76615                 lodash.each(entity.tags, function(v, k) {
76616                     if (v) tags[k] = v;
76617                 });
76618
76619                 graph = graph.replace(entity.update({
76620                     tags: lodash.omit(tags, dataDiscarded)
76621                 }));
76622             }
76623         }
76624
76625         difference.modified().forEach(discardTags);
76626         difference.created().forEach(discardTags);
76627
76628         return graph;
76629     };
76630 }
76631
76632 // Disconect the ways at the given node.
76633 //
76634 // Optionally, disconnect only the given ways.
76635 //
76636 // For testing convenience, accepts an ID to assign to the (first) new node.
76637 // Normally, this will be undefined and the way will automatically
76638 // be assigned a new ID.
76639 //
76640 // This is the inverse of `iD.actionConnect`.
76641 //
76642 // Reference:
76643 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
76644 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
76645 //
76646 function actionDisconnect(nodeId, newNodeId) {
76647     var wayIds;
76648
76649
76650     var action = function(graph) {
76651         var node = graph.entity(nodeId),
76652             connections = action.connections(graph);
76653
76654         connections.forEach(function(connection) {
76655             var way = graph.entity(connection.wayID),
76656                 newNode = osmNode({id: newNodeId, loc: node.loc, tags: node.tags});
76657
76658             graph = graph.replace(newNode);
76659             if (connection.index === 0 && way.isArea()) {
76660                 // replace shared node with shared node..
76661                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
76662             } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
76663                 // replace closing node with new new node..
76664                 graph = graph.replace(way.unclose().addNode(newNode.id));
76665             } else {
76666                 // replace shared node with multiple new nodes..
76667                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
76668             }
76669         });
76670
76671         return graph;
76672     };
76673
76674
76675     action.connections = function(graph) {
76676         var candidates = [],
76677             keeping = false,
76678             parentWays = graph.parentWays(graph.entity(nodeId));
76679
76680         parentWays.forEach(function(way) {
76681             if (wayIds && wayIds.indexOf(way.id) === -1) {
76682                 keeping = true;
76683                 return;
76684             }
76685             if (way.isArea() && (way.nodes[0] === nodeId)) {
76686                 candidates.push({ wayID: way.id, index: 0 });
76687             } else {
76688                 way.nodes.forEach(function(waynode, index) {
76689                     if (waynode === nodeId) {
76690                         candidates.push({ wayID: way.id, index: index });
76691                     }
76692                 });
76693             }
76694         });
76695
76696         return keeping ? candidates : candidates.slice(1);
76697     };
76698
76699
76700     action.disabled = function(graph) {
76701         var connections = action.connections(graph);
76702         if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
76703             return 'not_connected';
76704
76705         var parentWays = graph.parentWays(graph.entity(nodeId)),
76706             seenRelationIds = {},
76707             sharedRelation;
76708
76709         parentWays.forEach(function(way) {
76710             if (wayIds && wayIds.indexOf(way.id) === -1)
76711                 return;
76712
76713             var relations = graph.parentRelations(way);
76714             relations.forEach(function(relation) {
76715                 if (relation.id in seenRelationIds) {
76716                     sharedRelation = relation;
76717                 } else {
76718                     seenRelationIds[relation.id] = true;
76719                 }
76720             });
76721         });
76722
76723         if (sharedRelation)
76724             return 'relation';
76725     };
76726
76727
76728     action.limitWays = function(_) {
76729         if (!arguments.length) return wayIds;
76730         wayIds = _;
76731         return action;
76732     };
76733
76734
76735     return action;
76736 }
76737
76738 // Join ways at the end node they share.
76739 //
76740 // This is the inverse of `iD.actionSplit`.
76741 //
76742 // Reference:
76743 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
76744 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
76745 //
76746 function actionJoin(ids) {
76747
76748     function groupEntitiesByGeometry(graph) {
76749         var entities = ids.map(function(id) { return graph.entity(id); });
76750         return lodash.extend({line: []}, lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
76751     }
76752
76753
76754     var action = function(graph) {
76755         var ways = ids.map(graph.entity, graph),
76756             survivor = ways[0];
76757
76758         // Prefer to keep an existing way.
76759         for (var i = 0; i < ways.length; i++) {
76760             if (!ways[i].isNew()) {
76761                 survivor = ways[i];
76762                 break;
76763             }
76764         }
76765
76766         var joined = osmJoinWays(ways, graph)[0];
76767
76768         survivor = survivor.update({nodes: lodash.map(joined.nodes, 'id')});
76769         graph = graph.replace(survivor);
76770
76771         joined.forEach(function(way) {
76772             if (way.id === survivor.id)
76773                 return;
76774
76775             graph.parentRelations(way).forEach(function(parent) {
76776                 graph = graph.replace(parent.replaceMember(way, survivor));
76777             });
76778
76779             survivor = survivor.mergeTags(way.tags);
76780
76781             graph = graph.replace(survivor);
76782             graph = actionDeleteWay(way.id)(graph);
76783         });
76784
76785         return graph;
76786     };
76787
76788
76789     action.disabled = function(graph) {
76790         var geometries = groupEntitiesByGeometry(graph);
76791         if (ids.length < 2 || ids.length !== geometries.line.length)
76792             return 'not_eligible';
76793
76794         var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
76795         if (joined.length > 1)
76796             return 'not_adjacent';
76797
76798         var nodeIds = lodash.map(joined[0].nodes, 'id').slice(1, -1),
76799             relation,
76800             tags = {},
76801             conflicting = false;
76802
76803         joined[0].forEach(function(way) {
76804             var parents = graph.parentRelations(way);
76805             parents.forEach(function(parent) {
76806                 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
76807                     relation = parent;
76808             });
76809
76810             for (var k in way.tags) {
76811                 if (!(k in tags)) {
76812                     tags[k] = way.tags[k];
76813                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
76814                     conflicting = true;
76815                 }
76816             }
76817         });
76818
76819         if (relation)
76820             return 'restriction';
76821
76822         if (conflicting)
76823             return 'conflicting_tags';
76824     };
76825
76826
76827     return action;
76828 }
76829
76830 function actionMerge(ids) {
76831
76832     function groupEntitiesByGeometry(graph) {
76833         var entities = ids.map(function(id) { return graph.entity(id); });
76834         return lodash.extend({point: [], area: [], line: [], relation: []},
76835             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
76836     }
76837
76838
76839     var action = function(graph) {
76840         var geometries = groupEntitiesByGeometry(graph),
76841             target = geometries.area[0] || geometries.line[0],
76842             points = geometries.point;
76843
76844         points.forEach(function(point) {
76845             target = target.mergeTags(point.tags);
76846             graph = graph.replace(target);
76847
76848             graph.parentRelations(point).forEach(function(parent) {
76849                 graph = graph.replace(parent.replaceMember(point, target));
76850             });
76851
76852             var nodes = lodash.uniq(graph.childNodes(target)),
76853                 removeNode = point;
76854
76855             for (var i = 0; i < nodes.length; i++) {
76856                 var node = nodes[i];
76857                 if (graph.parentWays(node).length > 1 ||
76858                     graph.parentRelations(node).length ||
76859                     node.hasInterestingTags()) {
76860                     continue;
76861                 }
76862
76863                 // Found an uninteresting child node on the target way.
76864                 // Move orig point into its place to preserve point's history. #3683
76865                 graph = graph.replace(point.update({ tags: {}, loc: node.loc }));
76866                 target = target.replaceNode(node.id, point.id);
76867                 graph = graph.replace(target);
76868                 removeNode = node;
76869                 break;
76870             }
76871
76872             graph = graph.remove(removeNode);
76873         });
76874
76875         return graph;
76876     };
76877
76878
76879     action.disabled = function(graph) {
76880         var geometries = groupEntitiesByGeometry(graph);
76881         if (geometries.point.length === 0 ||
76882             (geometries.area.length + geometries.line.length) !== 1 ||
76883             geometries.relation.length !== 0)
76884             return 'not_eligible';
76885     };
76886
76887
76888     return action;
76889 }
76890
76891 function actionMergePolygon(ids, newRelationId) {
76892
76893     function groupEntities(graph) {
76894         var entities = ids.map(function (id) { return graph.entity(id); });
76895         return lodash.extend({
76896                 closedWay: [],
76897                 multipolygon: [],
76898                 other: []
76899             }, lodash.groupBy(entities, function(entity) {
76900                 if (entity.type === 'way' && entity.isClosed()) {
76901                     return 'closedWay';
76902                 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
76903                     return 'multipolygon';
76904                 } else {
76905                     return 'other';
76906                 }
76907             }));
76908     }
76909
76910
76911     var action = function(graph) {
76912         var entities = groupEntities(graph);
76913
76914         // An array representing all the polygons that are part of the multipolygon.
76915         //
76916         // Each element is itself an array of objects with an id property, and has a
76917         // locs property which is an array of the locations forming the polygon.
76918         var polygons = entities.multipolygon.reduce(function(polygons, m) {
76919             return polygons.concat(osmJoinWays(m.members, graph));
76920         }, []).concat(entities.closedWay.map(function(d) {
76921             var member = [{id: d.id}];
76922             member.nodes = graph.childNodes(d);
76923             return member;
76924         }));
76925
76926         // contained is an array of arrays of boolean values,
76927         // where contained[j][k] is true iff the jth way is
76928         // contained by the kth way.
76929         var contained = polygons.map(function(w, i) {
76930             return polygons.map(function(d, n) {
76931                 if (i === n) return null;
76932                 return geoPolygonContainsPolygon(
76933                     lodash.map(d.nodes, 'loc'),
76934                     lodash.map(w.nodes, 'loc'));
76935             });
76936         });
76937
76938         // Sort all polygons as either outer or inner ways
76939         var members = [],
76940             outer = true;
76941
76942         while (polygons.length) {
76943             extractUncontained(polygons);
76944             polygons = polygons.filter(isContained);
76945             contained = contained.filter(isContained).map(filterContained);
76946         }
76947
76948         function isContained(d, i) {
76949             return lodash.some(contained[i]);
76950         }
76951
76952         function filterContained(d) {
76953             return d.filter(isContained);
76954         }
76955
76956         function extractUncontained(polygons) {
76957             polygons.forEach(function(d, i) {
76958                 if (!isContained(d, i)) {
76959                     d.forEach(function(member) {
76960                         members.push({
76961                             type: 'way',
76962                             id: member.id,
76963                             role: outer ? 'outer' : 'inner'
76964                         });
76965                     });
76966                 }
76967             });
76968             outer = !outer;
76969         }
76970
76971         // Move all tags to one relation
76972         var relation = entities.multipolygon[0] ||
76973             osmRelation({ id: newRelationId, tags: { type: 'multipolygon' }});
76974
76975         entities.multipolygon.slice(1).forEach(function(m) {
76976             relation = relation.mergeTags(m.tags);
76977             graph = graph.remove(m);
76978         });
76979
76980         entities.closedWay.forEach(function(way) {
76981             function isThisOuter(m) {
76982                 return m.id === way.id && m.role !== 'inner';
76983             }
76984             if (members.some(isThisOuter)) {
76985                 relation = relation.mergeTags(way.tags);
76986                 graph = graph.replace(way.update({ tags: {} }));
76987             }
76988         });
76989
76990         return graph.replace(relation.update({
76991             members: members,
76992             tags: lodash.omit(relation.tags, 'area')
76993         }));
76994     };
76995
76996
76997     action.disabled = function(graph) {
76998         var entities = groupEntities(graph);
76999         if (entities.other.length > 0 ||
77000             entities.closedWay.length + entities.multipolygon.length < 2)
77001             return 'not_eligible';
77002         if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
77003             return 'incomplete_relation';
77004     };
77005
77006
77007     return action;
77008 }
77009
77010 // Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
77011 // Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
77012 //
77013 // Permission is hereby granted, free of charge, to any person
77014 // obtaining a copy of this software and associated documentation files
77015 // (the "Software"), to deal in the Software without restriction,
77016 // including without limitation the rights to use, copy, modify, merge,
77017 // publish, distribute, sublicense, and/or sell copies of the Software,
77018 // and to permit persons to whom the Software is furnished to do so,
77019 // subject to the following conditions:
77020 //
77021 // The above copyright notice and this permission notice shall be
77022 // included in all copies or substantial portions of the Software.
77023 //
77024 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
77025 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
77026 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
77027 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
77028 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
77029 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
77030 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
77031 // SOFTWARE.
77032
77033 // source:  https://bitbucket.org/lshift/synchrotron/src
77034 function longest_common_subsequence(file1, file2) {
77035     /* Text diff algorithm following Hunt and McIlroy 1976.
77036      * J. W. Hunt and M. D. McIlroy, An algorithm for differential file
77037      * comparison, Bell Telephone Laboratories CSTR #41 (1976)
77038      * http://www.cs.dartmouth.edu/~doug/
77039      *
77040      * Expects two arrays of strings.
77041      */
77042     var equivalenceClasses;
77043     var file2indices;
77044     var newCandidate;
77045     var candidates;
77046     var line;
77047     var c, i, j, jX, r, s;
77048
77049     equivalenceClasses = {};
77050     for (j = 0; j < file2.length; j++) {
77051         line = file2[j];
77052         if (equivalenceClasses[line]) {
77053             equivalenceClasses[line].push(j);
77054         } else {
77055             equivalenceClasses[line] = [j];
77056         }
77057     }
77058
77059     candidates = [{file1index: -1,
77060                    file2index: -1,
77061                    chain: null}];
77062
77063     for (i = 0; i < file1.length; i++) {
77064         line = file1[i];
77065         file2indices = equivalenceClasses[line] || [];
77066
77067         r = 0;
77068         c = candidates[0];
77069
77070         for (jX = 0; jX < file2indices.length; jX++) {
77071             j = file2indices[jX];
77072
77073             for (s = 0; s < candidates.length; s++) {
77074                 if ((candidates[s].file2index < j) &&
77075                     ((s === candidates.length - 1) ||
77076                      (candidates[s + 1].file2index > j)))
77077                     break;
77078             }
77079
77080             if (s < candidates.length) {
77081                 newCandidate = {file1index: i,
77082                                 file2index: j,
77083                                 chain: candidates[s]};
77084                 if (r === candidates.length) {
77085                     candidates.push(c);
77086                 } else {
77087                     candidates[r] = c;
77088                 }
77089                 r = s + 1;
77090                 c = newCandidate;
77091                 if (r === candidates.length) {
77092                     break; // no point in examining further (j)s
77093                 }
77094             }
77095         }
77096
77097         candidates[r] = c;
77098     }
77099
77100     // At this point, we know the LCS: it's in the reverse of the
77101     // linked-list through .chain of
77102     // candidates[candidates.length - 1].
77103
77104     return candidates[candidates.length - 1];
77105 }
77106
77107
77108
77109
77110
77111
77112
77113
77114
77115
77116
77117 function diff_indices(file1, file2) {
77118     // We apply the LCS to give a simple representation of the
77119     // offsets and lengths of mismatched chunks in the input
77120     // files. This is used by diff3_merge_indices below.
77121
77122     var result = [];
77123     var tail1 = file1.length;
77124     var tail2 = file2.length;
77125
77126     for (var candidate = longest_common_subsequence(file1, file2);
77127          candidate !== null;
77128          candidate = candidate.chain)
77129     {
77130         var mismatchLength1 = tail1 - candidate.file1index - 1;
77131         var mismatchLength2 = tail2 - candidate.file2index - 1;
77132         tail1 = candidate.file1index;
77133         tail2 = candidate.file2index;
77134
77135         if (mismatchLength1 || mismatchLength2) {
77136             result.push({file1: [tail1 + 1, mismatchLength1],
77137                          file2: [tail2 + 1, mismatchLength2]});
77138         }
77139     }
77140
77141     result.reverse();
77142     return result;
77143 }
77144
77145 function diff3_merge_indices (a, o, b) {
77146     // Given three files, A, O, and B, where both A and B are
77147     // independently derived from O, returns a fairly complicated
77148     // internal representation of merge decisions it's taken. The
77149     // interested reader may wish to consult
77150     //
77151     // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
77152     // Formal Investigation of Diff3." In Arvind and Prasad,
77153     // editors, Foundations of Software Technology and Theoretical
77154     // Computer Science (FSTTCS), December 2007.
77155     //
77156     // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
77157     var i;
77158
77159     var m1 = diff_indices(o, a);
77160     var m2 = diff_indices(o, b);
77161
77162     var hunks = [];
77163     function addHunk(h, side) {
77164         hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]);
77165     }
77166     for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); }
77167     for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); }
77168     hunks.sort();
77169
77170     var result = [];
77171     var commonOffset = 0;
77172     function copyCommon(targetOffset) {
77173         if (targetOffset > commonOffset) {
77174             result.push([1, commonOffset, targetOffset - commonOffset]);
77175             commonOffset = targetOffset;
77176         }
77177     }
77178
77179     for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {
77180         var firstHunkIndex = hunkIndex;
77181         var hunk = hunks[hunkIndex];
77182         var regionLhs = hunk[0];
77183         var regionRhs = regionLhs + hunk[2];
77184         while (hunkIndex < hunks.length - 1) {
77185             var maybeOverlapping = hunks[hunkIndex + 1];
77186             var maybeLhs = maybeOverlapping[0];
77187             if (maybeLhs > regionRhs) break;
77188             regionRhs = maybeLhs + maybeOverlapping[2];
77189             hunkIndex++;
77190         }
77191
77192         copyCommon(regionLhs);
77193         if (firstHunkIndex === hunkIndex) {
77194     // The "overlap" was only one hunk long, meaning that
77195     // there's no conflict here. Either a and o were the
77196     // same, or b and o were the same.
77197             if (hunk[4] > 0) {
77198                 result.push([hunk[1], hunk[3], hunk[4]]);
77199             }
77200         } else {
77201     // A proper conflict. Determine the extents of the
77202     // regions involved from a, o and b. Effectively merge
77203     // all the hunks on the left into one giant hunk, and
77204     // do the same for the right; then, correct for skew
77205     // in the regions of o that each side changed, and
77206     // report appropriate spans for the three sides.
77207     var regions = {
77208         0: [a.length, -1, o.length, -1],
77209         2: [b.length, -1, o.length, -1]
77210     };
77211             for (i = firstHunkIndex; i <= hunkIndex; i++) {
77212         hunk = hunks[i];
77213                 var side = hunk[1];
77214         var r = regions[side];
77215         var oLhs = hunk[0];
77216         var oRhs = oLhs + hunk[2];
77217                 var abLhs = hunk[3];
77218                 var abRhs = abLhs + hunk[4];
77219         r[0] = Math.min(abLhs, r[0]);
77220         r[1] = Math.max(abRhs, r[1]);
77221         r[2] = Math.min(oLhs, r[2]);
77222         r[3] = Math.max(oRhs, r[3]);
77223             }
77224     var aLhs = regions[0][0] + (regionLhs - regions[0][2]);
77225     var aRhs = regions[0][1] + (regionRhs - regions[0][3]);
77226     var bLhs = regions[2][0] + (regionLhs - regions[2][2]);
77227     var bRhs = regions[2][1] + (regionRhs - regions[2][3]);
77228             result.push([-1,
77229              aLhs,      aRhs      - aLhs,
77230              regionLhs, regionRhs - regionLhs,
77231              bLhs,      bRhs      - bLhs]);
77232         }
77233         commonOffset = regionRhs;
77234     }
77235
77236     copyCommon(o.length);
77237     return result;
77238 }
77239
77240 function diff3_merge (a, o, b, excludeFalseConflicts) {
77241     // Applies the output of Diff3.diff3_merge_indices to actually
77242     // construct the merged file; the returned result alternates
77243     // between "ok" and "conflict" blocks.
77244
77245     var result = [];
77246     var files = [a, o, b];
77247     var indices = diff3_merge_indices(a, o, b);
77248
77249     var okLines = [];
77250     function flushOk() {
77251         if (okLines.length) {
77252             result.push({ok: okLines});
77253         }
77254         okLines = [];
77255     }
77256     function pushOk(xs) {
77257         for (var j = 0; j < xs.length; j++) {
77258             okLines.push(xs[j]);
77259         }
77260     }
77261
77262     function isTrueConflict(rec) {
77263         if (rec[2] !== rec[6]) return true;
77264         var aoff = rec[1];
77265         var boff = rec[5];
77266         for (var j = 0; j < rec[2]; j++) {
77267             if (a[j + aoff] !== b[j + boff]) return true;
77268         }
77269         return false;
77270     }
77271
77272     for (var i = 0; i < indices.length; i++) {
77273         var x = indices[i];
77274         var side = x[0];
77275         if (side === -1) {
77276             if (excludeFalseConflicts && !isTrueConflict(x)) {
77277                 pushOk(files[0].slice(x[1], x[1] + x[2]));
77278             } else {
77279                 flushOk();
77280                 result.push({conflict: {a: a.slice(x[1], x[1] + x[2]),
77281                                         aIndex: x[1],
77282                                         o: o.slice(x[3], x[3] + x[4]),
77283                                         oIndex: x[3],
77284                                         b: b.slice(x[5], x[5] + x[6]),
77285                                         bIndex: x[5]}});
77286             }
77287         } else {
77288             pushOk(files[side].slice(x[1], x[1] + x[2]));
77289         }
77290     }
77291
77292     flushOk();
77293     return result;
77294 }
77295
77296 function actionMergeRemoteChanges(id, localGraph, remoteGraph, formatUser) {
77297     var option = 'safe',  // 'safe', 'force_local', 'force_remote'
77298         conflicts = [];
77299
77300
77301     function user(d) {
77302         return lodash.isFunction(formatUser) ? formatUser(d) : d;
77303     }
77304
77305
77306     function mergeLocation(remote, target) {
77307         function pointEqual(a, b) {
77308             var epsilon = 1e-6;
77309             return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
77310         }
77311
77312         if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
77313             return target;
77314         }
77315         if (option === 'force_remote') {
77316             return target.update({loc: remote.loc});
77317         }
77318
77319         conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
77320         return target;
77321     }
77322
77323
77324     function mergeNodes(base, remote, target) {
77325         if (option === 'force_local' || lodash.isEqual(target.nodes, remote.nodes)) {
77326             return target;
77327         }
77328         if (option === 'force_remote') {
77329             return target.update({nodes: remote.nodes});
77330         }
77331
77332         var ccount = conflicts.length,
77333             o = base.nodes || [],
77334             a = target.nodes || [],
77335             b = remote.nodes || [],
77336             nodes = [],
77337             hunks = diff3_merge(a, o, b, true);
77338
77339         for (var i = 0; i < hunks.length; i++) {
77340             var hunk = hunks[i];
77341             if (hunk.ok) {
77342                 nodes.push.apply(nodes, hunk.ok);
77343             } else {
77344                 // for all conflicts, we can assume c.a !== c.b
77345                 // because `diff3_merge` called with `true` option to exclude false conflicts..
77346                 var c = hunk.conflict;
77347                 if (lodash.isEqual(c.o, c.a)) {  // only changed remotely
77348                     nodes.push.apply(nodes, c.b);
77349                 } else if (lodash.isEqual(c.o, c.b)) {  // only changed locally
77350                     nodes.push.apply(nodes, c.a);
77351                 } else {       // changed both locally and remotely
77352                     conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
77353                     break;
77354                 }
77355             }
77356         }
77357
77358         return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
77359     }
77360
77361
77362     function mergeChildren(targetWay, children, updates, graph) {
77363         function isUsed(node, targetWay) {
77364             var parentWays = lodash.map(graph.parentWays(node), 'id');
77365             return node.hasInterestingTags() ||
77366                 lodash.without(parentWays, targetWay.id).length > 0 ||
77367                 graph.parentRelations(node).length > 0;
77368         }
77369
77370         var ccount = conflicts.length;
77371
77372         for (var i = 0; i < children.length; i++) {
77373             var id = children[i],
77374                 node = graph.hasEntity(id);
77375
77376             // remove unused childNodes..
77377             if (targetWay.nodes.indexOf(id) === -1) {
77378                 if (node && !isUsed(node, targetWay)) {
77379                     updates.removeIds.push(id);
77380                 }
77381                 continue;
77382             }
77383
77384             // restore used childNodes..
77385             var local = localGraph.hasEntity(id),
77386                 remote = remoteGraph.hasEntity(id),
77387                 target;
77388
77389             if (option === 'force_remote' && remote && remote.visible) {
77390                 updates.replacements.push(remote);
77391
77392             } else if (option === 'force_local' && local) {
77393                 target = osmEntity$$1(local);
77394                 if (remote) {
77395                     target = target.update({ version: remote.version });
77396                 }
77397                 updates.replacements.push(target);
77398
77399             } else if (option === 'safe' && local && remote && local.version !== remote.version) {
77400                 target = osmEntity$$1(local, { version: remote.version });
77401                 if (remote.visible) {
77402                     target = mergeLocation(remote, target);
77403                 } else {
77404                     conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
77405                 }
77406
77407                 if (conflicts.length !== ccount) break;
77408                 updates.replacements.push(target);
77409             }
77410         }
77411
77412         return targetWay;
77413     }
77414
77415
77416     function updateChildren(updates, graph) {
77417         for (var i = 0; i < updates.replacements.length; i++) {
77418             graph = graph.replace(updates.replacements[i]);
77419         }
77420         if (updates.removeIds.length) {
77421             graph = actionDeleteMultiple(updates.removeIds)(graph);
77422         }
77423         return graph;
77424     }
77425
77426
77427     function mergeMembers(remote, target) {
77428         if (option === 'force_local' || lodash.isEqual(target.members, remote.members)) {
77429             return target;
77430         }
77431         if (option === 'force_remote') {
77432             return target.update({members: remote.members});
77433         }
77434
77435         conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
77436         return target;
77437     }
77438
77439
77440     function mergeTags(base, remote, target) {
77441         function ignoreKey(k) {
77442             return lodash.includes(dataDiscarded, k);
77443         }
77444
77445         if (option === 'force_local' || lodash.isEqual(target.tags, remote.tags)) {
77446             return target;
77447         }
77448         if (option === 'force_remote') {
77449             return target.update({tags: remote.tags});
77450         }
77451
77452         var ccount = conflicts.length,
77453             o = base.tags || {},
77454             a = target.tags || {},
77455             b = remote.tags || {},
77456             keys = lodash.reject(lodash.union(lodash.keys(o), lodash.keys(a), lodash.keys(b)), ignoreKey),
77457             tags = lodash.clone(a),
77458             changed = false;
77459
77460         for (var i = 0; i < keys.length; i++) {
77461             var k = keys[i];
77462
77463             if (o[k] !== b[k] && a[k] !== b[k]) {    // changed remotely..
77464                 if (o[k] !== a[k]) {      // changed locally..
77465                     conflicts.push(t('merge_remote_changes.conflict.tags',
77466                         { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
77467
77468                 } else {                  // unchanged locally, accept remote change..
77469                     if (b.hasOwnProperty(k)) {
77470                         tags[k] = b[k];
77471                     } else {
77472                         delete tags[k];
77473                     }
77474                     changed = true;
77475                 }
77476             }
77477         }
77478
77479         return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
77480     }
77481
77482
77483     //  `graph.base()` is the common ancestor of the two graphs.
77484     //  `localGraph` contains user's edits up to saving
77485     //  `remoteGraph` contains remote edits to modified nodes
77486     //  `graph` must be a descendent of `localGraph` and may include
77487     //      some conflict resolution actions performed on it.
77488     //
77489     //                  --- ... --- `localGraph` -- ... -- `graph`
77490     //                 /
77491     //  `graph.base()` --- ... --- `remoteGraph`
77492     //
77493     var action = function(graph) {
77494         var updates = { replacements: [], removeIds: [] },
77495             base = graph.base().entities[id],
77496             local = localGraph.entity(id),
77497             remote = remoteGraph.entity(id),
77498             target = osmEntity$$1(local, { version: remote.version });
77499
77500         // delete/undelete
77501         if (!remote.visible) {
77502             if (option === 'force_remote') {
77503                 return actionDeleteMultiple([id])(graph);
77504
77505             } else if (option === 'force_local') {
77506                 if (target.type === 'way') {
77507                     target = mergeChildren(target, lodash.uniq(local.nodes), updates, graph);
77508                     graph = updateChildren(updates, graph);
77509                 }
77510                 return graph.replace(target);
77511
77512             } else {
77513                 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
77514                 return graph;  // do nothing
77515             }
77516         }
77517
77518         // merge
77519         if (target.type === 'node') {
77520             target = mergeLocation(remote, target);
77521
77522         } else if (target.type === 'way') {
77523             // pull in any child nodes that may not be present locally..
77524             graph.rebase(remoteGraph.childNodes(remote), [graph], false);
77525             target = mergeNodes(base, remote, target);
77526             target = mergeChildren(target, lodash.union(local.nodes, remote.nodes), updates, graph);
77527
77528         } else if (target.type === 'relation') {
77529             target = mergeMembers(remote, target);
77530         }
77531
77532         target = mergeTags(base, remote, target);
77533
77534         if (!conflicts.length) {
77535             graph = updateChildren(updates, graph).replace(target);
77536         }
77537
77538         return graph;
77539     };
77540
77541
77542     action.withOption = function(opt) {
77543         option = opt;
77544         return action;
77545     };
77546
77547
77548     action.conflicts = function() {
77549         return conflicts;
77550     };
77551
77552
77553     return action;
77554 }
77555
77556 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
77557 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
77558 function actionMove(moveIds, tryDelta, projection, cache) {
77559     var delta = tryDelta;
77560
77561     function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
77562     function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
77563
77564     function setupCache(graph) {
77565         function canMove(nodeId) {
77566             // Allow movement of any node that is in the selectedIDs list..
77567             if (moveIds.indexOf(nodeId) !== -1) return true;
77568
77569             // Allow movement of a vertex where 2 ways meet..
77570             var parents = lodash.map(graph.parentWays(graph.entity(nodeId)), 'id');
77571             if (parents.length < 3) return true;
77572
77573             // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
77574             var parentsMoving = lodash.every(parents, function(id) { return cache.moving[id]; });
77575             if (!parentsMoving) delete cache.moving[nodeId];
77576
77577             return parentsMoving;
77578         }
77579
77580         function cacheEntities(ids) {
77581             ids.forEach(function(id) {
77582                 if (cache.moving[id]) return;
77583                 cache.moving[id] = true;
77584
77585                 var entity = graph.hasEntity(id);
77586                 if (!entity) return;
77587
77588                 if (entity.type === 'node') {
77589                     cache.nodes.push(id);
77590                     cache.startLoc[id] = entity.loc;
77591                 } else if (entity.type === 'way') {
77592                     cache.ways.push(id);
77593                     cacheEntities(entity.nodes);
77594                 } else {
77595                     cacheEntities(entity.members.map(function(member) {
77596                         return member.id;
77597                     }));
77598                 }
77599             });
77600         }
77601
77602         function cacheIntersections(ids) {
77603             function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
77604
77605             ids.forEach(function(id) {
77606                 // consider only intersections with 1 moved and 1 unmoved way.
77607                 var childNodes = graph.childNodes(graph.entity(id));
77608                 childNodes.forEach(function(node) {
77609                     var parents = graph.parentWays(node);
77610                     if (parents.length !== 2) return;
77611
77612                     var moved = graph.entity(id),
77613                         unmoved = lodash.find(parents, function(way) { return !cache.moving[way.id]; });
77614                     if (!unmoved) return;
77615
77616                     // exclude ways that are overly connected..
77617                     if (lodash.intersection(moved.nodes, unmoved.nodes).length > 2) return;
77618
77619                     if (moved.isArea() || unmoved.isArea()) return;
77620
77621                     cache.intersection[node.id] = {
77622                         nodeId: node.id,
77623                         movedId: moved.id,
77624                         unmovedId: unmoved.id,
77625                         movedIsEP: isEndpoint(moved, node.id),
77626                         unmovedIsEP: isEndpoint(unmoved, node.id)
77627                     };
77628                 });
77629             });
77630         }
77631
77632
77633         if (!cache) {
77634             cache = {};
77635         }
77636         if (!cache.ok) {
77637             cache.moving = {};
77638             cache.intersection = {};
77639             cache.replacedVertex = {};
77640             cache.startLoc = {};
77641             cache.nodes = [];
77642             cache.ways = [];
77643
77644             cacheEntities(moveIds);
77645             cacheIntersections(cache.ways);
77646             cache.nodes = lodash.filter(cache.nodes, canMove);
77647
77648             cache.ok = true;
77649         }
77650     }
77651
77652
77653     // Place a vertex where the moved vertex used to be, to preserve way shape..
77654     function replaceMovedVertex(nodeId, wayId, graph, delta) {
77655         var way = graph.entity(wayId),
77656             moved = graph.entity(nodeId),
77657             movedIndex = way.nodes.indexOf(nodeId),
77658             len, prevIndex, nextIndex;
77659
77660         if (way.isClosed()) {
77661             len = way.nodes.length - 1;
77662             prevIndex = (movedIndex + len - 1) % len;
77663             nextIndex = (movedIndex + len + 1) % len;
77664         } else {
77665             len = way.nodes.length;
77666             prevIndex = movedIndex - 1;
77667             nextIndex = movedIndex + 1;
77668         }
77669
77670         var prev = graph.hasEntity(way.nodes[prevIndex]),
77671             next = graph.hasEntity(way.nodes[nextIndex]);
77672
77673         // Don't add orig vertex at endpoint..
77674         if (!prev || !next) return graph;
77675
77676         var key = wayId + '_' + nodeId,
77677             orig = cache.replacedVertex[key];
77678         if (!orig) {
77679             orig = osmNode();
77680             cache.replacedVertex[key] = orig;
77681             cache.startLoc[orig.id] = cache.startLoc[nodeId];
77682         }
77683
77684         var start, end;
77685         if (delta) {
77686             start = projection(cache.startLoc[nodeId]);
77687             end = projection.invert(vecAdd(start, delta));
77688         } else {
77689             end = cache.startLoc[nodeId];
77690         }
77691         orig = orig.move(end);
77692
77693         var angle = Math.abs(geoAngle(orig, prev, projection) -
77694                 geoAngle(orig, next, projection)) * 180 / Math.PI;
77695
77696         // Don't add orig vertex if it would just make a straight line..
77697         if (angle > 175 && angle < 185) return graph;
77698
77699         // Don't add orig vertex if another point is already nearby (within 10m)
77700         if (geoSphericalDistance(prev.loc, orig.loc) < 10 ||
77701             geoSphericalDistance(orig.loc, next.loc) < 10) return graph;
77702
77703         // moving forward or backward along way?
77704         var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
77705             p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
77706             d1 = geoPathLength(p1),
77707             d2 = geoPathLength(p2),
77708             insertAt = (d1 < d2) ? movedIndex : nextIndex;
77709
77710         // moving around closed loop?
77711         if (way.isClosed() && insertAt === 0) insertAt = len;
77712
77713         way = way.addNode(orig.id, insertAt);
77714         return graph.replace(orig).replace(way);
77715     }
77716
77717
77718     // Reorder nodes around intersections that have moved..
77719     function unZorroIntersection(intersection, graph) {
77720         var vertex = graph.entity(intersection.nodeId),
77721             way1 = graph.entity(intersection.movedId),
77722             way2 = graph.entity(intersection.unmovedId),
77723             isEP1 = intersection.movedIsEP,
77724             isEP2 = intersection.unmovedIsEP;
77725
77726         // don't move the vertex if it is the endpoint of both ways.
77727         if (isEP1 && isEP2) return graph;
77728
77729         var nodes1 = lodash.without(graph.childNodes(way1), vertex),
77730             nodes2 = lodash.without(graph.childNodes(way2), vertex);
77731
77732         if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
77733         if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
77734
77735         var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection),
77736             edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection),
77737             loc;
77738
77739         // snap vertex to nearest edge (or some point between them)..
77740         if (!isEP1 && !isEP2) {
77741             var epsilon = 1e-4, maxIter = 10;
77742             for (var i = 0; i < maxIter; i++) {
77743                 loc = geoInterp(edge1.loc, edge2.loc, 0.5);
77744                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
77745                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
77746                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
77747             }
77748         } else if (!isEP1) {
77749             loc = edge1.loc;
77750         } else {
77751             loc = edge2.loc;
77752         }
77753
77754         graph = graph.replace(vertex.move(loc));
77755
77756         // if zorro happened, reorder nodes..
77757         if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
77758             way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
77759             graph = graph.replace(way1);
77760         }
77761         if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
77762             way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
77763             graph = graph.replace(way2);
77764         }
77765
77766         return graph;
77767     }
77768
77769
77770     function cleanupIntersections(graph) {
77771         lodash.each(cache.intersection, function(obj) {
77772             graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
77773             graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
77774             graph = unZorroIntersection(obj, graph);
77775         });
77776
77777         return graph;
77778     }
77779
77780
77781     // check if moving way endpoint can cross an unmoved way, if so limit delta..
77782     function limitDelta(graph) {
77783         lodash.each(cache.intersection, function(obj) {
77784             // Don't limit movement if this is vertex joins 2 endpoints..
77785             if (obj.movedIsEP && obj.unmovedIsEP) return;
77786             // Don't limit movement if this vertex is not an endpoint anyway..
77787             if (!obj.movedIsEP) return;
77788
77789             var node = graph.entity(obj.nodeId),
77790                 start = projection(node.loc),
77791                 end = vecAdd(start, delta),
77792                 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
77793                 movedPath = lodash.map(lodash.map(movedNodes, 'loc'),
77794                     function(loc) { return vecAdd(projection(loc), delta); }),
77795                 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
77796                 unmovedPath = lodash.map(lodash.map(unmovedNodes, 'loc'), projection),
77797                 hits = geoPathIntersections(movedPath, unmovedPath);
77798
77799             for (var i = 0; i < hits.length; i++) {
77800                 if (lodash.isEqual(hits[i], end)) continue;
77801                 var edge = geoChooseEdge(unmovedNodes, end, projection);
77802                 delta = vecSub(projection(edge.loc), start);
77803             }
77804         });
77805     }
77806
77807
77808     var action = function(graph) {
77809         if (delta[0] === 0 && delta[1] === 0) return graph;
77810
77811         setupCache(graph);
77812
77813         if (!lodash.isEmpty(cache.intersection)) {
77814             limitDelta(graph);
77815         }
77816
77817         lodash.each(cache.nodes, function(id) {
77818             var node = graph.entity(id),
77819                 start = projection(node.loc),
77820                 end = vecAdd(start, delta);
77821             graph = graph.replace(node.move(projection.invert(end)));
77822         });
77823
77824         if (!lodash.isEmpty(cache.intersection)) {
77825             graph = cleanupIntersections(graph);
77826         }
77827
77828         return graph;
77829     };
77830
77831
77832     action.delta = function() {
77833         return delta;
77834     };
77835
77836
77837     return action;
77838 }
77839
77840 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
77841 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
77842 function actionMoveNode(nodeId, loc) {
77843     return function(graph) {
77844         return graph.replace(graph.entity(nodeId).move(loc));
77845     };
77846 }
77847
77848 function actionNoop() {
77849     return function(graph) {
77850         return graph;
77851     };
77852 }
77853
77854 /*
77855  * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
77856  */
77857 function actionOrthogonalize(wayId, projection) {
77858     var threshold = 12, // degrees within right or straight to alter
77859         lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
77860         upperThreshold = Math.cos(threshold * Math.PI / 180);
77861
77862
77863     var action = function(graph, t) {
77864         if (t === null || !isFinite(t)) t = 1;
77865         t = Math.min(Math.max(+t, 0), 1);
77866
77867         var way = graph.entity(wayId),
77868             nodes = graph.childNodes(way),
77869             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); }),
77870             corner = {i: 0, dotp: 1},
77871             epsilon = 1e-4,
77872             node, loc, score, motions, i, j;
77873
77874         if (points.length === 3) {   // move only one vertex for right triangle
77875             for (i = 0; i < 1000; i++) {
77876                 motions = points.map(calcMotion);
77877                 points[corner.i] = addPoints(points[corner.i], motions[corner.i]);
77878                 score = corner.dotp;
77879                 if (score < epsilon) {
77880                     break;
77881                 }
77882             }
77883
77884             node = graph.entity(nodes[corner.i].id);
77885             loc = projection.invert(points[corner.i]);
77886             graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
77887
77888         } else {
77889             var best,
77890                 originalPoints = lodash.clone(points);
77891             score = Infinity;
77892
77893             for (i = 0; i < 1000; i++) {
77894                 motions = points.map(calcMotion);
77895                 for (j = 0; j < motions.length; j++) {
77896                     points[j] = addPoints(points[j],motions[j]);
77897                 }
77898                 var newScore = squareness(points);
77899                 if (newScore < score) {
77900                     best = lodash.clone(points);
77901                     score = newScore;
77902                 }
77903                 if (score < epsilon) {
77904                     break;
77905                 }
77906             }
77907
77908             points = best;
77909
77910             for (i = 0; i < points.length; i++) {
77911                 // only move the points that actually moved
77912                 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
77913                     loc = projection.invert(points[i]);
77914                     node = graph.entity(nodes[i].id);
77915                     graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
77916                 }
77917             }
77918
77919             // remove empty nodes on straight sections
77920             for (i = 0; t === 1 && i < points.length; i++) {
77921                 node = graph.entity(nodes[i].id);
77922
77923                 if (graph.parentWays(node).length > 1 ||
77924                     graph.parentRelations(node).length ||
77925                     node.hasInterestingTags()) {
77926                     continue;
77927                 }
77928
77929                 var dotp = normalizedDotProduct(i, points);
77930                 if (dotp < -1 + epsilon) {
77931                     graph = actionDeleteNode(node.id)(graph);
77932                 }
77933             }
77934         }
77935
77936         return graph;
77937
77938
77939         function calcMotion(b, i, array) {
77940             var a = array[(i - 1 + array.length) % array.length],
77941                 c = array[(i + 1) % array.length],
77942                 p = subtractPoints(a, b),
77943                 q = subtractPoints(c, b),
77944                 scale, dotp;
77945
77946             scale = 2 * Math.min(geoEuclideanDistance(p, [0, 0]), geoEuclideanDistance(q, [0, 0]));
77947             p = normalizePoint(p, 1.0);
77948             q = normalizePoint(q, 1.0);
77949
77950             dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
77951
77952             // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
77953             if (array.length > 3) {
77954                 if (dotp < -0.707106781186547) {
77955                     dotp += 1.0;
77956                 }
77957             } else if (dotp && Math.abs(dotp) < corner.dotp) {
77958                 corner.i = i;
77959                 corner.dotp = Math.abs(dotp);
77960             }
77961
77962             return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
77963         }
77964     };
77965
77966
77967     function squareness(points) {
77968         return points.reduce(function(sum, val, i, array) {
77969             var dotp = normalizedDotProduct(i, array);
77970
77971             dotp = filterDotProduct(dotp);
77972             return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
77973         }, 0);
77974     }
77975
77976
77977     function normalizedDotProduct(i, points) {
77978         var a = points[(i - 1 + points.length) % points.length],
77979             b = points[i],
77980             c = points[(i + 1) % points.length],
77981             p = subtractPoints(a, b),
77982             q = subtractPoints(c, b);
77983
77984         p = normalizePoint(p, 1.0);
77985         q = normalizePoint(q, 1.0);
77986
77987         return p[0] * q[0] + p[1] * q[1];
77988     }
77989
77990
77991     function subtractPoints(a, b) {
77992         return [a[0] - b[0], a[1] - b[1]];
77993     }
77994
77995
77996     function addPoints(a, b) {
77997         return [a[0] + b[0], a[1] + b[1]];
77998     }
77999
78000
78001     function normalizePoint(point, scale) {
78002         var vector = [0, 0];
78003         var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
78004         if (length !== 0) {
78005             vector[0] = point[0] / length;
78006             vector[1] = point[1] / length;
78007         }
78008
78009         vector[0] *= scale;
78010         vector[1] *= scale;
78011
78012         return vector;
78013     }
78014
78015
78016     function filterDotProduct(dotp) {
78017         if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
78018             return dotp;
78019         }
78020
78021         return 0;
78022     }
78023
78024
78025     action.disabled = function(graph) {
78026         var way = graph.entity(wayId),
78027             nodes = graph.childNodes(way),
78028             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); });
78029
78030         if (squareness(points)) {
78031             return false;
78032         }
78033
78034         return 'not_squarish';
78035     };
78036
78037
78038     action.transitionable = true;
78039
78040
78041     return action;
78042 }
78043
78044 // Split a way at the given node.
78045 //
78046 // Optionally, split only the given ways, if multiple ways share
78047 // the given node.
78048 //
78049 // This is the inverse of `iD.actionJoin`.
78050 //
78051 // For testing convenience, accepts an ID to assign to the new way.
78052 // Normally, this will be undefined and the way will automatically
78053 // be assigned a new ID.
78054 //
78055 // Reference:
78056 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
78057 //
78058 function actionSplit(nodeId, newWayIds) {
78059     var wayIds;
78060
78061     // if the way is closed, we need to search for a partner node
78062     // to split the way at.
78063     //
78064     // The following looks for a node that is both far away from
78065     // the initial node in terms of way segment length and nearby
78066     // in terms of beeline-distance. This assures that areas get
78067     // split on the most "natural" points (independent of the number
78068     // of nodes).
78069     // For example: bone-shaped areas get split across their waist
78070     // line, circles across the diameter.
78071     function splitArea(nodes, idxA, graph) {
78072         var lengths = new Array(nodes.length),
78073             length,
78074             i,
78075             best = 0,
78076             idxB;
78077
78078         function wrap(index) {
78079             return utilWrap(index, nodes.length);
78080         }
78081
78082         function dist(nA, nB) {
78083             return geoSphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
78084         }
78085
78086         // calculate lengths
78087         length = 0;
78088         for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
78089             length += dist(nodes[i], nodes[wrap(i-1)]);
78090             lengths[i] = length;
78091         }
78092
78093         length = 0;
78094         for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
78095             length += dist(nodes[i], nodes[wrap(i+1)]);
78096             if (length < lengths[i])
78097                 lengths[i] = length;
78098         }
78099
78100         // determine best opposite node to split
78101         for (i = 0; i < nodes.length; i++) {
78102             var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
78103             if (cost > best) {
78104                 idxB = i;
78105                 best = cost;
78106             }
78107         }
78108
78109         return idxB;
78110     }
78111
78112
78113     function split(graph, wayA, newWayId) {
78114         var wayB = osmWay({id: newWayId, tags: wayA.tags}),
78115             nodesA,
78116             nodesB,
78117             isArea = wayA.isArea(),
78118             isOuter = osmIsSimpleMultipolygonOuterMember(wayA, graph);
78119
78120         if (wayA.isClosed()) {
78121             var nodes = wayA.nodes.slice(0, -1),
78122                 idxA = lodash.indexOf(nodes, nodeId),
78123                 idxB = splitArea(nodes, idxA, graph);
78124
78125             if (idxB < idxA) {
78126                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
78127                 nodesB = nodes.slice(idxB, idxA + 1);
78128             } else {
78129                 nodesA = nodes.slice(idxA, idxB + 1);
78130                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
78131             }
78132         } else {
78133             var idx = lodash.indexOf(wayA.nodes, nodeId, 1);
78134             nodesA = wayA.nodes.slice(0, idx + 1);
78135             nodesB = wayA.nodes.slice(idx);
78136         }
78137
78138         wayA = wayA.update({nodes: nodesA});
78139         wayB = wayB.update({nodes: nodesB});
78140
78141         graph = graph.replace(wayA);
78142         graph = graph.replace(wayB);
78143
78144         graph.parentRelations(wayA).forEach(function(relation) {
78145             if (relation.isRestriction()) {
78146                 var via = relation.memberByRole('via');
78147                 if (via && wayB.contains(via.id)) {
78148                     relation = relation.replaceMember(wayA, wayB);
78149                     graph = graph.replace(relation);
78150                 }
78151             } else {
78152                 if (relation === isOuter) {
78153                     graph = graph.replace(relation.mergeTags(wayA.tags));
78154                     graph = graph.replace(wayA.update({tags: {}}));
78155                     graph = graph.replace(wayB.update({tags: {}}));
78156                 }
78157
78158                 var member = {
78159                     id: wayB.id,
78160                     type: 'way',
78161                     role: relation.memberById(wayA.id).role
78162                 };
78163
78164                 graph = actionAddMember(relation.id, member)(graph);
78165             }
78166         });
78167
78168         if (!isOuter && isArea) {
78169             var multipolygon = osmRelation({
78170                 tags: lodash.extend({}, wayA.tags, {type: 'multipolygon'}),
78171                 members: [
78172                     {id: wayA.id, role: 'outer', type: 'way'},
78173                     {id: wayB.id, role: 'outer', type: 'way'}
78174                 ]});
78175
78176             graph = graph.replace(multipolygon);
78177             graph = graph.replace(wayA.update({tags: {}}));
78178             graph = graph.replace(wayB.update({tags: {}}));
78179         }
78180
78181         return graph;
78182     }
78183
78184
78185     var action = function(graph) {
78186         var candidates = action.ways(graph);
78187         for (var i = 0; i < candidates.length; i++) {
78188             graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
78189         }
78190         return graph;
78191     };
78192
78193
78194     action.ways = function(graph) {
78195         var node = graph.entity(nodeId),
78196             parents = graph.parentWays(node),
78197             hasLines = lodash.some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
78198
78199         return parents.filter(function(parent) {
78200             if (wayIds && wayIds.indexOf(parent.id) === -1)
78201                 return false;
78202
78203             if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
78204                 return false;
78205
78206             if (parent.isClosed()) {
78207                 return true;
78208             }
78209
78210             for (var i = 1; i < parent.nodes.length - 1; i++) {
78211                 if (parent.nodes[i] === nodeId) {
78212                     return true;
78213                 }
78214             }
78215
78216             return false;
78217         });
78218     };
78219
78220
78221     action.disabled = function(graph) {
78222         var candidates = action.ways(graph);
78223         if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
78224             return 'not_eligible';
78225     };
78226
78227
78228     action.limitWays = function(_) {
78229         if (!arguments.length) return wayIds;
78230         wayIds = _;
78231         return action;
78232     };
78233
78234
78235     return action;
78236 }
78237
78238 // Create a restriction relation for `turn`, which must have the following structure:
78239 //
78240 //     {
78241 //         from: { node: <node ID>, way: <way ID> },
78242 //         via:  { node: <node ID> },
78243 //         to:   { node: <node ID>, way: <way ID> },
78244 //         restriction: <'no_right_turn', 'no_left_turn', etc.>
78245 //     }
78246 //
78247 // This specifies a restriction of type `restriction` when traveling from
78248 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
78249 // (The action does not check that these entities form a valid intersection.)
78250 //
78251 // If `restriction` is not provided, it is automatically determined by
78252 // osmInferRestriction.
78253 //
78254 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
78255 // and `to.node` are used to determine which portion of the split ways become
78256 // members of the restriction.
78257 //
78258 // For testing convenience, accepts an ID to assign to the new relation.
78259 // Normally, this will be undefined and the relation will automatically
78260 // be assigned a new ID.
78261 //
78262 function actionRestrictTurn(turn, projection, restrictionId) {
78263
78264     return function(graph) {
78265         var from = graph.entity(turn.from.way),
78266             via  = graph.entity(turn.via.node),
78267             to   = graph.entity(turn.to.way);
78268
78269         function isClosingNode(way, nodeId) {
78270             return nodeId === way.first() && nodeId === way.last();
78271         }
78272
78273         function split(toOrFrom) {
78274             var newID = toOrFrom.newID || osmWay().id;
78275             graph = actionSplit(via.id, [newID])
78276                 .limitWays([toOrFrom.way])(graph);
78277
78278             var a = graph.entity(newID),
78279                 b = graph.entity(toOrFrom.way);
78280
78281             if (a.nodes.indexOf(toOrFrom.node) !== -1) {
78282                 return [a, b];
78283             } else {
78284                 return [b, a];
78285             }
78286         }
78287
78288         if (!from.affix(via.id) || isClosingNode(from, via.id)) {
78289             if (turn.from.node === turn.to.node) {
78290                 // U-turn
78291                 from = to = split(turn.from)[0];
78292             } else if (turn.from.way === turn.to.way) {
78293                 // Straight-on or circular
78294                 var s = split(turn.from);
78295                 from = s[0];
78296                 to   = s[1];
78297             } else {
78298                 // Other
78299                 from = split(turn.from)[0];
78300             }
78301         }
78302
78303         if (!to.affix(via.id) || isClosingNode(to, via.id)) {
78304             to = split(turn.to)[0];
78305         }
78306
78307         return graph.replace(osmRelation({
78308             id: restrictionId,
78309             tags: {
78310                 type: 'restriction',
78311                 restriction: turn.restriction ||
78312                     osmInferRestriction(
78313                         graph,
78314                         turn.from,
78315                         turn.via,
78316                         turn.to,
78317                         projection)
78318             },
78319             members: [
78320                 {id: from.id, type: 'way',  role: 'from'},
78321                 {id: via.id,  type: 'node', role: 'via'},
78322                 {id: to.id,   type: 'way',  role: 'to'}
78323             ]
78324         }));
78325     };
78326 }
78327
78328 function actionRevert(id) {
78329     var action = function(graph) {
78330         var entity = graph.hasEntity(id),
78331             base = graph.base().entities[id];
78332
78333         if (entity && !base) {    // entity will be removed..
78334             if (entity.type === 'node') {
78335                 graph.parentWays(entity)
78336                     .forEach(function(parent) {
78337                         parent = parent.removeNode(id);
78338                         graph = graph.replace(parent);
78339
78340                         if (parent.isDegenerate()) {
78341                             graph = actionDeleteWay(parent.id)(graph);
78342                         }
78343                     });
78344             }
78345
78346             graph.parentRelations(entity)
78347                 .forEach(function(parent) {
78348                     parent = parent.removeMembersWithID(id);
78349                     graph = graph.replace(parent);
78350
78351                     if (parent.isDegenerate()) {
78352                         graph = actionDeleteRelation(parent.id)(graph);
78353                     }
78354                 });
78355         }
78356
78357         return graph.revert(id);
78358     };
78359
78360     return action;
78361 }
78362
78363 function actionRotate(rotateIds, pivot, angle, projection) {
78364
78365     var action = function(graph) {
78366         return graph.update(function(graph) {
78367             utilGetAllNodes(rotateIds, graph).forEach(function(node) {
78368                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
78369                 graph = graph.replace(node.move(projection.invert(point)));
78370             });
78371         });
78372     };
78373
78374     return action;
78375 }
78376
78377 /*
78378  * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
78379  */
78380 function actionStraighten(wayId, projection) {
78381
78382     function positionAlongWay(n, s, e) {
78383         return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1])) /
78384                 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
78385     }
78386
78387
78388     var action = function(graph, t) {
78389         if (t === null || !isFinite(t)) t = 1;
78390         t = Math.min(Math.max(+t, 0), 1);
78391
78392         var way = graph.entity(wayId),
78393             nodes = graph.childNodes(way),
78394             points = nodes.map(function(n) { return projection(n.loc); }),
78395             startPoint = points[0],
78396             endPoint = points[points.length-1],
78397             toDelete = [],
78398             i;
78399
78400         for (i = 1; i < points.length-1; i++) {
78401             var node = nodes[i],
78402                 point = points[i];
78403
78404             if (t < 1 || graph.parentWays(node).length > 1 ||
78405                 graph.parentRelations(node).length ||
78406                 node.hasInterestingTags()) {
78407
78408                 var u = positionAlongWay(point, startPoint, endPoint),
78409                     p = [
78410                         startPoint[0] + u * (endPoint[0] - startPoint[0]),
78411                         startPoint[1] + u * (endPoint[1] - startPoint[1])
78412                     ],
78413                     loc2 = projection.invert(p);
78414
78415                 graph = graph.replace(node.move(geoInterp(node.loc, loc2, t)));
78416
78417             } else {
78418                 // safe to delete
78419                 if (toDelete.indexOf(node) === -1) {
78420                     toDelete.push(node);
78421                 }
78422             }
78423         }
78424
78425         for (i = 0; i < toDelete.length; i++) {
78426             graph = actionDeleteNode(toDelete[i].id)(graph);
78427         }
78428
78429         return graph;
78430     };
78431
78432
78433     action.disabled = function(graph) {
78434         // check way isn't too bendy
78435         var way = graph.entity(wayId),
78436             nodes = graph.childNodes(way),
78437             points = nodes.map(function(n) { return projection(n.loc); }),
78438             startPoint = points[0],
78439             endPoint = points[points.length-1],
78440             threshold = 0.2 * geoEuclideanDistance(startPoint, endPoint),
78441             i;
78442
78443         if (threshold === 0) {
78444             return 'too_bendy';
78445         }
78446
78447         for (i = 1; i < points.length-1; i++) {
78448             var point = points[i],
78449                 u = positionAlongWay(point, startPoint, endPoint),
78450                 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
78451                 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
78452                 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
78453
78454             // to bendy if point is off by 20% of total start/end distance in projected space
78455             if (isNaN(dist) || dist > threshold) {
78456                 return 'too_bendy';
78457             }
78458         }
78459     };
78460
78461
78462     action.transitionable = true;
78463
78464
78465     return action;
78466 }
78467
78468 // Remove the effects of `turn.restriction` on `turn`, which must have the
78469 // following structure:
78470 //
78471 //     {
78472 //         from: { node: <node ID>, way: <way ID> },
78473 //         via:  { node: <node ID> },
78474 //         to:   { node: <node ID>, way: <way ID> },
78475 //         restriction: <relation ID>
78476 //     }
78477 //
78478 // In the simple case, `restriction` is a reference to a `no_*` restriction
78479 // on the turn itself. In this case, it is simply deleted.
78480 //
78481 // The more complex case is where `restriction` references an `only_*`
78482 // restriction on a different turn in the same intersection. In that case,
78483 // that restriction is also deleted, but at the same time restrictions on
78484 // the turns other than the first two are created.
78485 //
78486 function actionUnrestrictTurn(turn) {
78487     return function(graph) {
78488         return actionDeleteRelation(turn.restriction)(graph);
78489     };
78490 }
78491
78492 /* Reflect the given area around its axis of symmetry */
78493 function actionReflect(reflectIds, projection$$1) {
78494     var useLongAxis = true;
78495
78496
78497     // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
78498     // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
78499     function getSmallestSurroundingRectangle(graph, nodes) {
78500         var points = nodes.map(function(n) { return projection$$1(n.loc); }),
78501             hull = d3polygonHull(points),
78502             centroid = d3polygonCentroid(hull),
78503             minArea = Infinity,
78504             ssrExtent = [],
78505             ssrAngle = 0,
78506             c1 = hull[0];
78507
78508         for (var i = 0; i < hull.length - 1; i++) {
78509             var c2 = hull[i + 1],
78510                 angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]),
78511                 poly = geoRotate(hull, -angle, centroid),
78512                 extent$$1 = poly.reduce(function(extent$$1, point) {
78513                         return extent$$1.extend(geoExtent$$1(point));
78514                     }, geoExtent$$1()),
78515                 area$$1 = extent$$1.area();
78516
78517             if (area$$1 < minArea) {
78518                 minArea = area$$1;
78519                 ssrExtent = extent$$1;
78520                 ssrAngle = angle;
78521             }
78522             c1 = c2;
78523         }
78524
78525         return {
78526             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
78527             angle: ssrAngle
78528         };
78529     }
78530
78531
78532     var action = function(graph, t) {
78533         if (t === null || !isFinite(t)) t = 1;
78534         t = Math.min(Math.max(+t, 0), 1);
78535
78536         var nodes = utilGetAllNodes(reflectIds, graph),
78537             ssr = getSmallestSurroundingRectangle(graph, nodes);
78538
78539         // Choose line pq = axis of symmetry.
78540         // The shape's surrounding rectangle has 2 axes of symmetry.
78541         // Reflect across the longer axis by default.
78542         var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2 ],
78543             q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2 ],
78544             p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2 ],
78545             q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2 ],
78546             p, q;
78547
78548         var isLong = (geoEuclideanDistance(p1, q1) > geoEuclideanDistance(p2, q2));
78549         if ((useLongAxis && isLong) || (!useLongAxis && !isLong)) {
78550             p = p1;
78551             q = q1;
78552         } else {
78553             p = p2;
78554             q = q2;
78555         }
78556
78557         // reflect c across pq
78558         // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
78559         var dx = q[0] - p[0];
78560         var dy = q[1] - p[1];
78561         var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
78562         var b = 2 * dx * dy / (dx * dx + dy * dy);
78563         for (var i = 0; i < nodes.length; i++) {
78564             var node = nodes[i];
78565             var c = projection$$1(node.loc);
78566             var c2 = [
78567                 a * (c[0] - p[0]) + b * (c[1] - p[1]) + p[0],
78568                 b * (c[0] - p[0]) - a * (c[1] - p[1]) + p[1]
78569             ];
78570             var loc2 = projection$$1.invert(c2);
78571             node = node.move(geoInterp(node.loc, loc2, t));
78572             graph = graph.replace(node);
78573         }
78574
78575         return graph;
78576     };
78577
78578
78579     action.useLongAxis = function(_) {
78580         if (!arguments.length) return useLongAxis;
78581         useLongAxis = _;
78582         return action;
78583     };
78584
78585
78586     action.transitionable = true;
78587
78588
78589     return action;
78590 }
78591
78592
78593
78594 var index$17 = Object.freeze({
78595         d3combobox: d3combobox,
78596         d3geoTile: d3geoTile,
78597         d3keybinding: d3keybinding
78598 });
78599
78600 /* export some legacy symbols: */
78601 var Connection = services.osm;
78602 var debug = false;
78603
78604
78605
78606
78607 var iD = Object.freeze({
78608         Connection: Connection,
78609         debug: debug,
78610         d3: index$2,
78611         _: lodash$1,
78612         lib: index$17,
78613         Context: coreContext,
78614         setAreaKeys: setAreaKeys,
78615         Difference: coreDifference,
78616         Graph: coreGraph$$1,
78617         History: coreHistory,
78618         Tree: coreTree,
78619         Entity: osmEntity$$1,
78620         Node: osmNode,
78621         Relation: osmRelation,
78622         Way: osmWay,
78623         BackgroundSource: rendererBackgroundSource,
78624         Background: rendererBackground,
78625         Features: rendererFeatures,
78626         Map: rendererMap,
78627         TileLayer: rendererTileLayer,
78628         Detect: utilDetect,
78629         actionAddEntity: actionAddEntity,
78630         actionAddMember: actionAddMember,
78631         actionAddMidpoint: actionAddMidpoint,
78632         actionAddVertex: actionAddVertex,
78633         actionChangeMember: actionChangeMember,
78634         actionChangePreset: actionChangePreset,
78635         actionChangeTags: actionChangeTags,
78636         actionCircularize: actionCircularize,
78637         actionConnect: actionConnect,
78638         actionCopyEntities: actionCopyEntities,
78639         actionDeleteMember: actionDeleteMember,
78640         actionDeleteMultiple: actionDeleteMultiple,
78641         actionDeleteNode: actionDeleteNode,
78642         actionDeleteRelation: actionDeleteRelation,
78643         actionDeleteWay: actionDeleteWay,
78644         actionDeprecateTags: actionDeprecateTags,
78645         actionDiscardTags: actionDiscardTags,
78646         actionDisconnect: actionDisconnect,
78647         actionJoin: actionJoin,
78648         actionMerge: actionMerge,
78649         actionMergePolygon: actionMergePolygon,
78650         actionMergeRemoteChanges: actionMergeRemoteChanges,
78651         actionMove: actionMove,
78652         actionMoveNode: actionMoveNode,
78653         actionNoop: actionNoop,
78654         actionOrthogonalize: actionOrthogonalize,
78655         actionRestrictTurn: actionRestrictTurn,
78656         actionReverse: actionReverse,
78657         actionRevert: actionRevert,
78658         actionRotate: actionRotate,
78659         actionSplit: actionSplit,
78660         actionStraighten: actionStraighten,
78661         actionUnrestrictTurn: actionUnrestrictTurn,
78662         actionReflect: actionReflect,
78663         behaviorAddWay: behaviorAddWay,
78664         behaviorBreathe: behaviorBreathe,
78665         behaviorCopy: behaviorCopy,
78666         behaviorDrag: behaviorDrag,
78667         behaviorDrawWay: behaviorDrawWay,
78668         behaviorDraw: behaviorDraw,
78669         behaviorEdit: behaviorEdit,
78670         behaviorHash: behaviorHash,
78671         behaviorHover: behaviorHover,
78672         behaviorLasso: behaviorLasso,
78673         behaviorOperation: behaviorOperation,
78674         behaviorPaste: behaviorPaste,
78675         behaviorSelect: behaviorSelect,
78676         behaviorTail: behaviorTail,
78677         coreContext: coreContext,
78678         coreDifference: coreDifference,
78679         coreGraph: coreGraph$$1,
78680         coreHistory: coreHistory,
78681         coreTree: coreTree,
78682         dataFeatureIcons: dataFeatureIcons,
78683         data: data,
78684         dataWikipedia: dataWikipedia,
78685         dataSuggestions: dataSuggestions,
78686         dataAddressFormats: dataAddressFormats,
78687         dataDeprecated: dataDeprecated,
78688         dataDiscarded: dataDiscarded,
78689         dataLocales: dataLocales,
78690         dataPhoneFormats: dataPhoneFormats,
78691         dataShortcuts: dataShortcuts,
78692         dataImperial: dataImperial,
78693         dataDriveLeft: dataDriveLeft,
78694         dataEn: en,
78695         geoAngle: geoAngle,
78696         geoChooseEdge: geoChooseEdge,
78697         geoCross: geoCross,
78698         geoEdgeEqual: geoEdgeEqual,
78699         geoEuclideanDistance: geoEuclideanDistance,
78700         geoExtent: geoExtent$$1,
78701         geoInterp: geoInterp,
78702         geoRawMercator: geoRawMercator,
78703         geoRoundCoords: geoRoundCoords,
78704         geoRotate: geoRotate,
78705         geoLatToMeters: geoLatToMeters,
78706         geoLineIntersection: geoLineIntersection,
78707         geoLonToMeters: geoLonToMeters,
78708         geoMetersToLat: geoMetersToLat,
78709         geoMetersToLon: geoMetersToLon,
78710         geoMetersToOffset: geoMetersToOffset,
78711         geoOffsetToMeters: geoOffsetToMeters,
78712         geoPathIntersections: geoPathIntersections,
78713         geoPathLength: geoPathLength,
78714         geoPointInPolygon: geoPointInPolygon,
78715         geoPolygonContainsPolygon: geoPolygonContainsPolygon,
78716         geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
78717         geoSphericalDistance: geoSphericalDistance,
78718         modeAddArea: modeAddArea$$1,
78719         modeAddLine: modeAddLine$$1,
78720         modeAddPoint: modeAddPoint$$1,
78721         modeBrowse: modeBrowse,
78722         modeDragNode: modeDragNode$$1,
78723         modeDrawArea: modeDrawArea,
78724         modeDrawLine: modeDrawLine,
78725         modeMove: modeMove$$1,
78726         modeRotate: modeRotate$$1,
78727         modeSave: modeSave$$1,
78728         modeSelect: modeSelect,
78729         operationCircularize: operationCircularize,
78730         operationContinue: operationContinue,
78731         operationDelete: operationDelete,
78732         operationDisconnect: operationDisconnect,
78733         operationMerge: operationMerge,
78734         operationMove: operationMove,
78735         operationOrthogonalize: operationOrthogonalize,
78736         operationReflectShort: operationReflectShort,
78737         operationReflectLong: operationReflectLong,
78738         operationReverse: operationReverse,
78739         operationRotate: operationRotate,
78740         operationSplit: operationSplit,
78741         operationStraighten: operationStraighten,
78742         osmChangeset: osmChangeset,
78743         osmEntity: osmEntity$$1,
78744         osmNode: osmNode,
78745         osmRelation: osmRelation,
78746         osmWay: osmWay,
78747         osmIntersection: osmIntersection,
78748         osmTurn: osmTurn,
78749         osmInferRestriction: osmInferRestriction,
78750         osmLanes: osmLanes,
78751         osmIsSimpleMultipolygonOuterMember: osmIsSimpleMultipolygonOuterMember,
78752         osmSimpleMultipolygonOuterMember: osmSimpleMultipolygonOuterMember,
78753         osmJoinWays: osmJoinWays,
78754         osmOneWayTags: osmOneWayTags,
78755         osmPavedTags: osmPavedTags,
78756         osmIsInterestingTag: osmIsInterestingTag,
78757         presetCategory: presetCategory,
78758         presetCollection: presetCollection,
78759         presetField: presetField,
78760         presetPreset: presetPreset,
78761         presetIndex: presetIndex,
78762         rendererBackgroundSource: rendererBackgroundSource,
78763         rendererBackground: rendererBackground,
78764         rendererFeatures: rendererFeatures,
78765         rendererMap: rendererMap,
78766         rendererTileLayer: rendererTileLayer,
78767         services: services,
78768         svgAreas: svgAreas$$1,
78769         svgDebug: svgDebug,
78770         svgDefs: svgDefs,
78771         svgGpx: svgGpx,
78772         svgIcon: svgIcon,
78773         svgLabels: svgLabels,
78774         svgLayers: svgLayers,
78775         svgLines: svgLines$$1,
78776         svgMapillaryImages: svgMapillaryImages,
78777         svgMapillarySigns: svgMapillarySigns,
78778         svgMidpoints: svgMidpoints$$1,
78779         svgOneWaySegments: svgOneWaySegments,
78780         svgOsm: svgOsm,
78781         svgPath: svgPath,
78782         svgPointTransform: svgPointTransform,
78783         svgPoints: svgPoints$$1,
78784         svgRelationMemberTags: svgRelationMemberTags,
78785         svgTagClasses: svgTagClasses,
78786         svgTurns: svgTurns,
78787         svgVertices: svgVertices$$1,
78788         uiFields: uiFields,
78789         uiFieldDefaultCheck: uiFieldCheck,
78790         uiFieldOnewayCheck: uiFieldCheck,
78791         uiFieldCheck: uiFieldCheck,
78792         uiFieldMultiCombo: uiFieldCombo,
78793         uiFieldNetworkCombo: uiFieldCombo,
78794         uiFieldSemiCombo: uiFieldCombo,
78795         uiFieldTypeCombo: uiFieldCombo,
78796         uiFieldCombo: uiFieldCombo,
78797         uiFieldUrl: uiFieldText,
78798         uiFieldNumber: uiFieldText,
78799         uiFieldTel: uiFieldText,
78800         uiFieldEmail: uiFieldText,
78801         uiFieldText: uiFieldText,
78802         uiFieldAccess: uiFieldAccess,
78803         uiFieldAddress: uiFieldAddress,
78804         uiFieldCycleway: uiFieldCycleway,
78805         uiFieldLanes: uiFieldLanes,
78806         uiFieldLocalized: uiFieldLocalized,
78807         uiFieldMaxspeed: uiFieldMaxspeed,
78808         uiFieldStructureRadio: uiFieldRadio,
78809         uiFieldRadio: uiFieldRadio,
78810         uiFieldRestrictions: uiFieldRestrictions,
78811         uiFieldTextarea: uiFieldTextarea,
78812         uiFieldWikipedia: uiFieldWikipedia,
78813         uiIntro: uiIntro,
78814         uiInfoPanels: uiInfoPanels,
78815         uiPanelBackground: uiPanelBackground,
78816         uiPanelHistory: uiPanelHistory,
78817         uiPanelLocation: uiPanelLocation,
78818         uiPanelMeasurement: uiPanelMeasurement,
78819         uiInit: uiInit,
78820         uiAccount: uiAccount,
78821         uiAttribution: uiAttribution,
78822         uiBackground: uiBackground,
78823         uiCmd: uiCmd,
78824         uiCommit: uiCommit,
78825         uiConfirm: uiConfirm,
78826         uiConflicts: uiConflicts,
78827         uiContributors: uiContributors,
78828         uiCurtain: uiCurtain,
78829         uiDisclosure: uiDisclosure,
78830         uiEditMenu: uiEditMenu,
78831         uiEntityEditor: uiEntityEditor,
78832         uiFeatureInfo: uiFeatureInfo,
78833         uiFeatureList: uiFeatureList,
78834         uiFlash: uiFlash,
78835         uiFullScreen: uiFullScreen,
78836         uiGeolocate: uiGeolocate,
78837         uiHelp: uiHelp,
78838         uiInfo: uiInfo,
78839         uiInspector: uiInspector,
78840         uiLasso: uiLasso,
78841         uiLoading: uiLoading,
78842         uiMapData: uiMapData,
78843         uiMapInMap: uiMapInMap,
78844         uiModal: uiModal,
78845         uiModes: uiModes,
78846         uiNotice: uiNotice,
78847         uiPreset: uiPreset,
78848         uiPresetIcon: uiPresetIcon,
78849         uiPresetList: uiPresetList,
78850         uiRadialMenu: uiRadialMenu,
78851         uiRawMemberEditor: uiRawMemberEditor,
78852         uiRawMembershipEditor: uiRawMembershipEditor,
78853         uiRawTagEditor: uiRawTagEditor,
78854         uiRestore: uiRestore,
78855         uiSave: uiSave,
78856         uiScale: uiScale,
78857         uiSelectionList: uiSelectionList,
78858         uiSidebar: uiSidebar,
78859         uiSourceSwitch: uiSourceSwitch,
78860         uiSpinner: uiSpinner,
78861         uiSplash: uiSplash,
78862         uiStatus: uiStatus,
78863         uiSuccess: uiSuccess,
78864         uiTagReference: uiTagReference,
78865         uiToggle: uiToggle,
78866         uiTooltipHtml: uiTooltipHtml,
78867         uiUndoRedo: uiUndoRedo,
78868         uiVersion: uiVersion,
78869         uiViewOnOSM: uiViewOnOSM,
78870         uiZoom: uiZoom,
78871         utilAsyncMap: utilAsyncMap,
78872         utilDisplayName: utilDisplayName,
78873         utilDisplayNameForPath: utilDisplayNameForPath,
78874         utilDisplayType: utilDisplayType,
78875         utilEditDistance: utilEditDistance,
78876         utilEntitySelector: utilEntitySelector,
78877         utilEntityOrMemberSelector: utilEntityOrMemberSelector,
78878         utilFastMouse: utilFastMouse,
78879         utilFunctor: utilFunctor,
78880         utilGetAllNodes: utilGetAllNodes,
78881         utilGetPrototypeOf: utilGetPrototypeOf,
78882         utilGetSetValue: utilGetSetValue,
78883         utilNoAuto: utilNoAuto,
78884         utilPrefixCSSProperty: utilPrefixCSSProperty,
78885         utilPrefixDOMProperty: utilPrefixDOMProperty,
78886         utilQsString: utilQsString,
78887         utilRebind: utilRebind,
78888         utilSetTransform: utilSetTransform,
78889         utilSessionMutex: utilSessionMutex,
78890         utilStringQs: utilStringQs,
78891         utilSuggestNames: utilSuggestNames,
78892         utilTagText: utilTagText,
78893         utilTriggerEvent: utilTriggerEvent,
78894         utilWrap: utilWrap,
78895         d3combobox: d3combobox,
78896         d3geoTile: d3geoTile,
78897         d3keybinding: d3keybinding,
78898         validationDeprecatedTag: validationDeprecatedTag,
78899         validationDisconnectedHighway: validationDisconnectedHighway,
78900         validationManyDeletions: validationManyDeletions,
78901         validationMissingTag: validationMissingTag,
78902         validationOldMultipolygon: validationOldMultipolygon,
78903         validationTagSuggestsArea: validationTagSuggestsArea
78904 });
78905
78906 window.iD = iD;
78907
78908 }());
78909 //# sourceMappingURL=iD.js.map