3 var bootstrap = (typeof exports.bootstrap === "object") ?
5 (exports.bootstrap = {});
7 bootstrap.tooltip = function() {
9 var tooltip = function(selection) {
10 selection.each(setup);
12 animation = d3.functor(false),
13 html = d3.functor(false),
15 var title = this.getAttribute("data-original-title");
19 title = this.getAttribute("title");
20 this.removeAttribute("title");
21 this.setAttribute("data-original-title", title);
25 over = "mouseenter.tooltip",
26 out = "mouseleave.tooltip",
27 placements = "top left bottom right".split(" "),
28 placement = d3.functor("top");
30 tooltip.title = function(_) {
31 if (arguments.length) {
32 title = d3.functor(_);
39 tooltip.html = function(_) {
40 if (arguments.length) {
48 tooltip.placement = function(_) {
49 if (arguments.length) {
50 placement = d3.functor(_);
57 tooltip.show = function(selection) {
61 tooltip.hide = function(selection) {
65 tooltip.toggle = function(selection) {
66 selection.each(toggle);
69 tooltip.destroy = function(selection) {
73 .attr("title", function() {
74 return this.getAttribute("data-original-title") || this.getAttribute("title");
76 .attr("data-original-title", null)
82 var root = d3.select(this),
83 animate = animation.apply(this, arguments),
84 tip = root.append("div")
85 .attr("class", "tooltip");
88 tip.classed("fade", true);
91 // TODO "inside" checks?
94 .attr("class", "tooltip-arrow");
96 .attr("class", "tooltip-inner");
98 var place = placement.apply(this, arguments);
99 tip.classed(place, true);
106 var root = d3.select(this),
107 content = title.apply(this, arguments),
108 tip = root.select(".tooltip")
109 .classed("in", true),
110 markup = html.apply(this, arguments),
111 innercontent = tip.select(".tooltip-inner")[markup ? "html" : "text"](content),
112 place = placement.apply(this, arguments),
113 outer = getPosition(root.node()),
114 inner = getPosition(tip.node()),
119 pos = {x: outer.x + (outer.w - inner.w) / 2, y: outer.y - inner.h};
122 pos = {x: outer.x + outer.w, y: outer.y + (outer.h - inner.h) / 2};
125 pos = {x: outer.x - inner.w, y: outer.y + (outer.h - inner.h) / 2};
128 pos = {x: Math.max(0, outer.x + (outer.w - inner.w) / 2), y: outer.y + outer.h};
133 {left: ~~pos.x + "px", top: ~~pos.y + "px"} :
134 {left: null, top: null});
136 this.tooltipVisible = true;
140 d3.select(this).select(".tooltip")
141 .classed("in", false);
143 this.tooltipVisible = false;
147 if (this.tooltipVisible) {
148 hide.apply(this, arguments);
150 show.apply(this, arguments);
157 function getPosition(node) {
158 var mode = d3.select(node).style('position');
159 if (mode === 'absolute' || mode === 'static') {
178 var d3 = {version: "3.5.5"}; // semver
179 d3.ascending = d3_ascending;
181 function d3_ascending(a, b) {
182 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
184 d3.descending = function(a, b) {
185 return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
187 d3.min = function(array, f) {
192 if (arguments.length === 1) {
193 while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; }
194 while (++i < n) if ((b = array[i]) != null && a > b) a = b;
196 while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = b; break; }
197 while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
201 d3.max = function(array, f) {
206 if (arguments.length === 1) {
207 while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; }
208 while (++i < n) if ((b = array[i]) != null && b > a) a = b;
210 while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = b; break; }
211 while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
215 d3.extent = function(array, f) {
221 if (arguments.length === 1) {
222 while (++i < n) if ((b = array[i]) != null && b >= b) { a = c = b; break; }
223 while (++i < n) if ((b = array[i]) != null) {
228 while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = c = b; break; }
229 while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
236 function d3_number(x) {
237 return x === null ? NaN : +x;
240 function d3_numeric(x) {
244 d3.sum = function(array, f) {
249 if (arguments.length === 1) {
250 while (++i < n) if (d3_numeric(a = +array[i])) s += a; // zero and null are equivalent
252 while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
257 d3.mean = function(array, f) {
263 if (arguments.length === 1) {
264 while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j;
266 while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j;
270 // R-7 per <http://en.wikipedia.org/wiki/Quantile>
271 d3.quantile = function(values, p) {
272 var H = (values.length - 1) * p + 1,
276 return e ? v + e * (values[h] - v) : v;
279 d3.median = function(array, f) {
284 if (arguments.length === 1) {
285 while (++i < n) if (d3_numeric(a = d3_number(array[i]))) numbers.push(a);
287 while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) numbers.push(a);
289 if (numbers.length) return d3.quantile(numbers.sort(d3_ascending), .5);
292 d3.variance = function(array, f) {
293 var n = array.length,
300 if (arguments.length === 1) {
302 if (d3_numeric(a = d3_number(array[i]))) {
310 if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) {
317 if (j > 1) return s / (j - 1);
320 d3.deviation = function() {
321 var v = d3.variance.apply(this, arguments);
322 return v ? Math.sqrt(v) : v;
325 function d3_bisector(compare) {
327 left: function(a, x, lo, hi) {
328 if (arguments.length < 3) lo = 0;
329 if (arguments.length < 4) hi = a.length;
331 var mid = lo + hi >>> 1;
332 if (compare(a[mid], x) < 0) lo = mid + 1;
337 right: function(a, x, lo, hi) {
338 if (arguments.length < 3) lo = 0;
339 if (arguments.length < 4) hi = a.length;
341 var mid = lo + hi >>> 1;
342 if (compare(a[mid], x) > 0) hi = mid;
350 var d3_bisect = d3_bisector(d3_ascending);
351 d3.bisectLeft = d3_bisect.left;
352 d3.bisect = d3.bisectRight = d3_bisect.right;
354 d3.bisector = function(f) {
355 return d3_bisector(f.length === 1
356 ? function(d, x) { return d3_ascending(f(d), x); }
359 d3.shuffle = function(array, i0, i1) {
360 if ((m = arguments.length) < 3) { i1 = array.length; if (m < 2) i0 = 0; }
361 var m = i1 - i0, t, i;
363 i = Math.random() * m-- | 0;
364 t = array[m + i0], array[m + i0] = array[i + i0], array[i + i0] = t;
368 d3.permute = function(array, indexes) {
369 var i = indexes.length, permutes = new Array(i);
370 while (i--) permutes[i] = array[indexes[i]];
373 d3.pairs = function(array) {
374 var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n);
375 while (i < n) pairs[i] = [p0 = p1, p1 = array[++i]];
379 d3.zip = function() {
380 if (!(n = arguments.length)) return [];
381 for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m;) {
382 for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n;) {
383 zip[j] = arguments[j][i];
389 function d3_zipLength(d) {
393 d3.transpose = function(matrix) {
394 return d3.zip.apply(d3, matrix);
396 d3.keys = function(map) {
398 for (var key in map) keys.push(key);
401 d3.values = function(map) {
403 for (var key in map) values.push(map[key]);
406 d3.entries = function(map) {
408 for (var key in map) entries.push({key: key, value: map[key]});
411 d3.merge = function(arrays) {
412 var n = arrays.length,
419 while (++i < n) j += arrays[i].length;
420 merged = new Array(j);
426 merged[--j] = array[m];
434 d3.range = function(start, stop, step) {
435 if (arguments.length < 3) {
437 if (arguments.length < 2) {
442 if ((stop - start) / step === Infinity) throw new Error("infinite range");
444 k = d3_range_integerScale(abs(step)),
447 start *= k, stop *= k, step *= k;
448 if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k);
449 else while ((j = start + step * ++i) < stop) range.push(j / k);
453 function d3_range_integerScale(x) {
455 while (x * k % 1) k *= 10;
458 function d3_class(ctor, properties) {
459 for (var key in properties) {
460 Object.defineProperty(ctor.prototype, key, {
461 value: properties[key],
467 d3.map = function(object, f) {
468 var map = new d3_Map;
469 if (object instanceof d3_Map) {
470 object.forEach(function(key, value) { map.set(key, value); });
471 } else if (Array.isArray(object)) {
475 if (arguments.length === 1) while (++i < n) map.set(i, object[i]);
476 else while (++i < n) map.set(f.call(object, o = object[i], i), o);
478 for (var key in object) map.set(key, object[key]);
484 this._ = Object.create(null);
487 var d3_map_proto = "__proto__",
493 return this._[d3_map_escape(key)];
495 set: function(key, value) {
496 return this._[d3_map_escape(key)] = value;
498 remove: d3_map_remove,
502 for (var key in this._) values.push(this._[key]);
505 entries: function() {
507 for (var key in this._) entries.push({key: d3_map_unescape(key), value: this._[key]});
512 forEach: function(f) {
513 for (var key in this._) f.call(this, d3_map_unescape(key), this._[key]);
517 function d3_map_escape(key) {
518 return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key;
521 function d3_map_unescape(key) {
522 return (key += "")[0] === d3_map_zero ? key.slice(1) : key;
525 function d3_map_has(key) {
526 return d3_map_escape(key) in this._;
529 function d3_map_remove(key) {
530 return (key = d3_map_escape(key)) in this._ && delete this._[key];
533 function d3_map_keys() {
535 for (var key in this._) keys.push(d3_map_unescape(key));
539 function d3_map_size() {
541 for (var key in this._) ++size;
545 function d3_map_empty() {
546 for (var key in this._) return false;
550 d3.nest = function() {
557 function map(mapType, array, depth) {
558 if (depth >= keys.length) return rollup
559 ? rollup.call(nest, array) : (sortValues
560 ? array.sort(sortValues)
569 valuesByKey = new d3_Map,
573 if (values = valuesByKey.get(keyValue = key(object = array[i]))) {
576 valuesByKey.set(keyValue, [object]);
582 setter = function(keyValue, values) {
583 object.set(keyValue, map(mapType, values, depth));
587 setter = function(keyValue, values) {
588 object[keyValue] = map(mapType, values, depth);
592 valuesByKey.forEach(setter);
596 function entries(map, depth) {
597 if (depth >= keys.length) return map;
600 sortKey = sortKeys[depth++];
602 map.forEach(function(key, keyMap) {
603 array.push({key: key, values: entries(keyMap, depth)});
607 ? array.sort(function(a, b) { return sortKey(a.key, b.key); })
611 nest.map = function(array, mapType) {
612 return map(mapType, array, 0);
615 nest.entries = function(array) {
616 return entries(map(d3.map, array, 0), 0);
619 nest.key = function(d) {
624 // Specifies the order for the most-recently specified key.
625 // Note: only applies to entries. Map keys are unordered!
626 nest.sortKeys = function(order) {
627 sortKeys[keys.length - 1] = order;
631 // Specifies the order for leaf values.
632 // Applies to both maps and entries array.
633 nest.sortValues = function(order) {
638 nest.rollup = function(f) {
646 d3.set = function(array) {
647 var set = new d3_Set;
648 if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]);
653 this._ = Object.create(null);
659 this._[d3_map_escape(key += "")] = true;
662 remove: d3_map_remove,
666 forEach: function(f) {
667 for (var key in this._) f.call(this, d3_map_unescape(key));
671 var d3_document = this.document;
673 function d3_documentElement(node) {
675 && (node.ownerDocument // node is a Node
676 || node.document // node is a Window
677 || node).documentElement; // node is a Document
680 function d3_window(node) {
682 && ((node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
683 || (node.document && node) // node is a Window
684 || node.defaultView); // node is a Document
686 // Copies a variable number of methods from source to target.
687 d3.rebind = function(target, source) {
688 var i = 1, n = arguments.length, method;
689 while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]);
693 // Method is assumed to be a standard D3 getter-setter:
694 // If passed with no arguments, gets the value.
695 // If passed with arguments, sets the value and returns the target.
696 function d3_rebind(target, source, method) {
698 var value = method.apply(source, arguments);
699 return value === source ? target : value;
702 function d3_vendorSymbol(object, name) {
703 if (name in object) return name;
704 name = name.charAt(0).toUpperCase() + name.slice(1);
705 for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) {
706 var prefixName = d3_vendorPrefixes[i] + name;
707 if (prefixName in object) return prefixName;
711 var d3_vendorPrefixes = ["webkit", "ms", "moz", "Moz", "o", "O"];
712 var d3_arraySlice = [].slice,
713 d3_array = function(list) { return d3_arraySlice.call(list); }; // conversion for NodeLists
714 function d3_noop() {}
716 d3.dispatch = function() {
717 var dispatch = new d3_dispatch,
719 n = arguments.length;
720 while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
724 function d3_dispatch() {}
726 d3_dispatch.prototype.on = function(type, listener) {
727 var i = type.indexOf("."),
730 // Extract optional namespace, e.g., "click.foo"
732 name = type.slice(i + 1);
733 type = type.slice(0, i);
736 if (type) return arguments.length < 2
737 ? this[type].on(name)
738 : this[type].on(name, listener);
740 if (arguments.length === 2) {
741 if (listener == null) for (type in this) {
742 if (this.hasOwnProperty(type)) this[type].on(name, null);
748 function d3_dispatch_event(dispatch) {
750 listenerByName = new d3_Map;
753 var z = listeners, // defensive reference
757 while (++i < n) if (l = z[i].on) l.apply(this, arguments);
761 event.on = function(name, listener) {
762 var l = listenerByName.get(name),
765 // return the current listener, if any
766 if (arguments.length < 2) return l && l.on;
768 // remove the old listener, if any (with copy-on-write)
771 listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
772 listenerByName.remove(name);
775 // add the new listener, if any
776 if (listener) listeners.push(listenerByName.set(name, {on: listener}));
786 function d3_eventPreventDefault() {
787 d3.event.preventDefault();
790 function d3_eventCancel() {
791 d3.event.preventDefault();
792 d3.event.stopPropagation();
795 function d3_eventSource() {
797 while (s = e.sourceEvent) e = s;
801 // Like d3.dispatch, but for custom events abstracting native UI events. These
802 // events have a target component (such as a brush), a target element (such as
803 // the svg:g element containing the brush) and the standard arguments `d` (the
804 // target element's data) and `i` (the selection index of the target element).
805 function d3_eventDispatch(target) {
806 var dispatch = new d3_dispatch,
808 n = arguments.length;
810 while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch);
812 // Creates a dispatch context for the specified `thiz` (typically, the target
813 // DOM element that received the source event) and `argumentz` (typically, the
814 // data `d` and index `i` of the target element). The returned function can be
815 // used to dispatch an event to any registered listeners; the function takes a
816 // single argument as input, being the event to dispatch. The event must have
817 // a "type" attribute which corresponds to a type registered in the
818 // constructor. This context will automatically populate the "sourceEvent" and
819 // "target" attributes of the event, as well as setting the `d3.event` global
820 // for the duration of the notification.
821 dispatch.of = function(thiz, argumentz) {
822 return function(e1) {
825 e1.sourceEvent = d3.event;
828 dispatch[e1.type].apply(thiz, argumentz);
837 d3.requote = function(s) {
838 return s.replace(d3_requote_re, "\\$&");
841 var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
842 var d3_subclass = {}.__proto__?
844 // Until ECMAScript supports array subclassing, prototype injection works well.
845 function(object, prototype) {
846 object.__proto__ = prototype;
849 // And if your browser doesn't support __proto__, we'll use direct extension.
850 function(object, prototype) {
851 for (var property in prototype) object[property] = prototype[property];
854 function d3_selection(groups) {
855 d3_subclass(groups, d3_selectionPrototype);
859 var d3_select = function(s, n) { return n.querySelector(s); },
860 d3_selectAll = function(s, n) { return n.querySelectorAll(s); },
861 d3_selectMatches = function(n, s) {
862 var d3_selectMatcher = n.matches || n[d3_vendorSymbol(n, "matchesSelector")];
863 d3_selectMatches = function(n, s) {
864 return d3_selectMatcher.call(n, s);
866 return d3_selectMatches(n, s);
869 // Prefer Sizzle, if available.
870 if (typeof Sizzle === "function") {
871 d3_select = function(s, n) { return Sizzle(s, n)[0] || null; };
872 d3_selectAll = Sizzle;
873 d3_selectMatches = Sizzle.matchesSelector;
876 d3.selection = function() {
877 return d3.select(d3_document.documentElement);
880 var d3_selectionPrototype = d3.selection.prototype = [];
883 d3_selectionPrototype.select = function(selector) {
890 selector = d3_selection_selector(selector);
892 for (var j = -1, m = this.length; ++j < m;) {
893 subgroups.push(subgroup = []);
894 subgroup.parentNode = (group = this[j]).parentNode;
895 for (var i = -1, n = group.length; ++i < n;) {
896 if (node = group[i]) {
897 subgroup.push(subnode = selector.call(node, node.__data__, i, j));
898 if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
905 return d3_selection(subgroups);
908 function d3_selection_selector(selector) {
909 return typeof selector === "function" ? selector : function() {
910 return d3_select(selector, this);
914 d3_selectionPrototype.selectAll = function(selector) {
919 selector = d3_selection_selectorAll(selector);
921 for (var j = -1, m = this.length; ++j < m;) {
922 for (var group = this[j], i = -1, n = group.length; ++i < n;) {
923 if (node = group[i]) {
924 subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j)));
925 subgroup.parentNode = node;
930 return d3_selection(subgroups);
933 function d3_selection_selectorAll(selector) {
934 return typeof selector === "function" ? selector : function() {
935 return d3_selectAll(selector, this);
939 svg: "http://www.w3.org/2000/svg",
940 xhtml: "http://www.w3.org/1999/xhtml",
941 xlink: "http://www.w3.org/1999/xlink",
942 xml: "http://www.w3.org/XML/1998/namespace",
943 xmlns: "http://www.w3.org/2000/xmlns/"
948 qualify: function(name) {
949 var i = name.indexOf(":"),
952 prefix = name.slice(0, i);
953 name = name.slice(i + 1);
955 return d3_nsPrefix.hasOwnProperty(prefix)
956 ? {space: d3_nsPrefix[prefix], local: name}
961 d3_selectionPrototype.attr = function(name, value) {
962 if (arguments.length < 2) {
964 // For attr(string), return the attribute value for the first node.
965 if (typeof name === "string") {
966 var node = this.node();
967 name = d3.ns.qualify(name);
969 ? node.getAttributeNS(name.space, name.local)
970 : node.getAttribute(name);
973 // For attr(object), the object specifies the names and values of the
974 // attributes to set or remove. The values may be functions that are
975 // evaluated for each element.
976 for (value in name) this.each(d3_selection_attr(value, name[value]));
980 return this.each(d3_selection_attr(name, value));
983 function d3_selection_attr(name, value) {
984 name = d3.ns.qualify(name);
986 // For attr(string, null), remove the attribute with the specified name.
987 function attrNull() {
988 this.removeAttribute(name);
990 function attrNullNS() {
991 this.removeAttributeNS(name.space, name.local);
994 // For attr(string, string), set the attribute with the specified name.
995 function attrConstant() {
996 this.setAttribute(name, value);
998 function attrConstantNS() {
999 this.setAttributeNS(name.space, name.local, value);
1002 // For attr(string, function), evaluate the function for each element, and set
1003 // or remove the attribute as appropriate.
1004 function attrFunction() {
1005 var x = value.apply(this, arguments);
1006 if (x == null) this.removeAttribute(name);
1007 else this.setAttribute(name, x);
1009 function attrFunctionNS() {
1010 var x = value.apply(this, arguments);
1011 if (x == null) this.removeAttributeNS(name.space, name.local);
1012 else this.setAttributeNS(name.space, name.local, x);
1015 return value == null
1016 ? (name.local ? attrNullNS : attrNull) : (typeof value === "function"
1017 ? (name.local ? attrFunctionNS : attrFunction)
1018 : (name.local ? attrConstantNS : attrConstant));
1020 function d3_collapse(s) {
1021 return s.trim().replace(/\s+/g, " ");
1024 d3_selectionPrototype.classed = function(name, value) {
1025 if (arguments.length < 2) {
1027 // For classed(string), return true only if the first node has the specified
1028 // class or classes. Note that even if the browser supports DOMTokenList, it
1029 // probably doesn't support it on SVG elements (which can be animated).
1030 if (typeof name === "string") {
1031 var node = this.node(),
1032 n = (name = d3_selection_classes(name)).length,
1034 if (value = node.classList) {
1035 while (++i < n) if (!value.contains(name[i])) return false;
1037 value = node.getAttribute("class");
1038 while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
1043 // For classed(object), the object specifies the names of classes to add or
1044 // remove. The values may be functions that are evaluated for each element.
1045 for (value in name) this.each(d3_selection_classed(value, name[value]));
1049 // Otherwise, both a name and a value are specified, and are handled as below.
1050 return this.each(d3_selection_classed(name, value));
1053 function d3_selection_classedRe(name) {
1054 return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
1057 function d3_selection_classes(name) {
1058 return (name + "").trim().split(/^|\s+/);
1061 // Multiple class names are allowed (e.g., "foo bar").
1062 function d3_selection_classed(name, value) {
1063 name = d3_selection_classes(name).map(d3_selection_classedName);
1064 var n = name.length;
1066 function classedConstant() {
1068 while (++i < n) name[i](this, value);
1071 // When the value is a function, the function is still evaluated only once per
1072 // element even if there are multiple class names.
1073 function classedFunction() {
1074 var i = -1, x = value.apply(this, arguments);
1075 while (++i < n) name[i](this, x);
1078 return typeof value === "function"
1083 function d3_selection_classedName(name) {
1084 var re = d3_selection_classedRe(name);
1085 return function(node, value) {
1086 if (c = node.classList) return value ? c.add(name) : c.remove(name);
1087 var c = node.getAttribute("class") || "";
1090 if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name));
1092 node.setAttribute("class", d3_collapse(c.replace(re, " ")));
1097 d3_selectionPrototype.style = function(name, value, priority) {
1098 var n = arguments.length;
1101 // For style(object) or style(object, string), the object specifies the
1102 // names and values of the attributes to set or remove. The values may be
1103 // functions that are evaluated for each element. The optional string
1104 // specifies the priority.
1105 if (typeof name !== "string") {
1106 if (n < 2) value = "";
1107 for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
1111 // For style(string), return the computed style value for the first node.
1113 var node = this.node();
1114 return d3_window(node).getComputedStyle(node, null).getPropertyValue(name);
1117 // For style(string, string) or style(string, function), use the default
1118 // priority. The priority is ignored for style(string, null).
1122 // Otherwise, a name, value and priority are specified, and handled as below.
1123 return this.each(d3_selection_style(name, value, priority));
1126 function d3_selection_style(name, value, priority) {
1128 // For style(name, null) or style(name, null, priority), remove the style
1129 // property with the specified name. The priority is ignored.
1130 function styleNull() {
1131 this.style.removeProperty(name);
1134 // For style(name, string) or style(name, string, priority), set the style
1135 // property with the specified name, using the specified priority.
1136 function styleConstant() {
1137 this.style.setProperty(name, value, priority);
1140 // For style(name, function) or style(name, function, priority), evaluate the
1141 // function for each element, and set or remove the style property as
1142 // appropriate. When setting, use the specified priority.
1143 function styleFunction() {
1144 var x = value.apply(this, arguments);
1145 if (x == null) this.style.removeProperty(name);
1146 else this.style.setProperty(name, x, priority);
1149 return value == null
1150 ? styleNull : (typeof value === "function"
1151 ? styleFunction : styleConstant);
1154 d3_selectionPrototype.property = function(name, value) {
1155 if (arguments.length < 2) {
1157 // For property(string), return the property value for the first node.
1158 if (typeof name === "string") return this.node()[name];
1160 // For property(object), the object specifies the names and values of the
1161 // properties to set or remove. The values may be functions that are
1162 // evaluated for each element.
1163 for (value in name) this.each(d3_selection_property(value, name[value]));
1167 // Otherwise, both a name and a value are specified, and are handled as below.
1168 return this.each(d3_selection_property(name, value));
1171 function d3_selection_property(name, value) {
1173 // For property(name, null), remove the property with the specified name.
1174 function propertyNull() {
1178 // For property(name, string), set the property with the specified name.
1179 function propertyConstant() {
1183 // For property(name, function), evaluate the function for each element, and
1184 // set or remove the property as appropriate.
1185 function propertyFunction() {
1186 var x = value.apply(this, arguments);
1187 if (x == null) delete this[name];
1188 else this[name] = x;
1191 return value == null
1192 ? propertyNull : (typeof value === "function"
1193 ? propertyFunction : propertyConstant);
1196 d3_selectionPrototype.text = function(value) {
1197 return arguments.length
1198 ? this.each(typeof value === "function"
1199 ? function() { var v = value.apply(this, arguments); this.textContent = v == null ? "" : v; } : value == null
1200 ? function() { if (this.textContent !== "") this.textContent = ""; }
1201 : function() { if (this.textContent !== value) this.textContent = value; })
1202 : this.node().textContent;
1205 d3_selectionPrototype.html = function(value) {
1206 return arguments.length
1207 ? this.each(typeof value === "function"
1208 ? function() { var v = value.apply(this, arguments); this.innerHTML = v == null ? "" : v; } : value == null
1209 ? function() { this.innerHTML = ""; }
1210 : function() { this.innerHTML = value; })
1211 : this.node().innerHTML;
1214 d3_selectionPrototype.append = function(name) {
1215 name = d3_selection_creator(name);
1216 return this.select(function() {
1217 return this.appendChild(name.apply(this, arguments));
1221 function d3_selection_creator(name) {
1224 var document = this.ownerDocument,
1225 namespace = this.namespaceURI;
1227 ? document.createElementNS(namespace, name)
1228 : document.createElement(name);
1231 function createNS() {
1232 return this.ownerDocument.createElementNS(name.space, name.local);
1235 return typeof name === "function" ? name
1236 : (name = d3.ns.qualify(name)).local ? createNS
1240 d3_selectionPrototype.insert = function(name, before) {
1241 name = d3_selection_creator(name);
1242 before = d3_selection_selector(before);
1243 return this.select(function() {
1244 return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null);
1248 // TODO remove(selector)?
1249 // TODO remove(node)?
1250 // TODO remove(function)?
1251 d3_selectionPrototype.remove = function() {
1252 return this.each(d3_selectionRemove);
1255 function d3_selectionRemove() {
1256 var parent = this.parentNode;
1257 if (parent) parent.removeChild(this);
1260 d3_selectionPrototype.data = function(value, key) {
1266 // If no value is specified, return the first value.
1267 if (!arguments.length) {
1268 value = new Array(n = (group = this[0]).length);
1270 if (node = group[i]) {
1271 value[i] = node.__data__;
1277 function bind(group, groupData) {
1280 m = groupData.length,
1281 n0 = Math.min(n, m),
1282 updateNodes = new Array(m),
1283 enterNodes = new Array(m),
1284 exitNodes = new Array(n),
1289 var nodeByKeyValue = new d3_Map,
1290 keyValues = new Array(n),
1293 for (i = -1; ++i < n;) {
1294 if (nodeByKeyValue.has(keyValue = key.call(node = group[i], node.__data__, i))) {
1295 exitNodes[i] = node; // duplicate selection key
1297 nodeByKeyValue.set(keyValue, node);
1299 keyValues[i] = keyValue;
1302 for (i = -1; ++i < m;) {
1303 if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) {
1304 enterNodes[i] = d3_selection_dataNode(nodeData);
1305 } else if (node !== true) { // no duplicate data key
1306 updateNodes[i] = node;
1307 node.__data__ = nodeData;
1309 nodeByKeyValue.set(keyValue, true);
1312 for (i = -1; ++i < n;) {
1313 if (nodeByKeyValue.get(keyValues[i]) !== true) {
1314 exitNodes[i] = group[i];
1318 for (i = -1; ++i < n0;) {
1320 nodeData = groupData[i];
1322 node.__data__ = nodeData;
1323 updateNodes[i] = node;
1325 enterNodes[i] = d3_selection_dataNode(nodeData);
1328 for (; i < m; ++i) {
1329 enterNodes[i] = d3_selection_dataNode(groupData[i]);
1331 for (; i < n; ++i) {
1332 exitNodes[i] = group[i];
1339 enterNodes.parentNode
1340 = updateNodes.parentNode
1341 = exitNodes.parentNode
1344 enter.push(enterNodes);
1345 update.push(updateNodes);
1346 exit.push(exitNodes);
1349 var enter = d3_selection_enter([]),
1350 update = d3_selection([]),
1351 exit = d3_selection([]);
1353 if (typeof value === "function") {
1355 bind(group = this[i], value.call(group, group.parentNode.__data__, i));
1359 bind(group = this[i], value);
1363 update.enter = function() { return enter; };
1364 update.exit = function() { return exit; };
1368 function d3_selection_dataNode(data) {
1369 return {__data__: data};
1372 d3_selectionPrototype.datum = function(value) {
1373 return arguments.length
1374 ? this.property("__data__", value)
1375 : this.property("__data__");
1378 d3_selectionPrototype.filter = function(filter) {
1384 if (typeof filter !== "function") filter = d3_selection_filter(filter);
1386 for (var j = 0, m = this.length; j < m; j++) {
1387 subgroups.push(subgroup = []);
1388 subgroup.parentNode = (group = this[j]).parentNode;
1389 for (var i = 0, n = group.length; i < n; i++) {
1390 if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
1391 subgroup.push(node);
1396 return d3_selection(subgroups);
1399 function d3_selection_filter(selector) {
1401 return d3_selectMatches(this, selector);
1405 d3_selectionPrototype.order = function() {
1406 for (var j = -1, m = this.length; ++j < m;) {
1407 for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
1408 if (node = group[i]) {
1409 if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
1417 d3_selectionPrototype.sort = function(comparator) {
1418 comparator = d3_selection_sortComparator.apply(this, arguments);
1419 for (var j = -1, m = this.length; ++j < m;) this[j].sort(comparator);
1420 return this.order();
1423 function d3_selection_sortComparator(comparator) {
1424 if (!arguments.length) comparator = d3_ascending;
1425 return function(a, b) {
1426 return a && b ? comparator(a.__data__, b.__data__) : !a - !b;
1430 d3_selectionPrototype.each = function(callback) {
1431 return d3_selection_each(this, function(node, i, j) {
1432 callback.call(node, node.__data__, i, j);
1436 function d3_selection_each(groups, callback) {
1437 for (var j = 0, m = groups.length; j < m; j++) {
1438 for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) {
1439 if (node = group[i]) callback(node, i, j);
1445 d3_selectionPrototype.call = function(callback) {
1446 var args = d3_array(arguments);
1447 callback.apply(args[0] = this, args);
1451 d3_selectionPrototype.empty = function() {
1452 return !this.node();
1455 d3_selectionPrototype.node = function() {
1456 for (var j = 0, m = this.length; j < m; j++) {
1457 for (var group = this[j], i = 0, n = group.length; i < n; i++) {
1458 var node = group[i];
1459 if (node) return node;
1465 d3_selectionPrototype.size = function() {
1467 d3_selection_each(this, function() { ++n; });
1471 function d3_selection_enter(selection) {
1472 d3_subclass(selection, d3_selection_enterPrototype);
1476 var d3_selection_enterPrototype = [];
1478 d3.selection.enter = d3_selection_enter;
1479 d3.selection.enter.prototype = d3_selection_enterPrototype;
1481 d3_selection_enterPrototype.append = d3_selectionPrototype.append;
1482 d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
1483 d3_selection_enterPrototype.node = d3_selectionPrototype.node;
1484 d3_selection_enterPrototype.call = d3_selectionPrototype.call;
1485 d3_selection_enterPrototype.size = d3_selectionPrototype.size;
1488 d3_selection_enterPrototype.select = function(selector) {
1496 for (var j = -1, m = this.length; ++j < m;) {
1497 upgroup = (group = this[j]).update;
1498 subgroups.push(subgroup = []);
1499 subgroup.parentNode = group.parentNode;
1500 for (var i = -1, n = group.length; ++i < n;) {
1501 if (node = group[i]) {
1502 subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j));
1503 subnode.__data__ = node.__data__;
1505 subgroup.push(null);
1510 return d3_selection(subgroups);
1513 d3_selection_enterPrototype.insert = function(name, before) {
1514 if (arguments.length < 2) before = d3_selection_enterInsertBefore(this);
1515 return d3_selectionPrototype.insert.call(this, name, before);
1518 function d3_selection_enterInsertBefore(enter) {
1520 return function(d, i, j) {
1521 var group = enter[j].update,
1524 if (j != j0) j0 = j, i0 = 0;
1525 if (i >= i0) i0 = i + 1;
1526 while (!(node = group[i0]) && ++i0 < n);
1531 // TODO fast singleton implementation?
1532 d3.select = function(node) {
1534 if (typeof node === "string") {
1535 group = [d3_select(node, d3_document)];
1536 group.parentNode = d3_document.documentElement;
1539 group.parentNode = d3_documentElement(node);
1541 return d3_selection([group]);
1544 d3.selectAll = function(nodes) {
1546 if (typeof nodes === "string") {
1547 group = d3_array(d3_selectAll(nodes, d3_document));
1548 group.parentNode = d3_document.documentElement;
1551 group.parentNode = null;
1553 return d3_selection([group]);
1556 d3_selectionPrototype.on = function(type, listener, capture) {
1557 var n = arguments.length;
1560 // For on(object) or on(object, boolean), the object specifies the event
1561 // types and listeners to add or remove. The optional boolean specifies
1562 // whether the listener captures events.
1563 if (typeof type !== "string") {
1564 if (n < 2) listener = false;
1565 for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
1569 // For on(string), return the listener for the first node.
1570 if (n < 2) return (n = this.node()["__on" + type]) && n._;
1572 // For on(string, function), use the default capture.
1576 // Otherwise, a type, listener and capture are specified, and handled as below.
1577 return this.each(d3_selection_on(type, listener, capture));
1580 function d3_selection_on(type, listener, capture) {
1581 var name = "__on" + type,
1582 i = type.indexOf("."),
1583 wrap = d3_selection_onListener;
1585 if (i > 0) type = type.slice(0, i);
1586 var filter = d3_selection_onFilters.get(type);
1587 if (filter) type = filter, wrap = d3_selection_onFilter;
1589 function onRemove() {
1592 this.removeEventListener(type, l, l.$);
1598 var l = wrap(listener, d3_array(arguments));
1599 if (typeof Raven !== 'undefined') l = Raven.wrap(l);
1600 onRemove.call(this);
1601 this.addEventListener(type, this[name] = l, l.$ = capture);
1605 function removeAll() {
1606 var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"),
1608 for (var name in this) {
1609 if (match = name.match(re)) {
1611 this.removeEventListener(match[1], l, l.$);
1618 ? listener ? onAdd : onRemove
1619 : listener ? d3_noop : removeAll;
1622 var d3_selection_onFilters = d3.map({
1623 mouseenter: "mouseover",
1624 mouseleave: "mouseout"
1628 d3_selection_onFilters.forEach(function(k) {
1629 if ("on" + k in d3_document) d3_selection_onFilters.remove(k);
1633 function d3_selection_onListener(listener, argumentz) {
1634 return function(e) {
1635 var o = d3.event; // Events can be reentrant (e.g., focus).
1637 argumentz[0] = this.__data__;
1639 listener.apply(this, argumentz);
1646 function d3_selection_onFilter(listener, argumentz) {
1647 var l = d3_selection_onListener(listener, argumentz);
1648 return function(e) {
1649 var target = this, related = e.relatedTarget;
1650 if (!related || (related !== target && !(related.compareDocumentPosition(target) & 8))) {
1656 var d3_event_dragSelect,
1657 d3_event_dragId = 0;
1659 function d3_event_dragSuppress(node) {
1660 var name = ".dragsuppress-" + ++d3_event_dragId,
1661 click = "click" + name,
1662 w = d3.select(d3_window(node))
1663 .on("touchmove" + name, d3_eventPreventDefault)
1664 .on("dragstart" + name, d3_eventPreventDefault)
1665 .on("selectstart" + name, d3_eventPreventDefault);
1667 if (d3_event_dragSelect == null) {
1668 d3_event_dragSelect = "onselectstart" in node ? false
1669 : d3_vendorSymbol(node.style, "userSelect");
1672 if (d3_event_dragSelect) {
1673 var style = d3_documentElement(node).style,
1674 select = style[d3_event_dragSelect];
1675 style[d3_event_dragSelect] = "none";
1678 return function(suppressClick) {
1680 if (d3_event_dragSelect) style[d3_event_dragSelect] = select;
1681 if (suppressClick) { // suppress the next click, but only if it’s immediate
1682 var off = function() { w.on(click, null); };
1683 w.on(click, function() { d3_eventCancel(); off(); }, true);
1689 d3.mouse = function(container) {
1690 return d3_mousePoint(container, d3_eventSource());
1693 // https://bugs.webkit.org/show_bug.cgi?id=44083
1694 var d3_mouse_bug44083 = this.navigator && /WebKit/.test(this.navigator.userAgent) ? -1 : 0;
1696 function d3_mousePoint(container, e) {
1697 if (e.changedTouches) e = e.changedTouches[0];
1698 var svg = container.ownerSVGElement || container;
1699 if (svg.createSVGPoint) {
1700 var point = svg.createSVGPoint();
1701 if (d3_mouse_bug44083 < 0) {
1702 var window = d3_window(container);
1703 if (window.scrollX || window.scrollY) {
1704 svg = d3.select("body").append("svg").style({
1705 position: "absolute",
1712 var ctm = svg[0][0].getScreenCTM();
1713 d3_mouse_bug44083 = !(ctm.f || ctm.e);
1717 if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY;
1718 else point.x = e.clientX, point.y = e.clientY;
1719 point = point.matrixTransform(container.getScreenCTM().inverse());
1720 return [point.x, point.y];
1722 var rect = container.getBoundingClientRect();
1723 return [e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop];
1726 d3.touches = function(container, touches) {
1727 if (arguments.length < 2) touches = d3_eventSource().touches;
1728 return touches ? d3_array(touches).map(function(touch) {
1729 var point = d3_mousePoint(container, touch);
1730 point.identifier = touch.identifier;
1740 d3_radians = π / 180,
1741 d3_degrees = 180 / π;
1743 function d3_sgn(x) {
1744 return x > 0 ? 1 : x < 0 ? -1 : 0;
1747 // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
1748 // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
1749 // right, +y is up). Returns a positive value if ABC is counter-clockwise,
1750 // negative if clockwise, and zero if the points are collinear.
1751 function d3_cross2d(a, b, c) {
1752 return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
1755 function d3_acos(x) {
1756 return x > 1 ? 0 : x < -1 ? π : Math.acos(x);
1759 function d3_asin(x) {
1760 return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x);
1763 function d3_sinh(x) {
1764 return ((x = Math.exp(x)) - 1 / x) / 2;
1767 function d3_cosh(x) {
1768 return ((x = Math.exp(x)) + 1 / x) / 2;
1771 function d3_tanh(x) {
1772 return ((x = Math.exp(2 * x)) - 1) / (x + 1);
1775 function d3_haversin(x) {
1776 return (x = Math.sin(x / 2)) * x;
1783 // p0 = [ux0, uy0, w0]
1784 // p1 = [ux1, uy1, w1]
1785 d3.interpolateZoom = function(p0, p1) {
1786 var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
1787 ux1 = p1[0], uy1 = p1[1], w1 = p1[2];
1791 d2 = dx * dx + dy * dy,
1793 b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1),
1794 b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1),
1795 r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
1796 r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1),
1798 S = (dr || Math.log(w1 / w0)) / ρ;
1800 function interpolate(t) {
1804 var coshr0 = d3_cosh(r0),
1805 u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0));
1809 w0 * coshr0 / d3_cosh(ρ * s + r0)
1812 // Special case for u0 ~= u1.
1816 w0 * Math.exp(ρ * s)
1820 interpolate.duration = S * 1000;
1825 d3.behavior.zoom = function() {
1826 var view = {x: 0, y: 0, k: 1},
1827 translate0, // translate when we started zooming (to avoid drift)
1828 center0, // implicit desired position of translate0 after zooming
1829 center, // explicit desired position of translate0 after zooming
1830 size = [960, 500], // viewport size; required for zoom interpolation
1831 scaleExtent = d3_behavior_zoomInfinity,
1834 mousedown = "mousedown.zoom",
1835 mousemove = "mousemove.zoom",
1836 mouseup = "mouseup.zoom",
1838 touchstart = "touchstart.zoom",
1839 touchtime, // time of last touchstart (to detect double-tap)
1840 event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"),
1846 // Lazily determine the DOM’s support for Wheel events.
1847 // https://developer.mozilla.org/en-US/docs/Mozilla_event_reference/wheel
1848 if (!d3_behavior_zoomWheel) {
1849 d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); }, "wheel")
1850 : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { return d3.event.wheelDelta; }, "mousewheel")
1851 : (d3_behavior_zoomDelta = function() { return -d3.event.detail; }, "MozMousePixelScroll");
1855 g .on(mousedown, mousedowned)
1856 .on(d3_behavior_zoomWheel + ".zoom", mousewheeled)
1857 .on("dblclick.zoom", dblclicked)
1858 .on(touchstart, touchstarted);
1861 zoom.event = function(g) {
1863 var dispatch = event.of(this, arguments),
1865 if (d3_transitionInheritId) {
1866 d3.select(this).transition()
1867 .each("start.zoom", function() {
1868 view = this.__chart__ || {x: 0, y: 0, k: 1}; // pre-transition state
1869 zoomstarted(dispatch);
1871 .tween("zoom:zoom", function() {
1874 cx = center0 ? center0[0] : dx / 2,
1875 cy = center0 ? center0[1] : dy / 2,
1876 i = d3.interpolateZoom(
1877 [(cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k],
1878 [(cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k]
1880 return function(t) {
1881 var l = i(t), k = dx / l[2];
1882 this.__chart__ = view = {x: cx - l[0] * k, y: cy - l[1] * k, k: k};
1886 .each("interrupt.zoom", function() {
1887 zoomended(dispatch);
1889 .each("end.zoom", function() {
1890 zoomended(dispatch);
1893 this.__chart__ = view;
1894 zoomstarted(dispatch);
1896 zoomended(dispatch);
1901 zoom.translate = function(_) {
1902 if (!arguments.length) return [view.x, view.y];
1903 view = {x: +_[0], y: +_[1], k: view.k}; // copy-on-write
1908 zoom.scale = function(_) {
1909 if (!arguments.length) return view.k;
1910 view = {x: view.x, y: view.y, k: +_}; // copy-on-write
1915 zoom.scaleExtent = function(_) {
1916 if (!arguments.length) return scaleExtent;
1917 scaleExtent = _ == null ? d3_behavior_zoomInfinity : [+_[0], +_[1]];
1921 zoom.center = function(_) {
1922 if (!arguments.length) return center;
1923 center = _ && [+_[0], +_[1]];
1927 zoom.size = function(_) {
1928 if (!arguments.length) return size;
1929 size = _ && [+_[0], +_[1]];
1933 zoom.duration = function(_) {
1934 if (!arguments.length) return duration;
1935 duration = +_; // TODO function based on interpolateZoom distance?
1939 zoom.x = function(z) {
1940 if (!arguments.length) return x1;
1943 view = {x: 0, y: 0, k: 1}; // copy-on-write
1947 zoom.y = function(z) {
1948 if (!arguments.length) return y1;
1951 view = {x: 0, y: 0, k: 1}; // copy-on-write
1955 function location(p) {
1956 return [(p[0] - view.x) / view.k, (p[1] - view.y) / view.k];
1960 return [l[0] * view.k + view.x, l[1] * view.k + view.y];
1963 function scaleTo(s) {
1964 view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s));
1967 function translateTo(p, l) {
1969 view.x += p[0] - l[0];
1970 view.y += p[1] - l[1];
1973 function zoomTo(that, p, l, k) {
1974 that.__chart__ = {x: view.x, y: view.y, k: view.k};
1976 scaleTo(Math.pow(2, k));
1977 translateTo(center0 = p, l);
1979 that = d3.select(that);
1980 if (duration > 0) that = that.transition().duration(duration);
1981 that.call(zoom.event);
1984 function rescale() {
1985 if (x1) x1.domain(x0.range().map(function(x) { return (x - view.x) / view.k; }).map(x0.invert));
1986 if (y1) y1.domain(y0.range().map(function(y) { return (y - view.y) / view.k; }).map(y0.invert));
1989 function zoomstarted(dispatch) {
1990 if (!zooming++) dispatch({type: "zoomstart"});
1993 function zoomed(dispatch) {
1995 dispatch({type: "zoom", scale: view.k, translate: [view.x, view.y]});
1998 function zoomended(dispatch) {
1999 if (!--zooming) dispatch({type: "zoomend"}), center0 = null;
2002 function mousedowned() {
2004 target = d3.event.target,
2005 dispatch = event.of(that, arguments),
2007 subject = d3.select(d3_window(that)).on(mousemove, moved).on(mouseup, ended),
2008 location0 = location(d3.mouse(that)),
2009 dragRestore = d3_event_dragSuppress(that);
2011 d3_selection_interrupt.call(that);
2012 zoomstarted(dispatch);
2016 translateTo(d3.mouse(that), location0);
2021 subject.on(mousemove, null).on(mouseup, null);
2022 dragRestore(dragged && d3.event.target === target);
2023 zoomended(dispatch);
2027 // These closures persist for as long as at least one touch is active.
2028 function touchstarted() {
2030 dispatch = event.of(that, arguments),
2031 locations0 = {}, // touchstart locations
2032 distance0 = 0, // distance² between initial touches
2033 scale0, // scale when we started touching
2034 zoomName = ".zoom-" + d3.event.changedTouches[0].identifier,
2035 touchmove = "touchmove" + zoomName,
2036 touchend = "touchend" + zoomName,
2038 subject = d3.select(that),
2039 dragRestore = d3_event_dragSuppress(that);
2042 zoomstarted(dispatch);
2044 // Workaround for Chrome issue 412723: the touchstart listener must be set
2045 // after the touchmove listener.
2046 subject.on(mousedown, null).on(touchstart, started); // prevent duplicate events
2048 // Updates locations of any touches in locations0.
2049 function relocate() {
2050 var touches = d3.touches(that);
2052 touches.forEach(function(t) {
2053 if (t.identifier in locations0) locations0[t.identifier] = location(t);
2058 // Temporarily override touchstart while gesture is active.
2059 function started() {
2061 // Listen for touchmove and touchend on the target of touchstart.
2062 var target = d3.event.target;
2063 d3.select(target).on(touchmove, moved).on(touchend, ended);
2064 targets.push(target);
2066 // Only track touches started on the same subject element.
2067 var changed = d3.event.changedTouches;
2068 for (var i = 0, n = changed.length; i < n; ++i) {
2069 locations0[changed[i].identifier] = null;
2072 var touches = relocate(),
2075 if (touches.length === 1) {
2076 if (now - touchtime < 500) { // dbltap
2078 zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1);
2079 d3_eventPreventDefault();
2082 } else if (touches.length > 1) {
2083 var p = touches[0], q = touches[1],
2084 dx = p[0] - q[0], dy = p[1] - q[1];
2085 distance0 = dx * dx + dy * dy;
2090 var touches = d3.touches(that),
2094 d3_selection_interrupt.call(that);
2096 for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
2098 if (l1 = locations0[p1.identifier]) {
2105 var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1,
2106 scale1 = distance0 && Math.sqrt(distance1 / distance0);
2107 p0 = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
2108 l0 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
2109 scaleTo(scale1 * scale0);
2113 translateTo(p0, l0);
2118 // If there are any globally-active touches remaining, remove the ended
2119 // touches from locations0.
2120 if (d3.event.touches.length) {
2121 var changed = d3.event.changedTouches;
2122 for (var i = 0, n = changed.length; i < n; ++i) {
2123 delete locations0[changed[i].identifier];
2125 // If locations0 is not empty, then relocate and continue listening for
2126 // touchmove and touchend.
2127 for (var identifier in locations0) {
2128 return void relocate(); // locations may have detached due to rotation
2131 // Otherwise, remove touchmove and touchend listeners.
2132 d3.selectAll(targets).on(zoomName, null);
2133 subject.on(mousedown, mousedowned).on(touchstart, touchstarted);
2135 zoomended(dispatch);
2139 function mousewheeled() {
2140 var dispatch = event.of(this, arguments);
2141 if (mousewheelTimer) clearTimeout(mousewheelTimer);
2142 else d3_selection_interrupt.call(this), translate0 = location(center0 = center || d3.mouse(this)), zoomstarted(dispatch);
2143 mousewheelTimer = setTimeout(function() { mousewheelTimer = null; zoomended(dispatch); }, 50);
2144 d3_eventPreventDefault();
2145 scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
2146 translateTo(center0, translate0);
2150 function dblclicked() {
2151 var p = d3.mouse(this),
2152 k = Math.log(view.k) / Math.LN2;
2154 zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1);
2157 return d3.rebind(zoom, event, "on");
2160 var d3_behavior_zoomInfinity = [0, Infinity], // default scale extent
2161 d3_behavior_zoomDelta, // initialized lazily
2162 d3_behavior_zoomWheel;
2163 function d3_functor(v) {
2164 return typeof v === "function" ? v : function() { return v; };
2167 d3.functor = d3_functor;
2169 d3.touch = function(container, touches, identifier) {
2170 if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches;
2171 if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) {
2172 if ((touch = touches[i]).identifier === identifier) {
2173 return d3_mousePoint(container, touch);
2178 var d3_timer_queueHead,
2180 d3_timer_interval, // is an interval (or frame) active?
2181 d3_timer_timeout, // is a timeout active?
2182 d3_timer_active, // active timer object
2183 d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) { setTimeout(callback, 17); };
2185 // The timer will continue to fire until callback returns true.
2186 d3.timer = function(callback, delay, then) {
2187 var n = arguments.length;
2188 if (n < 2) delay = 0;
2189 if (n < 3) then = Date.now();
2191 // Add the callback to the tail of the queue.
2192 var time = then + delay, timer = {c: callback, t: time, f: false, n: null};
2193 if (d3_timer_queueTail) d3_timer_queueTail.n = timer;
2194 else d3_timer_queueHead = timer;
2195 d3_timer_queueTail = timer;
2198 if (!d3_timer_interval) {
2199 d3_timer_timeout = clearTimeout(d3_timer_timeout);
2200 d3_timer_interval = 1;
2201 d3_timer_frame(d3_timer_step);
2205 function d3_timer_step() {
2206 var now = d3_timer_mark(),
2207 delay = d3_timer_sweep() - now;
2209 if (isFinite(delay)) {
2210 clearTimeout(d3_timer_timeout);
2211 d3_timer_timeout = setTimeout(d3_timer_step, delay);
2213 d3_timer_interval = 0;
2215 d3_timer_interval = 1;
2216 d3_timer_frame(d3_timer_step);
2220 d3.timer.flush = function() {
2225 function d3_timer_mark() {
2226 var now = Date.now();
2227 d3_timer_active = d3_timer_queueHead;
2228 while (d3_timer_active) {
2229 if (now >= d3_timer_active.t) d3_timer_active.f = d3_timer_active.c(now - d3_timer_active.t);
2230 d3_timer_active = d3_timer_active.n;
2235 // Flush after callbacks to avoid concurrent queue modification.
2236 // Returns the time of the earliest active timer, post-sweep.
2237 function d3_timer_sweep() {
2239 t1 = d3_timer_queueHead,
2243 t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n;
2245 if (t1.t < time) time = t1.t;
2249 d3_timer_queueTail = t0;
2254 d3.geo.stream = function(object, listener) {
2255 if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) {
2256 d3_geo_streamObjectType[object.type](object, listener);
2258 d3_geo_streamGeometry(object, listener);
2262 function d3_geo_streamGeometry(geometry, listener) {
2263 if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
2264 d3_geo_streamGeometryType[geometry.type](geometry, listener);
2268 var d3_geo_streamObjectType = {
2269 Feature: function(feature, listener) {
2270 d3_geo_streamGeometry(feature.geometry, listener);
2272 FeatureCollection: function(object, listener) {
2273 var features = object.features, i = -1, n = features.length;
2274 while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
2278 var d3_geo_streamGeometryType = {
2279 Sphere: function(object, listener) {
2282 Point: function(object, listener) {
2283 object = object.coordinates;
2284 listener.point(object[0], object[1], object[2]);
2286 MultiPoint: function(object, listener) {
2287 var coordinates = object.coordinates, i = -1, n = coordinates.length;
2288 while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]);
2290 LineString: function(object, listener) {
2291 d3_geo_streamLine(object.coordinates, listener, 0);
2293 MultiLineString: function(object, listener) {
2294 var coordinates = object.coordinates, i = -1, n = coordinates.length;
2295 while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
2297 Polygon: function(object, listener) {
2298 d3_geo_streamPolygon(object.coordinates, listener);
2300 MultiPolygon: function(object, listener) {
2301 var coordinates = object.coordinates, i = -1, n = coordinates.length;
2302 while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
2304 GeometryCollection: function(object, listener) {
2305 var geometries = object.geometries, i = -1, n = geometries.length;
2306 while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
2310 function d3_geo_streamLine(coordinates, listener, closed) {
2311 var i = -1, n = coordinates.length - closed, coordinate;
2312 listener.lineStart();
2313 while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]);
2317 function d3_geo_streamPolygon(coordinates, listener) {
2318 var i = -1, n = coordinates.length;
2319 listener.polygonStart();
2320 while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
2321 listener.polygonEnd();
2324 d3.geo.length = function(object) {
2325 d3_geo_lengthSum = 0;
2326 d3.geo.stream(object, d3_geo_length);
2327 return d3_geo_lengthSum;
2330 var d3_geo_lengthSum;
2332 var d3_geo_length = {
2335 lineStart: d3_geo_lengthLineStart,
2337 polygonStart: d3_noop,
2341 function d3_geo_lengthLineStart() {
2342 var λ0, sinφ0, cosφ0;
2344 d3_geo_length.point = function(λ, φ) {
2345 λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ);
2346 d3_geo_length.point = nextPoint;
2349 d3_geo_length.lineEnd = function() {
2350 d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;
2353 function nextPoint(λ, φ) {
2354 var sinφ = Math.sin(φ *= d3_radians),
2356 t = abs((λ *= d3_radians) - λ0),
2357 cosΔλ = Math.cos(t);
2358 d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ);
2359 λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ;
2362 function d3_identity(d) {
2365 function d3_true() {
2369 function d3_geo_spherical(cartesian) {
2371 Math.atan2(cartesian[1], cartesian[0]),
2372 d3_asin(cartesian[2])
2376 function d3_geo_sphericalEqual(a, b) {
2377 return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε;
2380 // General spherical polygon clipping algorithm: takes a polygon, cuts it into
2381 // visible line segments and rejoins the segments by interpolating along the
2383 function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) {
2387 segments.forEach(function(segment) {
2388 if ((n = segment.length - 1) <= 0) return;
2389 var n, p0 = segment[0], p1 = segment[n];
2391 // If the first and last points of a segment are coincident, then treat as
2393 // TODO if all rings are closed, then the winding order of the exterior
2394 // ring should be checked.
2395 if (d3_geo_sphericalEqual(p0, p1)) {
2396 listener.lineStart();
2397 for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);
2402 var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true),
2403 b = new d3_geo_clipPolygonIntersection(p0, null, a, false);
2407 a = new d3_geo_clipPolygonIntersection(p1, segment, null, false);
2408 b = new d3_geo_clipPolygonIntersection(p1, null, a, true);
2414 d3_geo_clipPolygonLinkCircular(subject);
2415 d3_geo_clipPolygonLinkCircular(clip);
2416 if (!subject.length) return;
2418 for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) {
2419 clip[i].e = entry = !entry;
2422 var start = subject[0],
2426 // Find first unvisited intersection.
2427 var current = start,
2429 while (current.v) if ((current = current.n) === start) return;
2431 listener.lineStart();
2433 current.v = current.o.v = true;
2436 for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]);
2438 interpolate(current.x, current.n.x, 1, listener);
2440 current = current.n;
2443 points = current.p.z;
2444 for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]);
2446 interpolate(current.x, current.p.x, -1, listener);
2448 current = current.p;
2450 current = current.o;
2452 isSubject = !isSubject;
2453 } while (!current.v);
2458 function d3_geo_clipPolygonLinkCircular(array) {
2459 if (!(n = array.length)) return;
2473 function d3_geo_clipPolygonIntersection(point, points, other, entry) {
2476 this.o = other; // another intersection
2477 this.e = entry; // is an entry?
2478 this.v = false; // visited
2479 this.n = this.p = null; // next & previous
2482 function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
2483 return function(rotate, listener) {
2484 var line = clipLine(listener),
2485 rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]);
2489 lineStart: lineStart,
2491 polygonStart: function() {
2492 clip.point = pointRing;
2493 clip.lineStart = ringStart;
2494 clip.lineEnd = ringEnd;
2498 polygonEnd: function() {
2500 clip.lineStart = lineStart;
2501 clip.lineEnd = lineEnd;
2503 segments = d3.merge(segments);
2504 var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
2505 if (segments.length) {
2506 if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
2507 d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);
2508 } else if (clipStartInside) {
2509 if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
2510 listener.lineStart();
2511 interpolate(null, null, 1, listener);
2514 if (polygonStarted) listener.polygonEnd(), polygonStarted = false;
2515 segments = polygon = null;
2517 sphere: function() {
2518 listener.polygonStart();
2519 listener.lineStart();
2520 interpolate(null, null, 1, listener);
2522 listener.polygonEnd();
2526 function point(λ, φ) {
2527 var point = rotate(λ, φ);
2528 if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ);
2530 function pointLine(λ, φ) {
2531 var point = rotate(λ, φ);
2532 line.point(point[0], point[1]);
2534 function lineStart() { clip.point = pointLine; line.lineStart(); }
2535 function lineEnd() { clip.point = point; line.lineEnd(); }
2539 var buffer = d3_geo_clipBufferListener(),
2540 ringListener = clipLine(buffer),
2541 polygonStarted = false,
2545 function pointRing(λ, φ) {
2547 var point = rotate(λ, φ);
2548 ringListener.point(point[0], point[1]);
2551 function ringStart() {
2552 ringListener.lineStart();
2556 function ringEnd() {
2557 pointRing(ring[0][0], ring[0][1]);
2558 ringListener.lineEnd();
2560 var clean = ringListener.clean(),
2561 ringSegments = buffer.buffer(),
2563 n = ringSegments.length;
2571 // No intersections.
2573 segment = ringSegments[0];
2574 var n = segment.length - 1,
2578 if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
2579 listener.lineStart();
2580 while (++i < n) listener.point((point = segment[i])[0], point[1]);
2586 // Rejoin connected segments.
2587 // TODO reuse bufferListener.rejoin()?
2588 if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
2590 segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
2597 function d3_geo_clipSegmentLength1(segment) {
2598 return segment.length > 1;
2601 function d3_geo_clipBufferListener() {
2605 lineStart: function() { lines.push(line = []); },
2606 point: function(λ, φ) { line.push([λ, φ]); },
2608 buffer: function() {
2614 rejoin: function() {
2615 if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
2620 // Intersection points are sorted along the clip edge. For both antimeridian
2621 // cutting and circle clipping, the same comparison is used.
2622 function d3_geo_clipSort(a, b) {
2623 return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1])
2624 - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]);
2627 var d3_geo_clipAntimeridian = d3_geo_clip(
2629 d3_geo_clipAntimeridianLine,
2630 d3_geo_clipAntimeridianInterpolate,
2633 // Takes a line and cuts into visible segments. Return values:
2634 // 0: there were intersections or the line was empty.
2635 // 1: no intersections.
2636 // 2: there were intersections, and the first and last segments should be
2638 function d3_geo_clipAntimeridianLine(listener) {
2642 clean; // no intersections
2645 lineStart: function() {
2646 listener.lineStart();
2649 point: function(λ1, φ1) {
2650 var sλ1 = λ1 > 0 ? π : -π,
2652 if (abs(dλ - π) < ε) { // line crosses a pole
2653 listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ);
2654 listener.point(sλ0, φ0);
2656 listener.lineStart();
2657 listener.point(sλ1, φ0);
2658 listener.point(λ1, φ0);
2660 } else if (sλ0 !== sλ1 && dλ >= π) { // line crosses antimeridian
2661 // handle degeneracies
2662 if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
2663 if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
2664 φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
2665 listener.point(sλ0, φ0);
2667 listener.lineStart();
2668 listener.point(sλ1, φ0);
2671 listener.point(λ0 = λ1, φ0 = φ1);
2674 lineEnd: function() {
2678 // if there are intersections, we always rejoin the first and last segments.
2679 clean: function() { return 2 - clean; }
2683 function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
2686 sinλ0_λ1 = Math.sin(λ0 - λ1);
2687 return abs(sinλ0_λ1) > ε
2688 ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1)
2689 - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0))
2690 / (cosφ0 * cosφ1 * sinλ0_λ1))
2694 function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
2697 φ = direction * halfπ;
2698 listener.point(-π, φ);
2699 listener.point( 0, φ);
2700 listener.point( π, φ);
2701 listener.point( π, 0);
2702 listener.point( π, -φ);
2703 listener.point( 0, -φ);
2704 listener.point(-π, -φ);
2705 listener.point(-π, 0);
2706 listener.point(-π, φ);
2707 } else if (abs(from[0] - to[0]) > ε) {
2708 var s = from[0] < to[0] ? π : -π;
2709 φ = direction * s / 2;
2710 listener.point(-s, φ);
2711 listener.point( 0, φ);
2712 listener.point( s, φ);
2714 listener.point(to[0], to[1]);
2718 // cross and scale return new vectors,
2719 // whereas add and normalize operate in-place
2721 function d3_geo_cartesian(spherical) {
2722 var λ = spherical[0],
2732 function d3_geo_cartesianDot(a, b) {
2733 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
2736 function d3_geo_cartesianCross(a, b) {
2738 a[1] * b[2] - a[2] * b[1],
2739 a[2] * b[0] - a[0] * b[2],
2740 a[0] * b[1] - a[1] * b[0]
2744 function d3_geo_cartesianAdd(a, b) {
2750 function d3_geo_cartesianScale(vector, k) {
2758 function d3_geo_cartesianNormalize(d) {
2759 var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
2764 function d3_geo_compose(a, b) {
2766 function compose(x, y) {
2767 return x = a(x, y), b(x[0], x[1]);
2770 if (a.invert && b.invert) compose.invert = function(x, y) {
2771 return x = b.invert(x, y), x && a.invert(x[0], x[1]);
2777 function d3_geo_equirectangular(λ, φ) {
2781 (d3.geo.equirectangular = function() {
2782 return d3_geo_projection(d3_geo_equirectangular);
2783 }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
2785 d3.geo.rotation = function(rotate) {
2786 rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0);
2788 function forward(coordinates) {
2789 coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
2790 return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
2793 forward.invert = function(coordinates) {
2794 coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
2795 return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
2801 function d3_geo_identityRotation(λ, φ) {
2802 return [λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ];
2805 d3_geo_identityRotation.invert = d3_geo_equirectangular;
2807 // Note: |δλ| must be < 2π
2808 function d3_geo_rotation(δλ, δφ, δγ) {
2809 return δλ ? (δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ))
2810 : d3_geo_rotationλ(δλ))
2811 : (δφ || δγ ? d3_geo_rotationφγ(δφ, δγ)
2812 : d3_geo_identityRotation);
2815 function d3_geo_forwardRotationλ(δλ) {
2816 return function(λ, φ) {
2817 return λ += δλ, [λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ];
2821 function d3_geo_rotationλ(δλ) {
2822 var rotation = d3_geo_forwardRotationλ(δλ);
2823 rotation.invert = d3_geo_forwardRotationλ(-δλ);
2827 function d3_geo_rotationφγ(δφ, δγ) {
2828 var cosδφ = Math.cos(δφ),
2829 sinδφ = Math.sin(δφ),
2830 cosδγ = Math.cos(δγ),
2831 sinδγ = Math.sin(δγ);
2833 function rotation(λ, φ) {
2834 var cosφ = Math.cos(φ),
2835 x = Math.cos(λ) * cosφ,
2836 y = Math.sin(λ) * cosφ,
2838 k = z * cosδφ + x * sinδφ;
2840 Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ),
2841 d3_asin(k * cosδγ + y * sinδγ)
2845 rotation.invert = function(λ, φ) {
2846 var cosφ = Math.cos(φ),
2847 x = Math.cos(λ) * cosφ,
2848 y = Math.sin(λ) * cosφ,
2850 k = z * cosδγ - y * sinδγ;
2852 Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ),
2853 d3_asin(k * cosδφ - x * sinδφ)
2860 d3.geo.circle = function() {
2861 var origin = [0, 0],
2867 var center = typeof origin === "function" ? origin.apply(this, arguments) : origin,
2868 rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert,
2871 interpolate(null, null, 1, {
2872 point: function(x, y) {
2873 ring.push(x = rotate(x, y));
2874 x[0] *= d3_degrees, x[1] *= d3_degrees;
2878 return {type: "Polygon", coordinates: [ring]};
2881 circle.origin = function(x) {
2882 if (!arguments.length) return origin;
2887 circle.angle = function(x) {
2888 if (!arguments.length) return angle;
2889 interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);
2893 circle.precision = function(_) {
2894 if (!arguments.length) return precision;
2895 interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);
2899 return circle.angle(90);
2902 // Interpolates along a circle centered at [0°, 0°], with a given radius and
2904 function d3_geo_circleInterpolate(radius, precision) {
2905 var cr = Math.cos(radius),
2906 sr = Math.sin(radius);
2907 return function(from, to, direction, listener) {
2908 var step = direction * precision;
2910 from = d3_geo_circleAngle(cr, from);
2911 to = d3_geo_circleAngle(cr, to);
2912 if (direction > 0 ? from < to: from > to) from += direction * τ;
2914 from = radius + direction * τ;
2915 to = radius - .5 * step;
2917 for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) {
2918 listener.point((point = d3_geo_spherical([
2927 // Signed angle of a cartesian point relative to [cr, 0, 0].
2928 function d3_geo_circleAngle(cr, point) {
2929 var a = d3_geo_cartesian(point);
2931 d3_geo_cartesianNormalize(a);
2932 var angle = d3_acos(-a[1]);
2933 return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
2935 // Adds floating point numbers with twice the normal precision.
2936 // Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
2937 // Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
2939 // Code adapted from GeographicLib by Charles F. F. Karney,
2940 // http://geographiclib.sourceforge.net/
2941 // See lib/geographiclib/LICENSE for details.
2943 function d3_adder() {}
2945 d3_adder.prototype = {
2946 s: 0, // rounded value
2947 t: 0, // exact error
2949 d3_adderSum(y, this.t, d3_adderTemp);
2950 d3_adderSum(d3_adderTemp.s, this.s, this);
2951 if (this.s) this.t += d3_adderTemp.t;
2952 else this.s = d3_adderTemp.t;
2955 this.s = this.t = 0;
2957 valueOf: function() {
2962 var d3_adderTemp = new d3_adder;
2964 function d3_adderSum(a, b, o) {
2965 var x = o.s = a + b, // a + b
2966 bv = x - a, av = x - bv; // b_virtual & a_virtual
2967 o.t = (a - av) + (b - bv); // a_roundoff + b_roundoff
2970 d3.geo.area = function(object) {
2972 d3.geo.stream(object, d3_geo_area);
2973 return d3_geo_areaSum;
2977 d3_geo_areaRingSum = new d3_adder;
2980 sphere: function() { d3_geo_areaSum += 4 * π; },
2985 // Only count area for polygon rings.
2986 polygonStart: function() {
2987 d3_geo_areaRingSum.reset();
2988 d3_geo_area.lineStart = d3_geo_areaRingStart;
2990 polygonEnd: function() {
2991 var area = 2 * d3_geo_areaRingSum;
2992 d3_geo_areaSum += area < 0 ? 4 * π + area : area;
2993 d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
2997 function d3_geo_areaRingStart() {
2998 var λ00, φ00, λ0, cosφ0, sinφ0; // start point and previous point
3000 // For the first point, …
3001 d3_geo_area.point = function(λ, φ) {
3002 d3_geo_area.point = nextPoint;
3003 λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), sinφ0 = Math.sin(φ);
3006 // For subsequent points, …
3007 function nextPoint(λ, φ) {
3009 φ = φ * d3_radians / 2 + π / 4; // half the angular distance from south pole
3011 // Spherical excess E for a spherical triangle with vertices: south pole,
3012 // previous point, current point. Uses a formula derived from Cagnoli’s
3013 // theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
3015 sdλ = dλ >= 0 ? 1 : -1,
3020 u = cosφ0 * cosφ + k * Math.cos(adλ),
3021 v = k * sdλ * Math.sin(adλ);
3022 d3_geo_areaRingSum.add(Math.atan2(v, u));
3024 // Advance the previous points.
3025 λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;
3028 // For the last point, return to the start.
3029 d3_geo_area.lineEnd = function() {
3030 nextPoint(λ00, φ00);
3034 function d3_geo_pointInPolygon(point, polygon) {
3035 var meridian = point[0],
3036 parallel = point[1],
3037 meridianNormal = [Math.sin(meridian), -Math.cos(meridian), 0],
3040 d3_geo_areaRingSum.reset();
3042 for (var i = 0, n = polygon.length; i < n; ++i) {
3043 var ring = polygon[i],
3046 var point0 = ring[0],
3048 φ0 = point0[1] / 2 + π / 4,
3049 sinφ0 = Math.sin(φ0),
3050 cosφ0 = Math.cos(φ0),
3057 φ = point[1] / 2 + π / 4,
3061 sdλ = dλ >= 0 ? 1 : -1,
3063 antimeridian = adλ > π,
3065 d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ)));
3067 polarAngle += antimeridian ? dλ + sdλ * τ : dλ;
3069 // Are the longitudes either side of the point's meridian, and are the
3070 // latitudes smaller than the parallel?
3071 if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {
3072 var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point));
3073 d3_geo_cartesianNormalize(arc);
3074 var intersection = d3_geo_cartesianCross(meridianNormal, arc);
3075 d3_geo_cartesianNormalize(intersection);
3076 var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);
3077 if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) {
3078 winding += antimeridian ^ dλ >= 0 ? 1 : -1;
3082 λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point;
3086 // First, determine whether the South pole is inside or outside:
3089 // * the polygon winds around it in a clockwise direction.
3090 // * the polygon does not (cumulatively) wind around it, but has a negative
3091 // (counter-clockwise) area.
3093 // Second, count the (signed) number of times a segment crosses a meridian
3094 // from the point to the South pole. If it is zero, then the point is the
3095 // same side as the South pole.
3097 return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < 0) ^ (winding & 1);
3100 // Clip features against a small circle centered at [0°, 0°].
3101 function d3_geo_clipCircle(radius) {
3102 var cr = Math.cos(radius),
3103 smallRadius = cr > 0,
3104 notHemisphere = abs(cr) > ε, // TODO optimise for this common case
3105 interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);
3107 return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-π, radius - π]);
3109 function visible(λ, φ) {
3110 return Math.cos(λ) * Math.cos(φ) > cr;
3113 // Takes a line and cuts into visible segments. Return values used for
3114 // polygon clipping:
3115 // 0: there were intersections or the line was empty.
3116 // 1: no intersections.
3117 // 2: there were intersections, and the first and last segments should be
3119 function clipLine(listener) {
3120 var point0, // previous point
3121 c0, // code for previous point
3122 v0, // visibility of previous point
3123 v00, // visibility of first point
3124 clean; // no intersections
3126 lineStart: function() {
3130 point: function(λ, φ) {
3131 var point1 = [λ, φ],
3135 ? v ? 0 : code(λ, φ)
3136 : v ? code(λ + (λ < 0 ? π : -π), φ) : 0;
3137 if (!point0 && (v00 = v0 = v)) listener.lineStart();
3138 // Handle degeneracies.
3139 // TODO ignore if not clipping polygons.
3141 point2 = intersect(point0, point1);
3142 if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {
3145 v = visible(point1[0], point1[1]);
3152 listener.lineStart();
3153 point2 = intersect(point1, point0);
3154 listener.point(point2[0], point2[1]);
3157 point2 = intersect(point0, point1);
3158 listener.point(point2[0], point2[1]);
3162 } else if (notHemisphere && point0 && smallRadius ^ v) {
3164 // If the codes for two points are different, or are both zero,
3165 // and there this segment intersects with the small circle.
3166 if (!(c & c0) && (t = intersect(point1, point0, true))) {
3169 listener.lineStart();
3170 listener.point(t[0][0], t[0][1]);
3171 listener.point(t[1][0], t[1][1]);
3174 listener.point(t[1][0], t[1][1]);
3176 listener.lineStart();
3177 listener.point(t[0][0], t[0][1]);
3181 if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {
3182 listener.point(point1[0], point1[1]);
3184 point0 = point1, v0 = v, c0 = c;
3186 lineEnd: function() {
3187 if (v0) listener.lineEnd();
3190 // Rejoin first and last segments if there were intersections and the first
3191 // and last points were visible.
3192 clean: function() { return clean | ((v00 && v0) << 1); }
3196 // Intersects the great circle between a and b with the clip circle.
3197 function intersect(a, b, two) {
3198 var pa = d3_geo_cartesian(a),
3199 pb = d3_geo_cartesian(b);
3201 // We have two planes, n1.p = d1 and n2.p = d2.
3202 // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
3203 var n1 = [1, 0, 0], // normal
3204 n2 = d3_geo_cartesianCross(pa, pb),
3205 n2n2 = d3_geo_cartesianDot(n2, n2),
3206 n1n2 = n2[0], // d3_geo_cartesianDot(n1, n2),
3207 determinant = n2n2 - n1n2 * n1n2;
3209 // Two polar points.
3210 if (!determinant) return !two && a;
3212 var c1 = cr * n2n2 / determinant,
3213 c2 = -cr * n1n2 / determinant,
3214 n1xn2 = d3_geo_cartesianCross(n1, n2),
3215 A = d3_geo_cartesianScale(n1, c1),
3216 B = d3_geo_cartesianScale(n2, c2);
3217 d3_geo_cartesianAdd(A, B);
3219 // Solve |p(t)|^2 = 1.
3221 w = d3_geo_cartesianDot(A, u),
3222 uu = d3_geo_cartesianDot(u, u),
3223 t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1);
3227 var t = Math.sqrt(t2),
3228 q = d3_geo_cartesianScale(u, (-w - t) / uu);
3229 d3_geo_cartesianAdd(q, A);
3230 q = d3_geo_spherical(q);
3233 // Two intersection points.
3239 if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;
3241 polar = abs(δλ - π) < ε,
3242 meridian = polar || δλ < ε;
3244 if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z;
3246 // Check that the first point is between a and b.
3249 ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1)
3250 : φ0 <= q[1] && q[1] <= φ1
3251 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) {
3252 var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);
3253 d3_geo_cartesianAdd(q1, A);
3254 return [q, d3_geo_spherical(q1)];
3258 // Generates a 4-bit vector representing the location of a point relative to
3259 // the small circle's bounding box.
3260 function code(λ, φ) {
3261 var r = smallRadius ? radius : π - radius,
3263 if (λ < -r) code |= 1; // left
3264 else if (λ > r) code |= 2; // right
3265 if (φ < -r) code |= 4; // below
3266 else if (φ > r) code |= 8; // above
3271 // Liang–Barsky line clipping.
3272 function d3_geom_clipLine(x0, y0, x1, y1) {
3273 return function(line) {
3287 if (!dx && r > 0) return;
3292 } else if (dx > 0) {
3298 if (!dx && r < 0) return;
3303 } else if (dx > 0) {
3309 if (!dy && r > 0) return;
3314 } else if (dy > 0) {
3320 if (!dy && r < 0) return;
3325 } else if (dy > 0) {
3330 if (t0 > 0) line.a = {x: ax + t0 * dx, y: ay + t0 * dy};
3331 if (t1 < 1) line.b = {x: ax + t1 * dx, y: ay + t1 * dy};
3336 var d3_geo_clipExtentMAX = 1e9;
3338 d3.geo.clipExtent = function() {
3343 stream: function(output) {
3344 if (stream) stream.valid = false;
3345 stream = clip(output);
3346 stream.valid = true; // allow caching by d3.geo.path
3349 extent: function(_) {
3350 if (!arguments.length) return [[x0, y0], [x1, y1]];
3351 clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);
3352 if (stream) stream.valid = false, stream = null;
3356 return clipExtent.extent([[0, 0], [960, 500]]);
3359 function d3_geo_clipExtent(x0, y0, x1, y1) {
3360 return function(listener) {
3361 var listener_ = listener,
3362 bufferListener = d3_geo_clipBufferListener(),
3363 clipLine = d3_geom_clipLine(x0, y0, x1, y1),
3370 lineStart: lineStart,
3372 polygonStart: function() {
3373 listener = bufferListener;
3378 polygonEnd: function() {
3379 listener = listener_;
3380 segments = d3.merge(segments);
3381 var clipStartInside = insidePolygon([x0, y1]),
3382 inside = clean && clipStartInside,
3383 visible = segments.length;
3384 if (inside || visible) {
3385 listener.polygonStart();
3387 listener.lineStart();
3388 interpolate(null, null, 1, listener);
3392 d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener);
3394 listener.polygonEnd();
3396 segments = polygon = ring = null;
3400 function insidePolygon(p) {
3401 var wn = 0, // the winding number counter
3405 for (var i = 0; i < n; ++i) {
3406 for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) {
3409 if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn;
3411 if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn;
3419 function interpolate(from, to, direction, listener) {
3422 (a = corner(from, direction)) !== (a1 = corner(to, direction)) ||
3423 comparePoints(from, to) < 0 ^ direction > 0) {
3425 listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
3426 } while ((a = (a + direction + 4) % 4) !== a1);
3428 listener.point(to[0], to[1]);
3432 function pointVisible(x, y) {
3433 return x0 <= x && x <= x1 && y0 <= y && y <= y1;
3436 function point(x, y) {
3437 if (pointVisible(x, y)) listener.point(x, y);
3440 var x__, y__, v__, // first point
3441 x_, y_, v_, // previous point
3445 function lineStart() {
3446 clip.point = linePoint;
3447 if (polygon) polygon.push(ring = []);
3453 function lineEnd() {
3454 // TODO rather than special-case polygons, simply handle them separately.
3455 // Ideally, coincident intersection points should be jittered to avoid
3458 linePoint(x__, y__);
3459 if (v__ && v_) bufferListener.rejoin();
3460 segments.push(bufferListener.buffer());
3463 if (v_) listener.lineEnd();
3466 function linePoint(x, y) {
3467 x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
3468 y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
3469 var v = pointVisible(x, y);
3470 if (polygon) ring.push([x, y]);
3472 x__ = x, y__ = y, v__ = v;
3475 listener.lineStart();
3476 listener.point(x, y);
3479 if (v && v_) listener.point(x, y);
3481 var l = {a: {x: x_, y: y_}, b: {x: x, y: y}};
3484 listener.lineStart();
3485 listener.point(l.a.x, l.a.y);
3487 listener.point(l.b.x, l.b.y);
3488 if (!v) listener.lineEnd();
3491 listener.lineStart();
3492 listener.point(x, y);
3497 x_ = x, y_ = y, v_ = v;
3503 function corner(p, direction) {
3504 return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3
3505 : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1
3506 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0
3507 : direction > 0 ? 3 : 2; // abs(p[1] - y1) < ε
3510 function compare(a, b) {
3511 return comparePoints(a.x, b.x);
3514 function comparePoints(a, b) {
3515 var ca = corner(a, 1),
3517 return ca !== cb ? ca - cb
3518 : ca === 0 ? b[1] - a[1]
3519 : ca === 1 ? a[0] - b[0]
3520 : ca === 2 ? a[1] - b[1]
3525 function d3_geo_conic(projectAt) {
3528 m = d3_geo_projectionMutator(projectAt),
3531 p.parallels = function(_) {
3532 if (!arguments.length) return [φ0 / π * 180, φ1 / π * 180];
3533 return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180);
3539 function d3_geo_conicEqualArea(φ0, φ1) {
3540 var sinφ0 = Math.sin(φ0),
3541 n = (sinφ0 + Math.sin(φ1)) / 2,
3542 C = 1 + sinφ0 * (2 * n - sinφ0),
3543 ρ0 = Math.sqrt(C) / n;
3545 function forward(λ, φ) {
3546 var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
3548 ρ * Math.sin(λ *= n),
3549 ρ0 - ρ * Math.cos(λ)
3553 forward.invert = function(x, y) {
3556 Math.atan2(x, ρ0_y) / n,
3557 d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n))
3564 (d3.geo.conicEqualArea = function() {
3565 return d3_geo_conic(d3_geo_conicEqualArea);
3566 }).raw = d3_geo_conicEqualArea;
3569 d3.geo.albers = function() {
3570 return d3.geo.conicEqualArea()
3572 .center([-.6, 38.7])
3573 .parallels([29.5, 45.5])
3577 // A composite projection for the United States, configured by default for
3578 // 960×500. Also works quite well at 960×600 with scale 1285. The set of
3579 // standard parallels for each region comes from USGS, which is published here:
3580 // http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
3581 d3.geo.albersUsa = function() {
3582 var lower48 = d3.geo.albers();
3585 var alaska = d3.geo.conicEqualArea()
3588 .parallels([55, 65]);
3591 var hawaii = d3.geo.conicEqualArea()
3594 .parallels([8, 18]);
3597 pointStream = {point: function(x, y) { point = [x, y]; }},
3602 function albersUsa(coordinates) {
3603 var x = coordinates[0], y = coordinates[1];
3605 (lower48Point(x, y), point)
3606 || (alaskaPoint(x, y), point)
3607 || hawaiiPoint(x, y);
3611 albersUsa.invert = function(coordinates) {
3612 var k = lower48.scale(),
3613 t = lower48.translate(),
3614 x = (coordinates[0] - t[0]) / k,
3615 y = (coordinates[1] - t[1]) / k;
3616 return (y >= .120 && y < .234 && x >= -.425 && x < -.214 ? alaska
3617 : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii
3618 : lower48).invert(coordinates);
3621 // A naïve multi-projection stream.
3622 // The projections must have mutually exclusive clip regions on the sphere,
3623 // as this will avoid emitting interleaving lines and polygons.
3624 albersUsa.stream = function(stream) {
3625 var lower48Stream = lower48.stream(stream),
3626 alaskaStream = alaska.stream(stream),
3627 hawaiiStream = hawaii.stream(stream);
3629 point: function(x, y) {
3630 lower48Stream.point(x, y);
3631 alaskaStream.point(x, y);
3632 hawaiiStream.point(x, y);
3634 sphere: function() {
3635 lower48Stream.sphere();
3636 alaskaStream.sphere();
3637 hawaiiStream.sphere();
3639 lineStart: function() {
3640 lower48Stream.lineStart();
3641 alaskaStream.lineStart();
3642 hawaiiStream.lineStart();
3644 lineEnd: function() {
3645 lower48Stream.lineEnd();
3646 alaskaStream.lineEnd();
3647 hawaiiStream.lineEnd();
3649 polygonStart: function() {
3650 lower48Stream.polygonStart();
3651 alaskaStream.polygonStart();
3652 hawaiiStream.polygonStart();
3654 polygonEnd: function() {
3655 lower48Stream.polygonEnd();
3656 alaskaStream.polygonEnd();
3657 hawaiiStream.polygonEnd();
3662 albersUsa.precision = function(_) {
3663 if (!arguments.length) return lower48.precision();
3664 lower48.precision(_);
3665 alaska.precision(_);
3666 hawaii.precision(_);
3670 albersUsa.scale = function(_) {
3671 if (!arguments.length) return lower48.scale();
3673 alaska.scale(_ * .35);
3675 return albersUsa.translate(lower48.translate());
3678 albersUsa.translate = function(_) {
3679 if (!arguments.length) return lower48.translate();
3680 var k = lower48.scale(), x = +_[0], y = +_[1];
3682 lower48Point = lower48
3684 .clipExtent([[x - .455 * k, y - .238 * k], [x + .455 * k, y + .238 * k]])
3685 .stream(pointStream).point;
3687 alaskaPoint = alaska
3688 .translate([x - .307 * k, y + .201 * k])
3689 .clipExtent([[x - .425 * k + ε, y + .120 * k + ε], [x - .214 * k - ε, y + .234 * k - ε]])
3690 .stream(pointStream).point;
3692 hawaiiPoint = hawaii
3693 .translate([x - .205 * k, y + .212 * k])
3694 .clipExtent([[x - .214 * k + ε, y + .166 * k + ε], [x - .115 * k - ε, y + .234 * k - ε]])
3695 .stream(pointStream).point;
3700 return albersUsa.scale(1070);
3703 d3.geo.bounds = (function() {
3704 var λ0, φ0, λ1, φ1, // bounds
3705 λ_, // previous λ-coordinate
3706 λ__, φ__, // first point
3707 p0, // previous 3D point
3714 lineStart: lineStart,
3717 polygonStart: function() {
3718 bound.point = ringPoint;
3719 bound.lineStart = ringStart;
3720 bound.lineEnd = ringEnd;
3722 d3_geo_area.polygonStart();
3724 polygonEnd: function() {
3725 d3_geo_area.polygonEnd();
3726 bound.point = point;
3727 bound.lineStart = lineStart;
3728 bound.lineEnd = lineEnd;
3729 if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90);
3730 else if (dλSum > ε) φ1 = 90;
3731 else if (dλSum < -ε) φ0 = -90;
3732 range[0] = λ0, range[1] = λ1;
3736 function point(λ, φ) {
3737 ranges.push(range = [λ0 = λ, λ1 = λ]);
3742 function linePoint(λ, φ) {
3743 var p = d3_geo_cartesian([λ * d3_radians, φ * d3_radians]);
3745 var normal = d3_geo_cartesianCross(p0, p),
3746 equatorial = [normal[1], -normal[0], 0],
3747 inflection = d3_geo_cartesianCross(equatorial, normal);
3748 d3_geo_cartesianNormalize(inflection);
3749 inflection = d3_geo_spherical(inflection);
3751 s = dλ > 0 ? 1 : -1,
3752 λi = inflection[0] * d3_degrees * s,
3753 antimeridian = abs(dλ) > 180;
3754 if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
3755 var φi = inflection[1] * d3_degrees;
3756 if (φi > φ1) φ1 = φi;
3757 } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
3758 var φi = -inflection[1] * d3_degrees;
3759 if (φi < φ0) φ0 = φi;
3766 if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
3768 if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
3776 if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
3778 if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
3788 function lineStart() { bound.point = linePoint; }
3789 function lineEnd() {
3790 range[0] = λ0, range[1] = λ1;
3791 bound.point = point;
3795 function ringPoint(λ, φ) {
3798 dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;
3799 } else λ__ = λ, φ__ = φ;
3800 d3_geo_area.point(λ, φ);
3804 function ringStart() {
3805 d3_geo_area.lineStart();
3808 function ringEnd() {
3809 ringPoint(λ__, φ__);
3810 d3_geo_area.lineEnd();
3811 if (abs(dλSum) > ε) λ0 = -(λ1 = 180);
3812 range[0] = λ0, range[1] = λ1;
3816 // Finds the left-right distance between two longitudes.
3817 // This is almost the same as (λ1 - λ0 + 360°) % 360°, except that we want
3818 // the distance between ±180° to be 360°.
3819 function angle(λ0, λ1) { return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; }
3821 function compareRanges(a, b) { return a[0] - b[0]; }
3823 function withinRange(x, range) {
3824 return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
3827 return function(feature) {
3828 φ1 = λ1 = -(λ0 = φ0 = Infinity);
3831 d3.geo.stream(feature, bound);
3833 var n = ranges.length;
3835 // First, sort ranges by their minimum longitudes.
3836 ranges.sort(compareRanges);
3838 // Then, merge any ranges that overlap.
3839 for (var i = 1, a = ranges[0], b, merged = [a]; i < n; ++i) {
3841 if (withinRange(b[0], a) || withinRange(b[1], a)) {
3842 if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
3843 if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
3849 // Finally, find the largest gap between the merged ranges.
3850 // The final bounding box will be the inverse of this gap.
3851 var best = -Infinity, dλ;
3852 for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) {
3854 if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];
3857 ranges = range = null;
3859 return λ0 === Infinity || φ0 === Infinity
3860 ? [[NaN, NaN], [NaN, NaN]]
3861 : [[λ0, φ0], [λ1, φ1]];
3865 d3.geo.centroid = function(object) {
3866 d3_geo_centroidW0 = d3_geo_centroidW1 =
3867 d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 =
3868 d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 =
3869 d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
3870 d3.geo.stream(object, d3_geo_centroid);
3872 var x = d3_geo_centroidX2,
3873 y = d3_geo_centroidY2,
3874 z = d3_geo_centroidZ2,
3875 m = x * x + y * y + z * z;
3877 // If the area-weighted centroid is undefined, fall back to length-weighted centroid.
3879 x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;
3880 // If the feature has zero length, fall back to arithmetic mean of point vectors.
3881 if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0;
3882 m = x * x + y * y + z * z;
3883 // If the feature still has an undefined centroid, then return.
3884 if (m < ε2) return [NaN, NaN];
3887 return [Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees];
3890 var d3_geo_centroidW0,
3902 var d3_geo_centroid = {
3904 point: d3_geo_centroidPoint,
3905 lineStart: d3_geo_centroidLineStart,
3906 lineEnd: d3_geo_centroidLineEnd,
3907 polygonStart: function() {
3908 d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
3910 polygonEnd: function() {
3911 d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
3915 // Arithmetic mean of Cartesian vectors.
3916 function d3_geo_centroidPoint(λ, φ) {
3918 var cosφ = Math.cos(φ *= d3_radians);
3919 d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ));
3922 function d3_geo_centroidPointXYZ(x, y, z) {
3923 ++d3_geo_centroidW0;
3924 d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;
3925 d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;
3926 d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;
3929 function d3_geo_centroidLineStart() {
3930 var x0, y0, z0; // previous point
3932 d3_geo_centroid.point = function(λ, φ) {
3934 var cosφ = Math.cos(φ *= d3_radians);
3935 x0 = cosφ * Math.cos(λ);
3936 y0 = cosφ * Math.sin(λ);
3938 d3_geo_centroid.point = nextPoint;
3939 d3_geo_centroidPointXYZ(x0, y0, z0);
3942 function nextPoint(λ, φ) {
3944 var cosφ = Math.cos(φ *= d3_radians),
3945 x = cosφ * Math.cos(λ),
3946 y = cosφ * Math.sin(λ),
3949 Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w),
3950 x0 * x + y0 * y + z0 * z);
3951 d3_geo_centroidW1 += w;
3952 d3_geo_centroidX1 += w * (x0 + (x0 = x));
3953 d3_geo_centroidY1 += w * (y0 + (y0 = y));
3954 d3_geo_centroidZ1 += w * (z0 + (z0 = z));
3955 d3_geo_centroidPointXYZ(x0, y0, z0);
3959 function d3_geo_centroidLineEnd() {
3960 d3_geo_centroid.point = d3_geo_centroidPoint;
3963 // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
3964 // J. Applied Mechanics 42, 239 (1975).
3965 function d3_geo_centroidRingStart() {
3966 var λ00, φ00, // first point
3967 x0, y0, z0; // previous point
3969 d3_geo_centroid.point = function(λ, φ) {
3971 d3_geo_centroid.point = nextPoint;
3973 var cosφ = Math.cos(φ *= d3_radians);
3974 x0 = cosφ * Math.cos(λ);
3975 y0 = cosφ * Math.sin(λ);
3977 d3_geo_centroidPointXYZ(x0, y0, z0);
3980 d3_geo_centroid.lineEnd = function() {
3981 nextPoint(λ00, φ00);
3982 d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
3983 d3_geo_centroid.point = d3_geo_centroidPoint;
3986 function nextPoint(λ, φ) {
3988 var cosφ = Math.cos(φ *= d3_radians),
3989 x = cosφ * Math.cos(λ),
3990 y = cosφ * Math.sin(λ),
3992 cx = y0 * z - z0 * y,
3993 cy = z0 * x - x0 * z,
3994 cz = x0 * y - y0 * x,
3995 m = Math.sqrt(cx * cx + cy * cy + cz * cz),
3996 u = x0 * x + y0 * y + z0 * z,
3997 v = m && -d3_acos(u) / m, // area weight
3998 w = Math.atan2(m, u); // line weight
3999 d3_geo_centroidX2 += v * cx;
4000 d3_geo_centroidY2 += v * cy;
4001 d3_geo_centroidZ2 += v * cz;
4002 d3_geo_centroidW1 += w;
4003 d3_geo_centroidX1 += w * (x0 + (x0 = x));
4004 d3_geo_centroidY1 += w * (y0 + (y0 = y));
4005 d3_geo_centroidZ1 += w * (z0 + (z0 = z));
4006 d3_geo_centroidPointXYZ(x0, y0, z0);
4010 // TODO Unify this code with d3.geom.polygon area?
4012 var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
4017 // Only count area for polygon rings.
4018 polygonStart: function() {
4019 d3_geo_pathAreaPolygon = 0;
4020 d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
4022 polygonEnd: function() {
4023 d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;
4024 d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2);
4028 function d3_geo_pathAreaRingStart() {
4029 var x00, y00, x0, y0;
4031 // For the first point, …
4032 d3_geo_pathArea.point = function(x, y) {
4033 d3_geo_pathArea.point = nextPoint;
4034 x00 = x0 = x, y00 = y0 = y;
4037 // For subsequent points, …
4038 function nextPoint(x, y) {
4039 d3_geo_pathAreaPolygon += y0 * x - x0 * y;
4043 // For the last point, return to the start.
4044 d3_geo_pathArea.lineEnd = function() {
4045 nextPoint(x00, y00);
4049 var d3_geo_pathBoundsX0,
4050 d3_geo_pathBoundsY0,
4051 d3_geo_pathBoundsX1,
4052 d3_geo_pathBoundsY1;
4054 var d3_geo_pathBounds = {
4055 point: d3_geo_pathBoundsPoint,
4058 polygonStart: d3_noop,
4062 function d3_geo_pathBoundsPoint(x, y) {
4063 if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;
4064 if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;
4065 if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;
4066 if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;
4068 function d3_geo_pathBuffer() {
4069 var pointCircle = d3_geo_pathBufferCircle(4.5),
4075 // While inside a line, override point to moveTo then lineTo.
4076 lineStart: function() { stream.point = pointLineStart; },
4079 // While inside a polygon, override lineEnd to closePath.
4080 polygonStart: function() { stream.lineEnd = lineEndPolygon; },
4081 polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; },
4083 pointRadius: function(_) {
4084 pointCircle = d3_geo_pathBufferCircle(_);
4088 result: function() {
4089 if (buffer.length) {
4090 var result = buffer.join("");
4097 function point(x, y) {
4098 buffer.push("M", x, ",", y, pointCircle);
4101 function pointLineStart(x, y) {
4102 buffer.push("M", x, ",", y);
4103 stream.point = pointLine;
4106 function pointLine(x, y) {
4107 buffer.push("L", x, ",", y);
4110 function lineEnd() {
4111 stream.point = point;
4114 function lineEndPolygon() {
4121 function d3_geo_pathBufferCircle(radius) {
4122 return "m0," + radius
4123 + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
4124 + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
4128 // TODO Unify this code with d3.geom.polygon centroid?
4129 // TODO Enforce positive area for exterior, negative area for interior?
4131 var d3_geo_pathCentroid = {
4132 point: d3_geo_pathCentroidPoint,
4134 // For lines, weight by length.
4135 lineStart: d3_geo_pathCentroidLineStart,
4136 lineEnd: d3_geo_pathCentroidLineEnd,
4138 // For polygons, weight by area.
4139 polygonStart: function() {
4140 d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
4142 polygonEnd: function() {
4143 d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
4144 d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
4145 d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
4149 function d3_geo_pathCentroidPoint(x, y) {
4150 d3_geo_centroidX0 += x;
4151 d3_geo_centroidY0 += y;
4152 ++d3_geo_centroidZ0;
4155 function d3_geo_pathCentroidLineStart() {
4158 d3_geo_pathCentroid.point = function(x, y) {
4159 d3_geo_pathCentroid.point = nextPoint;
4160 d3_geo_pathCentroidPoint(x0 = x, y0 = y);
4163 function nextPoint(x, y) {
4164 var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
4165 d3_geo_centroidX1 += z * (x0 + x) / 2;
4166 d3_geo_centroidY1 += z * (y0 + y) / 2;
4167 d3_geo_centroidZ1 += z;
4168 d3_geo_pathCentroidPoint(x0 = x, y0 = y);
4172 function d3_geo_pathCentroidLineEnd() {
4173 d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
4176 function d3_geo_pathCentroidRingStart() {
4177 var x00, y00, x0, y0;
4179 // For the first point, …
4180 d3_geo_pathCentroid.point = function(x, y) {
4181 d3_geo_pathCentroid.point = nextPoint;
4182 d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y);
4185 // For subsequent points, …
4186 function nextPoint(x, y) {
4187 var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
4188 d3_geo_centroidX1 += z * (x0 + x) / 2;
4189 d3_geo_centroidY1 += z * (y0 + y) / 2;
4190 d3_geo_centroidZ1 += z;
4192 z = y0 * x - x0 * y;
4193 d3_geo_centroidX2 += z * (x0 + x);
4194 d3_geo_centroidY2 += z * (y0 + y);
4195 d3_geo_centroidZ2 += z * 3;
4196 d3_geo_pathCentroidPoint(x0 = x, y0 = y);
4199 // For the last point, return to the start.
4200 d3_geo_pathCentroid.lineEnd = function() {
4201 nextPoint(x00, y00);
4205 function d3_geo_pathContext(context) {
4206 var pointRadius = 4.5;
4211 // While inside a line, override point to moveTo then lineTo.
4212 lineStart: function() { stream.point = pointLineStart; },
4215 // While inside a polygon, override lineEnd to closePath.
4216 polygonStart: function() { stream.lineEnd = lineEndPolygon; },
4217 polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; },
4219 pointRadius: function(_) {
4227 function point(x, y) {
4228 context.moveTo(x + pointRadius, y);
4229 context.arc(x, y, pointRadius, 0, τ);
4232 function pointLineStart(x, y) {
4233 context.moveTo(x, y);
4234 stream.point = pointLine;
4237 function pointLine(x, y) {
4238 context.lineTo(x, y);
4241 function lineEnd() {
4242 stream.point = point;
4245 function lineEndPolygon() {
4246 context.closePath();
4252 function d3_geo_resample(project) {
4253 var δ2 = .5, // precision, px²
4254 cosMinDistance = Math.cos(30 * d3_radians), // cos(minimum angular distance)
4257 function resample(stream) {
4258 return (maxDepth ? resampleRecursive : resampleNone)(stream);
4261 function resampleNone(stream) {
4262 return d3_geo_transformPoint(stream, function(x, y) {
4264 stream.point(x[0], x[1]);
4268 function resampleRecursive(stream) {
4269 var λ00, φ00, x00, y00, a00, b00, c00, // first point
4270 λ0, x0, y0, a0, b0, c0; // previous point
4274 lineStart: lineStart,
4276 polygonStart: function() { stream.polygonStart(); resample.lineStart = ringStart; },
4277 polygonEnd: function() { stream.polygonEnd(); resample.lineStart = lineStart; }
4280 function point(x, y) {
4282 stream.point(x[0], x[1]);
4285 function lineStart() {
4287 resample.point = linePoint;
4291 function linePoint(λ, φ) {
4292 var c = d3_geo_cartesian([λ, φ]), p = project(λ, φ);
4293 resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
4294 stream.point(x0, y0);
4297 function lineEnd() {
4298 resample.point = point;
4302 function ringStart() {
4304 resample.point = ringPoint;
4305 resample.lineEnd = ringEnd;
4308 function ringPoint(λ, φ) {
4309 linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
4310 resample.point = linePoint;
4313 function ringEnd() {
4314 resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);
4315 resample.lineEnd = lineEnd;
4322 function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {
4325 d2 = dx * dx + dy * dy;
4326 if (d2 > 4 * δ2 && depth--) {
4330 m = Math.sqrt(a * a + b * b + c * c),
4331 φ2 = Math.asin(c /= m),
4332 λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a),
4333 p = project(λ2, φ2),
4338 dz = dy * dx2 - dx * dy2;
4339 if (dz * dz / d2 > δ2 // perpendicular projected distance
4340 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 // midpoint close to an end
4341 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
4342 resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream);
4343 stream.point(x2, y2);
4344 resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
4349 resample.precision = function(_) {
4350 if (!arguments.length) return Math.sqrt(δ2);
4351 maxDepth = (δ2 = _ * _) > 0 && 16;
4358 d3.geo.path = function() {
4359 var pointRadius = 4.5,
4366 function path(object) {
4368 if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
4369 if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream);
4370 d3.geo.stream(object, cacheStream);
4372 return contextStream.result();
4375 path.area = function(object) {
4376 d3_geo_pathAreaSum = 0;
4377 d3.geo.stream(object, projectStream(d3_geo_pathArea));
4378 return d3_geo_pathAreaSum;
4381 path.centroid = function(object) {
4382 d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 =
4383 d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 =
4384 d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
4385 d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
4386 return d3_geo_centroidZ2 ? [d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2]
4387 : d3_geo_centroidZ1 ? [d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1]
4388 : d3_geo_centroidZ0 ? [d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0]
4392 path.bounds = function(object) {
4393 d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity);
4394 d3.geo.stream(object, projectStream(d3_geo_pathBounds));
4395 return [[d3_geo_pathBoundsX0, d3_geo_pathBoundsY0], [d3_geo_pathBoundsX1, d3_geo_pathBoundsY1]];
4398 path.projection = function(_) {
4399 if (!arguments.length) return projection;
4400 projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;
4404 path.context = function(_) {
4405 if (!arguments.length) return context;
4406 contextStream = (context = _) == null ? new d3_geo_pathBuffer : new d3_geo_pathContext(_);
4407 if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
4411 path.pointRadius = function(_) {
4412 if (!arguments.length) return pointRadius;
4413 pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
4422 return path.projection(d3.geo.albersUsa()).context(null);
4425 function d3_geo_pathProjectStream(project) {
4426 var resample = d3_geo_resample(function(x, y) { return project([x * d3_degrees, y * d3_degrees]); });
4427 return function(stream) { return d3_geo_projectionRadians(resample(stream)); };
4430 d3.geo.transform = function(methods) {
4432 stream: function(stream) {
4433 var transform = new d3_geo_transform(stream);
4434 for (var k in methods) transform[k] = methods[k];
4440 function d3_geo_transform(stream) {
4441 this.stream = stream;
4444 d3_geo_transform.prototype = {
4445 point: function(x, y) { this.stream.point(x, y); },
4446 sphere: function() { this.stream.sphere(); },
4447 lineStart: function() { this.stream.lineStart(); },
4448 lineEnd: function() { this.stream.lineEnd(); },
4449 polygonStart: function() { this.stream.polygonStart(); },
4450 polygonEnd: function() { this.stream.polygonEnd(); }
4453 function d3_geo_transformPoint(stream, point) {
4456 sphere: function() { stream.sphere(); },
4457 lineStart: function() { stream.lineStart(); },
4458 lineEnd: function() { stream.lineEnd(); },
4459 polygonStart: function() { stream.polygonStart(); },
4460 polygonEnd: function() { stream.polygonEnd(); },
4464 d3.geo.projection = d3_geo_projection;
4465 d3.geo.projectionMutator = d3_geo_projectionMutator;
4467 function d3_geo_projection(project) {
4468 return d3_geo_projectionMutator(function() { return project; })();
4471 function d3_geo_projectionMutator(projectAt) {
4475 projectResample = d3_geo_resample(function(x, y) { x = project(x, y); return [x[0] * k + δx, δy - x[1] * k]; }),
4477 x = 480, y = 250, // translate
4478 λ = 0, φ = 0, // center
4479 δλ = 0, δφ = 0, δγ = 0, // rotate
4481 preclip = d3_geo_clipAntimeridian,
4482 postclip = d3_identity,
4487 function projection(point) {
4488 point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
4489 return [point[0] * k + δx, δy - point[1] * k];
4492 function invert(point) {
4493 point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k);
4494 return point && [point[0] * d3_degrees, point[1] * d3_degrees];
4497 projection.stream = function(output) {
4498 if (stream) stream.valid = false;
4499 stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output))));
4500 stream.valid = true; // allow caching by d3.geo.path
4504 projection.clipAngle = function(_) {
4505 if (!arguments.length) return clipAngle;
4506 preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians);
4507 return invalidate();
4510 projection.clipExtent = function(_) {
4511 if (!arguments.length) return clipExtent;
4513 postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
4514 return invalidate();
4517 projection.scale = function(_) {
4518 if (!arguments.length) return k;
4523 projection.translate = function(_) {
4524 if (!arguments.length) return [x, y];
4530 projection.center = function(_) {
4531 if (!arguments.length) return [λ * d3_degrees, φ * d3_degrees];
4532 λ = _[0] % 360 * d3_radians;
4533 φ = _[1] % 360 * d3_radians;
4537 projection.rotate = function(_) {
4538 if (!arguments.length) return [δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees];
4539 δλ = _[0] % 360 * d3_radians;
4540 δφ = _[1] % 360 * d3_radians;
4541 δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
4545 d3.rebind(projection, projectResample, "precision");
4548 projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project);
4549 var center = project(λ, φ);
4550 δx = x - center[0] * k;
4551 δy = y + center[1] * k;
4552 return invalidate();
4555 function invalidate() {
4556 if (stream) stream.valid = false, stream = null;
4561 project = projectAt.apply(this, arguments);
4562 projection.invert = project.invert && invert;
4567 function d3_geo_projectionRadians(stream) {
4568 return d3_geo_transformPoint(stream, function(x, y) {
4569 stream.point(x * d3_radians, y * d3_radians);
4573 function d3_geo_mercator(λ, φ) {
4574 return [λ, Math.log(Math.tan(π / 4 + φ / 2))];
4577 d3_geo_mercator.invert = function(x, y) {
4578 return [x, 2 * Math.atan(Math.exp(y)) - halfπ];
4581 function d3_geo_mercatorProjection(project) {
4582 var m = d3_geo_projection(project),
4584 translate = m.translate,
4585 clipExtent = m.clipExtent,
4588 m.scale = function() {
4589 var v = scale.apply(m, arguments);
4590 return v === m ? (clipAuto ? m.clipExtent(null) : m) : v;
4593 m.translate = function() {
4594 var v = translate.apply(m, arguments);
4595 return v === m ? (clipAuto ? m.clipExtent(null) : m) : v;
4598 m.clipExtent = function(_) {
4599 var v = clipExtent.apply(m, arguments);
4601 if (clipAuto = _ == null) {
4602 var k = π * scale(), t = translate();
4603 clipExtent([[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]]);
4605 } else if (clipAuto) {
4611 return m.clipExtent(null);
4614 (d3.geo.mercator = function() {
4615 return d3_geo_mercatorProjection(d3_geo_mercator);
4616 }).raw = d3_geo_mercator;
4619 d3.geom.polygon = function(coordinates) {
4620 d3_subclass(coordinates, d3_geom_polygonPrototype);
4624 var d3_geom_polygonPrototype = d3.geom.polygon.prototype = [];
4626 d3_geom_polygonPrototype.area = function() {
4636 area += a[1] * b[0] - a[0] * b[1];
4642 d3_geom_polygonPrototype.centroid = function(k) {
4651 if (!arguments.length) k = -1 / (6 * this.area());
4656 c = a[0] * b[1] - b[0] * a[1];
4657 x += (a[0] + b[0]) * c;
4658 y += (a[1] + b[1]) * c;
4661 return [x * k, y * k];
4664 // The Sutherland-Hodgman clipping algorithm.
4665 // Note: requires the clip polygon to be counterclockwise and convex.
4666 d3_geom_polygonPrototype.clip = function(subject) {
4668 closed = d3_geom_polygonClosed(subject),
4670 n = this.length - d3_geom_polygonClosed(this),
4679 input = subject.slice();
4682 c = input[(m = input.length - closed) - 1];
4686 if (d3_geom_polygonInside(d, a, b)) {
4687 if (!d3_geom_polygonInside(c, a, b)) {
4688 subject.push(d3_geom_polygonIntersect(c, d, a, b));
4691 } else if (d3_geom_polygonInside(c, a, b)) {
4692 subject.push(d3_geom_polygonIntersect(c, d, a, b));
4696 if (closed) subject.push(subject[0]);
4703 function d3_geom_polygonInside(p, a, b) {
4704 return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
4707 // Intersect two infinite lines cd and ab.
4708 function d3_geom_polygonIntersect(c, d, a, b) {
4709 var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3,
4710 y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3,
4711 ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);
4712 return [x1 + ua * x21, y1 + ua * y21];
4715 // Returns true if the polygon is closed.
4716 function d3_geom_polygonClosed(coordinates) {
4717 var a = coordinates[0],
4718 b = coordinates[coordinates.length - 1];
4719 return !(a[0] - b[0] || a[1] - b[1]);
4721 function d3_geom_pointX(d) {
4725 function d3_geom_pointY(d) {
4730 * Computes the 2D convex hull of a set of points using the monotone chain
4732 * http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain)
4734 * The runtime of this algorithm is O(n log n), where n is the number of input
4735 * points. However in practice it outperforms other O(n log n) hulls.
4737 * @param vertices [[x1, y1], [x2, y2], ...]
4738 * @returns polygon [[x1, y1], [x2, y2], ...]
4740 d3.geom.hull = function(vertices) {
4741 var x = d3_geom_pointX,
4744 if (arguments.length) return hull(vertices);
4746 function hull(data) {
4747 // Hull of < 3 points is not well-defined
4748 if (data.length < 3) return [];
4750 var fx = d3_functor(x),
4754 points = [], // of the form [[x0, y0, 0], ..., [xn, yn, n]]
4757 for (i = 0 ; i < n; i++) {
4758 points.push([+fx.call(this, data[i], i), +fy.call(this, data[i], i), i]);
4761 // sort ascending by x-coord first, y-coord second
4762 points.sort(d3_geom_hullOrder);
4764 // we flip bottommost points across y axis so we can use the upper hull routine on both
4765 for (i = 0; i < n; i++) flippedPoints.push([points[i][0], -points[i][1]]);
4767 var upper = d3_geom_hullUpper(points),
4768 lower = d3_geom_hullUpper(flippedPoints);
4770 // construct the polygon, removing possible duplicate endpoints
4771 var skipLeft = lower[0] === upper[0],
4772 skipRight = lower[lower.length - 1] === upper[upper.length - 1],
4775 // add upper hull in r->l order
4776 // then add lower hull in l->r order
4777 for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]);
4778 for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]);
4783 hull.x = function(_) {
4784 return arguments.length ? (x = _, hull) : x;
4787 hull.y = function(_) {
4788 return arguments.length ? (y = _, hull) : y;
4794 // finds the 'upper convex hull' (see wiki link above)
4795 // assumes points arg has >=3 elements, is sorted by x, unique in y
4796 // returns array of indices into points in left to right order
4797 function d3_geom_hullUpper(points) {
4798 var n = points.length,
4800 hs = 2; // hull size
4802 for (var i = 2; i < n; i++) {
4803 while (hs > 1 && d3_cross2d(points[hull[hs-2]], points[hull[hs-1]], points[i]) <= 0) --hs;
4807 // we slice to make sure that the points we 'popped' from hull don't stay behind
4808 return hull.slice(0, hs);
4811 // comparator for ascending sort by x-coord first, y-coord second
4812 function d3_geom_hullOrder(a, b) {
4813 return a[0] - b[0] || a[1] - b[1];
4815 // import "../transition/transition";
4817 d3_selectionPrototype.transition = function(name) {
4818 var id = d3_transitionInheritId || ++d3_transitionId,
4819 ns = d3_transitionNamespace(name),
4823 transition = d3_transitionInherit || {time: Date.now(), ease: d3_ease_cubicInOut, delay: 0, duration: 250};
4825 for (var j = -1, m = this.length; ++j < m;) {
4826 subgroups.push(subgroup = []);
4827 for (var group = this[j], i = -1, n = group.length; ++i < n;) {
4828 if (node = group[i]) d3_transitionNode(node, i, ns, id, transition);
4829 subgroup.push(node);
4833 return d3_transition(subgroups, ns, id);
4835 // import "../transition/transition";
4837 // TODO Interrupt transitions for all namespaces?
4838 d3_selectionPrototype.interrupt = function(name) {
4839 return this.each(name == null
4840 ? d3_selection_interrupt
4841 : d3_selection_interruptNS(d3_transitionNamespace(name)));
4844 var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace());
4846 function d3_selection_interruptNS(ns) {
4849 if ((lock = this[ns]) && (active = lock[lock.active])) {
4850 if (--lock.count) delete lock[lock.active];
4851 else delete this[ns];
4853 active.event && active.event.interrupt.call(this, this.__data__, active.index);
4858 function d3_transition(groups, ns, id) {
4859 d3_subclass(groups, d3_transitionPrototype);
4862 groups.namespace = ns;
4868 var d3_transitionPrototype = [],
4869 d3_transitionId = 0,
4870 d3_transitionInheritId,
4871 d3_transitionInherit;
4873 d3_transitionPrototype.call = d3_selectionPrototype.call;
4874 d3_transitionPrototype.empty = d3_selectionPrototype.empty;
4875 d3_transitionPrototype.node = d3_selectionPrototype.node;
4876 d3_transitionPrototype.size = d3_selectionPrototype.size;
4878 d3.transition = function(selection, name) {
4879 return selection && selection.transition
4880 ? (d3_transitionInheritId ? selection.transition(name) : selection)
4881 : d3.selection().transition(selection);
4884 d3.transition.prototype = d3_transitionPrototype;
4887 d3_transitionPrototype.select = function(selector) {
4889 ns = this.namespace,
4895 selector = d3_selection_selector(selector);
4897 for (var j = -1, m = this.length; ++j < m;) {
4898 subgroups.push(subgroup = []);
4899 for (var group = this[j], i = -1, n = group.length; ++i < n;) {
4900 if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) {
4901 if ("__data__" in node) subnode.__data__ = node.__data__;
4902 d3_transitionNode(subnode, i, ns, id, node[ns][id]);
4903 subgroup.push(subnode);
4905 subgroup.push(null);
4910 return d3_transition(subgroups, ns, id);
4913 d3_transitionPrototype.selectAll = function(selector) {
4915 ns = this.namespace,
4923 selector = d3_selection_selectorAll(selector);
4925 for (var j = -1, m = this.length; ++j < m;) {
4926 for (var group = this[j], i = -1, n = group.length; ++i < n;) {
4927 if (node = group[i]) {
4928 transition = node[ns][id];
4929 subnodes = selector.call(node, node.__data__, i, j);
4930 subgroups.push(subgroup = []);
4931 for (var k = -1, o = subnodes.length; ++k < o;) {
4932 if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition);
4933 subgroup.push(subnode);
4939 return d3_transition(subgroups, ns, id);
4942 d3_transitionPrototype.filter = function(filter) {
4948 if (typeof filter !== "function") filter = d3_selection_filter(filter);
4950 for (var j = 0, m = this.length; j < m; j++) {
4951 subgroups.push(subgroup = []);
4952 for (var group = this[j], i = 0, n = group.length; i < n; i++) {
4953 if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
4954 subgroup.push(node);
4959 return d3_transition(subgroups, this.namespace, this.id);
4961 d3.color = d3_color;
4963 function d3_color() {}
4965 d3_color.prototype.toString = function() {
4966 return this.rgb() + "";
4971 function d3_hsl(h, s, l) {
4972 return this instanceof d3_hsl ? void (this.h = +h, this.s = +s, this.l = +l)
4973 : arguments.length < 2 ? (h instanceof d3_hsl ? new d3_hsl(h.h, h.s, h.l)
4974 : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl))
4975 : new d3_hsl(h, s, l);
4978 var d3_hslPrototype = d3_hsl.prototype = new d3_color;
4980 d3_hslPrototype.brighter = function(k) {
4981 k = Math.pow(0.7, arguments.length ? k : 1);
4982 return new d3_hsl(this.h, this.s, this.l / k);
4985 d3_hslPrototype.darker = function(k) {
4986 k = Math.pow(0.7, arguments.length ? k : 1);
4987 return new d3_hsl(this.h, this.s, k * this.l);
4990 d3_hslPrototype.rgb = function() {
4991 return d3_hsl_rgb(this.h, this.s, this.l);
4994 function d3_hsl_rgb(h, s, l) {
4998 /* Some simple corrections for h, s and l. */
4999 h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;
5000 s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s;
5001 l = l < 0 ? 0 : l > 1 ? 1 : l;
5003 /* From FvD 13.37, CSS Color Module Level 3 */
5004 m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
5008 if (h > 360) h -= 360;
5009 else if (h < 0) h += 360;
5010 if (h < 60) return m1 + (m2 - m1) * h / 60;
5011 if (h < 180) return m2;
5012 if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
5017 return Math.round(v(h) * 255);
5020 return new d3_rgb(vv(h + 120), vv(h), vv(h - 120));
5025 function d3_hcl(h, c, l) {
5026 return this instanceof d3_hcl ? void (this.h = +h, this.c = +c, this.l = +l)
5027 : arguments.length < 2 ? (h instanceof d3_hcl ? new d3_hcl(h.h, h.c, h.l)
5028 : (h instanceof d3_lab ? d3_lab_hcl(h.l, h.a, h.b)
5029 : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b)))
5030 : new d3_hcl(h, c, l);
5033 var d3_hclPrototype = d3_hcl.prototype = new d3_color;
5035 d3_hclPrototype.brighter = function(k) {
5036 return new d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
5039 d3_hclPrototype.darker = function(k) {
5040 return new d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
5043 d3_hclPrototype.rgb = function() {
5044 return d3_hcl_lab(this.h, this.c, this.l).rgb();
5047 function d3_hcl_lab(h, c, l) {
5048 if (isNaN(h)) h = 0;
5049 if (isNaN(c)) c = 0;
5050 return new d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
5055 function d3_lab(l, a, b) {
5056 return this instanceof d3_lab ? void (this.l = +l, this.a = +a, this.b = +b)
5057 : arguments.length < 2 ? (l instanceof d3_lab ? new d3_lab(l.l, l.a, l.b)
5058 : (l instanceof d3_hcl ? d3_hcl_lab(l.h, l.c, l.l)
5059 : d3_rgb_lab((l = d3_rgb(l)).r, l.g, l.b)))
5060 : new d3_lab(l, a, b);
5063 // Corresponds roughly to RGB brighter/darker
5066 // D65 standard referent
5067 var d3_lab_X = 0.950470,
5069 d3_lab_Z = 1.088830;
5071 var d3_labPrototype = d3_lab.prototype = new d3_color;
5073 d3_labPrototype.brighter = function(k) {
5074 return new d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
5077 d3_labPrototype.darker = function(k) {
5078 return new d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
5081 d3_labPrototype.rgb = function() {
5082 return d3_lab_rgb(this.l, this.a, this.b);
5085 function d3_lab_rgb(l, a, b) {
5086 var y = (l + 16) / 116,
5089 x = d3_lab_xyz(x) * d3_lab_X;
5090 y = d3_lab_xyz(y) * d3_lab_Y;
5091 z = d3_lab_xyz(z) * d3_lab_Z;
5093 d3_xyz_rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z),
5094 d3_xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
5095 d3_xyz_rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z)
5099 function d3_lab_hcl(l, a, b) {
5101 ? new d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l)
5102 : new d3_hcl(NaN, NaN, l);
5105 function d3_lab_xyz(x) {
5106 return x > 0.206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
5108 function d3_xyz_lab(x) {
5109 return x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
5112 function d3_xyz_rgb(r) {
5113 return Math.round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - 0.055));
5118 function d3_rgb(r, g, b) {
5119 return this instanceof d3_rgb ? void (this.r = ~~r, this.g = ~~g, this.b = ~~b)
5120 : arguments.length < 2 ? (r instanceof d3_rgb ? new d3_rgb(r.r, r.g, r.b)
5121 : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb))
5122 : new d3_rgb(r, g, b);
5125 function d3_rgbNumber(value) {
5126 return new d3_rgb(value >> 16, value >> 8 & 0xff, value & 0xff);
5129 function d3_rgbString(value) {
5130 return d3_rgbNumber(value) + "";
5133 var d3_rgbPrototype = d3_rgb.prototype = new d3_color;
5135 d3_rgbPrototype.brighter = function(k) {
5136 k = Math.pow(0.7, arguments.length ? k : 1);
5141 if (!r && !g && !b) return new d3_rgb(i, i, i);
5142 if (r && r < i) r = i;
5143 if (g && g < i) g = i;
5144 if (b && b < i) b = i;
5145 return new d3_rgb(Math.min(255, r / k), Math.min(255, g / k), Math.min(255, b / k));
5148 d3_rgbPrototype.darker = function(k) {
5149 k = Math.pow(0.7, arguments.length ? k : 1);
5150 return new d3_rgb(k * this.r, k * this.g, k * this.b);
5153 d3_rgbPrototype.hsl = function() {
5154 return d3_rgb_hsl(this.r, this.g, this.b);
5157 d3_rgbPrototype.toString = function() {
5158 return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
5161 function d3_rgb_hex(v) {
5163 ? "0" + Math.max(0, v).toString(16)
5164 : Math.min(255, v).toString(16);
5167 function d3_rgb_parse(format, rgb, hsl) {
5168 var r = 0, // red channel; int in [0, 255]
5169 g = 0, // green channel; int in [0, 255]
5170 b = 0, // blue channel; int in [0, 255]
5171 m1, // CSS color specification match
5172 m2, // CSS color specification type (e.g., rgb)
5175 /* Handle hsl, rgb. */
5176 m1 = /([a-z]+)\((.*)\)/i.exec(format);
5178 m2 = m1[2].split(",");
5182 parseFloat(m2[0]), // degrees
5183 parseFloat(m2[1]) / 100, // percentage
5184 parseFloat(m2[2]) / 100 // percentage
5189 d3_rgb_parseNumber(m2[0]),
5190 d3_rgb_parseNumber(m2[1]),
5191 d3_rgb_parseNumber(m2[2])
5198 if (color = d3_rgb_names.get(format.toLowerCase())) {
5199 return rgb(color.r, color.g, color.b);
5202 /* Hexadecimal colors: #rgb and #rrggbb. */
5203 if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.slice(1), 16))) {
5204 if (format.length === 4) {
5205 r = (color & 0xf00) >> 4; r = (r >> 4) | r;
5206 g = (color & 0xf0); g = (g >> 4) | g;
5207 b = (color & 0xf); b = (b << 4) | b;
5208 } else if (format.length === 7) {
5209 r = (color & 0xff0000) >> 16;
5210 g = (color & 0xff00) >> 8;
5215 return rgb(r, g, b);
5218 function d3_rgb_hsl(r, g, b) {
5219 var min = Math.min(r /= 255, g /= 255, b /= 255),
5220 max = Math.max(r, g, b),
5224 l = (max + min) / 2;
5226 s = l < .5 ? d / (max + min) : d / (2 - max - min);
5227 if (r == max) h = (g - b) / d + (g < b ? 6 : 0);
5228 else if (g == max) h = (b - r) / d + 2;
5229 else h = (r - g) / d + 4;
5233 s = l > 0 && l < 1 ? 0 : h;
5235 return new d3_hsl(h, s, l);
5238 function d3_rgb_lab(r, g, b) {
5242 var x = d3_xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / d3_lab_X),
5243 y = d3_xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / d3_lab_Y),
5244 z = d3_xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / d3_lab_Z);
5245 return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
5248 function d3_rgb_xyz(r) {
5249 return (r /= 255) <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
5252 function d3_rgb_parseNumber(c) { // either integer or percentage
5253 var f = parseFloat(c);
5254 return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
5257 var d3_rgb_names = d3.map({
5258 aliceblue: 0xf0f8ff,
5259 antiquewhite: 0xfaebd7,
5261 aquamarine: 0x7fffd4,
5266 blanchedalmond: 0xffebcd,
5268 blueviolet: 0x8a2be2,
5270 burlywood: 0xdeb887,
5271 cadetblue: 0x5f9ea0,
5272 chartreuse: 0x7fff00,
5273 chocolate: 0xd2691e,
5275 cornflowerblue: 0x6495ed,
5281 darkgoldenrod: 0xb8860b,
5283 darkgreen: 0x006400,
5285 darkkhaki: 0xbdb76b,
5286 darkmagenta: 0x8b008b,
5287 darkolivegreen: 0x556b2f,
5288 darkorange: 0xff8c00,
5289 darkorchid: 0x9932cc,
5291 darksalmon: 0xe9967a,
5292 darkseagreen: 0x8fbc8f,
5293 darkslateblue: 0x483d8b,
5294 darkslategray: 0x2f4f4f,
5295 darkslategrey: 0x2f4f4f,
5296 darkturquoise: 0x00ced1,
5297 darkviolet: 0x9400d3,
5299 deepskyblue: 0x00bfff,
5302 dodgerblue: 0x1e90ff,
5303 firebrick: 0xb22222,
5304 floralwhite: 0xfffaf0,
5305 forestgreen: 0x228b22,
5307 gainsboro: 0xdcdcdc,
5308 ghostwhite: 0xf8f8ff,
5310 goldenrod: 0xdaa520,
5313 greenyellow: 0xadff2f,
5317 indianred: 0xcd5c5c,
5322 lavenderblush: 0xfff0f5,
5323 lawngreen: 0x7cfc00,
5324 lemonchiffon: 0xfffacd,
5325 lightblue: 0xadd8e6,
5326 lightcoral: 0xf08080,
5327 lightcyan: 0xe0ffff,
5328 lightgoldenrodyellow: 0xfafad2,
5329 lightgray: 0xd3d3d3,
5330 lightgreen: 0x90ee90,
5331 lightgrey: 0xd3d3d3,
5332 lightpink: 0xffb6c1,
5333 lightsalmon: 0xffa07a,
5334 lightseagreen: 0x20b2aa,
5335 lightskyblue: 0x87cefa,
5336 lightslategray: 0x778899,
5337 lightslategrey: 0x778899,
5338 lightsteelblue: 0xb0c4de,
5339 lightyellow: 0xffffe0,
5341 limegreen: 0x32cd32,
5345 mediumaquamarine: 0x66cdaa,
5346 mediumblue: 0x0000cd,
5347 mediumorchid: 0xba55d3,
5348 mediumpurple: 0x9370db,
5349 mediumseagreen: 0x3cb371,
5350 mediumslateblue: 0x7b68ee,
5351 mediumspringgreen: 0x00fa9a,
5352 mediumturquoise: 0x48d1cc,
5353 mediumvioletred: 0xc71585,
5354 midnightblue: 0x191970,
5355 mintcream: 0xf5fffa,
5356 mistyrose: 0xffe4e1,
5358 navajowhite: 0xffdead,
5362 olivedrab: 0x6b8e23,
5364 orangered: 0xff4500,
5366 palegoldenrod: 0xeee8aa,
5367 palegreen: 0x98fb98,
5368 paleturquoise: 0xafeeee,
5369 palevioletred: 0xdb7093,
5370 papayawhip: 0xffefd5,
5371 peachpuff: 0xffdab9,
5375 powderblue: 0xb0e0e6,
5377 rebeccapurple: 0x663399,
5379 rosybrown: 0xbc8f8f,
5380 royalblue: 0x4169e1,
5381 saddlebrown: 0x8b4513,
5383 sandybrown: 0xf4a460,
5389 slateblue: 0x6a5acd,
5390 slategray: 0x708090,
5391 slategrey: 0x708090,
5393 springgreen: 0x00ff7f,
5394 steelblue: 0x4682b4,
5399 turquoise: 0x40e0d0,
5403 whitesmoke: 0xf5f5f5,
5405 yellowgreen: 0x9acd32
5408 d3_rgb_names.forEach(function(key, value) {
5409 d3_rgb_names.set(key, d3_rgbNumber(value));
5412 d3.interpolateRgb = d3_interpolateRgb;
5414 function d3_interpolateRgb(a, b) {
5423 return function(t) {
5425 + d3_rgb_hex(Math.round(ar + br * t))
5426 + d3_rgb_hex(Math.round(ag + bg * t))
5427 + d3_rgb_hex(Math.round(ab + bb * t));
5431 d3.interpolateObject = d3_interpolateObject;
5433 function d3_interpolateObject(a, b) {
5439 i[k] = d3_interpolate(a[k], b[k]);
5449 return function(t) {
5450 for (k in i) c[k] = i[k](t);
5455 d3.interpolateArray = d3_interpolateArray;
5457 function d3_interpolateArray(a, b) {
5462 n0 = Math.min(a.length, b.length),
5464 for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i]));
5465 for (; i < na; ++i) c[i] = a[i];
5466 for (; i < nb; ++i) c[i] = b[i];
5467 return function(t) {
5468 for (i = 0; i < n0; ++i) c[i] = x[i](t);
5472 d3.interpolateNumber = d3_interpolateNumber;
5474 function d3_interpolateNumber(a, b) {
5476 return function(t) { return a * (1 - t) + b * t; };
5479 d3.interpolateString = d3_interpolateString;
5481 function d3_interpolateString(a, b) {
5482 var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, // scan index for next number in b
5483 am, // current match in a
5484 bm, // current match in b
5485 bs, // string preceding current number in b, if any
5486 i = -1, // index in s
5487 s = [], // string constants and placeholders
5488 q = []; // number interpolators
5490 // Coerce inputs to strings.
5491 a = a + "", b = b + "";
5493 // Interpolate pairs of numbers in a & b.
5494 while ((am = d3_interpolate_numberA.exec(a))
5495 && (bm = d3_interpolate_numberB.exec(b))) {
5496 if ((bs = bm.index) > bi) { // a string precedes the next number in b
5497 bs = b.slice(bi, bs);
5498 if (s[i]) s[i] += bs; // coalesce with previous string
5501 if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
5502 if (s[i]) s[i] += bm; // coalesce with previous string
5504 } else { // interpolate non-matching numbers
5506 q.push({i: i, x: d3_interpolateNumber(am, bm)});
5508 bi = d3_interpolate_numberB.lastIndex;
5511 // Add remains of b.
5512 if (bi < b.length) {
5514 if (s[i]) s[i] += bs; // coalesce with previous string
5518 // Special optimization for only a single match.
5519 // Otherwise, interpolate each of the numbers and rejoin the string.
5521 ? (q[0] ? (b = q[0].x, function(t) { return b(t) + ""; })
5522 : function() { return b; })
5523 : (b = q.length, function(t) {
5524 for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
5529 var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
5530 d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g");
5532 d3.interpolate = d3_interpolate;
5534 function d3_interpolate(a, b) {
5535 var i = d3.interpolators.length, f;
5536 while (--i >= 0 && !(f = d3.interpolators[i](a, b)));
5540 d3.interpolators = [
5543 return (t === "string" ? (d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString)
5544 : b instanceof d3_color ? d3_interpolateRgb
5545 : Array.isArray(b) ? d3_interpolateArray
5546 : t === "object" && isNaN(b) ? d3_interpolateObject
5547 : d3_interpolateNumber)(a, b);
5551 d3.transform = function(string) {
5552 var g = d3_document.createElementNS(d3.ns.prefix.svg, "g");
5553 return (d3.transform = function(string) {
5554 if (string != null) {
5555 g.setAttribute("transform", string);
5556 var t = g.transform.baseVal.consolidate();
5558 return new d3_transform(t ? t.matrix : d3_transformIdentity);
5562 // Compute x-scale and normalize the first row.
5563 // Compute shear and make second row orthogonal to first.
5564 // Compute y-scale and normalize the second row.
5565 // Finally, compute the rotation.
5566 function d3_transform(m) {
5567 var r0 = [m.a, m.b],
5569 kx = d3_transformNormalize(r0),
5570 kz = d3_transformDot(r0, r1),
5571 ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
5572 if (r0[0] * r1[1] < r1[0] * r0[1]) {
5578 this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees;
5579 this.translate = [m.e, m.f];
5580 this.scale = [kx, ky];
5581 this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
5584 d3_transform.prototype.toString = function() {
5585 return "translate(" + this.translate
5586 + ")rotate(" + this.rotate
5587 + ")skewX(" + this.skew
5588 + ")scale(" + this.scale
5592 function d3_transformDot(a, b) {
5593 return a[0] * b[0] + a[1] * b[1];
5596 function d3_transformNormalize(a) {
5597 var k = Math.sqrt(d3_transformDot(a, a));
5605 function d3_transformCombine(a, b, k) {
5611 var d3_transformIdentity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0};
5613 d3.interpolateTransform = d3_interpolateTransform;
5615 function d3_interpolateTransform(a, b) {
5616 var s = [], // string constants and placeholders
5617 q = [], // number interpolators
5619 A = d3.transform(a),
5620 B = d3.transform(b),
5630 if (ta[0] != tb[0] || ta[1] != tb[1]) {
5631 s.push("translate(", null, ",", null, ")");
5632 q.push({i: 1, x: d3_interpolateNumber(ta[0], tb[0])}, {i: 3, x: d3_interpolateNumber(ta[1], tb[1])});
5633 } else if (tb[0] || tb[1]) {
5634 s.push("translate(" + tb + ")");
5640 if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; // shortest path
5641 q.push({i: s.push(s.pop() + "rotate(", null, ")") - 2, x: d3_interpolateNumber(ra, rb)});
5643 s.push(s.pop() + "rotate(" + rb + ")");
5647 q.push({i: s.push(s.pop() + "skewX(", null, ")") - 2, x: d3_interpolateNumber(wa, wb)});
5649 s.push(s.pop() + "skewX(" + wb + ")");
5652 if (ka[0] != kb[0] || ka[1] != kb[1]) {
5653 n = s.push(s.pop() + "scale(", null, ",", null, ")");
5654 q.push({i: n - 4, x: d3_interpolateNumber(ka[0], kb[0])}, {i: n - 2, x: d3_interpolateNumber(ka[1], kb[1])});
5655 } else if (kb[0] != 1 || kb[1] != 1) {
5656 s.push(s.pop() + "scale(" + kb + ")");
5660 return function(t) {
5662 while (++i < n) s[(o = q[i]).i] = o.x(t);
5667 d3_transitionPrototype.tween = function(name, tween) {
5668 var id = this.id, ns = this.namespace;
5669 if (arguments.length < 2) return this.node()[ns][id].tween.get(name);
5670 return d3_selection_each(this, tween == null
5671 ? function(node) { node[ns][id].tween.remove(name); }
5672 : function(node) { node[ns][id].tween.set(name, tween); });
5675 function d3_transition_tween(groups, name, value, tween) {
5676 var id = groups.id, ns = groups.namespace;
5677 return d3_selection_each(groups, typeof value === "function"
5678 ? function(node, i, j) { node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j))); }
5679 : (value = tween(value), function(node) { node[ns][id].tween.set(name, value); }));
5682 d3_transitionPrototype.attr = function(nameNS, value) {
5683 if (arguments.length < 2) {
5685 // For attr(object), the object specifies the names and values of the
5686 // attributes to transition. The values may be functions that are
5687 // evaluated for each element.
5688 for (value in nameNS) this.attr(value, nameNS[value]);
5692 var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate,
5693 name = d3.ns.qualify(nameNS);
5695 // For attr(string, null), remove the attribute with the specified name.
5696 function attrNull() {
5697 this.removeAttribute(name);
5699 function attrNullNS() {
5700 this.removeAttributeNS(name.space, name.local);
5703 // For attr(string, string), set the attribute with the specified name.
5704 function attrTween(b) {
5705 return b == null ? attrNull : (b += "", function() {
5706 var a = this.getAttribute(name), i;
5707 return a !== b && (i = interpolate(a, b), function(t) { this.setAttribute(name, i(t)); });
5710 function attrTweenNS(b) {
5711 return b == null ? attrNullNS : (b += "", function() {
5712 var a = this.getAttributeNS(name.space, name.local), i;
5713 return a !== b && (i = interpolate(a, b), function(t) { this.setAttributeNS(name.space, name.local, i(t)); });
5717 return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween);
5720 d3_transitionPrototype.attrTween = function(nameNS, tween) {
5721 var name = d3.ns.qualify(nameNS);
5723 function attrTween(d, i) {
5724 var f = tween.call(this, d, i, this.getAttribute(name));
5725 return f && function(t) { this.setAttribute(name, f(t)); };
5727 function attrTweenNS(d, i) {
5728 var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
5729 return f && function(t) { this.setAttributeNS(name.space, name.local, f(t)); };
5732 return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
5735 d3_transitionPrototype.style = function(name, value, priority) {
5736 var n = arguments.length;
5739 // For style(object) or style(object, string), the object specifies the
5740 // names and values of the attributes to set or remove. The values may be
5741 // functions that are evaluated for each element. The optional string
5742 // specifies the priority.
5743 if (typeof name !== "string") {
5744 if (n < 2) value = "";
5745 for (priority in name) this.style(priority, name[priority], value);
5749 // For style(string, string) or style(string, function), use the default
5750 // priority. The priority is ignored for style(string, null).
5754 // For style(name, null) or style(name, null, priority), remove the style
5755 // property with the specified name. The priority is ignored.
5756 function styleNull() {
5757 this.style.removeProperty(name);
5760 // For style(name, string) or style(name, string, priority), set the style
5761 // property with the specified name, using the specified priority.
5762 // Otherwise, a name, value and priority are specified, and handled as below.
5763 function styleString(b) {
5764 return b == null ? styleNull : (b += "", function() {
5765 var a = d3_window(this).getComputedStyle(this, null).getPropertyValue(name), i;
5766 return a !== b && (i = d3_interpolate(a, b), function(t) { this.style.setProperty(name, i(t), priority); });
5770 return d3_transition_tween(this, "style." + name, value, styleString);
5773 d3_transitionPrototype.styleTween = function(name, tween, priority) {
5774 if (arguments.length < 3) priority = "";
5776 function styleTween(d, i) {
5777 var f = tween.call(this, d, i, d3_window(this).getComputedStyle(this, null).getPropertyValue(name));
5778 return f && function(t) { this.style.setProperty(name, f(t), priority); };
5781 return this.tween("style." + name, styleTween);
5784 d3_transitionPrototype.text = function(value) {
5785 return d3_transition_tween(this, "text", value, d3_transition_text);
5788 function d3_transition_text(b) {
5789 if (b == null) b = "";
5790 return function() { this.textContent = b; };
5793 d3_transitionPrototype.remove = function() {
5794 var ns = this.namespace;
5795 return this.each("end.transition", function() {
5797 if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this);
5801 var d3_ease_default = function() { return d3_identity; };
5803 var d3_ease = d3.map({
5804 linear: d3_ease_default,
5806 quad: function() { return d3_ease_quad; },
5807 cubic: function() { return d3_ease_cubic; },
5808 sin: function() { return d3_ease_sin; },
5809 exp: function() { return d3_ease_exp; },
5810 circle: function() { return d3_ease_circle; },
5811 elastic: d3_ease_elastic,
5813 bounce: function() { return d3_ease_bounce; }
5816 var d3_ease_mode = d3.map({
5818 "out": d3_ease_reverse,
5819 "in-out": d3_ease_reflect,
5820 "out-in": function(f) { return d3_ease_reflect(d3_ease_reverse(f)); }
5823 d3.ease = function(name) {
5824 var i = name.indexOf("-"),
5825 t = i >= 0 ? name.slice(0, i) : name,
5826 m = i >= 0 ? name.slice(i + 1) : "in";
5827 t = d3_ease.get(t) || d3_ease_default;
5828 m = d3_ease_mode.get(m) || d3_identity;
5829 return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1))));
5832 function d3_ease_clamp(f) {
5833 return function(t) {
5834 return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
5838 function d3_ease_reverse(f) {
5839 return function(t) {
5840 return 1 - f(1 - t);
5844 function d3_ease_reflect(f) {
5845 return function(t) {
5846 return .5 * (t < .5 ? f(2 * t) : (2 - f(2 - 2 * t)));
5850 function d3_ease_quad(t) {
5854 function d3_ease_cubic(t) {
5858 // Optimized clamp(reflect(poly(3))).
5859 function d3_ease_cubicInOut(t) {
5860 if (t <= 0) return 0;
5861 if (t >= 1) return 1;
5862 var t2 = t * t, t3 = t2 * t;
5863 return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
5866 function d3_ease_poly(e) {
5867 return function(t) {
5868 return Math.pow(t, e);
5872 function d3_ease_sin(t) {
5873 return 1 - Math.cos(t * halfπ);
5876 function d3_ease_exp(t) {
5877 return Math.pow(2, 10 * (t - 1));
5880 function d3_ease_circle(t) {
5881 return 1 - Math.sqrt(1 - t * t);
5884 function d3_ease_elastic(a, p) {
5886 if (arguments.length < 2) p = 0.45;
5887 if (arguments.length) s = p / τ * Math.asin(1 / a);
5888 else a = 1, s = p / 4;
5889 return function(t) {
5890 return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p);
5894 function d3_ease_back(s) {
5895 if (!s) s = 1.70158;
5896 return function(t) {
5897 return t * t * ((s + 1) * t - s);
5901 function d3_ease_bounce(t) {
5902 return t < 1 / 2.75 ? 7.5625 * t * t
5903 : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75
5904 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375
5905 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
5908 d3_transitionPrototype.ease = function(value) {
5909 var id = this.id, ns = this.namespace;
5910 if (arguments.length < 1) return this.node()[ns][id].ease;
5911 if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
5912 return d3_selection_each(this, function(node) { node[ns][id].ease = value; });
5915 d3_transitionPrototype.delay = function(value) {
5916 var id = this.id, ns = this.namespace;
5917 if (arguments.length < 1) return this.node()[ns][id].delay;
5918 return d3_selection_each(this, typeof value === "function"
5919 ? function(node, i, j) { node[ns][id].delay = +value.call(node, node.__data__, i, j); }
5920 : (value = +value, function(node) { node[ns][id].delay = value; }));
5923 d3_transitionPrototype.duration = function(value) {
5924 var id = this.id, ns = this.namespace;
5925 if (arguments.length < 1) return this.node()[ns][id].duration;
5926 return d3_selection_each(this, typeof value === "function"
5927 ? function(node, i, j) { node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j)); }
5928 : (value = Math.max(1, value), function(node) { node[ns][id].duration = value; }));
5931 d3_transitionPrototype.each = function(type, listener) {
5932 var id = this.id, ns = this.namespace;
5933 if (arguments.length < 2) {
5934 var inherit = d3_transitionInherit,
5935 inheritId = d3_transitionInheritId;
5937 d3_transitionInheritId = id;
5938 d3_selection_each(this, function(node, i, j) {
5939 d3_transitionInherit = node[ns][id];
5940 type.call(node, node.__data__, i, j);
5943 d3_transitionInherit = inherit;
5944 d3_transitionInheritId = inheritId;
5947 d3_selection_each(this, function(node) {
5948 var transition = node[ns][id];
5949 (transition.event || (transition.event = d3.dispatch("start", "end", "interrupt"))).on(type, listener);
5955 d3_transitionPrototype.transition = function() {
5957 id1 = ++d3_transitionId,
5958 ns = this.namespace,
5965 for (var j = 0, m = this.length; j < m; j++) {
5966 subgroups.push(subgroup = []);
5967 for (var group = this[j], i = 0, n = group.length; i < n; i++) {
5968 if (node = group[i]) {
5969 transition = node[ns][id0];
5970 d3_transitionNode(node, i, ns, id1, {time: transition.time, ease: transition.ease, delay: transition.delay + transition.duration, duration: transition.duration});
5972 subgroup.push(node);
5976 return d3_transition(subgroups, ns, id1);
5979 function d3_transitionNamespace(name) {
5980 return name == null ? "__transition__" : "__transition_" + name + "__";
5983 function d3_transitionNode(node, i, ns, id, inherit) {
5984 var lock = node[ns] || (node[ns] = {active: 0, count: 0}),
5985 transition = lock[id];
5988 var time = inherit.time;
5990 transition = lock[id] = {
5993 delay: inherit.delay,
5994 duration: inherit.duration,
5999 inherit = null; // allow gc
6003 d3.timer(function(elapsed) {
6004 var delay = transition.delay,
6007 timer = d3_timer_active,
6010 timer.t = delay + time;
6011 if (delay <= elapsed) return start(elapsed - delay);
6014 function start(elapsed) {
6015 if (lock.active > id) return stop();
6017 var active = lock[lock.active];
6020 delete lock[lock.active];
6021 active.event && active.event.interrupt.call(node, node.__data__, active.index);
6026 transition.event && transition.event.start.call(node, node.__data__, i);
6028 transition.tween.forEach(function(key, value) {
6029 if (value = value.call(node, node.__data__, i)) {
6030 tweened.push(value);
6034 // Deferred capture to allow tweens to initialize ease & duration.
6035 ease = transition.ease;
6036 duration = transition.duration;
6038 d3.timer(function() { // defer to end of current frame
6039 timer.c = tick(elapsed || 1) ? d3_true : tick;
6044 function tick(elapsed) {
6045 if (lock.active !== id) return 1;
6047 var t = elapsed / duration,
6052 tweened[--n].call(node, e);
6056 transition.event && transition.event.end.call(node, node.__data__, i);
6062 if (--lock.count) delete lock[id];
6063 else delete node[ns];
6070 d3.xhr = d3_xhrType(d3_identity);
6072 function d3_xhrType(response) {
6073 return function(url, mimeType, callback) {
6074 if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, mimeType = null;
6075 return d3_xhr(url, mimeType, response, callback);
6079 function d3_xhr(url, mimeType, response, callback) {
6081 dispatch = d3.dispatch("beforesend", "progress", "load", "error"),
6083 request = new XMLHttpRequest,
6084 responseType = null;
6086 // If IE does not support CORS, use XDomainRequest.
6087 if (this.XDomainRequest
6088 && !("withCredentials" in request)
6089 && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest;
6092 ? request.onload = request.onerror = respond
6093 : request.onreadystatechange = function() { request.readyState > 3 && respond(); };
6095 function respond() {
6096 var status = request.status, result;
6097 if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) {
6099 result = response.call(xhr, request);
6101 dispatch.error.call(xhr, e);
6104 dispatch.load.call(xhr, result);
6106 dispatch.error.call(xhr, request);
6110 request.onprogress = function(event) {
6113 try { dispatch.progress.call(xhr, request); }
6114 finally { d3.event = o; }
6117 xhr.header = function(name, value) {
6118 name = (name + "").toLowerCase();
6119 if (arguments.length < 2) return headers[name];
6120 if (value == null) delete headers[name];
6121 else headers[name] = value + "";
6125 // If mimeType is non-null and no Accept header is set, a default is used.
6126 xhr.mimeType = function(value) {
6127 if (!arguments.length) return mimeType;
6128 mimeType = value == null ? null : value + "";
6132 // Specifies what type the response value should take;
6133 // for instance, arraybuffer, blob, document, or text.
6134 xhr.responseType = function(value) {
6135 if (!arguments.length) return responseType;
6136 responseType = value;
6140 // Specify how to convert the response content to a specific type;
6141 // changes the callback value on "load" events.
6142 xhr.response = function(value) {
6147 // Convenience methods.
6148 ["get", "post"].forEach(function(method) {
6149 xhr[method] = function() {
6150 return xhr.send.apply(xhr, [method].concat(d3_array(arguments)));
6154 // If callback is non-null, it will be used for error and load events.
6155 xhr.send = function(method, data, callback) {
6156 if (arguments.length === 2 && typeof data === "function") callback = data, data = null;
6157 request.open(method, url, true);
6158 if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*";
6159 if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);
6160 if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);
6161 if (responseType != null) request.responseType = responseType;
6162 if (callback != null) xhr.on("error", callback).on("load", function(request) { callback(null, request); });
6163 dispatch.beforesend.call(xhr, request);
6164 request.send(data == null ? null : data);
6168 xhr.abort = function() {
6173 d3.rebind(xhr, dispatch, "on");
6175 return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
6178 function d3_xhr_fixCallback(callback) {
6179 return callback.length === 1
6180 ? function(error, request) { callback(error == null ? request : null); }
6184 function d3_xhrHasResponse(request) {
6185 var type = request.responseType;
6186 return type && type !== "text"
6187 ? request.response // null on error
6188 : request.responseText; // "" on error
6191 d3.text = d3_xhrType(function(request) {
6192 return request.responseText;
6195 d3.json = function(url, callback) {
6196 return d3_xhr(url, "application/json", d3_json, callback);
6199 function d3_json(request) {
6200 return JSON.parse(request.responseText);
6203 d3.html = function(url, callback) {
6204 return d3_xhr(url, "text/html", d3_html, callback);
6207 function d3_html(request) {
6208 var range = d3_document.createRange();
6209 range.selectNode(d3_document.body);
6210 return range.createContextualFragment(request.responseText);
6213 d3.xml = d3_xhrType(function(request) {
6214 return request.responseXML;
6216 if (typeof define === "function" && define.amd) define(d3);
6217 else if (typeof module === "object" && module.exports) module.exports = d3;
6220 d3.combobox = function() {
6221 var event = d3.dispatch('accept'),
6225 caseSensitive = false;
6227 var fetcher = function(val, cb) {
6228 cb(data.filter(function(d) {
6232 .indexOf(val.toLowerCase()) !== -1;
6236 var combobox = function(input, attachTo) {
6238 container = d3.select(document.body)
6239 .selectAll('div.combobox')
6240 .filter(function(d) { return d === input.node(); }),
6241 shown = !container.empty();
6244 .classed('combobox-input', true)
6245 .on('focus.typeahead', focus)
6246 .on('blur.typeahead', blur)
6247 .on('keydown.typeahead', keydown)
6248 .on('keyup.typeahead', keyup)
6249 .on('input.typeahead', change)
6251 var parent = this.parentNode,
6252 sibling = this.nextSibling;
6254 var caret = d3.select(parent).selectAll('.combobox-caret')
6255 .filter(function(d) { return d === input.node(); })
6256 .data([input.node()]);
6258 caret.enter().insert('div', function() { return sibling; })
6259 .attr('class', 'combobox-caret');
6262 .on('mousedown', function () {
6263 // prevent the form element from blurring. it blurs
6265 d3.event.stopPropagation();
6266 d3.event.preventDefault();
6268 input.node().focus();
6277 fetch(value(), render);
6281 window.setTimeout(hide, 150);
6286 container = d3.select(document.body)
6287 .insert('div', ':first-child')
6288 .datum(input.node())
6289 .attr('class', 'combobox')
6291 position: 'absolute',
6295 .on('mousedown', function () {
6296 // prevent moving focus out of the text field
6297 d3.event.preventDefault();
6300 d3.select(document.body)
6301 .on('scroll.combobox', render, true);
6312 d3.select(document.body)
6313 .on('scroll.combobox', null);
6319 function keydown() {
6320 switch (d3.event.keyCode) {
6321 // backspace, delete
6324 input.on('input.typeahead', function() {
6327 var start = input.property('selectionStart');
6328 input.node().setSelectionRange(start, start);
6329 input.on('input.typeahead', change);
6334 container.selectAll('a.selected').each(event.accept);
6338 d3.event.preventDefault();
6343 d3.event.preventDefault();
6348 d3.event.preventDefault();
6351 d3.event.stopPropagation();
6355 switch (d3.event.keyCode) {
6362 container.selectAll('a.selected').each(event.accept);
6369 fetch(value(), function() {
6370 if (input.property('selectionEnd') === input.property('value').length) {
6378 if (!suggestions.length) return;
6379 idx = Math.max(Math.min(idx + dir, suggestions.length - 1), 0);
6380 input.property('value', suggestions[idx].value);
6386 var value = input.property('value'),
6387 start = input.property('selectionStart'),
6388 end = input.property('selectionEnd');
6391 value = value.substring(0, start);
6397 function fetch(v, cb) {
6398 fetcher.call(input, v, function(_) {
6404 function autocomplete() {
6405 var v = caseSensitive ? value() : value().toLowerCase();
6409 for (var i = 0; i < suggestions.length; i++) {
6410 var suggestion = suggestions[i].value,
6411 compare = caseSensitive ? suggestion : suggestion.toLowerCase();
6413 if (compare.indexOf(v) === 0) {
6415 input.property('value', suggestion);
6416 input.node().setSelectionRange(v.length, suggestion.length);
6423 if (suggestions.length >= minItems && document.activeElement === input.node()) {
6430 var options = container
6431 .selectAll('a.combobox-option')
6432 .data(suggestions, function(d) { return d.value; });
6434 options.enter().append('a')
6435 .attr('class', 'combobox-option')
6436 .text(function(d) { return d.value; });
6439 .attr('title', function(d) { return d.title; })
6440 .classed('selected', function(d, i) { return i == idx; })
6441 .on('mouseover', select)
6442 .on('click', accept)
6448 var node = attachTo ? attachTo.node() : input.node(),
6449 rect = node.getBoundingClientRect();
6452 'left': rect.left + 'px',
6453 'width': rect.width + 'px',
6454 'top': rect.height + rect.top + 'px'
6458 function select(d, i) {
6463 function ensureVisible() {
6464 var node = container.selectAll('a.selected').node();
6465 if (node) node.scrollIntoView();
6468 function accept(d) {
6471 .property('value', d.value)
6478 combobox.fetcher = function(_) {
6479 if (!arguments.length) return fetcher;
6484 combobox.data = function(_) {
6485 if (!arguments.length) return data;
6490 combobox.minItems = function(_) {
6491 if (!arguments.length) return minItems;
6496 combobox.caseSensitive = function(_) {
6497 if (!arguments.length) return caseSensitive;
6502 return d3.rebind(combobox, event, 'on');
6505 d3.combobox.off = function(input) {
6510 .on('focus.typeahead', null)
6511 .on('blur.typeahead', null)
6512 .on('keydown.typeahead', null)
6513 .on('keyup.typeahead', null)
6514 .on('input.typeahead', null)
6516 d3.select(this.parentNode).selectAll('.combobox-caret')
6517 .filter(function(d) { return d === input.node(); })
6518 .on('mousedown', null);
6521 d3.select(document.body)
6522 .on('scroll.combobox', null);
6524 d3.geo.tile = function() {
6525 var size = [960, 500],
6527 scaleExtent = [0, 20],
6528 translate = [size[0] / 2, size[1] / 2],
6532 return Math.min(scaleExtent[1], Math.max(scaleExtent[0], _));
6536 var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
6537 z0 = bound(Math.round(z + zoomDelta)),
6538 k = Math.pow(2, z - z0 + 8),
6539 origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
6541 cols = d3.range(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
6542 rows = d3.range(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
6544 rows.forEach(function(y) {
6545 cols.forEach(function(x) {
6546 tiles.push([x, y, z0]);
6550 tiles.translate = origin;
6556 tile.scaleExtent = function(_) {
6557 if (!arguments.length) return scaleExtent;
6562 tile.size = function(_) {
6563 if (!arguments.length) return size;
6568 tile.scale = function(_) {
6569 if (!arguments.length) return scale;
6574 tile.translate = function(_) {
6575 if (!arguments.length) return translate;
6580 tile.zoomDelta = function(_) {
6581 if (!arguments.length) return zoomDelta;
6588 d3.jsonp = function (url, callback) {
6590 var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
6592 while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
6596 function create(url) {
6597 var e = url.match(/callback=d3.jsonp.(\w+)/),
6598 c = e ? e[1] : rand();
6599 d3.jsonp[c] = function(data) {
6604 return 'd3.jsonp.' + c;
6607 var cb = create(url),
6608 script = d3.select('head')
6610 .attr('type', 'text/javascript')
6611 .attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
6614 * This code is licensed under the MIT license.
6616 * Copyright © 2013, iD authors.
6618 * Portions copyright © 2011, Keith Cirkel
6619 * See https://github.com/keithamus/jwerty
6622 d3.keybinding = function(namespace) {
6625 function matches(binding, event) {
6626 for (var p in binding.event) {
6627 if (event[p] != binding.event[p])
6633 function testBindings(isCapturing) {
6634 for (var i = 0; i < bindings.length; i++) {
6635 var binding = bindings[i];
6637 if (!!binding.capture === isCapturing && matches(binding, d3.event)) {
6643 function capture() {
6648 var tagName = d3.select(d3.event.target).node().tagName;
6649 if (tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA') {
6652 testBindings(false);
6655 function keybinding(selection) {
6656 selection = selection || d3.select(document);
6657 selection.on('keydown.capture' + namespace, capture, true);
6658 selection.on('keydown.bubble' + namespace, bubble, false);
6662 keybinding.off = function(selection) {
6664 selection = selection || d3.select(document);
6665 selection.on('keydown.capture' + namespace, null);
6666 selection.on('keydown.bubble' + namespace, null);
6670 keybinding.on = function(code, callback, capture) {
6683 code = code.toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
6685 for (var i = 0; i < code.length; i++) {
6686 // Normalise matching errors
6687 if (code[i] === '++') code[i] = '+';
6689 if (code[i] in d3.keybinding.modifierCodes) {
6690 binding.event[d3.keybinding.modifierProperties[d3.keybinding.modifierCodes[code[i]]]] = true;
6691 } else if (code[i] in d3.keybinding.keyCodes) {
6692 binding.event.keyCode = d3.keybinding.keyCodes[code[i]];
6696 bindings.push(binding);
6705 d3.keybinding.modifierCodes = {
6708 // CTRL key, on Mac: ⌃
6710 // ALT key, on Mac: ⌥ (Alt)
6711 '⌥': 18, alt: 18, option: 18,
6712 // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
6713 '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
6716 d3.keybinding.modifierProperties = {
6723 d3.keybinding.keyCodes = {
6724 // Backspace key, on Mac: ⌫ (Backspace)
6725 '⌫': 8, backspace: 8,
6726 // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
6727 '⇥': 9, '⇆': 9, tab: 9,
6729 '↩': 13, 'return': 13, enter: 13, '⌅': 13,
6731 'pause': 19, 'pause-break': 19,
6733 '⇪': 20, caps: 20, 'caps-lock': 20,
6734 // Escape key, on Mac: ⎋, on Windows: Esc
6735 '⎋': 27, escape: 27, esc: 27,
6738 // Page-Up key, or pgup, on Mac: ↖
6739 '↖': 33, pgup: 33, 'page-up': 33,
6740 // Page-Down key, or pgdown, on Mac: ↘
6741 '↘': 34, pgdown: 34, 'page-down': 34,
6742 // END key, on Mac: ⇟
6744 // HOME key, on Mac: ⇞
6746 // Insert key, or ins
6747 ins: 45, insert: 45,
6748 // Delete key, on Mac: ⌦ (Delete)
6749 '⌦': 46, del: 46, 'delete': 46,
6750 // Left Arrow Key, or ←
6751 '←': 37, left: 37, 'arrow-left': 37,
6752 // Up Arrow Key, or ↑
6753 '↑': 38, up: 38, 'arrow-up': 38,
6754 // Right Arrow Key, or →
6755 '→': 39, right: 39, 'arrow-right': 39,
6756 // Up Arrow Key, or ↓
6757 '↓': 40, down: 40, 'arrow-down': 40,
6758 // odities, printing characters that come out wrong:
6761 // Num-Multiply, or *
6762 '*': 106, star: 106, asterisk: 106, multiply: 106,
6764 '+': 107, 'plus': 107,
6765 // Num-Subtract, or -
6766 '-': 109, subtract: 109,
6772 ';': 186, semicolon: 186,
6774 '=': 187, 'equals': 187,
6776 ',': 188, comma: 188,
6778 // Period, or ., or full-stop
6779 '.': 190, period: 190, 'full-stop': 190,
6780 // Slash, or /, or forward-slash
6781 '/': 191, slash: 191, 'forward-slash': 191,
6782 // Tick, or `, or back-quote
6783 '`': 192, tick: 192, 'back-quote': 192,
6784 // Open bracket, or [
6785 '[': 219, 'open-bracket': 219,
6787 '\\': 220, 'back-slash': 220,
6788 // Close backet, or ]
6789 ']': 221, 'close-bracket': 221,
6790 // Apostrophe, or Quote, or '
6791 '\'': 222, quote: 222, apostrophe: 222
6797 d3.keybinding.keyCodes['num-' + n] = i;
6804 d3.keybinding.keyCodes[n] = i;
6811 d3.keybinding.keyCodes['f' + n] = i;
6818 d3.keybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i;
6821 d3.selection.prototype.one = function (type, listener, capture) {
6822 var target = this, typeOnce = type + ".once";
6824 target.on(typeOnce, null);
6825 listener.apply(this, arguments);
6827 target.on(typeOnce, one, capture);
6830 d3.selection.prototype.dimensions = function (dimensions) {
6831 var refresh = (function(node) {
6832 var cr = node.getBoundingClientRect();
6833 prop = [cr.width, cr.height];
6834 this.property('__dimensions__', prop);
6838 var node = this.node();
6840 if (!arguments.length) {
6841 if (!node) return [0,0];
6842 return this.property('__dimensions__') || refresh(node);
6844 if (dimensions === null) {
6845 if (!node) return [0,0];
6846 return refresh(node);
6850 .property('__dimensions__', [dimensions[0], dimensions[1]])
6851 .attr({width: dimensions[0], height: dimensions[1]});
6853 d3.selection.prototype.trigger = function (type) {
6854 this.each(function() {
6855 var evt = document.createEvent('HTMLEvents');
6856 evt.initEvent(type, true, true);
6857 this.dispatchEvent(evt);
6860 // Tooltips and svg mask used to highlight certain features
6861 d3.curtain = function() {
6863 var event = d3.dispatch(),
6868 function curtain(selection) {
6870 surface = selection.append('svg')
6871 .attr('id', 'curtain')
6874 'pointer-events': 'none',
6875 'position': 'absolute',
6880 darkness = surface.append('path')
6884 'class': 'curtain-darkness'
6887 d3.select(window).on('resize.curtain', resize);
6889 tooltip = selection.append('div')
6890 .attr('class', 'tooltip')
6891 .style('z-index', 1002);
6893 tooltip.append('div').attr('class', 'tooltip-arrow');
6894 tooltip.append('div').attr('class', 'tooltip-inner');
6900 width: window.innerWidth,
6901 height: window.innerHeight
6903 curtain.cut(darkness.datum());
6907 curtain.reveal = function(box, text, tooltipclass, duration) {
6908 if (typeof box === 'string') box = d3.select(box).node();
6909 if (box.getBoundingClientRect) box = box.getBoundingClientRect();
6911 curtain.cut(box, duration);
6914 // pseudo markdown bold text hack
6915 var parts = text.split('**');
6916 var html = parts[0] ? '<span>' + parts[0] + '</span>' : '';
6917 if (parts[1]) html += '<span class="bold">' + parts[1] + '</span>';
6919 var dimensions = tooltip.classed('in', true)
6920 .select('.tooltip-inner')
6926 var w = window.innerWidth,
6927 h = window.innerHeight;
6929 if (box.top + box.height < Math.min(100, box.width + box.left)) {
6931 pos = [box.left + box.width / 2 - dimensions[0]/ 2, box.top + box.height];
6933 } else if (box.left + box.width + 300 < window.innerWidth) {
6935 pos = [box.left + box.width, box.top + box.height / 2 - dimensions[1] / 2];
6937 } else if (box.left > 300) {
6939 pos = [box.left - 200, box.top + box.height / 2 - dimensions[1] / 2];
6942 pos = [box.left, box.top + box.height];
6946 Math.min(Math.max(10, pos[0]), w - dimensions[0] - 10),
6947 Math.min(Math.max(10, pos[1]), h - dimensions[1] - 10)
6951 if (duration !== 0 || !tooltip.classed(side)) tooltip.call(iD.ui.Toggle(true));
6954 .style('top', pos[1] + 'px')
6955 .style('left', pos[0] + 'px')
6956 .attr('class', 'curtain-tooltip tooltip in ' + side + ' ' + tooltipclass)
6957 .select('.tooltip-inner')
6961 tooltip.call(iD.ui.Toggle(false));
6965 curtain.cut = function(datum, duration) {
6966 darkness.datum(datum);
6968 (duration === 0 ? darkness : darkness.transition().duration(duration || 600))
6969 .attr('d', function(d) {
6970 var string = "M 0,0 L 0," + window.innerHeight + " L " +
6971 window.innerWidth + "," + window.innerHeight + "L" +
6972 window.innerWidth + ",0 Z";
6974 if (!d) return string;
6975 return string + 'M' +
6976 d.left + ',' + d.top + 'L' +
6977 d.left + ',' + (d.top + d.height) + 'L' +
6978 (d.left + d.width) + ',' + (d.top + d.height) + 'L' +
6979 (d.left + d.width) + ',' + (d.top) + 'Z';
6984 curtain.remove = function() {
6989 return d3.rebind(curtain, event, 'on');
6991 // Like selection.property('value', ...), but avoids no-op value sets,
6992 // which can result in layout/repaint thrashing in some situations.
6993 d3.selection.prototype.value = function(value) {
6994 function d3_selection_value(value) {
6995 function valueNull() {
6999 function valueConstant() {
7000 if (this.value !== value) this.value = value;
7003 function valueFunction() {
7004 var x = value.apply(this, arguments);
7005 if (x == null) delete this.value;
7006 else if (this.value !== x) this.value = x;
7009 return value == null
7010 ? valueNull : (typeof value === "function"
7011 ? valueFunction : valueConstant);
7014 if (!arguments.length) return this.property('value');
7015 return this.each(d3_selection_value(value));
7017 // Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
7018 // Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
7020 // Permission is hereby granted, free of charge, to any person
7021 // obtaining a copy of this software and associated documentation files
7022 // (the "Software"), to deal in the Software without restriction,
7023 // including without limitation the rights to use, copy, modify, merge,
7024 // publish, distribute, sublicense, and/or sell copies of the Software,
7025 // and to permit persons to whom the Software is furnished to do so,
7026 // subject to the following conditions:
7028 // The above copyright notice and this permission notice shall be
7029 // included in all copies or substantial portions of the Software.
7031 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
7032 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
7033 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
7034 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
7035 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
7036 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
7037 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
7040 // source: https://bitbucket.org/lshift/synchrotron/src
7042 Diff3 = (function() {
7046 longest_common_subsequence: function(file1, file2) {
7047 /* Text diff algorithm following Hunt and McIlroy 1976.
7048 * J. W. Hunt and M. D. McIlroy, An algorithm for differential file
7049 * comparison, Bell Telephone Laboratories CSTR #41 (1976)
7050 * http://www.cs.dartmouth.edu/~doug/
7052 * Expects two arrays of strings.
7054 var equivalenceClasses;
7059 var c, i, j, jX, r, s;
7061 equivalenceClasses = {};
7062 for (j = 0; j < file2.length; j++) {
7064 if (equivalenceClasses[line]) {
7065 equivalenceClasses[line].push(j);
7067 equivalenceClasses[line] = [j];
7071 candidates = [{file1index: -1,
7075 for (i = 0; i < file1.length; i++) {
7077 file2indices = equivalenceClasses[line] || [];
7082 for (jX = 0; jX < file2indices.length; jX++) {
7083 j = file2indices[jX];
7085 for (s = 0; s < candidates.length; s++) {
7086 if ((candidates[s].file2index < j) &&
7087 ((s == candidates.length - 1) ||
7088 (candidates[s + 1].file2index > j)))
7092 if (s < candidates.length) {
7093 newCandidate = {file1index: i,
7095 chain: candidates[s]};
7096 if (r == candidates.length) {
7103 if (r == candidates.length) {
7104 break; // no point in examining further (j)s
7112 // At this point, we know the LCS: it's in the reverse of the
7113 // linked-list through .chain of
7114 // candidates[candidates.length - 1].
7116 return candidates[candidates.length - 1];
7119 diff_comm: function(file1, file2) {
7120 // We apply the LCS to build a "comm"-style picture of the
7121 // differences between file1 and file2.
7124 var tail1 = file1.length;
7125 var tail2 = file2.length;
7126 var common = {common: []};
7128 function processCommon() {
7129 if (common.common.length) {
7130 common.common.reverse();
7131 result.push(common);
7132 common = {common: []};
7136 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7138 candidate = candidate.chain)
7140 var different = {file1: [], file2: []};
7142 while (--tail1 > candidate.file1index) {
7143 different.file1.push(file1[tail1]);
7146 while (--tail2 > candidate.file2index) {
7147 different.file2.push(file2[tail2]);
7150 if (different.file1.length || different.file2.length) {
7152 different.file1.reverse();
7153 different.file2.reverse();
7154 result.push(different);
7158 common.common.push(file1[tail1]);
7168 diff_patch: function(file1, file2) {
7169 // We apply the LCD to build a JSON representation of a
7170 // diff(1)-style patch.
7173 var tail1 = file1.length;
7174 var tail2 = file2.length;
7176 function chunkDescription(file, offset, length) {
7178 for (var i = 0; i < length; i++) {
7179 chunk.push(file[offset + i]);
7181 return {offset: offset,
7186 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7188 candidate = candidate.chain)
7190 var mismatchLength1 = tail1 - candidate.file1index - 1;
7191 var mismatchLength2 = tail2 - candidate.file2index - 1;
7192 tail1 = candidate.file1index;
7193 tail2 = candidate.file2index;
7195 if (mismatchLength1 || mismatchLength2) {
7196 result.push({file1: chunkDescription(file1,
7197 candidate.file1index + 1,
7199 file2: chunkDescription(file2,
7200 candidate.file2index + 1,
7209 strip_patch: function(patch) {
7210 // Takes the output of Diff3.diff_patch(), and removes
7211 // information from it. It can still be used by patch(),
7212 // below, but can no longer be inverted.
7214 for (var i = 0; i < patch.length; i++) {
7215 var chunk = patch[i];
7216 newpatch.push({file1: {offset: chunk.file1.offset,
7217 length: chunk.file1.length},
7218 file2: {chunk: chunk.file2.chunk}});
7223 invert_patch: function(patch) {
7224 // Takes the output of Diff3.diff_patch(), and inverts the
7225 // sense of it, so that it can be applied to file2 to give
7226 // file1 rather than the other way around.
7228 for (var i = 0; i < patch.length; i++) {
7229 var chunk = patch[i];
7230 var tmp = chunk.file1;
7231 chunk.file1 = chunk.file2;
7236 patch: function (file, patch) {
7237 // Applies a patch to a file.
7239 // Given file1 and file2, Diff3.patch(file1,
7240 // Diff3.diff_patch(file1, file2)) should give file2.
7243 var commonOffset = 0;
7245 function copyCommon(targetOffset) {
7246 while (commonOffset < targetOffset) {
7247 result.push(file[commonOffset]);
7252 for (var chunkIndex = 0; chunkIndex < patch.length; chunkIndex++) {
7253 var chunk = patch[chunkIndex];
7254 copyCommon(chunk.file1.offset);
7255 for (var lineIndex = 0; lineIndex < chunk.file2.chunk.length; lineIndex++) {
7256 result.push(chunk.file2.chunk[lineIndex]);
7258 commonOffset += chunk.file1.length;
7261 copyCommon(file.length);
7265 diff_indices: function(file1, file2) {
7266 // We apply the LCS to give a simple representation of the
7267 // offsets and lengths of mismatched chunks in the input
7268 // files. This is used by diff3_merge_indices below.
7271 var tail1 = file1.length;
7272 var tail2 = file2.length;
7274 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7276 candidate = candidate.chain)
7278 var mismatchLength1 = tail1 - candidate.file1index - 1;
7279 var mismatchLength2 = tail2 - candidate.file2index - 1;
7280 tail1 = candidate.file1index;
7281 tail2 = candidate.file2index;
7283 if (mismatchLength1 || mismatchLength2) {
7284 result.push({file1: [tail1 + 1, mismatchLength1],
7285 file2: [tail2 + 1, mismatchLength2]});
7293 diff3_merge_indices: function (a, o, b) {
7294 // Given three files, A, O, and B, where both A and B are
7295 // independently derived from O, returns a fairly complicated
7296 // internal representation of merge decisions it's taken. The
7297 // interested reader may wish to consult
7299 // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
7300 // Formal Investigation of Diff3." In Arvind and Prasad,
7301 // editors, Foundations of Software Technology and Theoretical
7302 // Computer Science (FSTTCS), December 2007.
7304 // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
7307 var m1 = Diff3.diff_indices(o, a);
7308 var m2 = Diff3.diff_indices(o, b);
7311 function addHunk(h, side) {
7312 hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]);
7314 for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); }
7315 for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); }
7319 var commonOffset = 0;
7320 function copyCommon(targetOffset) {
7321 if (targetOffset > commonOffset) {
7322 result.push([1, commonOffset, targetOffset - commonOffset]);
7323 commonOffset = targetOffset;
7327 for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {
7328 var firstHunkIndex = hunkIndex;
7329 var hunk = hunks[hunkIndex];
7330 var regionLhs = hunk[0];
7331 var regionRhs = regionLhs + hunk[2];
7332 while (hunkIndex < hunks.length - 1) {
7333 var maybeOverlapping = hunks[hunkIndex + 1];
7334 var maybeLhs = maybeOverlapping[0];
7335 if (maybeLhs > regionRhs) break;
7336 regionRhs = maybeLhs + maybeOverlapping[2];
7340 copyCommon(regionLhs);
7341 if (firstHunkIndex == hunkIndex) {
7342 // The "overlap" was only one hunk long, meaning that
7343 // there's no conflict here. Either a and o were the
7344 // same, or b and o were the same.
7346 result.push([hunk[1], hunk[3], hunk[4]]);
7349 // A proper conflict. Determine the extents of the
7350 // regions involved from a, o and b. Effectively merge
7351 // all the hunks on the left into one giant hunk, and
7352 // do the same for the right; then, correct for skew
7353 // in the regions of o that each side changed, and
7354 // report appropriate spans for the three sides.
7356 0: [a.length, -1, o.length, -1],
7357 2: [b.length, -1, o.length, -1]
7359 for (i = firstHunkIndex; i <= hunkIndex; i++) {
7362 var r = regions[side];
7364 var oRhs = oLhs + hunk[2];
7365 var abLhs = hunk[3];
7366 var abRhs = abLhs + hunk[4];
7367 r[0] = Math.min(abLhs, r[0]);
7368 r[1] = Math.max(abRhs, r[1]);
7369 r[2] = Math.min(oLhs, r[2]);
7370 r[3] = Math.max(oRhs, r[3]);
7372 var aLhs = regions[0][0] + (regionLhs - regions[0][2]);
7373 var aRhs = regions[0][1] + (regionRhs - regions[0][3]);
7374 var bLhs = regions[2][0] + (regionLhs - regions[2][2]);
7375 var bRhs = regions[2][1] + (regionRhs - regions[2][3]);
7378 regionLhs, regionRhs - regionLhs,
7379 bLhs, bRhs - bLhs]);
7381 commonOffset = regionRhs;
7384 copyCommon(o.length);
7388 diff3_merge: function (a, o, b, excludeFalseConflicts) {
7389 // Applies the output of Diff3.diff3_merge_indices to actually
7390 // construct the merged file; the returned result alternates
7391 // between "ok" and "conflict" blocks.
7394 var files = [a, o, b];
7395 var indices = Diff3.diff3_merge_indices(a, o, b);
7398 function flushOk() {
7399 if (okLines.length) {
7400 result.push({ok: okLines});
7404 function pushOk(xs) {
7405 for (var j = 0; j < xs.length; j++) {
7406 okLines.push(xs[j]);
7410 function isTrueConflict(rec) {
7411 if (rec[2] != rec[6]) return true;
7414 for (var j = 0; j < rec[2]; j++) {
7415 if (a[j + aoff] != b[j + boff]) return true;
7420 for (var i = 0; i < indices.length; i++) {
7424 if (excludeFalseConflicts && !isTrueConflict(x)) {
7425 pushOk(files[0].slice(x[1], x[1] + x[2]));
7428 result.push({conflict: {a: a.slice(x[1], x[1] + x[2]),
7430 o: o.slice(x[3], x[3] + x[4]),
7432 b: b.slice(x[5], x[5] + x[6]),
7436 pushOk(files[side].slice(x[1], x[1] + x[2]));
7447 if (typeof module !== 'undefined') module.exports = Diff3;
7448 var JXON = new (function () {
7450 sValueProp = "keyValue", sAttributesProp = "keyAttributes", sAttrPref = "@", /* you can customize these values */
7451 aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
7453 function parseText (sValue) {
7454 if (rIsNull.test(sValue)) { return null; }
7455 if (rIsBool.test(sValue)) { return sValue.toLowerCase() === "true"; }
7456 if (isFinite(sValue)) { return parseFloat(sValue); }
7457 if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
7461 function EmptyTree () { }
7462 EmptyTree.prototype.toString = function () { return "null"; };
7463 EmptyTree.prototype.valueOf = function () { return null; };
7465 function objectify (vValue) {
7466 return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
7469 function createObjTree (oParentNode, nVerb, bFreeze, bNesteAttr) {
7471 nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(),
7472 bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
7475 sProp, vContent, nLength = 0, sCollectedTxt = "",
7476 vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
7479 for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
7480 oNode = oParentNode.childNodes.item(nItem);
7481 if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is "CDATASection" (4) */
7482 else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is "Text" (3) */
7483 else if (oNode.nodeType === 1 && !oNode.prefix) { aCache.push(oNode); } /* nodeType is "Element" (1) */
7487 var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
7489 if (!bHighVerb && (bChildren || bAttributes)) { vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; }
7491 for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
7492 sProp = aCache[nElId].nodeName.toLowerCase();
7493 vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
7494 if (vResult.hasOwnProperty(sProp)) {
7495 if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; }
7496 vResult[sProp].push(vContent);
7498 vResult[sProp] = vContent;
7505 nAttrLen = oParentNode.attributes.length,
7506 sAPrefix = bNesteAttr ? "" : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
7508 for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
7509 oAttrib = oParentNode.attributes.item(nAttrib);
7510 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
7514 if (bFreeze) { Object.freeze(oAttrParent); }
7515 vResult[sAttributesProp] = oAttrParent;
7516 nLength -= nAttrLen - 1;
7520 if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
7521 vResult[sValueProp] = vBuiltVal;
7522 } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
7523 vResult = vBuiltVal;
7526 if (bFreeze && (bHighVerb || nLength > 0)) { Object.freeze(vResult); }
7528 aCache.length = nLevelStart;
7533 function loadObjTree (oXMLDoc, oParentEl, oParentObj) {
7536 if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
7537 oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
7538 } else if (oParentObj.constructor === Date) {
7539 oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
7542 for (var sName in oParentObj) {
7543 vValue = oParentObj[sName];
7544 if (isFinite(sName) || vValue instanceof Function) { continue; } /* verbosity level is 0 */
7545 if (sName === sValueProp) {
7546 if (vValue !== null && vValue !== true) { oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); }
7547 } else if (sName === sAttributesProp) { /* verbosity level is 3 */
7548 for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); }
7549 } else if (sName.charAt(0) === sAttrPref) {
7550 oParentEl.setAttribute(sName.slice(1), vValue);
7551 } else if (vValue.constructor === Array) {
7552 for (var nItem = 0; nItem < vValue.length; nItem++) {
7553 oChild = oXMLDoc.createElement(sName);
7554 loadObjTree(oXMLDoc, oChild, vValue[nItem]);
7555 oParentEl.appendChild(oChild);
7558 oChild = oXMLDoc.createElement(sName);
7559 if (vValue instanceof Object) {
7560 loadObjTree(oXMLDoc, oChild, vValue);
7561 } else if (vValue !== null && vValue !== true) {
7562 oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
7564 oParentEl.appendChild(oChild);
7569 this.build = function (oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
7570 var _nVerb = arguments.length > 1 && typeof nVerbosity === "number" ? nVerbosity & 3 : /* put here the default verbosity level: */ 1;
7571 return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
7574 this.unbuild = function (oObjTree) {
7575 var oNewDoc = document.implementation.createDocument("", "", null);
7576 loadObjTree(oNewDoc, oNewDoc, oObjTree);
7580 this.stringify = function (oObjTree) {
7581 return (new XMLSerializer()).serializeToString(JXON.unbuild(oObjTree));
7584 // var myObject = JXON.build(doc);
7585 // we got our javascript object! try: alert(JSON.stringify(myObject));
7587 // var newDoc = JXON.unbuild(myObject);
7588 // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
7591 * lodash (Custom Build) <https://lodash.com/>
7592 * Build: `lodash --development --output js/lib/lodash.js include="includes,toPairs,assign,bind,chunk,clone,compact,debounce,difference,each,every,extend,filter,find,first,forEach,forOwn,groupBy,indexOf,intersection,isEmpty,isEqual,isFunction,keys,last,map,omit,reject,some,throttle,union,uniq,values,without,flatten,value,chain,cloneDeep,merge,pick,reduce" exports="global,node"`
7593 * Copyright jQuery Foundation and other contributors <https://jquery.org/>
7594 * Released under MIT license <https://lodash.com/license>
7595 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
7596 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
7600 /** Used as a safe reference for `undefined` in pre-ES5 environments. */
7603 /** Used as the semantic version number. */
7604 var VERSION = '4.12.0';
7606 /** Used as the size to enable large array optimizations. */
7607 var LARGE_ARRAY_SIZE = 200;
7609 /** Used as the `TypeError` message for "Functions" methods. */
7610 var FUNC_ERROR_TEXT = 'Expected a function';
7612 /** Used to stand-in for `undefined` hash values. */
7613 var HASH_UNDEFINED = '__lodash_hash_undefined__';
7615 /** Used as the internal argument placeholder. */
7616 var PLACEHOLDER = '__lodash_placeholder__';
7618 /** Used to compose bitmasks for wrapper metadata. */
7621 CURRY_BOUND_FLAG = 4,
7623 CURRY_RIGHT_FLAG = 16,
7625 PARTIAL_RIGHT_FLAG = 64,
7630 /** Used to compose bitmasks for comparison styles. */
7631 var UNORDERED_COMPARE_FLAG = 1,
7632 PARTIAL_COMPARE_FLAG = 2;
7634 /** Used to detect hot functions by number of calls within a span of milliseconds. */
7635 var HOT_COUNT = 150,
7638 /** Used to indicate the type of lazy iteratees. */
7639 var LAZY_FILTER_FLAG = 1,
7641 LAZY_WHILE_FLAG = 3;
7643 /** Used as references for various `Number` constants. */
7644 var INFINITY = 1 / 0,
7645 MAX_SAFE_INTEGER = 9007199254740991,
7646 MAX_INTEGER = 1.7976931348623157e+308,
7649 /** Used as references for the maximum length and index of an array. */
7650 var MAX_ARRAY_LENGTH = 4294967295;
7652 /** `Object#toString` result references. */
7653 var argsTag = '[object Arguments]',
7654 arrayTag = '[object Array]',
7655 boolTag = '[object Boolean]',
7656 dateTag = '[object Date]',
7657 errorTag = '[object Error]',
7658 funcTag = '[object Function]',
7659 genTag = '[object GeneratorFunction]',
7660 mapTag = '[object Map]',
7661 numberTag = '[object Number]',
7662 objectTag = '[object Object]',
7663 promiseTag = '[object Promise]',
7664 regexpTag = '[object RegExp]',
7665 setTag = '[object Set]',
7666 stringTag = '[object String]',
7667 symbolTag = '[object Symbol]',
7668 weakMapTag = '[object WeakMap]';
7670 var arrayBufferTag = '[object ArrayBuffer]',
7671 dataViewTag = '[object DataView]',
7672 float32Tag = '[object Float32Array]',
7673 float64Tag = '[object Float64Array]',
7674 int8Tag = '[object Int8Array]',
7675 int16Tag = '[object Int16Array]',
7676 int32Tag = '[object Int32Array]',
7677 uint8Tag = '[object Uint8Array]',
7678 uint8ClampedTag = '[object Uint8ClampedArray]',
7679 uint16Tag = '[object Uint16Array]',
7680 uint32Tag = '[object Uint32Array]';
7682 /** Used to match property names within property paths. */
7683 var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
7684 reIsPlainProp = /^\w*$/,
7685 rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]/g;
7688 * Used to match `RegExp`
7689 * [syntax characters](http://ecma-international.org/ecma-262/6.0/#sec-patterns).
7691 var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
7693 /** Used to match leading and trailing whitespace. */
7694 var reTrim = /^\s+|\s+$/g;
7696 /** Used to match backslashes in property paths. */
7697 var reEscapeChar = /\\(\\)?/g;
7699 /** Used to match `RegExp` flags from their coerced string values. */
7700 var reFlags = /\w*$/;
7702 /** Used to detect bad signed hexadecimal string values. */
7703 var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
7705 /** Used to detect binary string values. */
7706 var reIsBinary = /^0b[01]+$/i;
7708 /** Used to detect host constructors (Safari). */
7709 var reIsHostCtor = /^\[object .+?Constructor\]$/;
7711 /** Used to detect octal string values. */
7712 var reIsOctal = /^0o[0-7]+$/i;
7714 /** Used to detect unsigned integer values. */
7715 var reIsUint = /^(?:0|[1-9]\d*)$/;
7717 /** Used to compose unicode character classes. */
7718 var rsAstralRange = '\\ud800-\\udfff',
7719 rsComboMarksRange = '\\u0300-\\u036f\\ufe20-\\ufe23',
7720 rsComboSymbolsRange = '\\u20d0-\\u20f0',
7721 rsVarRange = '\\ufe0e\\ufe0f';
7723 /** Used to compose unicode capture groups. */
7724 var rsAstral = '[' + rsAstralRange + ']',
7725 rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']',
7726 rsFitz = '\\ud83c[\\udffb-\\udfff]',
7727 rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
7728 rsNonAstral = '[^' + rsAstralRange + ']',
7729 rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
7730 rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
7733 /** Used to compose unicode regexes. */
7734 var reOptMod = rsModifier + '?',
7735 rsOptVar = '[' + rsVarRange + ']?',
7736 rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
7737 rsSeq = rsOptVar + reOptMod + rsOptJoin,
7738 rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
7740 /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
7741 var reComplexSymbol = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
7743 /** Used to identify `toStringTag` values of typed arrays. */
7744 var typedArrayTags = {};
7745 typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
7746 typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
7747 typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
7748 typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
7749 typedArrayTags[uint32Tag] = true;
7750 typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
7751 typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
7752 typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
7753 typedArrayTags[errorTag] = typedArrayTags[funcTag] =
7754 typedArrayTags[mapTag] = typedArrayTags[numberTag] =
7755 typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
7756 typedArrayTags[setTag] = typedArrayTags[stringTag] =
7757 typedArrayTags[weakMapTag] = false;
7759 /** Used to identify `toStringTag` values supported by `_.clone`. */
7760 var cloneableTags = {};
7761 cloneableTags[argsTag] = cloneableTags[arrayTag] =
7762 cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
7763 cloneableTags[boolTag] = cloneableTags[dateTag] =
7764 cloneableTags[float32Tag] = cloneableTags[float64Tag] =
7765 cloneableTags[int8Tag] = cloneableTags[int16Tag] =
7766 cloneableTags[int32Tag] = cloneableTags[mapTag] =
7767 cloneableTags[numberTag] = cloneableTags[objectTag] =
7768 cloneableTags[regexpTag] = cloneableTags[setTag] =
7769 cloneableTags[stringTag] = cloneableTags[symbolTag] =
7770 cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
7771 cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
7772 cloneableTags[errorTag] = cloneableTags[funcTag] =
7773 cloneableTags[weakMapTag] = false;
7775 /** Used to determine if values are of the language type `Object`. */
7781 /** Built-in method references without a dependency on `root`. */
7782 var freeParseInt = parseInt;
7784 /** Detect free variable `exports`. */
7785 var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType)
7789 /** Detect free variable `module`. */
7790 var freeModule = (objectTypes[typeof module] && module && !module.nodeType)
7794 /** Detect the popular CommonJS extension `module.exports`. */
7795 var moduleExports = (freeModule && freeModule.exports === freeExports)
7799 /** Detect free variable `global` from Node.js. */
7800 var freeGlobal = checkGlobal(freeExports && freeModule && typeof global == 'object' && global);
7802 /** Detect free variable `self`. */
7803 var freeSelf = checkGlobal(objectTypes[typeof self] && self);
7805 /** Detect free variable `window`. */
7806 var freeWindow = checkGlobal(objectTypes[typeof window] && window);
7808 /** Detect `this` as the global object. */
7809 var thisGlobal = checkGlobal(objectTypes[typeof this] && this);
7812 * Used as a reference to the global object.
7814 * The `this` value is used if it's the global object to avoid Greasemonkey's
7815 * restricted `window` object, otherwise the `window` object is used.
7817 var root = freeGlobal ||
7818 ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) ||
7819 freeSelf || thisGlobal || Function('return this')();
7821 /*--------------------------------------------------------------------------*/
7824 * Adds the key-value `pair` to `map`.
7827 * @param {Object} map The map to modify.
7828 * @param {Array} pair The key-value pair to add.
7829 * @returns {Object} Returns `map`.
7831 function addMapEntry(map, pair) {
7832 // Don't return `Map#set` because it doesn't return the map instance in IE 11.
7833 map.set(pair[0], pair[1]);
7838 * Adds `value` to `set`.
7841 * @param {Object} set The set to modify.
7842 * @param {*} value The value to add.
7843 * @returns {Object} Returns `set`.
7845 function addSetEntry(set, value) {
7851 * A faster alternative to `Function#apply`, this function invokes `func`
7852 * with the `this` binding of `thisArg` and the arguments of `args`.
7855 * @param {Function} func The function to invoke.
7856 * @param {*} thisArg The `this` binding of `func`.
7857 * @param {Array} args The arguments to invoke `func` with.
7858 * @returns {*} Returns the result of `func`.
7860 function apply(func, thisArg, args) {
7861 var length = args.length;
7863 case 0: return func.call(thisArg);
7864 case 1: return func.call(thisArg, args[0]);
7865 case 2: return func.call(thisArg, args[0], args[1]);
7866 case 3: return func.call(thisArg, args[0], args[1], args[2]);
7868 return func.apply(thisArg, args);
7872 * A specialized version of `baseAggregator` for arrays.
7875 * @param {Array} array The array to iterate over.
7876 * @param {Function} setter The function to set `accumulator` values.
7877 * @param {Function} iteratee The iteratee to transform keys.
7878 * @param {Object} accumulator The initial aggregated object.
7879 * @returns {Function} Returns `accumulator`.
7881 function arrayAggregator(array, setter, iteratee, accumulator) {
7883 length = array.length;
7885 while (++index < length) {
7886 var value = array[index];
7887 setter(accumulator, value, iteratee(value), array);
7893 * A specialized version of `_.forEach` for arrays without support for
7894 * iteratee shorthands.
7897 * @param {Array} array The array to iterate over.
7898 * @param {Function} iteratee The function invoked per iteration.
7899 * @returns {Array} Returns `array`.
7901 function arrayEach(array, iteratee) {
7903 length = array.length;
7905 while (++index < length) {
7906 if (iteratee(array[index], index, array) === false) {
7914 * A specialized version of `_.every` for arrays without support for
7915 * iteratee shorthands.
7918 * @param {Array} array The array to iterate over.
7919 * @param {Function} predicate The function invoked per iteration.
7920 * @returns {boolean} Returns `true` if all elements pass the predicate check,
7923 function arrayEvery(array, predicate) {
7925 length = array.length;
7927 while (++index < length) {
7928 if (!predicate(array[index], index, array)) {
7936 * A specialized version of `_.filter` for arrays without support for
7937 * iteratee shorthands.
7940 * @param {Array} array The array to iterate over.
7941 * @param {Function} predicate The function invoked per iteration.
7942 * @returns {Array} Returns the new filtered array.
7944 function arrayFilter(array, predicate) {
7946 length = array.length,
7950 while (++index < length) {
7951 var value = array[index];
7952 if (predicate(value, index, array)) {
7953 result[resIndex++] = value;
7960 * A specialized version of `_.includes` for arrays without support for
7961 * specifying an index to search from.
7964 * @param {Array} array The array to search.
7965 * @param {*} target The value to search for.
7966 * @returns {boolean} Returns `true` if `target` is found, else `false`.
7968 function arrayIncludes(array, value) {
7969 return !!array.length && baseIndexOf(array, value, 0) > -1;
7973 * This function is like `arrayIncludes` except that it accepts a comparator.
7976 * @param {Array} array The array to search.
7977 * @param {*} target The value to search for.
7978 * @param {Function} comparator The comparator invoked per element.
7979 * @returns {boolean} Returns `true` if `target` is found, else `false`.
7981 function arrayIncludesWith(array, value, comparator) {
7983 length = array.length;
7985 while (++index < length) {
7986 if (comparator(value, array[index])) {
7994 * A specialized version of `_.map` for arrays without support for iteratee
7998 * @param {Array} array The array to iterate over.
7999 * @param {Function} iteratee The function invoked per iteration.
8000 * @returns {Array} Returns the new mapped array.
8002 function arrayMap(array, iteratee) {
8004 length = array.length,
8005 result = Array(length);
8007 while (++index < length) {
8008 result[index] = iteratee(array[index], index, array);
8014 * Appends the elements of `values` to `array`.
8017 * @param {Array} array The array to modify.
8018 * @param {Array} values The values to append.
8019 * @returns {Array} Returns `array`.
8021 function arrayPush(array, values) {
8023 length = values.length,
8024 offset = array.length;
8026 while (++index < length) {
8027 array[offset + index] = values[index];
8033 * A specialized version of `_.reduce` for arrays without support for
8034 * iteratee shorthands.
8037 * @param {Array} array The array to iterate over.
8038 * @param {Function} iteratee The function invoked per iteration.
8039 * @param {*} [accumulator] The initial value.
8040 * @param {boolean} [initAccum] Specify using the first element of `array` as
8041 * the initial value.
8042 * @returns {*} Returns the accumulated value.
8044 function arrayReduce(array, iteratee, accumulator, initAccum) {
8046 length = array.length;
8048 if (initAccum && length) {
8049 accumulator = array[++index];
8051 while (++index < length) {
8052 accumulator = iteratee(accumulator, array[index], index, array);
8058 * A specialized version of `_.some` for arrays without support for iteratee
8062 * @param {Array} array The array to iterate over.
8063 * @param {Function} predicate The function invoked per iteration.
8064 * @returns {boolean} Returns `true` if any element passes the predicate check,
8067 function arraySome(array, predicate) {
8069 length = array.length;
8071 while (++index < length) {
8072 if (predicate(array[index], index, array)) {
8080 * The base implementation of methods like `_.find` and `_.findKey`, without
8081 * support for iteratee shorthands, which iterates over `collection` using
8085 * @param {Array|Object} collection The collection to search.
8086 * @param {Function} predicate The function invoked per iteration.
8087 * @param {Function} eachFunc The function to iterate over `collection`.
8088 * @param {boolean} [retKey] Specify returning the key of the found element
8089 * instead of the element itself.
8090 * @returns {*} Returns the found element or its key, else `undefined`.
8092 function baseFind(collection, predicate, eachFunc, retKey) {
8094 eachFunc(collection, function(value, key, collection) {
8095 if (predicate(value, key, collection)) {
8096 result = retKey ? key : value;
8104 * The base implementation of `_.findIndex` and `_.findLastIndex` without
8105 * support for iteratee shorthands.
8108 * @param {Array} array The array to search.
8109 * @param {Function} predicate The function invoked per iteration.
8110 * @param {boolean} [fromRight] Specify iterating from right to left.
8111 * @returns {number} Returns the index of the matched value, else `-1`.
8113 function baseFindIndex(array, predicate, fromRight) {
8114 var length = array.length,
8115 index = fromRight ? length : -1;
8117 while ((fromRight ? index-- : ++index < length)) {
8118 if (predicate(array[index], index, array)) {
8126 * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
8129 * @param {Array} array The array to search.
8130 * @param {*} value The value to search for.
8131 * @param {number} fromIndex The index to search from.
8132 * @returns {number} Returns the index of the matched value, else `-1`.
8134 function baseIndexOf(array, value, fromIndex) {
8135 if (value !== value) {
8136 return indexOfNaN(array, fromIndex);
8138 var index = fromIndex - 1,
8139 length = array.length;
8141 while (++index < length) {
8142 if (array[index] === value) {
8150 * The base implementation of `_.reduce` and `_.reduceRight`, without support
8151 * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
8154 * @param {Array|Object} collection The collection to iterate over.
8155 * @param {Function} iteratee The function invoked per iteration.
8156 * @param {*} accumulator The initial value.
8157 * @param {boolean} initAccum Specify using the first or last element of
8158 * `collection` as the initial value.
8159 * @param {Function} eachFunc The function to iterate over `collection`.
8160 * @returns {*} Returns the accumulated value.
8162 function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
8163 eachFunc(collection, function(value, index, collection) {
8164 accumulator = initAccum
8165 ? (initAccum = false, value)
8166 : iteratee(accumulator, value, index, collection);
8172 * The base implementation of `_.times` without support for iteratee shorthands
8173 * or max array length checks.
8176 * @param {number} n The number of times to invoke `iteratee`.
8177 * @param {Function} iteratee The function invoked per iteration.
8178 * @returns {Array} Returns the array of results.
8180 function baseTimes(n, iteratee) {
8184 while (++index < n) {
8185 result[index] = iteratee(index);
8191 * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
8192 * of key-value pairs for `object` corresponding to the property names of `props`.
8195 * @param {Object} object The object to query.
8196 * @param {Array} props The property names to get values for.
8197 * @returns {Object} Returns the key-value pairs.
8199 function baseToPairs(object, props) {
8200 return arrayMap(props, function(key) {
8201 return [key, object[key]];
8206 * The base implementation of `_.unary` without support for storing wrapper metadata.
8209 * @param {Function} func The function to cap arguments for.
8210 * @returns {Function} Returns the new capped function.
8212 function baseUnary(func) {
8213 return function(value) {
8219 * The base implementation of `_.values` and `_.valuesIn` which creates an
8220 * array of `object` property values corresponding to the property names
8224 * @param {Object} object The object to query.
8225 * @param {Array} props The property names to get values for.
8226 * @returns {Object} Returns the array of property values.
8228 function baseValues(object, props) {
8229 return arrayMap(props, function(key) {
8235 * Checks if a cache value for `key` exists.
8238 * @param {Object} cache The cache to query.
8239 * @param {string} key The key of the entry to check.
8240 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
8242 function cacheHas(cache, key) {
8243 return cache.has(key);
8247 * Checks if `value` is a global object.
8250 * @param {*} value The value to check.
8251 * @returns {null|Object} Returns `value` if it's a global object, else `null`.
8253 function checkGlobal(value) {
8254 return (value && value.Object === Object) ? value : null;
8258 * Gets the number of `placeholder` occurrences in `array`.
8261 * @param {Array} array The array to inspect.
8262 * @param {*} placeholder The placeholder to search for.
8263 * @returns {number} Returns the placeholder count.
8265 function countHolders(array, placeholder) {
8266 var length = array.length,
8270 if (array[length] === placeholder) {
8278 * Gets the index at which the first occurrence of `NaN` is found in `array`.
8281 * @param {Array} array The array to search.
8282 * @param {number} fromIndex The index to search from.
8283 * @param {boolean} [fromRight] Specify iterating from right to left.
8284 * @returns {number} Returns the index of the matched `NaN`, else `-1`.
8286 function indexOfNaN(array, fromIndex, fromRight) {
8287 var length = array.length,
8288 index = fromIndex + (fromRight ? 0 : -1);
8290 while ((fromRight ? index-- : ++index < length)) {
8291 var other = array[index];
8292 if (other !== other) {
8300 * Checks if `value` is a host object in IE < 9.
8303 * @param {*} value The value to check.
8304 * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
8306 function isHostObject(value) {
8307 // Many host objects are `Object` objects that can coerce to strings
8308 // despite having improperly defined `toString` methods.
8310 if (value != null && typeof value.toString != 'function') {
8312 result = !!(value + '');
8319 * Converts `iterator` to an array.
8322 * @param {Object} iterator The iterator to convert.
8323 * @returns {Array} Returns the converted array.
8325 function iteratorToArray(iterator) {
8329 while (!(data = iterator.next()).done) {
8330 result.push(data.value);
8336 * Converts `map` to its key-value pairs.
8339 * @param {Object} map The map to convert.
8340 * @returns {Array} Returns the key-value pairs.
8342 function mapToArray(map) {
8344 result = Array(map.size);
8346 map.forEach(function(value, key) {
8347 result[++index] = [key, value];
8353 * Replaces all `placeholder` elements in `array` with an internal placeholder
8354 * and returns an array of their indexes.
8357 * @param {Array} array The array to modify.
8358 * @param {*} placeholder The placeholder to replace.
8359 * @returns {Array} Returns the new array of placeholder indexes.
8361 function replaceHolders(array, placeholder) {
8363 length = array.length,
8367 while (++index < length) {
8368 var value = array[index];
8369 if (value === placeholder || value === PLACEHOLDER) {
8370 array[index] = PLACEHOLDER;
8371 result[resIndex++] = index;
8378 * Converts `set` to an array of its values.
8381 * @param {Object} set The set to convert.
8382 * @returns {Array} Returns the values.
8384 function setToArray(set) {
8386 result = Array(set.size);
8388 set.forEach(function(value) {
8389 result[++index] = value;
8395 * Converts `set` to its value-value pairs.
8398 * @param {Object} set The set to convert.
8399 * @returns {Array} Returns the value-value pairs.
8401 function setToPairs(set) {
8403 result = Array(set.size);
8405 set.forEach(function(value) {
8406 result[++index] = [value, value];
8412 * Converts `string` to an array.
8415 * @param {string} string The string to convert.
8416 * @returns {Array} Returns the converted array.
8418 function stringToArray(string) {
8419 return string.match(reComplexSymbol);
8422 /*--------------------------------------------------------------------------*/
8424 /** Used for built-in method references. */
8425 var arrayProto = Array.prototype,
8426 objectProto = Object.prototype;
8428 /** Used to resolve the decompiled source of functions. */
8429 var funcToString = Function.prototype.toString;
8431 /** Used to check objects for own properties. */
8432 var hasOwnProperty = objectProto.hasOwnProperty;
8434 /** Used to infer the `Object` constructor. */
8435 var objectCtorString = funcToString.call(Object);
8438 * Used to resolve the
8439 * [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
8442 var objectToString = objectProto.toString;
8444 /** Used to detect if a method is native. */
8445 var reIsNative = RegExp('^' +
8446 funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
8447 .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
8450 /** Built-in value references. */
8451 var Buffer = moduleExports ? root.Buffer : undefined,
8452 Reflect = root.Reflect,
8453 Symbol = root.Symbol,
8454 Uint8Array = root.Uint8Array,
8455 enumerate = Reflect ? Reflect.enumerate : undefined,
8456 getOwnPropertySymbols = Object.getOwnPropertySymbols,
8457 iteratorSymbol = typeof (iteratorSymbol = Symbol && Symbol.iterator) == 'symbol' ? iteratorSymbol : undefined,
8458 objectCreate = Object.create,
8459 propertyIsEnumerable = objectProto.propertyIsEnumerable,
8460 splice = arrayProto.splice;
8462 /* Built-in method references for those with the same name as other `lodash` methods. */
8463 var nativeCeil = Math.ceil,
8464 nativeGetPrototype = Object.getPrototypeOf,
8465 nativeKeys = Object.keys,
8466 nativeMax = Math.max,
8467 nativeMin = Math.min,
8468 nativeReverse = arrayProto.reverse;
8470 /* Built-in method references that are verified to be native. */
8471 var DataView = getNative(root, 'DataView'),
8472 Map = getNative(root, 'Map'),
8473 Promise = getNative(root, 'Promise'),
8474 Set = getNative(root, 'Set'),
8475 WeakMap = getNative(root, 'WeakMap'),
8476 nativeCreate = getNative(Object, 'create');
8478 /** Used to store function metadata. */
8479 var metaMap = WeakMap && new WeakMap;
8481 /** Detect if properties shadowing those on `Object.prototype` are non-enumerable. */
8482 var nonEnumShadows = !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf');
8484 /** Used to lookup unminified function names. */
8487 /** Used to detect maps, sets, and weakmaps. */
8488 var dataViewCtorString = toSource(DataView),
8489 mapCtorString = toSource(Map),
8490 promiseCtorString = toSource(Promise),
8491 setCtorString = toSource(Set),
8492 weakMapCtorString = toSource(WeakMap);
8494 /** Used to convert symbols to primitives and strings. */
8495 var symbolProto = Symbol ? Symbol.prototype : undefined,
8496 symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
8497 symbolToString = symbolProto ? symbolProto.toString : undefined;
8499 /*------------------------------------------------------------------------*/
8502 * Creates a `lodash` object which wraps `value` to enable implicit method
8503 * chain sequences. Methods that operate on and return arrays, collections,
8504 * and functions can be chained together. Methods that retrieve a single value
8505 * or may return a primitive value will automatically end the chain sequence
8506 * and return the unwrapped value. Otherwise, the value must be unwrapped
8509 * Explicit chain sequences, which must be unwrapped with `_#value`, may be
8510 * enabled using `_.chain`.
8512 * The execution of chained methods is lazy, that is, it's deferred until
8513 * `_#value` is implicitly or explicitly called.
8515 * Lazy evaluation allows several methods to support shortcut fusion.
8516 * Shortcut fusion is an optimization to merge iteratee calls; this avoids
8517 * the creation of intermediate arrays and can greatly reduce the number of
8518 * iteratee executions. Sections of a chain sequence qualify for shortcut
8519 * fusion if the section is applied to an array of at least `200` elements
8520 * and any iteratees accept only one argument. The heuristic for whether a
8521 * section qualifies for shortcut fusion is subject to change.
8523 * Chaining is supported in custom builds as long as the `_#value` method is
8524 * directly or indirectly included in the build.
8526 * In addition to lodash methods, wrappers have `Array` and `String` methods.
8528 * The wrapper `Array` methods are:
8529 * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
8531 * The wrapper `String` methods are:
8532 * `replace` and `split`
8534 * The wrapper methods that support shortcut fusion are:
8535 * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
8536 * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
8537 * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
8539 * The chainable wrapper methods are:
8540 * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
8541 * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
8542 * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
8543 * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
8544 * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
8545 * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
8546 * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
8547 * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
8548 * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
8549 * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
8550 * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
8551 * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
8552 * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
8553 * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
8554 * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
8555 * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
8556 * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
8557 * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
8558 * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
8559 * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
8560 * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
8561 * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
8562 * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
8563 * `zipObject`, `zipObjectDeep`, and `zipWith`
8565 * The wrapper methods that are **not** chainable by default are:
8566 * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
8567 * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `deburr`, `divide`, `each`,
8568 * `eachRight`, `endsWith`, `eq`, `escape`, `escapeRegExp`, `every`, `find`,
8569 * `findIndex`, `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `first`,
8570 * `floor`, `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`,
8571 * `forOwnRight`, `get`, `gt`, `gte`, `has`, `hasIn`, `head`, `identity`,
8572 * `includes`, `indexOf`, `inRange`, `invoke`, `isArguments`, `isArray`,
8573 * `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, `isBoolean`,
8574 * `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isEqualWith`,
8575 * `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, `isMap`,
8576 * `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, `isNumber`,
8577 * `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, `isSafeInteger`,
8578 * `isSet`, `isString`, `isUndefined`, `isTypedArray`, `isWeakMap`, `isWeakSet`,
8579 * `join`, `kebabCase`, `last`, `lastIndexOf`, `lowerCase`, `lowerFirst`,
8580 * `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, `min`, `minBy`, `multiply`,
8581 * `noConflict`, `noop`, `now`, `nth`, `pad`, `padEnd`, `padStart`, `parseInt`,
8582 * `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, `round`,
8583 * `runInContext`, `sample`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`,
8584 * `sortedIndexBy`, `sortedLastIndex`, `sortedLastIndexBy`, `startCase`,
8585 * `startsWith`, `subtract`, `sum`, `sumBy`, `template`, `times`, `toFinite`,
8586 * `toInteger`, `toJSON`, `toLength`, `toLower`, `toNumber`, `toSafeInteger`,
8587 * `toString`, `toUpper`, `trim`, `trimEnd`, `trimStart`, `truncate`, `unescape`,
8588 * `uniqueId`, `upperCase`, `upperFirst`, `value`, and `words`
8593 * @param {*} value The value to wrap in a `lodash` instance.
8594 * @returns {Object} Returns the new `lodash` wrapper instance.
8597 * function square(n) {
8601 * var wrapped = _([1, 2, 3]);
8603 * // Returns an unwrapped value.
8604 * wrapped.reduce(_.add);
8607 * // Returns a wrapped value.
8608 * var squares = wrapped.map(square);
8610 * _.isArray(squares);
8613 * _.isArray(squares.value());
8616 function lodash(value) {
8617 if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
8618 if (value instanceof LodashWrapper) {
8621 if (hasOwnProperty.call(value, '__wrapped__')) {
8622 return wrapperClone(value);
8625 return new LodashWrapper(value);
8629 * The function whose prototype chain sequence wrappers inherit from.
8633 function baseLodash() {
8634 // No operation performed.
8638 * The base constructor for creating `lodash` wrapper objects.
8641 * @param {*} value The value to wrap.
8642 * @param {boolean} [chainAll] Enable explicit method chain sequences.
8644 function LodashWrapper(value, chainAll) {
8645 this.__wrapped__ = value;
8646 this.__actions__ = [];
8647 this.__chain__ = !!chainAll;
8649 this.__values__ = undefined;
8652 // Ensure wrappers are instances of `baseLodash`.
8653 lodash.prototype = baseLodash.prototype;
8654 lodash.prototype.constructor = lodash;
8656 LodashWrapper.prototype = baseCreate(baseLodash.prototype);
8657 LodashWrapper.prototype.constructor = LodashWrapper;
8659 /*------------------------------------------------------------------------*/
8662 * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
8666 * @param {*} value The value to wrap.
8668 function LazyWrapper(value) {
8669 this.__wrapped__ = value;
8670 this.__actions__ = [];
8672 this.__filtered__ = false;
8673 this.__iteratees__ = [];
8674 this.__takeCount__ = MAX_ARRAY_LENGTH;
8675 this.__views__ = [];
8679 * Creates a clone of the lazy wrapper object.
8683 * @memberOf LazyWrapper
8684 * @returns {Object} Returns the cloned `LazyWrapper` object.
8686 function lazyClone() {
8687 var result = new LazyWrapper(this.__wrapped__);
8688 result.__actions__ = copyArray(this.__actions__);
8689 result.__dir__ = this.__dir__;
8690 result.__filtered__ = this.__filtered__;
8691 result.__iteratees__ = copyArray(this.__iteratees__);
8692 result.__takeCount__ = this.__takeCount__;
8693 result.__views__ = copyArray(this.__views__);
8698 * Reverses the direction of lazy iteration.
8702 * @memberOf LazyWrapper
8703 * @returns {Object} Returns the new reversed `LazyWrapper` object.
8705 function lazyReverse() {
8706 if (this.__filtered__) {
8707 var result = new LazyWrapper(this);
8708 result.__dir__ = -1;
8709 result.__filtered__ = true;
8711 result = this.clone();
8712 result.__dir__ *= -1;
8718 * Extracts the unwrapped value from its lazy wrapper.
8722 * @memberOf LazyWrapper
8723 * @returns {*} Returns the unwrapped value.
8725 function lazyValue() {
8726 var array = this.__wrapped__.value(),
8728 isArr = isArray(array),
8730 arrLength = isArr ? array.length : 0,
8731 view = getView(0, arrLength, this.__views__),
8734 length = end - start,
8735 index = isRight ? end : (start - 1),
8736 iteratees = this.__iteratees__,
8737 iterLength = iteratees.length,
8739 takeCount = nativeMin(length, this.__takeCount__);
8741 if (!isArr || arrLength < LARGE_ARRAY_SIZE ||
8742 (arrLength == length && takeCount == length)) {
8743 return baseWrapperValue(array, this.__actions__);
8748 while (length-- && resIndex < takeCount) {
8752 value = array[index];
8754 while (++iterIndex < iterLength) {
8755 var data = iteratees[iterIndex],
8756 iteratee = data.iteratee,
8758 computed = iteratee(value);
8760 if (type == LAZY_MAP_FLAG) {
8762 } else if (!computed) {
8763 if (type == LAZY_FILTER_FLAG) {
8770 result[resIndex++] = value;
8775 // Ensure `LazyWrapper` is an instance of `baseLodash`.
8776 LazyWrapper.prototype = baseCreate(baseLodash.prototype);
8777 LazyWrapper.prototype.constructor = LazyWrapper;
8779 /*------------------------------------------------------------------------*/
8782 * Creates a hash object.
8786 * @param {Array} [entries] The key-value pairs to cache.
8788 function Hash(entries) {
8790 length = entries ? entries.length : 0;
8793 while (++index < length) {
8794 var entry = entries[index];
8795 this.set(entry[0], entry[1]);
8800 * Removes all key-value entries from the hash.
8806 function hashClear() {
8807 this.__data__ = nativeCreate ? nativeCreate(null) : {};
8811 * Removes `key` and its value from the hash.
8816 * @param {Object} hash The hash to modify.
8817 * @param {string} key The key of the value to remove.
8818 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
8820 function hashDelete(key) {
8821 return this.has(key) && delete this.__data__[key];
8825 * Gets the hash value for `key`.
8830 * @param {string} key The key of the value to get.
8831 * @returns {*} Returns the entry value.
8833 function hashGet(key) {
8834 var data = this.__data__;
8836 var result = data[key];
8837 return result === HASH_UNDEFINED ? undefined : result;
8839 return hasOwnProperty.call(data, key) ? data[key] : undefined;
8843 * Checks if a hash value for `key` exists.
8848 * @param {string} key The key of the entry to check.
8849 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
8851 function hashHas(key) {
8852 var data = this.__data__;
8853 return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
8857 * Sets the hash `key` to `value`.
8862 * @param {string} key The key of the value to set.
8863 * @param {*} value The value to set.
8864 * @returns {Object} Returns the hash instance.
8866 function hashSet(key, value) {
8867 var data = this.__data__;
8868 data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
8872 // Add methods to `Hash`.
8873 Hash.prototype.clear = hashClear;
8874 Hash.prototype['delete'] = hashDelete;
8875 Hash.prototype.get = hashGet;
8876 Hash.prototype.has = hashHas;
8877 Hash.prototype.set = hashSet;
8879 /*------------------------------------------------------------------------*/
8882 * Creates an list cache object.
8886 * @param {Array} [entries] The key-value pairs to cache.
8888 function ListCache(entries) {
8890 length = entries ? entries.length : 0;
8893 while (++index < length) {
8894 var entry = entries[index];
8895 this.set(entry[0], entry[1]);
8900 * Removes all key-value entries from the list cache.
8904 * @memberOf ListCache
8906 function listCacheClear() {
8911 * Removes `key` and its value from the list cache.
8915 * @memberOf ListCache
8916 * @param {string} key The key of the value to remove.
8917 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
8919 function listCacheDelete(key) {
8920 var data = this.__data__,
8921 index = assocIndexOf(data, key);
8926 var lastIndex = data.length - 1;
8927 if (index == lastIndex) {
8930 splice.call(data, index, 1);
8936 * Gets the list cache value for `key`.
8940 * @memberOf ListCache
8941 * @param {string} key The key of the value to get.
8942 * @returns {*} Returns the entry value.
8944 function listCacheGet(key) {
8945 var data = this.__data__,
8946 index = assocIndexOf(data, key);
8948 return index < 0 ? undefined : data[index][1];
8952 * Checks if a list cache value for `key` exists.
8956 * @memberOf ListCache
8957 * @param {string} key The key of the entry to check.
8958 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
8960 function listCacheHas(key) {
8961 return assocIndexOf(this.__data__, key) > -1;
8965 * Sets the list cache `key` to `value`.
8969 * @memberOf ListCache
8970 * @param {string} key The key of the value to set.
8971 * @param {*} value The value to set.
8972 * @returns {Object} Returns the list cache instance.
8974 function listCacheSet(key, value) {
8975 var data = this.__data__,
8976 index = assocIndexOf(data, key);
8979 data.push([key, value]);
8981 data[index][1] = value;
8986 // Add methods to `ListCache`.
8987 ListCache.prototype.clear = listCacheClear;
8988 ListCache.prototype['delete'] = listCacheDelete;
8989 ListCache.prototype.get = listCacheGet;
8990 ListCache.prototype.has = listCacheHas;
8991 ListCache.prototype.set = listCacheSet;
8993 /*------------------------------------------------------------------------*/
8996 * Creates a map cache object to store key-value pairs.
9000 * @param {Array} [entries] The key-value pairs to cache.
9002 function MapCache(entries) {
9004 length = entries ? entries.length : 0;
9007 while (++index < length) {
9008 var entry = entries[index];
9009 this.set(entry[0], entry[1]);
9014 * Removes all key-value entries from the map.
9018 * @memberOf MapCache
9020 function mapCacheClear() {
9023 'map': new (Map || ListCache),
9029 * Removes `key` and its value from the map.
9033 * @memberOf MapCache
9034 * @param {string} key The key of the value to remove.
9035 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
9037 function mapCacheDelete(key) {
9038 return getMapData(this, key)['delete'](key);
9042 * Gets the map value for `key`.
9046 * @memberOf MapCache
9047 * @param {string} key The key of the value to get.
9048 * @returns {*} Returns the entry value.
9050 function mapCacheGet(key) {
9051 return getMapData(this, key).get(key);
9055 * Checks if a map value for `key` exists.
9059 * @memberOf MapCache
9060 * @param {string} key The key of the entry to check.
9061 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
9063 function mapCacheHas(key) {
9064 return getMapData(this, key).has(key);
9068 * Sets the map `key` to `value`.
9072 * @memberOf MapCache
9073 * @param {string} key The key of the value to set.
9074 * @param {*} value The value to set.
9075 * @returns {Object} Returns the map cache instance.
9077 function mapCacheSet(key, value) {
9078 getMapData(this, key).set(key, value);
9082 // Add methods to `MapCache`.
9083 MapCache.prototype.clear = mapCacheClear;
9084 MapCache.prototype['delete'] = mapCacheDelete;
9085 MapCache.prototype.get = mapCacheGet;
9086 MapCache.prototype.has = mapCacheHas;
9087 MapCache.prototype.set = mapCacheSet;
9089 /*------------------------------------------------------------------------*/
9093 * Creates an array cache object to store unique values.
9097 * @param {Array} [values] The values to cache.
9099 function SetCache(values) {
9101 length = values ? values.length : 0;
9103 this.__data__ = new MapCache;
9104 while (++index < length) {
9105 this.add(values[index]);
9110 * Adds `value` to the array cache.
9114 * @memberOf SetCache
9116 * @param {*} value The value to cache.
9117 * @returns {Object} Returns the cache instance.
9119 function setCacheAdd(value) {
9120 this.__data__.set(value, HASH_UNDEFINED);
9125 * Checks if `value` is in the array cache.
9129 * @memberOf SetCache
9130 * @param {*} value The value to search for.
9131 * @returns {number} Returns `true` if `value` is found, else `false`.
9133 function setCacheHas(value) {
9134 return this.__data__.has(value);
9137 // Add methods to `SetCache`.
9138 SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
9139 SetCache.prototype.has = setCacheHas;
9141 /*------------------------------------------------------------------------*/
9144 * Creates a stack cache object to store key-value pairs.
9148 * @param {Array} [entries] The key-value pairs to cache.
9150 function Stack(entries) {
9151 this.__data__ = new ListCache(entries);
9155 * Removes all key-value entries from the stack.
9161 function stackClear() {
9162 this.__data__ = new ListCache;
9166 * Removes `key` and its value from the stack.
9171 * @param {string} key The key of the value to remove.
9172 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
9174 function stackDelete(key) {
9175 return this.__data__['delete'](key);
9179 * Gets the stack value for `key`.
9184 * @param {string} key The key of the value to get.
9185 * @returns {*} Returns the entry value.
9187 function stackGet(key) {
9188 return this.__data__.get(key);
9192 * Checks if a stack value for `key` exists.
9197 * @param {string} key The key of the entry to check.
9198 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
9200 function stackHas(key) {
9201 return this.__data__.has(key);
9205 * Sets the stack `key` to `value`.
9210 * @param {string} key The key of the value to set.
9211 * @param {*} value The value to set.
9212 * @returns {Object} Returns the stack cache instance.
9214 function stackSet(key, value) {
9215 var cache = this.__data__;
9216 if (cache instanceof ListCache && cache.__data__.length == LARGE_ARRAY_SIZE) {
9217 cache = this.__data__ = new MapCache(cache.__data__);
9219 cache.set(key, value);
9223 // Add methods to `Stack`.
9224 Stack.prototype.clear = stackClear;
9225 Stack.prototype['delete'] = stackDelete;
9226 Stack.prototype.get = stackGet;
9227 Stack.prototype.has = stackHas;
9228 Stack.prototype.set = stackSet;
9230 /*------------------------------------------------------------------------*/
9233 * This function is like `assignValue` except that it doesn't assign
9234 * `undefined` values.
9237 * @param {Object} object The object to modify.
9238 * @param {string} key The key of the property to assign.
9239 * @param {*} value The value to assign.
9241 function assignMergeValue(object, key, value) {
9242 if ((value !== undefined && !eq(object[key], value)) ||
9243 (typeof key == 'number' && value === undefined && !(key in object))) {
9244 object[key] = value;
9249 * Assigns `value` to `key` of `object` if the existing value is not equivalent
9250 * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
9251 * for equality comparisons.
9254 * @param {Object} object The object to modify.
9255 * @param {string} key The key of the property to assign.
9256 * @param {*} value The value to assign.
9258 function assignValue(object, key, value) {
9259 var objValue = object[key];
9260 if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
9261 (value === undefined && !(key in object))) {
9262 object[key] = value;
9267 * Gets the index at which the `key` is found in `array` of key-value pairs.
9270 * @param {Array} array The array to search.
9271 * @param {*} key The key to search for.
9272 * @returns {number} Returns the index of the matched value, else `-1`.
9274 function assocIndexOf(array, key) {
9275 var length = array.length;
9277 if (eq(array[length][0], key)) {
9285 * Aggregates elements of `collection` on `accumulator` with keys transformed
9286 * by `iteratee` and values set by `setter`.
9289 * @param {Array|Object} collection The collection to iterate over.
9290 * @param {Function} setter The function to set `accumulator` values.
9291 * @param {Function} iteratee The iteratee to transform keys.
9292 * @param {Object} accumulator The initial aggregated object.
9293 * @returns {Function} Returns `accumulator`.
9295 function baseAggregator(collection, setter, iteratee, accumulator) {
9296 baseEach(collection, function(value, key, collection) {
9297 setter(accumulator, value, iteratee(value), collection);
9303 * The base implementation of `_.assign` without support for multiple sources
9304 * or `customizer` functions.
9307 * @param {Object} object The destination object.
9308 * @param {Object} source The source object.
9309 * @returns {Object} Returns `object`.
9311 function baseAssign(object, source) {
9312 return object && copyObject(source, keys(source), object);
9316 * The base implementation of `_.at` without support for individual paths.
9319 * @param {Object} object The object to iterate over.
9320 * @param {string[]} paths The property paths of elements to pick.
9321 * @returns {Array} Returns the picked elements.
9323 function baseAt(object, paths) {
9325 isNil = object == null,
9326 length = paths.length,
9327 result = Array(length);
9329 while (++index < length) {
9330 result[index] = isNil ? undefined : get(object, paths[index]);
9336 * The base implementation of `_.clone` and `_.cloneDeep` which tracks
9337 * traversed objects.
9340 * @param {*} value The value to clone.
9341 * @param {boolean} [isDeep] Specify a deep clone.
9342 * @param {boolean} [isFull] Specify a clone including symbols.
9343 * @param {Function} [customizer] The function to customize cloning.
9344 * @param {string} [key] The key of `value`.
9345 * @param {Object} [object] The parent object of `value`.
9346 * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
9347 * @returns {*} Returns the cloned value.
9349 function baseClone(value, isDeep, isFull, customizer, key, object, stack) {
9352 result = object ? customizer(value, key, object, stack) : customizer(value);
9354 if (result !== undefined) {
9357 if (!isObject(value)) {
9360 var isArr = isArray(value);
9362 result = initCloneArray(value);
9364 return copyArray(value, result);
9367 var tag = getTag(value),
9368 isFunc = tag == funcTag || tag == genTag;
9370 if (isBuffer(value)) {
9371 return cloneBuffer(value, isDeep);
9373 if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
9374 if (isHostObject(value)) {
9375 return object ? value : {};
9377 result = initCloneObject(isFunc ? {} : value);
9379 return copySymbols(value, baseAssign(result, value));
9382 if (!cloneableTags[tag]) {
9383 return object ? value : {};
9385 result = initCloneByTag(value, tag, baseClone, isDeep);
9388 // Check for circular references and return its corresponding clone.
9389 stack || (stack = new Stack);
9390 var stacked = stack.get(value);
9394 stack.set(value, result);
9397 var props = isFull ? getAllKeys(value) : keys(value);
9399 // Recursively populate clone (susceptible to call stack limits).
9400 arrayEach(props || value, function(subValue, key) {
9403 subValue = value[key];
9405 assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack));
9411 * The base implementation of `_.create` without support for assigning
9412 * properties to the created object.
9415 * @param {Object} prototype The object to inherit from.
9416 * @returns {Object} Returns the new object.
9418 function baseCreate(proto) {
9419 return isObject(proto) ? objectCreate(proto) : {};
9423 * The base implementation of methods like `_.difference` without support
9424 * for excluding multiple arrays or iteratee shorthands.
9427 * @param {Array} array The array to inspect.
9428 * @param {Array} values The values to exclude.
9429 * @param {Function} [iteratee] The iteratee invoked per element.
9430 * @param {Function} [comparator] The comparator invoked per element.
9431 * @returns {Array} Returns the new array of filtered values.
9433 function baseDifference(array, values, iteratee, comparator) {
9435 includes = arrayIncludes,
9437 length = array.length,
9439 valuesLength = values.length;
9445 values = arrayMap(values, baseUnary(iteratee));
9448 includes = arrayIncludesWith;
9451 else if (values.length >= LARGE_ARRAY_SIZE) {
9452 includes = cacheHas;
9454 values = new SetCache(values);
9457 while (++index < length) {
9458 var value = array[index],
9459 computed = iteratee ? iteratee(value) : value;
9461 value = (comparator || value !== 0) ? value : 0;
9462 if (isCommon && computed === computed) {
9463 var valuesIndex = valuesLength;
9464 while (valuesIndex--) {
9465 if (values[valuesIndex] === computed) {
9471 else if (!includes(values, computed, comparator)) {
9479 * The base implementation of `_.forEach` without support for iteratee shorthands.
9482 * @param {Array|Object} collection The collection to iterate over.
9483 * @param {Function} iteratee The function invoked per iteration.
9484 * @returns {Array|Object} Returns `collection`.
9486 var baseEach = createBaseEach(baseForOwn);
9489 * The base implementation of `_.every` without support for iteratee shorthands.
9492 * @param {Array|Object} collection The collection to iterate over.
9493 * @param {Function} predicate The function invoked per iteration.
9494 * @returns {boolean} Returns `true` if all elements pass the predicate check,
9497 function baseEvery(collection, predicate) {
9499 baseEach(collection, function(value, index, collection) {
9500 result = !!predicate(value, index, collection);
9507 * The base implementation of `_.filter` without support for iteratee shorthands.
9510 * @param {Array|Object} collection The collection to iterate over.
9511 * @param {Function} predicate The function invoked per iteration.
9512 * @returns {Array} Returns the new filtered array.
9514 function baseFilter(collection, predicate) {
9516 baseEach(collection, function(value, index, collection) {
9517 if (predicate(value, index, collection)) {
9525 * The base implementation of `_.flatten` with support for restricting flattening.
9528 * @param {Array} array The array to flatten.
9529 * @param {number} depth The maximum recursion depth.
9530 * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
9531 * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
9532 * @param {Array} [result=[]] The initial result value.
9533 * @returns {Array} Returns the new flattened array.
9535 function baseFlatten(array, depth, predicate, isStrict, result) {
9537 length = array.length;
9539 predicate || (predicate = isFlattenable);
9540 result || (result = []);
9542 while (++index < length) {
9543 var value = array[index];
9544 if (depth > 0 && predicate(value)) {
9546 // Recursively flatten arrays (susceptible to call stack limits).
9547 baseFlatten(value, depth - 1, predicate, isStrict, result);
9549 arrayPush(result, value);
9551 } else if (!isStrict) {
9552 result[result.length] = value;
9559 * The base implementation of `baseForOwn` which iterates over `object`
9560 * properties returned by `keysFunc` and invokes `iteratee` for each property.
9561 * Iteratee functions may exit iteration early by explicitly returning `false`.
9564 * @param {Object} object The object to iterate over.
9565 * @param {Function} iteratee The function invoked per iteration.
9566 * @param {Function} keysFunc The function to get the keys of `object`.
9567 * @returns {Object} Returns `object`.
9569 var baseFor = createBaseFor();
9572 * The base implementation of `_.forOwn` without support for iteratee shorthands.
9575 * @param {Object} object The object to iterate over.
9576 * @param {Function} iteratee The function invoked per iteration.
9577 * @returns {Object} Returns `object`.
9579 function baseForOwn(object, iteratee) {
9580 return object && baseFor(object, iteratee, keys);
9584 * The base implementation of `_.functions` which creates an array of
9585 * `object` function property names filtered from `props`.
9588 * @param {Object} object The object to inspect.
9589 * @param {Array} props The property names to filter.
9590 * @returns {Array} Returns the function names.
9592 function baseFunctions(object, props) {
9593 return arrayFilter(props, function(key) {
9594 return isFunction(object[key]);
9599 * The base implementation of `_.get` without support for default values.
9602 * @param {Object} object The object to query.
9603 * @param {Array|string} path The path of the property to get.
9604 * @returns {*} Returns the resolved value.
9606 function baseGet(object, path) {
9607 path = isKey(path, object) ? [path] : castPath(path);
9610 length = path.length;
9612 while (object != null && index < length) {
9613 object = object[toKey(path[index++])];
9615 return (index && index == length) ? object : undefined;
9619 * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
9620 * `keysFunc` and `symbolsFunc` to get the enumerable property names and
9621 * symbols of `object`.
9624 * @param {Object} object The object to query.
9625 * @param {Function} keysFunc The function to get the keys of `object`.
9626 * @param {Function} symbolsFunc The function to get the symbols of `object`.
9627 * @returns {Array} Returns the array of property names and symbols.
9629 function baseGetAllKeys(object, keysFunc, symbolsFunc) {
9630 var result = keysFunc(object);
9631 return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
9635 * The base implementation of `_.has` without support for deep paths.
9638 * @param {Object} object The object to query.
9639 * @param {Array|string} key The key to check.
9640 * @returns {boolean} Returns `true` if `key` exists, else `false`.
9642 function baseHas(object, key) {
9643 // Avoid a bug in IE 10-11 where objects with a [[Prototype]] of `null`,
9644 // that are composed entirely of index properties, return `false` for
9645 // `hasOwnProperty` checks of them.
9646 return hasOwnProperty.call(object, key) ||
9647 (typeof object == 'object' && key in object && getPrototype(object) === null);
9651 * The base implementation of `_.hasIn` without support for deep paths.
9654 * @param {Object} object The object to query.
9655 * @param {Array|string} key The key to check.
9656 * @returns {boolean} Returns `true` if `key` exists, else `false`.
9658 function baseHasIn(object, key) {
9659 return key in Object(object);
9663 * The base implementation of methods like `_.intersection`, without support
9664 * for iteratee shorthands, that accepts an array of arrays to inspect.
9667 * @param {Array} arrays The arrays to inspect.
9668 * @param {Function} [iteratee] The iteratee invoked per element.
9669 * @param {Function} [comparator] The comparator invoked per element.
9670 * @returns {Array} Returns the new array of shared values.
9672 function baseIntersection(arrays, iteratee, comparator) {
9673 var includes = comparator ? arrayIncludesWith : arrayIncludes,
9674 length = arrays[0].length,
9675 othLength = arrays.length,
9676 othIndex = othLength,
9677 caches = Array(othLength),
9678 maxLength = Infinity,
9681 while (othIndex--) {
9682 var array = arrays[othIndex];
9683 if (othIndex && iteratee) {
9684 array = arrayMap(array, baseUnary(iteratee));
9686 maxLength = nativeMin(array.length, maxLength);
9687 caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
9688 ? new SetCache(othIndex && array)
9697 while (++index < length && result.length < maxLength) {
9698 var value = array[index],
9699 computed = iteratee ? iteratee(value) : value;
9701 value = (comparator || value !== 0) ? value : 0;
9703 ? cacheHas(seen, computed)
9704 : includes(result, computed, comparator)
9706 othIndex = othLength;
9707 while (--othIndex) {
9708 var cache = caches[othIndex];
9710 ? cacheHas(cache, computed)
9711 : includes(arrays[othIndex], computed, comparator))
9717 seen.push(computed);
9726 * The base implementation of `_.invoke` without support for individual
9730 * @param {Object} object The object to query.
9731 * @param {Array|string} path The path of the method to invoke.
9732 * @param {Array} args The arguments to invoke the method with.
9733 * @returns {*} Returns the result of the invoked method.
9735 function baseInvoke(object, path, args) {
9736 if (!isKey(path, object)) {
9737 path = castPath(path);
9738 object = parent(object, path);
9741 var func = object == null ? object : object[toKey(path)];
9742 return func == null ? undefined : apply(func, object, args);
9746 * The base implementation of `_.isEqual` which supports partial comparisons
9747 * and tracks traversed objects.
9750 * @param {*} value The value to compare.
9751 * @param {*} other The other value to compare.
9752 * @param {Function} [customizer] The function to customize comparisons.
9753 * @param {boolean} [bitmask] The bitmask of comparison flags.
9754 * The bitmask may be composed of the following flags:
9755 * 1 - Unordered comparison
9756 * 2 - Partial comparison
9757 * @param {Object} [stack] Tracks traversed `value` and `other` objects.
9758 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
9760 function baseIsEqual(value, other, customizer, bitmask, stack) {
9761 if (value === other) {
9764 if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
9765 return value !== value && other !== other;
9767 return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack);
9771 * A specialized version of `baseIsEqual` for arrays and objects which performs
9772 * deep comparisons and tracks traversed objects enabling objects with circular
9773 * references to be compared.
9776 * @param {Object} object The object to compare.
9777 * @param {Object} other The other object to compare.
9778 * @param {Function} equalFunc The function to determine equivalents of values.
9779 * @param {Function} [customizer] The function to customize comparisons.
9780 * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual`
9782 * @param {Object} [stack] Tracks traversed `object` and `other` objects.
9783 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
9785 function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) {
9786 var objIsArr = isArray(object),
9787 othIsArr = isArray(other),
9792 objTag = getTag(object);
9793 objTag = objTag == argsTag ? objectTag : objTag;
9796 othTag = getTag(other);
9797 othTag = othTag == argsTag ? objectTag : othTag;
9799 var objIsObj = objTag == objectTag && !isHostObject(object),
9800 othIsObj = othTag == objectTag && !isHostObject(other),
9801 isSameTag = objTag == othTag;
9803 if (isSameTag && !objIsObj) {
9804 stack || (stack = new Stack);
9805 return (objIsArr || isTypedArray(object))
9806 ? equalArrays(object, other, equalFunc, customizer, bitmask, stack)
9807 : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack);
9809 if (!(bitmask & PARTIAL_COMPARE_FLAG)) {
9810 var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
9811 othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
9813 if (objIsWrapped || othIsWrapped) {
9814 var objUnwrapped = objIsWrapped ? object.value() : object,
9815 othUnwrapped = othIsWrapped ? other.value() : other;
9817 stack || (stack = new Stack);
9818 return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack);
9824 stack || (stack = new Stack);
9825 return equalObjects(object, other, equalFunc, customizer, bitmask, stack);
9829 * The base implementation of `_.isMatch` without support for iteratee shorthands.
9832 * @param {Object} object The object to inspect.
9833 * @param {Object} source The object of property values to match.
9834 * @param {Array} matchData The property names, values, and compare flags to match.
9835 * @param {Function} [customizer] The function to customize comparisons.
9836 * @returns {boolean} Returns `true` if `object` is a match, else `false`.
9838 function baseIsMatch(object, source, matchData, customizer) {
9839 var index = matchData.length,
9841 noCustomizer = !customizer;
9843 if (object == null) {
9846 object = Object(object);
9848 var data = matchData[index];
9849 if ((noCustomizer && data[2])
9850 ? data[1] !== object[data[0]]
9851 : !(data[0] in object)
9856 while (++index < length) {
9857 data = matchData[index];
9859 objValue = object[key],
9862 if (noCustomizer && data[2]) {
9863 if (objValue === undefined && !(key in object)) {
9867 var stack = new Stack;
9869 var result = customizer(objValue, srcValue, key, object, source, stack);
9871 if (!(result === undefined
9872 ? baseIsEqual(srcValue, objValue, customizer, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG, stack)
9883 * The base implementation of `_.iteratee`.
9886 * @param {*} [value=_.identity] The value to convert to an iteratee.
9887 * @returns {Function} Returns the iteratee.
9889 function baseIteratee(value) {
9890 // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
9891 // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
9892 if (typeof value == 'function') {
9895 if (value == null) {
9898 if (typeof value == 'object') {
9899 return isArray(value)
9900 ? baseMatchesProperty(value[0], value[1])
9901 : baseMatches(value);
9903 return property(value);
9907 * The base implementation of `_.keys` which doesn't skip the constructor
9908 * property of prototypes or treat sparse arrays as dense.
9911 * @param {Object} object The object to query.
9912 * @returns {Array} Returns the array of property names.
9914 function baseKeys(object) {
9915 return nativeKeys(Object(object));
9919 * The base implementation of `_.keysIn` which doesn't skip the constructor
9920 * property of prototypes or treat sparse arrays as dense.
9923 * @param {Object} object The object to query.
9924 * @returns {Array} Returns the array of property names.
9926 function baseKeysIn(object) {
9927 object = object == null ? object : Object(object);
9930 for (var key in object) {
9936 // Fallback for IE < 9 with es6-shim.
9937 if (enumerate && !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf')) {
9938 baseKeysIn = function(object) {
9939 return iteratorToArray(enumerate(object));
9944 * The base implementation of `_.map` without support for iteratee shorthands.
9947 * @param {Array|Object} collection The collection to iterate over.
9948 * @param {Function} iteratee The function invoked per iteration.
9949 * @returns {Array} Returns the new mapped array.
9951 function baseMap(collection, iteratee) {
9953 result = isArrayLike(collection) ? Array(collection.length) : [];
9955 baseEach(collection, function(value, key, collection) {
9956 result[++index] = iteratee(value, key, collection);
9962 * The base implementation of `_.matches` which doesn't clone `source`.
9965 * @param {Object} source The object of property values to match.
9966 * @returns {Function} Returns the new spec function.
9968 function baseMatches(source) {
9969 var matchData = getMatchData(source);
9970 if (matchData.length == 1 && matchData[0][2]) {
9971 return matchesStrictComparable(matchData[0][0], matchData[0][1]);
9973 return function(object) {
9974 return object === source || baseIsMatch(object, source, matchData);
9979 * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
9982 * @param {string} path The path of the property to get.
9983 * @param {*} srcValue The value to match.
9984 * @returns {Function} Returns the new spec function.
9986 function baseMatchesProperty(path, srcValue) {
9987 if (isKey(path) && isStrictComparable(srcValue)) {
9988 return matchesStrictComparable(toKey(path), srcValue);
9990 return function(object) {
9991 var objValue = get(object, path);
9992 return (objValue === undefined && objValue === srcValue)
9993 ? hasIn(object, path)
9994 : baseIsEqual(srcValue, objValue, undefined, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG);
9999 * The base implementation of `_.merge` without support for multiple sources.
10002 * @param {Object} object The destination object.
10003 * @param {Object} source The source object.
10004 * @param {number} srcIndex The index of `source`.
10005 * @param {Function} [customizer] The function to customize merged values.
10006 * @param {Object} [stack] Tracks traversed source values and their merged
10009 function baseMerge(object, source, srcIndex, customizer, stack) {
10010 if (object === source) {
10013 if (!(isArray(source) || isTypedArray(source))) {
10014 var props = keysIn(source);
10016 arrayEach(props || source, function(srcValue, key) {
10019 srcValue = source[key];
10021 if (isObject(srcValue)) {
10022 stack || (stack = new Stack);
10023 baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
10026 var newValue = customizer
10027 ? customizer(object[key], srcValue, (key + ''), object, source, stack)
10030 if (newValue === undefined) {
10031 newValue = srcValue;
10033 assignMergeValue(object, key, newValue);
10039 * A specialized version of `baseMerge` for arrays and objects which performs
10040 * deep merges and tracks traversed objects enabling objects with circular
10041 * references to be merged.
10044 * @param {Object} object The destination object.
10045 * @param {Object} source The source object.
10046 * @param {string} key The key of the value to merge.
10047 * @param {number} srcIndex The index of `source`.
10048 * @param {Function} mergeFunc The function to merge values.
10049 * @param {Function} [customizer] The function to customize assigned values.
10050 * @param {Object} [stack] Tracks traversed source values and their merged
10053 function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
10054 var objValue = object[key],
10055 srcValue = source[key],
10056 stacked = stack.get(srcValue);
10059 assignMergeValue(object, key, stacked);
10062 var newValue = customizer
10063 ? customizer(objValue, srcValue, (key + ''), object, source, stack)
10066 var isCommon = newValue === undefined;
10069 newValue = srcValue;
10070 if (isArray(srcValue) || isTypedArray(srcValue)) {
10071 if (isArray(objValue)) {
10072 newValue = objValue;
10074 else if (isArrayLikeObject(objValue)) {
10075 newValue = copyArray(objValue);
10079 newValue = baseClone(srcValue, true);
10082 else if (isPlainObject(srcValue) || isArguments(srcValue)) {
10083 if (isArguments(objValue)) {
10084 newValue = toPlainObject(objValue);
10086 else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
10088 newValue = baseClone(srcValue, true);
10091 newValue = objValue;
10098 stack.set(srcValue, newValue);
10101 // Recursively merge objects and arrays (susceptible to call stack limits).
10102 mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
10104 stack['delete'](srcValue);
10105 assignMergeValue(object, key, newValue);
10109 * The base implementation of `_.pick` without support for individual
10110 * property identifiers.
10113 * @param {Object} object The source object.
10114 * @param {string[]} props The property identifiers to pick.
10115 * @returns {Object} Returns the new object.
10117 function basePick(object, props) {
10118 object = Object(object);
10119 return arrayReduce(props, function(result, key) {
10120 if (key in object) {
10121 result[key] = object[key];
10128 * The base implementation of `_.property` without support for deep paths.
10131 * @param {string} key The key of the property to get.
10132 * @returns {Function} Returns the new accessor function.
10134 function baseProperty(key) {
10135 return function(object) {
10136 return object == null ? undefined : object[key];
10141 * A specialized version of `baseProperty` which supports deep paths.
10144 * @param {Array|string} path The path of the property to get.
10145 * @returns {Function} Returns the new accessor function.
10147 function basePropertyDeep(path) {
10148 return function(object) {
10149 return baseGet(object, path);
10154 * The base implementation of `setData` without support for hot loop detection.
10157 * @param {Function} func The function to associate metadata with.
10158 * @param {*} data The metadata.
10159 * @returns {Function} Returns `func`.
10161 var baseSetData = !metaMap ? identity : function(func, data) {
10162 metaMap.set(func, data);
10167 * The base implementation of `_.slice` without an iteratee call guard.
10170 * @param {Array} array The array to slice.
10171 * @param {number} [start=0] The start position.
10172 * @param {number} [end=array.length] The end position.
10173 * @returns {Array} Returns the slice of `array`.
10175 function baseSlice(array, start, end) {
10177 length = array.length;
10180 start = -start > length ? 0 : (length + start);
10182 end = end > length ? length : end;
10186 length = start > end ? 0 : ((end - start) >>> 0);
10189 var result = Array(length);
10190 while (++index < length) {
10191 result[index] = array[index + start];
10197 * The base implementation of `_.some` without support for iteratee shorthands.
10200 * @param {Array|Object} collection The collection to iterate over.
10201 * @param {Function} predicate The function invoked per iteration.
10202 * @returns {boolean} Returns `true` if any element passes the predicate check,
10205 function baseSome(collection, predicate) {
10208 baseEach(collection, function(value, index, collection) {
10209 result = predicate(value, index, collection);
10216 * The base implementation of `_.toString` which doesn't convert nullish
10217 * values to empty strings.
10220 * @param {*} value The value to process.
10221 * @returns {string} Returns the string.
10223 function baseToString(value) {
10224 // Exit early for strings to avoid a performance hit in some environments.
10225 if (typeof value == 'string') {
10228 if (isSymbol(value)) {
10229 return symbolToString ? symbolToString.call(value) : '';
10231 var result = (value + '');
10232 return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
10236 * The base implementation of `_.uniqBy` without support for iteratee shorthands.
10239 * @param {Array} array The array to inspect.
10240 * @param {Function} [iteratee] The iteratee invoked per element.
10241 * @param {Function} [comparator] The comparator invoked per element.
10242 * @returns {Array} Returns the new duplicate free array.
10244 function baseUniq(array, iteratee, comparator) {
10246 includes = arrayIncludes,
10247 length = array.length,
10254 includes = arrayIncludesWith;
10256 else if (length >= LARGE_ARRAY_SIZE) {
10257 var set = iteratee ? null : createSet(array);
10259 return setToArray(set);
10262 includes = cacheHas;
10263 seen = new SetCache;
10266 seen = iteratee ? [] : result;
10269 while (++index < length) {
10270 var value = array[index],
10271 computed = iteratee ? iteratee(value) : value;
10273 value = (comparator || value !== 0) ? value : 0;
10274 if (isCommon && computed === computed) {
10275 var seenIndex = seen.length;
10276 while (seenIndex--) {
10277 if (seen[seenIndex] === computed) {
10282 seen.push(computed);
10284 result.push(value);
10286 else if (!includes(seen, computed, comparator)) {
10287 if (seen !== result) {
10288 seen.push(computed);
10290 result.push(value);
10297 * The base implementation of `wrapperValue` which returns the result of
10298 * performing a sequence of actions on the unwrapped `value`, where each
10299 * successive action is supplied the return value of the previous.
10302 * @param {*} value The unwrapped value.
10303 * @param {Array} actions Actions to perform to resolve the unwrapped value.
10304 * @returns {*} Returns the resolved value.
10306 function baseWrapperValue(value, actions) {
10307 var result = value;
10308 if (result instanceof LazyWrapper) {
10309 result = result.value();
10311 return arrayReduce(actions, function(result, action) {
10312 return action.func.apply(action.thisArg, arrayPush([result], action.args));
10317 * Casts `value` to an empty array if it's not an array like object.
10320 * @param {*} value The value to inspect.
10321 * @returns {Array|Object} Returns the cast array-like object.
10323 function castArrayLikeObject(value) {
10324 return isArrayLikeObject(value) ? value : [];
10328 * Casts `value` to a path array if it's not one.
10331 * @param {*} value The value to inspect.
10332 * @returns {Array} Returns the cast property path array.
10334 function castPath(value) {
10335 return isArray(value) ? value : stringToPath(value);
10339 * Creates a clone of `buffer`.
10342 * @param {Buffer} buffer The buffer to clone.
10343 * @param {boolean} [isDeep] Specify a deep clone.
10344 * @returns {Buffer} Returns the cloned buffer.
10346 function cloneBuffer(buffer, isDeep) {
10348 return buffer.slice();
10350 var result = new buffer.constructor(buffer.length);
10351 buffer.copy(result);
10356 * Creates a clone of `arrayBuffer`.
10359 * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
10360 * @returns {ArrayBuffer} Returns the cloned array buffer.
10362 function cloneArrayBuffer(arrayBuffer) {
10363 var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
10364 new Uint8Array(result).set(new Uint8Array(arrayBuffer));
10369 * Creates a clone of `dataView`.
10372 * @param {Object} dataView The data view to clone.
10373 * @param {boolean} [isDeep] Specify a deep clone.
10374 * @returns {Object} Returns the cloned data view.
10376 function cloneDataView(dataView, isDeep) {
10377 var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
10378 return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
10382 * Creates a clone of `map`.
10385 * @param {Object} map The map to clone.
10386 * @param {Function} cloneFunc The function to clone values.
10387 * @param {boolean} [isDeep] Specify a deep clone.
10388 * @returns {Object} Returns the cloned map.
10390 function cloneMap(map, isDeep, cloneFunc) {
10391 var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map);
10392 return arrayReduce(array, addMapEntry, new map.constructor);
10396 * Creates a clone of `regexp`.
10399 * @param {Object} regexp The regexp to clone.
10400 * @returns {Object} Returns the cloned regexp.
10402 function cloneRegExp(regexp) {
10403 var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
10404 result.lastIndex = regexp.lastIndex;
10409 * Creates a clone of `set`.
10412 * @param {Object} set The set to clone.
10413 * @param {Function} cloneFunc The function to clone values.
10414 * @param {boolean} [isDeep] Specify a deep clone.
10415 * @returns {Object} Returns the cloned set.
10417 function cloneSet(set, isDeep, cloneFunc) {
10418 var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set);
10419 return arrayReduce(array, addSetEntry, new set.constructor);
10423 * Creates a clone of the `symbol` object.
10426 * @param {Object} symbol The symbol object to clone.
10427 * @returns {Object} Returns the cloned symbol object.
10429 function cloneSymbol(symbol) {
10430 return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
10434 * Creates a clone of `typedArray`.
10437 * @param {Object} typedArray The typed array to clone.
10438 * @param {boolean} [isDeep] Specify a deep clone.
10439 * @returns {Object} Returns the cloned typed array.
10441 function cloneTypedArray(typedArray, isDeep) {
10442 var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
10443 return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
10447 * Creates an array that is the composition of partially applied arguments,
10448 * placeholders, and provided arguments into a single array of arguments.
10451 * @param {Array} args The provided arguments.
10452 * @param {Array} partials The arguments to prepend to those provided.
10453 * @param {Array} holders The `partials` placeholder indexes.
10454 * @params {boolean} [isCurried] Specify composing for a curried function.
10455 * @returns {Array} Returns the new array of composed arguments.
10457 function composeArgs(args, partials, holders, isCurried) {
10458 var argsIndex = -1,
10459 argsLength = args.length,
10460 holdersLength = holders.length,
10462 leftLength = partials.length,
10463 rangeLength = nativeMax(argsLength - holdersLength, 0),
10464 result = Array(leftLength + rangeLength),
10465 isUncurried = !isCurried;
10467 while (++leftIndex < leftLength) {
10468 result[leftIndex] = partials[leftIndex];
10470 while (++argsIndex < holdersLength) {
10471 if (isUncurried || argsIndex < argsLength) {
10472 result[holders[argsIndex]] = args[argsIndex];
10475 while (rangeLength--) {
10476 result[leftIndex++] = args[argsIndex++];
10482 * This function is like `composeArgs` except that the arguments composition
10483 * is tailored for `_.partialRight`.
10486 * @param {Array} args The provided arguments.
10487 * @param {Array} partials The arguments to append to those provided.
10488 * @param {Array} holders The `partials` placeholder indexes.
10489 * @params {boolean} [isCurried] Specify composing for a curried function.
10490 * @returns {Array} Returns the new array of composed arguments.
10492 function composeArgsRight(args, partials, holders, isCurried) {
10493 var argsIndex = -1,
10494 argsLength = args.length,
10496 holdersLength = holders.length,
10498 rightLength = partials.length,
10499 rangeLength = nativeMax(argsLength - holdersLength, 0),
10500 result = Array(rangeLength + rightLength),
10501 isUncurried = !isCurried;
10503 while (++argsIndex < rangeLength) {
10504 result[argsIndex] = args[argsIndex];
10506 var offset = argsIndex;
10507 while (++rightIndex < rightLength) {
10508 result[offset + rightIndex] = partials[rightIndex];
10510 while (++holdersIndex < holdersLength) {
10511 if (isUncurried || argsIndex < argsLength) {
10512 result[offset + holders[holdersIndex]] = args[argsIndex++];
10519 * Copies the values of `source` to `array`.
10522 * @param {Array} source The array to copy values from.
10523 * @param {Array} [array=[]] The array to copy values to.
10524 * @returns {Array} Returns `array`.
10526 function copyArray(source, array) {
10528 length = source.length;
10530 array || (array = Array(length));
10531 while (++index < length) {
10532 array[index] = source[index];
10538 * Copies properties of `source` to `object`.
10541 * @param {Object} source The object to copy properties from.
10542 * @param {Array} props The property identifiers to copy.
10543 * @param {Object} [object={}] The object to copy properties to.
10544 * @param {Function} [customizer] The function to customize copied values.
10545 * @returns {Object} Returns `object`.
10547 function copyObject(source, props, object, customizer) {
10548 object || (object = {});
10551 length = props.length;
10553 while (++index < length) {
10554 var key = props[index];
10556 var newValue = customizer
10557 ? customizer(object[key], source[key], key, object, source)
10560 assignValue(object, key, newValue);
10566 * Copies own symbol properties of `source` to `object`.
10569 * @param {Object} source The object to copy symbols from.
10570 * @param {Object} [object={}] The object to copy symbols to.
10571 * @returns {Object} Returns `object`.
10573 function copySymbols(source, object) {
10574 return copyObject(source, getSymbols(source), object);
10578 * Creates a function like `_.groupBy`.
10581 * @param {Function} setter The function to set accumulator values.
10582 * @param {Function} [initializer] The accumulator object initializer.
10583 * @returns {Function} Returns the new aggregator function.
10585 function createAggregator(setter, initializer) {
10586 return function(collection, iteratee) {
10587 var func = isArray(collection) ? arrayAggregator : baseAggregator,
10588 accumulator = initializer ? initializer() : {};
10590 return func(collection, setter, getIteratee(iteratee), accumulator);
10595 * Creates a function like `_.assign`.
10598 * @param {Function} assigner The function to assign values.
10599 * @returns {Function} Returns the new assigner function.
10601 function createAssigner(assigner) {
10602 return rest(function(object, sources) {
10604 length = sources.length,
10605 customizer = length > 1 ? sources[length - 1] : undefined,
10606 guard = length > 2 ? sources[2] : undefined;
10608 customizer = (assigner.length > 3 && typeof customizer == 'function')
10609 ? (length--, customizer)
10612 if (guard && isIterateeCall(sources[0], sources[1], guard)) {
10613 customizer = length < 3 ? undefined : customizer;
10616 object = Object(object);
10617 while (++index < length) {
10618 var source = sources[index];
10620 assigner(object, source, index, customizer);
10628 * Creates a `baseEach` or `baseEachRight` function.
10631 * @param {Function} eachFunc The function to iterate over a collection.
10632 * @param {boolean} [fromRight] Specify iterating from right to left.
10633 * @returns {Function} Returns the new base function.
10635 function createBaseEach(eachFunc, fromRight) {
10636 return function(collection, iteratee) {
10637 if (collection == null) {
10640 if (!isArrayLike(collection)) {
10641 return eachFunc(collection, iteratee);
10643 var length = collection.length,
10644 index = fromRight ? length : -1,
10645 iterable = Object(collection);
10647 while ((fromRight ? index-- : ++index < length)) {
10648 if (iteratee(iterable[index], index, iterable) === false) {
10657 * Creates a base function for methods like `_.forIn` and `_.forOwn`.
10660 * @param {boolean} [fromRight] Specify iterating from right to left.
10661 * @returns {Function} Returns the new base function.
10663 function createBaseFor(fromRight) {
10664 return function(object, iteratee, keysFunc) {
10666 iterable = Object(object),
10667 props = keysFunc(object),
10668 length = props.length;
10671 var key = props[fromRight ? length : ++index];
10672 if (iteratee(iterable[key], key, iterable) === false) {
10681 * Creates a function that wraps `func` to invoke it with the optional `this`
10682 * binding of `thisArg`.
10685 * @param {Function} func The function to wrap.
10686 * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
10687 * for more details.
10688 * @param {*} [thisArg] The `this` binding of `func`.
10689 * @returns {Function} Returns the new wrapped function.
10691 function createBaseWrapper(func, bitmask, thisArg) {
10692 var isBind = bitmask & BIND_FLAG,
10693 Ctor = createCtorWrapper(func);
10695 function wrapper() {
10696 var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
10697 return fn.apply(isBind ? thisArg : this, arguments);
10703 * Creates a function that produces an instance of `Ctor` regardless of
10704 * whether it was invoked as part of a `new` expression or by `call` or `apply`.
10707 * @param {Function} Ctor The constructor to wrap.
10708 * @returns {Function} Returns the new wrapped function.
10710 function createCtorWrapper(Ctor) {
10711 return function() {
10712 // Use a `switch` statement to work with class constructors. See
10713 // http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
10714 // for more details.
10715 var args = arguments;
10716 switch (args.length) {
10717 case 0: return new Ctor;
10718 case 1: return new Ctor(args[0]);
10719 case 2: return new Ctor(args[0], args[1]);
10720 case 3: return new Ctor(args[0], args[1], args[2]);
10721 case 4: return new Ctor(args[0], args[1], args[2], args[3]);
10722 case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
10723 case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
10724 case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
10726 var thisBinding = baseCreate(Ctor.prototype),
10727 result = Ctor.apply(thisBinding, args);
10729 // Mimic the constructor's `return` behavior.
10730 // See https://es5.github.io/#x13.2.2 for more details.
10731 return isObject(result) ? result : thisBinding;
10736 * Creates a function that wraps `func` to enable currying.
10739 * @param {Function} func The function to wrap.
10740 * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
10741 * for more details.
10742 * @param {number} arity The arity of `func`.
10743 * @returns {Function} Returns the new wrapped function.
10745 function createCurryWrapper(func, bitmask, arity) {
10746 var Ctor = createCtorWrapper(func);
10748 function wrapper() {
10749 var length = arguments.length,
10750 args = Array(length),
10752 placeholder = getHolder(wrapper);
10755 args[index] = arguments[index];
10757 var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
10759 : replaceHolders(args, placeholder);
10761 length -= holders.length;
10762 if (length < arity) {
10763 return createRecurryWrapper(
10764 func, bitmask, createHybridWrapper, wrapper.placeholder, undefined,
10765 args, holders, undefined, undefined, arity - length);
10767 var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
10768 return apply(fn, this, args);
10774 * Creates a function that wraps `func` to invoke it with optional `this`
10775 * binding of `thisArg`, partial application, and currying.
10778 * @param {Function|string} func The function or method name to wrap.
10779 * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
10780 * for more details.
10781 * @param {*} [thisArg] The `this` binding of `func`.
10782 * @param {Array} [partials] The arguments to prepend to those provided to
10783 * the new function.
10784 * @param {Array} [holders] The `partials` placeholder indexes.
10785 * @param {Array} [partialsRight] The arguments to append to those provided
10786 * to the new function.
10787 * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
10788 * @param {Array} [argPos] The argument positions of the new function.
10789 * @param {number} [ary] The arity cap of `func`.
10790 * @param {number} [arity] The arity of `func`.
10791 * @returns {Function} Returns the new wrapped function.
10793 function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
10794 var isAry = bitmask & ARY_FLAG,
10795 isBind = bitmask & BIND_FLAG,
10796 isBindKey = bitmask & BIND_KEY_FLAG,
10797 isCurried = bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG),
10798 isFlip = bitmask & FLIP_FLAG,
10799 Ctor = isBindKey ? undefined : createCtorWrapper(func);
10801 function wrapper() {
10802 var length = arguments.length,
10803 args = Array(length),
10807 args[index] = arguments[index];
10810 var placeholder = getHolder(wrapper),
10811 holdersCount = countHolders(args, placeholder);
10814 args = composeArgs(args, partials, holders, isCurried);
10816 if (partialsRight) {
10817 args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
10819 length -= holdersCount;
10820 if (isCurried && length < arity) {
10821 var newHolders = replaceHolders(args, placeholder);
10822 return createRecurryWrapper(
10823 func, bitmask, createHybridWrapper, wrapper.placeholder, thisArg,
10824 args, newHolders, argPos, ary, arity - length
10827 var thisBinding = isBind ? thisArg : this,
10828 fn = isBindKey ? thisBinding[func] : func;
10830 length = args.length;
10832 args = reorder(args, argPos);
10833 } else if (isFlip && length > 1) {
10836 if (isAry && ary < length) {
10839 if (this && this !== root && this instanceof wrapper) {
10840 fn = Ctor || createCtorWrapper(fn);
10842 return fn.apply(thisBinding, args);
10848 * Creates a function that wraps `func` to invoke it with the `this` binding
10849 * of `thisArg` and `partials` prepended to the arguments it receives.
10852 * @param {Function} func The function to wrap.
10853 * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
10854 * for more details.
10855 * @param {*} thisArg The `this` binding of `func`.
10856 * @param {Array} partials The arguments to prepend to those provided to
10857 * the new function.
10858 * @returns {Function} Returns the new wrapped function.
10860 function createPartialWrapper(func, bitmask, thisArg, partials) {
10861 var isBind = bitmask & BIND_FLAG,
10862 Ctor = createCtorWrapper(func);
10864 function wrapper() {
10865 var argsIndex = -1,
10866 argsLength = arguments.length,
10868 leftLength = partials.length,
10869 args = Array(leftLength + argsLength),
10870 fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
10872 while (++leftIndex < leftLength) {
10873 args[leftIndex] = partials[leftIndex];
10875 while (argsLength--) {
10876 args[leftIndex++] = arguments[++argsIndex];
10878 return apply(fn, isBind ? thisArg : this, args);
10884 * Creates a function that wraps `func` to continue currying.
10887 * @param {Function} func The function to wrap.
10888 * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
10889 * for more details.
10890 * @param {Function} wrapFunc The function to create the `func` wrapper.
10891 * @param {*} placeholder The placeholder value.
10892 * @param {*} [thisArg] The `this` binding of `func`.
10893 * @param {Array} [partials] The arguments to prepend to those provided to
10894 * the new function.
10895 * @param {Array} [holders] The `partials` placeholder indexes.
10896 * @param {Array} [argPos] The argument positions of the new function.
10897 * @param {number} [ary] The arity cap of `func`.
10898 * @param {number} [arity] The arity of `func`.
10899 * @returns {Function} Returns the new wrapped function.
10901 function createRecurryWrapper(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
10902 var isCurry = bitmask & CURRY_FLAG,
10903 newHolders = isCurry ? holders : undefined,
10904 newHoldersRight = isCurry ? undefined : holders,
10905 newPartials = isCurry ? partials : undefined,
10906 newPartialsRight = isCurry ? undefined : partials;
10908 bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
10909 bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
10911 if (!(bitmask & CURRY_BOUND_FLAG)) {
10912 bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
10915 func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
10916 newHoldersRight, argPos, ary, arity
10919 var result = wrapFunc.apply(undefined, newData);
10920 if (isLaziable(func)) {
10921 setData(result, newData);
10923 result.placeholder = placeholder;
10928 * Creates a set of `values`.
10931 * @param {Array} values The values to add to the set.
10932 * @returns {Object} Returns the new set.
10934 var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
10935 return new Set(values);
10939 * Creates a `_.toPairs` or `_.toPairsIn` function.
10942 * @param {Function} keysFunc The function to get the keys of a given object.
10943 * @returns {Function} Returns the new pairs function.
10945 function createToPairs(keysFunc) {
10946 return function(object) {
10947 var tag = getTag(object);
10948 if (tag == mapTag) {
10949 return mapToArray(object);
10951 if (tag == setTag) {
10952 return setToPairs(object);
10954 return baseToPairs(object, keysFunc(object));
10959 * Creates a function that either curries or invokes `func` with optional
10960 * `this` binding and partially applied arguments.
10963 * @param {Function|string} func The function or method name to wrap.
10964 * @param {number} bitmask The bitmask of wrapper flags.
10965 * The bitmask may be composed of the following flags:
10968 * 4 - `_.curry` or `_.curryRight` of a bound function
10970 * 16 - `_.curryRight`
10972 * 64 - `_.partialRight`
10976 * @param {*} [thisArg] The `this` binding of `func`.
10977 * @param {Array} [partials] The arguments to be partially applied.
10978 * @param {Array} [holders] The `partials` placeholder indexes.
10979 * @param {Array} [argPos] The argument positions of the new function.
10980 * @param {number} [ary] The arity cap of `func`.
10981 * @param {number} [arity] The arity of `func`.
10982 * @returns {Function} Returns the new wrapped function.
10984 function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
10985 var isBindKey = bitmask & BIND_KEY_FLAG;
10986 if (!isBindKey && typeof func != 'function') {
10987 throw new TypeError(FUNC_ERROR_TEXT);
10989 var length = partials ? partials.length : 0;
10991 bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
10992 partials = holders = undefined;
10994 ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
10995 arity = arity === undefined ? arity : toInteger(arity);
10996 length -= holders ? holders.length : 0;
10998 if (bitmask & PARTIAL_RIGHT_FLAG) {
10999 var partialsRight = partials,
11000 holdersRight = holders;
11002 partials = holders = undefined;
11004 var data = isBindKey ? undefined : getData(func);
11007 func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
11012 mergeData(newData, data);
11015 bitmask = newData[1];
11016 thisArg = newData[2];
11017 partials = newData[3];
11018 holders = newData[4];
11019 arity = newData[9] = newData[9] == null
11020 ? (isBindKey ? 0 : func.length)
11021 : nativeMax(newData[9] - length, 0);
11023 if (!arity && bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG)) {
11024 bitmask &= ~(CURRY_FLAG | CURRY_RIGHT_FLAG);
11026 if (!bitmask || bitmask == BIND_FLAG) {
11027 var result = createBaseWrapper(func, bitmask, thisArg);
11028 } else if (bitmask == CURRY_FLAG || bitmask == CURRY_RIGHT_FLAG) {
11029 result = createCurryWrapper(func, bitmask, arity);
11030 } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !holders.length) {
11031 result = createPartialWrapper(func, bitmask, thisArg, partials);
11033 result = createHybridWrapper.apply(undefined, newData);
11035 var setter = data ? baseSetData : setData;
11036 return setter(result, newData);
11040 * A specialized version of `baseIsEqualDeep` for arrays with support for
11041 * partial deep comparisons.
11044 * @param {Array} array The array to compare.
11045 * @param {Array} other The other array to compare.
11046 * @param {Function} equalFunc The function to determine equivalents of values.
11047 * @param {Function} customizer The function to customize comparisons.
11048 * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
11049 * for more details.
11050 * @param {Object} stack Tracks traversed `array` and `other` objects.
11051 * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
11053 function equalArrays(array, other, equalFunc, customizer, bitmask, stack) {
11054 var isPartial = bitmask & PARTIAL_COMPARE_FLAG,
11055 arrLength = array.length,
11056 othLength = other.length;
11058 if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
11061 // Assume cyclic values are equal.
11062 var stacked = stack.get(array);
11064 return stacked == other;
11068 seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined;
11070 stack.set(array, other);
11072 // Ignore non-index properties.
11073 while (++index < arrLength) {
11074 var arrValue = array[index],
11075 othValue = other[index];
11078 var compared = isPartial
11079 ? customizer(othValue, arrValue, index, other, array, stack)
11080 : customizer(arrValue, othValue, index, array, other, stack);
11082 if (compared !== undefined) {
11089 // Recursively compare arrays (susceptible to call stack limits).
11091 if (!arraySome(other, function(othValue, othIndex) {
11092 if (!seen.has(othIndex) &&
11093 (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) {
11094 return seen.add(othIndex);
11101 arrValue === othValue ||
11102 equalFunc(arrValue, othValue, customizer, bitmask, stack)
11108 stack['delete'](array);
11113 * A specialized version of `baseIsEqualDeep` for comparing objects of
11114 * the same `toStringTag`.
11116 * **Note:** This function only supports comparing values with tags of
11117 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
11120 * @param {Object} object The object to compare.
11121 * @param {Object} other The other object to compare.
11122 * @param {string} tag The `toStringTag` of the objects to compare.
11123 * @param {Function} equalFunc The function to determine equivalents of values.
11124 * @param {Function} customizer The function to customize comparisons.
11125 * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
11126 * for more details.
11127 * @param {Object} stack Tracks traversed `object` and `other` objects.
11128 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
11130 function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) {
11133 if ((object.byteLength != other.byteLength) ||
11134 (object.byteOffset != other.byteOffset)) {
11137 object = object.buffer;
11138 other = other.buffer;
11140 case arrayBufferTag:
11141 if ((object.byteLength != other.byteLength) ||
11142 !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
11149 // Coerce dates and booleans to numbers, dates to milliseconds and
11150 // booleans to `1` or `0` treating invalid dates coerced to `NaN` as
11152 return +object == +other;
11155 return object.name == other.name && object.message == other.message;
11158 // Treat `NaN` vs. `NaN` as equal.
11159 return (object != +object) ? other != +other : object == +other;
11163 // Coerce regexes to strings and treat strings, primitives and objects,
11164 // as equal. See http://www.ecma-international.org/ecma-262/6.0/#sec-regexp.prototype.tostring
11165 // for more details.
11166 return object == (other + '');
11169 var convert = mapToArray;
11172 var isPartial = bitmask & PARTIAL_COMPARE_FLAG;
11173 convert || (convert = setToArray);
11175 if (object.size != other.size && !isPartial) {
11178 // Assume cyclic values are equal.
11179 var stacked = stack.get(object);
11181 return stacked == other;
11183 bitmask |= UNORDERED_COMPARE_FLAG;
11184 stack.set(object, other);
11186 // Recursively compare objects (susceptible to call stack limits).
11187 return equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack);
11190 if (symbolValueOf) {
11191 return symbolValueOf.call(object) == symbolValueOf.call(other);
11198 * A specialized version of `baseIsEqualDeep` for objects with support for
11199 * partial deep comparisons.
11202 * @param {Object} object The object to compare.
11203 * @param {Object} other The other object to compare.
11204 * @param {Function} equalFunc The function to determine equivalents of values.
11205 * @param {Function} customizer The function to customize comparisons.
11206 * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
11207 * for more details.
11208 * @param {Object} stack Tracks traversed `object` and `other` objects.
11209 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
11211 function equalObjects(object, other, equalFunc, customizer, bitmask, stack) {
11212 var isPartial = bitmask & PARTIAL_COMPARE_FLAG,
11213 objProps = keys(object),
11214 objLength = objProps.length,
11215 othProps = keys(other),
11216 othLength = othProps.length;
11218 if (objLength != othLength && !isPartial) {
11221 var index = objLength;
11223 var key = objProps[index];
11224 if (!(isPartial ? key in other : baseHas(other, key))) {
11228 // Assume cyclic values are equal.
11229 var stacked = stack.get(object);
11231 return stacked == other;
11234 stack.set(object, other);
11236 var skipCtor = isPartial;
11237 while (++index < objLength) {
11238 key = objProps[index];
11239 var objValue = object[key],
11240 othValue = other[key];
11243 var compared = isPartial
11244 ? customizer(othValue, objValue, key, other, object, stack)
11245 : customizer(objValue, othValue, key, object, other, stack);
11247 // Recursively compare objects (susceptible to call stack limits).
11248 if (!(compared === undefined
11249 ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack))
11255 skipCtor || (skipCtor = key == 'constructor');
11257 if (result && !skipCtor) {
11258 var objCtor = object.constructor,
11259 othCtor = other.constructor;
11261 // Non `Object` object instances with different constructors are not equal.
11262 if (objCtor != othCtor &&
11263 ('constructor' in object && 'constructor' in other) &&
11264 !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
11265 typeof othCtor == 'function' && othCtor instanceof othCtor)) {
11269 stack['delete'](object);
11274 * Creates an array of own enumerable property names and symbols of `object`.
11277 * @param {Object} object The object to query.
11278 * @returns {Array} Returns the array of property names and symbols.
11280 function getAllKeys(object) {
11281 return baseGetAllKeys(object, keys, getSymbols);
11285 * Creates an array of own and inherited enumerable property names and
11286 * symbols of `object`.
11289 * @param {Object} object The object to query.
11290 * @returns {Array} Returns the array of property names and symbols.
11292 function getAllKeysIn(object) {
11293 return baseGetAllKeys(object, keysIn, getSymbolsIn);
11297 * Gets metadata for `func`.
11300 * @param {Function} func The function to query.
11301 * @returns {*} Returns the metadata for `func`.
11303 var getData = !metaMap ? noop : function(func) {
11304 return metaMap.get(func);
11308 * Gets the name of `func`.
11311 * @param {Function} func The function to query.
11312 * @returns {string} Returns the function name.
11314 function getFuncName(func) {
11315 var result = (func.name + ''),
11316 array = realNames[result],
11317 length = hasOwnProperty.call(realNames, result) ? array.length : 0;
11320 var data = array[length],
11321 otherFunc = data.func;
11322 if (otherFunc == null || otherFunc == func) {
11330 * Gets the argument placeholder value for `func`.
11333 * @param {Function} func The function to inspect.
11334 * @returns {*} Returns the placeholder value.
11336 function getHolder(func) {
11337 var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
11338 return object.placeholder;
11342 * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
11343 * this function returns the custom method, otherwise it returns `baseIteratee`.
11344 * If arguments are provided, the chosen function is invoked with them and
11345 * its result is returned.
11348 * @param {*} [value] The value to convert to an iteratee.
11349 * @param {number} [arity] The arity of the created iteratee.
11350 * @returns {Function} Returns the chosen function or its result.
11352 function getIteratee() {
11353 var result = lodash.iteratee || iteratee;
11354 result = result === iteratee ? baseIteratee : result;
11355 return arguments.length ? result(arguments[0], arguments[1]) : result;
11359 * Gets the "length" property value of `object`.
11361 * **Note:** This function is used to avoid a
11362 * [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) that affects
11363 * Safari on at least iOS 8.1-8.3 ARM64.
11366 * @param {Object} object The object to query.
11367 * @returns {*} Returns the "length" value.
11369 var getLength = baseProperty('length');
11372 * Gets the data for `map`.
11375 * @param {Object} map The map to query.
11376 * @param {string} key The reference key.
11377 * @returns {*} Returns the map data.
11379 function getMapData(map, key) {
11380 var data = map.__data__;
11381 return isKeyable(key)
11382 ? data[typeof key == 'string' ? 'string' : 'hash']
11387 * Gets the property names, values, and compare flags of `object`.
11390 * @param {Object} object The object to query.
11391 * @returns {Array} Returns the match data of `object`.
11393 function getMatchData(object) {
11394 var result = toPairs(object),
11395 length = result.length;
11398 result[length][2] = isStrictComparable(result[length][1]);
11404 * Gets the native function at `key` of `object`.
11407 * @param {Object} object The object to query.
11408 * @param {string} key The key of the method to get.
11409 * @returns {*} Returns the function if it's native, else `undefined`.
11411 function getNative(object, key) {
11412 var value = object[key];
11413 return isNative(value) ? value : undefined;
11417 * Gets the `[[Prototype]]` of `value`.
11420 * @param {*} value The value to query.
11421 * @returns {null|Object} Returns the `[[Prototype]]`.
11423 function getPrototype(value) {
11424 return nativeGetPrototype(Object(value));
11428 * Creates an array of the own enumerable symbol properties of `object`.
11431 * @param {Object} object The object to query.
11432 * @returns {Array} Returns the array of symbols.
11434 function getSymbols(object) {
11435 // Coerce `object` to an object to avoid non-object errors in V8.
11436 // See https://bugs.chromium.org/p/v8/issues/detail?id=3443 for more details.
11437 return getOwnPropertySymbols(Object(object));
11440 // Fallback for IE < 11.
11441 if (!getOwnPropertySymbols) {
11442 getSymbols = function() {
11448 * Creates an array of the own and inherited enumerable symbol properties
11452 * @param {Object} object The object to query.
11453 * @returns {Array} Returns the array of symbols.
11455 var getSymbolsIn = !getOwnPropertySymbols ? getSymbols : function(object) {
11458 arrayPush(result, getSymbols(object));
11459 object = getPrototype(object);
11465 * Gets the `toStringTag` of `value`.
11468 * @param {*} value The value to query.
11469 * @returns {string} Returns the `toStringTag`.
11471 function getTag(value) {
11472 return objectToString.call(value);
11475 // Fallback for data views, maps, sets, and weak maps in IE 11,
11476 // for data views in Edge, and promises in Node.js.
11477 if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
11478 (Map && getTag(new Map) != mapTag) ||
11479 (Promise && getTag(Promise.resolve()) != promiseTag) ||
11480 (Set && getTag(new Set) != setTag) ||
11481 (WeakMap && getTag(new WeakMap) != weakMapTag)) {
11482 getTag = function(value) {
11483 var result = objectToString.call(value),
11484 Ctor = result == objectTag ? value.constructor : undefined,
11485 ctorString = Ctor ? toSource(Ctor) : undefined;
11488 switch (ctorString) {
11489 case dataViewCtorString: return dataViewTag;
11490 case mapCtorString: return mapTag;
11491 case promiseCtorString: return promiseTag;
11492 case setCtorString: return setTag;
11493 case weakMapCtorString: return weakMapTag;
11501 * Gets the view, applying any `transforms` to the `start` and `end` positions.
11504 * @param {number} start The start of the view.
11505 * @param {number} end The end of the view.
11506 * @param {Array} transforms The transformations to apply to the view.
11507 * @returns {Object} Returns an object containing the `start` and `end`
11508 * positions of the view.
11510 function getView(start, end, transforms) {
11512 length = transforms.length;
11514 while (++index < length) {
11515 var data = transforms[index],
11518 switch (data.type) {
11519 case 'drop': start += size; break;
11520 case 'dropRight': end -= size; break;
11521 case 'take': end = nativeMin(end, start + size); break;
11522 case 'takeRight': start = nativeMax(start, end - size); break;
11525 return { 'start': start, 'end': end };
11529 * Checks if `path` exists on `object`.
11532 * @param {Object} object The object to query.
11533 * @param {Array|string} path The path to check.
11534 * @param {Function} hasFunc The function to check properties.
11535 * @returns {boolean} Returns `true` if `path` exists, else `false`.
11537 function hasPath(object, path, hasFunc) {
11538 path = isKey(path, object) ? [path] : castPath(path);
11542 length = path.length;
11544 while (++index < length) {
11545 var key = toKey(path[index]);
11546 if (!(result = object != null && hasFunc(object, key))) {
11549 object = object[key];
11554 var length = object ? object.length : 0;
11555 return !!length && isLength(length) && isIndex(key, length) &&
11556 (isArray(object) || isString(object) || isArguments(object));
11560 * Initializes an array clone.
11563 * @param {Array} array The array to clone.
11564 * @returns {Array} Returns the initialized clone.
11566 function initCloneArray(array) {
11567 var length = array.length,
11568 result = array.constructor(length);
11570 // Add properties assigned by `RegExp#exec`.
11571 if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
11572 result.index = array.index;
11573 result.input = array.input;
11579 * Initializes an object clone.
11582 * @param {Object} object The object to clone.
11583 * @returns {Object} Returns the initialized clone.
11585 function initCloneObject(object) {
11586 return (typeof object.constructor == 'function' && !isPrototype(object))
11587 ? baseCreate(getPrototype(object))
11592 * Initializes an object clone based on its `toStringTag`.
11594 * **Note:** This function only supports cloning values with tags of
11595 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
11598 * @param {Object} object The object to clone.
11599 * @param {string} tag The `toStringTag` of the object to clone.
11600 * @param {Function} cloneFunc The function to clone values.
11601 * @param {boolean} [isDeep] Specify a deep clone.
11602 * @returns {Object} Returns the initialized clone.
11604 function initCloneByTag(object, tag, cloneFunc, isDeep) {
11605 var Ctor = object.constructor;
11607 case arrayBufferTag:
11608 return cloneArrayBuffer(object);
11612 return new Ctor(+object);
11615 return cloneDataView(object, isDeep);
11617 case float32Tag: case float64Tag:
11618 case int8Tag: case int16Tag: case int32Tag:
11619 case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
11620 return cloneTypedArray(object, isDeep);
11623 return cloneMap(object, isDeep, cloneFunc);
11627 return new Ctor(object);
11630 return cloneRegExp(object);
11633 return cloneSet(object, isDeep, cloneFunc);
11636 return cloneSymbol(object);
11641 * Creates an array of index keys for `object` values of arrays,
11642 * `arguments` objects, and strings, otherwise `null` is returned.
11645 * @param {Object} object The object to query.
11646 * @returns {Array|null} Returns index keys, else `null`.
11648 function indexKeys(object) {
11649 var length = object ? object.length : undefined;
11650 if (isLength(length) &&
11651 (isArray(object) || isString(object) || isArguments(object))) {
11652 return baseTimes(length, String);
11658 * Checks if `value` is a flattenable `arguments` object or array.
11661 * @param {*} value The value to check.
11662 * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
11664 function isFlattenable(value) {
11665 return isArray(value) || isArguments(value);
11669 * Checks if `value` is a valid array-like index.
11672 * @param {*} value The value to check.
11673 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
11674 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
11676 function isIndex(value, length) {
11677 length = length == null ? MAX_SAFE_INTEGER : length;
11679 (typeof value == 'number' || reIsUint.test(value)) &&
11680 (value > -1 && value % 1 == 0 && value < length);
11684 * Checks if the given arguments are from an iteratee call.
11687 * @param {*} value The potential iteratee value argument.
11688 * @param {*} index The potential iteratee index or key argument.
11689 * @param {*} object The potential iteratee object argument.
11690 * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
11693 function isIterateeCall(value, index, object) {
11694 if (!isObject(object)) {
11697 var type = typeof index;
11698 if (type == 'number'
11699 ? (isArrayLike(object) && isIndex(index, object.length))
11700 : (type == 'string' && index in object)
11702 return eq(object[index], value);
11708 * Checks if `value` is a property name and not a property path.
11711 * @param {*} value The value to check.
11712 * @param {Object} [object] The object to query keys on.
11713 * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
11715 function isKey(value, object) {
11716 if (isArray(value)) {
11719 var type = typeof value;
11720 if (type == 'number' || type == 'symbol' || type == 'boolean' ||
11721 value == null || isSymbol(value)) {
11724 return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
11725 (object != null && value in Object(object));
11729 * Checks if `value` is suitable for use as unique object key.
11732 * @param {*} value The value to check.
11733 * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
11735 function isKeyable(value) {
11736 var type = typeof value;
11737 return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
11738 ? (value !== '__proto__')
11739 : (value === null);
11743 * Checks if `func` has a lazy counterpart.
11746 * @param {Function} func The function to check.
11747 * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
11750 function isLaziable(func) {
11751 var funcName = getFuncName(func),
11752 other = lodash[funcName];
11754 if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
11757 if (func === other) {
11760 var data = getData(other);
11761 return !!data && func === data[0];
11765 * Checks if `value` is likely a prototype object.
11768 * @param {*} value The value to check.
11769 * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
11771 function isPrototype(value) {
11772 var Ctor = value && value.constructor,
11773 proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
11775 return value === proto;
11779 * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
11782 * @param {*} value The value to check.
11783 * @returns {boolean} Returns `true` if `value` if suitable for strict
11784 * equality comparisons, else `false`.
11786 function isStrictComparable(value) {
11787 return value === value && !isObject(value);
11791 * A specialized version of `matchesProperty` for source values suitable
11792 * for strict equality comparisons, i.e. `===`.
11795 * @param {string} key The key of the property to get.
11796 * @param {*} srcValue The value to match.
11797 * @returns {Function} Returns the new spec function.
11799 function matchesStrictComparable(key, srcValue) {
11800 return function(object) {
11801 if (object == null) {
11804 return object[key] === srcValue &&
11805 (srcValue !== undefined || (key in Object(object)));
11810 * Merges the function metadata of `source` into `data`.
11812 * Merging metadata reduces the number of wrappers used to invoke a function.
11813 * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
11814 * may be applied regardless of execution order. Methods like `_.ary` and
11815 * `_.rearg` modify function arguments, making the order in which they are
11816 * executed important, preventing the merging of metadata. However, we make
11817 * an exception for a safe combined case where curried functions have `_.ary`
11818 * and or `_.rearg` applied.
11821 * @param {Array} data The destination metadata.
11822 * @param {Array} source The source metadata.
11823 * @returns {Array} Returns `data`.
11825 function mergeData(data, source) {
11826 var bitmask = data[1],
11827 srcBitmask = source[1],
11828 newBitmask = bitmask | srcBitmask,
11829 isCommon = newBitmask < (BIND_FLAG | BIND_KEY_FLAG | ARY_FLAG);
11832 ((srcBitmask == ARY_FLAG) && (bitmask == CURRY_FLAG)) ||
11833 ((srcBitmask == ARY_FLAG) && (bitmask == REARG_FLAG) && (data[7].length <= source[8])) ||
11834 ((srcBitmask == (ARY_FLAG | REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == CURRY_FLAG));
11836 // Exit early if metadata can't be merged.
11837 if (!(isCommon || isCombo)) {
11840 // Use source `thisArg` if available.
11841 if (srcBitmask & BIND_FLAG) {
11842 data[2] = source[2];
11843 // Set when currying a bound function.
11844 newBitmask |= bitmask & BIND_FLAG ? 0 : CURRY_BOUND_FLAG;
11846 // Compose partial arguments.
11847 var value = source[3];
11849 var partials = data[3];
11850 data[3] = partials ? composeArgs(partials, value, source[4]) : value;
11851 data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
11853 // Compose partial right arguments.
11856 partials = data[5];
11857 data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
11858 data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
11860 // Use source `argPos` if available.
11865 // Use source `ary` if it's smaller.
11866 if (srcBitmask & ARY_FLAG) {
11867 data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
11869 // Use source `arity` if one is not provided.
11870 if (data[9] == null) {
11871 data[9] = source[9];
11873 // Use source `func` and merge bitmasks.
11874 data[0] = source[0];
11875 data[1] = newBitmask;
11881 * Gets the parent value at `path` of `object`.
11884 * @param {Object} object The object to query.
11885 * @param {Array} path The path to get the parent value of.
11886 * @returns {*} Returns the parent value.
11888 function parent(object, path) {
11889 return path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
11893 * Reorder `array` according to the specified indexes where the element at
11894 * the first index is assigned as the first element, the element at
11895 * the second index is assigned as the second element, and so on.
11898 * @param {Array} array The array to reorder.
11899 * @param {Array} indexes The arranged array indexes.
11900 * @returns {Array} Returns `array`.
11902 function reorder(array, indexes) {
11903 var arrLength = array.length,
11904 length = nativeMin(indexes.length, arrLength),
11905 oldArray = copyArray(array);
11908 var index = indexes[length];
11909 array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
11915 * Sets metadata for `func`.
11917 * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
11918 * period of time, it will trip its breaker and transition to an identity
11919 * function to avoid garbage collection pauses in V8. See
11920 * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
11921 * for more details.
11924 * @param {Function} func The function to associate metadata with.
11925 * @param {*} data The metadata.
11926 * @returns {Function} Returns `func`.
11928 var setData = (function() {
11932 return function(key, value) {
11934 remaining = HOT_SPAN - (stamp - lastCalled);
11936 lastCalled = stamp;
11937 if (remaining > 0) {
11938 if (++count >= HOT_COUNT) {
11944 return baseSetData(key, value);
11949 * Converts `string` to a property path array.
11952 * @param {string} string The string to convert.
11953 * @returns {Array} Returns the property path array.
11955 var stringToPath = memoize(function(string) {
11957 toString(string).replace(rePropName, function(match, number, quote, string) {
11958 result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
11964 * Converts `value` to a string key if it's not a string or symbol.
11967 * @param {*} value The value to inspect.
11968 * @returns {string|symbol} Returns the key.
11970 function toKey(value) {
11971 if (typeof value == 'string' || isSymbol(value)) {
11974 var result = (value + '');
11975 return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
11979 * Converts `func` to its source code.
11982 * @param {Function} func The function to process.
11983 * @returns {string} Returns the source code.
11985 function toSource(func) {
11986 if (func != null) {
11988 return funcToString.call(func);
11991 return (func + '');
11998 * Creates a clone of `wrapper`.
12001 * @param {Object} wrapper The wrapper to clone.
12002 * @returns {Object} Returns the cloned wrapper.
12004 function wrapperClone(wrapper) {
12005 if (wrapper instanceof LazyWrapper) {
12006 return wrapper.clone();
12008 var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
12009 result.__actions__ = copyArray(wrapper.__actions__);
12010 result.__index__ = wrapper.__index__;
12011 result.__values__ = wrapper.__values__;
12015 /*------------------------------------------------------------------------*/
12018 * Creates an array of elements split into groups the length of `size`.
12019 * If `array` can't be split evenly, the final chunk will be the remaining
12026 * @param {Array} array The array to process.
12027 * @param {number} [size=1] The length of each chunk
12028 * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
12029 * @returns {Array} Returns the new array of chunks.
12032 * _.chunk(['a', 'b', 'c', 'd'], 2);
12033 * // => [['a', 'b'], ['c', 'd']]
12035 * _.chunk(['a', 'b', 'c', 'd'], 3);
12036 * // => [['a', 'b', 'c'], ['d']]
12038 function chunk(array, size, guard) {
12039 if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
12042 size = nativeMax(toInteger(size), 0);
12044 var length = array ? array.length : 0;
12045 if (!length || size < 1) {
12050 result = Array(nativeCeil(length / size));
12052 while (index < length) {
12053 result[resIndex++] = baseSlice(array, index, (index += size));
12059 * Creates an array with all falsey values removed. The values `false`, `null`,
12060 * `0`, `""`, `undefined`, and `NaN` are falsey.
12066 * @param {Array} array The array to compact.
12067 * @returns {Array} Returns the new array of filtered values.
12070 * _.compact([0, 1, false, 2, '', 3]);
12073 function compact(array) {
12075 length = array ? array.length : 0,
12079 while (++index < length) {
12080 var value = array[index];
12082 result[resIndex++] = value;
12089 * Creates an array of unique `array` values not included in the other given
12090 * arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12091 * for equality comparisons. The order of result values is determined by the
12092 * order they occur in the first array.
12098 * @param {Array} array The array to inspect.
12099 * @param {...Array} [values] The values to exclude.
12100 * @returns {Array} Returns the new array of filtered values.
12101 * @see _.without, _.xor
12104 * _.difference([3, 2, 1], [4, 2]);
12107 var difference = rest(function(array, values) {
12108 return isArrayLikeObject(array)
12109 ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
12114 * Flattens `array` a single level deep.
12120 * @param {Array} array The array to flatten.
12121 * @returns {Array} Returns the new flattened array.
12124 * _.flatten([1, [2, [3, [4]], 5]]);
12125 * // => [1, 2, [3, [4]], 5]
12127 function flatten(array) {
12128 var length = array ? array.length : 0;
12129 return length ? baseFlatten(array, 1) : [];
12133 * Gets the first element of `array`.
12140 * @param {Array} array The array to query.
12141 * @returns {*} Returns the first element of `array`.
12144 * _.head([1, 2, 3]);
12150 function head(array) {
12151 return (array && array.length) ? array[0] : undefined;
12155 * Gets the index at which the first occurrence of `value` is found in `array`
12156 * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12157 * for equality comparisons. If `fromIndex` is negative, it's used as the
12158 * offset from the end of `array`.
12164 * @param {Array} array The array to search.
12165 * @param {*} value The value to search for.
12166 * @param {number} [fromIndex=0] The index to search from.
12167 * @returns {number} Returns the index of the matched value, else `-1`.
12170 * _.indexOf([1, 2, 1, 2], 2);
12173 * // Search from the `fromIndex`.
12174 * _.indexOf([1, 2, 1, 2], 2, 2);
12177 function indexOf(array, value, fromIndex) {
12178 var length = array ? array.length : 0;
12182 fromIndex = toInteger(fromIndex);
12183 if (fromIndex < 0) {
12184 fromIndex = nativeMax(length + fromIndex, 0);
12186 return baseIndexOf(array, value, fromIndex);
12190 * Creates an array of unique values that are included in all given arrays
12191 * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12192 * for equality comparisons. The order of result values is determined by the
12193 * order they occur in the first array.
12199 * @param {...Array} [arrays] The arrays to inspect.
12200 * @returns {Array} Returns the new array of intersecting values.
12203 * _.intersection([2, 1], [4, 2], [1, 2]);
12206 var intersection = rest(function(arrays) {
12207 var mapped = arrayMap(arrays, castArrayLikeObject);
12208 return (mapped.length && mapped[0] === arrays[0])
12209 ? baseIntersection(mapped)
12214 * Gets the last element of `array`.
12220 * @param {Array} array The array to query.
12221 * @returns {*} Returns the last element of `array`.
12224 * _.last([1, 2, 3]);
12227 function last(array) {
12228 var length = array ? array.length : 0;
12229 return length ? array[length - 1] : undefined;
12233 * Reverses `array` so that the first element becomes the last, the second
12234 * element becomes the second to last, and so on.
12236 * **Note:** This method mutates `array` and is based on
12237 * [`Array#reverse`](https://mdn.io/Array/reverse).
12243 * @param {Array} array The array to modify.
12244 * @returns {Array} Returns `array`.
12247 * var array = [1, 2, 3];
12249 * _.reverse(array);
12252 * console.log(array);
12255 function reverse(array) {
12256 return array ? nativeReverse.call(array) : array;
12260 * Creates an array of unique values, in order, from all given arrays using
12261 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12262 * for equality comparisons.
12268 * @param {...Array} [arrays] The arrays to inspect.
12269 * @returns {Array} Returns the new array of combined values.
12272 * _.union([2, 1], [4, 2], [1, 2]);
12275 var union = rest(function(arrays) {
12276 return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
12280 * Creates a duplicate-free version of an array, using
12281 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12282 * for equality comparisons, in which only the first occurrence of each
12289 * @param {Array} array The array to inspect.
12290 * @returns {Array} Returns the new duplicate free array.
12293 * _.uniq([2, 1, 2]);
12296 function uniq(array) {
12297 return (array && array.length)
12303 * Creates an array excluding all given values using
12304 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12305 * for equality comparisons.
12311 * @param {Array} array The array to inspect.
12312 * @param {...*} [values] The values to exclude.
12313 * @returns {Array} Returns the new array of filtered values.
12314 * @see _.difference, _.xor
12317 * _.without([1, 2, 1, 3], 1, 2);
12320 var without = rest(function(array, values) {
12321 return isArrayLikeObject(array)
12322 ? baseDifference(array, values)
12326 /*------------------------------------------------------------------------*/
12329 * Creates a `lodash` wrapper instance that wraps `value` with explicit method
12330 * chain sequences enabled. The result of such sequences must be unwrapped
12337 * @param {*} value The value to wrap.
12338 * @returns {Object} Returns the new `lodash` wrapper instance.
12342 * { 'user': 'barney', 'age': 36 },
12343 * { 'user': 'fred', 'age': 40 },
12344 * { 'user': 'pebbles', 'age': 1 }
12350 * .map(function(o) {
12351 * return o.user + ' is ' + o.age;
12355 * // => 'pebbles is 1'
12357 function chain(value) {
12358 var result = lodash(value);
12359 result.__chain__ = true;
12364 * This method invokes `interceptor` and returns `value`. The interceptor
12365 * is invoked with one argument; (value). The purpose of this method is to
12366 * "tap into" a method chain sequence in order to modify intermediate results.
12372 * @param {*} value The value to provide to `interceptor`.
12373 * @param {Function} interceptor The function to invoke.
12374 * @returns {*} Returns `value`.
12378 * .tap(function(array) {
12379 * // Mutate input array.
12386 function tap(value, interceptor) {
12387 interceptor(value);
12392 * This method is like `_.tap` except that it returns the result of `interceptor`.
12393 * The purpose of this method is to "pass thru" values replacing intermediate
12394 * results in a method chain sequence.
12400 * @param {*} value The value to provide to `interceptor`.
12401 * @param {Function} interceptor The function to invoke.
12402 * @returns {*} Returns the result of `interceptor`.
12408 * .thru(function(value) {
12414 function thru(value, interceptor) {
12415 return interceptor(value);
12419 * This method is the wrapper version of `_.at`.
12425 * @param {...(string|string[])} [paths] The property paths of elements to pick.
12426 * @returns {Object} Returns the new `lodash` wrapper instance.
12429 * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
12431 * _(object).at(['a[0].b.c', 'a[1]']).value();
12434 * _(['a', 'b', 'c']).at(0, 2).value();
12437 var wrapperAt = rest(function(paths) {
12438 paths = baseFlatten(paths, 1);
12439 var length = paths.length,
12440 start = length ? paths[0] : 0,
12441 value = this.__wrapped__,
12442 interceptor = function(object) { return baseAt(object, paths); };
12444 if (length > 1 || this.__actions__.length ||
12445 !(value instanceof LazyWrapper) || !isIndex(start)) {
12446 return this.thru(interceptor);
12448 value = value.slice(start, +start + (length ? 1 : 0));
12449 value.__actions__.push({
12451 'args': [interceptor],
12452 'thisArg': undefined
12454 return new LodashWrapper(value, this.__chain__).thru(function(array) {
12455 if (length && !array.length) {
12456 array.push(undefined);
12463 * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
12469 * @returns {Object} Returns the new `lodash` wrapper instance.
12473 * { 'user': 'barney', 'age': 36 },
12474 * { 'user': 'fred', 'age': 40 }
12477 * // A sequence without explicit chaining.
12479 * // => { 'user': 'barney', 'age': 36 }
12481 * // A sequence with explicit chaining.
12487 * // => { 'user': 'barney' }
12489 function wrapperChain() {
12490 return chain(this);
12494 * Executes the chain sequence and returns the wrapped result.
12500 * @returns {Object} Returns the new `lodash` wrapper instance.
12503 * var array = [1, 2];
12504 * var wrapped = _(array).push(3);
12506 * console.log(array);
12509 * wrapped = wrapped.commit();
12510 * console.log(array);
12516 * console.log(array);
12519 function wrapperCommit() {
12520 return new LodashWrapper(this.value(), this.__chain__);
12524 * Gets the next value on a wrapped object following the
12525 * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
12531 * @returns {Object} Returns the next iterator value.
12534 * var wrapped = _([1, 2]);
12537 * // => { 'done': false, 'value': 1 }
12540 * // => { 'done': false, 'value': 2 }
12543 * // => { 'done': true, 'value': undefined }
12545 function wrapperNext() {
12546 if (this.__values__ === undefined) {
12547 this.__values__ = toArray(this.value());
12549 var done = this.__index__ >= this.__values__.length,
12550 value = done ? undefined : this.__values__[this.__index__++];
12552 return { 'done': done, 'value': value };
12556 * Enables the wrapper to be iterable.
12558 * @name Symbol.iterator
12562 * @returns {Object} Returns the wrapper object.
12565 * var wrapped = _([1, 2]);
12567 * wrapped[Symbol.iterator]() === wrapped;
12570 * Array.from(wrapped);
12573 function wrapperToIterator() {
12578 * Creates a clone of the chain sequence planting `value` as the wrapped value.
12584 * @param {*} value The value to plant.
12585 * @returns {Object} Returns the new `lodash` wrapper instance.
12588 * function square(n) {
12592 * var wrapped = _([1, 2]).map(square);
12593 * var other = wrapped.plant([3, 4]);
12601 function wrapperPlant(value) {
12605 while (parent instanceof baseLodash) {
12606 var clone = wrapperClone(parent);
12607 clone.__index__ = 0;
12608 clone.__values__ = undefined;
12610 previous.__wrapped__ = clone;
12614 var previous = clone;
12615 parent = parent.__wrapped__;
12617 previous.__wrapped__ = value;
12622 * This method is the wrapper version of `_.reverse`.
12624 * **Note:** This method mutates the wrapped array.
12630 * @returns {Object} Returns the new `lodash` wrapper instance.
12633 * var array = [1, 2, 3];
12635 * _(array).reverse().value()
12638 * console.log(array);
12641 function wrapperReverse() {
12642 var value = this.__wrapped__;
12643 if (value instanceof LazyWrapper) {
12644 var wrapped = value;
12645 if (this.__actions__.length) {
12646 wrapped = new LazyWrapper(this);
12648 wrapped = wrapped.reverse();
12649 wrapped.__actions__.push({
12652 'thisArg': undefined
12654 return new LodashWrapper(wrapped, this.__chain__);
12656 return this.thru(reverse);
12660 * Executes the chain sequence to resolve the unwrapped value.
12665 * @alias toJSON, valueOf
12667 * @returns {*} Returns the resolved unwrapped value.
12670 * _([1, 2, 3]).value();
12673 function wrapperValue() {
12674 return baseWrapperValue(this.__wrapped__, this.__actions__);
12677 /*------------------------------------------------------------------------*/
12680 * Checks if `predicate` returns truthy for **all** elements of `collection`.
12681 * Iteration is stopped once `predicate` returns falsey. The predicate is
12682 * invoked with three arguments: (value, index|key, collection).
12687 * @category Collection
12688 * @param {Array|Object} collection The collection to iterate over.
12689 * @param {Array|Function|Object|string} [predicate=_.identity]
12690 * The function invoked per iteration.
12691 * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
12692 * @returns {boolean} Returns `true` if all elements pass the predicate check,
12696 * _.every([true, 1, null, 'yes'], Boolean);
12700 * { 'user': 'barney', 'age': 36, 'active': false },
12701 * { 'user': 'fred', 'age': 40, 'active': false }
12704 * // The `_.matches` iteratee shorthand.
12705 * _.every(users, { 'user': 'barney', 'active': false });
12708 * // The `_.matchesProperty` iteratee shorthand.
12709 * _.every(users, ['active', false]);
12712 * // The `_.property` iteratee shorthand.
12713 * _.every(users, 'active');
12716 function every(collection, predicate, guard) {
12717 var func = isArray(collection) ? arrayEvery : baseEvery;
12718 if (guard && isIterateeCall(collection, predicate, guard)) {
12719 predicate = undefined;
12721 return func(collection, getIteratee(predicate, 3));
12725 * Iterates over elements of `collection`, returning an array of all elements
12726 * `predicate` returns truthy for. The predicate is invoked with three
12727 * arguments: (value, index|key, collection).
12732 * @category Collection
12733 * @param {Array|Object} collection The collection to iterate over.
12734 * @param {Array|Function|Object|string} [predicate=_.identity]
12735 * The function invoked per iteration.
12736 * @returns {Array} Returns the new filtered array.
12741 * { 'user': 'barney', 'age': 36, 'active': true },
12742 * { 'user': 'fred', 'age': 40, 'active': false }
12745 * _.filter(users, function(o) { return !o.active; });
12746 * // => objects for ['fred']
12748 * // The `_.matches` iteratee shorthand.
12749 * _.filter(users, { 'age': 36, 'active': true });
12750 * // => objects for ['barney']
12752 * // The `_.matchesProperty` iteratee shorthand.
12753 * _.filter(users, ['active', false]);
12754 * // => objects for ['fred']
12756 * // The `_.property` iteratee shorthand.
12757 * _.filter(users, 'active');
12758 * // => objects for ['barney']
12760 function filter(collection, predicate) {
12761 var func = isArray(collection) ? arrayFilter : baseFilter;
12762 return func(collection, getIteratee(predicate, 3));
12766 * Iterates over elements of `collection`, returning the first element
12767 * `predicate` returns truthy for. The predicate is invoked with three
12768 * arguments: (value, index|key, collection).
12773 * @category Collection
12774 * @param {Array|Object} collection The collection to search.
12775 * @param {Array|Function|Object|string} [predicate=_.identity]
12776 * The function invoked per iteration.
12777 * @returns {*} Returns the matched element, else `undefined`.
12781 * { 'user': 'barney', 'age': 36, 'active': true },
12782 * { 'user': 'fred', 'age': 40, 'active': false },
12783 * { 'user': 'pebbles', 'age': 1, 'active': true }
12786 * _.find(users, function(o) { return o.age < 40; });
12787 * // => object for 'barney'
12789 * // The `_.matches` iteratee shorthand.
12790 * _.find(users, { 'age': 1, 'active': true });
12791 * // => object for 'pebbles'
12793 * // The `_.matchesProperty` iteratee shorthand.
12794 * _.find(users, ['active', false]);
12795 * // => object for 'fred'
12797 * // The `_.property` iteratee shorthand.
12798 * _.find(users, 'active');
12799 * // => object for 'barney'
12801 function find(collection, predicate) {
12802 predicate = getIteratee(predicate, 3);
12803 if (isArray(collection)) {
12804 var index = baseFindIndex(collection, predicate);
12805 return index > -1 ? collection[index] : undefined;
12807 return baseFind(collection, predicate, baseEach);
12811 * Iterates over elements of `collection` and invokes `iteratee` for each element.
12812 * The iteratee is invoked with three arguments: (value, index|key, collection).
12813 * Iteratee functions may exit iteration early by explicitly returning `false`.
12815 * **Note:** As with other "Collections" methods, objects with a "length"
12816 * property are iterated like arrays. To avoid this behavior use `_.forIn`
12817 * or `_.forOwn` for object iteration.
12823 * @category Collection
12824 * @param {Array|Object} collection The collection to iterate over.
12825 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12826 * @returns {Array|Object} Returns `collection`.
12827 * @see _.forEachRight
12830 * _([1, 2]).forEach(function(value) {
12831 * console.log(value);
12833 * // => Logs `1` then `2`.
12835 * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
12836 * console.log(key);
12838 * // => Logs 'a' then 'b' (iteration order is not guaranteed).
12840 function forEach(collection, iteratee) {
12841 var func = isArray(collection) ? arrayEach : baseEach;
12842 return func(collection, getIteratee(iteratee, 3));
12846 * Creates an object composed of keys generated from the results of running
12847 * each element of `collection` thru `iteratee`. The order of grouped values
12848 * is determined by the order they occur in `collection`. The corresponding
12849 * value of each key is an array of elements responsible for generating the
12850 * key. The iteratee is invoked with one argument: (value).
12855 * @category Collection
12856 * @param {Array|Object} collection The collection to iterate over.
12857 * @param {Array|Function|Object|string} [iteratee=_.identity]
12858 * The iteratee to transform keys.
12859 * @returns {Object} Returns the composed aggregate object.
12862 * _.groupBy([6.1, 4.2, 6.3], Math.floor);
12863 * // => { '4': [4.2], '6': [6.1, 6.3] }
12865 * // The `_.property` iteratee shorthand.
12866 * _.groupBy(['one', 'two', 'three'], 'length');
12867 * // => { '3': ['one', 'two'], '5': ['three'] }
12869 var groupBy = createAggregator(function(result, value, key) {
12870 if (hasOwnProperty.call(result, key)) {
12871 result[key].push(value);
12873 result[key] = [value];
12878 * Checks if `value` is in `collection`. If `collection` is a string, it's
12879 * checked for a substring of `value`, otherwise
12880 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12881 * is used for equality comparisons. If `fromIndex` is negative, it's used as
12882 * the offset from the end of `collection`.
12887 * @category Collection
12888 * @param {Array|Object|string} collection The collection to search.
12889 * @param {*} value The value to search for.
12890 * @param {number} [fromIndex=0] The index to search from.
12891 * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
12892 * @returns {boolean} Returns `true` if `value` is found, else `false`.
12895 * _.includes([1, 2, 3], 1);
12898 * _.includes([1, 2, 3], 1, 2);
12901 * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
12904 * _.includes('pebbles', 'eb');
12907 function includes(collection, value, fromIndex, guard) {
12908 collection = isArrayLike(collection) ? collection : values(collection);
12909 fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;
12911 var length = collection.length;
12912 if (fromIndex < 0) {
12913 fromIndex = nativeMax(length + fromIndex, 0);
12915 return isString(collection)
12916 ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
12917 : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
12921 * Creates an array of values by running each element in `collection` thru
12922 * `iteratee`. The iteratee is invoked with three arguments:
12923 * (value, index|key, collection).
12925 * Many lodash methods are guarded to work as iteratees for methods like
12926 * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
12928 * The guarded methods are:
12929 * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
12930 * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
12931 * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
12932 * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
12937 * @category Collection
12938 * @param {Array|Object} collection The collection to iterate over.
12939 * @param {Array|Function|Object|string} [iteratee=_.identity]
12940 * The function invoked per iteration.
12941 * @returns {Array} Returns the new mapped array.
12944 * function square(n) {
12948 * _.map([4, 8], square);
12951 * _.map({ 'a': 4, 'b': 8 }, square);
12952 * // => [16, 64] (iteration order is not guaranteed)
12955 * { 'user': 'barney' },
12956 * { 'user': 'fred' }
12959 * // The `_.property` iteratee shorthand.
12960 * _.map(users, 'user');
12961 * // => ['barney', 'fred']
12963 function map(collection, iteratee) {
12964 var func = isArray(collection) ? arrayMap : baseMap;
12965 return func(collection, getIteratee(iteratee, 3));
12969 * Reduces `collection` to a value which is the accumulated result of running
12970 * each element in `collection` thru `iteratee`, where each successive
12971 * invocation is supplied the return value of the previous. If `accumulator`
12972 * is not given, the first element of `collection` is used as the initial
12973 * value. The iteratee is invoked with four arguments:
12974 * (accumulator, value, index|key, collection).
12976 * Many lodash methods are guarded to work as iteratees for methods like
12977 * `_.reduce`, `_.reduceRight`, and `_.transform`.
12979 * The guarded methods are:
12980 * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
12986 * @category Collection
12987 * @param {Array|Object} collection The collection to iterate over.
12988 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12989 * @param {*} [accumulator] The initial value.
12990 * @returns {*} Returns the accumulated value.
12991 * @see _.reduceRight
12994 * _.reduce([1, 2], function(sum, n) {
12999 * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
13000 * (result[value] || (result[value] = [])).push(key);
13003 * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
13005 function reduce(collection, iteratee, accumulator) {
13006 var func = isArray(collection) ? arrayReduce : baseReduce,
13007 initAccum = arguments.length < 3;
13009 return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
13013 * The opposite of `_.filter`; this method returns the elements of `collection`
13014 * that `predicate` does **not** return truthy for.
13019 * @category Collection
13020 * @param {Array|Object} collection The collection to iterate over.
13021 * @param {Array|Function|Object|string} [predicate=_.identity]
13022 * The function invoked per iteration.
13023 * @returns {Array} Returns the new filtered array.
13028 * { 'user': 'barney', 'age': 36, 'active': false },
13029 * { 'user': 'fred', 'age': 40, 'active': true }
13032 * _.reject(users, function(o) { return !o.active; });
13033 * // => objects for ['fred']
13035 * // The `_.matches` iteratee shorthand.
13036 * _.reject(users, { 'age': 40, 'active': true });
13037 * // => objects for ['barney']
13039 * // The `_.matchesProperty` iteratee shorthand.
13040 * _.reject(users, ['active', false]);
13041 * // => objects for ['fred']
13043 * // The `_.property` iteratee shorthand.
13044 * _.reject(users, 'active');
13045 * // => objects for ['barney']
13047 function reject(collection, predicate) {
13048 var func = isArray(collection) ? arrayFilter : baseFilter;
13049 predicate = getIteratee(predicate, 3);
13050 return func(collection, function(value, index, collection) {
13051 return !predicate(value, index, collection);
13056 * Checks if `predicate` returns truthy for **any** element of `collection`.
13057 * Iteration is stopped once `predicate` returns truthy. The predicate is
13058 * invoked with three arguments: (value, index|key, collection).
13063 * @category Collection
13064 * @param {Array|Object} collection The collection to iterate over.
13065 * @param {Array|Function|Object|string} [predicate=_.identity]
13066 * The function invoked per iteration.
13067 * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
13068 * @returns {boolean} Returns `true` if any element passes the predicate check,
13072 * _.some([null, 0, 'yes', false], Boolean);
13076 * { 'user': 'barney', 'active': true },
13077 * { 'user': 'fred', 'active': false }
13080 * // The `_.matches` iteratee shorthand.
13081 * _.some(users, { 'user': 'barney', 'active': false });
13084 * // The `_.matchesProperty` iteratee shorthand.
13085 * _.some(users, ['active', false]);
13088 * // The `_.property` iteratee shorthand.
13089 * _.some(users, 'active');
13092 function some(collection, predicate, guard) {
13093 var func = isArray(collection) ? arraySome : baseSome;
13094 if (guard && isIterateeCall(collection, predicate, guard)) {
13095 predicate = undefined;
13097 return func(collection, getIteratee(predicate, 3));
13100 /*------------------------------------------------------------------------*/
13103 * Gets the timestamp of the number of milliseconds that have elapsed since
13104 * the Unix epoch (1 January 1970 00:00:00 UTC).
13111 * @returns {number} Returns the timestamp.
13114 * _.defer(function(stamp) {
13115 * console.log(_.now() - stamp);
13117 * // => Logs the number of milliseconds it took for the deferred function to be invoked.
13119 var now = Date.now;
13121 /*------------------------------------------------------------------------*/
13124 * Creates a function that invokes `func` with the `this` binding of `thisArg`
13125 * and `partials` prepended to the arguments it receives.
13127 * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
13128 * may be used as a placeholder for partially applied arguments.
13130 * **Note:** Unlike native `Function#bind` this method doesn't set the "length"
13131 * property of bound functions.
13136 * @category Function
13137 * @param {Function} func The function to bind.
13138 * @param {*} thisArg The `this` binding of `func`.
13139 * @param {...*} [partials] The arguments to be partially applied.
13140 * @returns {Function} Returns the new bound function.
13143 * var greet = function(greeting, punctuation) {
13144 * return greeting + ' ' + this.user + punctuation;
13147 * var object = { 'user': 'fred' };
13149 * var bound = _.bind(greet, object, 'hi');
13153 * // Bound with placeholders.
13154 * var bound = _.bind(greet, object, _, '!');
13158 var bind = rest(function(func, thisArg, partials) {
13159 var bitmask = BIND_FLAG;
13160 if (partials.length) {
13161 var holders = replaceHolders(partials, getHolder(bind));
13162 bitmask |= PARTIAL_FLAG;
13164 return createWrapper(func, bitmask, thisArg, partials, holders);
13168 * Creates a debounced function that delays invoking `func` until after `wait`
13169 * milliseconds have elapsed since the last time the debounced function was
13170 * invoked. The debounced function comes with a `cancel` method to cancel
13171 * delayed `func` invocations and a `flush` method to immediately invoke them.
13172 * Provide an options object to indicate whether `func` should be invoked on
13173 * the leading and/or trailing edge of the `wait` timeout. The `func` is invoked
13174 * with the last arguments provided to the debounced function. Subsequent calls
13175 * to the debounced function return the result of the last `func` invocation.
13177 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
13178 * on the trailing edge of the timeout only if the debounced function is
13179 * invoked more than once during the `wait` timeout.
13181 * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
13182 * for details over the differences between `_.debounce` and `_.throttle`.
13187 * @category Function
13188 * @param {Function} func The function to debounce.
13189 * @param {number} [wait=0] The number of milliseconds to delay.
13190 * @param {Object} [options={}] The options object.
13191 * @param {boolean} [options.leading=false]
13192 * Specify invoking on the leading edge of the timeout.
13193 * @param {number} [options.maxWait]
13194 * The maximum time `func` is allowed to be delayed before it's invoked.
13195 * @param {boolean} [options.trailing=true]
13196 * Specify invoking on the trailing edge of the timeout.
13197 * @returns {Function} Returns the new debounced function.
13200 * // Avoid costly calculations while the window size is in flux.
13201 * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
13203 * // Invoke `sendMail` when clicked, debouncing subsequent calls.
13204 * jQuery(element).on('click', _.debounce(sendMail, 300, {
13206 * 'trailing': false
13209 * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
13210 * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
13211 * var source = new EventSource('/stream');
13212 * jQuery(source).on('message', debounced);
13214 * // Cancel the trailing debounced invocation.
13215 * jQuery(window).on('popstate', debounced.cancel);
13217 function debounce(func, wait, options) {
13224 lastInvokeTime = 0,
13229 if (typeof func != 'function') {
13230 throw new TypeError(FUNC_ERROR_TEXT);
13232 wait = toNumber(wait) || 0;
13233 if (isObject(options)) {
13234 leading = !!options.leading;
13235 maxing = 'maxWait' in options;
13236 maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
13237 trailing = 'trailing' in options ? !!options.trailing : trailing;
13240 function invokeFunc(time) {
13241 var args = lastArgs,
13242 thisArg = lastThis;
13244 lastArgs = lastThis = undefined;
13245 lastInvokeTime = time;
13246 result = func.apply(thisArg, args);
13250 function leadingEdge(time) {
13251 // Reset any `maxWait` timer.
13252 lastInvokeTime = time;
13253 // Start the timer for the trailing edge.
13254 timerId = setTimeout(timerExpired, wait);
13255 // Invoke the leading edge.
13256 return leading ? invokeFunc(time) : result;
13259 function remainingWait(time) {
13260 var timeSinceLastCall = time - lastCallTime,
13261 timeSinceLastInvoke = time - lastInvokeTime,
13262 result = wait - timeSinceLastCall;
13264 return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
13267 function shouldInvoke(time) {
13268 var timeSinceLastCall = time - lastCallTime,
13269 timeSinceLastInvoke = time - lastInvokeTime;
13271 // Either this is the first call, activity has stopped and we're at the
13272 // trailing edge, the system time has gone backwards and we're treating
13273 // it as the trailing edge, or we've hit the `maxWait` limit.
13274 return (!lastCallTime || (timeSinceLastCall >= wait) ||
13275 (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
13278 function timerExpired() {
13280 if (shouldInvoke(time)) {
13281 return trailingEdge(time);
13283 // Restart the timer.
13284 timerId = setTimeout(timerExpired, remainingWait(time));
13287 function trailingEdge(time) {
13288 clearTimeout(timerId);
13289 timerId = undefined;
13291 // Only invoke if we have `lastArgs` which means `func` has been
13292 // debounced at least once.
13293 if (trailing && lastArgs) {
13294 return invokeFunc(time);
13296 lastArgs = lastThis = undefined;
13300 function cancel() {
13301 if (timerId !== undefined) {
13302 clearTimeout(timerId);
13304 lastCallTime = lastInvokeTime = 0;
13305 lastArgs = lastThis = timerId = undefined;
13309 return timerId === undefined ? result : trailingEdge(now());
13312 function debounced() {
13314 isInvoking = shouldInvoke(time);
13316 lastArgs = arguments;
13318 lastCallTime = time;
13321 if (timerId === undefined) {
13322 return leadingEdge(lastCallTime);
13325 // Handle invocations in a tight loop.
13326 clearTimeout(timerId);
13327 timerId = setTimeout(timerExpired, wait);
13328 return invokeFunc(lastCallTime);
13331 if (timerId === undefined) {
13332 timerId = setTimeout(timerExpired, wait);
13336 debounced.cancel = cancel;
13337 debounced.flush = flush;
13342 * Creates a function that memoizes the result of `func`. If `resolver` is
13343 * provided, it determines the cache key for storing the result based on the
13344 * arguments provided to the memoized function. By default, the first argument
13345 * provided to the memoized function is used as the map cache key. The `func`
13346 * is invoked with the `this` binding of the memoized function.
13348 * **Note:** The cache is exposed as the `cache` property on the memoized
13349 * function. Its creation may be customized by replacing the `_.memoize.Cache`
13350 * constructor with one whose instances implement the
13351 * [`Map`](http://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-map-prototype-object)
13352 * method interface of `delete`, `get`, `has`, and `set`.
13357 * @category Function
13358 * @param {Function} func The function to have its output memoized.
13359 * @param {Function} [resolver] The function to resolve the cache key.
13360 * @returns {Function} Returns the new memoized function.
13363 * var object = { 'a': 1, 'b': 2 };
13364 * var other = { 'c': 3, 'd': 4 };
13366 * var values = _.memoize(_.values);
13377 * // Modify the result cache.
13378 * values.cache.set(object, ['a', 'b']);
13382 * // Replace `_.memoize.Cache`.
13383 * _.memoize.Cache = WeakMap;
13385 function memoize(func, resolver) {
13386 if (typeof func != 'function' || (resolver && typeof resolver != 'function')) {
13387 throw new TypeError(FUNC_ERROR_TEXT);
13389 var memoized = function() {
13390 var args = arguments,
13391 key = resolver ? resolver.apply(this, args) : args[0],
13392 cache = memoized.cache;
13394 if (cache.has(key)) {
13395 return cache.get(key);
13397 var result = func.apply(this, args);
13398 memoized.cache = cache.set(key, result);
13401 memoized.cache = new (memoize.Cache || MapCache);
13405 // Assign cache to `_.memoize`.
13406 memoize.Cache = MapCache;
13409 * Creates a function that invokes `func` with the `this` binding of the
13410 * created function and arguments from `start` and beyond provided as
13413 * **Note:** This method is based on the
13414 * [rest parameter](https://mdn.io/rest_parameters).
13419 * @category Function
13420 * @param {Function} func The function to apply a rest parameter to.
13421 * @param {number} [start=func.length-1] The start position of the rest parameter.
13422 * @returns {Function} Returns the new function.
13425 * var say = _.rest(function(what, names) {
13426 * return what + ' ' + _.initial(names).join(', ') +
13427 * (_.size(names) > 1 ? ', & ' : '') + _.last(names);
13430 * say('hello', 'fred', 'barney', 'pebbles');
13431 * // => 'hello fred, barney, & pebbles'
13433 function rest(func, start) {
13434 if (typeof func != 'function') {
13435 throw new TypeError(FUNC_ERROR_TEXT);
13437 start = nativeMax(start === undefined ? (func.length - 1) : toInteger(start), 0);
13438 return function() {
13439 var args = arguments,
13441 length = nativeMax(args.length - start, 0),
13442 array = Array(length);
13444 while (++index < length) {
13445 array[index] = args[start + index];
13448 case 0: return func.call(this, array);
13449 case 1: return func.call(this, args[0], array);
13450 case 2: return func.call(this, args[0], args[1], array);
13452 var otherArgs = Array(start + 1);
13454 while (++index < start) {
13455 otherArgs[index] = args[index];
13457 otherArgs[start] = array;
13458 return apply(func, this, otherArgs);
13463 * Creates a throttled function that only invokes `func` at most once per
13464 * every `wait` milliseconds. The throttled function comes with a `cancel`
13465 * method to cancel delayed `func` invocations and a `flush` method to
13466 * immediately invoke them. Provide an options object to indicate whether
13467 * `func` should be invoked on the leading and/or trailing edge of the `wait`
13468 * timeout. The `func` is invoked with the last arguments provided to the
13469 * throttled function. Subsequent calls to the throttled function return the
13470 * result of the last `func` invocation.
13472 * **Note:** If `leading` and `trailing` options are `true`, `func` is
13473 * invoked on the trailing edge of the timeout only if the throttled function
13474 * is invoked more than once during the `wait` timeout.
13476 * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
13477 * for details over the differences between `_.throttle` and `_.debounce`.
13482 * @category Function
13483 * @param {Function} func The function to throttle.
13484 * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
13485 * @param {Object} [options={}] The options object.
13486 * @param {boolean} [options.leading=true]
13487 * Specify invoking on the leading edge of the timeout.
13488 * @param {boolean} [options.trailing=true]
13489 * Specify invoking on the trailing edge of the timeout.
13490 * @returns {Function} Returns the new throttled function.
13493 * // Avoid excessively updating the position while scrolling.
13494 * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
13496 * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
13497 * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
13498 * jQuery(element).on('click', throttled);
13500 * // Cancel the trailing throttled invocation.
13501 * jQuery(window).on('popstate', throttled.cancel);
13503 function throttle(func, wait, options) {
13504 var leading = true,
13507 if (typeof func != 'function') {
13508 throw new TypeError(FUNC_ERROR_TEXT);
13510 if (isObject(options)) {
13511 leading = 'leading' in options ? !!options.leading : leading;
13512 trailing = 'trailing' in options ? !!options.trailing : trailing;
13514 return debounce(func, wait, {
13515 'leading': leading,
13517 'trailing': trailing
13521 /*------------------------------------------------------------------------*/
13524 * Creates a shallow clone of `value`.
13526 * **Note:** This method is loosely based on the
13527 * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
13528 * and supports cloning arrays, array buffers, booleans, date objects, maps,
13529 * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
13530 * arrays. The own enumerable properties of `arguments` objects are cloned
13531 * as plain objects. An empty object is returned for uncloneable values such
13532 * as error objects, functions, DOM nodes, and WeakMaps.
13538 * @param {*} value The value to clone.
13539 * @returns {*} Returns the cloned value.
13543 * var objects = [{ 'a': 1 }, { 'b': 2 }];
13545 * var shallow = _.clone(objects);
13546 * console.log(shallow[0] === objects[0]);
13549 function clone(value) {
13550 return baseClone(value, false, true);
13554 * This method is like `_.clone` except that it recursively clones `value`.
13560 * @param {*} value The value to recursively clone.
13561 * @returns {*} Returns the deep cloned value.
13565 * var objects = [{ 'a': 1 }, { 'b': 2 }];
13567 * var deep = _.cloneDeep(objects);
13568 * console.log(deep[0] === objects[0]);
13571 function cloneDeep(value) {
13572 return baseClone(value, true, true);
13577 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
13578 * comparison between two values to determine if they are equivalent.
13584 * @param {*} value The value to compare.
13585 * @param {*} other The other value to compare.
13586 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
13589 * var object = { 'user': 'fred' };
13590 * var other = { 'user': 'fred' };
13592 * _.eq(object, object);
13595 * _.eq(object, other);
13601 * _.eq('a', Object('a'));
13607 function eq(value, other) {
13608 return value === other || (value !== value && other !== other);
13612 * Checks if `value` is likely an `arguments` object.
13618 * @param {*} value The value to check.
13619 * @returns {boolean} Returns `true` if `value` is correctly classified,
13623 * _.isArguments(function() { return arguments; }());
13626 * _.isArguments([1, 2, 3]);
13629 function isArguments(value) {
13630 // Safari 8.1 incorrectly makes `arguments.callee` enumerable in strict mode.
13631 return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
13632 (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
13636 * Checks if `value` is classified as an `Array` object.
13643 * @param {*} value The value to check.
13644 * @returns {boolean} Returns `true` if `value` is correctly classified,
13648 * _.isArray([1, 2, 3]);
13651 * _.isArray(document.body.children);
13654 * _.isArray('abc');
13657 * _.isArray(_.noop);
13660 var isArray = Array.isArray;
13663 * Checks if `value` is array-like. A value is considered array-like if it's
13664 * not a function and has a `value.length` that's an integer greater than or
13665 * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
13671 * @param {*} value The value to check.
13672 * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
13675 * _.isArrayLike([1, 2, 3]);
13678 * _.isArrayLike(document.body.children);
13681 * _.isArrayLike('abc');
13684 * _.isArrayLike(_.noop);
13687 function isArrayLike(value) {
13688 return value != null && isLength(getLength(value)) && !isFunction(value);
13692 * This method is like `_.isArrayLike` except that it also checks if `value`
13699 * @param {*} value The value to check.
13700 * @returns {boolean} Returns `true` if `value` is an array-like object,
13704 * _.isArrayLikeObject([1, 2, 3]);
13707 * _.isArrayLikeObject(document.body.children);
13710 * _.isArrayLikeObject('abc');
13713 * _.isArrayLikeObject(_.noop);
13716 function isArrayLikeObject(value) {
13717 return isObjectLike(value) && isArrayLike(value);
13721 * Checks if `value` is a buffer.
13727 * @param {*} value The value to check.
13728 * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
13731 * _.isBuffer(new Buffer(2));
13734 * _.isBuffer(new Uint8Array(2));
13737 var isBuffer = !Buffer ? constant(false) : function(value) {
13738 return value instanceof Buffer;
13742 * Checks if `value` is an empty object, collection, map, or set.
13744 * Objects are considered empty if they have no own enumerable string keyed
13747 * Array-like values such as `arguments` objects, arrays, buffers, strings, or
13748 * jQuery-like collections are considered empty if they have a `length` of `0`.
13749 * Similarly, maps and sets are considered empty if they have a `size` of `0`.
13755 * @param {*} value The value to check.
13756 * @returns {boolean} Returns `true` if `value` is empty, else `false`.
13768 * _.isEmpty([1, 2, 3]);
13771 * _.isEmpty({ 'a': 1 });
13774 function isEmpty(value) {
13775 if (isArrayLike(value) &&
13776 (isArray(value) || isString(value) || isFunction(value.splice) ||
13777 isArguments(value) || isBuffer(value))) {
13778 return !value.length;
13780 if (isObjectLike(value)) {
13781 var tag = getTag(value);
13782 if (tag == mapTag || tag == setTag) {
13783 return !value.size;
13786 for (var key in value) {
13787 if (hasOwnProperty.call(value, key)) {
13791 return !(nonEnumShadows && keys(value).length);
13795 * Performs a deep comparison between two values to determine if they are
13798 * **Note:** This method supports comparing arrays, array buffers, booleans,
13799 * date objects, error objects, maps, numbers, `Object` objects, regexes,
13800 * sets, strings, symbols, and typed arrays. `Object` objects are compared
13801 * by their own, not inherited, enumerable properties. Functions and DOM
13802 * nodes are **not** supported.
13808 * @param {*} value The value to compare.
13809 * @param {*} other The other value to compare.
13810 * @returns {boolean} Returns `true` if the values are equivalent,
13814 * var object = { 'user': 'fred' };
13815 * var other = { 'user': 'fred' };
13817 * _.isEqual(object, other);
13820 * object === other;
13823 function isEqual(value, other) {
13824 return baseIsEqual(value, other);
13828 * Checks if `value` is classified as a `Function` object.
13834 * @param {*} value The value to check.
13835 * @returns {boolean} Returns `true` if `value` is correctly classified,
13842 * _.isFunction(/abc/);
13845 function isFunction(value) {
13846 // The use of `Object#toString` avoids issues with the `typeof` operator
13847 // in Safari 8 which returns 'object' for typed array and weak map constructors,
13848 // and PhantomJS 1.9 which returns 'function' for `NodeList` instances.
13849 var tag = isObject(value) ? objectToString.call(value) : '';
13850 return tag == funcTag || tag == genTag;
13854 * Checks if `value` is a valid array-like length.
13856 * **Note:** This function is loosely based on
13857 * [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
13863 * @param {*} value The value to check.
13864 * @returns {boolean} Returns `true` if `value` is a valid length,
13871 * _.isLength(Number.MIN_VALUE);
13874 * _.isLength(Infinity);
13880 function isLength(value) {
13881 return typeof value == 'number' &&
13882 value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
13886 * Checks if `value` is the
13887 * [language type](http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-language-types)
13888 * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
13894 * @param {*} value The value to check.
13895 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
13901 * _.isObject([1, 2, 3]);
13904 * _.isObject(_.noop);
13907 * _.isObject(null);
13910 function isObject(value) {
13911 var type = typeof value;
13912 return !!value && (type == 'object' || type == 'function');
13916 * Checks if `value` is object-like. A value is object-like if it's not `null`
13917 * and has a `typeof` result of "object".
13923 * @param {*} value The value to check.
13924 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
13927 * _.isObjectLike({});
13930 * _.isObjectLike([1, 2, 3]);
13933 * _.isObjectLike(_.noop);
13936 * _.isObjectLike(null);
13939 function isObjectLike(value) {
13940 return !!value && typeof value == 'object';
13944 * Checks if `value` is a native function.
13950 * @param {*} value The value to check.
13951 * @returns {boolean} Returns `true` if `value` is a native function,
13955 * _.isNative(Array.prototype.push);
13961 function isNative(value) {
13962 if (!isObject(value)) {
13965 var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
13966 return pattern.test(toSource(value));
13970 * Checks if `value` is a plain object, that is, an object created by the
13971 * `Object` constructor or one with a `[[Prototype]]` of `null`.
13977 * @param {*} value The value to check.
13978 * @returns {boolean} Returns `true` if `value` is a plain object,
13986 * _.isPlainObject(new Foo);
13989 * _.isPlainObject([1, 2, 3]);
13992 * _.isPlainObject({ 'x': 0, 'y': 0 });
13995 * _.isPlainObject(Object.create(null));
13998 function isPlainObject(value) {
13999 if (!isObjectLike(value) ||
14000 objectToString.call(value) != objectTag || isHostObject(value)) {
14003 var proto = getPrototype(value);
14004 if (proto === null) {
14007 var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
14008 return (typeof Ctor == 'function' &&
14009 Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);
14013 * Checks if `value` is classified as a `String` primitive or object.
14019 * @param {*} value The value to check.
14020 * @returns {boolean} Returns `true` if `value` is correctly classified,
14024 * _.isString('abc');
14030 function isString(value) {
14031 return typeof value == 'string' ||
14032 (!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag);
14036 * Checks if `value` is classified as a `Symbol` primitive or object.
14042 * @param {*} value The value to check.
14043 * @returns {boolean} Returns `true` if `value` is correctly classified,
14047 * _.isSymbol(Symbol.iterator);
14050 * _.isSymbol('abc');
14053 function isSymbol(value) {
14054 return typeof value == 'symbol' ||
14055 (isObjectLike(value) && objectToString.call(value) == symbolTag);
14059 * Checks if `value` is classified as a typed array.
14065 * @param {*} value The value to check.
14066 * @returns {boolean} Returns `true` if `value` is correctly classified,
14070 * _.isTypedArray(new Uint8Array);
14073 * _.isTypedArray([]);
14076 function isTypedArray(value) {
14077 return isObjectLike(value) &&
14078 isLength(value.length) && !!typedArrayTags[objectToString.call(value)];
14082 * Converts `value` to an array.
14088 * @param {*} value The value to convert.
14089 * @returns {Array} Returns the converted array.
14092 * _.toArray({ 'a': 1, 'b': 2 });
14095 * _.toArray('abc');
14096 * // => ['a', 'b', 'c']
14104 function toArray(value) {
14108 if (isArrayLike(value)) {
14109 return isString(value) ? stringToArray(value) : copyArray(value);
14111 if (iteratorSymbol && value[iteratorSymbol]) {
14112 return iteratorToArray(value[iteratorSymbol]());
14114 var tag = getTag(value),
14115 func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);
14117 return func(value);
14121 * Converts `value` to a finite number.
14127 * @param {*} value The value to convert.
14128 * @returns {number} Returns the converted number.
14134 * _.toFinite(Number.MIN_VALUE);
14137 * _.toFinite(Infinity);
14138 * // => 1.7976931348623157e+308
14140 * _.toFinite('3.2');
14143 function toFinite(value) {
14145 return value === 0 ? value : 0;
14147 value = toNumber(value);
14148 if (value === INFINITY || value === -INFINITY) {
14149 var sign = (value < 0 ? -1 : 1);
14150 return sign * MAX_INTEGER;
14152 return value === value ? value : 0;
14156 * Converts `value` to an integer.
14158 * **Note:** This function is loosely based on
14159 * [`ToInteger`](http://www.ecma-international.org/ecma-262/6.0/#sec-tointeger).
14165 * @param {*} value The value to convert.
14166 * @returns {number} Returns the converted integer.
14169 * _.toInteger(3.2);
14172 * _.toInteger(Number.MIN_VALUE);
14175 * _.toInteger(Infinity);
14176 * // => 1.7976931348623157e+308
14178 * _.toInteger('3.2');
14181 function toInteger(value) {
14182 var result = toFinite(value),
14183 remainder = result % 1;
14185 return result === result ? (remainder ? result - remainder : result) : 0;
14189 * Converts `value` to a number.
14195 * @param {*} value The value to process.
14196 * @returns {number} Returns the number.
14202 * _.toNumber(Number.MIN_VALUE);
14205 * _.toNumber(Infinity);
14208 * _.toNumber('3.2');
14211 function toNumber(value) {
14212 if (typeof value == 'number') {
14215 if (isSymbol(value)) {
14218 if (isObject(value)) {
14219 var other = isFunction(value.valueOf) ? value.valueOf() : value;
14220 value = isObject(other) ? (other + '') : other;
14222 if (typeof value != 'string') {
14223 return value === 0 ? value : +value;
14225 value = value.replace(reTrim, '');
14226 var isBinary = reIsBinary.test(value);
14227 return (isBinary || reIsOctal.test(value))
14228 ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
14229 : (reIsBadHex.test(value) ? NAN : +value);
14233 * Converts `value` to a plain object flattening inherited enumerable string
14234 * keyed properties of `value` to own properties of the plain object.
14240 * @param {*} value The value to convert.
14241 * @returns {Object} Returns the converted plain object.
14248 * Foo.prototype.c = 3;
14250 * _.assign({ 'a': 1 }, new Foo);
14251 * // => { 'a': 1, 'b': 2 }
14253 * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
14254 * // => { 'a': 1, 'b': 2, 'c': 3 }
14256 function toPlainObject(value) {
14257 return copyObject(value, keysIn(value));
14261 * Converts `value` to a string. An empty string is returned for `null`
14262 * and `undefined` values. The sign of `-0` is preserved.
14268 * @param {*} value The value to process.
14269 * @returns {string} Returns the string.
14272 * _.toString(null);
14278 * _.toString([1, 2, 3]);
14281 function toString(value) {
14282 return value == null ? '' : baseToString(value);
14285 /*------------------------------------------------------------------------*/
14288 * Assigns own enumerable string keyed properties of source objects to the
14289 * destination object. Source objects are applied from left to right.
14290 * Subsequent sources overwrite property assignments of previous sources.
14292 * **Note:** This method mutates `object` and is loosely based on
14293 * [`Object.assign`](https://mdn.io/Object/assign).
14299 * @param {Object} object The destination object.
14300 * @param {...Object} [sources] The source objects.
14301 * @returns {Object} Returns `object`.
14313 * Foo.prototype.d = 4;
14314 * Bar.prototype.f = 6;
14316 * _.assign({ 'a': 1 }, new Foo, new Bar);
14317 * // => { 'a': 1, 'c': 3, 'e': 5 }
14319 var assign = createAssigner(function(object, source) {
14320 if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) {
14321 copyObject(source, keys(source), object);
14324 for (var key in source) {
14325 if (hasOwnProperty.call(source, key)) {
14326 assignValue(object, key, source[key]);
14332 * This method is like `_.assign` except that it iterates over own and
14333 * inherited source properties.
14335 * **Note:** This method mutates `object`.
14342 * @param {Object} object The destination object.
14343 * @param {...Object} [sources] The source objects.
14344 * @returns {Object} Returns `object`.
14356 * Foo.prototype.c = 3;
14357 * Bar.prototype.e = 5;
14359 * _.assignIn({ 'a': 1 }, new Foo, new Bar);
14360 * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5 }
14362 var assignIn = createAssigner(function(object, source) {
14363 if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) {
14364 copyObject(source, keysIn(source), object);
14367 for (var key in source) {
14368 assignValue(object, key, source[key]);
14373 * Iterates over own enumerable string keyed properties of an object and
14374 * invokes `iteratee` for each property. The iteratee is invoked with three
14375 * arguments: (value, key, object). Iteratee functions may exit iteration
14376 * early by explicitly returning `false`.
14382 * @param {Object} object The object to iterate over.
14383 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
14384 * @returns {Object} Returns `object`.
14385 * @see _.forOwnRight
14393 * Foo.prototype.c = 3;
14395 * _.forOwn(new Foo, function(value, key) {
14396 * console.log(key);
14398 * // => Logs 'a' then 'b' (iteration order is not guaranteed).
14400 function forOwn(object, iteratee) {
14401 return object && baseForOwn(object, getIteratee(iteratee, 3));
14405 * Gets the value at `path` of `object`. If the resolved value is
14406 * `undefined`, the `defaultValue` is used in its place.
14412 * @param {Object} object The object to query.
14413 * @param {Array|string} path The path of the property to get.
14414 * @param {*} [defaultValue] The value returned for `undefined` resolved values.
14415 * @returns {*} Returns the resolved value.
14418 * var object = { 'a': [{ 'b': { 'c': 3 } }] };
14420 * _.get(object, 'a[0].b.c');
14423 * _.get(object, ['a', '0', 'b', 'c']);
14426 * _.get(object, 'a.b.c', 'default');
14429 function get(object, path, defaultValue) {
14430 var result = object == null ? undefined : baseGet(object, path);
14431 return result === undefined ? defaultValue : result;
14435 * Checks if `path` is a direct or inherited property of `object`.
14441 * @param {Object} object The object to query.
14442 * @param {Array|string} path The path to check.
14443 * @returns {boolean} Returns `true` if `path` exists, else `false`.
14446 * var object = _.create({ 'a': _.create({ 'b': 2 }) });
14448 * _.hasIn(object, 'a');
14451 * _.hasIn(object, 'a.b');
14454 * _.hasIn(object, ['a', 'b']);
14457 * _.hasIn(object, 'b');
14460 function hasIn(object, path) {
14461 return object != null && hasPath(object, path, baseHasIn);
14465 * Creates an array of the own enumerable property names of `object`.
14467 * **Note:** Non-object values are coerced to objects. See the
14468 * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
14469 * for more details.
14475 * @param {Object} object The object to query.
14476 * @returns {Array} Returns the array of property names.
14484 * Foo.prototype.c = 3;
14487 * // => ['a', 'b'] (iteration order is not guaranteed)
14492 function keys(object) {
14493 var isProto = isPrototype(object);
14494 if (!(isProto || isArrayLike(object))) {
14495 return baseKeys(object);
14497 var indexes = indexKeys(object),
14498 skipIndexes = !!indexes,
14499 result = indexes || [],
14500 length = result.length;
14502 for (var key in object) {
14503 if (baseHas(object, key) &&
14504 !(skipIndexes && (key == 'length' || isIndex(key, length))) &&
14505 !(isProto && key == 'constructor')) {
14513 * Creates an array of the own and inherited enumerable property names of `object`.
14515 * **Note:** Non-object values are coerced to objects.
14521 * @param {Object} object The object to query.
14522 * @returns {Array} Returns the array of property names.
14530 * Foo.prototype.c = 3;
14532 * _.keysIn(new Foo);
14533 * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
14535 function keysIn(object) {
14537 isProto = isPrototype(object),
14538 props = baseKeysIn(object),
14539 propsLength = props.length,
14540 indexes = indexKeys(object),
14541 skipIndexes = !!indexes,
14542 result = indexes || [],
14543 length = result.length;
14545 while (++index < propsLength) {
14546 var key = props[index];
14547 if (!(skipIndexes && (key == 'length' || isIndex(key, length))) &&
14548 !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
14556 * This method is like `_.assign` except that it recursively merges own and
14557 * inherited enumerable string keyed properties of source objects into the
14558 * destination object. Source properties that resolve to `undefined` are
14559 * skipped if a destination value exists. Array and plain object properties
14560 * are merged recursively. Other objects and value types are overridden by
14561 * assignment. Source objects are applied from left to right. Subsequent
14562 * sources overwrite property assignments of previous sources.
14564 * **Note:** This method mutates `object`.
14570 * @param {Object} object The destination object.
14571 * @param {...Object} [sources] The source objects.
14572 * @returns {Object} Returns `object`.
14576 * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
14580 * 'data': [{ 'age': 36 }, { 'age': 40 }]
14583 * _.merge(users, ages);
14584 * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
14586 var merge = createAssigner(function(object, source, srcIndex) {
14587 baseMerge(object, source, srcIndex);
14591 * The opposite of `_.pick`; this method creates an object composed of the
14592 * own and inherited enumerable string keyed properties of `object` that are
14599 * @param {Object} object The source object.
14600 * @param {...(string|string[])} [props] The property identifiers to omit.
14601 * @returns {Object} Returns the new object.
14604 * var object = { 'a': 1, 'b': '2', 'c': 3 };
14606 * _.omit(object, ['a', 'c']);
14607 * // => { 'b': '2' }
14609 var omit = rest(function(object, props) {
14610 if (object == null) {
14613 props = arrayMap(baseFlatten(props, 1), toKey);
14614 return basePick(object, baseDifference(getAllKeysIn(object), props));
14618 * Creates an object composed of the picked `object` properties.
14624 * @param {Object} object The source object.
14625 * @param {...(string|string[])} [props] The property identifiers to pick.
14626 * @returns {Object} Returns the new object.
14629 * var object = { 'a': 1, 'b': '2', 'c': 3 };
14631 * _.pick(object, ['a', 'c']);
14632 * // => { 'a': 1, 'c': 3 }
14634 var pick = rest(function(object, props) {
14635 return object == null ? {} : basePick(object, arrayMap(baseFlatten(props, 1), toKey));
14639 * Creates an array of own enumerable string keyed-value pairs for `object`
14640 * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
14641 * entries are returned.
14648 * @param {Object} object The object to query.
14649 * @returns {Array} Returns the key-value pairs.
14657 * Foo.prototype.c = 3;
14659 * _.toPairs(new Foo);
14660 * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
14662 var toPairs = createToPairs(keys);
14665 * Creates an array of the own enumerable string keyed property values of `object`.
14667 * **Note:** Non-object values are coerced to objects.
14673 * @param {Object} object The object to query.
14674 * @returns {Array} Returns the array of property values.
14682 * Foo.prototype.c = 3;
14684 * _.values(new Foo);
14685 * // => [1, 2] (iteration order is not guaranteed)
14690 function values(object) {
14691 return object ? baseValues(object, keys(object)) : [];
14694 /*------------------------------------------------------------------------*/
14697 * Creates a function that returns `value`.
14703 * @param {*} value The value to return from the new function.
14704 * @returns {Function} Returns the new constant function.
14707 * var object = { 'user': 'fred' };
14708 * var getter = _.constant(object);
14710 * getter() === object;
14713 function constant(value) {
14714 return function() {
14720 * This method returns the first argument given to it.
14726 * @param {*} value Any value.
14727 * @returns {*} Returns `value`.
14730 * var object = { 'user': 'fred' };
14732 * _.identity(object) === object;
14735 function identity(value) {
14740 * Creates a function that invokes `func` with the arguments of the created
14741 * function. If `func` is a property name, the created function returns the
14742 * property value for a given element. If `func` is an array or object, the
14743 * created function returns `true` for elements that contain the equivalent
14744 * source properties, otherwise it returns `false`.
14750 * @param {*} [func=_.identity] The value to convert to a callback.
14751 * @returns {Function} Returns the callback.
14755 * { 'user': 'barney', 'age': 36, 'active': true },
14756 * { 'user': 'fred', 'age': 40, 'active': false }
14759 * // The `_.matches` iteratee shorthand.
14760 * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
14761 * // => [{ 'user': 'barney', 'age': 36, 'active': true }]
14763 * // The `_.matchesProperty` iteratee shorthand.
14764 * _.filter(users, _.iteratee(['user', 'fred']));
14765 * // => [{ 'user': 'fred', 'age': 40 }]
14767 * // The `_.property` iteratee shorthand.
14768 * _.map(users, _.iteratee('user'));
14769 * // => ['barney', 'fred']
14771 * // Create custom iteratee shorthands.
14772 * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
14773 * return !_.isRegExp(func) ? iteratee(func) : function(string) {
14774 * return func.test(string);
14778 * _.filter(['abc', 'def'], /ef/);
14781 function iteratee(func) {
14782 return baseIteratee(typeof func == 'function' ? func : baseClone(func, true));
14786 * Adds all own enumerable string keyed function properties of a source
14787 * object to the destination object. If `object` is a function, then methods
14788 * are added to its prototype as well.
14790 * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
14791 * avoid conflicts caused by modifying the original.
14797 * @param {Function|Object} [object=lodash] The destination object.
14798 * @param {Object} source The object of functions to add.
14799 * @param {Object} [options={}] The options object.
14800 * @param {boolean} [options.chain=true] Specify whether mixins are chainable.
14801 * @returns {Function|Object} Returns `object`.
14804 * function vowels(string) {
14805 * return _.filter(string, function(v) {
14806 * return /[aeiou]/i.test(v);
14810 * _.mixin({ 'vowels': vowels });
14811 * _.vowels('fred');
14814 * _('fred').vowels().value();
14817 * _.mixin({ 'vowels': vowels }, { 'chain': false });
14818 * _('fred').vowels();
14821 function mixin(object, source, options) {
14822 var props = keys(source),
14823 methodNames = baseFunctions(source, props);
14825 if (options == null &&
14826 !(isObject(source) && (methodNames.length || !props.length))) {
14830 methodNames = baseFunctions(source, keys(source));
14832 var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
14833 isFunc = isFunction(object);
14835 arrayEach(methodNames, function(methodName) {
14836 var func = source[methodName];
14837 object[methodName] = func;
14839 object.prototype[methodName] = function() {
14840 var chainAll = this.__chain__;
14841 if (chain || chainAll) {
14842 var result = object(this.__wrapped__),
14843 actions = result.__actions__ = copyArray(this.__actions__);
14845 actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
14846 result.__chain__ = chainAll;
14849 return func.apply(object, arrayPush([this.value()], arguments));
14858 * A no-operation function that returns `undefined` regardless of the
14859 * arguments it receives.
14867 * var object = { 'user': 'fred' };
14869 * _.noop(object) === undefined;
14873 // No operation performed.
14877 * Creates a function that returns the value at `path` of a given object.
14883 * @param {Array|string} path The path of the property to get.
14884 * @returns {Function} Returns the new accessor function.
14888 * { 'a': { 'b': 2 } },
14889 * { 'a': { 'b': 1 } }
14892 * _.map(objects, _.property('a.b'));
14895 * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
14898 function property(path) {
14899 return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
14902 /*------------------------------------------------------------------------*/
14904 // Add methods that return wrapped values in chain sequences.
14905 lodash.assign = assign;
14906 lodash.assignIn = assignIn;
14907 lodash.bind = bind;
14908 lodash.chain = chain;
14909 lodash.chunk = chunk;
14910 lodash.compact = compact;
14911 lodash.constant = constant;
14912 lodash.debounce = debounce;
14913 lodash.difference = difference;
14914 lodash.filter = filter;
14915 lodash.flatten = flatten;
14916 lodash.groupBy = groupBy;
14917 lodash.intersection = intersection;
14918 lodash.iteratee = iteratee;
14919 lodash.keys = keys;
14920 lodash.keysIn = keysIn;
14922 lodash.memoize = memoize;
14923 lodash.merge = merge;
14924 lodash.mixin = mixin;
14925 lodash.omit = omit;
14926 lodash.pick = pick;
14927 lodash.property = property;
14928 lodash.reject = reject;
14929 lodash.rest = rest;
14930 lodash.reverse = reverse;
14932 lodash.throttle = throttle;
14933 lodash.thru = thru;
14934 lodash.toArray = toArray;
14935 lodash.toPairs = toPairs;
14936 lodash.toPlainObject = toPlainObject;
14937 lodash.union = union;
14938 lodash.uniq = uniq;
14939 lodash.values = values;
14940 lodash.without = without;
14943 lodash.entries = toPairs;
14944 lodash.extend = assignIn;
14946 // Add methods to `lodash.prototype`.
14947 mixin(lodash, lodash);
14949 /*------------------------------------------------------------------------*/
14951 // Add methods that return unwrapped values in chain sequences.
14952 lodash.clone = clone;
14953 lodash.cloneDeep = cloneDeep;
14955 lodash.every = every;
14956 lodash.find = find;
14957 lodash.forEach = forEach;
14958 lodash.forOwn = forOwn;
14960 lodash.hasIn = hasIn;
14961 lodash.head = head;
14962 lodash.identity = identity;
14963 lodash.includes = includes;
14964 lodash.indexOf = indexOf;
14965 lodash.isArguments = isArguments;
14966 lodash.isArray = isArray;
14967 lodash.isArrayLike = isArrayLike;
14968 lodash.isArrayLikeObject = isArrayLikeObject;
14969 lodash.isBuffer = isBuffer;
14970 lodash.isEmpty = isEmpty;
14971 lodash.isEqual = isEqual;
14972 lodash.isFunction = isFunction;
14973 lodash.isLength = isLength;
14974 lodash.isNative = isNative;
14975 lodash.isObject = isObject;
14976 lodash.isObjectLike = isObjectLike;
14977 lodash.isPlainObject = isPlainObject;
14978 lodash.isString = isString;
14979 lodash.isSymbol = isSymbol;
14980 lodash.isTypedArray = isTypedArray;
14981 lodash.last = last;
14982 lodash.noop = noop;
14984 lodash.reduce = reduce;
14985 lodash.some = some;
14986 lodash.toFinite = toFinite;
14987 lodash.toInteger = toInteger;
14988 lodash.toNumber = toNumber;
14989 lodash.toString = toString;
14992 lodash.each = forEach;
14993 lodash.first = head;
14995 mixin(lodash, (function() {
14997 baseForOwn(lodash, function(func, methodName) {
14998 if (!hasOwnProperty.call(lodash.prototype, methodName)) {
14999 source[methodName] = func;
15003 }()), { 'chain': false });
15005 /*------------------------------------------------------------------------*/
15008 * The semantic version number.
15014 lodash.VERSION = VERSION;
15016 // Assign default placeholders.
15017 bind.placeholder = lodash;
15019 // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
15020 arrayEach(['drop', 'take'], function(methodName, index) {
15021 LazyWrapper.prototype[methodName] = function(n) {
15022 var filtered = this.__filtered__;
15023 if (filtered && !index) {
15024 return new LazyWrapper(this);
15026 n = n === undefined ? 1 : nativeMax(toInteger(n), 0);
15028 var result = this.clone();
15030 result.__takeCount__ = nativeMin(n, result.__takeCount__);
15032 result.__views__.push({
15033 'size': nativeMin(n, MAX_ARRAY_LENGTH),
15034 'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
15040 LazyWrapper.prototype[methodName + 'Right'] = function(n) {
15041 return this.reverse()[methodName](n).reverse();
15045 // Add `LazyWrapper` methods that accept an `iteratee` value.
15046 arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
15047 var type = index + 1,
15048 isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;
15050 LazyWrapper.prototype[methodName] = function(iteratee) {
15051 var result = this.clone();
15052 result.__iteratees__.push({
15053 'iteratee': getIteratee(iteratee, 3),
15056 result.__filtered__ = result.__filtered__ || isFilter;
15061 // Add `LazyWrapper` methods for `_.head` and `_.last`.
15062 arrayEach(['head', 'last'], function(methodName, index) {
15063 var takeName = 'take' + (index ? 'Right' : '');
15065 LazyWrapper.prototype[methodName] = function() {
15066 return this[takeName](1).value()[0];
15070 // Add `LazyWrapper` methods for `_.initial` and `_.tail`.
15071 arrayEach(['initial', 'tail'], function(methodName, index) {
15072 var dropName = 'drop' + (index ? '' : 'Right');
15074 LazyWrapper.prototype[methodName] = function() {
15075 return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
15079 LazyWrapper.prototype.compact = function() {
15080 return this.filter(identity);
15083 LazyWrapper.prototype.find = function(predicate) {
15084 return this.filter(predicate).head();
15087 LazyWrapper.prototype.findLast = function(predicate) {
15088 return this.reverse().find(predicate);
15091 LazyWrapper.prototype.invokeMap = rest(function(path, args) {
15092 if (typeof path == 'function') {
15093 return new LazyWrapper(this);
15095 return this.map(function(value) {
15096 return baseInvoke(value, path, args);
15100 LazyWrapper.prototype.reject = function(predicate) {
15101 predicate = getIteratee(predicate, 3);
15102 return this.filter(function(value) {
15103 return !predicate(value);
15107 LazyWrapper.prototype.slice = function(start, end) {
15108 start = toInteger(start);
15111 if (result.__filtered__ && (start > 0 || end < 0)) {
15112 return new LazyWrapper(result);
15115 result = result.takeRight(-start);
15116 } else if (start) {
15117 result = result.drop(start);
15119 if (end !== undefined) {
15120 end = toInteger(end);
15121 result = end < 0 ? result.dropRight(-end) : result.take(end - start);
15126 LazyWrapper.prototype.takeRightWhile = function(predicate) {
15127 return this.reverse().takeWhile(predicate).reverse();
15130 LazyWrapper.prototype.toArray = function() {
15131 return this.take(MAX_ARRAY_LENGTH);
15134 // Add `LazyWrapper` methods to `lodash.prototype`.
15135 baseForOwn(LazyWrapper.prototype, function(func, methodName) {
15136 var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
15137 isTaker = /^(?:head|last)$/.test(methodName),
15138 lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
15139 retUnwrapped = isTaker || /^find/.test(methodName);
15144 lodash.prototype[methodName] = function() {
15145 var value = this.__wrapped__,
15146 args = isTaker ? [1] : arguments,
15147 isLazy = value instanceof LazyWrapper,
15148 iteratee = args[0],
15149 useLazy = isLazy || isArray(value);
15151 var interceptor = function(value) {
15152 var result = lodashFunc.apply(lodash, arrayPush([value], args));
15153 return (isTaker && chainAll) ? result[0] : result;
15156 if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
15157 // Avoid lazy use if the iteratee has a "length" value other than `1`.
15158 isLazy = useLazy = false;
15160 var chainAll = this.__chain__,
15161 isHybrid = !!this.__actions__.length,
15162 isUnwrapped = retUnwrapped && !chainAll,
15163 onlyLazy = isLazy && !isHybrid;
15165 if (!retUnwrapped && useLazy) {
15166 value = onlyLazy ? value : new LazyWrapper(this);
15167 var result = func.apply(value, args);
15168 result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
15169 return new LodashWrapper(result, chainAll);
15171 if (isUnwrapped && onlyLazy) {
15172 return func.apply(this, args);
15174 result = this.thru(interceptor);
15175 return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
15179 // Add `Array` methods to `lodash.prototype`.
15180 arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
15181 var func = arrayProto[methodName],
15182 chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
15183 retUnwrapped = /^(?:pop|shift)$/.test(methodName);
15185 lodash.prototype[methodName] = function() {
15186 var args = arguments;
15187 if (retUnwrapped && !this.__chain__) {
15188 var value = this.value();
15189 return func.apply(isArray(value) ? value : [], args);
15191 return this[chainName](function(value) {
15192 return func.apply(isArray(value) ? value : [], args);
15197 // Map minified method names to their real names.
15198 baseForOwn(LazyWrapper.prototype, function(func, methodName) {
15199 var lodashFunc = lodash[methodName];
15201 var key = (lodashFunc.name + ''),
15202 names = realNames[key] || (realNames[key] = []);
15204 names.push({ 'name': methodName, 'func': lodashFunc });
15208 realNames[createHybridWrapper(undefined, BIND_KEY_FLAG).name] = [{
15213 // Add methods to `LazyWrapper`.
15214 LazyWrapper.prototype.clone = lazyClone;
15215 LazyWrapper.prototype.reverse = lazyReverse;
15216 LazyWrapper.prototype.value = lazyValue;
15218 // Add chain sequence methods to the `lodash` wrapper.
15219 lodash.prototype.chain = wrapperChain;
15220 lodash.prototype.commit = wrapperCommit;
15221 lodash.prototype.next = wrapperNext;
15222 lodash.prototype.plant = wrapperPlant;
15223 lodash.prototype.reverse = wrapperReverse;
15224 lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
15226 if (iteratorSymbol) {
15227 lodash.prototype[iteratorSymbol] = wrapperToIterator;
15230 /*--------------------------------------------------------------------------*/
15232 // Expose Lodash on the free variable `window` or `self` when available so it's
15233 // globally accessible, even when bundled with Browserify, Webpack, etc. This
15234 // also prevents errors in cases where Lodash is loaded by a script tag in the
15235 // presence of an AMD loader. See http://requirejs.org/docs/errors.html#mismatch
15236 // for more details. Use `_.noConflict` to remove Lodash from the global object.
15237 (freeWindow || freeSelf || {})._ = lodash;
15239 if (freeExports && freeModule) {
15240 // Export for Node.js.
15241 if (moduleExports) {
15242 (freeModule.exports = lodash)._ = lodash;
15244 // Export for CommonJS support.
15245 freeExports._ = lodash;
15248 // Export to the global object.
15252 (function(e){if("function"==typeof bootstrap)bootstrap("osmauth",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeOsmAuth=e}else"undefined"!=typeof window?window.osmAuth=e():global.osmAuth=e()})(function(){var define,ses,bootstrap,module,exports;
15253 return (function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){
15256 var ohauth = require('ohauth'),
15257 xtend = require('xtend'),
15258 store = require('store');
15262 // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
15263 // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
15264 // does not support custom headers, which this uses everywhere.
15265 module.exports = function(o) {
15269 // authenticated users will also have a request token secret, but it's
15270 // not used in transactions with the server
15271 oauth.authenticated = function() {
15272 return !!(token('oauth_token') && token('oauth_token_secret'));
15275 oauth.logout = function() {
15276 token('oauth_token', '');
15277 token('oauth_token_secret', '');
15278 token('oauth_request_token_secret', '');
15282 // TODO: detect lack of click event
15283 oauth.authenticate = function(callback) {
15284 if (oauth.authenticated()) return callback();
15288 // ## Getting a request token
15289 var params = timenonce(getAuth(o)),
15290 url = o.url + '/oauth/request_token',
15293 params.oauth_signature = ohauth.signature(
15294 o.oauth_secret, '',
15295 ohauth.baseString('POST', url, params));
15297 if (!o.singlepage) {
15298 // Create a 600x550 popup window in the center of the screen
15299 var w = 600, h = 550,
15301 ['width', w], ['height', h],
15302 ['left', screen.width / 2 - w / 2],
15303 ['top', screen.height / 2 - h / 2]].map(function(x) {
15304 return x.join('=');
15306 popup = window.open('about:blank', 'oauth_window', settings);
15309 timer = setInterval(function() {
15310 if (popup.closed) {
15312 clearInterval(timer);
15313 callback('not authenticated', null);
15318 // Request a request token. When this is complete, the popup
15319 // window is redirected to OSM's authorization page.
15320 ohauth.xhr('POST', url, params, null, {}, reqTokenDone);
15323 function reqTokenDone(err, xhr) {
15326 if (timer) clearInterval(timer);
15327 return callback(err);
15329 var resp = ohauth.stringQs(xhr.response);
15330 token('oauth_request_token_secret', resp.oauth_token_secret);
15331 var authorize_url = o.url + '/oauth/authorize?' + ohauth.qsString({
15332 oauth_token: resp.oauth_token,
15333 oauth_callback: location.href.replace('index.html', '')
15334 .replace(/#.*/, '') + o.landing
15337 if (o.singlepage) {
15338 location.href = authorize_url;
15340 popup.location = authorize_url;
15344 // Called by a function in a landing page, in the popup window. The
15345 // window closes itself.
15346 window.authComplete = function(token) {
15347 if (timer) clearInterval(timer);
15348 var oauth_token = ohauth.stringQs(token.split('?')[1]);
15349 get_access_token(oauth_token.oauth_token);
15350 delete window.authComplete;
15353 // ## Getting an request token
15355 // At this point we have an `oauth_token`, brought in from a function
15356 // call on a landing page popup.
15357 function get_access_token(oauth_token) {
15358 var url = o.url + '/oauth/access_token',
15359 params = timenonce(getAuth(o)),
15360 request_token_secret = token('oauth_request_token_secret');
15361 params.oauth_token = oauth_token;
15362 params.oauth_signature = ohauth.signature(
15364 request_token_secret,
15365 ohauth.baseString('POST', url, params));
15367 // ## Getting an access token
15369 // The final token required for authentication. At this point
15370 // we have a `request token secret`
15371 ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
15375 function accessTokenDone(err, xhr) {
15377 if (timer) clearInterval(timer);
15378 if (err) return callback(err);
15379 var access_token = ohauth.stringQs(xhr.response);
15380 token('oauth_token', access_token.oauth_token);
15381 token('oauth_token_secret', access_token.oauth_token_secret);
15382 callback(null, oauth);
15386 oauth.bootstrapToken = function(oauth_token, callback) {
15387 // ## Getting an request token
15388 // At this point we have an `oauth_token`, brought in from a function
15389 // call on a landing page popup.
15390 function get_access_token(oauth_token) {
15391 var url = o.url + '/oauth/access_token',
15392 params = timenonce(getAuth(o)),
15393 request_token_secret = token('oauth_request_token_secret');
15394 params.oauth_token = oauth_token;
15395 params.oauth_signature = ohauth.signature(
15397 request_token_secret,
15398 ohauth.baseString('POST', url, params));
15400 // ## Getting an access token
15401 // The final token required for authentication. At this point
15402 // we have a `request token secret`
15403 ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
15407 function accessTokenDone(err, xhr) {
15409 if (err) return callback(err);
15410 var access_token = ohauth.stringQs(xhr.response);
15411 token('oauth_token', access_token.oauth_token);
15412 token('oauth_token_secret', access_token.oauth_token_secret);
15413 callback(null, oauth);
15416 get_access_token(oauth_token);
15421 // A single XMLHttpRequest wrapper that does authenticated calls if the
15422 // user has logged in.
15423 oauth.xhr = function(options, callback) {
15424 if (!oauth.authenticated()) {
15425 if (o.auto) return oauth.authenticate(run);
15426 else return callback('not authenticated', null);
15427 } else return run();
15430 var params = timenonce(getAuth(o)),
15431 url = o.url + options.path,
15432 oauth_token_secret = token('oauth_token_secret');
15434 // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
15435 if ((!options.options || !options.options.header ||
15436 options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') &&
15438 params = xtend(params, ohauth.stringQs(options.content));
15441 params.oauth_token = token('oauth_token');
15442 params.oauth_signature = ohauth.signature(
15444 oauth_token_secret,
15445 ohauth.baseString(options.method, url, params));
15447 ohauth.xhr(options.method,
15448 url, params, options.content, options.options, done);
15451 function done(err, xhr) {
15452 if (err) return callback(err);
15453 else if (xhr.responseXML) return callback(err, xhr.responseXML);
15454 else return callback(err, xhr.response);
15458 // pre-authorize this object, if we can just get a token and token_secret
15460 oauth.preauth = function(c) {
15462 if (c.oauth_token) token('oauth_token', c.oauth_token);
15463 if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
15467 oauth.options = function(_) {
15468 if (!arguments.length) return o;
15472 o.url = o.url || 'http://www.openstreetmap.org';
15473 o.landing = o.landing || 'land.html';
15475 o.singlepage = o.singlepage || false;
15477 // Optional loading and loading-done functions for nice UI feedback.
15478 // by default, no-ops
15479 o.loading = o.loading || function() {};
15480 o.done = o.done || function() {};
15482 return oauth.preauth(o);
15485 // 'stamp' an authentication object from `getAuth()`
15486 // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
15488 function timenonce(o) {
15489 o.oauth_timestamp = ohauth.timestamp();
15490 o.oauth_nonce = ohauth.nonce();
15494 // get/set tokens. These are prefixed with the base URL so that `osm-auth`
15495 // can be used with multiple APIs and the keys in `localStorage`
15499 if (store.enabled) {
15500 token = function (x, y) {
15501 if (arguments.length === 1) return store.get(o.url + x);
15502 else if (arguments.length === 2) return store.set(o.url + x, y);
15506 token = function (x, y) {
15507 if (arguments.length === 1) return storage[o.url + x];
15508 else if (arguments.length === 2) return storage[o.url + x] = y;
15512 // Get an authentication object. If you just add and remove properties
15513 // from a single object, you'll need to use `delete` to make sure that
15514 // it doesn't contain undesired properties for authentication
15515 function getAuth(o) {
15517 oauth_consumer_key: o.oauth_consumer_key,
15518 oauth_signature_method: "HMAC-SHA1"
15522 // potentially pre-authorize
15528 },{"ohauth":2,"store":3,"xtend":4}],3:[function(require,module,exports){
15529 (function(global){;(function(win){
15531 doc = win.document,
15532 localStorageName = 'localStorage',
15535 store.disabled = false
15536 store.set = function(key, value) {}
15537 store.get = function(key) {}
15538 store.remove = function(key) {}
15539 store.clear = function() {}
15540 store.transact = function(key, defaultVal, transactionFn) {
15541 var val = store.get(key)
15542 if (transactionFn == null) {
15543 transactionFn = defaultVal
15546 if (typeof val == 'undefined') { val = defaultVal || {} }
15548 store.set(key, val)
15550 store.getAll = function() {}
15551 store.forEach = function() {}
15553 store.serialize = function(value) {
15554 return JSON.stringify(value)
15556 store.deserialize = function(value) {
15557 if (typeof value != 'string') { return undefined }
15558 try { return JSON.parse(value) }
15559 catch(e) { return value || undefined }
15562 // Functions to encapsulate questionable FireFox 3.6.13 behavior
15563 // when about.config::dom.storage.enabled === false
15564 // See https://github.com/marcuswestin/store.js/issues#issue/13
15565 function isLocalStorageNameSupported() {
15566 try { return (localStorageName in win && win[localStorageName]) }
15567 catch(err) { return false }
15570 if (isLocalStorageNameSupported()) {
15571 storage = win[localStorageName]
15572 store.set = function(key, val) {
15573 if (val === undefined) { return store.remove(key) }
15574 storage.setItem(key, store.serialize(val))
15577 store.get = function(key) { return store.deserialize(storage.getItem(key)) }
15578 store.remove = function(key) { storage.removeItem(key) }
15579 store.clear = function() { storage.clear() }
15580 store.getAll = function() {
15582 store.forEach(function(key, val) {
15587 store.forEach = function(callback) {
15588 for (var i=0; i<storage.length; i++) {
15589 var key = storage.key(i)
15590 callback(key, store.get(key))
15593 } else if (doc.documentElement.addBehavior) {
15596 // Since #userData storage applies only to specific paths, we need to
15597 // somehow link our data to a specific path. We choose /favicon.ico
15598 // as a pretty safe option, since all browsers already make a request to
15599 // this URL anyway and being a 404 will not hurt us here. We wrap an
15600 // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
15601 // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
15602 // since the iframe access rules appear to allow direct access and
15603 // manipulation of the document element, even for a 404 page. This
15604 // document can be used instead of the current document (which would
15605 // have been limited to the current path) to perform #userData storage.
15607 storageContainer = new ActiveXObject('htmlfile')
15608 storageContainer.open()
15609 storageContainer.write('<s' + 'cript>document.w=window</s' + 'cript><iframe src="/favicon.ico"></iframe>')
15610 storageContainer.close()
15611 storageOwner = storageContainer.w.frames[0].document
15612 storage = storageOwner.createElement('div')
15614 // somehow ActiveXObject instantiation failed (perhaps some special
15615 // security settings or otherwse), fall back to per-path storage
15616 storage = doc.createElement('div')
15617 storageOwner = doc.body
15619 function withIEStorage(storeFunction) {
15620 return function() {
15621 var args = Array.prototype.slice.call(arguments, 0)
15622 args.unshift(storage)
15623 // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
15624 // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
15625 storageOwner.appendChild(storage)
15626 storage.addBehavior('#default#userData')
15627 storage.load(localStorageName)
15628 var result = storeFunction.apply(store, args)
15629 storageOwner.removeChild(storage)
15634 // In IE7, keys may not contain special chars. See all of https://github.com/marcuswestin/store.js/issues/40
15635 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g")
15636 function ieKeyFix(key) {
15637 return key.replace(forbiddenCharsRegex, '___')
15639 store.set = withIEStorage(function(storage, key, val) {
15640 key = ieKeyFix(key)
15641 if (val === undefined) { return store.remove(key) }
15642 storage.setAttribute(key, store.serialize(val))
15643 storage.save(localStorageName)
15646 store.get = withIEStorage(function(storage, key) {
15647 key = ieKeyFix(key)
15648 return store.deserialize(storage.getAttribute(key))
15650 store.remove = withIEStorage(function(storage, key) {
15651 key = ieKeyFix(key)
15652 storage.removeAttribute(key)
15653 storage.save(localStorageName)
15655 store.clear = withIEStorage(function(storage) {
15656 var attributes = storage.XMLDocument.documentElement.attributes
15657 storage.load(localStorageName)
15658 for (var i=0, attr; attr=attributes[i]; i++) {
15659 storage.removeAttribute(attr.name)
15661 storage.save(localStorageName)
15663 store.getAll = function(storage) {
15665 store.forEach(function(key, val) {
15670 store.forEach = withIEStorage(function(storage, callback) {
15671 var attributes = storage.XMLDocument.documentElement.attributes
15672 for (var i=0, attr; attr=attributes[i]; ++i) {
15673 callback(attr.name, store.deserialize(storage.getAttribute(attr.name)))
15679 var testKey = '__storejs__'
15680 store.set(testKey, testKey)
15681 if (store.get(testKey) != testKey) { store.disabled = true }
15682 store.remove(testKey)
15684 store.disabled = true
15686 store.enabled = !store.disabled
15688 if (typeof module != 'undefined' && module.exports) { module.exports = store }
15689 else if (typeof define === 'function' && define.amd) { define(store) }
15690 else { win.store = store }
15692 })(this.window || global);
15695 },{}],5:[function(require,module,exports){
15696 module.exports = hasKeys
15698 function hasKeys(source) {
15699 return source !== null &&
15700 (typeof source === "object" ||
15701 typeof source === "function")
15704 },{}],4:[function(require,module,exports){
15705 var Keys = require("object-keys")
15706 var hasKeys = require("./has-keys")
15708 module.exports = extend
15710 function extend() {
15713 for (var i = 0; i < arguments.length; i++) {
15714 var source = arguments[i]
15716 if (!hasKeys(source)) {
15720 var keys = Keys(source)
15722 for (var j = 0; j < keys.length; j++) {
15724 target[name] = source[name]
15731 },{"./has-keys":5,"object-keys":6}],7:[function(require,module,exports){
15732 (function(global){/**
15733 * jsHashes - A fast and independent hashing library pure JavaScript implemented (ES3 compliant) for both server and client side
15736 * @author Tomas Aparicio <tomas@rijndael-project.com>
15737 * @license New BSD (see LICENSE file)
15740 * Algorithms specification:
15742 * MD5 <http://www.ietf.org/rfc/rfc1321.txt>
15743 * RIPEMD-160 <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
15744 * SHA1 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
15745 * SHA256 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
15746 * SHA512 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
15747 * HMAC <http://www.ietf.org/rfc/rfc2104.txt>
15753 // private helper methods
15754 function utf8Encode(str) {
15755 var x, y, output = '', i = -1, l;
15757 if (str && str.length) {
15759 while ((i+=1) < l) {
15760 /* Decode utf-16 surrogate pairs */
15761 x = str.charCodeAt(i);
15762 y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
15763 if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
15764 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
15767 /* Encode output as utf-8 */
15769 output += String.fromCharCode(x);
15770 } else if (x <= 0x7FF) {
15771 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
15772 0x80 | ( x & 0x3F));
15773 } else if (x <= 0xFFFF) {
15774 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
15775 0x80 | ((x >>> 6 ) & 0x3F),
15776 0x80 | ( x & 0x3F));
15777 } else if (x <= 0x1FFFFF) {
15778 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
15779 0x80 | ((x >>> 12) & 0x3F),
15780 0x80 | ((x >>> 6 ) & 0x3F),
15781 0x80 | ( x & 0x3F));
15788 function utf8Decode(str) {
15789 var i, ac, c1, c2, c3, arr = [], l;
15790 i = ac = c1 = c2 = c3 = 0;
15792 if (str && str.length) {
15797 c1 = str.charCodeAt(i);
15800 arr[ac] = String.fromCharCode(c1);
15802 } else if (c1 > 191 && c1 < 224) {
15803 c2 = str.charCodeAt(i + 1);
15804 arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
15807 c2 = str.charCodeAt(i + 1);
15808 c3 = str.charCodeAt(i + 2);
15809 arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
15814 return arr.join('');
15818 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
15819 * to work around bugs in some JS interpreters.
15821 function safe_add(x, y) {
15822 var lsw = (x & 0xFFFF) + (y & 0xFFFF),
15823 msw = (x >> 16) + (y >> 16) + (lsw >> 16);
15824 return (msw << 16) | (lsw & 0xFFFF);
15828 * Bitwise rotate a 32-bit number to the left.
15830 function bit_rol(num, cnt) {
15831 return (num << cnt) | (num >>> (32 - cnt));
15835 * Convert a raw string to a hex string
15837 function rstr2hex(input, hexcase) {
15838 var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
15839 output = '', x, i = 0, l = input.length;
15840 for (; i < l; i+=1) {
15841 x = input.charCodeAt(i);
15842 output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F);
15848 * Encode a string as utf-16
15850 function str2rstr_utf16le(input) {
15851 var i, l = input.length, output = '';
15852 for (i = 0; i < l; i+=1) {
15853 output += String.fromCharCode( input.charCodeAt(i) & 0xFF, (input.charCodeAt(i) >>> 8) & 0xFF);
15858 function str2rstr_utf16be(input) {
15859 var i, l = input.length, output = '';
15860 for (i = 0; i < l; i+=1) {
15861 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, input.charCodeAt(i) & 0xFF);
15867 * Convert an array of big-endian words to a string
15869 function binb2rstr(input) {
15870 var i, l = input.length * 32, output = '';
15871 for (i = 0; i < l; i += 8) {
15872 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
15878 * Convert an array of little-endian words to a string
15880 function binl2rstr(input) {
15881 var i, l = input.length * 32, output = '';
15882 for (i = 0;i < l; i += 8) {
15883 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
15889 * Convert a raw string to an array of little-endian words
15890 * Characters >255 have their high-byte silently ignored.
15892 function rstr2binl(input) {
15893 var i, l = input.length * 8, output = Array(input.length >> 2), lo = output.length;
15894 for (i = 0; i < lo; i+=1) {
15897 for (i = 0; i < l; i += 8) {
15898 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
15904 * Convert a raw string to an array of big-endian words
15905 * Characters >255 have their high-byte silently ignored.
15907 function rstr2binb(input) {
15908 var i, l = input.length * 8, output = Array(input.length >> 2), lo = output.length;
15909 for (i = 0; i < lo; i+=1) {
15912 for (i = 0; i < l; i += 8) {
15913 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
15919 * Convert a raw string to an arbitrary string encoding
15921 function rstr2any(input, encoding) {
15922 var divisor = encoding.length,
15923 remainders = Array(),
15924 i, q, x, ld, quotient, dividend, output, full_length;
15926 /* Convert to an array of 16-bit big-endian values, forming the dividend */
15927 dividend = Array(Math.ceil(input.length / 2));
15928 ld = dividend.length;
15929 for (i = 0; i < ld; i+=1) {
15930 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
15934 * Repeatedly perform a long division. The binary array forms the dividend,
15935 * the length of the encoding is the divisor. Once computed, the quotient
15936 * forms the dividend for the next step. We stop when the dividend is zerHashes.
15937 * All remainders are stored for later use.
15939 while(dividend.length > 0) {
15940 quotient = Array();
15942 for (i = 0; i < dividend.length; i+=1) {
15943 x = (x << 16) + dividend[i];
15944 q = Math.floor(x / divisor);
15946 if (quotient.length > 0 || q > 0) {
15947 quotient[quotient.length] = q;
15950 remainders[remainders.length] = x;
15951 dividend = quotient;
15954 /* Convert the remainders to the output string */
15956 for (i = remainders.length - 1; i >= 0; i--) {
15957 output += encoding.charAt(remainders[i]);
15960 /* Append leading zero equivalents */
15961 full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
15962 for (i = output.length; i < full_length; i+=1) {
15963 output = encoding[0] + output;
15969 * Convert a raw string to a base-64 string
15971 function rstr2b64(input, b64pad) {
15972 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
15974 len = input.length, i, j, triplet;
15975 b64pad= b64pad || '=';
15976 for (i = 0; i < len; i += 3) {
15977 triplet = (input.charCodeAt(i) << 16)
15978 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
15979 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
15980 for (j = 0; j < 4; j+=1) {
15981 if (i * 8 + j * 6 > input.length * 8) {
15984 output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
15993 * @property {String} version
16002 Base64 : function () {
16003 // private properties
16004 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
16005 pad = '=', // default pad according with the RFC standard
16006 url = false, // URL encoding support @todo
16007 utf8 = true; // by default enable UTF-8 support encoding
16009 // public method for encoding
16010 this.encode = function (input) {
16013 len = input.length;
16016 input = (utf8) ? utf8Encode(input) : input;
16018 for (i = 0; i < len; i += 3) {
16019 triplet = (input.charCodeAt(i) << 16)
16020 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
16021 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
16022 for (j = 0; j < 4; j+=1) {
16023 if (i * 8 + j * 6 > len * 8) {
16026 output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
16033 // public method for decoding
16034 this.decode = function (input) {
16035 // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
16036 var i, o1, o2, o3, h1, h2, h3, h4, bits, ac,
16039 if (!input) { return input; }
16042 input = input.replace(new RegExp('\\'+pad,'gi'),''); // use '='
16045 do { // unpack four hexets into three octets using index points in b64
16046 h1 = tab.indexOf(input.charAt(i+=1));
16047 h2 = tab.indexOf(input.charAt(i+=1));
16048 h3 = tab.indexOf(input.charAt(i+=1));
16049 h4 = tab.indexOf(input.charAt(i+=1));
16051 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
16053 o1 = bits >> 16 & 0xff;
16054 o2 = bits >> 8 & 0xff;
16059 arr[ac] = String.fromCharCode(o1);
16060 } else if (h4 === 64) {
16061 arr[ac] = String.fromCharCode(o1, o2);
16063 arr[ac] = String.fromCharCode(o1, o2, o3);
16065 } while (i < input.length);
16067 dec = arr.join('');
16068 dec = (utf8) ? utf8Decode(dec) : dec;
16073 // set custom pad string
16074 this.setPad = function (str) {
16078 // set custom tab string characters
16079 this.setTab = function (str) {
16083 this.setUTF8 = function (bool) {
16084 if (typeof bool === 'boolean') {
16092 * CRC-32 calculation
16096 * @param {String} str Input String
16099 CRC32 : function (str) {
16100 var crc = 0, x = 0, y = 0, table, i, iTop;
16101 str = utf8Encode(str);
16104 '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ',
16105 '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ',
16106 '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ',
16107 '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ',
16108 'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ',
16109 '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ',
16110 'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ',
16111 '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ',
16112 'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ',
16113 '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ',
16114 'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ',
16115 '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ',
16116 'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ',
16117 '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ',
16118 '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ',
16119 '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ',
16120 '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ',
16121 'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ',
16122 '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ',
16123 'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ',
16124 '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ',
16125 'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ',
16126 '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ',
16127 'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ',
16128 '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ',
16129 'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'
16133 for (i = 0, iTop = str.length; i < iTop; i+=1 ) {
16134 y = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
16135 x = '0x' + table.substr( y * 9, 8 );
16136 crc = ( crc >>> 8 ) ^ x;
16138 // always return a positive number (that's what >>> 0 does)
16139 return (crc ^ (-1)) >>> 0;
16145 * @param {Object} [config]
16147 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
16148 * Digest Algorithm, as defined in RFC 1321.
16149 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
16150 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
16151 * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
16153 MD5 : function (options) {
16155 * Private config properties. You may need to tweak these to be compatible with
16156 * the server-side, but the defaults work in most cases.
16157 * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
16159 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
16160 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
16161 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
16163 // privileged (public) methods
16164 this.hex = function (s) {
16165 return rstr2hex(rstr(s, utf8), hexcase);
16167 this.b64 = function (s) {
16168 return rstr2b64(rstr(s), b64pad);
16170 this.any = function(s, e) {
16171 return rstr2any(rstr(s, utf8), e);
16173 this.hex_hmac = function (k, d) {
16174 return rstr2hex(rstr_hmac(k, d), hexcase);
16176 this.b64_hmac = function (k, d) {
16177 return rstr2b64(rstr_hmac(k,d), b64pad);
16179 this.any_hmac = function (k, d, e) {
16180 return rstr2any(rstr_hmac(k, d), e);
16183 * Perform a simple self-test to see if the VM is working
16184 * @return {String} Hexadecimal hash sample
16186 this.vm_test = function () {
16187 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
16190 * Enable/disable uppercase hexadecimal returned string
16192 * @return {Object} this
16194 this.setUpperCase = function (a) {
16195 if (typeof a === 'boolean' ) {
16201 * Defines a base64 pad string
16202 * @param {String} Pad
16203 * @return {Object} this
16205 this.setPad = function (a) {
16206 b64pad = a || b64pad;
16210 * Defines a base64 pad string
16212 * @return {Object} [this]
16214 this.setUTF8 = function (a) {
16215 if (typeof a === 'boolean') {
16224 * Calculate the MD5 of a raw string
16227 s = (utf8) ? utf8Encode(s): s;
16228 return binl2rstr(binl(rstr2binl(s), s.length * 8));
16232 * Calculate the HMAC-MD5, of a key and some data (raw strings)
16234 function rstr_hmac(key, data) {
16235 var bkey, ipad, opad, hash, i;
16237 key = (utf8) ? utf8Encode(key) : key;
16238 data = (utf8) ? utf8Encode(data) : data;
16239 bkey = rstr2binl(key);
16240 if (bkey.length > 16) {
16241 bkey = binl(bkey, key.length * 8);
16244 ipad = Array(16), opad = Array(16);
16245 for (i = 0; i < 16; i+=1) {
16246 ipad[i] = bkey[i] ^ 0x36363636;
16247 opad[i] = bkey[i] ^ 0x5C5C5C5C;
16249 hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
16250 return binl2rstr(binl(opad.concat(hash), 512 + 128));
16254 * Calculate the MD5 of an array of little-endian words, and a bit length.
16256 function binl(x, len) {
16257 var i, olda, oldb, oldc, oldd,
16263 /* append padding */
16264 x[len >> 5] |= 0x80 << ((len) % 32);
16265 x[(((len + 64) >>> 9) << 4) + 14] = len;
16267 for (i = 0; i < x.length; i += 16) {
16273 a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
16274 d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
16275 c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
16276 b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
16277 a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
16278 d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
16279 c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
16280 b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
16281 a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
16282 d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
16283 c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
16284 b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
16285 a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
16286 d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
16287 c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
16288 b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
16290 a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
16291 d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
16292 c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
16293 b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
16294 a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
16295 d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
16296 c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
16297 b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
16298 a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
16299 d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
16300 c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
16301 b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
16302 a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
16303 d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
16304 c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
16305 b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
16307 a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
16308 d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
16309 c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
16310 b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
16311 a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
16312 d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
16313 c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
16314 b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
16315 a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
16316 d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
16317 c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
16318 b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
16319 a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
16320 d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
16321 c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
16322 b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
16324 a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
16325 d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
16326 c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
16327 b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
16328 a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
16329 d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
16330 c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
16331 b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
16332 a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
16333 d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
16334 c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
16335 b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
16336 a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
16337 d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
16338 c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
16339 b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
16341 a = safe_add(a, olda);
16342 b = safe_add(b, oldb);
16343 c = safe_add(c, oldc);
16344 d = safe_add(d, oldd);
16346 return Array(a, b, c, d);
16350 * These functions implement the four basic operations the algorithm uses.
16352 function md5_cmn(q, a, b, x, s, t) {
16353 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
16355 function md5_ff(a, b, c, d, x, s, t) {
16356 return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
16358 function md5_gg(a, b, c, d, x, s, t) {
16359 return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
16361 function md5_hh(a, b, c, d, x, s, t) {
16362 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
16364 function md5_ii(a, b, c, d, x, s, t) {
16365 return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
16370 * @class Hashes.SHA1
16371 * @param {Object} [config]
16374 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
16375 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
16376 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
16377 * See http://pajhome.org.uk/crypt/md5 for details.
16379 SHA1 : function (options) {
16381 * Private config properties. You may need to tweak these to be compatible with
16382 * the server-side, but the defaults work in most cases.
16383 * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
16385 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
16386 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
16387 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
16390 this.hex = function (s) {
16391 return rstr2hex(rstr(s, utf8), hexcase);
16393 this.b64 = function (s) {
16394 return rstr2b64(rstr(s, utf8), b64pad);
16396 this.any = function (s, e) {
16397 return rstr2any(rstr(s, utf8), e);
16399 this.hex_hmac = function (k, d) {
16400 return rstr2hex(rstr_hmac(k, d));
16402 this.b64_hmac = function (k, d) {
16403 return rstr2b64(rstr_hmac(k, d), b64pad);
16405 this.any_hmac = function (k, d, e) {
16406 return rstr2any(rstr_hmac(k, d), e);
16409 * Perform a simple self-test to see if the VM is working
16410 * @return {String} Hexadecimal hash sample
16413 this.vm_test = function () {
16414 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
16417 * @description Enable/disable uppercase hexadecimal returned string
16419 * @return {Object} this
16422 this.setUpperCase = function (a) {
16423 if (typeof a === 'boolean') {
16429 * @description Defines a base64 pad string
16430 * @param {string} Pad
16431 * @return {Object} this
16434 this.setPad = function (a) {
16435 b64pad = a || b64pad;
16439 * @description Defines a base64 pad string
16441 * @return {Object} this
16444 this.setUTF8 = function (a) {
16445 if (typeof a === 'boolean') {
16454 * Calculate the SHA-512 of a raw string
16457 s = (utf8) ? utf8Encode(s) : s;
16458 return binb2rstr(binb(rstr2binb(s), s.length * 8));
16462 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
16464 function rstr_hmac(key, data) {
16465 var bkey, ipad, opad, i, hash;
16466 key = (utf8) ? utf8Encode(key) : key;
16467 data = (utf8) ? utf8Encode(data) : data;
16468 bkey = rstr2binb(key);
16470 if (bkey.length > 16) {
16471 bkey = binb(bkey, key.length * 8);
16473 ipad = Array(16), opad = Array(16);
16474 for (i = 0; i < 16; i+=1) {
16475 ipad[i] = bkey[i] ^ 0x36363636;
16476 opad[i] = bkey[i] ^ 0x5C5C5C5C;
16478 hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
16479 return binb2rstr(binb(opad.concat(hash), 512 + 160));
16483 * Calculate the SHA-1 of an array of big-endian words, and a bit length
16485 function binb(x, len) {
16486 var i, j, t, olda, oldb, oldc, oldd, olde,
16494 /* append padding */
16495 x[len >> 5] |= 0x80 << (24 - len % 32);
16496 x[((len + 64 >> 9) << 4) + 15] = len;
16498 for (i = 0; i < x.length; i += 16) {
16505 for (j = 0; j < 80; j+=1) {
16509 w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
16511 t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
16512 safe_add(safe_add(e, w[j]), sha1_kt(j)));
16515 c = bit_rol(b, 30);
16520 a = safe_add(a, olda);
16521 b = safe_add(b, oldb);
16522 c = safe_add(c, oldc);
16523 d = safe_add(d, oldd);
16524 e = safe_add(e, olde);
16526 return Array(a, b, c, d, e);
16530 * Perform the appropriate triplet combination function for the current
16533 function sha1_ft(t, b, c, d) {
16534 if (t < 20) { return (b & c) | ((~b) & d); }
16535 if (t < 40) { return b ^ c ^ d; }
16536 if (t < 60) { return (b & c) | (b & d) | (c & d); }
16541 * Determine the appropriate additive constant for the current iteration
16543 function sha1_kt(t) {
16544 return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
16545 (t < 60) ? -1894007588 : -899497514;
16549 * @class Hashes.SHA256
16552 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
16553 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
16554 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
16555 * See http://pajhome.org.uk/crypt/md5 for details.
16556 * Also http://anmar.eu.org/projects/jssha2/
16558 SHA256 : function (options) {
16560 * Private properties configuration variables. You may need to tweak these to be compatible with
16561 * the server-side, but the defaults work in most cases.
16562 * @see this.setUpperCase() method
16563 * @see this.setPad() method
16565 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase */
16566 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
16567 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
16570 /* privileged (public) methods */
16571 this.hex = function (s) {
16572 return rstr2hex(rstr(s, utf8));
16574 this.b64 = function (s) {
16575 return rstr2b64(rstr(s, utf8), b64pad);
16577 this.any = function (s, e) {
16578 return rstr2any(rstr(s, utf8), e);
16580 this.hex_hmac = function (k, d) {
16581 return rstr2hex(rstr_hmac(k, d));
16583 this.b64_hmac = function (k, d) {
16584 return rstr2b64(rstr_hmac(k, d), b64pad);
16586 this.any_hmac = function (k, d, e) {
16587 return rstr2any(rstr_hmac(k, d), e);
16590 * Perform a simple self-test to see if the VM is working
16591 * @return {String} Hexadecimal hash sample
16594 this.vm_test = function () {
16595 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
16598 * Enable/disable uppercase hexadecimal returned string
16600 * @return {Object} this
16603 this.setUpperCase = function (a) {
16604 if (typeof a === 'boolean') {
16610 * @description Defines a base64 pad string
16611 * @param {string} Pad
16612 * @return {Object} this
16615 this.setPad = function (a) {
16616 b64pad = a || b64pad;
16620 * Defines a base64 pad string
16622 * @return {Object} this
16625 this.setUTF8 = function (a) {
16626 if (typeof a === 'boolean') {
16635 * Calculate the SHA-512 of a raw string
16637 function rstr(s, utf8) {
16638 s = (utf8) ? utf8Encode(s) : s;
16639 return binb2rstr(binb(rstr2binb(s), s.length * 8));
16643 * Calculate the HMAC-sha256 of a key and some data (raw strings)
16645 function rstr_hmac(key, data) {
16646 key = (utf8) ? utf8Encode(key) : key;
16647 data = (utf8) ? utf8Encode(data) : data;
16649 bkey = rstr2binb(key),
16653 if (bkey.length > 16) { bkey = binb(bkey, key.length * 8); }
16655 for (; i < 16; i+=1) {
16656 ipad[i] = bkey[i] ^ 0x36363636;
16657 opad[i] = bkey[i] ^ 0x5C5C5C5C;
16660 hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
16661 return binb2rstr(binb(opad.concat(hash), 512 + 256));
16665 * Main sha256 function, with its support functions
16667 function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
16668 function sha256_R (X, n) {return ( X >>> n );}
16669 function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
16670 function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
16671 function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
16672 function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
16673 function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
16674 function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
16675 function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
16676 function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
16677 function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
16678 function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
16681 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
16682 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
16683 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
16684 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
16685 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
16686 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
16687 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
16688 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
16689 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
16690 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
16691 -1866530822, -1538233109, -1090935817, -965641998
16694 function binb(m, l) {
16695 var HASH = [1779033703, -1150833019, 1013904242, -1521486534,
16696 1359893119, -1694144372, 528734635, 1541459225];
16697 var W = new Array(64);
16698 var a, b, c, d, e, f, g, h;
16701 /* append padding */
16702 m[l >> 5] |= 0x80 << (24 - l % 32);
16703 m[((l + 64 >> 9) << 4) + 15] = l;
16705 for (i = 0; i < m.length; i += 16)
16716 for (j = 0; j < 64; j+=1)
16721 W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
16722 sha256_Gamma0256(W[j - 15])), W[j - 16]);
16725 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
16726 sha256_K[j]), W[j]);
16727 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
16731 e = safe_add(d, T1);
16735 a = safe_add(T1, T2);
16738 HASH[0] = safe_add(a, HASH[0]);
16739 HASH[1] = safe_add(b, HASH[1]);
16740 HASH[2] = safe_add(c, HASH[2]);
16741 HASH[3] = safe_add(d, HASH[3]);
16742 HASH[4] = safe_add(e, HASH[4]);
16743 HASH[5] = safe_add(f, HASH[5]);
16744 HASH[6] = safe_add(g, HASH[6]);
16745 HASH[7] = safe_add(h, HASH[7]);
16753 * @class Hashes.SHA512
16756 * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
16757 * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
16758 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
16759 * See http://pajhome.org.uk/crypt/md5 for details.
16761 SHA512 : function (options) {
16763 * Private properties configuration variables. You may need to tweak these to be compatible with
16764 * the server-side, but the defaults work in most cases.
16765 * @see this.setUpperCase() method
16766 * @see this.setPad() method
16768 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false , /* hexadecimal output case format. false - lowercase; true - uppercase */
16769 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
16770 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
16773 /* privileged (public) methods */
16774 this.hex = function (s) {
16775 return rstr2hex(rstr(s));
16777 this.b64 = function (s) {
16778 return rstr2b64(rstr(s), b64pad);
16780 this.any = function (s, e) {
16781 return rstr2any(rstr(s), e);
16783 this.hex_hmac = function (k, d) {
16784 return rstr2hex(rstr_hmac(k, d));
16786 this.b64_hmac = function (k, d) {
16787 return rstr2b64(rstr_hmac(k, d), b64pad);
16789 this.any_hmac = function (k, d, e) {
16790 return rstr2any(rstr_hmac(k, d), e);
16793 * Perform a simple self-test to see if the VM is working
16794 * @return {String} Hexadecimal hash sample
16797 this.vm_test = function () {
16798 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
16801 * @description Enable/disable uppercase hexadecimal returned string
16803 * @return {Object} this
16806 this.setUpperCase = function (a) {
16807 if (typeof a === 'boolean') {
16813 * @description Defines a base64 pad string
16814 * @param {string} Pad
16815 * @return {Object} this
16818 this.setPad = function (a) {
16819 b64pad = a || b64pad;
16823 * @description Defines a base64 pad string
16825 * @return {Object} this
16828 this.setUTF8 = function (a) {
16829 if (typeof a === 'boolean') {
16835 /* private methods */
16838 * Calculate the SHA-512 of a raw string
16841 s = (utf8) ? utf8Encode(s) : s;
16842 return binb2rstr(binb(rstr2binb(s), s.length * 8));
16845 * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
16847 function rstr_hmac(key, data) {
16848 key = (utf8) ? utf8Encode(key) : key;
16849 data = (utf8) ? utf8Encode(data) : data;
16852 bkey = rstr2binb(key),
16853 ipad = Array(32), opad = Array(32);
16855 if (bkey.length > 32) { bkey = binb(bkey, key.length * 8); }
16857 for (; i < 32; i+=1) {
16858 ipad[i] = bkey[i] ^ 0x36363636;
16859 opad[i] = bkey[i] ^ 0x5C5C5C5C;
16862 hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
16863 return binb2rstr(binb(opad.concat(hash), 1024 + 512));
16867 * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
16869 function binb(x, len) {
16872 hash = new Array(16),
16873 //Initial hash values
16875 new int64(0x6a09e667, -205731576),
16876 new int64(-1150833019, -2067093701),
16877 new int64(0x3c6ef372, -23791573),
16878 new int64(-1521486534, 0x5f1d36f1),
16879 new int64(0x510e527f, -1377402159),
16880 new int64(-1694144372, 0x2b3e6c1f),
16881 new int64(0x1f83d9ab, -79577749),
16882 new int64(0x5be0cd19, 0x137e2179)
16884 T1 = new int64(0, 0),
16885 T2 = new int64(0, 0),
16886 a = new int64(0,0),
16887 b = new int64(0,0),
16888 c = new int64(0,0),
16889 d = new int64(0,0),
16890 e = new int64(0,0),
16891 f = new int64(0,0),
16892 g = new int64(0,0),
16893 h = new int64(0,0),
16894 //Temporary variables not specified by the document
16895 s0 = new int64(0, 0),
16896 s1 = new int64(0, 0),
16897 Ch = new int64(0, 0),
16898 Maj = new int64(0, 0),
16899 r1 = new int64(0, 0),
16900 r2 = new int64(0, 0),
16901 r3 = new int64(0, 0);
16903 if (sha512_k === undefined) {
16906 new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
16907 new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
16908 new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
16909 new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
16910 new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
16911 new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
16912 new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
16913 new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
16914 new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
16915 new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
16916 new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
16917 new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
16918 new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
16919 new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
16920 new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
16921 new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
16922 new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
16923 new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
16924 new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
16925 new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
16926 new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
16927 new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
16928 new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
16929 new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
16930 new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
16931 new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
16932 new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
16933 new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
16934 new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
16935 new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
16936 new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
16937 new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
16938 new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
16939 new int64(-354779690, -840897762), new int64(-176337025, -294727304),
16940 new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
16941 new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
16942 new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
16943 new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
16944 new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
16945 new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)
16949 for (i=0; i<80; i+=1) {
16950 W[i] = new int64(0, 0);
16953 // append padding to the source string. The format is described in the FIPS.
16954 x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
16955 x[((len + 128 >> 10)<< 5) + 31] = len;
16957 for (i = 0; i<l; i+=32) { //32 dwords is the block size
16958 int64copy(a, H[0]);
16959 int64copy(b, H[1]);
16960 int64copy(c, H[2]);
16961 int64copy(d, H[3]);
16962 int64copy(e, H[4]);
16963 int64copy(f, H[5]);
16964 int64copy(g, H[6]);
16965 int64copy(h, H[7]);
16967 for (j=0; j<16; j+=1) {
16968 W[j].h = x[i + 2*j];
16969 W[j].l = x[i + 2*j + 1];
16972 for (j=16; j<80; j+=1) {
16974 int64rrot(r1, W[j-2], 19);
16975 int64revrrot(r2, W[j-2], 29);
16976 int64shr(r3, W[j-2], 6);
16977 s1.l = r1.l ^ r2.l ^ r3.l;
16978 s1.h = r1.h ^ r2.h ^ r3.h;
16980 int64rrot(r1, W[j-15], 1);
16981 int64rrot(r2, W[j-15], 8);
16982 int64shr(r3, W[j-15], 7);
16983 s0.l = r1.l ^ r2.l ^ r3.l;
16984 s0.h = r1.h ^ r2.h ^ r3.h;
16986 int64add4(W[j], s1, W[j-7], s0, W[j-16]);
16989 for (j = 0; j < 80; j+=1) {
16991 Ch.l = (e.l & f.l) ^ (~e.l & g.l);
16992 Ch.h = (e.h & f.h) ^ (~e.h & g.h);
16995 int64rrot(r1, e, 14);
16996 int64rrot(r2, e, 18);
16997 int64revrrot(r3, e, 9);
16998 s1.l = r1.l ^ r2.l ^ r3.l;
16999 s1.h = r1.h ^ r2.h ^ r3.h;
17002 int64rrot(r1, a, 28);
17003 int64revrrot(r2, a, 2);
17004 int64revrrot(r3, a, 7);
17005 s0.l = r1.l ^ r2.l ^ r3.l;
17006 s0.h = r1.h ^ r2.h ^ r3.h;
17009 Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
17010 Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
17012 int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
17013 int64add(T2, s0, Maj);
17018 int64add(e, d, T1);
17022 int64add(a, T1, T2);
17024 int64add(H[0], H[0], a);
17025 int64add(H[1], H[1], b);
17026 int64add(H[2], H[2], c);
17027 int64add(H[3], H[3], d);
17028 int64add(H[4], H[4], e);
17029 int64add(H[5], H[5], f);
17030 int64add(H[6], H[6], g);
17031 int64add(H[7], H[7], h);
17034 //represent the hash as an array of 32-bit dwords
17035 for (i=0; i<8; i+=1) {
17036 hash[2*i] = H[i].h;
17037 hash[2*i + 1] = H[i].l;
17042 //A constructor for 64-bit numbers
17043 function int64(h, l) {
17046 //this.toString = int64toString;
17049 //Copies src into dst, assuming both are 64-bit numbers
17050 function int64copy(dst, src) {
17055 //Right-rotates a 64-bit number by shift
17056 //Won't handle cases of shift>=32
17057 //The function revrrot() is for that
17058 function int64rrot(dst, x, shift) {
17059 dst.l = (x.l >>> shift) | (x.h << (32-shift));
17060 dst.h = (x.h >>> shift) | (x.l << (32-shift));
17063 //Reverses the dwords of the source and then rotates right by shift.
17064 //This is equivalent to rotation by 32+shift
17065 function int64revrrot(dst, x, shift) {
17066 dst.l = (x.h >>> shift) | (x.l << (32-shift));
17067 dst.h = (x.l >>> shift) | (x.h << (32-shift));
17070 //Bitwise-shifts right a 64-bit number by shift
17071 //Won't handle shift>=32, but it's never needed in SHA512
17072 function int64shr(dst, x, shift) {
17073 dst.l = (x.l >>> shift) | (x.h << (32-shift));
17074 dst.h = (x.h >>> shift);
17077 //Adds two 64-bit numbers
17078 //Like the original implementation, does not rely on 32-bit operations
17079 function int64add(dst, x, y) {
17080 var w0 = (x.l & 0xffff) + (y.l & 0xffff);
17081 var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
17082 var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
17083 var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
17084 dst.l = (w0 & 0xffff) | (w1 << 16);
17085 dst.h = (w2 & 0xffff) | (w3 << 16);
17088 //Same, except with 4 addends. Works faster than adding them one by one.
17089 function int64add4(dst, a, b, c, d) {
17090 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
17091 var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
17092 var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
17093 var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
17094 dst.l = (w0 & 0xffff) | (w1 << 16);
17095 dst.h = (w2 & 0xffff) | (w3 << 16);
17098 //Same, except with 5 addends
17099 function int64add5(dst, a, b, c, d, e) {
17100 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
17101 w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
17102 w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
17103 w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
17104 dst.l = (w0 & 0xffff) | (w1 << 16);
17105 dst.h = (w2 & 0xffff) | (w3 << 16);
17109 * @class Hashes.RMD160
17111 * @param {Object} [config]
17113 * A JavaScript implementation of the RIPEMD-160 Algorithm
17114 * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
17115 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
17116 * See http://pajhome.org.uk/crypt/md5 for details.
17117 * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
17119 RMD160 : function (options) {
17121 * Private properties configuration variables. You may need to tweak these to be compatible with
17122 * the server-side, but the defaults work in most cases.
17123 * @see this.setUpperCase() method
17124 * @see this.setPad() method
17126 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, /* hexadecimal output case format. false - lowercase; true - uppercase */
17127 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
17128 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
17130 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
17131 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
17132 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
17133 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
17134 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
17137 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
17138 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
17139 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
17140 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
17141 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
17144 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
17145 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
17146 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
17147 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
17148 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
17151 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
17152 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
17153 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
17154 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
17155 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
17158 /* privileged (public) methods */
17159 this.hex = function (s) {
17160 return rstr2hex(rstr(s, utf8));
17162 this.b64 = function (s) {
17163 return rstr2b64(rstr(s, utf8), b64pad);
17165 this.any = function (s, e) {
17166 return rstr2any(rstr(s, utf8), e);
17168 this.hex_hmac = function (k, d) {
17169 return rstr2hex(rstr_hmac(k, d));
17171 this.b64_hmac = function (k, d) {
17172 return rstr2b64(rstr_hmac(k, d), b64pad);
17174 this.any_hmac = function (k, d, e) {
17175 return rstr2any(rstr_hmac(k, d), e);
17178 * Perform a simple self-test to see if the VM is working
17179 * @return {String} Hexadecimal hash sample
17182 this.vm_test = function () {
17183 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
17186 * @description Enable/disable uppercase hexadecimal returned string
17188 * @return {Object} this
17191 this.setUpperCase = function (a) {
17192 if (typeof a === 'boolean' ) { hexcase = a; }
17196 * @description Defines a base64 pad string
17197 * @param {string} Pad
17198 * @return {Object} this
17201 this.setPad = function (a) {
17202 if (typeof a !== 'undefined' ) { b64pad = a; }
17206 * @description Defines a base64 pad string
17208 * @return {Object} this
17211 this.setUTF8 = function (a) {
17212 if (typeof a === 'boolean') { utf8 = a; }
17216 /* private methods */
17219 * Calculate the rmd160 of a raw string
17222 s = (utf8) ? utf8Encode(s) : s;
17223 return binl2rstr(binl(rstr2binl(s), s.length * 8));
17227 * Calculate the HMAC-rmd160 of a key and some data (raw strings)
17229 function rstr_hmac(key, data) {
17230 key = (utf8) ? utf8Encode(key) : key;
17231 data = (utf8) ? utf8Encode(data) : data;
17233 bkey = rstr2binl(key),
17234 ipad = Array(16), opad = Array(16);
17236 if (bkey.length > 16) {
17237 bkey = binl(bkey, key.length * 8);
17240 for (i = 0; i < 16; i+=1) {
17241 ipad[i] = bkey[i] ^ 0x36363636;
17242 opad[i] = bkey[i] ^ 0x5C5C5C5C;
17244 hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
17245 return binl2rstr(binl(opad.concat(hash), 512 + 160));
17249 * Convert an array of little-endian words to a string
17251 function binl2rstr(input) {
17252 var i, output = '', l = input.length * 32;
17253 for (i = 0; i < l; i += 8) {
17254 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
17260 * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
17262 function binl(x, len) {
17269 A1, B1, C1, D1, E1,
17270 A2, B2, C2, D2, E2;
17272 /* append padding */
17273 x[len >> 5] |= 0x80 << (len % 32);
17274 x[(((len + 64) >>> 9) << 4) + 14] = len;
17277 for (i = 0; i < l; i+=16) {
17278 A1 = A2 = h0; B1 = B2 = h1; C1 = C2 = h2; D1 = D2 = h3; E1 = E2 = h4;
17279 for (j = 0; j <= 79; j+=1) {
17280 T = safe_add(A1, rmd160_f(j, B1, C1, D1));
17281 T = safe_add(T, x[i + rmd160_r1[j]]);
17282 T = safe_add(T, rmd160_K1(j));
17283 T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
17284 A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
17285 T = safe_add(A2, rmd160_f(79-j, B2, C2, D2));
17286 T = safe_add(T, x[i + rmd160_r2[j]]);
17287 T = safe_add(T, rmd160_K2(j));
17288 T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
17289 A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
17292 T = safe_add(h1, safe_add(C1, D2));
17293 h1 = safe_add(h2, safe_add(D1, E2));
17294 h2 = safe_add(h3, safe_add(E1, A2));
17295 h3 = safe_add(h4, safe_add(A1, B2));
17296 h4 = safe_add(h0, safe_add(B1, C2));
17299 return [h0, h1, h2, h3, h4];
17302 // specific algorithm methods
17303 function rmd160_f(j, x, y, z) {
17304 return ( 0 <= j && j <= 15) ? (x ^ y ^ z) :
17305 (16 <= j && j <= 31) ? (x & y) | (~x & z) :
17306 (32 <= j && j <= 47) ? (x | ~y) ^ z :
17307 (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
17308 (64 <= j && j <= 79) ? x ^ (y | ~z) :
17309 'rmd160_f: j out of range';
17312 function rmd160_K1(j) {
17313 return ( 0 <= j && j <= 15) ? 0x00000000 :
17314 (16 <= j && j <= 31) ? 0x5a827999 :
17315 (32 <= j && j <= 47) ? 0x6ed9eba1 :
17316 (48 <= j && j <= 63) ? 0x8f1bbcdc :
17317 (64 <= j && j <= 79) ? 0xa953fd4e :
17318 'rmd160_K1: j out of range';
17321 function rmd160_K2(j){
17322 return ( 0 <= j && j <= 15) ? 0x50a28be6 :
17323 (16 <= j && j <= 31) ? 0x5c4dd124 :
17324 (32 <= j && j <= 47) ? 0x6d703ef3 :
17325 (48 <= j && j <= 63) ? 0x7a6d76e9 :
17326 (64 <= j && j <= 79) ? 0x00000000 :
17327 'rmd160_K2: j out of range';
17333 (function( window, undefined ) {
17334 var freeExports = false;
17335 if (typeof exports === 'object' ) {
17336 freeExports = exports;
17337 if (exports && typeof global === 'object' && global && global === global.global ) { window = global; }
17340 if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
17341 // define as an anonymous module, so, through path mapping, it can be aliased
17342 define(function () { return Hashes; });
17344 else if ( freeExports ) {
17345 // in Node.js or RingoJS v0.8.0+
17346 if ( typeof module === 'object' && module && module.exports === freeExports ) {
17347 module.exports = Hashes;
17349 // in Narwhal or RingoJS v0.7.0-
17351 freeExports.Hashes = Hashes;
17355 // in a browser or Rhino
17356 window.Hashes = Hashes;
17362 },{}],2:[function(require,module,exports){
17365 var hashes = require('jshashes'),
17366 xtend = require('xtend'),
17367 sha1 = new hashes.SHA1();
17371 ohauth.qsString = function(obj) {
17372 return Object.keys(obj).sort().map(function(key) {
17373 return ohauth.percentEncode(key) + '=' +
17374 ohauth.percentEncode(obj[key]);
17378 ohauth.stringQs = function(str) {
17379 return str.split('&').reduce(function(obj, pair){
17380 var parts = pair.split('=');
17381 obj[decodeURIComponent(parts[0])] = (null === parts[1]) ?
17382 '' : decodeURIComponent(parts[1]);
17387 ohauth.rawxhr = function(method, url, data, headers, callback) {
17388 var xhr = new XMLHttpRequest(),
17389 twoHundred = /^20\d$/;
17390 xhr.onreadystatechange = function() {
17391 if (4 == xhr.readyState && 0 !== xhr.status) {
17392 if (twoHundred.test(xhr.status)) callback(null, xhr);
17393 else return callback(xhr, null);
17396 xhr.onerror = function(e) { return callback(e, null); };
17397 xhr.open(method, url, true);
17398 for (var h in headers) xhr.setRequestHeader(h, headers[h]);
17402 ohauth.xhr = function(method, url, auth, data, options, callback) {
17403 var headers = (options && options.header) || {
17404 'Content-Type': 'application/x-www-form-urlencoded'
17406 headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
17407 ohauth.rawxhr(method, url, data, headers, callback);
17410 ohauth.nonce = function() {
17411 for (var o = ''; o.length < 6;) {
17412 o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
17417 ohauth.authHeader = function(obj) {
17418 return Object.keys(obj).sort().map(function(key) {
17419 return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
17423 ohauth.timestamp = function() { return ~~((+new Date()) / 1000); };
17425 ohauth.percentEncode = function(s) {
17426 return encodeURIComponent(s)
17427 .replace(/\!/g, '%21').replace(/\'/g, '%27')
17428 .replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
17431 ohauth.baseString = function(method, url, params) {
17432 if (params.oauth_signature) delete params.oauth_signature;
17435 ohauth.percentEncode(url),
17436 ohauth.percentEncode(ohauth.qsString(params))].join('&');
17439 ohauth.signature = function(oauth_secret, token_secret, baseString) {
17440 return sha1.b64_hmac(
17441 ohauth.percentEncode(oauth_secret) + '&' +
17442 ohauth.percentEncode(token_secret),
17447 * Takes an options object for configuration (consumer_key,
17448 * consumer_secret, version, signature_method, token) and returns a
17449 * function that generates the Authorization header for given data.
17451 * The returned function takes these parameters:
17452 * - method: GET/POST/...
17453 * - uri: full URI with protocol, port, path and query string
17454 * - extra_params: any extra parameters (that are passed in the POST data),
17455 * can be an object or a from-urlencoded string.
17457 * Returned function returns full OAuth header with "OAuth" string in it.
17460 ohauth.headerGenerator = function(options) {
17461 options = options || {};
17462 var consumer_key = options.consumer_key || '',
17463 consumer_secret = options.consumer_secret || '',
17464 signature_method = options.signature_method || 'HMAC-SHA1',
17465 version = options.version || '1.0',
17466 token = options.token || '';
17468 return function(method, uri, extra_params) {
17469 method = method.toUpperCase();
17470 if (typeof extra_params === 'string' && extra_params.length > 0) {
17471 extra_params = ohauth.stringQs(extra_params);
17474 var uri_parts = uri.split('?', 2),
17475 base_uri = uri_parts[0];
17477 var query_params = uri_parts.length === 2 ?
17478 ohauth.stringQs(uri_parts[1]) : {};
17480 var oauth_params = {
17481 oauth_consumer_key: consumer_key,
17482 oauth_signature_method: signature_method,
17483 oauth_version: version,
17484 oauth_timestamp: ohauth.timestamp(),
17485 oauth_nonce: ohauth.nonce()
17488 if (token) oauth_params.oauth_token = token;
17490 var all_params = xtend({}, oauth_params, query_params, extra_params),
17491 base_str = ohauth.baseString(method, base_uri, all_params);
17493 oauth_params.oauth_signature = ohauth.signature(consumer_secret, token, base_str);
17495 return 'OAuth ' + ohauth.authHeader(oauth_params);
17499 module.exports = ohauth;
17501 },{"jshashes":7,"xtend":4}],6:[function(require,module,exports){
17502 module.exports = Object.keys || require('./shim');
17505 },{"./shim":8}],8:[function(require,module,exports){
17509 // modified from https://github.com/kriskowal/es5-shim
17510 var has = Object.prototype.hasOwnProperty,
17511 is = require('is'),
17512 forEach = require('foreach'),
17513 hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
17520 "propertyIsEnumerable",
17525 keysShim = function keys(object) {
17526 if (!is.object(object) && !is.array(object)) {
17527 throw new TypeError("Object.keys called on a non-object");
17530 var name, theKeys = [];
17531 for (name in object) {
17532 if (has.call(object, name)) {
17533 theKeys.push(name);
17537 if (hasDontEnumBug) {
17538 forEach(dontEnums, function (dontEnum) {
17539 if (has.call(object, dontEnum)) {
17540 theKeys.push(dontEnum);
17547 module.exports = keysShim;
17551 },{"is":9,"foreach":10}],9:[function(require,module,exports){
17555 * the definitive JavaScript type testing library
17557 * @copyright 2013 Enrico Marino
17561 var objProto = Object.prototype;
17562 var owns = objProto.hasOwnProperty;
17563 var toString = objProto.toString;
17564 var isActualNaN = function (value) {
17565 return value !== value;
17567 var NON_HOST_TYPES = {
17578 var is = module.exports = {};
17586 * Test if `value` is a type of `type`.
17588 * @param {Mixed} value value to test
17589 * @param {String} type type
17590 * @return {Boolean} true if `value` is a type of `type`, false otherwise
17595 is.type = function (value, type) {
17596 return typeof value === type;
17601 * Test if `value` is defined.
17603 * @param {Mixed} value value to test
17604 * @return {Boolean} true if 'value' is defined, false otherwise
17608 is.defined = function (value) {
17609 return value !== undefined;
17614 * Test if `value` is empty.
17616 * @param {Mixed} value value to test
17617 * @return {Boolean} true if `value` is empty, false otherwise
17621 is.empty = function (value) {
17622 var type = toString.call(value);
17625 if ('[object Array]' === type || '[object Arguments]' === type) {
17626 return value.length === 0;
17629 if ('[object Object]' === type) {
17630 for (key in value) if (owns.call(value, key)) return false;
17634 if ('[object String]' === type) {
17635 return '' === value;
17643 * Test if `value` is equal to `other`.
17645 * @param {Mixed} value value to test
17646 * @param {Mixed} other value to compare with
17647 * @return {Boolean} true if `value` is equal to `other`, false otherwise
17650 is.equal = function (value, other) {
17651 var type = toString.call(value)
17654 if (type !== toString.call(other)) {
17658 if ('[object Object]' === type) {
17659 for (key in value) {
17660 if (!is.equal(value[key], other[key])) {
17667 if ('[object Array]' === type) {
17668 key = value.length;
17669 if (key !== other.length) {
17673 if (!is.equal(value[key], other[key])) {
17680 if ('[object Function]' === type) {
17681 return value.prototype === other.prototype;
17684 if ('[object Date]' === type) {
17685 return value.getTime() === other.getTime();
17688 return value === other;
17693 * Test if `value` is hosted by `host`.
17695 * @param {Mixed} value to test
17696 * @param {Mixed} host host to test with
17697 * @return {Boolean} true if `value` is hosted by `host`, false otherwise
17701 is.hosted = function (value, host) {
17702 var type = typeof host[value];
17703 return type === 'object' ? !!host[value] : !NON_HOST_TYPES[type];
17708 * Test if `value` is an instance of `constructor`.
17710 * @param {Mixed} value value to test
17711 * @return {Boolean} true if `value` is an instance of `constructor`
17715 is.instance = is['instanceof'] = function (value, constructor) {
17716 return value instanceof constructor;
17721 * Test if `value` is null.
17723 * @param {Mixed} value value to test
17724 * @return {Boolean} true if `value` is null, false otherwise
17728 is['null'] = function (value) {
17729 return value === null;
17734 * Test if `value` is undefined.
17736 * @param {Mixed} value value to test
17737 * @return {Boolean} true if `value` is undefined, false otherwise
17741 is.undefined = function (value) {
17742 return value === undefined;
17751 * Test if `value` is an arguments object.
17753 * @param {Mixed} value value to test
17754 * @return {Boolean} true if `value` is an arguments object, false otherwise
17758 is.arguments = function (value) {
17759 var isStandardArguments = '[object Arguments]' === toString.call(value);
17760 var isOldArguments = !is.array(value) && is.arraylike(value) && is.object(value) && is.fn(value.callee);
17761 return isStandardArguments || isOldArguments;
17770 * Test if 'value' is an array.
17772 * @param {Mixed} value value to test
17773 * @return {Boolean} true if `value` is an array, false otherwise
17777 is.array = function (value) {
17778 return '[object Array]' === toString.call(value);
17782 * is.arguments.empty
17783 * Test if `value` is an empty arguments object.
17785 * @param {Mixed} value value to test
17786 * @return {Boolean} true if `value` is an empty arguments object, false otherwise
17789 is.arguments.empty = function (value) {
17790 return is.arguments(value) && value.length === 0;
17795 * Test if `value` is an empty array.
17797 * @param {Mixed} value value to test
17798 * @return {Boolean} true if `value` is an empty array, false otherwise
17801 is.array.empty = function (value) {
17802 return is.array(value) && value.length === 0;
17807 * Test if `value` is an arraylike object.
17809 * @param {Mixed} value value to test
17810 * @return {Boolean} true if `value` is an arguments object, false otherwise
17814 is.arraylike = function (value) {
17815 return !!value && !is.boolean(value)
17816 && owns.call(value, 'length')
17817 && isFinite(value.length)
17818 && is.number(value.length)
17819 && value.length >= 0;
17828 * Test if `value` is a boolean.
17830 * @param {Mixed} value value to test
17831 * @return {Boolean} true if `value` is a boolean, false otherwise
17835 is.boolean = function (value) {
17836 return '[object Boolean]' === toString.call(value);
17841 * Test if `value` is false.
17843 * @param {Mixed} value value to test
17844 * @return {Boolean} true if `value` is false, false otherwise
17848 is['false'] = function (value) {
17849 return is.boolean(value) && (value === false || value.valueOf() === false);
17854 * Test if `value` is true.
17856 * @param {Mixed} value value to test
17857 * @return {Boolean} true if `value` is true, false otherwise
17861 is['true'] = function (value) {
17862 return is.boolean(value) && (value === true || value.valueOf() === true);
17871 * Test if `value` is a date.
17873 * @param {Mixed} value value to test
17874 * @return {Boolean} true if `value` is a date, false otherwise
17878 is.date = function (value) {
17879 return '[object Date]' === toString.call(value);
17888 * Test if `value` is an html element.
17890 * @param {Mixed} value value to test
17891 * @return {Boolean} true if `value` is an HTML Element, false otherwise
17895 is.element = function (value) {
17896 return value !== undefined
17897 && typeof HTMLElement !== 'undefined'
17898 && value instanceof HTMLElement
17899 && value.nodeType === 1;
17908 * Test if `value` is an error object.
17910 * @param {Mixed} value value to test
17911 * @return {Boolean} true if `value` is an error object, false otherwise
17915 is.error = function (value) {
17916 return '[object Error]' === toString.call(value);
17924 * is.fn / is.function (deprecated)
17925 * Test if `value` is a function.
17927 * @param {Mixed} value value to test
17928 * @return {Boolean} true if `value` is a function, false otherwise
17932 is.fn = is['function'] = function (value) {
17933 var isAlert = typeof window !== 'undefined' && value === window.alert;
17934 return isAlert || '[object Function]' === toString.call(value);
17943 * Test if `value` is a number.
17945 * @param {Mixed} value value to test
17946 * @return {Boolean} true if `value` is a number, false otherwise
17950 is.number = function (value) {
17951 return '[object Number]' === toString.call(value);
17956 * Test if `value` is positive or negative infinity.
17958 * @param {Mixed} value value to test
17959 * @return {Boolean} true if `value` is positive or negative Infinity, false otherwise
17962 is.infinite = function (value) {
17963 return value === Infinity || value === -Infinity;
17968 * Test if `value` is a decimal number.
17970 * @param {Mixed} value value to test
17971 * @return {Boolean} true if `value` is a decimal number, false otherwise
17975 is.decimal = function (value) {
17976 return is.number(value) && !isActualNaN(value) && value % 1 !== 0;
17981 * Test if `value` is divisible by `n`.
17983 * @param {Number} value value to test
17984 * @param {Number} n dividend
17985 * @return {Boolean} true if `value` is divisible by `n`, false otherwise
17989 is.divisibleBy = function (value, n) {
17990 var isDividendInfinite = is.infinite(value);
17991 var isDivisorInfinite = is.infinite(n);
17992 var isNonZeroNumber = is.number(value) && !isActualNaN(value) && is.number(n) && !isActualNaN(n) && n !== 0;
17993 return isDividendInfinite || isDivisorInfinite || (isNonZeroNumber && value % n === 0);
17998 * Test if `value` is an integer.
18000 * @param value to test
18001 * @return {Boolean} true if `value` is an integer, false otherwise
18005 is.int = function (value) {
18006 return is.number(value) && !isActualNaN(value) && value % 1 === 0;
18011 * Test if `value` is greater than 'others' values.
18013 * @param {Number} value value to test
18014 * @param {Array} others values to compare with
18015 * @return {Boolean} true if `value` is greater than `others` values
18019 is.maximum = function (value, others) {
18020 if (isActualNaN(value)) {
18021 throw new TypeError('NaN is not a valid value');
18022 } else if (!is.arraylike(others)) {
18023 throw new TypeError('second argument must be array-like');
18025 var len = others.length;
18027 while (--len >= 0) {
18028 if (value < others[len]) {
18038 * Test if `value` is less than `others` values.
18040 * @param {Number} value value to test
18041 * @param {Array} others values to compare with
18042 * @return {Boolean} true if `value` is less than `others` values
18046 is.minimum = function (value, others) {
18047 if (isActualNaN(value)) {
18048 throw new TypeError('NaN is not a valid value');
18049 } else if (!is.arraylike(others)) {
18050 throw new TypeError('second argument must be array-like');
18052 var len = others.length;
18054 while (--len >= 0) {
18055 if (value > others[len]) {
18065 * Test if `value` is not a number.
18067 * @param {Mixed} value value to test
18068 * @return {Boolean} true if `value` is not a number, false otherwise
18072 is.nan = function (value) {
18073 return !is.number(value) || value !== value;
18078 * Test if `value` is an even number.
18080 * @param {Number} value value to test
18081 * @return {Boolean} true if `value` is an even number, false otherwise
18085 is.even = function (value) {
18086 return is.infinite(value) || (is.number(value) && value === value && value % 2 === 0);
18091 * Test if `value` is an odd number.
18093 * @param {Number} value value to test
18094 * @return {Boolean} true if `value` is an odd number, false otherwise
18098 is.odd = function (value) {
18099 return is.infinite(value) || (is.number(value) && value === value && value % 2 !== 0);
18104 * Test if `value` is greater than or equal to `other`.
18106 * @param {Number} value value to test
18107 * @param {Number} other value to compare with
18108 * @return {Boolean}
18112 is.ge = function (value, other) {
18113 if (isActualNaN(value) || isActualNaN(other)) {
18114 throw new TypeError('NaN is not a valid value');
18116 return !is.infinite(value) && !is.infinite(other) && value >= other;
18121 * Test if `value` is greater than `other`.
18123 * @param {Number} value value to test
18124 * @param {Number} other value to compare with
18125 * @return {Boolean}
18129 is.gt = function (value, other) {
18130 if (isActualNaN(value) || isActualNaN(other)) {
18131 throw new TypeError('NaN is not a valid value');
18133 return !is.infinite(value) && !is.infinite(other) && value > other;
18138 * Test if `value` is less than or equal to `other`.
18140 * @param {Number} value value to test
18141 * @param {Number} other value to compare with
18142 * @return {Boolean} if 'value' is less than or equal to 'other'
18146 is.le = function (value, other) {
18147 if (isActualNaN(value) || isActualNaN(other)) {
18148 throw new TypeError('NaN is not a valid value');
18150 return !is.infinite(value) && !is.infinite(other) && value <= other;
18155 * Test if `value` is less than `other`.
18157 * @param {Number} value value to test
18158 * @param {Number} other value to compare with
18159 * @return {Boolean} if `value` is less than `other`
18163 is.lt = function (value, other) {
18164 if (isActualNaN(value) || isActualNaN(other)) {
18165 throw new TypeError('NaN is not a valid value');
18167 return !is.infinite(value) && !is.infinite(other) && value < other;
18172 * Test if `value` is within `start` and `finish`.
18174 * @param {Number} value value to test
18175 * @param {Number} start lower bound
18176 * @param {Number} finish upper bound
18177 * @return {Boolean} true if 'value' is is within 'start' and 'finish'
18180 is.within = function (value, start, finish) {
18181 if (isActualNaN(value) || isActualNaN(start) || isActualNaN(finish)) {
18182 throw new TypeError('NaN is not a valid value');
18183 } else if (!is.number(value) || !is.number(start) || !is.number(finish)) {
18184 throw new TypeError('all arguments must be numbers');
18186 var isAnyInfinite = is.infinite(value) || is.infinite(start) || is.infinite(finish);
18187 return isAnyInfinite || (value >= start && value <= finish);
18196 * Test if `value` is an object.
18198 * @param {Mixed} value value to test
18199 * @return {Boolean} true if `value` is an object, false otherwise
18203 is.object = function (value) {
18204 return value && '[object Object]' === toString.call(value);
18209 * Test if `value` is a hash - a plain object literal.
18211 * @param {Mixed} value value to test
18212 * @return {Boolean} true if `value` is a hash, false otherwise
18216 is.hash = function (value) {
18217 return is.object(value) && value.constructor === Object && !value.nodeType && !value.setInterval;
18226 * Test if `value` is a regular expression.
18228 * @param {Mixed} value value to test
18229 * @return {Boolean} true if `value` is a regexp, false otherwise
18233 is.regexp = function (value) {
18234 return '[object RegExp]' === toString.call(value);
18243 * Test if `value` is a string.
18245 * @param {Mixed} value value to test
18246 * @return {Boolean} true if 'value' is a string, false otherwise
18250 is.string = function (value) {
18251 return '[object String]' === toString.call(value);
18255 },{}],10:[function(require,module,exports){
18257 var hasOwn = Object.prototype.hasOwnProperty;
18258 var toString = Object.prototype.toString;
18260 module.exports = function forEach (obj, fn, ctx) {
18261 if (toString.call(fn) !== '[object Function]') {
18262 throw new TypeError('iterator must be a function');
18264 var l = obj.length;
18266 for (var i = 0; i < l; i++) {
18267 fn.call(ctx, obj[i], i, obj);
18270 for (var k in obj) {
18271 if (hasOwn.call(obj, k)) {
18272 fn.call(ctx, obj[k], k, obj);
18283 (c) 2015, Vladimir Agafonkin
18284 RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles.
18285 https://github.com/mourner/rbush
18291 function rbush(maxEntries, format) {
18293 // jshint newcap: false, validthis: true
18294 if (!(this instanceof rbush)) return new rbush(maxEntries, format);
18296 // max entries in a node is 9 by default; min node fill is 40% for best performance
18297 this._maxEntries = Math.max(4, maxEntries || 9);
18298 this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
18301 this._initFormat(format);
18307 rbush.prototype = {
18310 return this._all(this.data, []);
18313 search: function (bbox) {
18315 var node = this.data,
18317 toBBox = this.toBBox;
18319 if (!intersects(bbox, node.bbox)) return result;
18321 var nodesToSearch = [],
18322 i, len, child, childBBox;
18325 for (i = 0, len = node.children.length; i < len; i++) {
18327 child = node.children[i];
18328 childBBox = node.leaf ? toBBox(child) : child.bbox;
18330 if (intersects(bbox, childBBox)) {
18331 if (node.leaf) result.push(child);
18332 else if (contains(bbox, childBBox)) this._all(child, result);
18333 else nodesToSearch.push(child);
18336 node = nodesToSearch.pop();
18342 collides: function (bbox) {
18344 var node = this.data,
18345 toBBox = this.toBBox;
18347 if (!intersects(bbox, node.bbox)) return false;
18349 var nodesToSearch = [],
18350 i, len, child, childBBox;
18353 for (i = 0, len = node.children.length; i < len; i++) {
18355 child = node.children[i];
18356 childBBox = node.leaf ? toBBox(child) : child.bbox;
18358 if (intersects(bbox, childBBox)) {
18359 if (node.leaf || contains(bbox, childBBox)) return true;
18360 nodesToSearch.push(child);
18363 node = nodesToSearch.pop();
18369 load: function (data) {
18370 if (!(data && data.length)) return this;
18372 if (data.length < this._minEntries) {
18373 for (var i = 0, len = data.length; i < len; i++) {
18374 this.insert(data[i]);
18379 // recursively build the tree with the given data from stratch using OMT algorithm
18380 var node = this._build(data.slice(), 0, data.length - 1, 0);
18382 if (!this.data.children.length) {
18383 // save as is if tree is empty
18386 } else if (this.data.height === node.height) {
18387 // split root if trees have the same height
18388 this._splitRoot(this.data, node);
18391 if (this.data.height < node.height) {
18392 // swap trees if inserted one is bigger
18393 var tmpNode = this.data;
18398 // insert the small tree into the large tree at appropriate level
18399 this._insert(node, this.data.height - node.height - 1, true);
18405 insert: function (item) {
18406 if (item) this._insert(item, this.data.height - 1);
18410 clear: function () {
18420 remove: function (item) {
18421 if (!item) return this;
18423 var node = this.data,
18424 bbox = this.toBBox(item),
18427 i, parent, index, goingUp;
18429 // depth-first iterative tree traversal
18430 while (node || path.length) {
18432 if (!node) { // go up
18434 parent = path[path.length - 1];
18439 if (node.leaf) { // check current node
18440 index = node.children.indexOf(item);
18442 if (index !== -1) {
18443 // item found, remove the item and condense tree upwards
18444 node.children.splice(index, 1);
18446 this._condense(path);
18451 if (!goingUp && !node.leaf && contains(node.bbox, bbox)) { // go down
18456 node = node.children[0];
18458 } else if (parent) { // go right
18460 node = parent.children[i];
18463 } else node = null; // nothing found
18469 toBBox: function (item) { return item; },
18471 compareMinX: function (a, b) { return a[0] - b[0]; },
18472 compareMinY: function (a, b) { return a[1] - b[1]; },
18474 toJSON: function () { return this.data; },
18476 fromJSON: function (data) {
18481 _all: function (node, result) {
18482 var nodesToSearch = [];
18484 if (node.leaf) result.push.apply(result, node.children);
18485 else nodesToSearch.push.apply(nodesToSearch, node.children);
18487 node = nodesToSearch.pop();
18492 _build: function (items, left, right, height) {
18494 var N = right - left + 1,
18495 M = this._maxEntries,
18499 // reached leaf level; return leaf
18501 children: items.slice(left, right + 1),
18506 calcBBox(node, this.toBBox);
18511 // target height of the bulk-loaded tree
18512 height = Math.ceil(Math.log(N) / Math.log(M));
18514 // target number of root entries to maximize storage utilization
18515 M = Math.ceil(N / Math.pow(M, height - 1));
18525 // split the items into M mostly square tiles
18527 var N2 = Math.ceil(N / M),
18528 N1 = N2 * Math.ceil(Math.sqrt(M)),
18529 i, j, right2, right3;
18531 multiSelect(items, left, right, N1, this.compareMinX);
18533 for (i = left; i <= right; i += N1) {
18535 right2 = Math.min(i + N1 - 1, right);
18537 multiSelect(items, i, right2, N2, this.compareMinY);
18539 for (j = i; j <= right2; j += N2) {
18541 right3 = Math.min(j + N2 - 1, right2);
18543 // pack each entry recursively
18544 node.children.push(this._build(items, j, right3, height - 1));
18548 calcBBox(node, this.toBBox);
18553 _chooseSubtree: function (bbox, node, level, path) {
18555 var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
18560 if (node.leaf || path.length - 1 === level) break;
18562 minArea = minEnlargement = Infinity;
18564 for (i = 0, len = node.children.length; i < len; i++) {
18565 child = node.children[i];
18566 area = bboxArea(child.bbox);
18567 enlargement = enlargedArea(bbox, child.bbox) - area;
18569 // choose entry with the least area enlargement
18570 if (enlargement < minEnlargement) {
18571 minEnlargement = enlargement;
18572 minArea = area < minArea ? area : minArea;
18573 targetNode = child;
18575 } else if (enlargement === minEnlargement) {
18576 // otherwise choose one with the smallest area
18577 if (area < minArea) {
18579 targetNode = child;
18590 _insert: function (item, level, isNode) {
18592 var toBBox = this.toBBox,
18593 bbox = isNode ? item.bbox : toBBox(item),
18596 // find the best node for accommodating the item, saving all nodes along the path too
18597 var node = this._chooseSubtree(bbox, this.data, level, insertPath);
18599 // put the item into the node
18600 node.children.push(item);
18601 extend(node.bbox, bbox);
18603 // split on node overflow; propagate upwards if necessary
18604 while (level >= 0) {
18605 if (insertPath[level].children.length > this._maxEntries) {
18606 this._split(insertPath, level);
18611 // adjust bboxes along the insertion path
18612 this._adjustParentBBoxes(bbox, insertPath, level);
18615 // split overflowed node into two
18616 _split: function (insertPath, level) {
18618 var node = insertPath[level],
18619 M = node.children.length,
18620 m = this._minEntries;
18622 this._chooseSplitAxis(node, m, M);
18624 var splitIndex = this._chooseSplitIndex(node, m, M);
18627 children: node.children.splice(splitIndex, node.children.length - splitIndex),
18628 height: node.height,
18633 if (node.leaf) newNode.leaf = true;
18635 calcBBox(node, this.toBBox);
18636 calcBBox(newNode, this.toBBox);
18638 if (level) insertPath[level - 1].children.push(newNode);
18639 else this._splitRoot(node, newNode);
18642 _splitRoot: function (node, newNode) {
18645 children: [node, newNode],
18646 height: node.height + 1,
18650 calcBBox(this.data, this.toBBox);
18653 _chooseSplitIndex: function (node, m, M) {
18655 var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
18657 minOverlap = minArea = Infinity;
18659 for (i = m; i <= M - m; i++) {
18660 bbox1 = distBBox(node, 0, i, this.toBBox);
18661 bbox2 = distBBox(node, i, M, this.toBBox);
18663 overlap = intersectionArea(bbox1, bbox2);
18664 area = bboxArea(bbox1) + bboxArea(bbox2);
18666 // choose distribution with minimum overlap
18667 if (overlap < minOverlap) {
18668 minOverlap = overlap;
18671 minArea = area < minArea ? area : minArea;
18673 } else if (overlap === minOverlap) {
18674 // otherwise choose distribution with minimum area
18675 if (area < minArea) {
18685 // sorts node children by the best axis for split
18686 _chooseSplitAxis: function (node, m, M) {
18688 var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
18689 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
18690 xMargin = this._allDistMargin(node, m, M, compareMinX),
18691 yMargin = this._allDistMargin(node, m, M, compareMinY);
18693 // if total distributions margin value is minimal for x, sort by minX,
18694 // otherwise it's already sorted by minY
18695 if (xMargin < yMargin) node.children.sort(compareMinX);
18698 // total margin of all possible split distributions where each node is at least m full
18699 _allDistMargin: function (node, m, M, compare) {
18701 node.children.sort(compare);
18703 var toBBox = this.toBBox,
18704 leftBBox = distBBox(node, 0, m, toBBox),
18705 rightBBox = distBBox(node, M - m, M, toBBox),
18706 margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
18709 for (i = m; i < M - m; i++) {
18710 child = node.children[i];
18711 extend(leftBBox, node.leaf ? toBBox(child) : child.bbox);
18712 margin += bboxMargin(leftBBox);
18715 for (i = M - m - 1; i >= m; i--) {
18716 child = node.children[i];
18717 extend(rightBBox, node.leaf ? toBBox(child) : child.bbox);
18718 margin += bboxMargin(rightBBox);
18724 _adjustParentBBoxes: function (bbox, path, level) {
18725 // adjust bboxes along the given tree path
18726 for (var i = level; i >= 0; i--) {
18727 extend(path[i].bbox, bbox);
18731 _condense: function (path) {
18732 // go through the path, removing empty nodes and updating bboxes
18733 for (var i = path.length - 1, siblings; i >= 0; i--) {
18734 if (path[i].children.length === 0) {
18736 siblings = path[i - 1].children;
18737 siblings.splice(siblings.indexOf(path[i]), 1);
18739 } else this.clear();
18741 } else calcBBox(path[i], this.toBBox);
18745 _initFormat: function (format) {
18746 // data format (minX, minY, maxX, maxY accessors)
18748 // uses eval-type function compilation instead of just accepting a toBBox function
18749 // because the algorithms are very sensitive to sorting functions performance,
18750 // so they should be dead simple and without inner calls
18752 // jshint evil: true
18754 var compareArr = ['return a', ' - b', ';'];
18756 this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
18757 this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
18759 this.toBBox = new Function('a', 'return [a' + format.join(', a') + '];');
18764 // calculate node's bbox from bboxes of its children
18765 function calcBBox(node, toBBox) {
18766 node.bbox = distBBox(node, 0, node.children.length, toBBox);
18769 // min bounding rectangle of node children from k to p-1
18770 function distBBox(node, k, p, toBBox) {
18771 var bbox = empty();
18773 for (var i = k, child; i < p; i++) {
18774 child = node.children[i];
18775 extend(bbox, node.leaf ? toBBox(child) : child.bbox);
18781 function empty() { return [Infinity, Infinity, -Infinity, -Infinity]; }
18783 function extend(a, b) {
18784 a[0] = Math.min(a[0], b[0]);
18785 a[1] = Math.min(a[1], b[1]);
18786 a[2] = Math.max(a[2], b[2]);
18787 a[3] = Math.max(a[3], b[3]);
18791 function compareNodeMinX(a, b) { return a.bbox[0] - b.bbox[0]; }
18792 function compareNodeMinY(a, b) { return a.bbox[1] - b.bbox[1]; }
18794 function bboxArea(a) { return (a[2] - a[0]) * (a[3] - a[1]); }
18795 function bboxMargin(a) { return (a[2] - a[0]) + (a[3] - a[1]); }
18797 function enlargedArea(a, b) {
18798 return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) *
18799 (Math.max(b[3], a[3]) - Math.min(b[1], a[1]));
18802 function intersectionArea(a, b) {
18803 var minX = Math.max(a[0], b[0]),
18804 minY = Math.max(a[1], b[1]),
18805 maxX = Math.min(a[2], b[2]),
18806 maxY = Math.min(a[3], b[3]);
18808 return Math.max(0, maxX - minX) *
18809 Math.max(0, maxY - minY);
18812 function contains(a, b) {
18813 return a[0] <= b[0] &&
18819 function intersects(a, b) {
18820 return b[0] <= a[2] &&
18826 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
18827 // combines selection algorithm with binary divide & conquer approach
18829 function multiSelect(arr, left, right, n, compare) {
18830 var stack = [left, right],
18833 while (stack.length) {
18834 right = stack.pop();
18835 left = stack.pop();
18837 if (right - left <= n) continue;
18839 mid = left + Math.ceil((right - left) / n / 2) * n;
18840 select(arr, left, right, mid, compare);
18842 stack.push(left, mid, mid, right);
18846 // Floyd-Rivest selection algorithm:
18847 // sort an array between left and right (inclusive) so that the smallest k elements come first (unordered)
18848 function select(arr, left, right, k, compare) {
18849 var n, i, z, s, sd, newLeft, newRight, t, j;
18851 while (right > left) {
18852 if (right - left > 600) {
18853 n = right - left + 1;
18856 s = 0.5 * Math.exp(2 * z / 3);
18857 sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (i - n / 2 < 0 ? -1 : 1);
18858 newLeft = Math.max(left, Math.floor(k - i * s / n + sd));
18859 newRight = Math.min(right, Math.floor(k + (n - i) * s / n + sd));
18860 select(arr, newLeft, newRight, k, compare);
18867 swap(arr, left, k);
18868 if (compare(arr[right], t) > 0) swap(arr, left, right);
18874 while (compare(arr[i], t) < 0) i++;
18875 while (compare(arr[j], t) > 0) j--;
18878 if (compare(arr[left], t) === 0) swap(arr, left, j);
18881 swap(arr, j, right);
18884 if (j <= k) left = j + 1;
18885 if (k <= j) right = j - 1;
18889 function swap(arr, i, j) {
18896 // export as AMD/CommonJS module or global variable
18897 if (typeof define === 'function' && define.amd) define('rbush', function () { return rbush; });
18898 else if (typeof module !== 'undefined') module.exports = rbush;
18899 else if (typeof self !== 'undefined') self.rbush = rbush;
18900 else window.rbush = rbush;
18903 (function(e){if("function"==typeof bootstrap)bootstrap("sexagesimal",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeSexagesimal=e}else"undefined"!=typeof window?window.sexagesimal=e():global.sexagesimal=e()})(function(){var define,ses,bootstrap,module,exports;
18904 return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
18905 module.exports = element;
18906 module.exports.pair = pair;
18907 module.exports.format = format;
18908 module.exports.formatPair = formatPair;
18910 function element(x, dims) {
18911 return search(x, dims).val;
18914 function formatPair(x) {
18915 return format(x.lat, 'lat') + ' ' + format(x.lon, 'lon');
18918 // Is 0 North or South?
18919 function format(x, dim) {
18924 dir = dirs[x >= 0 ? 0 : 1],
18926 whole = Math.floor(abs),
18927 fraction = abs - whole,
18928 fractionMinutes = fraction * 60,
18929 minutes = Math.floor(fractionMinutes),
18930 seconds = Math.floor((fractionMinutes - minutes) * 60);
18932 return whole + '° ' +
18933 (minutes ? minutes + "' " : '') +
18934 (seconds ? seconds + '" ' : '') + dir;
18937 function search(x, dims, r) {
18938 if (!dims) dims = 'NSEW';
18939 if (typeof x !== 'string') return { val: null, regex: r };
18940 r = r || /[\s\,]*([\-|\—|\―]?[0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/gi;
18942 if (!m) return { val: null, regex: r };
18943 else if (m[4] && dims.indexOf(m[4]) === -1) return { val: null, regex: r };
18945 val: (((m[1]) ? parseFloat(m[1]) : 0) +
18946 ((m[2] ? parseFloat(m[2]) / 60 : 0)) +
18947 ((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
18948 ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1),
18955 function pair(x, dims) {
18957 var one = search(x, dims);
18958 if (one.val === null) return null;
18959 var two = search(x, dims, one.regex);
18960 if (two.val === null) return null;
18961 // null if one/two are not contiguous.
18962 if (one.raw + two.raw !== x) return null;
18963 if (one.dim) return swapdim(one.val, two.val, one.dim);
18964 else return [one.val, two.val];
18967 function swapdim(a, b, dim) {
18968 if (dim == 'N' || dim == 'S') return [a, b];
18969 if (dim == 'W' || dim == 'E') return [b, a];
18975 ;toGeoJSON = (function() {
18978 var removeSpace = (/\s*/g),
18979 trimSpace = (/^\s*|\s*$/g),
18980 splitSpace = (/\s+/);
18981 // generate a short, numeric hash of a string
18982 function okhash(x) {
18983 if (!x || !x.length) return 0;
18984 for (var i = 0, h = 0; i < x.length; i++) {
18985 h = ((h << 5) - h) + x.charCodeAt(i) | 0;
18988 // all Y children of X
18989 function get(x, y) { return x.getElementsByTagName(y); }
18990 function attr(x, y) { return x.getAttribute(y); }
18991 function attrf(x, y) { return parseFloat(attr(x, y)); }
18992 // one Y child of X, if any, otherwise null
18993 function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
18994 // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
18995 function norm(el) { if (el.normalize) { el.normalize(); } return el; }
18996 // cast array x into numbers
18997 function numarray(x) {
18998 for (var j = 0, o = []; j < x.length; j++) o[j] = parseFloat(x[j]);
19001 function clean(x) {
19003 for (var i in x) if (x[i]) o[i] = x[i];
19006 // get the content of a text node, if any
19007 function nodeVal(x) { if (x) {norm(x);} return x && x.firstChild && x.firstChild.nodeValue; }
19008 // get one coordinate from a coordinate array, if any
19009 function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
19010 // get all coordinates from a coordinate array as [[],[]]
19011 function coord(v) {
19012 var coords = v.replace(trimSpace, '').split(splitSpace),
19014 for (var i = 0; i < coords.length; i++) {
19015 o.push(coord1(coords[i]));
19019 function coordPair(x) { return [attrf(x, 'lon'), attrf(x, 'lat')]; }
19021 // create a new feature collection parent object
19024 type: 'FeatureCollection',
19029 var styleSupport = false;
19030 if (typeof XMLSerializer !== 'undefined') {
19031 var serializer = new XMLSerializer();
19032 styleSupport = true;
19034 function xml2str(str) { return serializer.serializeToString(str); }
19037 kml: function(doc, o) {
19041 // styleindex keeps track of hashed styles in order to match features
19043 // atomic geospatial types supported by KML - MultiGeometry is
19044 // handled separately
19045 geotypes = ['Polygon', 'LineString', 'Point', 'Track'],
19046 // all root placemarks in the file
19047 placemarks = get(doc, 'Placemark'),
19048 styles = get(doc, 'Style');
19050 if (styleSupport) for (var k = 0; k < styles.length; k++) {
19051 styleIndex['#' + attr(styles[k], 'id')] = okhash(xml2str(styles[k])).toString(16);
19053 for (var j = 0; j < placemarks.length; j++) {
19054 gj.features = gj.features.concat(getPlacemark(placemarks[j]));
19056 function gxCoord(v) { return numarray(v.split(' ')); }
19057 function gxCoords(root) {
19058 var elems = get(root, 'coord', 'gx'), coords = [];
19059 for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
19062 function getGeometry(root) {
19063 var geomNode, geomNodes, i, j, k, geoms = [];
19064 if (get1(root, 'MultiGeometry')) return getGeometry(get1(root, 'MultiGeometry'));
19065 if (get1(root, 'MultiTrack')) return getGeometry(get1(root, 'MultiTrack'));
19066 for (i = 0; i < geotypes.length; i++) {
19067 geomNodes = get(root, geotypes[i]);
19069 for (j = 0; j < geomNodes.length; j++) {
19070 geomNode = geomNodes[j];
19071 if (geotypes[i] == 'Point') {
19074 coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
19076 } else if (geotypes[i] == 'LineString') {
19078 type: 'LineString',
19079 coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
19081 } else if (geotypes[i] == 'Polygon') {
19082 var rings = get(geomNode, 'LinearRing'),
19084 for (k = 0; k < rings.length; k++) {
19085 coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
19089 coordinates: coords
19091 } else if (geotypes[i] == 'Track') {
19093 type: 'LineString',
19094 coordinates: gxCoords(geomNode)
19102 function getPlacemark(root) {
19103 var geoms = getGeometry(root), i, properties = {},
19104 name = nodeVal(get1(root, 'name')),
19105 styleUrl = nodeVal(get1(root, 'styleUrl')),
19106 description = nodeVal(get1(root, 'description')),
19107 extendedData = get1(root, 'ExtendedData');
19109 if (!geoms.length) return [];
19110 if (name) properties.name = name;
19111 if (styleUrl && styleIndex[styleUrl]) {
19112 properties.styleUrl = styleUrl;
19113 properties.styleHash = styleIndex[styleUrl];
19115 if (description) properties.description = description;
19116 if (extendedData) {
19117 var datas = get(extendedData, 'Data'),
19118 simpleDatas = get(extendedData, 'SimpleData');
19120 for (i = 0; i < datas.length; i++) {
19121 properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
19123 for (i = 0; i < simpleDatas.length; i++) {
19124 properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
19129 geometry: (geoms.length === 1) ? geoms[0] : {
19130 type: 'GeometryCollection',
19133 properties: properties
19138 gpx: function(doc, o) {
19140 tracks = get(doc, 'trk'),
19141 routes = get(doc, 'rte'),
19142 waypoints = get(doc, 'wpt'),
19143 // a feature collection
19145 for (i = 0; i < tracks.length; i++) {
19146 gj.features.push(getLinestring(tracks[i], 'trkpt'));
19148 for (i = 0; i < routes.length; i++) {
19149 gj.features.push(getLinestring(routes[i], 'rtept'));
19151 for (i = 0; i < waypoints.length; i++) {
19152 gj.features.push(getPoint(waypoints[i]));
19154 function getLinestring(node, pointname) {
19155 var j, pts = get(node, pointname), line = [];
19156 for (j = 0; j < pts.length; j++) {
19157 line.push(coordPair(pts[j]));
19161 properties: getProperties(node),
19163 type: 'LineString',
19168 function getPoint(node) {
19169 var prop = getProperties(node);
19170 prop.ele = nodeVal(get1(node, 'ele'));
19171 prop.sym = nodeVal(get1(node, 'sym'));
19177 coordinates: coordPair(node)
19181 function getProperties(node) {
19182 var meta = ['name', 'desc', 'author', 'copyright', 'link',
19183 'time', 'keywords'],
19186 for (k = 0; k < meta.length; k++) {
19187 prop[meta[k]] = nodeVal(get1(node, meta[k]));
19189 return clean(prop);
19197 if (typeof module !== 'undefined') module.exports = toGeoJSON;
19199 * marked - a markdown parser
19200 * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
19201 * https://github.com/chjj/marked
19207 * Block-Level Grammar
19212 code: /^( {4}[^\n]+\n*)+/,
19214 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
19215 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
19217 lheading: /^([^\n]+)\n *(=|-){3,} *\n*/,
19218 blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
19219 list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
19220 html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
19221 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
19223 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
19227 block.bullet = /(?:[*+-]|\d+\.)/;
19228 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
19229 block.item = replace(block.item, 'gm')
19230 (/bull/g, block.bullet)
19233 block.list = replace(block.list)
19234 (/bull/g, block.bullet)
19235 ('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
19238 block._tag = '(?!(?:'
19239 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
19240 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
19241 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
19243 block.html = replace(block.html)
19244 ('comment', /<!--[\s\S]*?-->/)
19245 ('closed', /<(tag)[\s\S]+?<\/\1>/)
19246 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
19247 (/tag/g, block._tag)
19250 block.paragraph = replace(block.paragraph)
19252 ('heading', block.heading)
19253 ('lheading', block.lheading)
19254 ('blockquote', block.blockquote)
19255 ('tag', '<' + block._tag)
19260 * Normal Block Grammar
19263 block.normal = merge({}, block);
19266 * GFM Block Grammar
19269 block.gfm = merge({}, block.normal, {
19270 fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
19274 block.gfm.paragraph = replace(block.paragraph)
19275 ('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|')
19279 * GFM + Tables Block Grammar
19282 block.tables = merge({}, block.gfm, {
19283 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
19284 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
19291 function Lexer(options) {
19293 this.tokens.links = {};
19294 this.options = options || marked.defaults;
19295 this.rules = block.normal;
19297 if (this.options.gfm) {
19298 if (this.options.tables) {
19299 this.rules = block.tables;
19301 this.rules = block.gfm;
19307 * Expose Block Rules
19310 Lexer.rules = block;
19313 * Static Lex Method
19316 Lexer.lex = function(src, options) {
19317 var lexer = new Lexer(options);
19318 return lexer.lex(src);
19325 Lexer.prototype.lex = function(src) {
19327 .replace(/\r\n|\r/g, '\n')
19328 .replace(/\t/g, ' ')
19329 .replace(/\u00a0/g, ' ')
19330 .replace(/\u2424/g, '\n');
19332 return this.token(src, true);
19339 Lexer.prototype.token = function(src, top) {
19340 var src = src.replace(/^ +$/gm, '')
19353 if (cap = this.rules.newline.exec(src)) {
19354 src = src.substring(cap[0].length);
19355 if (cap[0].length > 1) {
19363 if (cap = this.rules.code.exec(src)) {
19364 src = src.substring(cap[0].length);
19365 cap = cap[0].replace(/^ {4}/gm, '');
19368 text: !this.options.pedantic
19369 ? cap.replace(/\n+$/, '')
19376 if (cap = this.rules.fences.exec(src)) {
19377 src = src.substring(cap[0].length);
19387 if (cap = this.rules.heading.exec(src)) {
19388 src = src.substring(cap[0].length);
19391 depth: cap[1].length,
19397 // table no leading pipe (gfm)
19398 if (top && (cap = this.rules.nptable.exec(src))) {
19399 src = src.substring(cap[0].length);
19403 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19404 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19405 cells: cap[3].replace(/\n$/, '').split('\n')
19408 for (i = 0; i < item.align.length; i++) {
19409 if (/^ *-+: *$/.test(item.align[i])) {
19410 item.align[i] = 'right';
19411 } else if (/^ *:-+: *$/.test(item.align[i])) {
19412 item.align[i] = 'center';
19413 } else if (/^ *:-+ *$/.test(item.align[i])) {
19414 item.align[i] = 'left';
19416 item.align[i] = null;
19420 for (i = 0; i < item.cells.length; i++) {
19421 item.cells[i] = item.cells[i].split(/ *\| */);
19424 this.tokens.push(item);
19430 if (cap = this.rules.lheading.exec(src)) {
19431 src = src.substring(cap[0].length);
19434 depth: cap[2] === '=' ? 1 : 2,
19441 if (cap = this.rules.hr.exec(src)) {
19442 src = src.substring(cap[0].length);
19450 if (cap = this.rules.blockquote.exec(src)) {
19451 src = src.substring(cap[0].length);
19454 type: 'blockquote_start'
19457 cap = cap[0].replace(/^ *> ?/gm, '');
19459 // Pass `top` to keep the current
19460 // "toplevel" state. This is exactly
19461 // how markdown.pl works.
19462 this.token(cap, top);
19465 type: 'blockquote_end'
19472 if (cap = this.rules.list.exec(src)) {
19473 src = src.substring(cap[0].length);
19477 type: 'list_start',
19478 ordered: bull.length > 1
19481 // Get each top-level item.
19482 cap = cap[0].match(this.rules.item);
19488 for (; i < l; i++) {
19491 // Remove the list item's bullet
19492 // so it is seen as the next token.
19493 space = item.length;
19494 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19496 // Outdent whatever the
19497 // list item contains. Hacky.
19498 if (~item.indexOf('\n ')) {
19499 space -= item.length;
19500 item = !this.options.pedantic
19501 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19502 : item.replace(/^ {1,4}/gm, '');
19505 // Determine whether the next list item belongs here.
19506 // Backpedal if it does not belong in this list.
19507 if (this.options.smartLists && i !== l - 1) {
19508 b = block.bullet.exec(cap[i+1])[0];
19509 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19510 src = cap.slice(i + 1).join('\n') + src;
19515 // Determine whether item is loose or not.
19516 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19517 // for discount behavior.
19518 loose = next || /\n\n(?!\s*$)/.test(item);
19520 next = item[item.length-1] === '\n';
19521 if (!loose) loose = next;
19526 ? 'loose_item_start'
19527 : 'list_item_start'
19531 this.token(item, false);
19534 type: 'list_item_end'
19546 if (cap = this.rules.html.exec(src)) {
19547 src = src.substring(cap[0].length);
19549 type: this.options.sanitize
19552 pre: cap[1] === 'pre' || cap[1] === 'script',
19559 if (top && (cap = this.rules.def.exec(src))) {
19560 src = src.substring(cap[0].length);
19561 this.tokens.links[cap[1].toLowerCase()] = {
19569 if (top && (cap = this.rules.table.exec(src))) {
19570 src = src.substring(cap[0].length);
19574 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19575 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19576 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19579 for (i = 0; i < item.align.length; i++) {
19580 if (/^ *-+: *$/.test(item.align[i])) {
19581 item.align[i] = 'right';
19582 } else if (/^ *:-+: *$/.test(item.align[i])) {
19583 item.align[i] = 'center';
19584 } else if (/^ *:-+ *$/.test(item.align[i])) {
19585 item.align[i] = 'left';
19587 item.align[i] = null;
19591 for (i = 0; i < item.cells.length; i++) {
19592 item.cells[i] = item.cells[i]
19593 .replace(/^ *\| *| *\| *$/g, '')
19597 this.tokens.push(item);
19602 // top-level paragraph
19603 if (top && (cap = this.rules.paragraph.exec(src))) {
19604 src = src.substring(cap[0].length);
19607 text: cap[1][cap[1].length-1] === '\n'
19608 ? cap[1].slice(0, -1)
19615 if (cap = this.rules.text.exec(src)) {
19616 // Top-level should never reach here.
19617 src = src.substring(cap[0].length);
19627 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19631 return this.tokens;
19635 * Inline-Level Grammar
19639 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19640 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19642 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19643 link: /^!?\[(inside)\]\(href\)/,
19644 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19645 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19646 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19647 em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19648 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19649 br: /^ {2,}\n(?!\s*$)/,
19651 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19654 inline._inside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
19655 inline._href = /\s*<?([^\s]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19657 inline.link = replace(inline.link)
19658 ('inside', inline._inside)
19659 ('href', inline._href)
19662 inline.reflink = replace(inline.reflink)
19663 ('inside', inline._inside)
19667 * Normal Inline Grammar
19670 inline.normal = merge({}, inline);
19673 * Pedantic Inline Grammar
19676 inline.pedantic = merge({}, inline.normal, {
19677 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19678 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19682 * GFM Inline Grammar
19685 inline.gfm = merge({}, inline.normal, {
19686 escape: replace(inline.escape)('])', '~|])')(),
19687 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19688 del: /^~~(?=\S)([\s\S]*?\S)~~/,
19689 text: replace(inline.text)
19691 ('|', '|https?://|')
19696 * GFM + Line Breaks Inline Grammar
19699 inline.breaks = merge({}, inline.gfm, {
19700 br: replace(inline.br)('{2,}', '*')(),
19701 text: replace(inline.gfm.text)('{2,}', '*')()
19705 * Inline Lexer & Compiler
19708 function InlineLexer(links, options) {
19709 this.options = options || marked.defaults;
19710 this.links = links;
19711 this.rules = inline.normal;
19715 Error('Tokens array requires a `links` property.');
19718 if (this.options.gfm) {
19719 if (this.options.breaks) {
19720 this.rules = inline.breaks;
19722 this.rules = inline.gfm;
19724 } else if (this.options.pedantic) {
19725 this.rules = inline.pedantic;
19730 * Expose Inline Rules
19733 InlineLexer.rules = inline;
19736 * Static Lexing/Compiling Method
19739 InlineLexer.output = function(src, links, options) {
19740 var inline = new InlineLexer(links, options);
19741 return inline.output(src);
19748 InlineLexer.prototype.output = function(src) {
19757 if (cap = this.rules.escape.exec(src)) {
19758 src = src.substring(cap[0].length);
19764 if (cap = this.rules.autolink.exec(src)) {
19765 src = src.substring(cap[0].length);
19766 if (cap[2] === '@') {
19767 text = cap[1][6] === ':'
19768 ? this.mangle(cap[1].substring(7))
19769 : this.mangle(cap[1]);
19770 href = this.mangle('mailto:') + text;
19772 text = escape(cap[1]);
19784 if (cap = this.rules.url.exec(src)) {
19785 src = src.substring(cap[0].length);
19786 text = escape(cap[1]);
19797 if (cap = this.rules.tag.exec(src)) {
19798 src = src.substring(cap[0].length);
19799 out += this.options.sanitize
19806 if (cap = this.rules.link.exec(src)) {
19807 src = src.substring(cap[0].length);
19808 out += this.outputLink(cap, {
19816 if ((cap = this.rules.reflink.exec(src))
19817 || (cap = this.rules.nolink.exec(src))) {
19818 src = src.substring(cap[0].length);
19819 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19820 link = this.links[link.toLowerCase()];
19821 if (!link || !link.href) {
19823 src = cap[0].substring(1) + src;
19826 out += this.outputLink(cap, link);
19831 if (cap = this.rules.strong.exec(src)) {
19832 src = src.substring(cap[0].length);
19834 + this.output(cap[2] || cap[1])
19840 if (cap = this.rules.em.exec(src)) {
19841 src = src.substring(cap[0].length);
19843 + this.output(cap[2] || cap[1])
19849 if (cap = this.rules.code.exec(src)) {
19850 src = src.substring(cap[0].length);
19852 + escape(cap[2], true)
19858 if (cap = this.rules.br.exec(src)) {
19859 src = src.substring(cap[0].length);
19865 if (cap = this.rules.del.exec(src)) {
19866 src = src.substring(cap[0].length);
19868 + this.output(cap[1])
19874 if (cap = this.rules.text.exec(src)) {
19875 src = src.substring(cap[0].length);
19876 out += escape(cap[0]);
19882 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19893 InlineLexer.prototype.outputLink = function(cap, link) {
19894 if (cap[0][0] !== '!') {
19896 + escape(link.href)
19900 + escape(link.title)
19904 + this.output(cap[1])
19907 return '<img src="'
19908 + escape(link.href)
19914 + escape(link.title)
19922 * Smartypants Transformations
19925 InlineLexer.prototype.smartypants = function(text) {
19926 if (!this.options.smartypants) return text;
19928 .replace(/--/g, '—')
19929 .replace(/'([^']*)'/g, '‘$1’')
19930 .replace(/"([^"]*)"/g, '“$1”')
19931 .replace(/\.{3}/g, '…');
19938 InlineLexer.prototype.mangle = function(text) {
19944 for (; i < l; i++) {
19945 ch = text.charCodeAt(i);
19946 if (Math.random() > 0.5) {
19947 ch = 'x' + ch.toString(16);
19949 out += '&#' + ch + ';';
19956 * Parsing & Compiling
19959 function Parser(options) {
19962 this.options = options || marked.defaults;
19966 * Static Parse Method
19969 Parser.parse = function(src, options) {
19970 var parser = new Parser(options);
19971 return parser.parse(src);
19978 Parser.prototype.parse = function(src) {
19979 this.inline = new InlineLexer(src.links, this.options);
19980 this.tokens = src.reverse();
19983 while (this.next()) {
19994 Parser.prototype.next = function() {
19995 return this.token = this.tokens.pop();
19999 * Preview Next Token
20002 Parser.prototype.peek = function() {
20003 return this.tokens[this.tokens.length-1] || 0;
20007 * Parse Text Tokens
20010 Parser.prototype.parseText = function() {
20011 var body = this.token.text;
20013 while (this.peek().type === 'text') {
20014 body += '\n' + this.next().text;
20017 return this.inline.output(body);
20021 * Parse Current Token
20024 Parser.prototype.tok = function() {
20025 switch (this.token.type) {
20036 + this.inline.output(this.token.text)
20042 if (this.options.highlight) {
20043 var code = this.options.highlight(this.token.text, this.token.lang);
20044 if (code != null && code !== this.token.text) {
20045 this.token.escaped = true;
20046 this.token.text = code;
20050 if (!this.token.escaped) {
20051 this.token.text = escape(this.token.text, true);
20054 return '<pre><code'
20057 + this.options.langPrefix
20063 + '</code></pre>\n';
20074 body += '<thead>\n<tr>\n';
20075 for (i = 0; i < this.token.header.length; i++) {
20076 heading = this.inline.output(this.token.header[i]);
20077 body += this.token.align[i]
20078 ? '<th align="' + this.token.align[i] + '">' + heading + '</th>\n'
20079 : '<th>' + heading + '</th>\n';
20081 body += '</tr>\n</thead>\n';
20084 body += '<tbody>\n'
20085 for (i = 0; i < this.token.cells.length; i++) {
20086 row = this.token.cells[i];
20088 for (j = 0; j < row.length; j++) {
20089 cell = this.inline.output(row[j]);
20090 body += this.token.align[j]
20091 ? '<td align="' + this.token.align[j] + '">' + cell + '</td>\n'
20092 : '<td>' + cell + '</td>\n';
20096 body += '</tbody>\n';
20102 case 'blockquote_start': {
20105 while (this.next().type !== 'blockquote_end') {
20106 body += this.tok();
20109 return '<blockquote>\n'
20111 + '</blockquote>\n';
20113 case 'list_start': {
20114 var type = this.token.ordered ? 'ol' : 'ul'
20117 while (this.next().type !== 'list_end') {
20118 body += this.tok();
20129 case 'list_item_start': {
20132 while (this.next().type !== 'list_item_end') {
20133 body += this.token.type === 'text'
20142 case 'loose_item_start': {
20145 while (this.next().type !== 'list_item_end') {
20146 body += this.tok();
20154 return !this.token.pre && !this.options.pedantic
20155 ? this.inline.output(this.token.text)
20158 case 'paragraph': {
20160 + this.inline.output(this.token.text)
20175 function escape(html, encode) {
20177 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
20178 .replace(/</g, '<')
20179 .replace(/>/g, '>')
20180 .replace(/"/g, '"')
20181 .replace(/'/g, ''');
20184 function replace(regex, opt) {
20185 regex = regex.source;
20187 return function self(name, val) {
20188 if (!name) return new RegExp(regex, opt);
20189 val = val.source || val;
20190 val = val.replace(/(^|[^\[])\^/g, '$1');
20191 regex = regex.replace(name, val);
20199 function merge(obj) {
20204 for (; i < arguments.length; i++) {
20205 target = arguments[i];
20206 for (key in target) {
20207 if (Object.prototype.hasOwnProperty.call(target, key)) {
20208 obj[key] = target[key];
20220 function marked(src, opt, callback) {
20221 if (callback || typeof opt === 'function') {
20227 if (opt) opt = merge({}, marked.defaults, opt);
20229 var tokens = Lexer.lex(tokens, opt)
20230 , highlight = opt.highlight
20232 , l = tokens.length
20235 if (!highlight || highlight.length < 3) {
20236 return callback(null, Parser.parse(tokens, opt));
20239 var done = function() {
20240 delete opt.highlight;
20241 var out = Parser.parse(tokens, opt);
20242 opt.highlight = highlight;
20243 return callback(null, out);
20246 for (; i < l; i++) {
20248 if (token.type !== 'code') return;
20250 return highlight(token.text, token.lang, function(err, code) {
20251 if (code == null || code === token.text) {
20252 return --pending || done();
20255 token.escaped = true;
20256 --pending || done();
20264 if (opt) opt = merge({}, marked.defaults, opt);
20265 return Parser.parse(Lexer.lex(src, opt), opt);
20267 e.message += '\nPlease report this to https://github.com/chjj/marked.';
20268 if ((opt || marked.defaults).silent) {
20269 return '<p>An error occured:</p><pre>'
20270 + escape(e.message + '', true)
20282 marked.setOptions = function(opt) {
20283 merge(marked.defaults, opt);
20287 marked.defaults = {
20296 langPrefix: 'lang-'
20303 marked.Parser = Parser;
20304 marked.parser = Parser.parse;
20306 marked.Lexer = Lexer;
20307 marked.lexer = Lexer.lex;
20309 marked.InlineLexer = InlineLexer;
20310 marked.inlineLexer = InlineLexer.output;
20312 marked.parse = marked;
20314 if (typeof exports === 'object') {
20315 module.exports = marked;
20316 } else if (typeof define === 'function' && define.amd) {
20317 define(function() { return marked; });
20319 this.marked = marked;
20322 }).call(function() {
20323 return this || (typeof window !== 'undefined' ? window : global);
20327 window.iD = function () {
20328 window.locale.en = iD.data.en;
20329 window.locale.current('en');
20331 var dispatch = d3.dispatch('enter', 'exit', 'change'),
20334 // https://github.com/openstreetmap/iD/issues/772
20335 // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
20337 try { storage = localStorage; } catch (e) {} // eslint-disable-line no-empty
20338 storage = storage || (function() {
20341 getItem: function(k) { return s[k]; },
20342 setItem: function(k, v) { s[k] = v; },
20343 removeItem: function(k) { delete s[k]; }
20347 context.storage = function(k, v) {
20349 if (arguments.length === 1) return storage.getItem(k);
20350 else if (v === null) storage.removeItem(k);
20351 else storage.setItem(k, v);
20353 // localstorage quota exceeded
20354 /* eslint-disable no-console */
20355 if (typeof console !== 'undefined') console.error('localStorage quota exceeded');
20356 /* eslint-enable no-console */
20361 /* Straight accessors. Avoid using these if you can. */
20362 var ui, connection, history;
20363 context.ui = function() { return ui; };
20364 context.connection = function() { return connection; };
20365 context.history = function() { return history; };
20369 function entitiesLoaded(err, result) {
20370 if (!err) history.merge(result.data, result.extent);
20373 context.preauth = function(options) {
20374 connection.switch(options);
20378 context.loadTiles = function(projection, dimensions, callback) {
20379 function done(err, result) {
20380 entitiesLoaded(err, result);
20381 if (callback) callback(err, result);
20383 connection.loadTiles(projection, dimensions, done);
20386 context.loadEntity = function(id, callback) {
20387 function done(err, result) {
20388 entitiesLoaded(err, result);
20389 if (callback) callback(err, result);
20391 connection.loadEntity(id, done);
20394 context.zoomToEntity = function(id, zoomTo) {
20395 if (zoomTo !== false) {
20396 this.loadEntity(id, function(err, result) {
20398 var entity = _.find(result.data, function(e) { return e.id === id; });
20399 if (entity) { map.zoomTo(entity); }
20403 map.on('drawn.zoomToEntity', function() {
20404 if (!context.hasEntity(id)) return;
20405 map.on('drawn.zoomToEntity', null);
20406 context.on('enter.zoomToEntity', null);
20407 context.enter(iD.modes.Select(context, [id]));
20410 context.on('enter.zoomToEntity', function() {
20411 if (mode.id !== 'browse') {
20412 map.on('drawn.zoomToEntity', null);
20413 context.on('enter.zoomToEntity', null);
20418 var minEditableZoom = 16;
20419 context.minEditableZoom = function(_) {
20420 if (!arguments.length) return minEditableZoom;
20421 minEditableZoom = _;
20422 connection.tileZoom(_);
20428 var inIntro = false;
20429 context.inIntro = function(_) {
20430 if (!arguments.length) return inIntro;
20435 context.save = function() {
20436 if (inIntro || (mode && mode.id === 'save') || d3.select('.modal').size()) return;
20438 if (history.hasChanges()) return t('save.unsaved_changes');
20441 context.flush = function() {
20442 context.debouncedSave.cancel();
20443 connection.flush();
20446 _.each(iD.services, function(service) {
20447 var reset = service().reset;
20448 if (reset) reset(context);
20455 context.hasEntity = function(id) {
20456 return history.graph().hasEntity(id);
20458 context.entity = function(id) {
20459 return history.graph().entity(id);
20461 context.childNodes = function(way) {
20462 return history.graph().childNodes(way);
20464 context.geometry = function(id) {
20465 return context.entity(id).geometry(history.graph());
20471 context.mode = function() {
20474 context.enter = function(newMode) {
20477 dispatch.exit(mode);
20482 dispatch.enter(mode);
20485 context.selectedIDs = function() {
20486 if (mode && mode.selectedIDs) {
20487 return mode.selectedIDs();
20495 context.install = function(behavior) {
20496 context.surface().call(behavior);
20498 context.uninstall = function(behavior) {
20499 context.surface().call(behavior.off);
20504 var copyIDs = [], copyGraph;
20505 context.copyGraph = function() { return copyGraph; };
20506 context.copyIDs = function(_) {
20507 if (!arguments.length) return copyIDs;
20509 copyGraph = history.graph();
20516 context.background = function() { return background; };
20521 context.features = function() { return features; };
20522 context.hasHiddenConnections = function(id) {
20523 var graph = history.graph(),
20524 entity = graph.entity(id);
20525 return features.hasHiddenConnections(entity, graph);
20531 context.map = function() { return map; };
20532 context.layers = function() { return map.layers; };
20533 context.surface = function() { return map.surface; };
20534 context.editable = function() { return map.editable(); };
20536 context.surfaceRect = function() {
20537 // Work around a bug in Firefox.
20538 // http://stackoverflow.com/questions/18153989/
20539 // https://bugzilla.mozilla.org/show_bug.cgi?id=530985
20540 return context.surface().node().parentNode.getBoundingClientRect();
20552 context.debugFlags = function() {
20555 context.setDebug = function(flag, val) {
20556 if (arguments.length === 1) val = true;
20557 debugFlags[flag] = val;
20561 context.getDebug = function(flag) {
20562 return flag && debugFlags[flag];
20568 context.presets = function(_) {
20569 if (!arguments.length) return presets;
20571 iD.areaKeys = presets.areaKeys();
20577 context.imagery = function(_) {
20578 background.load(_);
20584 var container, embed;
20585 context.container = function(_) {
20586 if (!arguments.length) return container;
20588 container.classed('id-container', true);
20591 context.embed = function(_) {
20592 if (!arguments.length) return embed;
20600 context.taginfo = function(_) {
20601 if (!arguments.length) return taginfo;
20608 var assetPath = '';
20609 context.assetPath = function(_) {
20610 if (!arguments.length) return assetPath;
20616 context.assetMap = function(_) {
20617 if (!arguments.length) return assetMap;
20622 context.asset = function(_) {
20623 var filename = assetPath + _;
20624 return assetMap[filename] || filename;
20627 context.imagePath = function(_) {
20628 return context.asset('img/' + _);
20631 var locale, localePath;
20632 context.locale = function(loc, path) {
20636 // Also set iD.detect().locale (unless we detected 'en-us' and openstreetmap wants 'en')..
20637 if (!(loc.toLowerCase() === 'en' && iD.detect().locale.toLowerCase() === 'en-us')) {
20638 iD.detect().locale = loc;
20644 context.loadLocale = function(cb) {
20645 if (locale && locale !== 'en' && iD.data.locales.indexOf(locale) !== -1) {
20646 localePath = localePath || context.asset('locales/' + locale + '.json');
20647 d3.json(localePath, function(err, result) {
20648 window.locale[locale] = result;
20649 window.locale.current(locale);
20660 context.projection = iD.geo.RawMercator();
20662 locale = iD.detect().locale;
20663 if (locale && iD.data.locales.indexOf(locale) === -1) {
20664 locale = locale.split('-')[0];
20667 history = iD.History(context);
20668 context.graph = history.graph;
20669 context.changes = history.changes;
20670 context.intersects = history.intersects;
20672 // Debounce save, since it's a synchronous localStorage write,
20673 // and history changes can happen frequently (e.g. when dragging).
20674 context.debouncedSave = _.debounce(context.save, 350);
20675 function withDebouncedSave(fn) {
20676 return function() {
20677 var result = fn.apply(history, arguments);
20678 context.debouncedSave();
20683 context.perform = withDebouncedSave(history.perform);
20684 context.replace = withDebouncedSave(history.replace);
20685 context.pop = withDebouncedSave(history.pop);
20686 context.overwrite = withDebouncedSave(history.overwrite);
20687 context.undo = withDebouncedSave(history.undo);
20688 context.redo = withDebouncedSave(history.redo);
20690 ui = iD.ui(context);
20692 connection = iD.Connection();
20694 background = iD.Background(context);
20696 features = iD.Features(context);
20698 map = iD.Map(context);
20699 context.mouse = map.mouse;
20700 context.extent = map.extent;
20701 context.pan = map.pan;
20702 context.zoomIn = map.zoomIn;
20703 context.zoomOut = map.zoomOut;
20704 context.zoomInFurther = map.zoomInFurther;
20705 context.zoomOutFurther = map.zoomOutFurther;
20706 context.redrawEnable = map.redrawEnable;
20708 presets = iD.presets();
20710 return d3.rebind(context, dispatch, 'on');
20714 iD.version = '1.9.7';
20719 var ua = navigator.userAgent,
20722 m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
20724 detected.browser = m[1];
20725 detected.version = m[2];
20727 if (!detected.browser) {
20728 m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
20730 detected.browser = 'msie';
20731 detected.version = m[1];
20734 if (!detected.browser) {
20735 m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
20737 detected.browser = 'Opera';
20738 detected.version = m[2];
20741 if (!detected.browser) {
20742 m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
20744 detected.browser = m[1];
20745 detected.version = m[2];
20746 m = ua.match(/version\/([\.\d]+)/i);
20747 if (m !== null) detected.version = m[1];
20750 if (!detected.browser) {
20751 detected.browser = navigator.appName;
20752 detected.version = navigator.appVersion;
20755 // keep major.minor version only..
20756 detected.version = detected.version.split(/\W/).slice(0,2).join('.');
20758 if (detected.browser.toLowerCase() === 'msie') {
20759 detected.ie = true;
20760 detected.browser = 'Internet Explorer';
20761 detected.support = parseFloat(detected.version) >= 11;
20763 detected.ie = false;
20764 detected.support = true;
20767 // Added due to incomplete svg style support. See #715
20768 detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 );
20770 detected.locale = (navigator.languages && navigator.languages.length)
20771 ? navigator.languages[0] : (navigator.language || navigator.userLanguage || 'en-US');
20773 detected.filedrop = (window.FileReader && 'ondrop' in window);
20776 return navigator.userAgent.indexOf(x) !== -1;
20780 detected.os = 'win';
20781 detected.platform = 'Windows';
20783 else if (nav('Mac')) {
20784 detected.os = 'mac';
20785 detected.platform = 'Macintosh';
20787 else if (nav('X11') || nav('Linux')) {
20788 detected.os = 'linux';
20789 detected.platform = 'Linux';
20792 detected.os = 'win';
20793 detected.platform = 'Unknown';
20796 iD.detect = function() { return detected; };
20799 iD.services.mapillary = function() {
20800 var mapillary = {},
20801 dispatch = d3.dispatch('loadedImages', 'loadedSigns'),
20802 apibase = 'https://a.mapillary.com/v2/',
20803 viewercss = 'https://npmcdn.com/mapillary-js@1.3.0/dist/mapillary-js.min.css',
20804 viewerjs = 'https://npmcdn.com/mapillary-js@1.3.0/dist/mapillary-js.min.js',
20805 clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi',
20811 function loadSignStyles(context) {
20812 d3.select('head').selectAll('#traffico')
20816 .attr('id', 'traffico')
20817 .attr('rel', 'stylesheet')
20818 .attr('href', context.asset('traffico/stylesheets/traffico.css'));
20821 function loadSignDefs(context) {
20822 if (iD.services.mapillary.sign_defs) return;
20823 iD.services.mapillary.sign_defs = {};
20825 _.each(['au', 'br', 'ca', 'de', 'us'], function(region) {
20826 d3.json(context.asset('traffico/string-maps/' + region + '-map.json'), function(err, data) {
20828 if (region === 'de') region = 'eu';
20829 iD.services.mapillary.sign_defs[region] = data;
20834 function loadViewer() {
20836 var wrap = d3.select('#content').selectAll('.mapillary-wrap')
20839 var enter = wrap.enter().append('div')
20840 .attr('class', 'mapillary-wrap')
20841 .classed('al', true) // 'al'=left, 'ar'=right
20842 .classed('hidden', true);
20844 enter.append('button')
20845 .attr('class', 'thumb-hide')
20846 .on('click', function () { mapillary.hideViewer(); })
20848 .call(iD.svg.Icon('#icon-close'));
20850 enter.append('div')
20852 .attr('class', 'mly-wrapper')
20853 .classed('active', false);
20855 // mapillary-viewercss
20856 d3.select('head').selectAll('#mapillary-viewercss')
20860 .attr('id', 'mapillary-viewercss')
20861 .attr('rel', 'stylesheet')
20862 .attr('href', viewercss);
20864 // mapillary-viewerjs
20865 d3.select('head').selectAll('#mapillary-viewerjs')
20869 .attr('id', 'mapillary-viewerjs')
20870 .attr('src', viewerjs);
20873 function initViewer(imageKey, context) {
20875 function nodeChanged(d) {
20876 var clicks = iD.services.mapillary.clicks;
20877 var index = clicks.indexOf(d.key);
20878 if (index > -1) { // nodechange initiated from clicking on a marker..
20879 clicks.splice(index, 1);
20880 } else { // nodechange initiated from the Mapillary viewer controls..
20881 var loc = d.apiNavImIm ? [d.apiNavImIm.lon, d.apiNavImIm.lat] : [d.latLon.lon, d.latLon.lat];
20882 context.map().centerEase(loc);
20883 mapillary.setSelectedImage(d.key, false);
20887 if (Mapillary && imageKey) {
20889 baseImageSize: 320,
20898 var viewer = new Mapillary.Viewer('mly', clientId, imageKey, opts);
20899 viewer.on('nodechanged', nodeChanged);
20900 viewer.on('loadingchanged', mapillary.setViewerLoading);
20901 iD.services.mapillary.viewer = viewer;
20905 function abortRequest(i) {
20909 function nearNullIsland(x, y, z) {
20911 var center = Math.pow(2, z - 1),
20912 width = Math.pow(2, z - 6),
20913 min = center - (width / 2),
20914 max = center + (width / 2) - 1;
20915 return x >= min && x <= max && y >= min && y <= max;
20920 function getTiles(projection, dimensions) {
20921 var s = projection.scale() * 2 * Math.PI,
20922 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
20923 ts = 256 * Math.pow(2, z - tileZoom),
20925 s / 2 - projection.translate()[0],
20926 s / 2 - projection.translate()[1]];
20928 return d3.geo.tile()
20929 .scaleExtent([tileZoom, tileZoom])
20932 .translate(projection.translate())()
20933 .map(function(tile) {
20934 var x = tile[0] * ts - origin[0],
20935 y = tile[1] * ts - origin[1];
20938 id: tile.toString(),
20939 extent: iD.geo.Extent(
20940 projection.invert([x, y + ts]),
20941 projection.invert([x + ts, y]))
20947 function loadTiles(which, url, projection, dimensions) {
20948 var tiles = getTiles(projection, dimensions).filter(function(t) {
20949 var xyz = t.id.split(',');
20950 return !nearNullIsland(xyz[0], xyz[1], xyz[2]);
20953 _.filter(which.inflight, function(v, k) {
20954 var wanted = _.find(tiles, function(tile) { return k === (tile.id + ',0'); });
20955 if (!wanted) delete which.inflight[k];
20957 }).map(abortRequest);
20959 tiles.forEach(function(tile) {
20960 loadTilePage(which, url, tile, 0);
20964 function loadTilePage(which, url, tile, page) {
20965 var cache = iD.services.mapillary.cache[which],
20966 id = tile.id + ',' + String(page),
20967 rect = tile.extent.rectangle();
20969 if (cache.loaded[id] || cache.inflight[id]) return;
20971 cache.inflight[id] = d3.json(url +
20976 client_id: clientId,
20981 }), function(err, data) {
20982 cache.loaded[id] = true;
20983 delete cache.inflight[id];
20984 if (err || !data.features || !data.features.length) return;
20987 nextPage = page + 1,
20990 for (var i = 0; i < data.features.length; i++) {
20991 feature = data.features[i];
20992 loc = feature.geometry.coordinates;
20993 d = { key: feature.properties.key, loc: loc };
20994 if (which === 'images') d.ca = feature.properties.ca;
20995 if (which === 'signs') d.signs = feature.properties.rects;
20997 features.push([loc[0], loc[1], loc[0], loc[1], d]);
21000 cache.rtree.load(features);
21002 if (which === 'images') dispatch.loadedImages();
21003 if (which === 'signs') dispatch.loadedSigns();
21005 if (data.features.length === maxResults && nextPage < maxPages) {
21006 loadTilePage(which, url, tile, nextPage);
21012 mapillary.loadImages = function(projection, dimensions) {
21013 var url = apibase + 'search/im/geojson?';
21014 loadTiles('images', url, projection, dimensions);
21017 mapillary.loadSigns = function(context, projection, dimensions) {
21018 var url = apibase + 'search/im/geojson/or?';
21019 loadSignStyles(context);
21020 loadSignDefs(context);
21021 loadTiles('signs', url, projection, dimensions);
21024 mapillary.loadViewer = function() {
21029 // partition viewport into `psize` x `psize` regions
21030 function partitionViewport(psize, projection, dimensions) {
21031 psize = psize || 16;
21032 var cols = d3.range(0, dimensions[0], psize),
21033 rows = d3.range(0, dimensions[1], psize),
21036 rows.forEach(function(y) {
21037 cols.forEach(function(x) {
21038 var min = [x, y + psize],
21039 max = [x + psize, y];
21041 iD.geo.Extent(projection.invert(min), projection.invert(max)));
21048 // no more than `limit` results per partition.
21049 function searchLimited(psize, limit, projection, dimensions, rtree) {
21050 limit = limit || 3;
21052 var partitions = partitionViewport(psize, projection, dimensions);
21053 return _.flatten(_.compact(_.map(partitions, function(extent) {
21054 return rtree.search(extent.rectangle())
21056 .map(function(d) { return d[4]; });
21060 mapillary.images = function(projection, dimensions) {
21061 var psize = 16, limit = 3;
21062 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.images.rtree);
21065 mapillary.signs = function(projection, dimensions) {
21066 var psize = 32, limit = 3;
21067 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.signs.rtree);
21070 mapillary.signsSupported = function() {
21071 var detected = iD.detect();
21072 return (!(detected.ie || detected.browser.toLowerCase() === 'safari'));
21075 mapillary.signHTML = function(d) {
21076 if (!iD.services.mapillary.sign_defs) return;
21078 var detectionPackage = d.signs[0].package,
21079 type = d.signs[0].type,
21080 country = detectionPackage.split('_')[1];
21082 return iD.services.mapillary.sign_defs[country][type];
21085 mapillary.showViewer = function() {
21086 d3.select('#content')
21087 .selectAll('.mapillary-wrap')
21088 .classed('hidden', false)
21089 .selectAll('.mly-wrapper')
21090 .classed('active', true);
21095 mapillary.hideViewer = function() {
21096 d3.select('#content')
21097 .selectAll('.mapillary-wrap')
21098 .classed('hidden', true)
21099 .selectAll('.mly-wrapper')
21100 .classed('active', false);
21102 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
21103 .classed('selected', false);
21105 iD.services.mapillary.image = null;
21110 mapillary.setViewerLoading = function(loading) {
21111 var canvas = d3.select('#content')
21112 .selectAll('.mly-wrapper canvas');
21114 if (canvas.empty()) return; // viewer not loaded yet
21116 var cover = d3.select('#content')
21117 .selectAll('.mly-wrapper .Cover');
21119 cover.classed('CoverDone', !loading);
21121 var button = cover.selectAll('.CoverButton')
21122 .data(loading ? [0] : []);
21126 .attr('class', 'CoverButton')
21128 .attr('class', 'uil-ripple-css')
21137 mapillary.updateViewer = function(imageKey, context) {
21138 if (!iD.services.mapillary) return;
21139 if (!imageKey) return;
21141 if (!iD.services.mapillary.viewer) {
21142 initViewer(imageKey, context);
21144 iD.services.mapillary.viewer.moveToKey(imageKey);
21150 mapillary.getSelectedImage = function() {
21151 if (!iD.services.mapillary) return null;
21152 return iD.services.mapillary.image;
21155 mapillary.setSelectedImage = function(imageKey, fromClick) {
21156 if (!iD.services.mapillary) return null;
21158 iD.services.mapillary.image = imageKey;
21160 iD.services.mapillary.clicks.push(imageKey);
21163 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
21164 .classed('selected', function(d) { return d.key === imageKey; });
21169 mapillary.reset = function() {
21170 var cache = iD.services.mapillary.cache;
21173 _.forEach(cache.images.inflight, abortRequest);
21174 _.forEach(cache.signs.inflight, abortRequest);
21177 iD.services.mapillary.cache = {
21178 images: { inflight: {}, loaded: {}, rtree: rbush() },
21179 signs: { inflight: {}, loaded: {}, rtree: rbush() }
21182 iD.services.mapillary.image = null;
21183 iD.services.mapillary.clicks = [];
21189 if (!iD.services.mapillary.cache) {
21193 return d3.rebind(mapillary, dispatch, 'on');
21195 iD.services.nominatim = function() {
21196 var nominatim = {},
21197 endpoint = 'https://nominatim.openstreetmap.org/reverse?';
21200 nominatim.countryCode = function(location, callback) {
21201 var cache = iD.services.nominatim.cache,
21202 countryCodes = cache.search([location[0], location[1], location[0], location[1]]);
21204 if (countryCodes.length > 0)
21205 return callback(null, countryCodes[0][4]);
21213 }), function(err, result) {
21215 return callback(err);
21216 else if (result && result.error)
21217 return callback(result.error);
21219 var extent = iD.geo.Extent(location).padByMeters(1000);
21221 cache.insert(extent.rectangle().concat(result.address.country_code));
21223 callback(null, result.address.country_code);
21227 nominatim.reset = function() {
21228 iD.services.nominatim.cache = rbush();
21233 if (!iD.services.nominatim.cache) {
21239 iD.services.taginfo = function() {
21241 endpoint = 'https://taginfo.openstreetmap.org/api/4/',
21243 point: 'count_nodes',
21244 vertex: 'count_nodes',
21245 area: 'count_ways',
21256 function sets(parameters, n, o) {
21257 if (parameters.geometry && o[parameters.geometry]) {
21258 parameters[n] = o[parameters.geometry];
21263 function setFilter(parameters) {
21264 return sets(parameters, 'filter', tag_filters);
21267 function setSort(parameters) {
21268 return sets(parameters, 'sortname', tag_sorts);
21271 function clean(parameters) {
21272 return _.omit(parameters, 'geometry', 'debounce');
21275 function filterKeys(type) {
21276 var count_type = type ? 'count_' + type : 'count_all';
21277 return function(d) {
21278 return parseFloat(d[count_type]) > 2500 || d.in_wiki;
21282 function filterMultikeys() {
21283 return function(d) {
21284 return (d.key.match(/:/g) || []).length === 1; // exactly one ':'
21288 function filterValues() {
21289 return function(d) {
21290 if (d.value.match(/[A-Z*;,]/) !== null) return false; // exclude some punctuation, uppercase letters
21291 return parseFloat(d.fraction) > 0.0 || d.in_wiki;
21295 function valKey(d) {
21302 function valKeyDescription(d) {
21305 title: d.description || d.value
21309 // sort keys with ':' lower than keys without ':'
21310 function sortKeys(a, b) {
21311 return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
21312 : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
21316 var debounced = _.debounce(d3.json, 100, true);
21318 function request(url, debounce, callback) {
21319 var cache = iD.services.taginfo.cache;
21322 callback(null, cache[url]);
21323 } else if (debounce) {
21324 debounced(url, done);
21326 d3.json(url, done);
21329 function done(err, data) {
21330 if (!err) cache[url] = data;
21331 callback(err, data);
21335 taginfo.keys = function(parameters, callback) {
21336 var debounce = parameters.debounce;
21337 parameters = clean(setSort(parameters));
21338 request(endpoint + 'keys/all?' +
21339 iD.util.qsString(_.extend({
21341 sortname: 'count_all',
21344 }, parameters)), debounce, function(err, d) {
21345 if (err) return callback(err);
21346 var f = filterKeys(parameters.filter);
21347 callback(null, d.data.filter(f).sort(sortKeys).map(valKey));
21351 taginfo.multikeys = function(parameters, callback) {
21352 var debounce = parameters.debounce;
21353 parameters = clean(setSort(parameters));
21354 request(endpoint + 'keys/all?' +
21355 iD.util.qsString(_.extend({
21357 sortname: 'count_all',
21360 }, parameters)), debounce, function(err, d) {
21361 if (err) return callback(err);
21362 var f = filterMultikeys();
21363 callback(null, d.data.filter(f).map(valKey));
21367 taginfo.values = function(parameters, callback) {
21368 var debounce = parameters.debounce;
21369 parameters = clean(setSort(setFilter(parameters)));
21370 request(endpoint + 'key/values?' +
21371 iD.util.qsString(_.extend({
21373 sortname: 'count_all',
21376 }, parameters)), debounce, function(err, d) {
21377 if (err) return callback(err);
21378 var f = filterValues();
21379 callback(null, d.data.filter(f).map(valKeyDescription));
21383 taginfo.docs = function(parameters, callback) {
21384 var debounce = parameters.debounce;
21385 parameters = clean(setSort(parameters));
21387 var path = 'key/wiki_pages?';
21388 if (parameters.value) path = 'tag/wiki_pages?';
21389 else if (parameters.rtype) path = 'relation/wiki_pages?';
21391 request(endpoint + path + iD.util.qsString(parameters), debounce, function(err, d) {
21392 if (err) return callback(err);
21393 callback(null, d.data);
21397 taginfo.endpoint = function(_) {
21398 if (!arguments.length) return endpoint;
21403 taginfo.reset = function() {
21404 iD.services.taginfo.cache = {};
21409 if (!iD.services.taginfo.cache) {
21415 iD.services.wikidata = function() {
21417 endpoint = 'https://www.wikidata.org/w/api.php?';
21419 // Given a Wikipedia language and article title, return an array of
21420 // corresponding Wikidata entities.
21421 wiki.itemsByTitle = function(lang, title, callback) {
21422 lang = lang || 'en';
21423 d3.jsonp(endpoint + iD.util.qsString({
21424 action: 'wbgetentities',
21426 sites: lang.replace(/-/g, '_') + 'wiki',
21428 languages: 'en', // shrink response by filtering to one language
21429 callback: '{callback}'
21430 }), function(data) {
21431 callback(title, data.entities || {});
21437 iD.services.wikipedia = function() {
21439 endpoint = 'https://en.wikipedia.org/w/api.php?';
21441 wiki.search = function(lang, query, callback) {
21442 lang = lang || 'en';
21443 d3.jsonp(endpoint.replace('en', lang) +
21448 srinfo: 'suggestion',
21450 callback: '{callback}',
21452 }), function(data) {
21453 if (!data.query) return;
21454 callback(query, data.query.search.map(function(d) {
21460 wiki.suggestions = function(lang, query, callback) {
21461 lang = lang || 'en';
21462 d3.jsonp(endpoint.replace('en', lang) +
21464 action: 'opensearch',
21468 callback: '{callback}',
21471 callback(d[0], d[1]);
21475 wiki.translations = function(lang, title, callback) {
21476 d3.jsonp(endpoint.replace('en', lang) +
21481 callback: '{callback}',
21485 var list = d.query.pages[Object.keys(d.query.pages)[0]],
21487 if (list && list.langlinks) {
21488 list.langlinks.forEach(function(d) {
21489 translations[d.lang] = d['*'];
21491 callback(translations);
21500 iD.util.tagText = function(entity) {
21501 return d3.entries(entity.tags).map(function(e) {
21502 return e.key + '=' + e.value;
21506 iD.util.entitySelector = function(ids) {
21507 return ids.length ? '.' + ids.join(',.') : 'nothing';
21510 iD.util.entityOrMemberSelector = function(ids, graph) {
21511 var s = iD.util.entitySelector(ids);
21513 ids.forEach(function(id) {
21514 var entity = graph.hasEntity(id);
21515 if (entity && entity.type === 'relation') {
21516 entity.members.forEach(function(member) {
21517 s += ',.' + member.id;
21525 iD.util.displayName = function(entity) {
21526 var localeName = 'name:' + iD.detect().locale.toLowerCase().split('-')[0];
21527 return entity.tags[localeName] || entity.tags.name || entity.tags.ref;
21530 iD.util.displayType = function(id) {
21532 n: t('inspector.node'),
21533 w: t('inspector.way'),
21534 r: t('inspector.relation')
21538 iD.util.stringQs = function(str) {
21539 return str.split('&').reduce(function(obj, pair){
21540 var parts = pair.split('=');
21541 if (parts.length === 2) {
21542 obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
21548 iD.util.qsString = function(obj, noencode) {
21549 function softEncode(s) {
21550 // encode everything except special characters used in certain hash parameters:
21551 // "/" in map states, ":", ",", {" and "}" in background
21552 return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
21554 return Object.keys(obj).sort().map(function(key) {
21555 return encodeURIComponent(key) + '=' + (
21556 noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
21560 iD.util.prefixDOMProperty = function(property) {
21561 var prefixes = ['webkit', 'ms', 'moz', 'o'],
21563 n = prefixes.length,
21569 property = property.substr(0, 1).toUpperCase() + property.substr(1);
21572 if (prefixes[i] + property in s)
21573 return prefixes[i] + property;
21578 iD.util.prefixCSSProperty = function(property) {
21579 var prefixes = ['webkit', 'ms', 'Moz', 'O'],
21581 n = prefixes.length,
21582 s = document.body.style;
21584 if (property.toLowerCase() in s)
21585 return property.toLowerCase();
21588 if (prefixes[i] + property in s)
21589 return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
21595 iD.util.setTransform = function(el, x, y, scale) {
21596 var prop = iD.util.transformProperty = iD.util.transformProperty || iD.util.prefixCSSProperty('Transform'),
21597 translate = iD.detect().opera ?
21598 'translate(' + x + 'px,' + y + 'px)' :
21599 'translate3d(' + x + 'px,' + y + 'px,0)';
21600 return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
21603 iD.util.getStyle = function(selector) {
21604 for (var i = 0; i < document.styleSheets.length; i++) {
21605 var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules || [];
21606 for (var k = 0; k < rules.length; k++) {
21607 var selectorText = rules[k].selectorText && rules[k].selectorText.split(', ');
21608 if (_.includes(selectorText, selector)) {
21615 iD.util.editDistance = function(a, b) {
21616 if (a.length === 0) return b.length;
21617 if (b.length === 0) return a.length;
21619 for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
21620 for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
21621 for (i = 1; i <= b.length; i++) {
21622 for (j = 1; j <= a.length; j++) {
21623 if (b.charAt(i-1) === a.charAt(j-1)) {
21624 matrix[i][j] = matrix[i-1][j-1];
21626 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
21627 Math.min(matrix[i][j-1] + 1, // insertion
21628 matrix[i-1][j] + 1)); // deletion
21632 return matrix[b.length][a.length];
21635 // a d3.mouse-alike which
21636 // 1. Only works on HTML elements, not SVG
21637 // 2. Does not cause style recalculation
21638 iD.util.fastMouse = function(container) {
21639 var rect = container.getBoundingClientRect(),
21640 rectLeft = rect.left,
21641 rectTop = rect.top,
21642 clientLeft = +container.clientLeft,
21643 clientTop = +container.clientTop;
21644 return function(e) {
21646 e.clientX - rectLeft - clientLeft,
21647 e.clientY - rectTop - clientTop];
21651 /* eslint-disable no-proto */
21652 iD.util.getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
21653 /* eslint-enable no-proto */
21655 iD.util.asyncMap = function(inputs, func, callback) {
21656 var remaining = inputs.length,
21660 inputs.forEach(function(d, i) {
21661 func(d, function done(err, data) {
21665 if (!remaining) callback(errors, results);
21670 // wraps an index to an interval [0..length-1]
21671 iD.util.wrap = function(index, length) {
21673 index += Math.ceil(-index/length)*length;
21674 return index % length;
21676 // A per-domain session mutex backed by a cookie and dead man's
21677 // switch. If the session crashes, the mutex will auto-release
21678 // after 5 seconds.
21680 iD.util.SessionMutex = function(name) {
21685 var expires = new Date();
21686 expires.setSeconds(expires.getSeconds() + 5);
21687 document.cookie = name + '=1; expires=' + expires.toUTCString();
21690 mutex.lock = function() {
21691 if (intervalID) return true;
21692 var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
21693 if (cookie) return false;
21695 intervalID = window.setInterval(renew, 4000);
21699 mutex.unlock = function() {
21700 if (!intervalID) return;
21701 document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
21702 clearInterval(intervalID);
21706 mutex.locked = function() {
21707 return !!intervalID;
21712 iD.util.SuggestNames = function(preset, suggestions) {
21713 preset = preset.id.split('/', 2);
21717 return function(value, callback) {
21719 if (value && value.length > 2) {
21720 if (suggestions[k] && suggestions[k][v]) {
21721 for (var sugg in suggestions[k][v]) {
21722 var dist = iD.util.editDistance(value, sugg.substring(0, value.length));
21732 result.sort(function(a, b) {
21733 return a.dist - b.dist;
21736 result = result.slice(0,3);
21742 iD.geo.roundCoords = function(c) {
21743 return [Math.floor(c[0]), Math.floor(c[1])];
21746 iD.geo.interp = function(p1, p2, t) {
21747 return [p1[0] + (p2[0] - p1[0]) * t,
21748 p1[1] + (p2[1] - p1[1]) * t];
21751 // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
21752 // Returns a positive value, if OAB makes a counter-clockwise turn,
21753 // negative for clockwise turn, and zero if the points are collinear.
21754 iD.geo.cross = function(o, a, b) {
21755 return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
21758 // http://jsperf.com/id-dist-optimization
21759 iD.geo.euclideanDistance = function(a, b) {
21760 var x = a[0] - b[0], y = a[1] - b[1];
21761 return Math.sqrt((x * x) + (y * y));
21764 // using WGS84 polar radius (6356752.314245179 m)
21765 // const = 2 * PI * r / 360
21766 iD.geo.latToMeters = function(dLat) {
21767 return dLat * 110946.257617;
21770 // using WGS84 equatorial radius (6378137.0 m)
21771 // const = 2 * PI * r / 360
21772 iD.geo.lonToMeters = function(dLon, atLat) {
21773 return Math.abs(atLat) >= 90 ? 0 :
21774 dLon * 111319.490793 * Math.abs(Math.cos(atLat * (Math.PI/180)));
21777 // using WGS84 polar radius (6356752.314245179 m)
21778 // const = 2 * PI * r / 360
21779 iD.geo.metersToLat = function(m) {
21780 return m / 110946.257617;
21783 // using WGS84 equatorial radius (6378137.0 m)
21784 // const = 2 * PI * r / 360
21785 iD.geo.metersToLon = function(m, atLat) {
21786 return Math.abs(atLat) >= 90 ? 0 :
21787 m / 111319.490793 / Math.abs(Math.cos(atLat * (Math.PI/180)));
21790 iD.geo.offsetToMeters = function(offset) {
21791 var equatRadius = 6356752.314245179,
21792 polarRadius = 6378137.0,
21796 offset[0] * 2 * Math.PI * equatRadius / tileSize,
21797 -offset[1] * 2 * Math.PI * polarRadius / tileSize
21801 iD.geo.metersToOffset = function(meters) {
21802 var equatRadius = 6356752.314245179,
21803 polarRadius = 6378137.0,
21807 meters[0] * tileSize / (2 * Math.PI * equatRadius),
21808 -meters[1] * tileSize / (2 * Math.PI * polarRadius)
21812 // Equirectangular approximation of spherical distances on Earth
21813 iD.geo.sphericalDistance = function(a, b) {
21814 var x = iD.geo.lonToMeters(a[0] - b[0], (a[1] + b[1]) / 2),
21815 y = iD.geo.latToMeters(a[1] - b[1]);
21816 return Math.sqrt((x * x) + (y * y));
21819 iD.geo.edgeEqual = function(a, b) {
21820 return (a[0] === b[0] && a[1] === b[1]) ||
21821 (a[0] === b[1] && a[1] === b[0]);
21824 // Return the counterclockwise angle in the range (-pi, pi)
21825 // between the positive X axis and the line intersecting a and b.
21826 iD.geo.angle = function(a, b, projection) {
21827 a = projection(a.loc);
21828 b = projection(b.loc);
21829 return Math.atan2(b[1] - a[1], b[0] - a[0]);
21832 // Choose the edge with the minimal distance from `point` to its orthogonal
21833 // projection onto that edge, if such a projection exists, or the distance to
21834 // the closest vertex on that edge. Returns an object with the `index` of the
21835 // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
21836 iD.geo.chooseEdge = function(nodes, point, projection) {
21837 var dist = iD.geo.euclideanDistance,
21838 points = nodes.map(function(n) { return projection(n.loc); }),
21842 function dot(p, q) {
21843 return p[0] * q[0] + p[1] * q[1];
21846 for (var i = 0; i < points.length - 1; i++) {
21848 s = [points[i + 1][0] - o[0],
21849 points[i + 1][1] - o[1]],
21850 v = [point[0] - o[0],
21852 proj = dot(v, s) / dot(s, s),
21857 } else if (proj > 1) {
21860 p = [o[0] + proj * s[0], o[1] + proj * s[1]];
21863 var d = dist(p, point);
21867 loc = projection.invert(p);
21878 // Return the intersection point of 2 line segments.
21879 // From https://github.com/pgkelley4/line-segments-intersect
21880 // This uses the vector cross product approach described below:
21881 // http://stackoverflow.com/a/565282/786339
21882 iD.geo.lineIntersection = function(a, b) {
21883 function subtractPoints(point1, point2) {
21884 return [point1[0] - point2[0], point1[1] - point2[1]];
21886 function crossProduct(point1, point2) {
21887 return point1[0] * point2[1] - point1[1] * point2[0];
21890 var p = [a[0][0], a[0][1]],
21891 p2 = [a[1][0], a[1][1]],
21892 q = [b[0][0], b[0][1]],
21893 q2 = [b[1][0], b[1][1]],
21894 r = subtractPoints(p2, p),
21895 s = subtractPoints(q2, q),
21896 uNumerator = crossProduct(subtractPoints(q, p), r),
21897 denominator = crossProduct(r, s);
21899 if (uNumerator && denominator) {
21900 var u = uNumerator / denominator,
21901 t = crossProduct(subtractPoints(q, p), s) / denominator;
21903 if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
21904 return iD.geo.interp(p, p2, t);
21911 iD.geo.pathIntersections = function(path1, path2) {
21912 var intersections = [];
21913 for (var i = 0; i < path1.length - 1; i++) {
21914 for (var j = 0; j < path2.length - 1; j++) {
21915 var a = [ path1[i], path1[i+1] ],
21916 b = [ path2[j], path2[j+1] ],
21917 hit = iD.geo.lineIntersection(a, b);
21918 if (hit) intersections.push(hit);
21921 return intersections;
21924 // Return whether point is contained in polygon.
21926 // `point` should be a 2-item array of coordinates.
21927 // `polygon` should be an array of 2-item arrays of coordinates.
21929 // From https://github.com/substack/point-in-polygon.
21930 // ray-casting algorithm based on
21931 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
21933 iD.geo.pointInPolygon = function(point, polygon) {
21938 for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
21939 var xi = polygon[i][0], yi = polygon[i][1];
21940 var xj = polygon[j][0], yj = polygon[j][1];
21942 var intersect = ((yi > y) !== (yj > y)) &&
21943 (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
21944 if (intersect) inside = !inside;
21950 iD.geo.polygonContainsPolygon = function(outer, inner) {
21951 return _.every(inner, function(point) {
21952 return iD.geo.pointInPolygon(point, outer);
21956 iD.geo.polygonIntersectsPolygon = function(outer, inner, checkSegments) {
21957 function testSegments(outer, inner) {
21958 for (var i = 0; i < outer.length - 1; i++) {
21959 for (var j = 0; j < inner.length - 1; j++) {
21960 var a = [ outer[i], outer[i+1] ],
21961 b = [ inner[j], inner[j+1] ];
21962 if (iD.geo.lineIntersection(a, b)) return true;
21968 function testPoints(outer, inner) {
21969 return _.some(inner, function(point) {
21970 return iD.geo.pointInPolygon(point, outer);
21974 return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
21977 iD.geo.pathLength = function(path) {
21980 for (var i = 0; i < path.length - 1; i++) {
21981 dx = path[i][0] - path[i + 1][0];
21982 dy = path[i][1] - path[i + 1][1];
21983 length += Math.sqrt(dx * dx + dy * dy);
21987 iD.geo.Extent = function geoExtent(min, max) {
21988 if (!(this instanceof iD.geo.Extent)) return new iD.geo.Extent(min, max);
21989 if (min instanceof iD.geo.Extent) {
21991 } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
21995 this[0] = min || [ Infinity, Infinity];
21996 this[1] = max || min || [-Infinity, -Infinity];
22000 iD.geo.Extent.prototype = new Array(2);
22002 _.extend(iD.geo.Extent.prototype, {
22003 equals: function (obj) {
22004 return this[0][0] === obj[0][0] &&
22005 this[0][1] === obj[0][1] &&
22006 this[1][0] === obj[1][0] &&
22007 this[1][1] === obj[1][1];
22010 extend: function(obj) {
22011 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
22012 return iD.geo.Extent([Math.min(obj[0][0], this[0][0]),
22013 Math.min(obj[0][1], this[0][1])],
22014 [Math.max(obj[1][0], this[1][0]),
22015 Math.max(obj[1][1], this[1][1])]);
22018 _extend: function(extent) {
22019 this[0][0] = Math.min(extent[0][0], this[0][0]);
22020 this[0][1] = Math.min(extent[0][1], this[0][1]);
22021 this[1][0] = Math.max(extent[1][0], this[1][0]);
22022 this[1][1] = Math.max(extent[1][1], this[1][1]);
22026 return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
22029 center: function() {
22030 return [(this[0][0] + this[1][0]) / 2,
22031 (this[0][1] + this[1][1]) / 2];
22034 rectangle: function() {
22035 return [this[0][0], this[0][1], this[1][0], this[1][1]];
22038 polygon: function() {
22040 [this[0][0], this[0][1]],
22041 [this[0][0], this[1][1]],
22042 [this[1][0], this[1][1]],
22043 [this[1][0], this[0][1]],
22044 [this[0][0], this[0][1]]
22048 contains: function(obj) {
22049 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
22050 return obj[0][0] >= this[0][0] &&
22051 obj[0][1] >= this[0][1] &&
22052 obj[1][0] <= this[1][0] &&
22053 obj[1][1] <= this[1][1];
22056 intersects: function(obj) {
22057 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
22058 return obj[0][0] <= this[1][0] &&
22059 obj[0][1] <= this[1][1] &&
22060 obj[1][0] >= this[0][0] &&
22061 obj[1][1] >= this[0][1];
22064 intersection: function(obj) {
22065 if (!this.intersects(obj)) return new iD.geo.Extent();
22066 return new iD.geo.Extent([Math.max(obj[0][0], this[0][0]),
22067 Math.max(obj[0][1], this[0][1])],
22068 [Math.min(obj[1][0], this[1][0]),
22069 Math.min(obj[1][1], this[1][1])]);
22072 percentContainedIn: function(obj) {
22073 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
22074 var a1 = this.intersection(obj).area(),
22077 if (a1 === Infinity || a2 === Infinity || a1 === 0 || a2 === 0) {
22084 padByMeters: function(meters) {
22085 var dLat = iD.geo.metersToLat(meters),
22086 dLon = iD.geo.metersToLon(meters, this.center()[1]);
22087 return iD.geo.Extent(
22088 [this[0][0] - dLon, this[0][1] - dLat],
22089 [this[1][0] + dLon, this[1][1] + dLat]);
22092 toParam: function() {
22093 return this.rectangle().join(',');
22097 iD.geo.Turn = function(turn) {
22098 if (!(this instanceof iD.geo.Turn))
22099 return new iD.geo.Turn(turn);
22100 _.extend(this, turn);
22103 iD.geo.Intersection = function(graph, vertexId) {
22104 var vertex = graph.entity(vertexId),
22105 parentWays = graph.parentWays(vertex),
22109 function addHighway(way, adjacentNodeId) {
22110 if (highways[adjacentNodeId]) {
22111 coincident.push(adjacentNodeId);
22113 highways[adjacentNodeId] = way;
22117 // Pre-split ways that would need to be split in
22118 // order to add a restriction. The real split will
22119 // happen when the restriction is added.
22120 parentWays.forEach(function(way) {
22121 if (!way.tags.highway || way.isArea() || way.isDegenerate())
22124 var isFirst = (vertexId === way.first()),
22125 isLast = (vertexId === way.last()),
22126 isAffix = (isFirst || isLast),
22127 isClosingNode = (isFirst && isLast);
22129 if (isAffix && !isClosingNode) {
22130 var index = (isFirst ? 1 : way.nodes.length - 2);
22131 addHighway(way, way.nodes[index]);
22134 var splitIndex, wayA, wayB, indexA, indexB;
22135 if (isClosingNode) {
22136 splitIndex = Math.ceil(way.nodes.length / 2); // split at midpoint
22137 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
22138 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
22140 indexB = way.nodes.length - 2;
22142 splitIndex = _.indexOf(way.nodes, vertex.id, 1); // split at vertexid
22143 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
22144 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
22145 indexA = splitIndex - 1;
22146 indexB = splitIndex + 1;
22148 graph = graph.replace(wayA).replace(wayB);
22149 addHighway(wayA, way.nodes[indexA]);
22150 addHighway(wayB, way.nodes[indexB]);
22154 // remove any ways from this intersection that are coincident
22155 // (i.e. any adjacent node used by more than one intersecting way)
22156 coincident.forEach(function (n) {
22157 delete highways[n];
22161 var intersection = {
22162 highways: highways,
22163 ways: _.values(highways),
22167 intersection.adjacentNodeId = function(fromWayId) {
22168 return _.find(_.keys(highways), function(k) {
22169 return highways[k].id === fromWayId;
22173 intersection.turns = function(fromNodeId) {
22174 var start = highways[fromNodeId];
22178 if (start.first() === vertex.id && start.tags.oneway === 'yes')
22180 if (start.last() === vertex.id && start.tags.oneway === '-1')
22183 function withRestriction(turn) {
22184 graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
22185 if (relation.tags.type !== 'restriction')
22188 var f = relation.memberByRole('from'),
22189 t = relation.memberByRole('to'),
22190 v = relation.memberByRole('via');
22192 if (f && f.id === turn.from.way &&
22193 v && v.id === turn.via.node &&
22194 t && t.id === turn.to.way) {
22195 turn.restriction = relation.id;
22196 } else if (/^only_/.test(relation.tags.restriction) &&
22197 f && f.id === turn.from.way &&
22198 v && v.id === turn.via.node &&
22199 t && t.id !== turn.to.way) {
22200 turn.restriction = relation.id;
22201 turn.indirect_restriction = true;
22205 return iD.geo.Turn(turn);
22210 way: start.id.split(/-(a|b)/)[0]
22212 via = { node: vertex.id },
22215 _.each(highways, function(end, adjacentNodeId) {
22220 if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
22221 turns.push(withRestriction({
22225 node: adjacentNodeId,
22226 way: end.id.split(/-(a|b)/)[0]
22232 if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
22233 turns.push(withRestriction({
22237 node: adjacentNodeId,
22238 way: end.id.split(/-(a|b)/)[0]
22246 if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
22247 turns.push(withRestriction({
22258 return intersection;
22262 iD.geo.inferRestriction = function(graph, from, via, to, projection) {
22263 var fromWay = graph.entity(from.way),
22264 fromNode = graph.entity(from.node),
22265 toWay = graph.entity(to.way),
22266 toNode = graph.entity(to.node),
22267 viaNode = graph.entity(via.node),
22268 fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
22269 (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
22270 toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
22271 (toWay.tags.oneway === '-1' && toWay.last() === via.node),
22272 angle = iD.geo.angle(viaNode, fromNode, projection) -
22273 iD.geo.angle(viaNode, toNode, projection);
22275 angle = angle * 180 / Math.PI;
22280 if (fromNode === toNode)
22281 return 'no_u_turn';
22282 if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
22283 return 'no_u_turn';
22285 return 'no_right_turn';
22287 return 'no_left_turn';
22289 return 'no_straight_on';
22291 // For fixing up rendering of multipolygons with tags on the outer member.
22292 // https://github.com/openstreetmap/iD/issues/613
22293 iD.geo.isSimpleMultipolygonOuterMember = function(entity, graph) {
22294 if (entity.type !== 'way')
22297 var parents = graph.parentRelations(entity);
22298 if (parents.length !== 1)
22301 var parent = parents[0];
22302 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
22305 var members = parent.members, member;
22306 for (var i = 0; i < members.length; i++) {
22307 member = members[i];
22308 if (member.id === entity.id && member.role && member.role !== 'outer')
22309 return false; // Not outer member
22310 if (member.id !== entity.id && (!member.role || member.role === 'outer'))
22311 return false; // Not a simple multipolygon
22317 iD.geo.simpleMultipolygonOuterMember = function(entity, graph) {
22318 if (entity.type !== 'way')
22321 var parents = graph.parentRelations(entity);
22322 if (parents.length !== 1)
22325 var parent = parents[0];
22326 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
22329 var members = parent.members, member, outerMember;
22330 for (var i = 0; i < members.length; i++) {
22331 member = members[i];
22332 if (!member.role || member.role === 'outer') {
22334 return false; // Not a simple multipolygon
22335 outerMember = member;
22339 return outerMember && graph.hasEntity(outerMember.id);
22342 // Join `array` into sequences of connecting ways.
22344 // Segments which share identical start/end nodes will, as much as possible,
22345 // be connected with each other.
22347 // The return value is a nested array. Each constituent array contains elements
22348 // of `array` which have been determined to connect. Each consitituent array
22349 // also has a `nodes` property whose value is an ordered array of member nodes,
22350 // with appropriate order reversal and start/end coordinate de-duplication.
22352 // Members of `array` must have, at minimum, `type` and `id` properties.
22353 // Thus either an array of `iD.Way`s or a relation member array may be
22356 // If an member has a `tags` property, its tags will be reversed via
22357 // `iD.actions.Reverse` in the output.
22359 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
22360 // false) and non-way members are ignored.
22362 iD.geo.joinWays = function(array, graph) {
22363 var joined = [], member, current, nodes, first, last, i, how, what;
22365 array = array.filter(function(member) {
22366 return member.type === 'way' && graph.hasEntity(member.id);
22369 function resolve(member) {
22370 return graph.childNodes(graph.entity(member.id));
22373 function reverse(member) {
22374 return member.tags ? iD.actions.Reverse(member.id, {reverseOneway: true})(graph).entity(member.id) : member;
22377 while (array.length) {
22378 member = array.shift();
22379 current = [member];
22380 current.nodes = nodes = resolve(member).slice();
22381 joined.push(current);
22383 while (array.length && _.first(nodes) !== _.last(nodes)) {
22384 first = _.first(nodes);
22385 last = _.last(nodes);
22387 for (i = 0; i < array.length; i++) {
22389 what = resolve(member);
22391 if (last === _.first(what)) {
22393 what = what.slice(1);
22395 } else if (last === _.last(what)) {
22397 what = what.slice(0, -1).reverse();
22398 member = reverse(member);
22400 } else if (first === _.last(what)) {
22401 how = nodes.unshift;
22402 what = what.slice(0, -1);
22404 } else if (first === _.first(what)) {
22405 how = nodes.unshift;
22406 what = what.slice(1).reverse();
22407 member = reverse(member);
22415 break; // No more joinable ways.
22417 how.apply(current, [member]);
22418 how.apply(nodes, what);
22420 array.splice(i, 1);
22427 Bypasses features of D3's default projection stream pipeline that are unnecessary:
22428 * Antimeridian clipping
22429 * Spherical rotation
22432 iD.geo.RawMercator = function () {
22433 var project = d3.geo.mercator.raw,
22434 k = 512 / Math.PI, // scale
22435 x = 0, y = 0, // translate
22436 clipExtent = [[0, 0], [0, 0]];
22438 function projection(point) {
22439 point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
22440 return [point[0] * k + x, y - point[1] * k];
22443 projection.invert = function(point) {
22444 point = project.invert((point[0] - x) / k, (y - point[1]) / k);
22445 return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
22448 projection.scale = function(_) {
22449 if (!arguments.length) return k;
22454 projection.translate = function(_) {
22455 if (!arguments.length) return [x, y];
22461 projection.clipExtent = function(_) {
22462 if (!arguments.length) return clipExtent;
22467 projection.stream = d3.geo.transform({
22468 point: function(x, y) {
22469 x = projection([x, y]);
22470 this.stream.point(x[0], x[1]);
22477 iD.actions.AddEntity = function(way) {
22478 return function(graph) {
22479 return graph.replace(way);
22482 iD.actions.AddMember = function(relationId, member, memberIndex) {
22483 return function(graph) {
22484 var relation = graph.entity(relationId);
22486 if (isNaN(memberIndex) && member.type === 'way') {
22487 var members = relation.indexedMembers();
22488 members.push(member);
22490 var joined = iD.geo.joinWays(members, graph);
22491 for (var i = 0; i < joined.length; i++) {
22492 var segment = joined[i];
22493 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
22494 if (segment[j] !== member)
22498 memberIndex = segment[j + 1].index;
22499 } else if (j === segment.length - 1) {
22500 memberIndex = segment[j - 1].index + 1;
22502 memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
22508 return graph.replace(relation.addMember(member, memberIndex));
22511 iD.actions.AddMidpoint = function(midpoint, node) {
22512 return function(graph) {
22513 graph = graph.replace(node.move(midpoint.loc));
22515 var parents = _.intersection(
22516 graph.parentWays(graph.entity(midpoint.edge[0])),
22517 graph.parentWays(graph.entity(midpoint.edge[1])));
22519 parents.forEach(function(way) {
22520 for (var i = 0; i < way.nodes.length - 1; i++) {
22521 if (iD.geo.edgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
22522 graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
22524 // Add only one midpoint on doubled-back segments,
22525 // turning them into self-intersections.
22534 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
22535 iD.actions.AddVertex = function(wayId, nodeId, index) {
22536 return function(graph) {
22537 return graph.replace(graph.entity(wayId).addNode(nodeId, index));
22540 iD.actions.ChangeMember = function(relationId, member, memberIndex) {
22541 return function(graph) {
22542 return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
22545 iD.actions.ChangePreset = function(entityId, oldPreset, newPreset) {
22546 return function(graph) {
22547 var entity = graph.entity(entityId),
22548 geometry = entity.geometry(graph),
22549 tags = entity.tags;
22551 if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
22552 if (newPreset) tags = newPreset.applyTags(tags, geometry);
22554 return graph.replace(entity.update({tags: tags}));
22557 iD.actions.ChangeTags = function(entityId, tags) {
22558 return function(graph) {
22559 var entity = graph.entity(entityId);
22560 return graph.replace(entity.update({tags: tags}));
22563 iD.actions.Circularize = function(wayId, projection, maxAngle) {
22564 maxAngle = (maxAngle || 20) * Math.PI / 180;
22566 var action = function(graph) {
22567 var way = graph.entity(wayId);
22569 if (!way.isConvex(graph)) {
22570 graph = action.makeConvex(graph);
22573 var nodes = _.uniq(graph.childNodes(way)),
22574 keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
22575 points = nodes.map(function(n) { return projection(n.loc); }),
22576 keyPoints = keyNodes.map(function(n) { return projection(n.loc); }),
22577 centroid = (points.length === 2) ? iD.geo.interp(points[0], points[1], 0.5) : d3.geom.polygon(points).centroid(),
22578 radius = d3.median(points, function(p) { return iD.geo.euclideanDistance(centroid, p); }),
22579 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
22582 // we need atleast two key nodes for the algorithm to work
22583 if (!keyNodes.length) {
22584 keyNodes = [nodes[0]];
22585 keyPoints = [points[0]];
22588 if (keyNodes.length === 1) {
22589 var index = nodes.indexOf(keyNodes[0]),
22590 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
22592 keyNodes.push(nodes[oppositeIndex]);
22593 keyPoints.push(points[oppositeIndex]);
22596 // key points and nodes are those connected to the ways,
22597 // they are projected onto the circle, inbetween nodes are moved
22598 // to constant intervals between key nodes, extra inbetween nodes are
22599 // added if necessary.
22600 for (var i = 0; i < keyPoints.length; i++) {
22601 var nextKeyNodeIndex = (i + 1) % keyNodes.length,
22602 startNode = keyNodes[i],
22603 endNode = keyNodes[nextKeyNodeIndex],
22604 startNodeIndex = nodes.indexOf(startNode),
22605 endNodeIndex = nodes.indexOf(endNode),
22606 numberNewPoints = -1,
22607 indexRange = endNodeIndex - startNodeIndex,
22608 distance, totalAngle, eachAngle, startAngle, endAngle,
22609 angle, loc, node, j,
22610 inBetweenNodes = [];
22612 if (indexRange < 0) {
22613 indexRange += nodes.length;
22616 // position this key node
22617 distance = iD.geo.euclideanDistance(centroid, keyPoints[i]);
22618 if (distance === 0) { distance = 1e-4; }
22620 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius,
22621 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
22622 graph = graph.replace(keyNodes[i].move(projection.invert(keyPoints[i])));
22624 // figure out the between delta angle we want to match to
22625 startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
22626 endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
22627 totalAngle = endAngle - startAngle;
22629 // detects looping around -pi/pi
22630 if (totalAngle * sign > 0) {
22631 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
22636 eachAngle = totalAngle / (indexRange + numberNewPoints);
22637 } while (Math.abs(eachAngle) > maxAngle);
22639 // move existing points
22640 for (j = 1; j < indexRange; j++) {
22641 angle = startAngle + j * eachAngle;
22642 loc = projection.invert([
22643 centroid[0] + Math.cos(angle)*radius,
22644 centroid[1] + Math.sin(angle)*radius]);
22646 node = nodes[(j + startNodeIndex) % nodes.length].move(loc);
22647 graph = graph.replace(node);
22650 // add new inbetween nodes if necessary
22651 for (j = 0; j < numberNewPoints; j++) {
22652 angle = startAngle + (indexRange + j) * eachAngle;
22653 loc = projection.invert([
22654 centroid[0] + Math.cos(angle) * radius,
22655 centroid[1] + Math.sin(angle) * radius]);
22657 node = iD.Node({loc: loc});
22658 graph = graph.replace(node);
22660 nodes.splice(endNodeIndex + j, 0, node);
22661 inBetweenNodes.push(node.id);
22664 // Check for other ways that share these keyNodes..
22665 // If keyNodes are adjacent in both ways,
22666 // we can add inBetween nodes to that shared way too..
22667 if (indexRange === 1 && inBetweenNodes.length) {
22668 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
22669 endIndex1 = way.nodes.lastIndexOf(endNode.id),
22670 wayDirection1 = (endIndex1 - startIndex1);
22671 if (wayDirection1 < -1) { wayDirection1 = 1; }
22673 /* eslint-disable no-loop-func */
22674 _.each(_.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
22675 if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
22676 var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
22677 endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
22678 wayDirection2 = (endIndex2 - startIndex2),
22679 insertAt = endIndex2;
22680 if (wayDirection2 < -1) { wayDirection2 = 1; }
22682 if (wayDirection1 !== wayDirection2) {
22683 inBetweenNodes.reverse();
22684 insertAt = startIndex2;
22686 for (j = 0; j < inBetweenNodes.length; j++) {
22687 sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
22689 graph = graph.replace(sharedWay);
22692 /* eslint-enable no-loop-func */
22697 // update the way to have all the new nodes
22698 ids = nodes.map(function(n) { return n.id; });
22701 way = way.update({nodes: ids});
22702 graph = graph.replace(way);
22707 action.makeConvex = function(graph) {
22708 var way = graph.entity(wayId),
22709 nodes = _.uniq(graph.childNodes(way)),
22710 points = nodes.map(function(n) { return projection(n.loc); }),
22711 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
22712 hull = d3.geom.hull(points);
22714 // D3 convex hulls go counterclockwise..
22720 for (var i = 0; i < hull.length - 1; i++) {
22721 var startIndex = points.indexOf(hull[i]),
22722 endIndex = points.indexOf(hull[i+1]),
22723 indexRange = (endIndex - startIndex);
22725 if (indexRange < 0) {
22726 indexRange += nodes.length;
22729 // move interior nodes to the surface of the convex hull..
22730 for (var j = 1; j < indexRange; j++) {
22731 var point = iD.geo.interp(hull[i], hull[i+1], j / indexRange),
22732 node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
22733 graph = graph.replace(node);
22739 action.disabled = function(graph) {
22740 if (!graph.entity(wayId).isClosed())
22741 return 'not_closed';
22746 // Connect the ways at the given nodes.
22748 // The last node will survive. All other nodes will be replaced with
22749 // the surviving node in parent ways, and then removed.
22751 // Tags and relation memberships of of non-surviving nodes are merged
22752 // to the survivor.
22754 // This is the inverse of `iD.actions.Disconnect`.
22757 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
22758 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
22760 iD.actions.Connect = function(nodeIds) {
22761 return function(graph) {
22762 var survivor = graph.entity(_.last(nodeIds));
22764 for (var i = 0; i < nodeIds.length - 1; i++) {
22765 var node = graph.entity(nodeIds[i]);
22767 /* eslint-disable no-loop-func */
22768 graph.parentWays(node).forEach(function(parent) {
22769 if (!parent.areAdjacent(node.id, survivor.id)) {
22770 graph = graph.replace(parent.replaceNode(node.id, survivor.id));
22774 graph.parentRelations(node).forEach(function(parent) {
22775 graph = graph.replace(parent.replaceMember(node, survivor));
22777 /* eslint-enable no-loop-func */
22779 survivor = survivor.mergeTags(node.tags);
22780 graph = iD.actions.DeleteNode(node.id)(graph);
22783 graph = graph.replace(survivor);
22788 iD.actions.CopyEntities = function(ids, fromGraph) {
22791 var action = function(graph) {
22792 ids.forEach(function(id) {
22793 fromGraph.entity(id).copy(fromGraph, copies);
22796 for (var id in copies) {
22797 graph = graph.replace(copies[id]);
22803 action.copies = function() {
22809 iD.actions.DeleteMember = function(relationId, memberIndex) {
22810 return function(graph) {
22811 var relation = graph.entity(relationId)
22812 .removeMember(memberIndex);
22814 graph = graph.replace(relation);
22816 if (relation.isDegenerate())
22817 graph = iD.actions.DeleteRelation(relation.id)(graph);
22822 iD.actions.DeleteMultiple = function(ids) {
22824 way: iD.actions.DeleteWay,
22825 node: iD.actions.DeleteNode,
22826 relation: iD.actions.DeleteRelation
22829 var action = function(graph) {
22830 ids.forEach(function(id) {
22831 if (graph.hasEntity(id)) { // It may have been deleted aready.
22832 graph = actions[graph.entity(id).type](id)(graph);
22839 action.disabled = function(graph) {
22840 for (var i = 0; i < ids.length; i++) {
22842 disabled = actions[graph.entity(id).type](id).disabled(graph);
22843 if (disabled) return disabled;
22849 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
22850 iD.actions.DeleteNode = function(nodeId) {
22851 var action = function(graph) {
22852 var node = graph.entity(nodeId);
22854 graph.parentWays(node)
22855 .forEach(function(parent) {
22856 parent = parent.removeNode(nodeId);
22857 graph = graph.replace(parent);
22859 if (parent.isDegenerate()) {
22860 graph = iD.actions.DeleteWay(parent.id)(graph);
22864 graph.parentRelations(node)
22865 .forEach(function(parent) {
22866 parent = parent.removeMembersWithID(nodeId);
22867 graph = graph.replace(parent);
22869 if (parent.isDegenerate()) {
22870 graph = iD.actions.DeleteRelation(parent.id)(graph);
22874 return graph.remove(node);
22877 action.disabled = function() {
22883 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
22884 iD.actions.DeleteRelation = function(relationId) {
22885 function deleteEntity(entity, graph) {
22886 return !graph.parentWays(entity).length &&
22887 !graph.parentRelations(entity).length &&
22888 !entity.hasInterestingTags();
22891 var action = function(graph) {
22892 var relation = graph.entity(relationId);
22894 graph.parentRelations(relation)
22895 .forEach(function(parent) {
22896 parent = parent.removeMembersWithID(relationId);
22897 graph = graph.replace(parent);
22899 if (parent.isDegenerate()) {
22900 graph = iD.actions.DeleteRelation(parent.id)(graph);
22904 _.uniq(_.map(relation.members, 'id')).forEach(function(memberId) {
22905 graph = graph.replace(relation.removeMembersWithID(memberId));
22907 var entity = graph.entity(memberId);
22908 if (deleteEntity(entity, graph)) {
22909 graph = iD.actions.DeleteMultiple([memberId])(graph);
22913 return graph.remove(relation);
22916 action.disabled = function(graph) {
22917 if (!graph.entity(relationId).isComplete(graph))
22918 return 'incomplete_relation';
22923 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
22924 iD.actions.DeleteWay = function(wayId) {
22925 function deleteNode(node, graph) {
22926 return !graph.parentWays(node).length &&
22927 !graph.parentRelations(node).length &&
22928 !node.hasInterestingTags();
22931 var action = function(graph) {
22932 var way = graph.entity(wayId);
22934 graph.parentRelations(way)
22935 .forEach(function(parent) {
22936 parent = parent.removeMembersWithID(wayId);
22937 graph = graph.replace(parent);
22939 if (parent.isDegenerate()) {
22940 graph = iD.actions.DeleteRelation(parent.id)(graph);
22944 _.uniq(way.nodes).forEach(function(nodeId) {
22945 graph = graph.replace(way.removeNode(nodeId));
22947 var node = graph.entity(nodeId);
22948 if (deleteNode(node, graph)) {
22949 graph = graph.remove(node);
22953 return graph.remove(way);
22956 action.disabled = function(graph) {
22957 var disabled = false;
22959 graph.parentRelations(graph.entity(wayId)).forEach(function(parent) {
22960 var type = parent.tags.type,
22961 role = parent.memberById(wayId).role || 'outer';
22962 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
22963 disabled = 'part_of_relation';
22972 iD.actions.DeprecateTags = function(entityId) {
22973 return function(graph) {
22974 var entity = graph.entity(entityId),
22975 newtags = _.clone(entity.tags),
22979 // This handles deprecated tags with a single condition
22980 for (var i = 0; i < iD.data.deprecated.length; i++) {
22982 rule = iD.data.deprecated[i];
22983 var match = _.toPairs(rule.old)[0],
22984 replacements = rule.replace ? _.toPairs(rule.replace) : null;
22986 if (entity.tags[match[0]] && match[1] === '*') {
22988 var value = entity.tags[match[0]];
22989 if (replacements && !newtags[replacements[0][0]]) {
22990 newtags[replacements[0][0]] = value;
22992 delete newtags[match[0]];
22995 } else if (entity.tags[match[0]] === match[1]) {
22996 newtags = _.assign({}, rule.replace || {}, _.omit(newtags, match[0]));
23002 return graph.replace(entity.update({tags: newtags}));
23008 iD.actions.DiscardTags = function(difference) {
23009 return function(graph) {
23010 function discardTags(entity) {
23011 if (!_.isEmpty(entity.tags)) {
23013 _.each(entity.tags, function(v, k) {
23014 if (v) tags[k] = v;
23017 graph = graph.replace(entity.update({
23018 tags: _.omit(tags, iD.data.discarded)
23023 difference.modified().forEach(discardTags);
23024 difference.created().forEach(discardTags);
23029 // Disconect the ways at the given node.
23031 // Optionally, disconnect only the given ways.
23033 // For testing convenience, accepts an ID to assign to the (first) new node.
23034 // Normally, this will be undefined and the way will automatically
23035 // be assigned a new ID.
23037 // This is the inverse of `iD.actions.Connect`.
23040 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
23041 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
23043 iD.actions.Disconnect = function(nodeId, newNodeId) {
23046 var action = function(graph) {
23047 var node = graph.entity(nodeId),
23048 connections = action.connections(graph);
23050 connections.forEach(function(connection) {
23051 var way = graph.entity(connection.wayID),
23052 newNode = iD.Node({id: newNodeId, loc: node.loc, tags: node.tags});
23054 graph = graph.replace(newNode);
23055 if (connection.index === 0 && way.isArea()) {
23056 // replace shared node with shared node..
23057 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
23059 // replace shared node with multiple new nodes..
23060 graph = graph.replace(way.updateNode(newNode.id, connection.index));
23067 action.connections = function(graph) {
23068 var candidates = [],
23070 parentWays = graph.parentWays(graph.entity(nodeId));
23072 parentWays.forEach(function(way) {
23073 if (wayIds && wayIds.indexOf(way.id) === -1) {
23077 if (way.isArea() && (way.nodes[0] === nodeId)) {
23078 candidates.push({wayID: way.id, index: 0});
23080 way.nodes.forEach(function(waynode, index) {
23081 if (waynode === nodeId) {
23082 candidates.push({wayID: way.id, index: index});
23088 return keeping ? candidates : candidates.slice(1);
23091 action.disabled = function(graph) {
23092 var connections = action.connections(graph);
23093 if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
23094 return 'not_connected';
23096 var parentWays = graph.parentWays(graph.entity(nodeId)),
23097 seenRelationIds = {},
23100 parentWays.forEach(function(way) {
23101 if (wayIds && wayIds.indexOf(way.id) === -1)
23104 var relations = graph.parentRelations(way);
23105 relations.forEach(function(relation) {
23106 if (relation.id in seenRelationIds) {
23107 sharedRelation = relation;
23109 seenRelationIds[relation.id] = true;
23114 if (sharedRelation)
23118 action.limitWays = function(_) {
23119 if (!arguments.length) return wayIds;
23126 // Join ways at the end node they share.
23128 // This is the inverse of `iD.actions.Split`.
23131 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
23132 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
23134 iD.actions.Join = function(ids) {
23136 function groupEntitiesByGeometry(graph) {
23137 var entities = ids.map(function(id) { return graph.entity(id); });
23138 return _.extend({line: []}, _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
23141 var action = function(graph) {
23142 var ways = ids.map(graph.entity, graph),
23143 survivor = ways[0];
23145 // Prefer to keep an existing way.
23146 for (var i = 0; i < ways.length; i++) {
23147 if (!ways[i].isNew()) {
23148 survivor = ways[i];
23153 var joined = iD.geo.joinWays(ways, graph)[0];
23155 survivor = survivor.update({nodes: _.map(joined.nodes, 'id')});
23156 graph = graph.replace(survivor);
23158 joined.forEach(function(way) {
23159 if (way.id === survivor.id)
23162 graph.parentRelations(way).forEach(function(parent) {
23163 graph = graph.replace(parent.replaceMember(way, survivor));
23166 survivor = survivor.mergeTags(way.tags);
23168 graph = graph.replace(survivor);
23169 graph = iD.actions.DeleteWay(way.id)(graph);
23175 action.disabled = function(graph) {
23176 var geometries = groupEntitiesByGeometry(graph);
23177 if (ids.length < 2 || ids.length !== geometries.line.length)
23178 return 'not_eligible';
23180 var joined = iD.geo.joinWays(ids.map(graph.entity, graph), graph);
23181 if (joined.length > 1)
23182 return 'not_adjacent';
23184 var nodeIds = _.map(joined[0].nodes, 'id').slice(1, -1),
23187 conflicting = false;
23189 joined[0].forEach(function(way) {
23190 var parents = graph.parentRelations(way);
23191 parents.forEach(function(parent) {
23192 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
23196 for (var k in way.tags) {
23197 if (!(k in tags)) {
23198 tags[k] = way.tags[k];
23199 } else if (tags[k] && iD.interestingTag(k) && tags[k] !== way.tags[k]) {
23200 conflicting = true;
23206 return 'restriction';
23209 return 'conflicting_tags';
23214 iD.actions.Merge = function(ids) {
23215 function groupEntitiesByGeometry(graph) {
23216 var entities = ids.map(function(id) { return graph.entity(id); });
23217 return _.extend({point: [], area: [], line: [], relation: []},
23218 _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
23221 var action = function(graph) {
23222 var geometries = groupEntitiesByGeometry(graph),
23223 target = geometries.area[0] || geometries.line[0],
23224 points = geometries.point;
23226 points.forEach(function(point) {
23227 target = target.mergeTags(point.tags);
23229 graph.parentRelations(point).forEach(function(parent) {
23230 graph = graph.replace(parent.replaceMember(point, target));
23233 graph = graph.remove(point);
23236 graph = graph.replace(target);
23241 action.disabled = function(graph) {
23242 var geometries = groupEntitiesByGeometry(graph);
23243 if (geometries.point.length === 0 ||
23244 (geometries.area.length + geometries.line.length) !== 1 ||
23245 geometries.relation.length !== 0)
23246 return 'not_eligible';
23251 iD.actions.MergePolygon = function(ids, newRelationId) {
23253 function groupEntities(graph) {
23254 var entities = ids.map(function (id) { return graph.entity(id); });
23259 }, _.groupBy(entities, function(entity) {
23260 if (entity.type === 'way' && entity.isClosed()) {
23261 return 'closedWay';
23262 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
23263 return 'multipolygon';
23270 var action = function(graph) {
23271 var entities = groupEntities(graph);
23273 // An array representing all the polygons that are part of the multipolygon.
23275 // Each element is itself an array of objects with an id property, and has a
23276 // locs property which is an array of the locations forming the polygon.
23277 var polygons = entities.multipolygon.reduce(function(polygons, m) {
23278 return polygons.concat(iD.geo.joinWays(m.members, graph));
23279 }, []).concat(entities.closedWay.map(function(d) {
23280 var member = [{id: d.id}];
23281 member.nodes = graph.childNodes(d);
23285 // contained is an array of arrays of boolean values,
23286 // where contained[j][k] is true iff the jth way is
23287 // contained by the kth way.
23288 var contained = polygons.map(function(w, i) {
23289 return polygons.map(function(d, n) {
23290 if (i === n) return null;
23291 return iD.geo.polygonContainsPolygon(
23292 _.map(d.nodes, 'loc'),
23293 _.map(w.nodes, 'loc'));
23297 // Sort all polygons as either outer or inner ways
23301 while (polygons.length) {
23302 extractUncontained(polygons);
23303 polygons = polygons.filter(isContained);
23304 contained = contained.filter(isContained).map(filterContained);
23307 function isContained(d, i) {
23308 return _.some(contained[i]);
23311 function filterContained(d) {
23312 return d.filter(isContained);
23315 function extractUncontained(polygons) {
23316 polygons.forEach(function(d, i) {
23317 if (!isContained(d, i)) {
23318 d.forEach(function(member) {
23322 role: outer ? 'outer' : 'inner'
23330 // Move all tags to one relation
23331 var relation = entities.multipolygon[0] ||
23332 iD.Relation({ id: newRelationId, tags: { type: 'multipolygon' }});
23334 entities.multipolygon.slice(1).forEach(function(m) {
23335 relation = relation.mergeTags(m.tags);
23336 graph = graph.remove(m);
23339 entities.closedWay.forEach(function(way) {
23340 function isThisOuter(m) {
23341 return m.id === way.id && m.role !== 'inner';
23343 if (members.some(isThisOuter)) {
23344 relation = relation.mergeTags(way.tags);
23345 graph = graph.replace(way.update({ tags: {} }));
23349 return graph.replace(relation.update({
23351 tags: _.omit(relation.tags, 'area')
23355 action.disabled = function(graph) {
23356 var entities = groupEntities(graph);
23357 if (entities.other.length > 0 ||
23358 entities.closedWay.length + entities.multipolygon.length < 2)
23359 return 'not_eligible';
23360 if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
23361 return 'incomplete_relation';
23366 iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser) {
23367 var option = 'safe', // 'safe', 'force_local', 'force_remote'
23371 return _.isFunction(formatUser) ? formatUser(d) : d;
23375 function mergeLocation(remote, target) {
23376 function pointEqual(a, b) {
23377 var epsilon = 1e-6;
23378 return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
23381 if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
23384 if (option === 'force_remote') {
23385 return target.update({loc: remote.loc});
23388 conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
23393 function mergeNodes(base, remote, target) {
23394 if (option === 'force_local' || _.isEqual(target.nodes, remote.nodes)) {
23397 if (option === 'force_remote') {
23398 return target.update({nodes: remote.nodes});
23401 var ccount = conflicts.length,
23402 o = base.nodes || [],
23403 a = target.nodes || [],
23404 b = remote.nodes || [],
23406 hunks = Diff3.diff3_merge(a, o, b, true);
23408 for (var i = 0; i < hunks.length; i++) {
23409 var hunk = hunks[i];
23411 nodes.push.apply(nodes, hunk.ok);
23413 // for all conflicts, we can assume c.a !== c.b
23414 // because `diff3_merge` called with `true` option to exclude false conflicts..
23415 var c = hunk.conflict;
23416 if (_.isEqual(c.o, c.a)) { // only changed remotely
23417 nodes.push.apply(nodes, c.b);
23418 } else if (_.isEqual(c.o, c.b)) { // only changed locally
23419 nodes.push.apply(nodes, c.a);
23420 } else { // changed both locally and remotely
23421 conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
23427 return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
23431 function mergeChildren(targetWay, children, updates, graph) {
23432 function isUsed(node, targetWay) {
23433 var parentWays = _.map(graph.parentWays(node), 'id');
23434 return node.hasInterestingTags() ||
23435 _.without(parentWays, targetWay.id).length > 0 ||
23436 graph.parentRelations(node).length > 0;
23439 var ccount = conflicts.length;
23441 for (var i = 0; i < children.length; i++) {
23442 var id = children[i],
23443 node = graph.hasEntity(id);
23445 // remove unused childNodes..
23446 if (targetWay.nodes.indexOf(id) === -1) {
23447 if (node && !isUsed(node, targetWay)) {
23448 updates.removeIds.push(id);
23453 // restore used childNodes..
23454 var local = localGraph.hasEntity(id),
23455 remote = remoteGraph.hasEntity(id),
23458 if (option === 'force_remote' && remote && remote.visible) {
23459 updates.replacements.push(remote);
23461 } else if (option === 'force_local' && local) {
23462 target = iD.Entity(local);
23464 target = target.update({ version: remote.version });
23466 updates.replacements.push(target);
23468 } else if (option === 'safe' && local && remote && local.version !== remote.version) {
23469 target = iD.Entity(local, { version: remote.version });
23470 if (remote.visible) {
23471 target = mergeLocation(remote, target);
23473 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
23476 if (conflicts.length !== ccount) break;
23477 updates.replacements.push(target);
23485 function updateChildren(updates, graph) {
23486 for (var i = 0; i < updates.replacements.length; i++) {
23487 graph = graph.replace(updates.replacements[i]);
23489 if (updates.removeIds.length) {
23490 graph = iD.actions.DeleteMultiple(updates.removeIds)(graph);
23496 function mergeMembers(remote, target) {
23497 if (option === 'force_local' || _.isEqual(target.members, remote.members)) {
23500 if (option === 'force_remote') {
23501 return target.update({members: remote.members});
23504 conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
23509 function mergeTags(base, remote, target) {
23510 function ignoreKey(k) {
23511 return _.includes(iD.data.discarded, k);
23514 if (option === 'force_local' || _.isEqual(target.tags, remote.tags)) {
23517 if (option === 'force_remote') {
23518 return target.update({tags: remote.tags});
23521 var ccount = conflicts.length,
23522 o = base.tags || {},
23523 a = target.tags || {},
23524 b = remote.tags || {},
23525 keys = _.reject(_.union(_.keys(o), _.keys(a), _.keys(b)), ignoreKey),
23529 for (var i = 0; i < keys.length; i++) {
23532 if (o[k] !== b[k] && a[k] !== b[k]) { // changed remotely..
23533 if (o[k] !== a[k]) { // changed locally..
23534 conflicts.push(t('merge_remote_changes.conflict.tags',
23535 { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
23537 } else { // unchanged locally, accept remote change..
23538 if (b.hasOwnProperty(k)) {
23548 return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
23552 // `graph.base()` is the common ancestor of the two graphs.
23553 // `localGraph` contains user's edits up to saving
23554 // `remoteGraph` contains remote edits to modified nodes
23555 // `graph` must be a descendent of `localGraph` and may include
23556 // some conflict resolution actions performed on it.
23558 // --- ... --- `localGraph` -- ... -- `graph`
23560 // `graph.base()` --- ... --- `remoteGraph`
23562 var action = function(graph) {
23563 var updates = { replacements: [], removeIds: [] },
23564 base = graph.base().entities[id],
23565 local = localGraph.entity(id),
23566 remote = remoteGraph.entity(id),
23567 target = iD.Entity(local, { version: remote.version });
23570 if (!remote.visible) {
23571 if (option === 'force_remote') {
23572 return iD.actions.DeleteMultiple([id])(graph);
23574 } else if (option === 'force_local') {
23575 if (target.type === 'way') {
23576 target = mergeChildren(target, _.uniq(local.nodes), updates, graph);
23577 graph = updateChildren(updates, graph);
23579 return graph.replace(target);
23582 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
23583 return graph; // do nothing
23588 if (target.type === 'node') {
23589 target = mergeLocation(remote, target);
23591 } else if (target.type === 'way') {
23592 // pull in any child nodes that may not be present locally..
23593 graph.rebase(remoteGraph.childNodes(remote), [graph], false);
23594 target = mergeNodes(base, remote, target);
23595 target = mergeChildren(target, _.union(local.nodes, remote.nodes), updates, graph);
23597 } else if (target.type === 'relation') {
23598 target = mergeMembers(remote, target);
23601 target = mergeTags(base, remote, target);
23603 if (!conflicts.length) {
23604 graph = updateChildren(updates, graph).replace(target);
23610 action.withOption = function(opt) {
23615 action.conflicts = function() {
23621 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
23622 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
23623 iD.actions.Move = function(moveIds, tryDelta, projection, cache) {
23624 var delta = tryDelta;
23626 function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
23627 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
23629 function setupCache(graph) {
23630 function canMove(nodeId) {
23631 var parents = _.map(graph.parentWays(graph.entity(nodeId)), 'id');
23632 if (parents.length < 3) return true;
23634 // Don't move a vertex where >2 ways meet, unless all parentWays are moving too..
23635 var parentsMoving = _.every(parents, function(id) { return cache.moving[id]; });
23636 if (!parentsMoving) delete cache.moving[nodeId];
23638 return parentsMoving;
23641 function cacheEntities(ids) {
23642 _.each(ids, function(id) {
23643 if (cache.moving[id]) return;
23644 cache.moving[id] = true;
23646 var entity = graph.hasEntity(id);
23647 if (!entity) return;
23649 if (entity.type === 'node') {
23650 cache.nodes.push(id);
23651 cache.startLoc[id] = entity.loc;
23652 } else if (entity.type === 'way') {
23653 cache.ways.push(id);
23654 cacheEntities(entity.nodes);
23656 cacheEntities(_.map(entity.members, 'id'));
23661 function cacheIntersections(ids) {
23662 function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
23664 _.each(ids, function(id) {
23665 // consider only intersections with 1 moved and 1 unmoved way.
23666 _.each(graph.childNodes(graph.entity(id)), function(node) {
23667 var parents = graph.parentWays(node);
23668 if (parents.length !== 2) return;
23670 var moved = graph.entity(id),
23671 unmoved = _.find(parents, function(way) { return !cache.moving[way.id]; });
23672 if (!unmoved) return;
23674 // exclude ways that are overly connected..
23675 if (_.intersection(moved.nodes, unmoved.nodes).length > 2) return;
23677 if (moved.isArea() || unmoved.isArea()) return;
23679 cache.intersection[node.id] = {
23682 unmovedId: unmoved.id,
23683 movedIsEP: isEndpoint(moved, node.id),
23684 unmovedIsEP: isEndpoint(unmoved, node.id)
23696 cache.intersection = {};
23697 cache.replacedVertex = {};
23698 cache.startLoc = {};
23702 cacheEntities(moveIds);
23703 cacheIntersections(cache.ways);
23704 cache.nodes = _.filter(cache.nodes, canMove);
23711 // Place a vertex where the moved vertex used to be, to preserve way shape..
23712 function replaceMovedVertex(nodeId, wayId, graph, delta) {
23713 var way = graph.entity(wayId),
23714 moved = graph.entity(nodeId),
23715 movedIndex = way.nodes.indexOf(nodeId),
23716 len, prevIndex, nextIndex;
23718 if (way.isClosed()) {
23719 len = way.nodes.length - 1;
23720 prevIndex = (movedIndex + len - 1) % len;
23721 nextIndex = (movedIndex + len + 1) % len;
23723 len = way.nodes.length;
23724 prevIndex = movedIndex - 1;
23725 nextIndex = movedIndex + 1;
23728 var prev = graph.hasEntity(way.nodes[prevIndex]),
23729 next = graph.hasEntity(way.nodes[nextIndex]);
23731 // Don't add orig vertex at endpoint..
23732 if (!prev || !next) return graph;
23734 var key = wayId + '_' + nodeId,
23735 orig = cache.replacedVertex[key];
23738 cache.replacedVertex[key] = orig;
23739 cache.startLoc[orig.id] = cache.startLoc[nodeId];
23744 start = projection(cache.startLoc[nodeId]);
23745 end = projection.invert(vecAdd(start, delta));
23747 end = cache.startLoc[nodeId];
23749 orig = orig.move(end);
23751 var angle = Math.abs(iD.geo.angle(orig, prev, projection) -
23752 iD.geo.angle(orig, next, projection)) * 180 / Math.PI;
23754 // Don't add orig vertex if it would just make a straight line..
23755 if (angle > 175 && angle < 185) return graph;
23757 // Don't add orig vertex if another point is already nearby (within 10m)
23758 if (iD.geo.sphericalDistance(prev.loc, orig.loc) < 10 ||
23759 iD.geo.sphericalDistance(orig.loc, next.loc) < 10) return graph;
23761 // moving forward or backward along way?
23762 var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
23763 p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
23764 d1 = iD.geo.pathLength(p1),
23765 d2 = iD.geo.pathLength(p2),
23766 insertAt = (d1 < d2) ? movedIndex : nextIndex;
23768 // moving around closed loop?
23769 if (way.isClosed() && insertAt === 0) insertAt = len;
23771 way = way.addNode(orig.id, insertAt);
23772 return graph.replace(orig).replace(way);
23775 // Reorder nodes around intersections that have moved..
23776 function unZorroIntersection(intersection, graph) {
23777 var vertex = graph.entity(intersection.nodeId),
23778 way1 = graph.entity(intersection.movedId),
23779 way2 = graph.entity(intersection.unmovedId),
23780 isEP1 = intersection.movedIsEP,
23781 isEP2 = intersection.unmovedIsEP;
23783 // don't move the vertex if it is the endpoint of both ways.
23784 if (isEP1 && isEP2) return graph;
23786 var nodes1 = _.without(graph.childNodes(way1), vertex),
23787 nodes2 = _.without(graph.childNodes(way2), vertex);
23789 if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
23790 if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
23792 var edge1 = !isEP1 && iD.geo.chooseEdge(nodes1, projection(vertex.loc), projection),
23793 edge2 = !isEP2 && iD.geo.chooseEdge(nodes2, projection(vertex.loc), projection),
23796 // snap vertex to nearest edge (or some point between them)..
23797 if (!isEP1 && !isEP2) {
23798 var epsilon = 1e-4, maxIter = 10;
23799 for (var i = 0; i < maxIter; i++) {
23800 loc = iD.geo.interp(edge1.loc, edge2.loc, 0.5);
23801 edge1 = iD.geo.chooseEdge(nodes1, projection(loc), projection);
23802 edge2 = iD.geo.chooseEdge(nodes2, projection(loc), projection);
23803 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
23805 } else if (!isEP1) {
23811 graph = graph.replace(vertex.move(loc));
23813 // if zorro happened, reorder nodes..
23814 if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
23815 way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
23816 graph = graph.replace(way1);
23818 if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
23819 way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
23820 graph = graph.replace(way2);
23827 function cleanupIntersections(graph) {
23828 _.each(cache.intersection, function(obj) {
23829 graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
23830 graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
23831 graph = unZorroIntersection(obj, graph);
23837 // check if moving way endpoint can cross an unmoved way, if so limit delta..
23838 function limitDelta(graph) {
23839 _.each(cache.intersection, function(obj) {
23840 if (!obj.movedIsEP) return;
23842 var node = graph.entity(obj.nodeId),
23843 start = projection(node.loc),
23844 end = vecAdd(start, delta),
23845 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
23846 movedPath = _.map(_.map(movedNodes, 'loc'),
23847 function(loc) { return vecAdd(projection(loc), delta); }),
23848 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
23849 unmovedPath = _.map(_.map(unmovedNodes, 'loc'), projection),
23850 hits = iD.geo.pathIntersections(movedPath, unmovedPath);
23852 for (var i = 0; i < hits.length; i++) {
23853 if (_.isEqual(hits[i], end)) continue;
23854 var edge = iD.geo.chooseEdge(unmovedNodes, end, projection);
23855 delta = vecSub(projection(edge.loc), start);
23861 var action = function(graph) {
23862 if (delta[0] === 0 && delta[1] === 0) return graph;
23866 if (!_.isEmpty(cache.intersection)) {
23870 _.each(cache.nodes, function(id) {
23871 var node = graph.entity(id),
23872 start = projection(node.loc),
23873 end = vecAdd(start, delta);
23874 graph = graph.replace(node.move(projection.invert(end)));
23877 if (!_.isEmpty(cache.intersection)) {
23878 graph = cleanupIntersections(graph);
23884 action.disabled = function(graph) {
23885 function incompleteRelation(id) {
23886 var entity = graph.entity(id);
23887 return entity.type === 'relation' && !entity.isComplete(graph);
23890 if (_.some(moveIds, incompleteRelation))
23891 return 'incomplete_relation';
23894 action.delta = function() {
23900 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
23901 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
23902 iD.actions.MoveNode = function(nodeId, loc) {
23903 return function(graph) {
23904 return graph.replace(graph.entity(nodeId).move(loc));
23907 iD.actions.Noop = function() {
23908 return function(graph) {
23913 * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
23916 iD.actions.Orthogonalize = function(wayId, projection) {
23917 var threshold = 12, // degrees within right or straight to alter
23918 lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
23919 upperThreshold = Math.cos(threshold * Math.PI / 180);
23921 var action = function(graph) {
23922 var way = graph.entity(wayId),
23923 nodes = graph.childNodes(way),
23924 points = _.uniq(nodes).map(function(n) { return projection(n.loc); }),
23925 corner = {i: 0, dotp: 1},
23927 i, j, score, motions;
23929 if (nodes.length === 4) {
23930 for (i = 0; i < 1000; i++) {
23931 motions = points.map(calcMotion);
23932 points[corner.i] = addPoints(points[corner.i],motions[corner.i]);
23933 score = corner.dotp;
23934 if (score < epsilon) {
23939 graph = graph.replace(graph.entity(nodes[corner.i].id)
23940 .move(projection.invert(points[corner.i])));
23943 originalPoints = _.clone(points);
23946 for (i = 0; i < 1000; i++) {
23947 motions = points.map(calcMotion);
23948 for (j = 0; j < motions.length; j++) {
23949 points[j] = addPoints(points[j],motions[j]);
23951 var newScore = squareness(points);
23952 if (newScore < score) {
23953 best = _.clone(points);
23956 if (score < epsilon) {
23963 for (i = 0; i < points.length; i++) {
23964 // only move the points that actually moved
23965 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
23966 graph = graph.replace(graph.entity(nodes[i].id)
23967 .move(projection.invert(points[i])));
23971 // remove empty nodes on straight sections
23972 for (i = 0; i < points.length; i++) {
23973 var node = nodes[i];
23975 if (graph.parentWays(node).length > 1 ||
23976 graph.parentRelations(node).length ||
23977 node.hasInterestingTags()) {
23982 var dotp = normalizedDotProduct(i, points);
23983 if (dotp < -1 + epsilon) {
23984 graph = iD.actions.DeleteNode(nodes[i].id)(graph);
23991 function calcMotion(b, i, array) {
23992 var a = array[(i - 1 + array.length) % array.length],
23993 c = array[(i + 1) % array.length],
23994 p = subtractPoints(a, b),
23995 q = subtractPoints(c, b),
23998 scale = 2 * Math.min(iD.geo.euclideanDistance(p, [0, 0]), iD.geo.euclideanDistance(q, [0, 0]));
23999 p = normalizePoint(p, 1.0);
24000 q = normalizePoint(q, 1.0);
24002 dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
24004 // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
24005 if (array.length > 3) {
24006 if (dotp < -0.707106781186547) {
24009 } else if (dotp && Math.abs(dotp) < corner.dotp) {
24011 corner.dotp = Math.abs(dotp);
24014 return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
24018 function squareness(points) {
24019 return points.reduce(function(sum, val, i, array) {
24020 var dotp = normalizedDotProduct(i, array);
24022 dotp = filterDotProduct(dotp);
24023 return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
24027 function normalizedDotProduct(i, points) {
24028 var a = points[(i - 1 + points.length) % points.length],
24030 c = points[(i + 1) % points.length],
24031 p = subtractPoints(a, b),
24032 q = subtractPoints(c, b);
24034 p = normalizePoint(p, 1.0);
24035 q = normalizePoint(q, 1.0);
24037 return p[0] * q[0] + p[1] * q[1];
24040 function subtractPoints(a, b) {
24041 return [a[0] - b[0], a[1] - b[1]];
24044 function addPoints(a, b) {
24045 return [a[0] + b[0], a[1] + b[1]];
24048 function normalizePoint(point, scale) {
24049 var vector = [0, 0];
24050 var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
24051 if (length !== 0) {
24052 vector[0] = point[0] / length;
24053 vector[1] = point[1] / length;
24056 vector[0] *= scale;
24057 vector[1] *= scale;
24062 function filterDotProduct(dotp) {
24063 if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
24070 action.disabled = function(graph) {
24071 var way = graph.entity(wayId),
24072 nodes = graph.childNodes(way),
24073 points = _.uniq(nodes).map(function(n) { return projection(n.loc); });
24075 if (squareness(points)) {
24079 return 'not_squarish';
24084 // Create a restriction relation for `turn`, which must have the following structure:
24087 // from: { node: <node ID>, way: <way ID> },
24088 // via: { node: <node ID> },
24089 // to: { node: <node ID>, way: <way ID> },
24090 // restriction: <'no_right_turn', 'no_left_turn', etc.>
24093 // This specifies a restriction of type `restriction` when traveling from
24094 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
24095 // (The action does not check that these entities form a valid intersection.)
24097 // If `restriction` is not provided, it is automatically determined by
24098 // iD.geo.inferRestriction.
24100 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
24101 // and `to.node` are used to determine which portion of the split ways become
24102 // members of the restriction.
24104 // For testing convenience, accepts an ID to assign to the new relation.
24105 // Normally, this will be undefined and the relation will automatically
24106 // be assigned a new ID.
24108 iD.actions.RestrictTurn = function(turn, projection, restrictionId) {
24109 return function(graph) {
24110 var from = graph.entity(turn.from.way),
24111 via = graph.entity(turn.via.node),
24112 to = graph.entity(turn.to.way);
24114 function isClosingNode(way, nodeId) {
24115 return nodeId === way.first() && nodeId === way.last();
24118 function split(toOrFrom) {
24119 var newID = toOrFrom.newID || iD.Way().id;
24120 graph = iD.actions.Split(via.id, [newID])
24121 .limitWays([toOrFrom.way])(graph);
24123 var a = graph.entity(newID),
24124 b = graph.entity(toOrFrom.way);
24126 if (a.nodes.indexOf(toOrFrom.node) !== -1) {
24133 if (!from.affix(via.id) || isClosingNode(from, via.id)) {
24134 if (turn.from.node === turn.to.node) {
24136 from = to = split(turn.from)[0];
24137 } else if (turn.from.way === turn.to.way) {
24138 // Straight-on or circular
24139 var s = split(turn.from);
24144 from = split(turn.from)[0];
24148 if (!to.affix(via.id) || isClosingNode(to, via.id)) {
24149 to = split(turn.to)[0];
24152 return graph.replace(iD.Relation({
24155 type: 'restriction',
24156 restriction: turn.restriction ||
24157 iD.geo.inferRestriction(
24165 {id: from.id, type: 'way', role: 'from'},
24166 {id: via.id, type: 'node', role: 'via'},
24167 {id: to.id, type: 'way', role: 'to'}
24173 Order the nodes of a way in reverse order and reverse any direction dependent tags
24174 other than `oneway`. (We assume that correcting a backwards oneway is the primary
24175 reason for reversing a way.)
24177 The following transforms are performed:
24180 *:right=* ⟺ *:left=*
24181 *:forward=* ⟺ *:backward=*
24182 direction=up ⟺ direction=down
24183 incline=up ⟺ incline=down
24187 role=forward ⟺ role=backward
24188 role=north ⟺ role=south
24189 role=east ⟺ role=west
24191 In addition, numeric-valued `incline` tags are negated.
24193 The JOSM implementation was used as a guide, but transformations that were of unclear benefit
24194 or adjusted tags that don't seem to be used in practice were omitted.
24197 http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
24198 http://wiki.openstreetmap.org/wiki/Key:direction#Steps
24199 http://wiki.openstreetmap.org/wiki/Key:incline
24200 http://wiki.openstreetmap.org/wiki/Route#Members
24201 http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
24203 iD.actions.Reverse = function(wayId, options) {
24204 var replacements = [
24205 [/:right$/, ':left'], [/:left$/, ':right'],
24206 [/:forward$/, ':backward'], [/:backward$/, ':forward']
24208 numeric = /^([+\-]?)(?=[\d.])/,
24210 forward: 'backward',
24211 backward: 'forward',
24218 function reverseKey(key) {
24219 for (var i = 0; i < replacements.length; ++i) {
24220 var replacement = replacements[i];
24221 if (replacement[0].test(key)) {
24222 return key.replace(replacement[0], replacement[1]);
24228 function reverseValue(key, value) {
24229 if (key === 'incline' && numeric.test(value)) {
24230 return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
24231 } else if (key === 'incline' || key === 'direction') {
24232 return {up: 'down', down: 'up'}[value] || value;
24233 } else if (options && options.reverseOneway && key === 'oneway') {
24234 return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
24236 return {left: 'right', right: 'left'}[value] || value;
24240 return function(graph) {
24241 var way = graph.entity(wayId),
24242 nodes = way.nodes.slice().reverse(),
24243 tags = {}, key, role;
24245 for (key in way.tags) {
24246 tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
24249 graph.parentRelations(way).forEach(function(relation) {
24250 relation.members.forEach(function(member, index) {
24251 if (member.id === way.id && (role = roleReversals[member.role])) {
24252 relation = relation.updateMember({role: role}, index);
24253 graph = graph.replace(relation);
24258 return graph.replace(way.update({nodes: nodes, tags: tags}));
24261 iD.actions.Revert = function(id) {
24263 var action = function(graph) {
24264 var entity = graph.hasEntity(id),
24265 base = graph.base().entities[id];
24267 if (entity && !base) { // entity will be removed..
24268 if (entity.type === 'node') {
24269 graph.parentWays(entity)
24270 .forEach(function(parent) {
24271 parent = parent.removeNode(id);
24272 graph = graph.replace(parent);
24274 if (parent.isDegenerate()) {
24275 graph = iD.actions.DeleteWay(parent.id)(graph);
24280 graph.parentRelations(entity)
24281 .forEach(function(parent) {
24282 parent = parent.removeMembersWithID(id);
24283 graph = graph.replace(parent);
24285 if (parent.isDegenerate()) {
24286 graph = iD.actions.DeleteRelation(parent.id)(graph);
24291 return graph.revert(id);
24296 iD.actions.RotateWay = function(wayId, pivot, angle, projection) {
24297 return function(graph) {
24298 return graph.update(function(graph) {
24299 var way = graph.entity(wayId);
24301 _.uniq(way.nodes).forEach(function(id) {
24303 var node = graph.entity(id),
24304 point = projection(node.loc),
24307 radial[0] = point[0] - pivot[0];
24308 radial[1] = point[1] - pivot[1];
24311 radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + pivot[0],
24312 radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + pivot[1]
24315 graph = graph.replace(node.move(projection.invert(point)));
24322 // Split a way at the given node.
24324 // Optionally, split only the given ways, if multiple ways share
24327 // This is the inverse of `iD.actions.Join`.
24329 // For testing convenience, accepts an ID to assign to the new way.
24330 // Normally, this will be undefined and the way will automatically
24331 // be assigned a new ID.
24334 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
24336 iD.actions.Split = function(nodeId, newWayIds) {
24339 // if the way is closed, we need to search for a partner node
24340 // to split the way at.
24342 // The following looks for a node that is both far away from
24343 // the initial node in terms of way segment length and nearby
24344 // in terms of beeline-distance. This assures that areas get
24345 // split on the most "natural" points (independent of the number
24347 // For example: bone-shaped areas get split across their waist
24348 // line, circles across the diameter.
24349 function splitArea(nodes, idxA, graph) {
24350 var lengths = new Array(nodes.length),
24356 function wrap(index) {
24357 return iD.util.wrap(index, nodes.length);
24360 function dist(nA, nB) {
24361 return iD.geo.sphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
24364 // calculate lengths
24366 for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
24367 length += dist(nodes[i], nodes[wrap(i-1)]);
24368 lengths[i] = length;
24372 for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
24373 length += dist(nodes[i], nodes[wrap(i+1)]);
24374 if (length < lengths[i])
24375 lengths[i] = length;
24378 // determine best opposite node to split
24379 for (i = 0; i < nodes.length; i++) {
24380 var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
24390 function split(graph, wayA, newWayId) {
24391 var wayB = iD.Way({id: newWayId, tags: wayA.tags}),
24394 isArea = wayA.isArea(),
24395 isOuter = iD.geo.isSimpleMultipolygonOuterMember(wayA, graph);
24397 if (wayA.isClosed()) {
24398 var nodes = wayA.nodes.slice(0, -1),
24399 idxA = _.indexOf(nodes, nodeId),
24400 idxB = splitArea(nodes, idxA, graph);
24403 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
24404 nodesB = nodes.slice(idxB, idxA + 1);
24406 nodesA = nodes.slice(idxA, idxB + 1);
24407 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
24410 var idx = _.indexOf(wayA.nodes, nodeId, 1);
24411 nodesA = wayA.nodes.slice(0, idx + 1);
24412 nodesB = wayA.nodes.slice(idx);
24415 wayA = wayA.update({nodes: nodesA});
24416 wayB = wayB.update({nodes: nodesB});
24418 graph = graph.replace(wayA);
24419 graph = graph.replace(wayB);
24421 graph.parentRelations(wayA).forEach(function(relation) {
24422 if (relation.isRestriction()) {
24423 var via = relation.memberByRole('via');
24424 if (via && wayB.contains(via.id)) {
24425 relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
24426 graph = graph.replace(relation);
24429 if (relation === isOuter) {
24430 graph = graph.replace(relation.mergeTags(wayA.tags));
24431 graph = graph.replace(wayA.update({tags: {}}));
24432 graph = graph.replace(wayB.update({tags: {}}));
24438 role: relation.memberById(wayA.id).role
24441 graph = iD.actions.AddMember(relation.id, member)(graph);
24445 if (!isOuter && isArea) {
24446 var multipolygon = iD.Relation({
24447 tags: _.extend({}, wayA.tags, {type: 'multipolygon'}),
24449 {id: wayA.id, role: 'outer', type: 'way'},
24450 {id: wayB.id, role: 'outer', type: 'way'}
24453 graph = graph.replace(multipolygon);
24454 graph = graph.replace(wayA.update({tags: {}}));
24455 graph = graph.replace(wayB.update({tags: {}}));
24461 var action = function(graph) {
24462 var candidates = action.ways(graph);
24463 for (var i = 0; i < candidates.length; i++) {
24464 graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
24469 action.ways = function(graph) {
24470 var node = graph.entity(nodeId),
24471 parents = graph.parentWays(node),
24472 hasLines = _.some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
24474 return parents.filter(function(parent) {
24475 if (wayIds && wayIds.indexOf(parent.id) === -1)
24478 if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
24481 if (parent.isClosed()) {
24485 for (var i = 1; i < parent.nodes.length - 1; i++) {
24486 if (parent.nodes[i] === nodeId) {
24495 action.disabled = function(graph) {
24496 var candidates = action.ways(graph);
24497 if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
24498 return 'not_eligible';
24501 action.limitWays = function(_) {
24502 if (!arguments.length) return wayIds;
24510 * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
24513 iD.actions.Straighten = function(wayId, projection) {
24514 function positionAlongWay(n, s, e) {
24515 return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1]))/
24516 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
24519 var action = function(graph) {
24520 var way = graph.entity(wayId),
24521 nodes = graph.childNodes(way),
24522 points = nodes.map(function(n) { return projection(n.loc); }),
24523 startPoint = points[0],
24524 endPoint = points[points.length-1],
24528 for (i = 1; i < points.length-1; i++) {
24529 var node = nodes[i],
24532 if (graph.parentWays(node).length > 1 ||
24533 graph.parentRelations(node).length ||
24534 node.hasInterestingTags()) {
24536 var u = positionAlongWay(point, startPoint, endPoint),
24537 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
24538 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]);
24540 graph = graph.replace(graph.entity(node.id)
24541 .move(projection.invert([p0, p1])));
24544 if (toDelete.indexOf(node) === -1) {
24545 toDelete.push(node);
24550 for (i = 0; i < toDelete.length; i++) {
24551 graph = iD.actions.DeleteNode(toDelete[i].id)(graph);
24557 action.disabled = function(graph) {
24558 // check way isn't too bendy
24559 var way = graph.entity(wayId),
24560 nodes = graph.childNodes(way),
24561 points = nodes.map(function(n) { return projection(n.loc); }),
24562 startPoint = points[0],
24563 endPoint = points[points.length-1],
24564 threshold = 0.2 * Math.sqrt(Math.pow(startPoint[0] - endPoint[0], 2) + Math.pow(startPoint[1] - endPoint[1], 2)),
24567 if (threshold === 0) {
24568 return 'too_bendy';
24571 for (i = 1; i < points.length-1; i++) {
24572 var point = points[i],
24573 u = positionAlongWay(point, startPoint, endPoint),
24574 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
24575 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
24576 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
24578 // to bendy if point is off by 20% of total start/end distance in projected space
24579 if (isNaN(dist) || dist > threshold) {
24580 return 'too_bendy';
24587 // Remove the effects of `turn.restriction` on `turn`, which must have the
24588 // following structure:
24591 // from: { node: <node ID>, way: <way ID> },
24592 // via: { node: <node ID> },
24593 // to: { node: <node ID>, way: <way ID> },
24594 // restriction: <relation ID>
24597 // In the simple case, `restriction` is a reference to a `no_*` restriction
24598 // on the turn itself. In this case, it is simply deleted.
24600 // The more complex case is where `restriction` references an `only_*`
24601 // restriction on a different turn in the same intersection. In that case,
24602 // that restriction is also deleted, but at the same time restrictions on
24603 // the turns other than the first two are created.
24605 iD.actions.UnrestrictTurn = function(turn) {
24606 return function(graph) {
24607 return iD.actions.DeleteRelation(turn.restriction)(graph);
24611 iD.behavior.AddWay = function(context) {
24612 var event = d3.dispatch('start', 'startFromWay', 'startFromNode'),
24613 draw = iD.behavior.Draw(context);
24615 var addWay = function(surface) {
24616 draw.on('click', event.start)
24617 .on('clickWay', event.startFromWay)
24618 .on('clickNode', event.startFromNode)
24619 .on('cancel', addWay.cancel)
24620 .on('finish', addWay.cancel);
24623 .dblclickEnable(false);
24625 surface.call(draw);
24628 addWay.off = function(surface) {
24629 surface.call(draw.off);
24632 addWay.cancel = function() {
24633 window.setTimeout(function() {
24634 context.map().dblclickEnable(true);
24637 context.enter(iD.modes.Browse(context));
24640 addWay.tail = function(text) {
24645 return d3.rebind(addWay, event, 'on');
24647 iD.behavior.Breathe = function() {
24648 var duration = 800,
24649 selector = '.selected.shadow, .selected .shadow',
24650 selected = d3.select(null),
24655 function reset(selection) {
24657 .style('stroke-opacity', null)
24658 .style('stroke-width', null)
24659 .style('fill-opacity', null)
24663 function setAnimationParams(transition, fromTo) {
24665 .style('stroke-opacity', function(d) { return params[d.id][fromTo].opacity; })
24666 .style('stroke-width', function(d) { return params[d.id][fromTo].width; })
24667 .style('fill-opacity', function(d) { return params[d.id][fromTo].opacity; })
24668 .style('r', function(d) { return params[d.id][fromTo].width; });
24671 function calcAnimationParams(selection) {
24674 .each(function(d) {
24675 var s = d3.select(this),
24676 tag = s.node().tagName,
24677 p = {'from': {}, 'to': {}},
24680 // determine base opacity and width
24681 if (tag === 'circle') {
24682 opacity = parseFloat(s.style('fill-opacity') || 0.5);
24683 width = parseFloat(s.style('r') || 15.5);
24685 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
24686 width = parseFloat(s.style('stroke-width') || 10);
24689 // calculate from/to interpolation params..
24691 p.from.opacity = opacity * 0.6;
24692 p.to.opacity = opacity * 1.25;
24693 p.from.width = width * 0.9;
24694 p.to.width = width * (tag === 'circle' ? 1.5 : 1.25);
24699 function run(surface, fromTo) {
24700 var toFrom = (fromTo === 'from' ? 'to': 'from'),
24701 currSelected = surface.selectAll(selector),
24702 currClassed = surface.attr('class'),
24705 if (done || currSelected.empty()) {
24706 selected.call(reset);
24710 if (!_.isEqual(currSelected, selected) || currClassed !== classed) {
24711 selected.call(reset);
24712 classed = currClassed;
24713 selected = currSelected.call(calcAnimationParams);
24718 .call(setAnimationParams, fromTo)
24719 .duration(duration)
24720 .each(function() { ++n; })
24721 .each('end', function() {
24722 if (!--n) { // call once
24723 surface.call(run, toFrom);
24728 var breathe = function(surface) {
24730 d3.timer(function() {
24731 if (done) return true;
24733 var currSelected = surface.selectAll(selector);
24734 if (currSelected.empty()) return false;
24736 surface.call(run, 'from');
24741 breathe.off = function() {
24752 iD.behavior.Copy = function(context) {
24753 var keybinding = d3.keybinding('copy');
24755 function groupEntities(ids, graph) {
24756 var entities = ids.map(function (id) { return graph.entity(id); });
24757 return _.extend({relation: [], way: [], node: []},
24758 _.groupBy(entities, function(entity) { return entity.type; }));
24761 function getDescendants(id, graph, descendants) {
24762 var entity = graph.entity(id),
24765 descendants = descendants || {};
24767 if (entity.type === 'relation') {
24768 children = _.map(entity.members, 'id');
24769 } else if (entity.type === 'way') {
24770 children = entity.nodes;
24775 for (i = 0; i < children.length; i++) {
24776 if (!descendants[children[i]]) {
24777 descendants[children[i]] = true;
24778 descendants = getDescendants(children[i], graph, descendants);
24782 return descendants;
24785 function doCopy() {
24786 d3.event.preventDefault();
24787 if (context.inIntro()) return;
24789 var graph = context.graph(),
24790 selected = groupEntities(context.selectedIDs(), graph),
24795 for (i = 0; i < selected.relation.length; i++) {
24796 entity = selected.relation[i];
24797 if (!skip[entity.id] && entity.isComplete(graph)) {
24798 canCopy.push(entity.id);
24799 skip = getDescendants(entity.id, graph, skip);
24802 for (i = 0; i < selected.way.length; i++) {
24803 entity = selected.way[i];
24804 if (!skip[entity.id]) {
24805 canCopy.push(entity.id);
24806 skip = getDescendants(entity.id, graph, skip);
24809 for (i = 0; i < selected.node.length; i++) {
24810 entity = selected.node[i];
24811 if (!skip[entity.id]) {
24812 canCopy.push(entity.id);
24816 context.copyIDs(canCopy);
24820 keybinding.on(iD.ui.cmd('⌘C'), doCopy);
24821 d3.select(document).call(keybinding);
24825 copy.off = function() {
24826 d3.select(document).call(keybinding.off);
24832 `iD.behavior.drag` is like `d3.behavior.drag`, with the following differences:
24834 * The `origin` function is expected to return an [x, y] tuple rather than an
24836 * The events are `start`, `move`, and `end`.
24837 (https://github.com/mbostock/d3/issues/563)
24838 * The `start` event is not dispatched until the first cursor movement occurs.
24839 (https://github.com/mbostock/d3/pull/368)
24840 * The `move` event has a `point` and `delta` [x, y] tuple properties rather
24841 than `x`, `y`, `dx`, and `dy` properties.
24842 * The `end` event is not dispatched if no movement occurs.
24843 * An `off` function is available that unbinds the drag's internal event handlers.
24844 * Delegation is supported via the `delegate` function.
24847 iD.behavior.drag = function() {
24848 function d3_eventCancel() {
24849 d3.event.stopPropagation();
24850 d3.event.preventDefault();
24853 var event = d3.dispatch('start', 'move', 'end'),
24857 event_, target, surface;
24859 event.of = function(thiz, argumentz) {
24860 return function(e1) {
24861 var e0 = e1.sourceEvent = d3.event;
24865 event[e1.type].apply(thiz, argumentz);
24872 var d3_event_userSelectProperty = iD.util.prefixCSSProperty('UserSelect'),
24873 d3_event_userSelectSuppress = d3_event_userSelectProperty ?
24875 var selection = d3.selection(),
24876 select = selection.style(d3_event_userSelectProperty);
24877 selection.style(d3_event_userSelectProperty, 'none');
24878 return function () {
24879 selection.style(d3_event_userSelectProperty, select);
24883 var w = d3.select(window).on('selectstart.' + type, d3_eventCancel);
24884 return function () {
24885 w.on('selectstart.' + type, null);
24889 function mousedown() {
24891 event_ = event.of(target, arguments);
24892 var eventTarget = d3.event.target,
24893 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
24897 selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
24899 var w = d3.select(window)
24900 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
24901 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
24904 offset = origin.apply(target, arguments);
24905 offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
24910 if (touchId === null) d3.event.stopPropagation();
24913 var p = target.parentNode || surface;
24914 return touchId !== null ? d3.touches(p).filter(function(p) {
24915 return p.identifier === touchId;
24916 })[0] : d3.mouse(p);
24919 function dragmove() {
24922 dx = p[0] - origin_[0],
24923 dy = p[1] - origin_[1];
24925 if (dx === 0 && dy === 0)
24940 point: [p[0] + offset[0], p[1] + offset[1]],
24945 function dragend() {
24952 if (d3.event.target === eventTarget) w.on('click.drag', click, true);
24955 w.on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
24956 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
24962 w.on('click.drag', null);
24966 function drag(selection) {
24967 var matchesSelector = iD.util.prefixDOMProperty('matchesSelector'),
24968 delegate = mousedown;
24971 delegate = function() {
24973 target = d3.event.target;
24974 for (; target && target !== root; target = target.parentNode) {
24975 if (target[matchesSelector](selector) &&
24976 (!filter || filter(target.__data__))) {
24977 return mousedown.call(target, target.__data__);
24983 selection.on('mousedown.drag' + selector, delegate)
24984 .on('touchstart.drag' + selector, delegate);
24987 drag.off = function(selection) {
24988 selection.on('mousedown.drag' + selector, null)
24989 .on('touchstart.drag' + selector, null);
24992 drag.delegate = function(_) {
24993 if (!arguments.length) return selector;
24998 drag.filter = function(_) {
24999 if (!arguments.length) return origin;
25004 drag.origin = function (_) {
25005 if (!arguments.length) return origin;
25010 drag.cancel = function() {
25012 .on('mousemove.drag', null)
25013 .on('mouseup.drag', null);
25017 drag.target = function() {
25018 if (!arguments.length) return target;
25019 target = arguments[0];
25020 event_ = event.of(target, Array.prototype.slice.call(arguments, 1));
25024 drag.surface = function() {
25025 if (!arguments.length) return surface;
25026 surface = arguments[0];
25030 return d3.rebind(drag, event, 'on');
25032 iD.behavior.Draw = function(context) {
25033 var event = d3.dispatch('move', 'click', 'clickWay',
25034 'clickNode', 'undo', 'cancel', 'finish'),
25035 keybinding = d3.keybinding('draw'),
25036 hover = iD.behavior.Hover(context)
25038 .on('hover', context.ui().sidebar.hover),
25039 tail = iD.behavior.Tail(),
25040 edit = iD.behavior.Edit(context),
25041 closeTolerance = 4,
25043 mouseLeave = false,
25045 cached = iD.behavior.Draw;
25048 if (d3.event.altKey) return {};
25050 if (d3.event.type === 'keydown') {
25051 return (lastMouse && lastMouse.target.__data__) || {};
25053 return d3.event.target.__data__ || {};
25057 function mousedown() {
25060 var p = context.container().node();
25061 return touchId !== null ? d3.touches(p).filter(function(p) {
25062 return p.identifier === touchId;
25063 })[0] : d3.mouse(p);
25066 var element = d3.select(this),
25067 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
25071 element.on('mousemove.draw', null);
25073 d3.select(window).on('mouseup.draw', function() {
25074 var t2 = +new Date(),
25076 dist = iD.geo.euclideanDistance(p1, p2);
25078 element.on('mousemove.draw', mousemove);
25079 d3.select(window).on('mouseup.draw', null);
25081 if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
25082 // Prevent a quick second click
25083 d3.select(window).on('click.draw-block', function() {
25084 d3.event.stopPropagation();
25087 context.map().dblclickEnable(false);
25089 window.setTimeout(function() {
25090 context.map().dblclickEnable(true);
25091 d3.select(window).on('click.draw-block', null);
25099 function mousemove() {
25100 lastMouse = d3.event;
25101 event.move(datum());
25104 function mouseenter() {
25105 mouseLeave = false;
25108 function mouseleave() {
25114 if (d.type === 'way') {
25115 var dims = context.map().dimensions(),
25116 mouse = context.mouse(),
25118 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
25119 mouse[1] > pad && mouse[1] < dims[1] - pad;
25122 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection),
25123 edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
25124 event.clickWay(choice.loc, edge);
25126 event.click(context.map().mouseCoordinates());
25129 } else if (d.type === 'node') {
25130 event.clickNode(d);
25133 event.click(context.map().mouseCoordinates());
25138 var currSpace = context.mouse();
25139 if (cached.disableSpace && cached.lastSpace) {
25140 var dist = iD.geo.euclideanDistance(cached.lastSpace, currSpace);
25141 if (dist > tolerance) {
25142 cached.disableSpace = false;
25146 if (cached.disableSpace || mouseLeave || !lastMouse) return;
25148 // user must move mouse or release space bar to allow another click
25149 cached.lastSpace = currSpace;
25150 cached.disableSpace = true;
25152 d3.select(window).on('keyup.space-block', function() {
25153 cached.disableSpace = false;
25154 d3.select(window).on('keyup.space-block', null);
25157 d3.event.preventDefault();
25161 function backspace() {
25162 d3.event.preventDefault();
25167 d3.event.preventDefault();
25172 d3.event.preventDefault();
25176 function draw(selection) {
25177 context.install(hover);
25178 context.install(edit);
25180 if (!context.inIntro() && !cached.usedTails[tail.text()]) {
25181 context.install(tail);
25185 .on('⌫', backspace)
25189 .on('space', space)
25190 .on('⌥space', space);
25193 .on('mouseenter.draw', mouseenter)
25194 .on('mouseleave.draw', mouseleave)
25195 .on('mousedown.draw', mousedown)
25196 .on('mousemove.draw', mousemove);
25198 d3.select(document)
25204 draw.off = function(selection) {
25205 context.ui().sidebar.hover.cancel();
25206 context.uninstall(hover);
25207 context.uninstall(edit);
25209 if (!context.inIntro() && !cached.usedTails[tail.text()]) {
25210 context.uninstall(tail);
25211 cached.usedTails[tail.text()] = true;
25215 .on('mouseenter.draw', null)
25216 .on('mouseleave.draw', null)
25217 .on('mousedown.draw', null)
25218 .on('mousemove.draw', null);
25221 .on('mouseup.draw', null);
25222 // note: keyup.space-block, click.draw-block should remain
25224 d3.select(document)
25225 .call(keybinding.off);
25228 draw.tail = function(_) {
25233 return d3.rebind(draw, event, 'on');
25236 iD.behavior.Draw.usedTails = {};
25237 iD.behavior.Draw.disableSpace = false;
25238 iD.behavior.Draw.lastSpace = null;
25239 iD.behavior.DrawWay = function(context, wayId, index, mode, baseGraph) {
25240 var way = context.entity(wayId),
25241 isArea = context.geometry(wayId) === 'area',
25243 annotation = t((way.isDegenerate() ?
25244 'operations.start.annotation.' :
25245 'operations.continue.annotation.') + context.geometry(wayId)),
25246 draw = iD.behavior.Draw(context);
25248 var startIndex = typeof index === 'undefined' ? way.nodes.length - 1 : 0,
25249 start = iD.Node({loc: context.graph().entity(way.nodes[startIndex]).loc}),
25250 end = iD.Node({loc: context.map().mouseCoordinates()}),
25252 nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
25253 tags: _.clone(way.tags)
25256 var f = context[way.isDegenerate() ? 'replace' : 'perform'];
25258 f(iD.actions.AddEntity(end),
25259 iD.actions.AddVertex(wayId, end.id, index));
25261 f(iD.actions.AddEntity(start),
25262 iD.actions.AddEntity(end),
25263 iD.actions.AddEntity(segment));
25266 function move(datum) {
25269 if (datum.type === 'node' && datum.id !== end.id) {
25272 } else if (datum.type === 'way' && datum.id !== segment.id) {
25273 var dims = context.map().dimensions(),
25274 mouse = context.mouse(),
25276 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
25277 mouse[1] > pad && mouse[1] < dims[1] - pad;
25280 loc = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
25285 loc = context.map().mouseCoordinates();
25288 context.replace(iD.actions.MoveNode(end.id, loc));
25291 function undone() {
25293 context.enter(iD.modes.Browse(context));
25296 function setActiveElements() {
25297 var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
25298 context.surface().selectAll(iD.util.entitySelector(active))
25299 .classed('active', true);
25302 var drawWay = function(surface) {
25303 draw.on('move', move)
25304 .on('click', drawWay.add)
25305 .on('clickWay', drawWay.addWay)
25306 .on('clickNode', drawWay.addNode)
25307 .on('undo', context.undo)
25308 .on('cancel', drawWay.cancel)
25309 .on('finish', drawWay.finish);
25312 .dblclickEnable(false)
25313 .on('drawn.draw', setActiveElements);
25315 setActiveElements();
25317 surface.call(draw);
25320 .on('undone.draw', undone);
25323 drawWay.off = function(surface) {
25328 .on('drawn.draw', null);
25330 surface.call(draw.off)
25331 .selectAll('.active')
25332 .classed('active', false);
25335 .on('undone.draw', null);
25338 function ReplaceTemporaryNode(newNode) {
25339 return function(graph) {
25342 .replace(way.addNode(newNode.id, index))
25347 .replace(graph.entity(wayId).addNode(newNode.id, index))
25355 // Accept the current position of the temporary node and continue drawing.
25356 drawWay.add = function(loc) {
25358 // prevent duplicate nodes
25359 var last = context.hasEntity(way.nodes[way.nodes.length - (isArea ? 2 : 1)]);
25360 if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
25362 var newNode = iD.Node({loc: loc});
25365 iD.actions.AddEntity(newNode),
25366 ReplaceTemporaryNode(newNode),
25370 context.enter(mode);
25373 // Connect the way to an existing way.
25374 drawWay.addWay = function(loc, edge) {
25375 var previousEdge = startIndex ?
25376 [way.nodes[startIndex], way.nodes[startIndex - 1]] :
25377 [way.nodes[0], way.nodes[1]];
25379 // Avoid creating duplicate segments
25380 if (!isArea && iD.geo.edgeEqual(edge, previousEdge))
25383 var newNode = iD.Node({ loc: loc });
25386 iD.actions.AddMidpoint({ loc: loc, edge: edge}, newNode),
25387 ReplaceTemporaryNode(newNode),
25391 context.enter(mode);
25394 // Connect the way to an existing node and continue drawing.
25395 drawWay.addNode = function(node) {
25397 // Avoid creating duplicate segments
25398 if (way.areAdjacent(node.id, way.nodes[way.nodes.length - 1])) return;
25401 ReplaceTemporaryNode(node),
25405 context.enter(mode);
25408 // Finish the draw operation, removing the temporary node. If the way has enough
25409 // nodes to be valid, it's selected. Otherwise, return to browse mode.
25410 drawWay.finish = function() {
25414 window.setTimeout(function() {
25415 context.map().dblclickEnable(true);
25418 if (context.hasEntity(wayId)) {
25420 iD.modes.Select(context, [wayId])
25421 .suppressMenu(true)
25422 .newFeature(true));
25424 context.enter(iD.modes.Browse(context));
25428 // Cancel the draw operation and return to browse, deleting everything drawn.
25429 drawWay.cancel = function() {
25431 d3.functor(baseGraph),
25432 t('operations.cancel_draw.annotation'));
25434 window.setTimeout(function() {
25435 context.map().dblclickEnable(true);
25439 context.enter(iD.modes.Browse(context));
25442 drawWay.tail = function(text) {
25449 iD.behavior.Edit = function(context) {
25452 .minzoom(context.minEditableZoom());
25455 edit.off = function() {
25462 iD.behavior.Hash = function(context) {
25463 var s0 = null, // cached location.hash
25464 lat = 90 - 1e-8; // allowable latitude range
25466 var parser = function(map, s) {
25467 var q = iD.util.stringQs(s);
25468 var args = (q.map || '').split('/').map(Number);
25469 if (args.length < 3 || args.some(isNaN)) {
25470 return true; // replace bogus hash
25471 } else if (s !== formatter(map).slice(1)) {
25472 map.centerZoom([args[1],
25473 Math.min(lat, Math.max(-lat, args[2]))], args[0]);
25477 var formatter = function(map) {
25478 var mode = context.mode(),
25479 center = map.center(),
25481 precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)),
25482 q = _.omit(iD.util.stringQs(location.hash.substring(1)), 'comment'),
25485 if (mode && mode.id === 'browse') {
25488 var selected = context.selectedIDs().filter(function(id) {
25489 return !context.entity(id).isNew();
25491 if (selected.length) {
25492 newParams.id = selected.join(',');
25496 newParams.map = zoom.toFixed(2) +
25497 '/' + center[0].toFixed(precision) +
25498 '/' + center[1].toFixed(precision);
25500 return '#' + iD.util.qsString(_.assign(q, newParams), true);
25503 function update() {
25504 if (context.inIntro()) return;
25505 var s1 = formatter(context.map());
25506 if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map!
25509 var throttledUpdate = _.throttle(update, 500);
25511 function hashchange() {
25512 if (location.hash === s0) return; // ignore spurious hashchange events
25513 if (parser(context.map(), (s0 = location.hash).substring(1))) {
25514 update(); // replace bogus hash
25520 .on('move.hash', throttledUpdate);
25523 .on('enter.hash', throttledUpdate);
25526 .on('hashchange.hash', hashchange);
25528 if (location.hash) {
25529 var q = iD.util.stringQs(location.hash.substring(1));
25530 if (q.id) context.zoomToEntity(q.id.split(',')[0], !q.map);
25531 if (q.comment) context.storage('comment', q.comment);
25533 if (q.map) hash.hadHash = true;
25537 hash.off = function() {
25538 throttledUpdate.cancel();
25541 .on('move.hash', null);
25544 .on('enter.hash', null);
25547 .on('hashchange.hash', null);
25549 location.hash = '';
25555 The hover behavior adds the `.hover` class on mouseover to all elements to which
25556 the identical datum is bound, and removes it on mouseout.
25558 The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
25559 representation may consist of several elements scattered throughout the DOM hierarchy.
25560 Only one of these elements can have the :hover pseudo-class, but all of them will
25561 have the .hover class.
25563 iD.behavior.Hover = function() {
25564 var dispatch = d3.dispatch('hover'),
25569 function keydown() {
25570 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
25571 dispatch.hover(null);
25572 selection.selectAll('.hover')
25573 .classed('hover-suppressed', true)
25574 .classed('hover', false);
25579 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
25580 dispatch.hover(target ? target.id : null);
25581 selection.selectAll('.hover-suppressed')
25582 .classed('hover-suppressed', false)
25583 .classed('hover', true);
25587 var hover = function(__) {
25590 function enter(d) {
25591 if (d === target) return;
25595 selection.selectAll('.hover')
25596 .classed('hover', false);
25597 selection.selectAll('.hover-suppressed')
25598 .classed('hover-suppressed', false);
25600 if (target instanceof iD.Entity) {
25601 var selector = '.' + target.id;
25603 if (target.type === 'relation') {
25604 target.members.forEach(function(member) {
25605 selector += ', .' + member.id;
25609 var suppressed = altDisables && d3.event && d3.event.altKey;
25611 selection.selectAll(selector)
25612 .classed(suppressed ? 'hover-suppressed' : 'hover', true);
25614 dispatch.hover(target.id);
25616 dispatch.hover(null);
25622 function mouseover() {
25624 var target = d3.event.target;
25625 enter(target ? target.__data__ : null);
25628 function mouseout() {
25630 var target = d3.event.relatedTarget;
25631 enter(target ? target.__data__ : null);
25634 function mousedown() {
25637 .on('mouseup.hover', mouseup);
25640 function mouseup() {
25645 .on('mouseover.hover', mouseover)
25646 .on('mouseout.hover', mouseout)
25647 .on('mousedown.hover', mousedown)
25648 .on('mouseup.hover', mouseup);
25651 .on('keydown.hover', keydown)
25652 .on('keyup.hover', keyup);
25655 hover.off = function(selection) {
25656 selection.selectAll('.hover')
25657 .classed('hover', false);
25658 selection.selectAll('.hover-suppressed')
25659 .classed('hover-suppressed', false);
25662 .on('mouseover.hover', null)
25663 .on('mouseout.hover', null)
25664 .on('mousedown.hover', null)
25665 .on('mouseup.hover', null);
25668 .on('keydown.hover', null)
25669 .on('keyup.hover', null)
25670 .on('mouseup.hover', null);
25673 hover.altDisables = function(_) {
25674 if (!arguments.length) return altDisables;
25679 return d3.rebind(hover, dispatch, 'on');
25681 iD.behavior.Lasso = function(context) {
25683 var behavior = function(selection) {
25686 function mousedown() {
25687 var button = 0; // left
25688 if (d3.event.button === button && d3.event.shiftKey === true) {
25692 .on('mousemove.lasso', mousemove)
25693 .on('mouseup.lasso', mouseup);
25695 d3.event.stopPropagation();
25699 function mousemove() {
25701 lasso = iD.ui.Lasso(context);
25702 context.surface().call(lasso);
25705 lasso.p(context.mouse());
25708 function normalize(a, b) {
25710 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
25711 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
25714 function lassoed() {
25715 if (!lasso) return [];
25717 var graph = context.graph(),
25718 bounds = lasso.extent().map(context.projection.invert),
25719 extent = iD.geo.Extent(normalize(bounds[0], bounds[1]));
25721 return _.map(context.intersects(extent).filter(function(entity) {
25722 return entity.type === 'node' &&
25723 iD.geo.pointInPolygon(context.projection(entity.loc), lasso.coordinates) &&
25724 !context.features().isHidden(entity, graph, entity.geometry(graph));
25728 function mouseup() {
25730 .on('mousemove.lasso', null)
25731 .on('mouseup.lasso', null);
25733 if (!lasso) return;
25735 var ids = lassoed();
25739 context.enter(iD.modes.Select(context, ids));
25744 .on('mousedown.lasso', mousedown);
25747 behavior.off = function(selection) {
25748 selection.on('mousedown.lasso', null);
25753 iD.behavior.Paste = function(context) {
25754 var keybinding = d3.keybinding('paste');
25756 function omitTag(v, k) {
25764 k === 'description' ||
25765 k.indexOf('name') !== -1 ||
25766 k.indexOf('wiki') === 0 ||
25767 k.indexOf('addr:') === 0 ||
25768 k.indexOf('contact:') === 0
25772 function doPaste() {
25773 d3.event.preventDefault();
25774 if (context.inIntro()) return;
25776 var baseGraph = context.graph(),
25777 mouse = context.mouse(),
25778 projection = context.projection,
25779 viewport = iD.geo.Extent(projection.clipExtent()).polygon();
25781 if (!iD.geo.pointInPolygon(mouse, viewport)) return;
25783 var extent = iD.geo.Extent(),
25784 oldIDs = context.copyIDs(),
25785 oldGraph = context.copyGraph(),
25788 if (!oldIDs.length) return;
25790 var action = iD.actions.CopyEntities(oldIDs, oldGraph);
25791 context.perform(action);
25793 var copies = action.copies();
25794 for (var id in copies) {
25795 var oldEntity = oldGraph.entity(id),
25796 newEntity = copies[id];
25798 extent._extend(oldEntity.extent(oldGraph));
25799 newIDs.push(newEntity.id);
25800 context.perform(iD.actions.ChangeTags(newEntity.id, _.omit(newEntity.tags, omitTag)));
25803 // Put pasted objects where mouse pointer is..
25804 var center = projection(extent.center()),
25805 delta = [ mouse[0] - center[0], mouse[1] - center[1] ];
25807 context.perform(iD.actions.Move(newIDs, delta, projection));
25808 context.enter(iD.modes.Move(context, newIDs, baseGraph));
25812 keybinding.on(iD.ui.cmd('⌘V'), doPaste);
25813 d3.select(document).call(keybinding);
25817 paste.off = function() {
25818 d3.select(document).call(keybinding.off);
25823 iD.behavior.Select = function(context) {
25824 function keydown() {
25825 if (d3.event && d3.event.shiftKey) {
25827 .classed('behavior-multiselect', true);
25832 if (!d3.event || !d3.event.shiftKey) {
25834 .classed('behavior-multiselect', false);
25839 var datum = d3.event.target.__data__,
25840 lasso = d3.select('#surface .lasso').node(),
25841 mode = context.mode();
25843 if (!(datum instanceof iD.Entity)) {
25844 if (!d3.event.shiftKey && !lasso && mode.id !== 'browse')
25845 context.enter(iD.modes.Browse(context));
25847 } else if (!d3.event.shiftKey && !lasso) {
25848 // Avoid re-entering Select mode with same entity.
25849 if (context.selectedIDs().length !== 1 || context.selectedIDs()[0] !== datum.id) {
25850 context.enter(iD.modes.Select(context, [datum.id]));
25852 mode.suppressMenu(false).reselect();
25854 } else if (context.selectedIDs().indexOf(datum.id) >= 0) {
25855 var selectedIDs = _.without(context.selectedIDs(), datum.id);
25856 context.enter(selectedIDs.length ?
25857 iD.modes.Select(context, selectedIDs) :
25858 iD.modes.Browse(context));
25861 context.enter(iD.modes.Select(context, context.selectedIDs().concat([datum.id])));
25865 var behavior = function(selection) {
25867 .on('keydown.select', keydown)
25868 .on('keyup.select', keyup);
25870 selection.on('click.select', click);
25875 behavior.off = function(selection) {
25877 .on('keydown.select', null)
25878 .on('keyup.select', null);
25880 selection.on('click.select', null);
25887 iD.behavior.Tail = function() {
25891 tooltipSize = [0, 0],
25892 selectionSize = [0, 0];
25894 function tail(selection) {
25898 .on('resize.tail', function() { selectionSize = selection.dimensions(); });
25901 container.style('display', 'block');
25902 tooltipSize = container.dimensions();
25905 function mousemove() {
25906 if (container.style('display') === 'none') show();
25907 var xoffset = ((d3.event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
25908 -tooltipSize[0] - xmargin : xmargin;
25909 container.classed('left', xoffset > 0);
25910 iD.util.setTransform(container, d3.event.clientX + xoffset, d3.event.clientY);
25913 function mouseleave() {
25914 if (d3.event.relatedTarget !== container.node()) {
25915 container.style('display', 'none');
25919 function mouseenter() {
25920 if (d3.event.relatedTarget !== container.node()) {
25925 container = d3.select(document.body)
25927 .style('display', 'none')
25928 .attr('class', 'tail tooltip-inner');
25930 container.append('div')
25934 .on('mousemove.tail', mousemove)
25935 .on('mouseenter.tail', mouseenter)
25936 .on('mouseleave.tail', mouseleave);
25939 .on('mousemove.tail', mousemove);
25941 tooltipSize = container.dimensions();
25942 selectionSize = selection.dimensions();
25945 tail.off = function(selection) {
25949 .on('mousemove.tail', null)
25953 .on('mousemove.tail', null)
25954 .on('mouseenter.tail', null)
25955 .on('mouseleave.tail', null);
25958 .on('resize.tail', null);
25961 tail.text = function(_) {
25962 if (!arguments.length) return text;
25970 iD.modes.AddArea = function(context) {
25974 title: t('modes.add_area.title'),
25975 description: t('modes.add_area.description'),
25979 var behavior = iD.behavior.AddWay(context)
25980 .tail(t('modes.add_area.tail'))
25981 .on('start', start)
25982 .on('startFromWay', startFromWay)
25983 .on('startFromNode', startFromNode),
25984 defaultTags = {area: 'yes'};
25986 function start(loc) {
25987 var graph = context.graph(),
25988 node = iD.Node({loc: loc}),
25989 way = iD.Way({tags: defaultTags});
25992 iD.actions.AddEntity(node),
25993 iD.actions.AddEntity(way),
25994 iD.actions.AddVertex(way.id, node.id),
25995 iD.actions.AddVertex(way.id, node.id));
25997 context.enter(iD.modes.DrawArea(context, way.id, graph));
26000 function startFromWay(loc, edge) {
26001 var graph = context.graph(),
26002 node = iD.Node({loc: loc}),
26003 way = iD.Way({tags: defaultTags});
26006 iD.actions.AddEntity(node),
26007 iD.actions.AddEntity(way),
26008 iD.actions.AddVertex(way.id, node.id),
26009 iD.actions.AddVertex(way.id, node.id),
26010 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
26012 context.enter(iD.modes.DrawArea(context, way.id, graph));
26015 function startFromNode(node) {
26016 var graph = context.graph(),
26017 way = iD.Way({tags: defaultTags});
26020 iD.actions.AddEntity(way),
26021 iD.actions.AddVertex(way.id, node.id),
26022 iD.actions.AddVertex(way.id, node.id));
26024 context.enter(iD.modes.DrawArea(context, way.id, graph));
26027 mode.enter = function() {
26028 context.install(behavior);
26031 mode.exit = function() {
26032 context.uninstall(behavior);
26037 iD.modes.AddLine = function(context) {
26041 title: t('modes.add_line.title'),
26042 description: t('modes.add_line.description'),
26046 var behavior = iD.behavior.AddWay(context)
26047 .tail(t('modes.add_line.tail'))
26048 .on('start', start)
26049 .on('startFromWay', startFromWay)
26050 .on('startFromNode', startFromNode);
26052 function start(loc) {
26053 var baseGraph = context.graph(),
26054 node = iD.Node({loc: loc}),
26058 iD.actions.AddEntity(node),
26059 iD.actions.AddEntity(way),
26060 iD.actions.AddVertex(way.id, node.id));
26062 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
26065 function startFromWay(loc, edge) {
26066 var baseGraph = context.graph(),
26067 node = iD.Node({loc: loc}),
26071 iD.actions.AddEntity(node),
26072 iD.actions.AddEntity(way),
26073 iD.actions.AddVertex(way.id, node.id),
26074 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
26076 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
26079 function startFromNode(node) {
26080 var baseGraph = context.graph(),
26084 iD.actions.AddEntity(way),
26085 iD.actions.AddVertex(way.id, node.id));
26087 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
26090 mode.enter = function() {
26091 context.install(behavior);
26094 mode.exit = function() {
26095 context.uninstall(behavior);
26100 iD.modes.AddPoint = function(context) {
26104 title: t('modes.add_point.title'),
26105 description: t('modes.add_point.description'),
26109 var behavior = iD.behavior.Draw(context)
26110 .tail(t('modes.add_point.tail'))
26112 .on('clickWay', addWay)
26113 .on('clickNode', addNode)
26114 .on('cancel', cancel)
26115 .on('finish', cancel);
26117 function add(loc) {
26118 var node = iD.Node({loc: loc});
26121 iD.actions.AddEntity(node),
26122 t('operations.add.annotation.point'));
26125 iD.modes.Select(context, [node.id])
26126 .suppressMenu(true)
26127 .newFeature(true));
26130 function addWay(loc) {
26134 function addNode(node) {
26138 function cancel() {
26139 context.enter(iD.modes.Browse(context));
26142 mode.enter = function() {
26143 context.install(behavior);
26146 mode.exit = function() {
26147 context.uninstall(behavior);
26152 iD.modes.Browse = function(context) {
26156 title: t('modes.browse.title'),
26157 description: t('modes.browse.description')
26161 iD.behavior.Paste(context),
26162 iD.behavior.Hover(context)
26163 .on('hover', context.ui().sidebar.hover),
26164 iD.behavior.Select(context),
26165 iD.behavior.Lasso(context),
26166 iD.modes.DragNode(context).behavior];
26168 mode.enter = function() {
26169 behaviors.forEach(function(behavior) {
26170 context.install(behavior);
26173 // Get focus on the body.
26174 if (document.activeElement && document.activeElement.blur) {
26175 document.activeElement.blur();
26179 context.ui().sidebar.show(sidebar);
26181 context.ui().sidebar.select(null);
26185 mode.exit = function() {
26186 context.ui().sidebar.hover.cancel();
26187 behaviors.forEach(function(behavior) {
26188 context.uninstall(behavior);
26192 context.ui().sidebar.hide();
26196 mode.sidebar = function(_) {
26197 if (!arguments.length) return sidebar;
26204 iD.modes.DragNode = function(context) {
26215 hover = iD.behavior.Hover(context)
26217 .on('hover', context.ui().sidebar.hover),
26218 edit = iD.behavior.Edit(context);
26220 function edge(point, size) {
26221 var pad = [30, 100, 30, 100];
26222 if (point[0] > size[0] - pad[0]) return [-10, 0];
26223 else if (point[0] < pad[2]) return [10, 0];
26224 else if (point[1] > size[1] - pad[1]) return [0, -10];
26225 else if (point[1] < pad[3]) return [0, 10];
26229 function startNudge(nudge) {
26230 if (nudgeInterval) window.clearInterval(nudgeInterval);
26231 nudgeInterval = window.setInterval(function() {
26232 context.pan(nudge);
26236 function stopNudge() {
26237 if (nudgeInterval) window.clearInterval(nudgeInterval);
26238 nudgeInterval = null;
26241 function moveAnnotation(entity) {
26242 return t('operations.move.annotation.' + entity.geometry(context.graph()));
26245 function connectAnnotation(entity) {
26246 return t('operations.connect.annotation.' + entity.geometry(context.graph()));
26249 function origin(entity) {
26250 return context.projection(entity.loc);
26253 function start(entity) {
26254 cancelled = d3.event.sourceEvent.shiftKey ||
26255 context.features().hasHiddenConnections(entity, context.graph());
26257 if (cancelled) return behavior.cancel();
26259 wasMidpoint = entity.type === 'midpoint';
26261 var midpoint = entity;
26262 entity = iD.Node();
26263 context.perform(iD.actions.AddMidpoint(midpoint, entity));
26265 var vertex = context.surface()
26266 .selectAll('.' + entity.id);
26267 behavior.target(vertex.node(), entity);
26271 iD.actions.Noop());
26274 activeIDs = _.map(context.graph().parentWays(entity), 'id');
26275 activeIDs.push(entity.id);
26277 context.enter(mode);
26281 if (d3.event.sourceEvent.altKey) {
26285 return d3.event.sourceEvent.target.__data__ || {};
26288 // via https://gist.github.com/shawnbot/4166283
26289 function childOf(p, c) {
26290 if (p === c) return false;
26291 while (c && c !== p) c = c.parentNode;
26295 function move(entity) {
26296 if (cancelled) return;
26297 d3.event.sourceEvent.stopPropagation();
26299 var nudge = childOf(context.container().node(),
26300 d3.event.sourceEvent.toElement) &&
26301 edge(d3.event.point, context.map().dimensions());
26303 if (nudge) startNudge(nudge);
26306 var loc = context.projection.invert(d3.event.point);
26309 if (d.type === 'node' && d.id !== entity.id) {
26311 } else if (d.type === 'way' && !d3.select(d3.event.sourceEvent.target).classed('fill')) {
26312 loc = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
26316 iD.actions.MoveNode(entity.id, loc),
26317 moveAnnotation(entity));
26320 function end(entity) {
26321 if (cancelled) return;
26325 if (d.type === 'way') {
26326 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection);
26328 iD.actions.AddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
26329 connectAnnotation(d));
26331 } else if (d.type === 'node' && d.id !== entity.id) {
26333 iD.actions.Connect([d.id, entity.id]),
26334 connectAnnotation(d));
26336 } else if (wasMidpoint) {
26339 t('operations.add.annotation.vertex'));
26344 moveAnnotation(entity));
26347 var reselection = selectedIDs.filter(function(id) {
26348 return context.graph().hasEntity(id);
26351 if (reselection.length) {
26353 iD.modes.Select(context, reselection)
26354 .suppressMenu(true));
26356 context.enter(iD.modes.Browse(context));
26360 function cancel() {
26362 context.enter(iD.modes.Browse(context));
26365 function setActiveElements() {
26366 context.surface().selectAll(iD.util.entitySelector(activeIDs))
26367 .classed('active', true);
26370 var behavior = iD.behavior.drag()
26371 .delegate('g.node, g.point, g.midpoint')
26372 .surface(context.surface().node())
26374 .on('start', start)
26378 mode.enter = function() {
26379 context.install(hover);
26380 context.install(edit);
26383 .on('undone.drag-node', cancel);
26386 .on('drawn.drag-node', setActiveElements);
26388 setActiveElements();
26391 mode.exit = function() {
26392 context.ui().sidebar.hover.cancel();
26393 context.uninstall(hover);
26394 context.uninstall(edit);
26397 .on('undone.drag-node', null);
26400 .on('drawn.drag-node', null);
26403 .selectAll('.active')
26404 .classed('active', false);
26409 mode.selectedIDs = function(_) {
26410 if (!arguments.length) return selectedIDs;
26415 mode.behavior = behavior;
26419 iD.modes.DrawArea = function(context, wayId, baseGraph) {
26427 mode.enter = function() {
26428 var way = context.entity(wayId),
26429 headId = way.nodes[way.nodes.length - 2],
26430 tailId = way.first();
26432 behavior = iD.behavior.DrawWay(context, wayId, -1, mode, baseGraph)
26433 .tail(t('modes.draw_area.tail'));
26435 var addNode = behavior.addNode;
26437 behavior.addNode = function(node) {
26438 if (node.id === headId || node.id === tailId) {
26445 context.install(behavior);
26448 mode.exit = function() {
26449 context.uninstall(behavior);
26452 mode.selectedIDs = function() {
26458 iD.modes.DrawLine = function(context, wayId, baseGraph, affix) {
26466 mode.enter = function() {
26467 var way = context.entity(wayId),
26468 index = (affix === 'prefix') ? 0 : undefined,
26469 headId = (affix === 'prefix') ? way.first() : way.last();
26471 behavior = iD.behavior.DrawWay(context, wayId, index, mode, baseGraph)
26472 .tail(t('modes.draw_line.tail'));
26474 var addNode = behavior.addNode;
26476 behavior.addNode = function(node) {
26477 if (node.id === headId) {
26484 context.install(behavior);
26487 mode.exit = function() {
26488 context.uninstall(behavior);
26491 mode.selectedIDs = function() {
26497 iD.modes.Move = function(context, entityIDs, baseGraph) {
26503 var keybinding = d3.keybinding('move'),
26504 edit = iD.behavior.Edit(context),
26505 annotation = entityIDs.length === 1 ?
26506 t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
26507 t('operations.move.annotation.multiple'),
26512 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
26514 function edge(point, size) {
26515 var pad = [30, 100, 30, 100];
26516 if (point[0] > size[0] - pad[0]) return [-10, 0];
26517 else if (point[0] < pad[2]) return [10, 0];
26518 else if (point[1] > size[1] - pad[1]) return [0, -10];
26519 else if (point[1] < pad[3]) return [0, 10];
26523 function startNudge(nudge) {
26524 if (nudgeInterval) window.clearInterval(nudgeInterval);
26525 nudgeInterval = window.setInterval(function() {
26526 context.pan(nudge);
26528 var currMouse = context.mouse(),
26529 origMouse = context.projection(origin),
26530 delta = vecSub(vecSub(currMouse, origMouse), nudge),
26531 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
26533 context.overwrite(action, annotation);
26538 function stopNudge() {
26539 if (nudgeInterval) window.clearInterval(nudgeInterval);
26540 nudgeInterval = null;
26544 var currMouse = context.mouse(),
26545 origMouse = context.projection(origin),
26546 delta = vecSub(currMouse, origMouse),
26547 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
26549 context.overwrite(action, annotation);
26551 var nudge = edge(currMouse, context.map().dimensions());
26552 if (nudge) startNudge(nudge);
26556 function finish() {
26557 d3.event.stopPropagation();
26558 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
26562 function cancel() {
26564 while (context.graph() !== baseGraph) context.pop();
26565 context.enter(iD.modes.Browse(context));
26568 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
26573 function undone() {
26574 context.enter(iD.modes.Browse(context));
26577 mode.enter = function() {
26578 origin = context.map().mouseCoordinates();
26581 context.install(edit);
26588 .on('mousemove.move', move)
26589 .on('click.move', finish);
26592 .on('undone.move', undone);
26598 d3.select(document)
26602 mode.exit = function() {
26605 context.uninstall(edit);
26608 .on('mousemove.move', null)
26609 .on('click.move', null);
26612 .on('undone.move', null);
26619 iD.modes.RotateWay = function(context, wayId) {
26625 var keybinding = d3.keybinding('rotate-way'),
26626 edit = iD.behavior.Edit(context);
26628 mode.enter = function() {
26629 context.install(edit);
26631 var annotation = t('operations.rotate.annotation.' + context.geometry(wayId)),
26632 way = context.graph().entity(wayId),
26633 nodes = _.uniq(context.graph().childNodes(way)),
26634 points = nodes.map(function(n) { return context.projection(n.loc); }),
26635 pivot = d3.geom.polygon(points).centroid(),
26642 function rotate() {
26644 var mousePoint = context.mouse(),
26645 newAngle = Math.atan2(mousePoint[1] - pivot[1], mousePoint[0] - pivot[0]);
26647 if (typeof angle === 'undefined') angle = newAngle;
26650 iD.actions.RotateWay(wayId, pivot, newAngle - angle, context.projection),
26656 function finish() {
26657 d3.event.stopPropagation();
26658 context.enter(iD.modes.Select(context, [wayId])
26659 .suppressMenu(true));
26662 function cancel() {
26664 context.enter(iD.modes.Select(context, [wayId])
26665 .suppressMenu(true));
26668 function undone() {
26669 context.enter(iD.modes.Browse(context));
26673 .on('mousemove.rotate-way', rotate)
26674 .on('click.rotate-way', finish);
26677 .on('undone.rotate-way', undone);
26683 d3.select(document)
26687 mode.exit = function() {
26688 context.uninstall(edit);
26691 .on('mousemove.rotate-way', null)
26692 .on('click.rotate-way', null);
26695 .on('undone.rotate-way', null);
26702 iD.modes.Save = function(context) {
26703 var ui = iD.ui.Commit(context)
26704 .on('cancel', cancel)
26707 function cancel() {
26708 context.enter(iD.modes.Browse(context));
26711 function save(e, tryAgain) {
26712 function withChildNodes(ids, graph) {
26713 return _.uniq(_.reduce(ids, function(result, id) {
26714 var e = graph.entity(id);
26715 if (e.type === 'way') {
26717 var cn = graph.childNodes(e);
26718 result.push.apply(result, _.map(_.filter(cn, 'version'), 'id'));
26720 /* eslint-disable no-console */
26721 if (typeof console !== 'undefined') console.error(err);
26722 /* eslint-enable no-console */
26729 var loading = iD.ui.Loading(context).message(t('save.uploading')).blocking(true),
26730 history = context.history(),
26731 origChanges = history.changes(iD.actions.DiscardTags(history.difference())),
26732 localGraph = context.graph(),
26733 remoteGraph = iD.Graph(history.base(), true),
26734 modified = _.filter(history.difference().summary(), {changeType: 'modified'}),
26735 toCheck = _.map(_.map(modified, 'entity'), 'id'),
26736 toLoad = withChildNodes(toCheck, localGraph),
26740 if (!tryAgain) history.perform(iD.actions.Noop()); // checkpoint
26741 context.container().call(loading);
26743 if (toCheck.length) {
26744 context.connection().loadMultiple(toLoad, loaded);
26750 // Reload modified entities into an alternate graph and check for conflicts..
26751 function loaded(err, result) {
26752 if (errors.length) return;
26756 msg: err.responseText,
26757 details: [ t('save.status_code', { code: err.status }) ]
26763 _.each(result.data, function(entity) {
26764 remoteGraph.replace(entity);
26765 toLoad = _.without(toLoad, entity.id);
26767 // Because loadMultiple doesn't download /full like loadEntity,
26768 // need to also load children that aren't already being checked..
26769 if (!entity.visible) return;
26770 if (entity.type === 'way') {
26771 loadMore.push.apply(loadMore,
26772 _.difference(entity.nodes, toCheck, toLoad, loadMore));
26773 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
26774 loadMore.push.apply(loadMore,
26775 _.difference(_.map(entity.members, 'id'), toCheck, toLoad, loadMore));
26779 if (loadMore.length) {
26780 toLoad.push.apply(toLoad, loadMore);
26781 context.connection().loadMultiple(loadMore, loaded);
26784 if (!toLoad.length) {
26791 function checkConflicts() {
26792 function choice(id, text, action) {
26793 return { id: id, text: text, action: function() { history.replace(action); } };
26795 function formatUser(d) {
26796 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
26798 function entityName(entity) {
26799 return iD.util.displayName(entity) || (iD.util.displayType(entity.id) + ' ' + entity.id);
26802 function compareVersions(local, remote) {
26803 if (local.version !== remote.version) return false;
26805 if (local.type === 'way') {
26806 var children = _.union(local.nodes, remote.nodes);
26808 for (var i = 0; i < children.length; i++) {
26809 var a = localGraph.hasEntity(children[i]),
26810 b = remoteGraph.hasEntity(children[i]);
26812 if (a && b && a.version !== b.version) return false;
26819 _.each(toCheck, function(id) {
26820 var local = localGraph.entity(id),
26821 remote = remoteGraph.entity(id);
26823 if (compareVersions(local, remote)) return;
26825 var action = iD.actions.MergeRemoteChanges,
26826 merge = action(id, localGraph, remoteGraph, formatUser);
26828 history.replace(merge);
26830 var mergeConflicts = merge.conflicts();
26831 if (!mergeConflicts.length) return; // merged safely
26833 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
26834 forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
26835 keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
26836 keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
26840 name: entityName(local),
26841 details: mergeConflicts,
26844 choice(id, keepMine, forceLocal),
26845 choice(id, keepTheirs, forceRemote)
26854 function finalize() {
26855 if (conflicts.length) {
26856 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
26858 } else if (errors.length) {
26861 var changes = history.changes(iD.actions.DiscardTags(history.difference()));
26862 if (changes.modified.length || changes.created.length || changes.deleted.length) {
26863 context.connection().putChangeset(
26866 history.imageryUsed(),
26867 function(err, changeset_id) {
26870 msg: err.responseText,
26871 details: [ t('save.status_code', { code: err.status }) ]
26875 history.clearSaved();
26876 success(e, changeset_id);
26877 // Add delay to allow for postgres replication #1646 #2678
26878 window.setTimeout(function() {
26884 } else { // changes were insignificant or reverted by user
26893 function showConflicts() {
26894 var selection = context.container()
26895 .select('#sidebar')
26897 .attr('class','sidebar-component');
26901 selection.call(iD.ui.Conflicts(context)
26903 .on('download', function() {
26904 var data = JXON.stringify(context.connection().osmChangeJXON('CHANGEME', origChanges)),
26905 win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
26908 .on('cancel', function() {
26910 selection.remove();
26912 .on('save', function() {
26913 for (var i = 0; i < conflicts.length; i++) {
26914 if (conflicts[i].chosen === 1) { // user chose "keep theirs"
26915 var entity = context.hasEntity(conflicts[i].id);
26916 if (entity && entity.type === 'way') {
26917 var children = _.uniq(entity.nodes);
26918 for (var j = 0; j < children.length; j++) {
26919 history.replace(iD.actions.Revert(children[j]));
26922 history.replace(iD.actions.Revert(conflicts[i].id));
26926 selection.remove();
26933 function showErrors() {
26934 var selection = iD.ui.confirm(context.container());
26940 .select('.modal-section.header')
26942 .text(t('save.error'));
26944 addErrors(selection, errors);
26945 selection.okButton();
26949 function addErrors(selection, data) {
26950 var message = selection
26951 .select('.modal-section.message-text');
26953 var items = message
26954 .selectAll('.error-container')
26957 var enter = items.enter()
26959 .attr('class', 'error-container');
26963 .attr('class', 'error-description')
26965 .classed('hide-toggle', true)
26966 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
26967 .on('click', function() {
26968 var error = d3.select(this),
26969 detail = d3.select(this.nextElementSibling),
26970 exp = error.classed('expanded');
26972 detail.style('display', exp ? 'none' : 'block');
26973 error.classed('expanded', !exp);
26975 d3.event.preventDefault();
26978 var details = enter
26980 .attr('class', 'error-detail-container')
26981 .style('display', 'none');
26985 .attr('class', 'error-detail-list')
26987 .data(function(d) { return d.details || []; })
26990 .attr('class', 'error-detail-item')
26991 .text(function(d) { return d; });
27000 function success(e, changeset_id) {
27001 context.enter(iD.modes.Browse(context)
27002 .sidebar(iD.ui.Success(context)
27007 .on('cancel', function() {
27008 context.ui().sidebar.hide();
27016 mode.enter = function() {
27017 context.connection().authenticate(function(err) {
27021 context.ui().sidebar.show(ui);
27026 mode.exit = function() {
27027 context.ui().sidebar.hide();
27032 iD.modes.Select = function(context, selectedIDs) {
27038 var keybinding = d3.keybinding('select'),
27041 iD.behavior.Copy(context),
27042 iD.behavior.Paste(context),
27043 iD.behavior.Breathe(context),
27044 iD.behavior.Hover(context),
27045 iD.behavior.Select(context),
27046 iD.behavior.Lasso(context),
27047 iD.modes.DragNode(context)
27048 .selectedIDs(selectedIDs)
27052 newFeature = false,
27053 suppressMenu = false;
27055 var wrap = context.container()
27056 .select('.inspector-wrap');
27059 function singular() {
27060 if (selectedIDs.length === 1) {
27061 return context.hasEntity(selectedIDs[0]);
27065 function closeMenu() {
27067 context.surface().call(radialMenu.close);
27071 function positionMenu() {
27072 if (suppressMenu || !radialMenu) { return; }
27074 var entity = singular();
27075 if (entity && context.geometry(entity.id) === 'relation') {
27076 suppressMenu = true;
27077 } else if (entity && entity.type === 'node') {
27078 radialMenu.center(context.projection(entity.loc));
27080 var point = context.mouse(),
27081 viewport = iD.geo.Extent(context.projection.clipExtent()).polygon();
27082 if (iD.geo.pointInPolygon(point, viewport)) {
27083 radialMenu.center(point);
27085 suppressMenu = true;
27090 function showMenu() {
27092 if (!suppressMenu && radialMenu) {
27093 context.surface().call(radialMenu);
27097 function toggleMenu() {
27098 if (d3.select('.radial-menu').empty()) {
27105 mode.selectedIDs = function() {
27106 return selectedIDs;
27109 mode.reselect = function() {
27110 var surfaceNode = context.surface().node();
27111 if (surfaceNode.focus) { // FF doesn't support it
27112 surfaceNode.focus();
27119 mode.newFeature = function(_) {
27120 if (!arguments.length) return newFeature;
27125 mode.suppressMenu = function(_) {
27126 if (!arguments.length) return suppressMenu;
27131 mode.enter = function() {
27132 function update() {
27134 if (_.some(selectedIDs, function(id) { return !context.hasEntity(id); })) {
27135 // Exit mode if selected entity gets undone
27136 context.enter(iD.modes.Browse(context));
27140 function dblclick() {
27141 var target = d3.select(d3.event.target),
27142 datum = target.datum();
27144 if (datum instanceof iD.Way && !target.classed('fill')) {
27145 var choice = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection),
27148 var prev = datum.nodes[choice.index - 1],
27149 next = datum.nodes[choice.index];
27152 iD.actions.AddMidpoint({loc: choice.loc, edge: [prev, next]}, node),
27153 t('operations.add.annotation.vertex'));
27155 d3.event.preventDefault();
27156 d3.event.stopPropagation();
27160 function selectElements(drawn) {
27161 var entity = singular();
27162 if (entity && context.geometry(entity.id) === 'relation') {
27163 suppressMenu = true;
27167 var selection = context.surface()
27168 .selectAll(iD.util.entityOrMemberSelector(selectedIDs, context.graph()));
27170 if (selection.empty()) {
27171 if (drawn) { // Exit mode if selected DOM elements have disappeared..
27172 context.enter(iD.modes.Browse(context));
27176 .classed('selected', true);
27181 if (!context.inIntro()) {
27182 context.enter(iD.modes.Browse(context));
27187 behaviors.forEach(function(behavior) {
27188 context.install(behavior);
27191 var operations = _.without(d3.values(iD.operations), iD.operations.Delete)
27192 .map(function(o) { return o(selectedIDs, context); })
27193 .filter(function(o) { return o.available(); });
27195 operations.unshift(iD.operations.Delete(selectedIDs, context));
27198 .on('⎋', esc, true)
27199 .on('space', toggleMenu);
27201 operations.forEach(function(operation) {
27202 operation.keys.forEach(function(key) {
27203 keybinding.on(key, function() {
27204 if (!(context.inIntro() || operation.disabled())) {
27211 d3.select(document)
27214 radialMenu = iD.ui.RadialMenu(context, operations);
27216 context.ui().sidebar
27217 .select(singular() ? singular().id : null, newFeature);
27220 .on('undone.select', update)
27221 .on('redone.select', update);
27224 .on('move.select', closeMenu)
27225 .on('drawn.select', selectElements);
27229 var show = d3.event && !suppressMenu;
27235 timeout = window.setTimeout(function() {
27241 .on('dblclick.select', dblclick);
27244 if (selectedIDs.length > 1) {
27245 var entities = iD.ui.SelectionList(context, selectedIDs);
27246 context.ui().sidebar.show(entities);
27250 mode.exit = function() {
27251 if (timeout) window.clearTimeout(timeout);
27253 if (inspector) wrap.call(inspector.close);
27255 behaviors.forEach(function(behavior) {
27256 context.uninstall(behavior);
27261 radialMenu = undefined;
27264 .on('undone.select', null)
27265 .on('redone.select', null);
27268 .on('dblclick.select', null)
27269 .selectAll('.selected')
27270 .classed('selected', false);
27272 context.map().on('drawn.select', null);
27273 context.ui().sidebar.hide();
27278 iD.operations = {};
27279 iD.operations.Circularize = function(selectedIDs, context) {
27280 var entityId = selectedIDs[0],
27281 entity = context.entity(entityId),
27282 extent = entity.extent(context.graph()),
27283 geometry = context.geometry(entityId),
27284 action = iD.actions.Circularize(entityId, context.projection);
27286 var operation = function() {
27287 var annotation = t('operations.circularize.annotation.' + geometry);
27288 context.perform(action, annotation);
27291 operation.available = function() {
27292 return selectedIDs.length === 1 &&
27293 entity.type === 'way' &&
27294 _.uniq(entity.nodes).length > 1;
27297 operation.disabled = function() {
27299 if (extent.percentContainedIn(context.extent()) < 0.8) {
27300 reason = 'too_large';
27301 } else if (context.hasHiddenConnections(entityId)) {
27302 reason = 'connected_to_hidden';
27304 return action.disabled(context.graph()) || reason;
27307 operation.tooltip = function() {
27308 var disable = operation.disabled();
27310 t('operations.circularize.' + disable) :
27311 t('operations.circularize.description.' + geometry);
27314 operation.id = 'circularize';
27315 operation.keys = [t('operations.circularize.key')];
27316 operation.title = t('operations.circularize.title');
27320 iD.operations.Continue = function(selectedIDs, context) {
27321 var graph = context.graph(),
27322 entities = selectedIDs.map(function(id) { return graph.entity(id); }),
27323 geometries = _.extend({line: [], vertex: []},
27324 _.groupBy(entities, function(entity) { return entity.geometry(graph); })),
27325 vertex = geometries.vertex[0];
27327 function candidateWays() {
27328 return graph.parentWays(vertex).filter(function(parent) {
27329 return parent.geometry(graph) === 'line' &&
27330 parent.affix(vertex.id) &&
27331 (geometries.line.length === 0 || geometries.line[0] === parent);
27335 var operation = function() {
27336 var candidate = candidateWays()[0];
27337 context.enter(iD.modes.DrawLine(
27341 candidate.affix(vertex.id)));
27344 operation.available = function() {
27345 return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
27346 !context.features().hasHiddenConnections(vertex, context.graph());
27349 operation.disabled = function() {
27350 var candidates = candidateWays();
27351 if (candidates.length === 0)
27352 return 'not_eligible';
27353 if (candidates.length > 1)
27357 operation.tooltip = function() {
27358 var disable = operation.disabled();
27360 t('operations.continue.' + disable) :
27361 t('operations.continue.description');
27364 operation.id = 'continue';
27365 operation.keys = [t('operations.continue.key')];
27366 operation.title = t('operations.continue.title');
27370 iD.operations.Delete = function(selectedIDs, context) {
27371 var action = iD.actions.DeleteMultiple(selectedIDs);
27373 var operation = function() {
27377 if (selectedIDs.length > 1) {
27378 annotation = t('operations.delete.annotation.multiple', {n: selectedIDs.length});
27381 var id = selectedIDs[0],
27382 entity = context.entity(id),
27383 geometry = context.geometry(id),
27384 parents = context.graph().parentWays(entity),
27385 parent = parents[0];
27387 annotation = t('operations.delete.annotation.' + geometry);
27389 // Select the next closest node in the way.
27390 if (geometry === 'vertex' && parents.length === 1 && parent.nodes.length > 2) {
27391 var nodes = parent.nodes,
27392 i = nodes.indexOf(id);
27396 } else if (i === nodes.length - 1) {
27399 var a = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
27400 b = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
27401 i = a < b ? i - 1 : i + 1;
27404 nextSelectedID = nodes[i];
27408 if (nextSelectedID && context.hasEntity(nextSelectedID)) {
27409 context.enter(iD.modes.Select(context, [nextSelectedID]));
27411 context.enter(iD.modes.Browse(context));
27419 operation.available = function() {
27423 operation.disabled = function() {
27425 if (_.some(selectedIDs, context.hasHiddenConnections)) {
27426 reason = 'connected_to_hidden';
27428 return action.disabled(context.graph()) || reason;
27431 operation.tooltip = function() {
27432 var disable = operation.disabled();
27434 t('operations.delete.' + disable) :
27435 t('operations.delete.description');
27438 operation.id = 'delete';
27439 operation.keys = [iD.ui.cmd('⌘⌫'), iD.ui.cmd('⌘⌦')];
27440 operation.title = t('operations.delete.title');
27444 iD.operations.Disconnect = function(selectedIDs, context) {
27445 var vertices = _.filter(selectedIDs, function vertex(entityId) {
27446 return context.geometry(entityId) === 'vertex';
27449 var entityId = vertices[0],
27450 action = iD.actions.Disconnect(entityId);
27452 if (selectedIDs.length > 1) {
27453 action.limitWays(_.without(selectedIDs, entityId));
27456 var operation = function() {
27457 context.perform(action, t('operations.disconnect.annotation'));
27460 operation.available = function() {
27461 return vertices.length === 1;
27464 operation.disabled = function() {
27466 if (_.some(selectedIDs, context.hasHiddenConnections)) {
27467 reason = 'connected_to_hidden';
27469 return action.disabled(context.graph()) || reason;
27472 operation.tooltip = function() {
27473 var disable = operation.disabled();
27475 t('operations.disconnect.' + disable) :
27476 t('operations.disconnect.description');
27479 operation.id = 'disconnect';
27480 operation.keys = [t('operations.disconnect.key')];
27481 operation.title = t('operations.disconnect.title');
27485 iD.operations.Merge = function(selectedIDs, context) {
27486 var join = iD.actions.Join(selectedIDs),
27487 merge = iD.actions.Merge(selectedIDs),
27488 mergePolygon = iD.actions.MergePolygon(selectedIDs);
27490 var operation = function() {
27491 var annotation = t('operations.merge.annotation', {n: selectedIDs.length}),
27494 if (!join.disabled(context.graph())) {
27496 } else if (!merge.disabled(context.graph())) {
27499 action = mergePolygon;
27502 context.perform(action, annotation);
27503 context.enter(iD.modes.Select(context, selectedIDs.filter(function(id) { return context.hasEntity(id); }))
27504 .suppressMenu(true));
27507 operation.available = function() {
27508 return selectedIDs.length >= 2;
27511 operation.disabled = function() {
27512 return join.disabled(context.graph()) &&
27513 merge.disabled(context.graph()) &&
27514 mergePolygon.disabled(context.graph());
27517 operation.tooltip = function() {
27518 var j = join.disabled(context.graph()),
27519 m = merge.disabled(context.graph()),
27520 p = mergePolygon.disabled(context.graph());
27522 if (j === 'restriction' && m && p)
27523 return t('operations.merge.restriction', {relation: context.presets().item('type/restriction').name()});
27525 if (p === 'incomplete_relation' && j && m)
27526 return t('operations.merge.incomplete_relation');
27529 return t('operations.merge.' + j);
27531 return t('operations.merge.description');
27534 operation.id = 'merge';
27535 operation.keys = [t('operations.merge.key')];
27536 operation.title = t('operations.merge.title');
27540 iD.operations.Move = function(selectedIDs, context) {
27541 var extent = selectedIDs.reduce(function(extent, id) {
27542 return extent.extend(context.entity(id).extent(context.graph()));
27543 }, iD.geo.Extent());
27545 var operation = function() {
27546 context.enter(iD.modes.Move(context, selectedIDs));
27549 operation.available = function() {
27550 return selectedIDs.length > 1 ||
27551 context.entity(selectedIDs[0]).type !== 'node';
27554 operation.disabled = function() {
27556 if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
27557 reason = 'too_large';
27558 } else if (_.some(selectedIDs, context.hasHiddenConnections)) {
27559 reason = 'connected_to_hidden';
27561 return iD.actions.Move(selectedIDs).disabled(context.graph()) || reason;
27564 operation.tooltip = function() {
27565 var disable = operation.disabled();
27567 t('operations.move.' + disable) :
27568 t('operations.move.description');
27571 operation.id = 'move';
27572 operation.keys = [t('operations.move.key')];
27573 operation.title = t('operations.move.title');
27577 iD.operations.Orthogonalize = function(selectedIDs, context) {
27578 var entityId = selectedIDs[0],
27579 entity = context.entity(entityId),
27580 extent = entity.extent(context.graph()),
27581 geometry = context.geometry(entityId),
27582 action = iD.actions.Orthogonalize(entityId, context.projection);
27584 var operation = function() {
27585 var annotation = t('operations.orthogonalize.annotation.' + geometry);
27586 context.perform(action, annotation);
27589 operation.available = function() {
27590 return selectedIDs.length === 1 &&
27591 entity.type === 'way' &&
27592 entity.isClosed() &&
27593 _.uniq(entity.nodes).length > 2;
27596 operation.disabled = function() {
27598 if (extent.percentContainedIn(context.extent()) < 0.8) {
27599 reason = 'too_large';
27600 } else if (context.hasHiddenConnections(entityId)) {
27601 reason = 'connected_to_hidden';
27603 return action.disabled(context.graph()) || reason;
27606 operation.tooltip = function() {
27607 var disable = operation.disabled();
27609 t('operations.orthogonalize.' + disable) :
27610 t('operations.orthogonalize.description.' + geometry);
27613 operation.id = 'orthogonalize';
27614 operation.keys = [t('operations.orthogonalize.key')];
27615 operation.title = t('operations.orthogonalize.title');
27619 iD.operations.Reverse = function(selectedIDs, context) {
27620 var entityId = selectedIDs[0];
27622 var operation = function() {
27624 iD.actions.Reverse(entityId),
27625 t('operations.reverse.annotation'));
27628 operation.available = function() {
27629 return selectedIDs.length === 1 &&
27630 context.geometry(entityId) === 'line';
27633 operation.disabled = function() {
27637 operation.tooltip = function() {
27638 return t('operations.reverse.description');
27641 operation.id = 'reverse';
27642 operation.keys = [t('operations.reverse.key')];
27643 operation.title = t('operations.reverse.title');
27647 iD.operations.Rotate = function(selectedIDs, context) {
27648 var entityId = selectedIDs[0],
27649 entity = context.entity(entityId),
27650 extent = entity.extent(context.graph()),
27651 geometry = context.geometry(entityId);
27653 var operation = function() {
27654 context.enter(iD.modes.RotateWay(context, entityId));
27657 operation.available = function() {
27658 if (selectedIDs.length !== 1 || entity.type !== 'way')
27660 if (geometry === 'area')
27662 if (entity.isClosed() &&
27663 context.graph().parentRelations(entity).some(function(r) { return r.isMultipolygon(); }))
27668 operation.disabled = function() {
27669 if (extent.percentContainedIn(context.extent()) < 0.8) {
27670 return 'too_large';
27671 } else if (context.hasHiddenConnections(entityId)) {
27672 return 'connected_to_hidden';
27678 operation.tooltip = function() {
27679 var disable = operation.disabled();
27681 t('operations.rotate.' + disable) :
27682 t('operations.rotate.description');
27685 operation.id = 'rotate';
27686 operation.keys = [t('operations.rotate.key')];
27687 operation.title = t('operations.rotate.title');
27691 iD.operations.Split = function(selectedIDs, context) {
27692 var vertices = _.filter(selectedIDs, function vertex(entityId) {
27693 return context.geometry(entityId) === 'vertex';
27696 var entityId = vertices[0],
27697 action = iD.actions.Split(entityId);
27699 if (selectedIDs.length > 1) {
27700 action.limitWays(_.without(selectedIDs, entityId));
27703 var operation = function() {
27706 var ways = action.ways(context.graph());
27707 if (ways.length === 1) {
27708 annotation = t('operations.split.annotation.' + context.geometry(ways[0].id));
27710 annotation = t('operations.split.annotation.multiple', {n: ways.length});
27713 var difference = context.perform(action, annotation);
27714 context.enter(iD.modes.Select(context, difference.extantIDs()));
27717 operation.available = function() {
27718 return vertices.length === 1;
27721 operation.disabled = function() {
27723 if (_.some(selectedIDs, context.hasHiddenConnections)) {
27724 reason = 'connected_to_hidden';
27726 return action.disabled(context.graph()) || reason;
27729 operation.tooltip = function() {
27730 var disable = operation.disabled();
27732 return t('operations.split.' + disable);
27735 var ways = action.ways(context.graph());
27736 if (ways.length === 1) {
27737 return t('operations.split.description.' + context.geometry(ways[0].id));
27739 return t('operations.split.description.multiple');
27743 operation.id = 'split';
27744 operation.keys = [t('operations.split.key')];
27745 operation.title = t('operations.split.title');
27749 iD.operations.Straighten = function(selectedIDs, context) {
27750 var entityId = selectedIDs[0],
27751 action = iD.actions.Straighten(entityId, context.projection);
27753 function operation() {
27754 var annotation = t('operations.straighten.annotation');
27755 context.perform(action, annotation);
27758 operation.available = function() {
27759 var entity = context.entity(entityId);
27760 return selectedIDs.length === 1 &&
27761 entity.type === 'way' &&
27762 !entity.isClosed() &&
27763 _.uniq(entity.nodes).length > 2;
27766 operation.disabled = function() {
27768 if (context.hasHiddenConnections(entityId)) {
27769 reason = 'connected_to_hidden';
27771 return action.disabled(context.graph()) || reason;
27774 operation.tooltip = function() {
27775 var disable = operation.disabled();
27777 t('operations.straighten.' + disable) :
27778 t('operations.straighten.description');
27781 operation.id = 'straighten';
27782 operation.keys = [t('operations.straighten.key')];
27783 operation.title = t('operations.straighten.title');
27787 iD.Connection = function(useHttps) {
27788 if (typeof useHttps !== 'boolean') {
27789 useHttps = window.location.protocol === 'https:';
27792 var event = d3.dispatch('authenticating', 'authenticated', 'auth', 'loading', 'loaded'),
27793 protocol = useHttps ? 'https:' : 'http:',
27794 url = protocol + '//www.openstreetmap.org',
27800 url: protocol + '//www.openstreetmap.org',
27801 oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
27802 oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
27803 loading: authenticating,
27804 done: authenticated
27808 memberStr = 'member',
27811 relationStr = 'relation',
27816 connection.changesetURL = function(changesetId) {
27817 return url + '/changeset/' + changesetId;
27820 connection.changesetsURL = function(center, zoom) {
27821 var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
27822 return url + '/history#map=' +
27823 Math.floor(zoom) + '/' +
27824 center[1].toFixed(precision) + '/' +
27825 center[0].toFixed(precision);
27828 connection.entityURL = function(entity) {
27829 return url + '/' + entity.type + '/' + entity.osmId();
27832 connection.userURL = function(username) {
27833 return url + '/user/' + username;
27836 connection.loadFromURL = function(url, callback) {
27837 function done(err, dom) {
27838 return callback(err, parse(dom));
27840 return d3.xml(url).get(done);
27843 connection.loadEntity = function(id, callback) {
27844 var type = iD.Entity.id.type(id),
27845 osmID = iD.Entity.id.toOSM(id);
27847 connection.loadFromURL(
27848 url + '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
27849 function(err, entities) {
27850 if (callback) callback(err, {data: entities});
27854 connection.loadEntityVersion = function(id, version, callback) {
27855 var type = iD.Entity.id.type(id),
27856 osmID = iD.Entity.id.toOSM(id);
27858 connection.loadFromURL(
27859 url + '/api/0.6/' + type + '/' + osmID + '/' + version,
27860 function(err, entities) {
27861 if (callback) callback(err, {data: entities});
27865 connection.loadMultiple = function(ids, callback) {
27866 _.each(_.groupBy(_.uniq(ids), iD.Entity.id.type), function(v, k) {
27867 var type = k + 's',
27868 osmIDs = _.map(v, iD.Entity.id.toOSM);
27870 _.each(_.chunk(osmIDs, 150), function(arr) {
27871 connection.loadFromURL(
27872 url + '/api/0.6/' + type + '?' + type + '=' + arr.join(),
27873 function(err, entities) {
27874 if (callback) callback(err, {data: entities});
27880 function authenticating() {
27881 event.authenticating();
27884 function authenticated() {
27885 event.authenticated();
27888 function getLoc(attrs) {
27889 var lon = attrs.lon && attrs.lon.value,
27890 lat = attrs.lat && attrs.lat.value;
27891 return [parseFloat(lon), parseFloat(lat)];
27894 function getNodes(obj) {
27895 var elems = obj.getElementsByTagName(ndStr),
27896 nodes = new Array(elems.length);
27897 for (var i = 0, l = elems.length; i < l; i++) {
27898 nodes[i] = 'n' + elems[i].attributes.ref.value;
27903 function getTags(obj) {
27904 var elems = obj.getElementsByTagName(tagStr),
27906 for (var i = 0, l = elems.length; i < l; i++) {
27907 var attrs = elems[i].attributes;
27908 tags[attrs.k.value] = attrs.v.value;
27913 function getMembers(obj) {
27914 var elems = obj.getElementsByTagName(memberStr),
27915 members = new Array(elems.length);
27916 for (var i = 0, l = elems.length; i < l; i++) {
27917 var attrs = elems[i].attributes;
27919 id: attrs.type.value[0] + attrs.ref.value,
27920 type: attrs.type.value,
27921 role: attrs.role.value
27927 function getVisible(attrs) {
27928 return (!attrs.visible || attrs.visible.value !== 'false');
27932 node: function nodeData(obj) {
27933 var attrs = obj.attributes;
27934 return new iD.Node({
27935 id: iD.Entity.id.fromOSM(nodeStr, attrs.id.value),
27936 loc: getLoc(attrs),
27937 version: attrs.version.value,
27938 user: attrs.user && attrs.user.value,
27939 tags: getTags(obj),
27940 visible: getVisible(attrs)
27944 way: function wayData(obj) {
27945 var attrs = obj.attributes;
27946 return new iD.Way({
27947 id: iD.Entity.id.fromOSM(wayStr, attrs.id.value),
27948 version: attrs.version.value,
27949 user: attrs.user && attrs.user.value,
27950 tags: getTags(obj),
27951 nodes: getNodes(obj),
27952 visible: getVisible(attrs)
27956 relation: function relationData(obj) {
27957 var attrs = obj.attributes;
27958 return new iD.Relation({
27959 id: iD.Entity.id.fromOSM(relationStr, attrs.id.value),
27960 version: attrs.version.value,
27961 user: attrs.user && attrs.user.value,
27962 tags: getTags(obj),
27963 members: getMembers(obj),
27964 visible: getVisible(attrs)
27969 function parse(dom) {
27970 if (!dom || !dom.childNodes) return;
27972 var root = dom.childNodes[0],
27973 children = root.childNodes,
27976 for (var i = 0, l = children.length; i < l; i++) {
27977 var child = children[i],
27978 parser = parsers[child.nodeName];
27980 entities.push(parser(child));
27987 connection.authenticated = function() {
27988 return oauth.authenticated();
27991 // Generate Changeset XML. Returns a string.
27992 connection.changesetJXON = function(tags) {
27996 tag: _.map(tags, function(value, key) {
27997 return { '@k': key, '@v': value };
28006 // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
28007 // XML. Returns a string.
28008 connection.osmChangeJXON = function(changeset_id, changes) {
28009 function nest(x, order) {
28011 for (var i = 0; i < x.length; i++) {
28012 var tagName = Object.keys(x[i])[0];
28013 if (!groups[tagName]) groups[tagName] = [];
28014 groups[tagName].push(x[i][tagName]);
28017 order.forEach(function(o) {
28018 if (groups[o]) ordered[o] = groups[o];
28023 function rep(entity) {
28024 return entity.asJXON(changeset_id);
28030 '@generator': 'iD',
28031 'create': nest(changes.created.map(rep), ['node', 'way', 'relation']),
28032 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
28033 'delete': _.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {'@if-unused': true})
28038 connection.changesetTags = function(comment, imageryUsed) {
28039 var detected = iD.detect(),
28041 created_by: 'iD ' + iD.version,
28042 imagery_used: imageryUsed.join(';').substr(0, 255),
28043 host: (window.location.origin + window.location.pathname).substr(0, 255),
28044 locale: detected.locale
28048 tags.comment = comment.substr(0, 255);
28054 connection.putChangeset = function(changes, comment, imageryUsed, callback) {
28057 path: '/api/0.6/changeset/create',
28058 options: { header: { 'Content-Type': 'text/xml' } },
28059 content: JXON.stringify(connection.changesetJXON(connection.changesetTags(comment, imageryUsed)))
28060 }, function(err, changeset_id) {
28061 if (err) return callback(err);
28064 path: '/api/0.6/changeset/' + changeset_id + '/upload',
28065 options: { header: { 'Content-Type': 'text/xml' } },
28066 content: JXON.stringify(connection.osmChangeJXON(changeset_id, changes))
28068 if (err) return callback(err);
28069 // POST was successful, safe to call the callback.
28070 // Still attempt to close changeset, but ignore response because #2667
28071 // Add delay to allow for postgres replication #1646 #2678
28072 window.setTimeout(function() { callback(null, changeset_id); }, 2500);
28075 path: '/api/0.6/changeset/' + changeset_id + '/close',
28076 options: { header: { 'Content-Type': 'text/xml' } }
28077 }, d3.functor(true));
28082 connection.userDetails = function(callback) {
28084 callback(undefined, userDetails);
28088 function done(err, user_details) {
28089 if (err) return callback(err);
28091 var u = user_details.getElementsByTagName('user')[0],
28092 img = u.getElementsByTagName('img'),
28095 if (img && img[0] && img[0].getAttribute('href')) {
28096 image_url = img[0].getAttribute('href');
28100 display_name: u.attributes.display_name.value,
28101 image_url: image_url,
28102 id: u.attributes.id.value
28105 callback(undefined, userDetails);
28108 oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
28111 connection.userChangesets = function(callback) {
28112 connection.userDetails(function(err, user) {
28113 if (err) return callback(err);
28115 function done(changesets) {
28116 callback(undefined, Array.prototype.map.call(changesets.getElementsByTagName('changeset'),
28117 function (changeset) {
28118 return { tags: getTags(changeset) };
28122 d3.xml(url + '/api/0.6/changesets?user=' + user.id).get()
28124 .on('error', callback);
28128 connection.status = function(callback) {
28129 function done(capabilities) {
28130 var apiStatus = capabilities.getElementsByTagName('status');
28131 callback(undefined, apiStatus[0].getAttribute('api'));
28133 d3.xml(url + '/api/capabilities').get()
28135 .on('error', callback);
28138 function abortRequest(i) { i.abort(); }
28140 connection.tileZoom = function(_) {
28141 if (!arguments.length) return tileZoom;
28146 connection.loadTiles = function(projection, dimensions, callback) {
28150 var s = projection.scale() * 2 * Math.PI,
28151 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
28152 ts = 256 * Math.pow(2, z - tileZoom),
28154 s / 2 - projection.translate()[0],
28155 s / 2 - projection.translate()[1]];
28157 var tiles = d3.geo.tile()
28158 .scaleExtent([tileZoom, tileZoom])
28161 .translate(projection.translate())()
28162 .map(function(tile) {
28163 var x = tile[0] * ts - origin[0],
28164 y = tile[1] * ts - origin[1];
28167 id: tile.toString(),
28168 extent: iD.geo.Extent(
28169 projection.invert([x, y + ts]),
28170 projection.invert([x + ts, y]))
28174 function bboxUrl(tile) {
28175 return url + '/api/0.6/map?bbox=' + tile.extent.toParam();
28178 _.filter(inflight, function(v, i) {
28179 var wanted = _.find(tiles, function(tile) {
28180 return i === tile.id;
28182 if (!wanted) delete inflight[i];
28184 }).map(abortRequest);
28186 tiles.forEach(function(tile) {
28189 if (loadedTiles[id] || inflight[id]) return;
28191 if (_.isEmpty(inflight)) {
28195 inflight[id] = connection.loadFromURL(bboxUrl(tile), function(err, parsed) {
28196 loadedTiles[id] = true;
28197 delete inflight[id];
28199 if (callback) callback(err, _.extend({data: parsed}, tile));
28201 if (_.isEmpty(inflight)) {
28208 connection.switch = function(options) {
28210 oauth.options(_.extend({
28211 loading: authenticating,
28212 done: authenticated
28215 connection.flush();
28219 connection.toggle = function(_) {
28224 connection.flush = function() {
28225 userDetails = undefined;
28226 _.forEach(inflight, abortRequest);
28232 connection.loadedTiles = function(_) {
28233 if (!arguments.length) return loadedTiles;
28238 connection.logout = function() {
28239 userDetails = undefined;
28245 connection.authenticate = function(callback) {
28246 userDetails = undefined;
28247 function done(err, res) {
28249 if (callback) callback(err, res);
28251 return oauth.authenticate(done);
28254 return d3.rebind(connection, event, 'on');
28257 iD.Difference represents the difference between two graphs.
28258 It knows how to calculate the set of entities that were
28259 created, modified, or deleted, and also contains the logic
28260 for recursively extending a difference to the complete set
28261 of entities that will require a redraw, taking into account
28262 child and parent relationships.
28264 iD.Difference = function(base, head) {
28265 var changes = {}, length = 0;
28267 function changed(h, b) {
28268 return h !== b && !_.isEqual(_.omit(h, 'v'), _.omit(b, 'v'));
28271 _.each(head.entities, function(h, id) {
28272 var b = base.entities[id];
28273 if (changed(h, b)) {
28274 changes[id] = {base: b, head: h};
28279 _.each(base.entities, function(b, id) {
28280 var h = head.entities[id];
28281 if (!changes[id] && changed(h, b)) {
28282 changes[id] = {base: b, head: h};
28287 function addParents(parents, result) {
28288 for (var i = 0; i < parents.length; i++) {
28289 var parent = parents[i];
28291 if (parent.id in result)
28294 result[parent.id] = parent;
28295 addParents(head.parentRelations(parent), result);
28299 var difference = {};
28301 difference.length = function() {
28305 difference.changes = function() {
28309 difference.extantIDs = function() {
28311 _.each(changes, function(change, id) {
28312 if (change.head) result.push(id);
28317 difference.modified = function() {
28319 _.each(changes, function(change) {
28320 if (change.base && change.head) result.push(change.head);
28325 difference.created = function() {
28327 _.each(changes, function(change) {
28328 if (!change.base && change.head) result.push(change.head);
28333 difference.deleted = function() {
28335 _.each(changes, function(change) {
28336 if (change.base && !change.head) result.push(change.base);
28341 difference.summary = function() {
28344 function addEntity(entity, graph, changeType) {
28345 relevant[entity.id] = {
28348 changeType: changeType
28352 function addParents(entity) {
28353 var parents = head.parentWays(entity);
28354 for (var j = parents.length - 1; j >= 0; j--) {
28355 var parent = parents[j];
28356 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
28360 _.each(changes, function(change) {
28361 if (change.head && change.head.geometry(head) !== 'vertex') {
28362 addEntity(change.head, head, change.base ? 'modified' : 'created');
28364 } else if (change.base && change.base.geometry(base) !== 'vertex') {
28365 addEntity(change.base, base, 'deleted');
28367 } else if (change.base && change.head) { // modified vertex
28368 var moved = !_.isEqual(change.base.loc, change.head.loc),
28369 retagged = !_.isEqual(change.base.tags, change.head.tags);
28372 addParents(change.head);
28375 if (retagged || (moved && change.head.hasInterestingTags())) {
28376 addEntity(change.head, head, 'modified');
28379 } else if (change.head && change.head.hasInterestingTags()) { // created vertex
28380 addEntity(change.head, head, 'created');
28382 } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
28383 addEntity(change.base, base, 'deleted');
28387 return d3.values(relevant);
28390 difference.complete = function(extent) {
28391 var result = {}, id, change;
28393 for (id in changes) {
28394 change = changes[id];
28396 var h = change.head,
28401 (!h || !h.intersects(extent, head)) &&
28402 (!b || !b.intersects(extent, base)))
28407 if (entity.type === 'way') {
28408 var nh = h ? h.nodes : [],
28409 nb = b ? b.nodes : [],
28412 diff = _.difference(nh, nb);
28413 for (i = 0; i < diff.length; i++) {
28414 result[diff[i]] = head.hasEntity(diff[i]);
28417 diff = _.difference(nb, nh);
28418 for (i = 0; i < diff.length; i++) {
28419 result[diff[i]] = head.hasEntity(diff[i]);
28423 addParents(head.parentWays(entity), result);
28424 addParents(head.parentRelations(entity), result);
28432 iD.Entity = function(attrs) {
28433 // For prototypal inheritance.
28434 if (this instanceof iD.Entity) return;
28436 // Create the appropriate subtype.
28437 if (attrs && attrs.type) {
28438 return iD.Entity[attrs.type].apply(this, arguments);
28439 } else if (attrs && attrs.id) {
28440 return iD.Entity[iD.Entity.id.type(attrs.id)].apply(this, arguments);
28443 // Initialize a generic Entity (used only in tests).
28444 return (new iD.Entity()).initialize(arguments);
28447 iD.Entity.id = function(type) {
28448 return iD.Entity.id.fromOSM(type, iD.Entity.id.next[type]--);
28451 iD.Entity.id.next = {node: -1, way: -1, relation: -1};
28453 iD.Entity.id.fromOSM = function(type, id) {
28454 return type[0] + id;
28457 iD.Entity.id.toOSM = function(id) {
28458 return id.slice(1);
28461 iD.Entity.id.type = function(id) {
28462 return {'n': 'node', 'w': 'way', 'r': 'relation'}[id[0]];
28465 // A function suitable for use as the second argument to d3.selection#data().
28466 iD.Entity.key = function(entity) {
28467 return entity.id + 'v' + (entity.v || 0);
28470 iD.Entity.prototype = {
28473 initialize: function(sources) {
28474 for (var i = 0; i < sources.length; ++i) {
28475 var source = sources[i];
28476 for (var prop in source) {
28477 if (Object.prototype.hasOwnProperty.call(source, prop)) {
28478 if (source[prop] === undefined) {
28481 this[prop] = source[prop];
28487 if (!this.id && this.type) {
28488 this.id = iD.Entity.id(this.type);
28490 if (!this.hasOwnProperty('visible')) {
28491 this.visible = true;
28495 Object.freeze(this);
28496 Object.freeze(this.tags);
28498 if (this.loc) Object.freeze(this.loc);
28499 if (this.nodes) Object.freeze(this.nodes);
28500 if (this.members) Object.freeze(this.members);
28506 copy: function(resolver, copies) {
28507 if (copies[this.id])
28508 return copies[this.id];
28510 var copy = iD.Entity(this, {id: undefined, user: undefined, version: undefined});
28511 copies[this.id] = copy;
28516 osmId: function() {
28517 return iD.Entity.id.toOSM(this.id);
28520 isNew: function() {
28521 return this.osmId() < 0;
28524 update: function(attrs) {
28525 return iD.Entity(this, attrs, {v: 1 + (this.v || 0)});
28528 mergeTags: function(tags) {
28529 var merged = _.clone(this.tags), changed = false;
28530 for (var k in tags) {
28531 var t1 = merged[k],
28536 } else if (t1 !== t2) {
28538 merged[k] = _.union(t1.split(/;\s*/), t2.split(/;\s*/)).join(';');
28541 return changed ? this.update({tags: merged}) : this;
28544 intersects: function(extent, resolver) {
28545 return this.extent(resolver).intersects(extent);
28548 isUsed: function(resolver) {
28549 return _.without(Object.keys(this.tags), 'area').length > 0 ||
28550 resolver.parentRelations(this).length > 0;
28553 hasInterestingTags: function() {
28554 return _.keys(this.tags).some(iD.interestingTag);
28557 isHighwayIntersection: function() {
28561 deprecatedTags: function() {
28562 var tags = _.toPairs(this.tags);
28563 var deprecated = {};
28565 iD.data.deprecated.forEach(function(d) {
28566 var match = _.toPairs(d.old)[0];
28567 tags.forEach(function(t) {
28568 if (t[0] === match[0] &&
28569 (t[1] === match[1] || match[1] === '*')) {
28570 deprecated[t[0]] = t[1];
28578 iD.Graph = function(other, mutable) {
28579 if (!(this instanceof iD.Graph)) return new iD.Graph(other, mutable);
28581 if (other instanceof iD.Graph) {
28582 var base = other.base();
28583 this.entities = _.assign(Object.create(base.entities), other.entities);
28584 this._parentWays = _.assign(Object.create(base.parentWays), other._parentWays);
28585 this._parentRels = _.assign(Object.create(base.parentRels), other._parentRels);
28588 this.entities = Object.create({});
28589 this._parentWays = Object.create({});
28590 this._parentRels = Object.create({});
28591 this.rebase(other || [], [this]);
28594 this.transients = {};
28595 this._childNodes = {};
28596 this.frozen = !mutable;
28599 iD.Graph.prototype = {
28600 hasEntity: function(id) {
28601 return this.entities[id];
28604 entity: function(id) {
28605 var entity = this.entities[id];
28607 throw new Error('entity ' + id + ' not found');
28612 transient: function(entity, key, fn) {
28613 var id = entity.id,
28614 transients = this.transients[id] ||
28615 (this.transients[id] = {});
28617 if (transients[key] !== undefined) {
28618 return transients[key];
28621 transients[key] = fn.call(entity);
28623 return transients[key];
28626 parentWays: function(entity) {
28627 var parents = this._parentWays[entity.id],
28631 for (var i = 0; i < parents.length; i++) {
28632 result.push(this.entity(parents[i]));
28638 isPoi: function(entity) {
28639 var parentWays = this._parentWays[entity.id];
28640 return !parentWays || parentWays.length === 0;
28643 isShared: function(entity) {
28644 var parentWays = this._parentWays[entity.id];
28645 return parentWays && parentWays.length > 1;
28648 parentRelations: function(entity) {
28649 var parents = this._parentRels[entity.id],
28653 for (var i = 0; i < parents.length; i++) {
28654 result.push(this.entity(parents[i]));
28660 childNodes: function(entity) {
28661 if (this._childNodes[entity.id]) return this._childNodes[entity.id];
28662 if (!entity.nodes) return [];
28665 for (var i = 0; i < entity.nodes.length; i++) {
28666 nodes[i] = this.entity(entity.nodes[i]);
28669 if (iD.debug) Object.freeze(nodes);
28671 this._childNodes[entity.id] = nodes;
28672 return this._childNodes[entity.id];
28677 'entities': iD.util.getPrototypeOf(this.entities),
28678 'parentWays': iD.util.getPrototypeOf(this._parentWays),
28679 'parentRels': iD.util.getPrototypeOf(this._parentRels)
28683 // Unlike other graph methods, rebase mutates in place. This is because it
28684 // is used only during the history operation that merges newly downloaded
28685 // data into each state. To external consumers, it should appear as if the
28686 // graph always contained the newly downloaded data.
28687 rebase: function(entities, stack, force) {
28688 var base = this.base(),
28691 for (i = 0; i < entities.length; i++) {
28692 var entity = entities[i];
28694 if (!entity.visible || (!force && base.entities[entity.id]))
28697 // Merging data into the base graph
28698 base.entities[entity.id] = entity;
28699 this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
28701 // Restore provisionally-deleted nodes that are discovered to have an extant parent
28702 if (entity.type === 'way') {
28703 for (j = 0; j < entity.nodes.length; j++) {
28704 id = entity.nodes[j];
28705 for (k = 1; k < stack.length; k++) {
28706 var ents = stack[k].entities;
28707 if (ents.hasOwnProperty(id) && ents[id] === undefined) {
28715 for (i = 0; i < stack.length; i++) {
28716 stack[i]._updateRebased();
28720 _updateRebased: function() {
28721 var base = this.base(),
28722 i, k, child, id, keys;
28724 keys = Object.keys(this._parentWays);
28725 for (i = 0; i < keys.length; i++) {
28727 if (base.parentWays[child]) {
28728 for (k = 0; k < base.parentWays[child].length; k++) {
28729 id = base.parentWays[child][k];
28730 if (!this.entities.hasOwnProperty(id) && !_.includes(this._parentWays[child], id)) {
28731 this._parentWays[child].push(id);
28737 keys = Object.keys(this._parentRels);
28738 for (i = 0; i < keys.length; i++) {
28740 if (base.parentRels[child]) {
28741 for (k = 0; k < base.parentRels[child].length; k++) {
28742 id = base.parentRels[child][k];
28743 if (!this.entities.hasOwnProperty(id) && !_.includes(this._parentRels[child], id)) {
28744 this._parentRels[child].push(id);
28750 this.transients = {};
28752 // this._childNodes is not updated, under the assumption that
28753 // ways are always downloaded with their child nodes.
28756 // Updates calculated properties (parentWays, parentRels) for the specified change
28757 _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
28759 parentWays = parentWays || this._parentWays;
28760 parentRels = parentRels || this._parentRels;
28762 var type = entity && entity.type || oldentity && oldentity.type,
28763 removed, added, ways, rels, i;
28766 if (type === 'way') {
28768 // Update parentWays
28769 if (oldentity && entity) {
28770 removed = _.difference(oldentity.nodes, entity.nodes);
28771 added = _.difference(entity.nodes, oldentity.nodes);
28772 } else if (oldentity) {
28773 removed = oldentity.nodes;
28775 } else if (entity) {
28777 added = entity.nodes;
28779 for (i = 0; i < removed.length; i++) {
28780 parentWays[removed[i]] = _.without(parentWays[removed[i]], oldentity.id);
28782 for (i = 0; i < added.length; i++) {
28783 ways = _.without(parentWays[added[i]], entity.id);
28784 ways.push(entity.id);
28785 parentWays[added[i]] = ways;
28788 } else if (type === 'relation') {
28790 // Update parentRels
28791 if (oldentity && entity) {
28792 removed = _.difference(oldentity.members, entity.members);
28793 added = _.difference(entity.members, oldentity);
28794 } else if (oldentity) {
28795 removed = oldentity.members;
28797 } else if (entity) {
28799 added = entity.members;
28801 for (i = 0; i < removed.length; i++) {
28802 parentRels[removed[i].id] = _.without(parentRels[removed[i].id], oldentity.id);
28804 for (i = 0; i < added.length; i++) {
28805 rels = _.without(parentRels[added[i].id], entity.id);
28806 rels.push(entity.id);
28807 parentRels[added[i].id] = rels;
28812 replace: function(entity) {
28813 if (this.entities[entity.id] === entity)
28816 return this.update(function() {
28817 this._updateCalculated(this.entities[entity.id], entity);
28818 this.entities[entity.id] = entity;
28822 remove: function(entity) {
28823 return this.update(function() {
28824 this._updateCalculated(entity, undefined);
28825 this.entities[entity.id] = undefined;
28829 revert: function(id) {
28830 var baseEntity = this.base().entities[id],
28831 headEntity = this.entities[id];
28833 if (headEntity === baseEntity)
28836 return this.update(function() {
28837 this._updateCalculated(headEntity, baseEntity);
28838 delete this.entities[id];
28842 update: function() {
28843 var graph = this.frozen ? iD.Graph(this, true) : this;
28845 for (var i = 0; i < arguments.length; i++) {
28846 arguments[i].call(graph, graph);
28849 if (this.frozen) graph.frozen = true;
28854 // Obliterates any existing entities
28855 load: function(entities) {
28856 var base = this.base();
28857 this.entities = Object.create(base.entities);
28859 for (var i in entities) {
28860 this.entities[i] = entities[i];
28861 this._updateCalculated(base.entities[i], this.entities[i]);
28867 iD.History = function(context) {
28868 var stack, index, tree,
28869 imageryUsed = ['Bing'],
28870 dispatch = d3.dispatch('change', 'undone', 'redone'),
28871 lock = iD.util.SessionMutex('lock');
28873 function perform(actions) {
28874 actions = Array.prototype.slice.call(actions);
28878 if (!_.isFunction(_.last(actions))) {
28879 annotation = actions.pop();
28882 var graph = stack[index].graph;
28883 for (var i = 0; i < actions.length; i++) {
28884 graph = actions[i](graph);
28889 annotation: annotation,
28890 imageryUsed: imageryUsed
28894 function change(previous) {
28895 var difference = iD.Difference(previous, history.graph());
28896 dispatch.change(difference);
28900 // iD uses namespaced keys so multiple installations do not conflict
28901 function getKey(n) {
28902 return 'iD_' + window.location.origin + '_' + n;
28906 graph: function() {
28907 return stack[index].graph;
28911 return stack[0].graph;
28914 merge: function(entities, extent) {
28915 stack[0].graph.rebase(entities, _.map(stack, 'graph'), false);
28916 tree.rebase(entities, false);
28918 dispatch.change(undefined, extent);
28921 perform: function() {
28922 var previous = stack[index].graph;
28924 stack = stack.slice(0, index + 1);
28925 stack.push(perform(arguments));
28928 return change(previous);
28931 replace: function() {
28932 var previous = stack[index].graph;
28934 // assert(index == stack.length - 1)
28935 stack[index] = perform(arguments);
28937 return change(previous);
28941 var previous = stack[index].graph;
28946 return change(previous);
28950 // Same as calling pop and then perform
28951 overwrite: function() {
28952 var previous = stack[index].graph;
28958 stack = stack.slice(0, index + 1);
28959 stack.push(perform(arguments));
28962 return change(previous);
28966 var previous = stack[index].graph;
28968 // Pop to the next annotated state.
28969 while (index > 0) {
28971 if (stack[index].annotation) break;
28975 return change(previous);
28979 var previous = stack[index].graph;
28981 while (index < stack.length - 1) {
28983 if (stack[index].annotation) break;
28987 return change(previous);
28990 undoAnnotation: function() {
28993 if (stack[i].annotation) return stack[i].annotation;
28998 redoAnnotation: function() {
29000 while (i <= stack.length - 1) {
29001 if (stack[i].annotation) return stack[i].annotation;
29006 intersects: function(extent) {
29007 return tree.intersects(extent, stack[index].graph);
29010 difference: function() {
29011 var base = stack[0].graph,
29012 head = stack[index].graph;
29013 return iD.Difference(base, head);
29016 changes: function(action) {
29017 var base = stack[0].graph,
29018 head = stack[index].graph;
29021 head = action(head);
29024 var difference = iD.Difference(base, head);
29027 modified: difference.modified(),
29028 created: difference.created(),
29029 deleted: difference.deleted()
29033 validate: function(changes) {
29034 return _(iD.validations)
29035 .map(function(fn) { return fn()(changes, stack[index].graph); })
29040 hasChanges: function() {
29041 return this.difference().length() > 0;
29044 imageryUsed: function(sources) {
29046 imageryUsed = sources;
29049 return _(stack.slice(1, index + 1))
29050 .map('imageryUsed')
29053 .without(undefined, 'Custom')
29058 reset: function() {
29059 stack = [{graph: iD.Graph()}];
29061 tree = iD.Tree(stack[0].graph);
29066 toJSON: function() {
29067 if (!this.hasChanges()) return;
29069 var allEntities = {},
29073 var s = stack.map(function(i) {
29074 var modified = [], deleted = [];
29076 _.forEach(i.graph.entities, function(entity, id) {
29078 var key = iD.Entity.key(entity);
29079 allEntities[key] = entity;
29080 modified.push(key);
29085 // make sure that the originals of changed or deleted entities get merged
29086 // into the base of the stack after restoring the data from JSON.
29087 if (id in base.graph.entities) {
29088 baseEntities[id] = base.graph.entities[id];
29090 // get originals of parent entities too
29091 _.forEach(base.graph._parentWays[id], function(parentId) {
29092 if (parentId in base.graph.entities) {
29093 baseEntities[parentId] = base.graph.entities[parentId];
29100 if (modified.length) x.modified = modified;
29101 if (deleted.length) x.deleted = deleted;
29102 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
29103 if (i.annotation) x.annotation = i.annotation;
29108 return JSON.stringify({
29110 entities: _.values(allEntities),
29111 baseEntities: _.values(baseEntities),
29113 nextIDs: iD.Entity.id.next,
29118 fromJSON: function(json, loadChildNodes) {
29119 var h = JSON.parse(json),
29120 loadComplete = true;
29122 iD.Entity.id.next = h.nextIDs;
29125 if (h.version === 2 || h.version === 3) {
29126 var allEntities = {};
29128 h.entities.forEach(function(entity) {
29129 allEntities[iD.Entity.key(entity)] = iD.Entity(entity);
29132 if (h.version === 3) {
29133 // This merges originals for changed entities into the base of
29134 // the stack even if the current stack doesn't have them (for
29135 // example when iD has been restarted in a different region)
29136 var baseEntities = h.baseEntities.map(function(d) { return iD.Entity(d); });
29137 stack[0].graph.rebase(baseEntities, _.map(stack, 'graph'), true);
29138 tree.rebase(baseEntities, true);
29140 // When we restore a modified way, we also need to fetch any missing
29141 // childnodes that would normally have been downloaded with it.. #2142
29142 if (loadChildNodes) {
29143 var missing = _(baseEntities)
29144 .filter({ type: 'way' })
29148 .reject(function(n) { return stack[0].graph.hasEntity(n); })
29151 if (!_.isEmpty(missing)) {
29152 loadComplete = false;
29153 context.redrawEnable(false);
29155 var loading = iD.ui.Loading(context).blocking(true);
29156 context.container().call(loading);
29158 var childNodesLoaded = function(err, result) {
29160 var visible = _.groupBy(result.data, 'visible');
29161 if (!_.isEmpty(visible.true)) {
29162 missing = _.difference(missing, _.map(visible.true, 'id'));
29163 stack[0].graph.rebase(visible.true, _.map(stack, 'graph'), true);
29164 tree.rebase(visible.true, true);
29167 // fetch older versions of nodes that were deleted..
29168 _.each(visible.false, function(entity) {
29169 context.connection()
29170 .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
29174 if (err || _.isEmpty(missing)) {
29176 context.redrawEnable(true);
29181 context.connection().loadMultiple(missing, childNodesLoaded);
29186 stack = h.stack.map(function(d) {
29187 var entities = {}, entity;
29190 d.modified.forEach(function(key) {
29191 entity = allEntities[key];
29192 entities[entity.id] = entity;
29197 d.deleted.forEach(function(id) {
29198 entities[id] = undefined;
29203 graph: iD.Graph(stack[0].graph).load(entities),
29204 annotation: d.annotation,
29205 imageryUsed: d.imageryUsed
29209 } else { // original version
29210 stack = h.stack.map(function(d) {
29213 for (var i in d.entities) {
29214 var entity = d.entities[i];
29215 entities[i] = entity === 'undefined' ? undefined : iD.Entity(entity);
29218 d.graph = iD.Graph(stack[0].graph).load(entities);
29223 if (loadComplete) {
29231 if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
29235 clearSaved: function() {
29236 context.debouncedSave.cancel();
29237 if (lock.locked()) context.storage(getKey('saved_history'), null);
29242 return lock.lock();
29245 unlock: function() {
29249 // is iD not open in another window and it detects that
29250 // there's a history stored in localStorage that's recoverable?
29251 restorableChanges: function() {
29252 return lock.locked() && !!context.storage(getKey('saved_history'));
29255 // load history from a version stored in localStorage
29256 restore: function() {
29257 if (!lock.locked()) return;
29259 var json = context.storage(getKey('saved_history'));
29260 if (json) history.fromJSON(json, true);
29269 return d3.rebind(history, dispatch, 'on');
29271 iD.Node = iD.Entity.node = function iD_Node() {
29272 if (!(this instanceof iD_Node)) {
29273 return (new iD_Node()).initialize(arguments);
29274 } else if (arguments.length) {
29275 this.initialize(arguments);
29279 iD.Node.prototype = Object.create(iD.Entity.prototype);
29281 _.extend(iD.Node.prototype, {
29284 extent: function() {
29285 return new iD.geo.Extent(this.loc);
29288 geometry: function(graph) {
29289 return graph.transient(this, 'geometry', function() {
29290 return graph.isPoi(this) ? 'point' : 'vertex';
29294 move: function(loc) {
29295 return this.update({loc: loc});
29298 isIntersection: function(resolver) {
29299 return resolver.transient(this, 'isIntersection', function() {
29300 return resolver.parentWays(this).filter(function(parent) {
29301 return (parent.tags.highway ||
29302 parent.tags.waterway ||
29303 parent.tags.railway ||
29304 parent.tags.aeroway) &&
29305 parent.geometry(resolver) === 'line';
29310 isHighwayIntersection: function(resolver) {
29311 return resolver.transient(this, 'isHighwayIntersection', function() {
29312 return resolver.parentWays(this).filter(function(parent) {
29313 return parent.tags.highway && parent.geometry(resolver) === 'line';
29318 isOnAddressLine: function(resolver) {
29319 return resolver.transient(this, 'isOnAddressLine', function() {
29320 return resolver.parentWays(this).filter(function(parent) {
29321 return parent.tags.hasOwnProperty('addr:interpolation') &&
29322 parent.geometry(resolver) === 'line';
29327 asJXON: function(changeset_id) {
29330 '@id': this.osmId(),
29331 '@lon': this.loc[0],
29332 '@lat': this.loc[1],
29333 '@version': (this.version || 0),
29334 tag: _.map(this.tags, function(v, k) {
29335 return { keyAttributes: { k: k, v: v } };
29339 if (changeset_id) r.node['@changeset'] = changeset_id;
29343 asGeoJSON: function() {
29346 coordinates: this.loc
29350 iD.Relation = iD.Entity.relation = function iD_Relation() {
29351 if (!(this instanceof iD_Relation)) {
29352 return (new iD_Relation()).initialize(arguments);
29353 } else if (arguments.length) {
29354 this.initialize(arguments);
29358 iD.Relation.prototype = Object.create(iD.Entity.prototype);
29360 iD.Relation.creationOrder = function(a, b) {
29361 var aId = parseInt(iD.Entity.id.toOSM(a.id), 10);
29362 var bId = parseInt(iD.Entity.id.toOSM(b.id), 10);
29364 if (aId < 0 || bId < 0) return aId - bId;
29368 _.extend(iD.Relation.prototype, {
29372 copy: function(resolver, copies) {
29373 if (copies[this.id])
29374 return copies[this.id];
29376 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
29378 var members = this.members.map(function(member) {
29379 return _.extend({}, member, {id: resolver.entity(member.id).copy(resolver, copies).id});
29382 copy = copy.update({members: members});
29383 copies[this.id] = copy;
29388 extent: function(resolver, memo) {
29389 return resolver.transient(this, 'extent', function() {
29390 if (memo && memo[this.id]) return iD.geo.Extent();
29392 memo[this.id] = true;
29394 var extent = iD.geo.Extent();
29395 for (var i = 0; i < this.members.length; i++) {
29396 var member = resolver.hasEntity(this.members[i].id);
29398 extent._extend(member.extent(resolver, memo));
29405 geometry: function(graph) {
29406 return graph.transient(this, 'geometry', function() {
29407 return this.isMultipolygon() ? 'area' : 'relation';
29411 isDegenerate: function() {
29412 return this.members.length === 0;
29415 // Return an array of members, each extended with an 'index' property whose value
29416 // is the member index.
29417 indexedMembers: function() {
29418 var result = new Array(this.members.length);
29419 for (var i = 0; i < this.members.length; i++) {
29420 result[i] = _.extend({}, this.members[i], {index: i});
29425 // Return the first member with the given role. A copy of the member object
29426 // is returned, extended with an 'index' property whose value is the member index.
29427 memberByRole: function(role) {
29428 for (var i = 0; i < this.members.length; i++) {
29429 if (this.members[i].role === role) {
29430 return _.extend({}, this.members[i], {index: i});
29435 // Return the first member with the given id. A copy of the member object
29436 // is returned, extended with an 'index' property whose value is the member index.
29437 memberById: function(id) {
29438 for (var i = 0; i < this.members.length; i++) {
29439 if (this.members[i].id === id) {
29440 return _.extend({}, this.members[i], {index: i});
29445 // Return the first member with the given id and role. A copy of the member object
29446 // is returned, extended with an 'index' property whose value is the member index.
29447 memberByIdAndRole: function(id, role) {
29448 for (var i = 0; i < this.members.length; i++) {
29449 if (this.members[i].id === id && this.members[i].role === role) {
29450 return _.extend({}, this.members[i], {index: i});
29455 addMember: function(member, index) {
29456 var members = this.members.slice();
29457 members.splice(index === undefined ? members.length : index, 0, member);
29458 return this.update({members: members});
29461 updateMember: function(member, index) {
29462 var members = this.members.slice();
29463 members.splice(index, 1, _.extend({}, members[index], member));
29464 return this.update({members: members});
29467 removeMember: function(index) {
29468 var members = this.members.slice();
29469 members.splice(index, 1);
29470 return this.update({members: members});
29473 removeMembersWithID: function(id) {
29474 var members = _.reject(this.members, function(m) { return m.id === id; });
29475 return this.update({members: members});
29478 // Wherever a member appears with id `needle.id`, replace it with a member
29479 // with id `replacement.id`, type `replacement.type`, and the original role,
29480 // unless a member already exists with that id and role. Return an updated
29482 replaceMember: function(needle, replacement) {
29483 if (!this.memberById(needle.id))
29488 for (var i = 0; i < this.members.length; i++) {
29489 var member = this.members[i];
29490 if (member.id !== needle.id) {
29491 members.push(member);
29492 } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
29493 members.push({id: replacement.id, type: replacement.type, role: member.role});
29497 return this.update({members: members});
29500 asJXON: function(changeset_id) {
29503 '@id': this.osmId(),
29504 '@version': this.version || 0,
29505 member: _.map(this.members, function(member) {
29506 return { keyAttributes: { type: member.type, role: member.role, ref: iD.Entity.id.toOSM(member.id) } };
29508 tag: _.map(this.tags, function(v, k) {
29509 return { keyAttributes: { k: k, v: v } };
29513 if (changeset_id) r.relation['@changeset'] = changeset_id;
29517 asGeoJSON: function(resolver) {
29518 return resolver.transient(this, 'GeoJSON', function () {
29519 if (this.isMultipolygon()) {
29521 type: 'MultiPolygon',
29522 coordinates: this.multipolygon(resolver)
29526 type: 'FeatureCollection',
29527 properties: this.tags,
29528 features: this.members.map(function (member) {
29529 return _.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
29536 area: function(resolver) {
29537 return resolver.transient(this, 'area', function() {
29538 return d3.geo.area(this.asGeoJSON(resolver));
29542 isMultipolygon: function() {
29543 return this.tags.type === 'multipolygon';
29546 isComplete: function(resolver) {
29547 for (var i = 0; i < this.members.length; i++) {
29548 if (!resolver.hasEntity(this.members[i].id)) {
29555 isRestriction: function() {
29556 return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
29559 // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
29560 // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
29562 // This corresponds to the structure needed for rendering a multipolygon path using a
29563 // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
29565 // In the case of invalid geometries, this function will still return a result which
29566 // includes the nodes of all way members, but some Nds may be unclosed and some inner
29567 // rings not matched with the intended outer ring.
29569 multipolygon: function(resolver) {
29570 var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
29571 inners = this.members.filter(function(m) { return 'inner' === m.role; });
29573 outers = iD.geo.joinWays(outers, resolver);
29574 inners = iD.geo.joinWays(inners, resolver);
29576 outers = outers.map(function(outer) { return _.map(outer.nodes, 'loc'); });
29577 inners = inners.map(function(inner) { return _.map(inner.nodes, 'loc'); });
29579 var result = outers.map(function(o) {
29580 // Heuristic for detecting counterclockwise winding order. Assumes
29581 // that OpenStreetMap polygons are not hemisphere-spanning.
29582 return [d3.geo.area({type: 'Polygon', coordinates: [o]}) > 2 * Math.PI ? o.reverse() : o];
29585 function findOuter(inner) {
29588 for (o = 0; o < outers.length; o++) {
29590 if (iD.geo.polygonContainsPolygon(outer, inner))
29594 for (o = 0; o < outers.length; o++) {
29596 if (iD.geo.polygonIntersectsPolygon(outer, inner))
29601 for (var i = 0; i < inners.length; i++) {
29602 var inner = inners[i];
29604 if (d3.geo.area({type: 'Polygon', coordinates: [inner]}) < 2 * Math.PI) {
29605 inner = inner.reverse();
29608 var o = findOuter(inners[i]);
29609 if (o !== undefined)
29610 result[o].push(inners[i]);
29612 result.push([inners[i]]); // Invalid geometry
29620 'chair_lift': true,
29621 'mixed_lift': true,
29626 'magic_carpet': true,
29631 'motorway_link': true
29637 'piste:halfpipe': true
29661 iD.interestingTag = function (key) {
29662 return key !== 'attribution' &&
29663 key !== 'created_by' &&
29664 key !== 'source' &&
29666 key.indexOf('tiger:') !== 0;
29669 iD.Tree = function(head) {
29670 var rtree = rbush(),
29673 function entityRectangle(entity) {
29674 var rect = entity.extent(head).rectangle();
29675 rect.id = entity.id;
29676 rectangles[entity.id] = rect;
29680 function updateParents(entity, insertions, memo) {
29681 head.parentWays(entity).forEach(function(way) {
29682 if (rectangles[way.id]) {
29683 rtree.remove(rectangles[way.id]);
29684 insertions[way.id] = way;
29686 updateParents(way, insertions, memo);
29689 head.parentRelations(entity).forEach(function(relation) {
29690 if (memo[entity.id]) return;
29691 memo[entity.id] = true;
29692 if (rectangles[relation.id]) {
29693 rtree.remove(rectangles[relation.id]);
29694 insertions[relation.id] = relation;
29696 updateParents(relation, insertions, memo);
29702 tree.rebase = function(entities, force) {
29703 var insertions = {};
29705 for (var i = 0; i < entities.length; i++) {
29706 var entity = entities[i];
29708 if (!entity.visible)
29711 if (head.entities.hasOwnProperty(entity.id) || rectangles[entity.id]) {
29714 } else if (rectangles[entity.id]) {
29715 rtree.remove(rectangles[entity.id]);
29719 insertions[entity.id] = entity;
29720 updateParents(entity, insertions, {});
29723 rtree.load(_.map(insertions, entityRectangle));
29728 tree.intersects = function(extent, graph) {
29729 if (graph !== head) {
29730 var diff = iD.Difference(head, graph),
29735 diff.deleted().forEach(function(entity) {
29736 rtree.remove(rectangles[entity.id]);
29737 delete rectangles[entity.id];
29740 diff.modified().forEach(function(entity) {
29741 rtree.remove(rectangles[entity.id]);
29742 insertions[entity.id] = entity;
29743 updateParents(entity, insertions, {});
29746 diff.created().forEach(function(entity) {
29747 insertions[entity.id] = entity;
29750 rtree.load(_.map(insertions, entityRectangle));
29753 return rtree.search(extent.rectangle()).map(function(rect) {
29754 return head.entity(rect.id);
29760 iD.Way = iD.Entity.way = function iD_Way() {
29761 if (!(this instanceof iD_Way)) {
29762 return (new iD_Way()).initialize(arguments);
29763 } else if (arguments.length) {
29764 this.initialize(arguments);
29768 iD.Way.prototype = Object.create(iD.Entity.prototype);
29770 _.extend(iD.Way.prototype, {
29774 copy: function(resolver, copies) {
29775 if (copies[this.id])
29776 return copies[this.id];
29778 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
29780 var nodes = this.nodes.map(function(id) {
29781 return resolver.entity(id).copy(resolver, copies).id;
29784 copy = copy.update({nodes: nodes});
29785 copies[this.id] = copy;
29790 extent: function(resolver) {
29791 return resolver.transient(this, 'extent', function() {
29792 var extent = iD.geo.Extent();
29793 for (var i = 0; i < this.nodes.length; i++) {
29794 var node = resolver.hasEntity(this.nodes[i]);
29796 extent._extend(node.extent());
29803 first: function() {
29804 return this.nodes[0];
29808 return this.nodes[this.nodes.length - 1];
29811 contains: function(node) {
29812 return this.nodes.indexOf(node) >= 0;
29815 affix: function(node) {
29816 if (this.nodes[0] === node) return 'prefix';
29817 if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
29820 layer: function() {
29821 // explicit layer tag, clamp between -10, 10..
29822 if (this.tags.layer !== undefined) {
29823 return Math.max(-10, Math.min(+(this.tags.layer), 10));
29826 // implied layer tag..
29827 if (this.tags.location === 'overground') return 1;
29828 if (this.tags.location === 'underground') return -1;
29829 if (this.tags.location === 'underwater') return -10;
29831 if (this.tags.power === 'line') return 10;
29832 if (this.tags.power === 'minor_line') return 10;
29833 if (this.tags.aerialway) return 10;
29834 if (this.tags.bridge) return 1;
29835 if (this.tags.cutting) return -1;
29836 if (this.tags.tunnel) return -1;
29837 if (this.tags.waterway) return -1;
29838 if (this.tags.man_made === 'pipeline') return -10;
29839 if (this.tags.boundary) return -10;
29843 isOneWay: function() {
29844 // explicit oneway tag..
29845 if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
29846 if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
29848 // implied oneway tag..
29849 for (var key in this.tags) {
29850 if (key in iD.oneWayTags && (this.tags[key] in iD.oneWayTags[key]))
29856 isClosed: function() {
29857 return this.nodes.length > 0 && this.first() === this.last();
29860 isConvex: function(resolver) {
29861 if (!this.isClosed() || this.isDegenerate()) return null;
29863 var nodes = _.uniq(resolver.childNodes(this)),
29864 coords = _.map(nodes, 'loc'),
29865 curr = 0, prev = 0;
29867 for (var i = 0; i < coords.length; i++) {
29868 var o = coords[(i+1) % coords.length],
29870 b = coords[(i+2) % coords.length],
29871 res = iD.geo.cross(o, a, b);
29873 curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
29876 } else if (prev && curr !== prev) {
29884 isArea: function() {
29885 if (this.tags.area === 'yes')
29887 if (!this.isClosed() || this.tags.area === 'no')
29889 for (var key in this.tags)
29890 if (key in iD.areaKeys && !(this.tags[key] in iD.areaKeys[key]))
29895 isDegenerate: function() {
29896 return _.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
29899 areAdjacent: function(n1, n2) {
29900 for (var i = 0; i < this.nodes.length; i++) {
29901 if (this.nodes[i] === n1) {
29902 if (this.nodes[i - 1] === n2) return true;
29903 if (this.nodes[i + 1] === n2) return true;
29909 geometry: function(graph) {
29910 return graph.transient(this, 'geometry', function() {
29911 return this.isArea() ? 'area' : 'line';
29915 addNode: function(id, index) {
29916 var nodes = this.nodes.slice();
29917 nodes.splice(index === undefined ? nodes.length : index, 0, id);
29918 return this.update({nodes: nodes});
29921 updateNode: function(id, index) {
29922 var nodes = this.nodes.slice();
29923 nodes.splice(index, 1, id);
29924 return this.update({nodes: nodes});
29927 replaceNode: function(needle, replacement) {
29928 if (this.nodes.indexOf(needle) < 0)
29931 var nodes = this.nodes.slice();
29932 for (var i = 0; i < nodes.length; i++) {
29933 if (nodes[i] === needle) {
29934 nodes[i] = replacement;
29937 return this.update({nodes: nodes});
29940 removeNode: function(id) {
29943 for (var i = 0; i < this.nodes.length; i++) {
29944 var node = this.nodes[i];
29945 if (node !== id && nodes[nodes.length - 1] !== node) {
29950 // Preserve circularity
29951 if (this.nodes.length > 1 && this.first() === id && this.last() === id && nodes[nodes.length - 1] !== nodes[0]) {
29952 nodes.push(nodes[0]);
29955 return this.update({nodes: nodes});
29958 asJXON: function(changeset_id) {
29961 '@id': this.osmId(),
29962 '@version': this.version || 0,
29963 nd: _.map(this.nodes, function(id) {
29964 return { keyAttributes: { ref: iD.Entity.id.toOSM(id) } };
29966 tag: _.map(this.tags, function(v, k) {
29967 return { keyAttributes: { k: k, v: v } };
29971 if (changeset_id) r.way['@changeset'] = changeset_id;
29975 asGeoJSON: function(resolver) {
29976 return resolver.transient(this, 'GeoJSON', function() {
29977 var coordinates = _.map(resolver.childNodes(this), 'loc');
29978 if (this.isArea() && this.isClosed()) {
29981 coordinates: [coordinates]
29985 type: 'LineString',
29986 coordinates: coordinates
29992 area: function(resolver) {
29993 return resolver.transient(this, 'area', function() {
29994 var nodes = resolver.childNodes(this);
29998 coordinates: [_.map(nodes, 'loc')]
30001 if (!this.isClosed() && nodes.length) {
30002 json.coordinates[0].push(nodes[0].loc);
30005 var area = d3.geo.area(json);
30007 // Heuristic for detecting counterclockwise winding order. Assumes
30008 // that OpenStreetMap polygons are not hemisphere-spanning.
30009 if (area > 2 * Math.PI) {
30010 json.coordinates[0] = json.coordinates[0].reverse();
30011 area = d3.geo.area(json);
30014 return isNaN(area) ? 0 : area;
30018 iD.Background = function(context) {
30019 var dispatch = d3.dispatch('change'),
30020 baseLayer = iD.TileLayer(context).projection(context.projection),
30021 overlayLayers = [],
30025 function findSource(id) {
30026 return _.find(backgroundSources, function(d) {
30027 return d.id && d.id === id;
30032 function background(selection) {
30033 var base = selection.selectAll('.layer-background')
30037 .insert('div', '.layer-data')
30038 .attr('class', 'layer layer-background');
30040 base.call(baseLayer);
30042 var overlays = selection.selectAll('.layer-overlay')
30043 .data(overlayLayers, function(d) { return d.source().name(); });
30046 .insert('div', '.layer-data')
30047 .attr('class', 'layer layer-overlay');
30049 overlays.each(function(layer) {
30050 d3.select(this).call(layer);
30058 background.updateImagery = function() {
30059 var b = background.baseLayerSource(),
30060 o = overlayLayers.map(function (d) { return d.source().id; }).join(','),
30061 meters = iD.geo.offsetToMeters(b.offset()),
30063 x = +meters[0].toFixed(2),
30064 y = +meters[1].toFixed(2),
30065 q = iD.util.stringQs(location.hash.substring(1));
30068 if (id === 'custom') {
30069 id = 'custom:' + b.template;
30075 delete q.background;
30084 if (Math.abs(x) > epsilon || Math.abs(y) > epsilon) {
30085 q.offset = x + ',' + y;
30090 location.replace('#' + iD.util.qsString(q, true));
30092 var imageryUsed = [b.imageryUsed()];
30094 overlayLayers.forEach(function (d) {
30095 var source = d.source();
30096 if (!source.isLocatorOverlay()) {
30097 imageryUsed.push(source.imageryUsed());
30101 var gpx = context.layers().layer('gpx');
30102 if (gpx && gpx.enabled() && gpx.hasGpx()) {
30103 imageryUsed.push('Local GPX');
30106 var mapillary_images = context.layers().layer('mapillary-images');
30107 if (mapillary_images && mapillary_images.enabled()) {
30108 imageryUsed.push('Mapillary Images');
30111 var mapillary_signs = context.layers().layer('mapillary-signs');
30112 if (mapillary_signs && mapillary_signs.enabled()) {
30113 imageryUsed.push('Mapillary Signs');
30116 context.history().imageryUsed(imageryUsed);
30119 background.sources = function(extent) {
30120 return backgroundSources.filter(function(source) {
30121 return source.intersects(extent);
30125 background.dimensions = function(_) {
30126 baseLayer.dimensions(_);
30128 overlayLayers.forEach(function(layer) {
30129 layer.dimensions(_);
30133 background.baseLayerSource = function(d) {
30134 if (!arguments.length) return baseLayer.source();
30135 baseLayer.source(d);
30137 background.updateImagery();
30141 background.bing = function() {
30142 background.baseLayerSource(findSource('Bing'));
30145 background.showsLayer = function(d) {
30146 return d === baseLayer.source() ||
30147 (d.id === 'custom' && baseLayer.source().id === 'custom') ||
30148 overlayLayers.some(function(l) { return l.source() === d; });
30151 background.overlayLayerSources = function() {
30152 return overlayLayers.map(function (l) { return l.source(); });
30155 background.toggleOverlayLayer = function(d) {
30158 for (var i = 0; i < overlayLayers.length; i++) {
30159 layer = overlayLayers[i];
30160 if (layer.source() === d) {
30161 overlayLayers.splice(i, 1);
30163 background.updateImagery();
30168 layer = iD.TileLayer(context)
30170 .projection(context.projection)
30171 .dimensions(baseLayer.dimensions());
30173 overlayLayers.push(layer);
30175 background.updateImagery();
30178 background.nudge = function(d, zoom) {
30179 baseLayer.source().nudge(d, zoom);
30181 background.updateImagery();
30185 background.offset = function(d) {
30186 if (!arguments.length) return baseLayer.source().offset();
30187 baseLayer.source().offset(d);
30189 background.updateImagery();
30193 background.load = function(imagery) {
30194 function parseMap(qmap) {
30195 if (!qmap) return false;
30196 var args = qmap.split('/').map(Number);
30197 if (args.length < 3 || args.some(isNaN)) return false;
30198 return iD.geo.Extent([args[1], args[2]]);
30201 var q = iD.util.stringQs(location.hash.substring(1)),
30202 chosen = q.background || q.layer,
30203 extent = parseMap(q.map),
30206 backgroundSources = imagery.map(function(source) {
30207 if (source.type === 'bing') {
30208 return iD.BackgroundSource.Bing(source, dispatch);
30210 return iD.BackgroundSource(source);
30214 backgroundSources.unshift(iD.BackgroundSource.None());
30216 if (!chosen && extent) {
30217 best = _.find(this.sources(extent), function(s) { return s.best(); });
30220 if (chosen && chosen.indexOf('custom:') === 0) {
30221 background.baseLayerSource(iD.BackgroundSource.Custom(chosen.replace(/^custom:/, '')));
30223 background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
30226 var locator = _.find(backgroundSources, function(d) {
30227 return d.overlay && d.default;
30231 background.toggleOverlayLayer(locator);
30234 var overlays = (q.overlays || '').split(',');
30235 overlays.forEach(function(overlay) {
30236 overlay = findSource(overlay);
30238 background.toggleOverlayLayer(overlay);
30243 var gpx = context.layers().layer('gpx');
30250 var offset = q.offset.replace(/;/g, ',').split(',').map(function(n) {
30251 return !isNaN(n) && n;
30254 if (offset.length === 2) {
30255 background.offset(iD.geo.metersToOffset(offset));
30260 return d3.rebind(background, dispatch, 'on');
30262 iD.BackgroundSource = function(data) {
30263 var source = _.clone(data),
30265 name = source.name,
30266 best = !!source.best;
30268 source.scaleExtent = data.scaleExtent || [0, 20];
30269 source.overzoom = data.overzoom !== false;
30271 source.offset = function(_) {
30272 if (!arguments.length) return offset;
30277 source.nudge = function(_, zoomlevel) {
30278 offset[0] += _[0] / Math.pow(2, zoomlevel);
30279 offset[1] += _[1] / Math.pow(2, zoomlevel);
30283 source.name = function() {
30287 source.best = function() {
30291 source.area = function() {
30292 if (!data.polygon) return Number.MAX_VALUE; // worldwide
30293 var area = d3.geo.area({ type: 'MultiPolygon', coordinates: [ data.polygon ] });
30294 return isNaN(area) ? 0 : area;
30297 source.imageryUsed = function() {
30298 return source.id || name;
30301 source.url = function(coord) {
30302 return data.template
30303 .replace('{x}', coord[0])
30304 .replace('{y}', coord[1])
30305 // TMS-flipped y coordinate
30306 .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
30307 .replace(/\{z(oom)?\}/, coord[2])
30308 .replace(/\{switch:([^}]+)\}/, function(s, r) {
30309 var subdomains = r.split(',');
30310 return subdomains[(coord[0] + coord[1]) % subdomains.length];
30312 .replace('{u}', function() {
30314 for (var zoom = coord[2]; zoom > 0; zoom--) {
30316 var mask = 1 << (zoom - 1);
30317 if ((coord[0] & mask) !== 0) b++;
30318 if ((coord[1] & mask) !== 0) b += 2;
30325 source.intersects = function(extent) {
30326 extent = extent.polygon();
30327 return !data.polygon || data.polygon.some(function(polygon) {
30328 return iD.geo.polygonIntersectsPolygon(polygon, extent, true);
30332 source.validZoom = function(z) {
30333 return source.scaleExtent[0] <= z &&
30334 (source.overzoom || source.scaleExtent[1] > z);
30337 source.isLocatorOverlay = function() {
30338 return name === 'Locator Overlay';
30341 source.copyrightNotices = function() {};
30346 iD.BackgroundSource.Bing = function(data, dispatch) {
30347 // http://msdn.microsoft.com/en-us/library/ff701716.aspx
30348 // http://msdn.microsoft.com/en-us/library/ff701701.aspx
30350 data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
30352 var bing = iD.BackgroundSource(data),
30353 key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
30354 url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
30355 key + '&jsonp={callback}',
30358 d3.jsonp(url, function(json) {
30359 providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
30361 attribution: provider.attribution,
30362 areas: provider.coverageAreas.map(function(area) {
30364 zoom: [area.zoomMin, area.zoomMax],
30365 extent: iD.geo.Extent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
30373 bing.copyrightNotices = function(zoom, extent) {
30374 zoom = Math.min(zoom, 21);
30375 return providers.filter(function(provider) {
30376 return _.some(provider.areas, function(area) {
30377 return extent.intersects(area.extent) &&
30378 area.zoom[0] <= zoom &&
30379 area.zoom[1] >= zoom;
30381 }).map(function(provider) {
30382 return provider.attribution;
30386 bing.logo = 'bing_maps.png';
30387 bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
30392 iD.BackgroundSource.None = function() {
30393 var source = iD.BackgroundSource({id: 'none', template: ''});
30395 source.name = function() {
30396 return t('background.none');
30399 source.imageryUsed = function() {
30403 source.area = function() {
30410 iD.BackgroundSource.Custom = function(template) {
30411 var source = iD.BackgroundSource({id: 'custom', template: template});
30413 source.name = function() {
30414 return t('background.custom');
30417 source.imageryUsed = function() {
30418 return 'Custom (' + template + ')';
30421 source.area = function() {
30427 iD.Features = function(context) {
30428 var traffic_roads = {
30430 'motorway_link': true,
30432 'trunk_link': true,
30434 'primary_link': true,
30436 'secondary_link': true,
30438 'tertiary_link': true,
30439 'residential': true,
30440 'unclassified': true,
30441 'living_street': true
30444 var service_roads = {
30456 'pedestrian': true,
30460 var past_futures = {
30462 'construction': true,
30464 'dismantled': true,
30467 'demolished': true,
30468 'obliterated': true
30471 var dispatch = d3.dispatch('change', 'redraw'),
30479 function update() {
30480 _hidden = features.hidden();
30485 function defineFeature(k, filter, max) {
30489 enabled: true, // whether the user wants it enabled..
30491 currentMax: (max || Infinity),
30492 defaultMax: (max || Infinity),
30493 enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
30494 disable: function() { this.enabled = false; this.currentMax = 0; },
30495 hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
30496 autoHidden: function() { return this.hidden() && this.currentMax > 0; }
30501 defineFeature('points', function isPoint(entity, resolver, geometry) {
30502 return geometry === 'point';
30505 defineFeature('traffic_roads', function isTrafficRoad(entity) {
30506 return traffic_roads[entity.tags.highway];
30509 defineFeature('service_roads', function isServiceRoad(entity) {
30510 return service_roads[entity.tags.highway];
30513 defineFeature('paths', function isPath(entity) {
30514 return paths[entity.tags.highway];
30517 defineFeature('buildings', function isBuilding(entity) {
30519 !!entity.tags['building:part'] ||
30520 (!!entity.tags.building && entity.tags.building !== 'no') ||
30521 entity.tags.amenity === 'shelter' ||
30522 entity.tags.parking === 'multi-storey' ||
30523 entity.tags.parking === 'sheds' ||
30524 entity.tags.parking === 'carports' ||
30525 entity.tags.parking === 'garage_boxes'
30529 defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
30530 return geometry === 'area' &&
30531 !_features.buildings.filter(entity) &&
30532 !_features.water.filter(entity);
30535 defineFeature('boundaries', function isBoundary(entity) {
30536 return !!entity.tags.boundary;
30539 defineFeature('water', function isWater(entity) {
30541 !!entity.tags.waterway ||
30542 entity.tags.natural === 'water' ||
30543 entity.tags.natural === 'coastline' ||
30544 entity.tags.natural === 'bay' ||
30545 entity.tags.landuse === 'pond' ||
30546 entity.tags.landuse === 'basin' ||
30547 entity.tags.landuse === 'reservoir' ||
30548 entity.tags.landuse === 'salt_pond'
30552 defineFeature('rail', function isRail(entity) {
30554 !!entity.tags.railway ||
30555 entity.tags.landuse === 'railway'
30557 traffic_roads[entity.tags.highway] ||
30558 service_roads[entity.tags.highway] ||
30559 paths[entity.tags.highway]
30563 defineFeature('power', function isPower(entity) {
30564 return !!entity.tags.power;
30567 // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
30568 defineFeature('past_future', function isPastFuture(entity) {
30570 traffic_roads[entity.tags.highway] ||
30571 service_roads[entity.tags.highway] ||
30572 paths[entity.tags.highway]
30573 ) { return false; }
30575 var strings = Object.keys(entity.tags);
30577 for (var i = 0; i < strings.length; i++) {
30578 var s = strings[i];
30579 if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
30584 // Lines or areas that don't match another feature filter.
30585 // IMPORTANT: The 'others' feature must be the last one defined,
30586 // so that code in getMatches can skip this test if `hasMatch = true`
30587 defineFeature('others', function isOther(entity, resolver, geometry) {
30588 return (geometry === 'line' || geometry === 'area');
30592 function features() {}
30594 features.features = function() {
30598 features.keys = function() {
30602 features.enabled = function(k) {
30603 if (!arguments.length) {
30604 return _.filter(_keys, function(k) { return _features[k].enabled; });
30606 return _features[k] && _features[k].enabled;
30609 features.disabled = function(k) {
30610 if (!arguments.length) {
30611 return _.reject(_keys, function(k) { return _features[k].enabled; });
30613 return _features[k] && !_features[k].enabled;
30616 features.hidden = function(k) {
30617 if (!arguments.length) {
30618 return _.filter(_keys, function(k) { return _features[k].hidden(); });
30620 return _features[k] && _features[k].hidden();
30623 features.autoHidden = function(k) {
30624 if (!arguments.length) {
30625 return _.filter(_keys, function(k) { return _features[k].autoHidden(); });
30627 return _features[k] && _features[k].autoHidden();
30630 features.enable = function(k) {
30631 if (_features[k] && !_features[k].enabled) {
30632 _features[k].enable();
30637 features.disable = function(k) {
30638 if (_features[k] && _features[k].enabled) {
30639 _features[k].disable();
30644 features.toggle = function(k) {
30645 if (_features[k]) {
30646 (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
30651 features.resetStats = function() {
30652 _.each(_features, function(f) { f.count = 0; });
30656 features.gatherStats = function(d, resolver, dimensions) {
30657 var needsRedraw = false,
30658 type = _.groupBy(d, function(ent) { return ent.type; }),
30659 entities = [].concat(type.relation || [], type.way || [], type.node || []),
30660 currHidden, geometry, matches;
30662 _.each(_features, function(f) { f.count = 0; });
30664 // adjust the threshold for point/building culling based on viewport size..
30665 // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
30666 _cullFactor = dimensions[0] * dimensions[1] / 1000000;
30668 for (var i = 0; i < entities.length; i++) {
30669 geometry = entities[i].geometry(resolver);
30670 if (!(geometry === 'vertex' || geometry === 'relation')) {
30671 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
30672 for (var j = 0; j < matches.length; j++) {
30673 _features[matches[j]].count++;
30678 currHidden = features.hidden();
30679 if (currHidden !== _hidden) {
30680 _hidden = currHidden;
30681 needsRedraw = true;
30685 return needsRedraw;
30688 features.stats = function() {
30689 _.each(_keys, function(k) { _stats[k] = _features[k].count; });
30693 features.clear = function(d) {
30694 for (var i = 0; i < d.length; i++) {
30695 features.clearEntity(d[i]);
30699 features.clearEntity = function(entity) {
30700 delete _cache[iD.Entity.key(entity)];
30703 features.reset = function() {
30707 features.getMatches = function(entity, resolver, geometry) {
30708 if (geometry === 'vertex' || geometry === 'relation') return {};
30710 var ent = iD.Entity.key(entity);
30711 if (!_cache[ent]) {
30715 if (!_cache[ent].matches) {
30719 for (var i = 0; i < _keys.length; i++) {
30720 if (_keys[i] === 'others') {
30721 if (hasMatch) continue;
30723 // Multipolygon members:
30725 // 1. is a way that hasn't matched other "interesting" feature rules,
30726 // 2. and it belongs to a single parent multipolygon relation
30727 // ...then match whatever feature rules the parent multipolygon has matched.
30728 // see #2548, #2887
30731 // For this to work, getMatches must be called on relations before ways.
30733 if (entity.type === 'way') {
30734 var parents = features.getParents(entity, resolver, geometry);
30735 if (parents.length === 1 && parents[0].isMultipolygon()) {
30736 var pkey = iD.Entity.key(parents[0]);
30737 if (_cache[pkey] && _cache[pkey].matches) {
30738 matches = _.clone(_cache[pkey].matches);
30745 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
30746 matches[_keys[i]] = hasMatch = true;
30749 _cache[ent].matches = matches;
30752 return _cache[ent].matches;
30755 features.getParents = function(entity, resolver, geometry) {
30756 if (geometry === 'point') return [];
30758 var ent = iD.Entity.key(entity);
30759 if (!_cache[ent]) {
30763 if (!_cache[ent].parents) {
30765 if (geometry === 'vertex') {
30766 parents = resolver.parentWays(entity);
30767 } else { // 'line', 'area', 'relation'
30768 parents = resolver.parentRelations(entity);
30770 _cache[ent].parents = parents;
30772 return _cache[ent].parents;
30775 features.isHiddenFeature = function(entity, resolver, geometry) {
30776 if (!_hidden.length) return false;
30777 if (!entity.version) return false;
30779 var matches = features.getMatches(entity, resolver, geometry);
30781 for (var i = 0; i < _hidden.length; i++) {
30782 if (matches[_hidden[i]]) return true;
30787 features.isHiddenChild = function(entity, resolver, geometry) {
30788 if (!_hidden.length) return false;
30789 if (!entity.version || geometry === 'point') return false;
30791 var parents = features.getParents(entity, resolver, geometry);
30792 if (!parents.length) return false;
30794 for (var i = 0; i < parents.length; i++) {
30795 if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
30802 features.hasHiddenConnections = function(entity, resolver) {
30803 if (!_hidden.length) return false;
30804 var childNodes, connections;
30806 if (entity.type === 'midpoint') {
30807 childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
30810 childNodes = entity.nodes ? resolver.childNodes(entity) : [];
30811 connections = features.getParents(entity, resolver, entity.geometry(resolver));
30814 // gather ways connected to child nodes..
30815 connections = _.reduce(childNodes, function(result, e) {
30816 return resolver.isShared(e) ? _.union(result, resolver.parentWays(e)) : result;
30819 return connections.length ? _.some(connections, function(e) {
30820 return features.isHidden(e, resolver, e.geometry(resolver));
30824 features.isHidden = function(entity, resolver, geometry) {
30825 if (!_hidden.length) return false;
30826 if (!entity.version) return false;
30828 var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
30829 return fn(entity, resolver, geometry);
30832 features.filter = function(d, resolver) {
30833 if (!_hidden.length) return d;
30836 for (var i = 0; i < d.length; i++) {
30838 if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
30839 result.push(entity);
30845 return d3.rebind(features, dispatch, 'on');
30847 iD.Map = function(context) {
30848 var dimensions = [1, 1],
30849 dispatch = d3.dispatch('move', 'drawn'),
30850 projection = context.projection,
30851 zoom = d3.behavior.zoom()
30852 .translate(projection.translate())
30853 .scale(projection.scale() * 2 * Math.PI)
30854 .scaleExtent([1024, 256 * Math.pow(2, 24)])
30855 .on('zoom', zoomPan),
30856 dblclickEnabled = true,
30857 redrawEnabled = true,
30859 transformed = false,
30862 drawLayers = iD.svg.Layers(projection, context),
30863 drawPoints = iD.svg.Points(projection, context),
30864 drawVertices = iD.svg.Vertices(projection, context),
30865 drawLines = iD.svg.Lines(projection),
30866 drawAreas = iD.svg.Areas(projection),
30867 drawMidpoints = iD.svg.Midpoints(projection, context),
30868 drawLabels = iD.svg.Labels(projection, context),
30875 function map(selection) {
30877 .on('change.map', redraw);
30879 .on('change.map', redraw);
30880 context.background()
30881 .on('change.map', redraw);
30883 .on('redraw.map', redraw);
30885 .on('change.map', function() {
30886 context.background().updateImagery();
30891 .on('dblclick.map', dblClick)
30894 supersurface = selection.append('div')
30895 .attr('id', 'supersurface')
30896 .call(iD.util.setTransform, 0, 0);
30898 // Need a wrapper div because Opera can't cope with an absolutely positioned
30899 // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
30900 wrapper = supersurface
30902 .attr('class', 'layer layer-data');
30904 map.surface = surface = wrapper
30906 .selectAll('.surface')
30907 .attr('id', 'surface');
30910 .on('mousedown.zoom', function() {
30911 if (d3.event.button === 2) {
30912 d3.event.stopPropagation();
30915 .on('mouseup.zoom', function() {
30916 if (resetTransform()) redraw();
30918 .on('mousemove.map', function() {
30919 mousemove = d3.event;
30921 .on('mouseover.vertices', function() {
30922 if (map.editable() && !transformed) {
30923 var hover = d3.event.target.__data__;
30924 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
30925 dispatch.drawn({full: false});
30928 .on('mouseout.vertices', function() {
30929 if (map.editable() && !transformed) {
30930 var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__;
30931 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
30932 dispatch.drawn({full: false});
30938 .call(context.background());
30941 context.on('enter.map', function() {
30942 if (map.editable() && !transformed) {
30943 var all = context.intersects(map.extent()),
30944 filter = d3.functor(true),
30945 graph = context.graph();
30947 all = context.features().filter(all, graph);
30949 .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
30950 .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
30951 dispatch.drawn({full: false});
30955 map.dimensions(selection.dimensions());
30957 drawLabels.supersurface(supersurface);
30960 function pxCenter() {
30961 return [dimensions[0] / 2, dimensions[1] / 2];
30964 function drawVector(difference, extent) {
30965 var graph = context.graph(),
30966 features = context.features(),
30967 all = context.intersects(map.extent()),
30971 var complete = difference.complete(map.extent());
30972 data = _.compact(_.values(complete));
30973 filter = function(d) { return d.id in complete; };
30974 features.clear(data);
30977 // force a full redraw if gatherStats detects that a feature
30978 // should be auto-hidden (e.g. points or buildings)..
30979 if (features.gatherStats(all, graph, dimensions)) {
30980 extent = undefined;
30984 data = context.intersects(map.extent().intersection(extent));
30985 var set = d3.set(_.map(data, 'id'));
30986 filter = function(d) { return set.has(d.id); };
30990 filter = d3.functor(true);
30994 data = features.filter(data, graph);
30997 .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
30998 .call(drawLines, graph, data, filter)
30999 .call(drawAreas, graph, data, filter)
31000 .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
31001 .call(drawLabels, graph, data, filter, dimensions, !difference && !extent)
31002 .call(drawPoints, graph, data, filter);
31004 dispatch.drawn({full: true});
31007 function editOff() {
31008 context.features().resetStats();
31009 surface.selectAll('.layer-osm *').remove();
31010 dispatch.drawn({full: true});
31013 function dblClick() {
31014 if (!dblclickEnabled) {
31015 d3.event.preventDefault();
31016 d3.event.stopImmediatePropagation();
31020 function zoomPan() {
31021 if (Math.log(d3.event.scale) / Math.LN2 - 8 < minzoom) {
31022 surface.interrupt();
31023 iD.ui.flash(context.container())
31024 .select('.content')
31025 .text(t('cannot_zoom'));
31026 setZoom(context.minEditableZoom(), true);
31028 dispatch.move(map);
31033 .translate(d3.event.translate)
31034 .scale(d3.event.scale / (2 * Math.PI));
31036 var scale = d3.event.scale / transformStart[0],
31037 tX = (d3.event.translate[0] / scale - transformStart[1][0]) * scale,
31038 tY = (d3.event.translate[1] / scale - transformStart[1][1]) * scale;
31040 transformed = true;
31041 iD.util.setTransform(supersurface, tX, tY, scale);
31044 dispatch.move(map);
31047 function resetTransform() {
31048 if (!transformed) return false;
31050 surface.selectAll('.radial-menu').interrupt().remove();
31051 iD.util.setTransform(supersurface, 0, 0);
31052 transformed = false;
31056 function redraw(difference, extent) {
31057 if (!surface || !redrawEnabled) return;
31059 clearTimeout(timeoutId);
31061 // If we are in the middle of a zoom/pan, we can't do differenced redraws.
31062 // It would result in artifacts where differenced entities are redrawn with
31063 // one transform and unchanged entities with another.
31064 if (resetTransform()) {
31065 difference = extent = undefined;
31068 var zoom = String(~~map.zoom());
31069 if (surface.attr('data-zoom') !== zoom) {
31070 surface.attr('data-zoom', zoom)
31071 .classed('low-zoom', zoom <= 16);
31075 supersurface.call(context.background());
31079 if (map.editable()) {
31080 context.loadTiles(projection, dimensions);
31081 drawVector(difference, extent);
31090 projection.scale() * 2 * Math.PI,
31091 projection.translate().slice()];
31097 function queueRedraw() {
31098 timeoutId = setTimeout(function() { redraw(); }, 750);
31101 function pointLocation(p) {
31102 var translate = projection.translate(),
31103 scale = projection.scale() * 2 * Math.PI;
31104 return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
31107 function locationPoint(l) {
31108 var translate = projection.translate(),
31109 scale = projection.scale() * 2 * Math.PI;
31110 return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
31113 map.mouse = function() {
31114 var e = mousemove || d3.event, s;
31115 while ((s = e.sourceEvent)) e = s;
31119 map.mouseCoordinates = function() {
31120 return projection.invert(map.mouse());
31123 map.dblclickEnable = function(_) {
31124 if (!arguments.length) return dblclickEnabled;
31125 dblclickEnabled = _;
31129 map.redrawEnable = function(_) {
31130 if (!arguments.length) return redrawEnabled;
31135 function interpolateZoom(_) {
31136 var k = projection.scale(),
31137 t = projection.translate();
31139 surface.node().__chart__ = {
31146 projection.scale(k).translate(t); // undo setZoom projection changes
31148 zoom.event(surface.transition());
31151 function setZoom(_, force) {
31152 if (_ === map.zoom() && !force)
31154 var scale = 256 * Math.pow(2, _),
31155 center = pxCenter(),
31156 l = pointLocation(center);
31157 scale = Math.max(1024, Math.min(256 * Math.pow(2, 24), scale));
31158 projection.scale(scale / (2 * Math.PI));
31160 var t = projection.translate();
31161 l = locationPoint(l);
31162 t[0] += center[0] - l[0];
31163 t[1] += center[1] - l[1];
31164 projection.translate(t);
31165 zoom.translate(projection.translate());
31169 function setCenter(_) {
31170 var c = map.center();
31171 if (_[0] === c[0] && _[1] === c[1])
31173 var t = projection.translate(),
31175 ll = projection(_);
31176 projection.translate([
31177 t[0] - ll[0] + pxC[0],
31178 t[1] - ll[1] + pxC[1]]);
31179 zoom.translate(projection.translate());
31183 map.pan = function(d) {
31184 var t = projection.translate();
31187 projection.translate(t);
31188 zoom.translate(projection.translate());
31189 dispatch.move(map);
31193 map.dimensions = function(_) {
31194 if (!arguments.length) return dimensions;
31195 var center = map.center();
31197 drawLayers.dimensions(dimensions);
31198 context.background().dimensions(dimensions);
31199 projection.clipExtent([[0, 0], dimensions]);
31200 mouse = iD.util.fastMouse(supersurface.node());
31205 function zoomIn(integer) {
31206 interpolateZoom(~~map.zoom() + integer);
31209 function zoomOut(integer) {
31210 interpolateZoom(~~map.zoom() - integer);
31213 map.zoomIn = function() { zoomIn(1); };
31214 map.zoomInFurther = function() { zoomIn(4); };
31216 map.zoomOut = function() { zoomOut(1); };
31217 map.zoomOutFurther = function() { zoomOut(4); };
31219 map.center = function(loc) {
31220 if (!arguments.length) {
31221 return projection.invert(pxCenter());
31224 if (setCenter(loc)) {
31225 dispatch.move(map);
31231 map.zoom = function(z) {
31232 if (!arguments.length) {
31233 return Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8, 0);
31237 surface.interrupt();
31238 iD.ui.flash(context.container())
31239 .select('.content')
31240 .text(t('cannot_zoom'));
31241 z = context.minEditableZoom();
31245 dispatch.move(map);
31251 map.zoomTo = function(entity, zoomLimits) {
31252 var extent = entity.extent(context.graph());
31253 if (!isFinite(extent.area())) return;
31255 var zoom = map.trimmedExtentZoom(extent);
31256 zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
31257 map.centerZoom(extent.center(), Math.min(Math.max(zoom, zoomLimits[0]), zoomLimits[1]));
31260 map.centerZoom = function(loc, z) {
31261 var centered = setCenter(loc),
31262 zoomed = setZoom(z);
31264 if (centered || zoomed) {
31265 dispatch.move(map);
31271 map.centerEase = function(loc2, duration) {
31272 duration = duration || 250;
31274 surface.one('mousedown.ease', function() {
31282 var t1 = Date.now(),
31283 t2 = t1 + duration,
31284 loc1 = map.center(),
31285 ease = d3.ease('cubic-in-out');
31289 d3.timer(function() {
31290 if (!easing) return true; // cancelled ease
31292 var tNow = Date.now();
31298 var locNow = iD.geo.interp(loc1, loc2, ease((tNow - t1) / duration));
31302 scale: zoom.scale(),
31303 translate: zoom.translate()
31313 map.cancelEase = function() {
31319 map.extent = function(_) {
31320 if (!arguments.length) {
31321 return new iD.geo.Extent(projection.invert([0, dimensions[1]]),
31322 projection.invert([dimensions[0], 0]));
31324 var extent = iD.geo.Extent(_);
31325 map.centerZoom(extent.center(), map.extentZoom(extent));
31329 map.trimmedExtent = function(_) {
31330 if (!arguments.length) {
31331 var headerY = 60, footerY = 30, pad = 10;
31332 return new iD.geo.Extent(projection.invert([pad, dimensions[1] - footerY - pad]),
31333 projection.invert([dimensions[0] - pad, headerY + pad]));
31335 var extent = iD.geo.Extent(_);
31336 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
31340 function calcZoom(extent, dim) {
31341 var tl = projection([extent[0][0], extent[1][1]]),
31342 br = projection([extent[1][0], extent[0][1]]);
31344 // Calculate maximum zoom that fits extent
31345 var hFactor = (br[0] - tl[0]) / dim[0],
31346 vFactor = (br[1] - tl[1]) / dim[1],
31347 hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
31348 vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
31349 newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
31354 map.extentZoom = function(_) {
31355 return calcZoom(iD.geo.Extent(_), dimensions);
31358 map.trimmedExtentZoom = function(_) {
31359 var trimY = 120, trimX = 40,
31360 trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
31361 return calcZoom(iD.geo.Extent(_), trimmed);
31364 map.editable = function() {
31365 return map.zoom() >= context.minEditableZoom();
31368 map.minzoom = function(_) {
31369 if (!arguments.length) return minzoom;
31374 map.layers = drawLayers;
31376 return d3.rebind(map, dispatch, 'on');
31378 iD.TileLayer = function(context) {
31379 var tileSize = 256,
31380 tile = d3.geo.tile(),
31385 transformProp = iD.util.prefixCSSProperty('Transform'),
31386 source = d3.functor('');
31389 // blacklist overlay tiles around Null Island..
31390 function nearNullIsland(x, y, z) {
31392 var center = Math.pow(2, z - 1),
31393 width = Math.pow(2, z - 6),
31394 min = center - (width / 2),
31395 max = center + (width / 2) - 1;
31396 return x >= min && x <= max && y >= min && y <= max;
31401 function tileSizeAtZoom(d, z) {
31402 var epsilon = 0.002;
31403 return ((tileSize * Math.pow(2, z - d[2])) / tileSize) + epsilon;
31406 function atZoom(t, distance) {
31407 var power = Math.pow(2, distance);
31409 Math.floor(t[0] * power),
31410 Math.floor(t[1] * power),
31414 function lookUp(d) {
31415 for (var up = -1; up > -d[2]; up--) {
31416 var tile = atZoom(d, up);
31417 if (cache[source.url(tile)] !== false) {
31423 function uniqueBy(a, n) {
31424 var o = [], seen = {};
31425 for (var i = 0; i < a.length; i++) {
31426 if (seen[a[i][n]] === undefined) {
31428 seen[a[i][n]] = true;
31434 function addSource(d) {
31435 d.push(source.url(d));
31439 // Update tiles based on current state of `projection`.
31440 function background(selection) {
31441 tile.scale(projection.scale() * 2 * Math.PI)
31442 .translate(projection.translate());
31445 projection.scale() * Math.PI - projection.translate()[0],
31446 projection.scale() * Math.PI - projection.translate()[1]];
31448 z = Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
31453 // Derive the tiles onscreen, remove those offscreen and position them.
31454 // Important that this part not depend on `projection` because it's
31455 // rentered when tiles load/error (see #644).
31456 function render(selection) {
31458 var showDebug = context.getDebug('tile') && !source.overlay;
31460 if (source.validZoom(z)) {
31461 tile().forEach(function(d) {
31463 if (d[3] === '') return;
31464 if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
31466 if (cache[d[3]] === false && lookUp(d)) {
31467 requests.push(addSource(lookUp(d)));
31471 requests = uniqueBy(requests, 3).filter(function(r) {
31472 if (!!source.overlay && nearNullIsland(r[0], r[1], r[2])) {
31475 // don't re-request tiles which have failed in the past
31476 return cache[r[3]] !== false;
31480 var pixelOffset = [
31481 source.offset()[0] * Math.pow(2, z),
31482 source.offset()[1] * Math.pow(2, z)
31486 cache[d[3]] = true;
31490 .classed('tile-loaded', true);
31494 function error(d) {
31495 cache[d[3]] = false;
31503 function imageTransform(d) {
31504 var _ts = tileSize * Math.pow(2, z - d[2]);
31505 var scale = tileSizeAtZoom(d, z);
31506 return 'translate(' +
31507 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
31508 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
31509 'scale(' + scale + ',' + scale + ')';
31512 function debugTransform(d) {
31513 var _ts = tileSize * Math.pow(2, z - d[2]);
31514 var scale = tileSizeAtZoom(d, z);
31515 return 'translate(' +
31516 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0] + scale * (tileSize / 4)) + 'px,' +
31517 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1] + scale * (tileSize / 2)) + 'px)';
31520 var image = selection
31522 .data(requests, function(d) { return d[3]; });
31525 .style(transformProp, imageTransform)
31526 .classed('tile-removing', true)
31528 var tile = d3.select(this);
31529 window.setTimeout(function() {
31530 if (tile.classed('tile-removing')) {
31536 image.enter().append('img')
31537 .attr('class', 'tile')
31538 .attr('src', function(d) { return d[3]; })
31539 .on('error', error)
31543 .style(transformProp, imageTransform)
31544 .classed('tile-debug', showDebug)
31545 .classed('tile-removing', false);
31548 var debug = selection.selectAll('.tile-label-debug')
31549 .data(showDebug ? requests : [], function(d) { return d[3]; });
31556 .attr('class', 'tile-label-debug');
31559 .text(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; })
31560 .style(transformProp, debugTransform);
31563 background.projection = function(_) {
31564 if (!arguments.length) return projection;
31569 background.dimensions = function(_) {
31570 if (!arguments.length) return tile.size();
31575 background.source = function(_) {
31576 if (!arguments.length) return source;
31579 tile.scaleExtent(source.scaleExtent);
31586 PointTransform: function(projection) {
31587 return function(entity) {
31588 // http://jsperf.com/short-array-join
31589 var pt = projection(entity.loc);
31590 return 'translate(' + pt[0] + ',' + pt[1] + ')';
31594 Path: function(projection, graph, polygon) {
31596 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
31597 project = projection.stream,
31598 path = d3.geo.path()
31599 .projection({stream: function(output) { return polygon ? project(output) : project(clip(output)); }});
31601 return function(entity) {
31602 if (entity.id in cache) {
31603 return cache[entity.id];
31605 return cache[entity.id] = path(entity.asGeoJSON(graph));
31610 OneWaySegments: function(projection, graph, dt) {
31611 return function(entity) {
31617 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
31618 coordinates = graph.childNodes(entity).map(function(n) {
31622 if (entity.tags.oneway === '-1') coordinates.reverse();
31625 type: 'LineString',
31626 coordinates: coordinates
31627 }, projection.stream(clip({
31628 lineStart: function() {},
31629 lineEnd: function() {
31632 point: function(x, y) {
31636 var span = iD.geo.euclideanDistance(a, b) - offset;
31639 var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
31640 dx = dt * Math.cos(angle),
31641 dy = dt * Math.sin(angle),
31642 p = [a[0] + offset * Math.cos(angle),
31643 a[1] + offset * Math.sin(angle)];
31645 var segment = 'M' + a[0] + ',' + a[1] +
31646 'L' + p[0] + ',' + p[1];
31648 for (span -= dt; span >= 0; span -= dt) {
31651 segment += 'L' + p[0] + ',' + p[1];
31654 segment += 'L' + b[0] + ',' + b[1];
31655 segments.push({id: entity.id, index: i, d: segment});
31670 RelationMemberTags: function(graph) {
31671 return function(entity) {
31672 var tags = entity.tags;
31673 graph.parentRelations(entity).forEach(function(relation) {
31674 var type = relation.tags.type;
31675 if (type === 'multipolygon' || type === 'boundary') {
31676 tags = _.extend({}, relation.tags, tags);
31683 iD.svg.Areas = function(projection) {
31684 // Patterns only work in Firefox when set directly on element.
31685 // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
31687 wetland: 'wetland',
31690 construction: 'construction',
31691 military: 'construction',
31692 cemetery: 'cemetery',
31693 grave_yard: 'cemetery',
31696 farmland: 'farmland',
31700 var patternKeys = ['landuse', 'natural', 'amenity'];
31702 function setPattern(d) {
31703 for (var i = 0; i < patternKeys.length; i++) {
31704 if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
31705 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
31709 this.style.fill = this.style.stroke = '';
31712 return function drawAreas(surface, graph, entities, filter) {
31713 var path = iD.svg.Path(projection, graph, true),
31717 for (var i = 0; i < entities.length; i++) {
31718 var entity = entities[i];
31719 if (entity.geometry(graph) !== 'area') continue;
31721 multipolygon = iD.geo.isSimpleMultipolygonOuterMember(entity, graph);
31722 if (multipolygon) {
31723 areas[multipolygon.id] = {
31724 entity: multipolygon.mergeTags(entity.tags),
31725 area: Math.abs(entity.area(graph))
31727 } else if (!areas[entity.id]) {
31728 areas[entity.id] = {
31730 area: Math.abs(entity.area(graph))
31735 areas = d3.values(areas).filter(function hasPath(a) { return path(a.entity); });
31736 areas.sort(function areaSort(a, b) { return b.area - a.area; });
31737 areas = _.map(areas, 'entity');
31739 var strokes = areas.filter(function(area) {
31740 return area.type === 'way';
31750 var clipPaths = surface.selectAll('defs').selectAll('.clipPath')
31752 .data(data.clip, iD.Entity.key);
31755 .append('clipPath')
31756 .attr('class', 'clipPath')
31757 .attr('id', function(entity) { return entity.id + '-clippath'; })
31760 clipPaths.selectAll('path')
31766 var areagroup = surface
31767 .selectAll('.layer-areas')
31768 .selectAll('g.areagroup')
31769 .data(['fill', 'shadow', 'stroke']);
31773 .attr('class', function(d) { return 'layer areagroup area-' + d; });
31775 var paths = areagroup
31778 .data(function(layer) { return data[layer]; }, iD.Entity.key);
31780 // Remove exiting areas first, so they aren't included in the `fills`
31781 // array used for sorting below (https://github.com/openstreetmap/iD/issues/1903).
31785 var fills = surface.selectAll('.area-fill path.area')[0];
31787 var bisect = d3.bisector(function(node) {
31788 return -node.__data__.area(graph);
31791 function sortedByArea(entity) {
31792 if (this.__data__ === 'fill') {
31793 return fills[bisect(fills, -entity.area(graph))];
31798 .insert('path', sortedByArea)
31799 .each(function(entity) {
31800 var layer = this.parentNode.__data__;
31802 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
31804 if (layer === 'fill') {
31805 this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
31806 setPattern.apply(this, arguments);
31809 .call(iD.svg.TagClasses());
31815 iD.svg.Debug = function(projection, context) {
31817 function multipolygons(imagery) {
31818 return imagery.map(function(data) {
31820 type: 'MultiPolygon',
31821 coordinates: [ data.polygon ]
31826 function drawDebug(surface) {
31827 var showsTile = context.getDebug('tile'),
31828 showsCollision = context.getDebug('collision'),
31829 showsImagery = context.getDebug('imagery'),
31830 showsImperial = context.getDebug('imperial'),
31831 showsDriveLeft = context.getDebug('driveLeft'),
31832 path = d3.geo.path().projection(projection);
31835 var debugData = [];
31837 debugData.push({ class: 'red', label: 'tile' });
31839 if (showsCollision) {
31840 debugData.push({ class: 'yellow', label: 'collision' });
31842 if (showsImagery) {
31843 debugData.push({ class: 'orange', label: 'imagery' });
31845 if (showsImperial) {
31846 debugData.push({ class: 'cyan', label: 'imperial' });
31848 if (showsDriveLeft) {
31849 debugData.push({ class: 'green', label: 'driveLeft' });
31853 var legend = d3.select('#content')
31854 .selectAll('.debug-legend')
31855 .data(debugData.length ? [0] : []);
31859 .attr('class', 'fillD debug-legend');
31865 var legendItems = legend.selectAll('.debug-legend-item')
31866 .data(debugData, function(d) { return d.label; });
31868 legendItems.enter()
31870 .attr('class', function(d) { return 'debug-legend-item ' + d.class; })
31871 .text(function(d) { return d.label; });
31877 var layer = surface.selectAll('.layer-debug')
31878 .data(showsImagery || showsImperial || showsDriveLeft ? [0] : []);
31882 .attr('class', 'layer-debug');
31888 var extent = context.map().extent(),
31889 availableImagery = showsImagery && multipolygons(iD.data.imagery.filter(function(source) {
31890 if (!source.polygon) return false;
31891 return source.polygon.some(function(polygon) {
31892 return iD.geo.polygonIntersectsPolygon(polygon, extent, true);
31896 var imagery = layer.selectAll('path.debug-imagery')
31897 .data(showsImagery ? availableImagery : []);
31901 .attr('class', 'debug-imagery debug orange');
31907 var imperial = layer
31908 .selectAll('path.debug-imperial')
31909 .data(showsImperial ? [iD.data.imperial] : []);
31913 .attr('class', 'debug-imperial debug cyan');
31919 var driveLeft = layer
31920 .selectAll('path.debug-drive-left')
31921 .data(showsDriveLeft ? [iD.data.driveLeft] : []);
31925 .attr('class', 'debug-drive-left debug green');
31932 layer.selectAll('path')
31936 // This looks strange because `enabled` methods on other layers are
31937 // chainable getter/setters, and this one is just a getter.
31938 drawDebug.enabled = function() {
31939 if (!arguments.length) {
31940 return context.getDebug('tile') ||
31941 context.getDebug('collision') ||
31942 context.getDebug('imagery') ||
31943 context.getDebug('imperial') ||
31944 context.getDebug('driveLeft');
31953 A standalone SVG element that contains only a `defs` sub-element. To be
31954 used once globally, since defs IDs must be unique within a document.
31956 iD.svg.Defs = function(context) {
31958 function SVGSpriteDefinition(id, href) {
31959 return function(defs) {
31960 d3.xml(href, 'image/svg+xml', function(err, svg) {
31962 defs.node().appendChild(
31963 d3.select(svg.documentElement).attr('id', id).node()
31969 return function drawDefs(selection) {
31970 var defs = selection.append('defs');
31973 defs.append('marker')
31975 id: 'oneway-marker',
31976 viewBox: '0 0 10 10',
31981 markerUnits: 'strokeWidth',
31985 .attr('class', 'oneway')
31986 .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')
31987 .attr('stroke', 'none')
31988 .attr('fill', '#000')
31989 .attr('opacity', '0.5');
31992 var patterns = defs.selectAll('pattern')
31994 // pattern name, pattern image name
31995 ['wetland', 'wetland'],
31996 ['construction', 'construction'],
31997 ['cemetery', 'cemetery'],
31998 ['orchard', 'orchard'],
31999 ['farmland', 'farmland'],
32008 return 'pattern-' + d[0];
32012 patternUnits: 'userSpaceOnUse'
32015 patterns.append('rect')
32021 'class': function (d) {
32022 return 'pattern-color-' + d[0];
32026 patterns.append('image')
32033 .attr('xlink:href', function (d) {
32034 return context.imagePath('pattern/' + d[1] + '.png');
32039 .data([12, 18, 20, 32, 45])
32040 .enter().append('clipPath')
32041 .attr('id', function (d) {
32042 return 'clip-square-' + d;
32047 .attr('width', function (d) {
32050 .attr('height', function (d) {
32054 defs.call(SVGSpriteDefinition(
32056 context.imagePath('iD-sprite.svg')));
32058 defs.call(SVGSpriteDefinition(
32060 context.imagePath('maki-sprite.svg')));
32063 iD.svg.Gpx = function(projection, context, dispatch) {
32064 var showLabels = true,
32068 if (iD.svg.Gpx.initialized) return; // run once
32070 iD.svg.Gpx.geojson = {};
32071 iD.svg.Gpx.enabled = true;
32074 d3.event.stopPropagation();
32075 d3.event.preventDefault();
32076 d3.event.dataTransfer.dropEffect = 'copy';
32080 .attr('dropzone', 'copy')
32081 .on('drop.localgpx', function() {
32082 d3.event.stopPropagation();
32083 d3.event.preventDefault();
32084 if (!iD.detect().filedrop) return;
32085 drawGpx.files(d3.event.dataTransfer.files);
32087 .on('dragenter.localgpx', over)
32088 .on('dragexit.localgpx', over)
32089 .on('dragover.localgpx', over);
32091 iD.svg.Gpx.initialized = true;
32095 function drawGpx(surface) {
32096 var geojson = iD.svg.Gpx.geojson,
32097 enabled = iD.svg.Gpx.enabled;
32099 layer = surface.selectAll('.layer-gpx')
32100 .data(enabled ? [0] : []);
32104 .attr('class', 'layer-gpx');
32116 .attr('class', 'gpx');
32121 var path = d3.geo.path()
32122 .projection(projection);
32128 var labels = layer.selectAll('text')
32129 .data(showLabels && geojson.features ? geojson.features : []);
32133 .attr('class', 'gpx');
32139 .text(function(d) {
32140 return d.properties.desc || d.properties.name;
32142 .attr('x', function(d) {
32143 var centroid = path.centroid(d);
32144 return centroid[0] + 7;
32146 .attr('y', function(d) {
32147 var centroid = path.centroid(d);
32148 return centroid[1];
32153 function toDom(x) {
32154 return (new DOMParser()).parseFromString(x, 'text/xml');
32157 drawGpx.showLabels = function(_) {
32158 if (!arguments.length) return showLabels;
32163 drawGpx.enabled = function(_) {
32164 if (!arguments.length) return iD.svg.Gpx.enabled;
32165 iD.svg.Gpx.enabled = _;
32170 drawGpx.hasGpx = function() {
32171 var geojson = iD.svg.Gpx.geojson;
32172 return (!(_.isEmpty(geojson) || _.isEmpty(geojson.features)));
32175 drawGpx.geojson = function(gj) {
32176 if (!arguments.length) return iD.svg.Gpx.geojson;
32177 if (_.isEmpty(gj) || _.isEmpty(gj.features)) return this;
32178 iD.svg.Gpx.geojson = gj;
32183 drawGpx.url = function(url) {
32184 d3.text(url, function(err, data) {
32186 drawGpx.geojson(toGeoJSON.gpx(toDom(data)));
32192 drawGpx.files = function(fileList) {
32193 if (!fileList.length) return this;
32194 var f = fileList[0],
32195 reader = new FileReader();
32197 reader.onload = function(e) {
32198 drawGpx.geojson(toGeoJSON.gpx(toDom(e.target.result))).fitZoom();
32201 reader.readAsText(f);
32205 drawGpx.fitZoom = function() {
32206 if (!this.hasGpx()) return this;
32207 var geojson = iD.svg.Gpx.geojson;
32209 var map = context.map(),
32210 viewport = map.trimmedExtent().polygon(),
32211 coords = _.reduce(geojson.features, function(coords, feature) {
32212 var c = feature.geometry.coordinates;
32213 return _.union(coords, feature.geometry.type === 'Point' ? [c] : c);
32216 if (!iD.geo.polygonIntersectsPolygon(viewport, coords, true)) {
32217 var extent = iD.geo.Extent(d3.geo.bounds(geojson));
32218 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
32227 iD.svg.Icon = function(name, svgklass, useklass) {
32228 return function drawIcon(selection) {
32229 selection.selectAll('svg')
32233 .attr('class', 'icon ' + (svgklass || ''))
32235 .attr('xlink:href', name)
32236 .attr('class', useklass);
32239 iD.svg.Labels = function(projection, context) {
32240 var path = d3.geo.path().projection(projection);
32242 // Replace with dict and iterate over entities tags instead?
32243 var label_stack = [
32244 ['line', 'aeroway'],
32245 ['line', 'highway'],
32246 ['line', 'railway'],
32247 ['line', 'waterway'],
32248 ['area', 'aeroway'],
32249 ['area', 'amenity'],
32250 ['area', 'building'],
32251 ['area', 'historic'],
32252 ['area', 'leisure'],
32253 ['area', 'man_made'],
32254 ['area', 'natural'],
32256 ['area', 'tourism'],
32257 ['point', 'aeroway'],
32258 ['point', 'amenity'],
32259 ['point', 'building'],
32260 ['point', 'historic'],
32261 ['point', 'leisure'],
32262 ['point', 'man_made'],
32263 ['point', 'natural'],
32265 ['point', 'tourism'],
32271 var default_size = 12;
32273 var font_sizes = label_stack.map(function(d) {
32274 var style = iD.util.getStyle('text.' + d[0] + '.tag-' + d[1]),
32275 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
32276 if (m) return parseInt(m[1], 10);
32278 style = iD.util.getStyle('text.' + d[0]);
32279 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
32280 if (m) return parseInt(m[1], 10);
32282 return default_size;
32287 var pointOffsets = [
32288 [15, -11, 'start'], // right
32289 [10, -11, 'start'], // unused right now
32293 var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25,
32294 75, 20, 80, 15, 95, 10, 90, 5, 95];
32297 var noIcons = ['building', 'landuse', 'natural'];
32298 function blacklisted(preset) {
32299 return _.some(noIcons, function(s) {
32300 return preset.id.indexOf(s) >= 0;
32304 function get(array, prop) {
32305 return function(d, i) { return array[i][prop]; };
32308 var textWidthCache = {};
32310 function textWidth(text, size, elem) {
32311 var c = textWidthCache[size];
32312 if (!c) c = textWidthCache[size] = {};
32318 c[text] = elem.getComputedTextLength();
32322 var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
32323 if (str === null) {
32324 return size / 3 * 2 * text.length;
32326 return size / 3 * (2 * text.length + str.length);
32331 function drawLineLabels(group, entities, filter, classes, labels) {
32332 var texts = group.selectAll('text.' + classes)
32334 .data(entities, iD.Entity.key);
32338 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
32339 .append('textPath')
32340 .attr('class', 'textpath');
32343 texts.selectAll('.textpath')
32345 .data(entities, iD.Entity.key)
32347 'startOffset': '50%',
32348 'xlink:href': function(d) { return '#labelpath-' + d.id; }
32350 .text(iD.util.displayName);
32352 texts.exit().remove();
32355 function drawLinePaths(group, entities, filter, classes, labels) {
32356 var halos = group.selectAll('path')
32358 .data(entities, iD.Entity.key);
32362 .style('stroke-width', get(labels, 'font-size'))
32363 .attr('id', function(d) { return 'labelpath-' + d.id; })
32364 .attr('class', classes);
32366 halos.attr('d', get(labels, 'lineString'));
32368 halos.exit().remove();
32371 function drawPointLabels(group, entities, filter, classes, labels) {
32372 var texts = group.selectAll('text.' + classes)
32374 .data(entities, iD.Entity.key);
32378 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; });
32380 texts.attr('x', get(labels, 'x'))
32381 .attr('y', get(labels, 'y'))
32382 .style('text-anchor', get(labels, 'textAnchor'))
32383 .text(iD.util.displayName)
32384 .each(function(d, i) { textWidth(iD.util.displayName(d), labels[i].height, this); });
32386 texts.exit().remove();
32390 function drawAreaLabels(group, entities, filter, classes, labels) {
32391 entities = entities.filter(hasText);
32392 labels = labels.filter(hasText);
32393 return drawPointLabels(group, entities, filter, classes, labels);
32395 function hasText(d, i) {
32396 return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
32400 function drawAreaIcons(group, entities, filter, classes, labels) {
32401 var icons = group.selectAll('use')
32403 .data(entities, iD.Entity.key);
32407 .attr('class', 'icon areaicon')
32408 .attr('width', '18px')
32409 .attr('height', '18px');
32411 icons.attr('transform', get(labels, 'transform'))
32412 .attr('xlink:href', function(d) {
32413 var icon = context.presets().match(d, context.graph()).icon;
32414 return '#' + icon + (icon === 'hairdresser' ? '-24': '-18'); // workaround: maki hairdresser-18 broken?
32418 icons.exit().remove();
32421 function reverse(p) {
32422 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
32423 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
32426 function lineString(nodes) {
32427 return 'M' + nodes.join('L');
32430 function subpath(nodes, from, to) {
32431 function segmentLength(i) {
32432 var dx = nodes[i][0] - nodes[i + 1][0];
32433 var dy = nodes[i][1] - nodes[i + 1][1];
32434 return Math.sqrt(dx * dx + dy * dy);
32438 start, end, i0, i1;
32439 for (var i = 0; i < nodes.length - 1; i++) {
32440 var current = segmentLength(i);
32442 if (!start && sofar + current >= from) {
32443 portion = (from - sofar) / current;
32445 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
32446 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
32450 if (!end && sofar + current >= to) {
32451 portion = (to - sofar) / current;
32453 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
32454 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
32461 var ret = nodes.slice(i0, i1);
32462 ret.unshift(start);
32468 function hideOnMouseover() {
32469 var layers = d3.select(this)
32470 .selectAll('.layer-label, .layer-halo');
32472 layers.selectAll('.proximate')
32473 .classed('proximate', false);
32475 var mouse = context.mouse(),
32477 rect = [mouse[0] - pad, mouse[1] - pad, mouse[0] + pad, mouse[1] + pad],
32478 ids = _.map(rtree.search(rect), 'id');
32480 if (!ids.length) return;
32481 layers.selectAll('.' + ids.join(', .'))
32482 .classed('proximate', true);
32485 var rtree = rbush(),
32488 function drawLabels(surface, graph, entities, filter, dimensions, fullRedraw) {
32489 var hidePoints = !surface.selectAll('.node.point').node();
32491 var labelable = [], i, k, entity;
32492 for (i = 0; i < label_stack.length; i++) labelable.push([]);
32498 for (i = 0; i < entities.length; i++) {
32499 rtree.remove(rectangles[entities[i].id]);
32503 // Split entities into groups specified by label_stack
32504 for (i = 0; i < entities.length; i++) {
32505 entity = entities[i];
32506 var geometry = entity.geometry(graph);
32508 if (geometry === 'vertex')
32510 if (hidePoints && geometry === 'point')
32513 var preset = geometry === 'area' && context.presets().match(entity, graph),
32514 icon = preset && !blacklisted(preset) && preset.icon;
32516 if (!icon && !iD.util.displayName(entity))
32519 for (k = 0; k < label_stack.length; k++) {
32520 if (geometry === label_stack[k][0] && entity.tags[label_stack[k][1]]) {
32521 labelable[k].push(entity);
32539 // Try and find a valid label for labellable entities
32540 for (k = 0; k < labelable.length; k++) {
32541 var font_size = font_sizes[k];
32542 for (i = 0; i < labelable[k].length; i++) {
32543 entity = labelable[k][i];
32544 var name = iD.util.displayName(entity),
32545 width = name && textWidth(name, font_size),
32547 if (entity.geometry(graph) === 'point') {
32548 p = getPointLabel(entity, width, font_size);
32549 } else if (entity.geometry(graph) === 'line') {
32550 p = getLineLabel(entity, width, font_size);
32551 } else if (entity.geometry(graph) === 'area') {
32552 p = getAreaLabel(entity, width, font_size);
32555 p.classes = entity.geometry(graph) + ' tag-' + label_stack[k][1];
32556 positions[entity.geometry(graph)].push(p);
32557 labelled[entity.geometry(graph)].push(entity);
32562 function getPointLabel(entity, width, height) {
32563 var coord = projection(entity.loc),
32565 offset = pointOffsets[0],
32569 x: coord[0] + offset[0],
32570 y: coord[1] + offset[1],
32571 textAnchor: offset[2]
32573 var rect = [p.x - m, p.y - m, p.x + width + m, p.y + height + m];
32574 if (tryInsert(rect, entity.id)) return p;
32578 function getLineLabel(entity, width, height) {
32579 var nodes = _.map(graph.childNodes(entity), 'loc').map(projection),
32580 length = iD.geo.pathLength(nodes);
32581 if (length < width + 20) return;
32583 for (var i = 0; i < lineOffsets.length; i++) {
32584 var offset = lineOffsets[i],
32585 middle = offset / 100 * length,
32586 start = middle - width/2;
32587 if (start < 0 || start + width > length) continue;
32588 var sub = subpath(nodes, start, start + width),
32589 rev = reverse(sub),
32591 Math.min(sub[0][0], sub[sub.length - 1][0]) - 10,
32592 Math.min(sub[0][1], sub[sub.length - 1][1]) - 10,
32593 Math.max(sub[0][0], sub[sub.length - 1][0]) + 20,
32594 Math.max(sub[0][1], sub[sub.length - 1][1]) + 30
32596 if (rev) sub = sub.reverse();
32597 if (tryInsert(rect, entity.id)) return {
32598 'font-size': height + 2,
32599 lineString: lineString(sub),
32600 startOffset: offset + '%'
32605 function getAreaLabel(entity, width, height) {
32606 var centroid = path.centroid(entity.asGeoJSON(graph, true)),
32607 extent = entity.extent(graph),
32608 entitywidth = projection(extent[1])[0] - projection(extent[0])[0],
32611 if (isNaN(centroid[0]) || entitywidth < 20) return;
32613 var iconX = centroid[0] - (iconSize/2),
32614 iconY = centroid[1] - (iconSize/2),
32615 textOffset = iconSize + 5;
32618 transform: 'translate(' + iconX + ',' + iconY + ')'
32621 if (width && entitywidth >= width + 20) {
32623 p.y = centroid[1] + textOffset;
32624 p.textAnchor = 'middle';
32626 rect = [p.x - width/2, p.y, p.x + width/2, p.y + height + textOffset];
32628 rect = [iconX, iconY, iconX + iconSize, iconY + iconSize];
32631 if (tryInsert(rect, entity.id)) return p;
32635 function tryInsert(rect, id) {
32636 // Check that label is visible
32637 if (rect[0] < 0 || rect[1] < 0 || rect[2] > dimensions[0] ||
32638 rect[3] > dimensions[1]) return false;
32639 var v = rtree.search(rect).length === 0;
32642 rtree.insert(rect);
32643 rectangles[id] = rect;
32648 var label = surface.selectAll('.layer-label'),
32649 halo = surface.selectAll('.layer-halo');
32652 drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
32653 drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
32656 drawLinePaths(halo, labelled.line, filter, '', positions.line);
32657 drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
32658 drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
32661 drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
32662 drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
32663 drawAreaIcons(label, labelled.area, filter, 'arealabel-icon', positions.area);
32666 var showDebug = context.getDebug('collision');
32667 var debug = label.selectAll('.layer-label-debug')
32668 .data(showDebug ? [true] : []);
32672 .attr('class', 'layer-label-debug');
32678 var gj = rtree.all().map(function(d) {
32679 return { type: 'Polygon', coordinates: [[
32688 var debugboxes = debug.selectAll('.debug').data(gj);
32692 .attr('class', 'debug yellow');
32698 .attr('d', d3.geo.path().projection(null));
32702 drawLabels.supersurface = function(supersurface) {
32704 .on('mousemove.hidelabels', hideOnMouseover)
32705 .on('mousedown.hidelabels', function () {
32706 supersurface.on('mousemove.hidelabels', null);
32708 .on('mouseup.hidelabels', function () {
32709 supersurface.on('mousemove.hidelabels', hideOnMouseover);
32715 iD.svg.Layers = function(projection, context) {
32716 var dispatch = d3.dispatch('change'),
32717 svg = d3.select(null),
32719 { id: 'osm', layer: iD.svg.Osm(projection, context, dispatch) },
32720 { id: 'gpx', layer: iD.svg.Gpx(projection, context, dispatch) },
32721 { id: 'mapillary-images', layer: iD.svg.MapillaryImages(projection, context, dispatch) },
32722 { id: 'mapillary-signs', layer: iD.svg.MapillarySigns(projection, context, dispatch) },
32723 { id: 'debug', layer: iD.svg.Debug(projection, context, dispatch) }
32727 function drawLayers(selection) {
32728 svg = selection.selectAll('.surface')
32733 .attr('class', 'surface')
32736 var groups = svg.selectAll('.data-layer')
32741 .attr('class', function(d) { return 'data-layer data-layer-' + d.id; });
32744 .each(function(d) { d3.select(this).call(d.layer); });
32750 drawLayers.all = function() {
32754 drawLayers.layer = function(id) {
32755 var obj = _.find(layers, function(o) {return o.id === id;});
32756 return obj && obj.layer;
32759 drawLayers.only = function(what) {
32760 var arr = [].concat(what);
32761 drawLayers.remove(_.difference(_.map(layers, 'id'), arr));
32765 drawLayers.remove = function(what) {
32766 var arr = [].concat(what);
32767 arr.forEach(function(id) {
32768 layers = _.reject(layers, function(o) {return o.id === id;});
32774 drawLayers.add = function(what) {
32775 var arr = [].concat(what);
32776 arr.forEach(function(obj) {
32777 if ('id' in obj && 'layer' in obj) {
32785 drawLayers.dimensions = function(_) {
32786 if (!arguments.length) return svg.dimensions();
32788 layers.forEach(function(obj) {
32789 if (obj.layer.dimensions) {
32790 obj.layer.dimensions(_);
32797 return d3.rebind(drawLayers, dispatch, 'on');
32799 iD.svg.Lines = function(projection) {
32801 var highway_stack = {
32816 function waystack(a, b) {
32817 var as = 0, bs = 0;
32819 if (a.tags.highway) { as -= highway_stack[a.tags.highway]; }
32820 if (b.tags.highway) { bs -= highway_stack[b.tags.highway]; }
32824 return function drawLines(surface, graph, entities, filter) {
32825 var ways = [], pathdata = {}, onewaydata = {},
32826 getPath = iD.svg.Path(projection, graph);
32828 for (var i = 0; i < entities.length; i++) {
32829 var entity = entities[i],
32830 outer = iD.geo.simpleMultipolygonOuterMember(entity, graph);
32832 ways.push(entity.mergeTags(outer.tags));
32833 } else if (entity.geometry(graph) === 'line') {
32838 ways = ways.filter(getPath);
32840 pathdata = _.groupBy(ways, function(way) { return way.layer(); });
32842 _.forOwn(pathdata, function(v, k) {
32843 onewaydata[k] = _(v)
32844 .filter(function(d) { return d.isOneWay(); })
32845 .map(iD.svg.OneWaySegments(projection, graph, 35))
32850 var layergroup = surface
32851 .selectAll('.layer-lines')
32852 .selectAll('g.layergroup')
32853 .data(d3.range(-10, 11));
32857 .attr('class', function(d) { return 'layer layergroup layer' + String(d); });
32860 var linegroup = layergroup
32861 .selectAll('g.linegroup')
32862 .data(['shadow', 'casing', 'stroke']);
32866 .attr('class', function(d) { return 'layer linegroup line-' + d; });
32869 var lines = linegroup
32873 function() { return pathdata[this.parentNode.parentNode.__data__] || []; },
32877 // Optimization: call simple TagClasses only on enter selection. This
32878 // works because iD.Entity.key is defined to include the entity v attribute.
32881 .attr('class', function(d) { return 'way line ' + this.parentNode.__data__ + ' ' + d.id; })
32882 .call(iD.svg.TagClasses());
32886 .attr('d', getPath)
32887 .call(iD.svg.TagClasses().tags(iD.svg.RelationMemberTags(graph)));
32893 var onewaygroup = layergroup
32894 .selectAll('g.onewaygroup')
32897 onewaygroup.enter()
32899 .attr('class', 'layer onewaygroup');
32902 var oneways = onewaygroup
32906 function() { return onewaydata[this.parentNode.parentNode.__data__] || []; },
32907 function(d) { return [d.id, d.index]; }
32912 .attr('class', 'oneway')
32913 .attr('marker-mid', 'url(#oneway-marker)');
32916 .attr('d', function(d) { return d.d; });
32918 if (iD.detect().ie) {
32919 oneways.each(function() { this.parentNode.insertBefore(this, this); });
32927 iD.svg.MapillaryImages = function(projection, context, dispatch) {
32928 var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000),
32930 layer = d3.select(null),
32935 if (iD.svg.MapillaryImages.initialized) return; // run once
32936 iD.svg.MapillaryImages.enabled = false;
32937 iD.svg.MapillaryImages.initialized = true;
32940 function getMapillary() {
32941 if (iD.services.mapillary && !_mapillary) {
32942 _mapillary = iD.services.mapillary();
32943 _mapillary.on('loadedImages', debouncedRedraw);
32944 } else if (!iD.services.mapillary && _mapillary) {
32951 function showLayer() {
32952 var mapillary = getMapillary();
32953 if (!mapillary) return;
32955 mapillary.loadViewer();
32959 .style('opacity', 0)
32962 .style('opacity', 1)
32963 .each('end', debouncedRedraw);
32966 function hideLayer() {
32967 var mapillary = getMapillary();
32969 mapillary.hideViewer();
32972 debouncedRedraw.cancel();
32977 .style('opacity', 0)
32978 .each('end', editOff);
32981 function editOn() {
32982 layer.style('display', 'block');
32985 function editOff() {
32986 layer.selectAll('.viewfield-group').remove();
32987 layer.style('display', 'none');
32990 function click(d) {
32991 var mapillary = getMapillary();
32992 if (!mapillary) return;
32994 context.map().centerEase(d.loc);
32997 .setSelectedImage(d.key, true)
32998 .updateViewer(d.key, context)
33002 function transform(d) {
33003 var t = iD.svg.PointTransform(projection)(d);
33004 if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
33008 function update() {
33009 var mapillary = getMapillary(),
33010 data = (mapillary ? mapillary.images(projection, layer.dimensions()) : []),
33011 imageKey = mapillary ? mapillary.getSelectedImage() : null;
33013 var markers = layer.selectAll('.viewfield-group')
33014 .data(data, function(d) { return d.key; });
33017 var enter = markers.enter()
33019 .attr('class', 'viewfield-group')
33020 .classed('selected', function(d) { return d.key === imageKey; })
33021 .on('click', click);
33023 enter.append('path')
33024 .attr('class', 'viewfield')
33025 .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
33026 .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');
33028 enter.append('circle')
33039 .attr('transform', transform);
33042 function drawImages(selection) {
33043 var enabled = iD.svg.MapillaryImages.enabled,
33044 mapillary = getMapillary();
33046 layer = selection.selectAll('.layer-mapillary-images')
33047 .data(mapillary ? [0] : []);
33051 .attr('class', 'layer-mapillary-images')
33052 .style('display', enabled ? 'block' : 'none');
33058 if (mapillary && ~~context.map().zoom() >= minZoom) {
33061 mapillary.loadImages(projection, layer.dimensions());
33068 drawImages.enabled = function(_) {
33069 if (!arguments.length) return iD.svg.MapillaryImages.enabled;
33070 iD.svg.MapillaryImages.enabled = _;
33071 if (iD.svg.MapillaryImages.enabled) {
33080 drawImages.supported = function() {
33081 return !!getMapillary();
33084 drawImages.dimensions = function(_) {
33085 if (!arguments.length) return layer.dimensions();
33086 layer.dimensions(_);
33093 iD.svg.MapillarySigns = function(projection, context, dispatch) {
33094 var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000),
33096 layer = d3.select(null),
33101 if (iD.svg.MapillarySigns.initialized) return; // run once
33102 iD.svg.MapillarySigns.enabled = false;
33103 iD.svg.MapillarySigns.initialized = true;
33106 function getMapillary() {
33107 if (iD.services.mapillary && !_mapillary) {
33108 _mapillary = iD.services.mapillary().on('loadedSigns', debouncedRedraw);
33109 } else if (!iD.services.mapillary && _mapillary) {
33115 function showLayer() {
33120 function hideLayer() {
33121 debouncedRedraw.cancel();
33125 function editOn() {
33126 layer.style('display', 'block');
33129 function editOff() {
33130 layer.selectAll('.icon-sign').remove();
33131 layer.style('display', 'none');
33134 function click(d) {
33135 var mapillary = getMapillary();
33136 if (!mapillary) return;
33138 context.map().centerEase(d.loc);
33141 .setSelectedImage(d.key, true)
33142 .updateViewer(d.key, context)
33146 function update() {
33147 var mapillary = getMapillary(),
33148 data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []),
33149 imageKey = mapillary ? mapillary.getSelectedImage() : null;
33151 var signs = layer.selectAll('.icon-sign')
33152 .data(data, function(d) { return d.key; });
33155 var enter = signs.enter()
33156 .append('foreignObject')
33157 .attr('class', 'icon-sign')
33158 .attr('width', '32px') // for Firefox
33159 .attr('height', '32px') // for Firefox
33160 .classed('selected', function(d) { return d.key === imageKey; })
33161 .on('click', click);
33164 .append('xhtml:body')
33165 .html(mapillary.signHTML);
33173 .attr('transform', iD.svg.PointTransform(projection));
33176 function drawSigns(selection) {
33177 var enabled = iD.svg.MapillarySigns.enabled,
33178 mapillary = getMapillary();
33180 layer = selection.selectAll('.layer-mapillary-signs')
33181 .data(mapillary ? [0] : []);
33185 .attr('class', 'layer-mapillary-signs')
33186 .style('display', enabled ? 'block' : 'none')
33187 .attr('transform', 'translate(-16, -16)'); // center signs on loc
33193 if (mapillary && ~~context.map().zoom() >= minZoom) {
33196 mapillary.loadSigns(context, projection, layer.dimensions());
33203 drawSigns.enabled = function(_) {
33204 if (!arguments.length) return iD.svg.MapillarySigns.enabled;
33205 iD.svg.MapillarySigns.enabled = _;
33206 if (iD.svg.MapillarySigns.enabled) {
33215 drawSigns.supported = function() {
33216 var mapillary = getMapillary();
33217 return (mapillary && mapillary.signsSupported());
33220 drawSigns.dimensions = function(_) {
33221 if (!arguments.length) return layer.dimensions();
33222 layer.dimensions(_);
33229 iD.svg.Midpoints = function(projection, context) {
33230 return function drawMidpoints(surface, graph, entities, filter, extent) {
33231 var poly = extent.polygon(),
33234 for (var i = 0; i < entities.length; i++) {
33235 var entity = entities[i];
33237 if (entity.type !== 'way')
33239 if (!filter(entity))
33241 if (context.selectedIDs().indexOf(entity.id) < 0)
33244 var nodes = graph.childNodes(entity);
33245 for (var j = 0; j < nodes.length - 1; j++) {
33249 id = [a.id, b.id].sort().join('-');
33251 if (midpoints[id]) {
33252 midpoints[id].parents.push(entity);
33254 if (iD.geo.euclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
33255 var point = iD.geo.interp(a.loc, b.loc, 0.5),
33258 if (extent.intersects(point)) {
33261 for (var k = 0; k < 4; k++) {
33262 point = iD.geo.lineIntersection([a.loc, b.loc], [poly[k], poly[k+1]]);
33264 iD.geo.euclideanDistance(projection(a.loc), projection(point)) > 20 &&
33265 iD.geo.euclideanDistance(projection(b.loc), projection(point)) > 20)
33278 edge: [a.id, b.id],
33287 function midpointFilter(d) {
33288 if (midpoints[d.id])
33291 for (var i = 0; i < d.parents.length; i++)
33292 if (filter(d.parents[i]))
33298 var groups = surface.selectAll('.layer-hit').selectAll('g.midpoint')
33299 .filter(midpointFilter)
33300 .data(_.values(midpoints), function(d) { return d.id; });
33302 var enter = groups.enter()
33303 .insert('g', ':first-child')
33304 .attr('class', 'midpoint');
33306 enter.append('polygon')
33307 .attr('points', '-6,8 10,0 -6,-8')
33308 .attr('class', 'shadow');
33310 enter.append('polygon')
33311 .attr('points', '-3,4 5,0 -3,-4')
33312 .attr('class', 'fill');
33315 .attr('transform', function(d) {
33316 var translate = iD.svg.PointTransform(projection),
33317 a = context.entity(d.edge[0]),
33318 b = context.entity(d.edge[1]),
33319 angle = Math.round(iD.geo.angle(a, b, projection) * (180 / Math.PI));
33320 return translate(d) + ' rotate(' + angle + ')';
33322 .call(iD.svg.TagClasses().tags(
33323 function(d) { return d.parents[0].tags; }
33326 // Propagate data bindings.
33327 groups.select('polygon.shadow');
33328 groups.select('polygon.fill');
33334 iD.svg.Osm = function() {
33335 return function drawOsm(selection) {
33336 var layers = selection.selectAll('.layer-osm')
33337 .data(['areas', 'lines', 'hit', 'halo', 'label']);
33339 layers.enter().append('g')
33340 .attr('class', function(d) { return 'layer-osm layer-' + d; });
33343 iD.svg.Points = function(projection, context) {
33344 function markerPath(selection, klass) {
33346 .attr('class', klass)
33347 .attr('transform', 'translate(-8, -23)')
33348 .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');
33351 function sortY(a, b) {
33352 return b.loc[1] - a.loc[1];
33355 return function drawPoints(surface, graph, entities, filter) {
33356 var wireframe = surface.classed('fill-wireframe'),
33357 points = wireframe ? [] : _.filter(entities, function(e) {
33358 return e.geometry(graph) === 'point';
33361 points.sort(sortY);
33363 var groups = surface.selectAll('.layer-hit').selectAll('g.point')
33365 .data(points, iD.Entity.key);
33367 var group = groups.enter()
33369 .attr('class', function(d) { return 'node point ' + d.id; })
33372 group.append('path')
33373 .call(markerPath, 'shadow');
33375 group.append('path')
33376 .call(markerPath, 'stroke');
33378 group.append('use')
33379 .attr('transform', 'translate(-6, -20)')
33380 .attr('class', 'icon')
33381 .attr('width', '12px')
33382 .attr('height', '12px');
33384 groups.attr('transform', iD.svg.PointTransform(projection))
33385 .call(iD.svg.TagClasses());
33387 // Selecting the following implicitly
33388 // sets the data (point entity) on the element
33389 groups.select('.shadow');
33390 groups.select('.stroke');
33391 groups.select('.icon')
33392 .attr('xlink:href', function(entity) {
33393 var preset = context.presets().match(entity, graph);
33394 return preset.icon ? '#' + preset.icon + '-12' : '';
33401 iD.svg.TagClasses = function() {
33403 'building', 'highway', 'railway', 'waterway', 'aeroway',
33404 'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
33408 'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
33409 'razed', 'demolished', 'obliterated'
33412 'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
33413 'surface', 'tracktype', 'crossing'
33415 tagClassRe = /^tag-/,
33416 tags = function(entity) { return entity.tags; };
33419 var tagClasses = function(selection) {
33420 selection.each(function tagClassesEach(entity) {
33421 var value = this.className,
33422 classes, primary, status;
33424 if (value.baseVal !== undefined) value = value.baseVal;
33426 classes = value.trim().split(/\s+/).filter(function(name) {
33427 return name.length && !tagClassRe.test(name);
33430 var t = tags(entity), i, k, v;
33432 // pick at most one primary classification tag..
33433 for (i = 0; i < primaries.length; i++) {
33436 if (!v || v === 'no') continue;
33439 if (statuses.indexOf(v) !== -1) { // e.g. `railway=abandoned`
33441 classes += ' tag-' + k;
33443 classes += ' tag-' + k + ' tag-' + k + '-' + v;
33449 // add at most one status tag, only if relates to primary tag..
33451 for (i = 0; i < statuses.length; i++) {
33454 if (!v || v === 'no') continue;
33456 if (v === 'yes') { // e.g. `railway=rail + abandoned=yes`
33459 else if (primary && primary === v) { // e.g. `railway=rail + abandoned=railway`
33461 } else if (!primary && primaries.indexOf(v) !== -1) { // e.g. `abandoned=railway`
33464 classes += ' tag-' + v;
33465 } // else ignore e.g. `highway=path + abandoned=railway`
33472 classes += ' tag-status tag-status-' + status;
33475 // add any secondary (structure) tags
33476 for (i = 0; i < secondaries.length; i++) {
33477 k = secondaries[i];
33479 if (!v || v === 'no') continue;
33480 classes += ' tag-' + k + ' tag-' + k + '-' + v;
33483 // For highways, look for surface tagging..
33484 if (primary === 'highway') {
33485 var paved = (t.highway !== 'track');
33488 if (k in iD.pavedTags) {
33489 paved = !!iD.pavedTags[k][v];
33494 classes += ' tag-unpaved';
33498 classes = classes.trim();
33500 if (classes !== value) {
33501 d3.select(this).attr('class', classes);
33506 tagClasses.tags = function(_) {
33507 if (!arguments.length) return tags;
33514 iD.svg.Turns = function(projection) {
33515 return function drawTurns(surface, graph, turns) {
33516 function key(turn) {
33517 return [turn.from.node + turn.via.node + turn.to.node].join('-');
33520 function icon(turn) {
33521 var u = turn.u ? '-u' : '';
33522 if (!turn.restriction)
33523 return '#turn-yes' + u;
33524 var restriction = graph.entity(turn.restriction).tags.restriction;
33526 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
33529 var groups = surface.selectAll('.layer-hit').selectAll('g.turn')
33533 var enter = groups.enter().append('g')
33534 .attr('class', 'turn');
33536 var nEnter = enter.filter(function (turn) { return !turn.u; });
33538 nEnter.append('rect')
33539 .attr('transform', 'translate(-22, -12)')
33540 .attr('width', '44')
33541 .attr('height', '24');
33543 nEnter.append('use')
33544 .attr('transform', 'translate(-22, -12)')
33545 .attr('width', '44')
33546 .attr('height', '24');
33549 var uEnter = enter.filter(function (turn) { return turn.u; });
33551 uEnter.append('circle')
33554 uEnter.append('use')
33555 .attr('transform', 'translate(-16, -16)')
33556 .attr('width', '32')
33557 .attr('height', '32');
33562 .attr('transform', function (turn) {
33563 var v = graph.entity(turn.via.node),
33564 t = graph.entity(turn.to.node),
33565 a = iD.geo.angle(v, t, projection),
33566 p = projection(v.loc),
33567 r = turn.u ? 0 : 60;
33569 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
33570 'rotate(' + a * 180 / Math.PI + ')';
33573 groups.select('use')
33574 .attr('xlink:href', icon);
33576 groups.select('rect');
33577 groups.select('circle');
33587 iD.svg.Vertices = function(projection, context) {
33589 // z16-, z17, z18+, tagged
33590 shadow: [6, 7.5, 7.5, 11.5],
33591 stroke: [2.5, 3.5, 3.5, 7],
33592 fill: [1, 1.5, 1.5, 1.5]
33597 function siblingAndChildVertices(ids, graph, extent) {
33600 function addChildVertices(entity) {
33601 if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
33603 if (entity.type === 'way') {
33604 for (i = 0; i < entity.nodes.length; i++) {
33605 addChildVertices(graph.entity(entity.nodes[i]));
33607 } else if (entity.type === 'relation') {
33608 for (i = 0; i < entity.members.length; i++) {
33609 var member = context.hasEntity(entity.members[i].id);
33611 addChildVertices(member);
33614 } else if (entity.intersects(extent, graph)) {
33615 vertices[entity.id] = entity;
33620 ids.forEach(function(id) {
33621 var entity = context.hasEntity(id);
33622 if (entity && entity.type === 'node') {
33623 vertices[entity.id] = entity;
33624 context.graph().parentWays(entity).forEach(function(entity) {
33625 addChildVertices(entity);
33627 } else if (entity) {
33628 addChildVertices(entity);
33635 function draw(selection, vertices, klass, graph, zoom) {
33637 z = (zoom < 17 ? 0 : zoom < 18 ? 1 : 2);
33639 var groups = selection
33640 .data(vertices, iD.Entity.key);
33642 function icon(entity) {
33643 if (entity.id in icons) return icons[entity.id];
33645 entity.hasInterestingTags() &&
33646 context.presets().match(entity, graph).icon;
33647 return icons[entity.id];
33650 function setClass(klass) {
33651 return function(entity) {
33652 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
33656 function setAttributes(selection) {
33657 ['shadow','stroke','fill'].forEach(function(klass) {
33658 var rads = radiuses[klass];
33659 selection.selectAll('.' + klass)
33660 .each(function(entity) {
33661 var i = z && icon(entity),
33663 r = rads[i ? 3 : z];
33664 this.setAttribute('cx', c);
33665 this.setAttribute('cy', -c);
33666 this.setAttribute('r', r);
33667 if (i && klass === 'fill') {
33668 this.setAttribute('visibility', 'hidden');
33670 this.removeAttribute('visibility');
33675 selection.selectAll('use')
33678 this.removeAttribute('visibility');
33680 this.setAttribute('visibility', 'hidden');
33685 var enter = groups.enter()
33687 .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
33689 enter.append('circle')
33690 .each(setClass('shadow'));
33692 enter.append('circle')
33693 .each(setClass('stroke'));
33695 // Vertices with icons get a `use`.
33696 enter.filter(function(d) { return icon(d); })
33698 .attr('transform', 'translate(-6, -6)')
33699 .attr('xlink:href', function(d) { return '#' + icon(d) + '-12'; })
33700 .attr('width', '12px')
33701 .attr('height', '12px')
33702 .each(setClass('icon'));
33704 // Vertices with tags get a fill.
33705 enter.filter(function(d) { return d.hasInterestingTags(); })
33707 .each(setClass('fill'));
33710 .attr('transform', iD.svg.PointTransform(projection))
33711 .classed('shared', function(entity) { return graph.isShared(entity); })
33712 .call(setAttributes);
33718 function drawVertices(surface, graph, entities, filter, extent, zoom) {
33719 var selected = siblingAndChildVertices(context.selectedIDs(), graph, extent),
33720 wireframe = surface.classed('fill-wireframe'),
33723 for (var i = 0; i < entities.length; i++) {
33724 var entity = entities[i],
33725 geometry = entity.geometry(graph);
33727 if (wireframe && geometry === 'point') {
33728 vertices.push(entity);
33732 if (geometry !== 'vertex')
33735 if (entity.id in selected ||
33736 entity.hasInterestingTags() ||
33737 entity.isIntersection(graph)) {
33738 vertices.push(entity);
33742 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-persistent')
33744 .call(draw, vertices, 'vertex-persistent', graph, zoom);
33746 drawHover(surface, graph, extent, zoom);
33749 function drawHover(surface, graph, extent, zoom) {
33750 var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent) : {};
33752 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-hover')
33753 .call(draw, d3.values(hovered), 'vertex-hover', graph, zoom);
33756 drawVertices.drawHover = function(surface, graph, target, extent, zoom) {
33757 if (target === hover) return;
33759 drawHover(surface, graph, extent, zoom);
33762 return drawVertices;
33764 iD.ui = function(context) {
33765 function render(container) {
33766 var map = context.map();
33768 if (iD.detect().opera) container.classed('opera', true);
33770 var hash = iD.behavior.Hash(context);
33774 if (!hash.hadHash) {
33775 map.centerZoom([0, 0], 2);
33778 container.append('svg')
33779 .attr('id', 'defs')
33780 .call(iD.svg.Defs(context));
33782 container.append('div')
33783 .attr('id', 'sidebar')
33784 .attr('class', 'col4')
33787 var content = container.append('div')
33788 .attr('id', 'content');
33790 var bar = content.append('div')
33792 .attr('class', 'fillD');
33794 content.append('div')
33799 .call(iD.ui.MapInMap(context));
33801 content.append('div')
33802 .call(iD.ui.Info(context));
33805 .attr('class', 'spacer col4');
33807 var limiter = bar.append('div')
33808 .attr('class', 'limiter');
33810 limiter.append('div')
33811 .attr('class', 'button-wrap joined col3')
33812 .call(iD.ui.Modes(context), limiter);
33814 limiter.append('div')
33815 .attr('class', 'button-wrap joined col1')
33816 .call(iD.ui.UndoRedo(context));
33818 limiter.append('div')
33819 .attr('class', 'button-wrap col1')
33820 .call(iD.ui.Save(context));
33823 .attr('class', 'full-screen')
33824 .call(iD.ui.FullScreen(context));
33827 .attr('class', 'spinner')
33828 .call(iD.ui.Spinner(context));
33830 var controls = bar.append('div')
33831 .attr('class', 'map-controls');
33833 controls.append('div')
33834 .attr('class', 'map-control zoombuttons')
33835 .call(iD.ui.Zoom(context));
33837 controls.append('div')
33838 .attr('class', 'map-control geolocate-control')
33839 .call(iD.ui.Geolocate(context));
33841 controls.append('div')
33842 .attr('class', 'map-control background-control')
33843 .call(iD.ui.Background(context));
33845 controls.append('div')
33846 .attr('class', 'map-control map-data-control')
33847 .call(iD.ui.MapData(context));
33849 controls.append('div')
33850 .attr('class', 'map-control help-control')
33851 .call(iD.ui.Help(context));
33853 var about = content.append('div')
33854 .attr('id', 'about');
33856 about.append('div')
33857 .attr('id', 'attrib')
33858 .call(iD.ui.Attribution(context));
33860 var footer = about.append('div')
33861 .attr('id', 'footer')
33862 .attr('class', 'fillD');
33864 footer.append('div')
33865 .attr('class', 'api-status')
33866 .call(iD.ui.Status(context));
33868 footer.append('div')
33869 .attr('id', 'scale-block')
33870 .call(iD.ui.Scale(context));
33872 var aboutList = footer.append('div')
33873 .attr('id', 'info-block')
33875 .attr('id', 'about-list');
33877 if (!context.embed()) {
33878 aboutList.call(iD.ui.Account(context));
33881 aboutList.append('li')
33883 .attr('target', '_blank')
33884 .attr('tabindex', -1)
33885 .attr('href', 'https://github.com/openstreetmap/iD')
33888 var issueLinks = aboutList.append('li');
33890 issueLinks.append('a')
33891 .attr('target', '_blank')
33892 .attr('tabindex', -1)
33893 .attr('href', 'https://github.com/openstreetmap/iD/issues')
33894 .call(iD.svg.Icon('#icon-bug', 'light'))
33895 .call(bootstrap.tooltip()
33896 .title(t('report_a_bug'))
33900 issueLinks.append('a')
33901 .attr('target', '_blank')
33902 .attr('tabindex', -1)
33903 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
33904 .call(iD.svg.Icon('#icon-translate', 'light'))
33905 .call(bootstrap.tooltip()
33906 .title(t('help_translate'))
33910 aboutList.append('li')
33911 .attr('class', 'feature-warning')
33912 .attr('tabindex', -1)
33913 .call(iD.ui.FeatureInfo(context));
33915 aboutList.append('li')
33916 .attr('class', 'user-list')
33917 .attr('tabindex', -1)
33918 .call(iD.ui.Contributors(context));
33920 window.onbeforeunload = function() {
33921 return context.save();
33924 window.onunload = function() {
33925 context.history().unlock();
33928 var mapDimensions = map.dimensions();
33930 d3.select(window).on('resize.editor', function() {
33931 mapDimensions = content.dimensions(null);
33932 map.dimensions(mapDimensions);
33936 return function() {
33937 d3.event.preventDefault();
33938 if (!context.inIntro()) context.pan(d);
33945 var keybinding = d3.keybinding('main')
33946 .on('⌫', function() { d3.event.preventDefault(); })
33947 .on('←', pan([pa, 0]))
33948 .on('↑', pan([0, pa]))
33949 .on('→', pan([-pa, 0]))
33950 .on('↓', pan([0, -pa]))
33951 .on('⇧←', pan([mapDimensions[0], 0]))
33952 .on('⇧↑', pan([0, mapDimensions[1]]))
33953 .on('⇧→', pan([-mapDimensions[0], 0]))
33954 .on('⇧↓', pan([0, -mapDimensions[1]]))
33955 .on(iD.ui.cmd('⌘←'), pan([mapDimensions[0], 0]))
33956 .on(iD.ui.cmd('⌘↑'), pan([0, mapDimensions[1]]))
33957 .on(iD.ui.cmd('⌘→'), pan([-mapDimensions[0], 0]))
33958 .on(iD.ui.cmd('⌘↓'), pan([0, -mapDimensions[1]]));
33960 d3.select(document)
33963 context.enter(iD.modes.Browse(context));
33965 context.container()
33966 .call(iD.ui.Splash(context))
33967 .call(iD.ui.Restore(context));
33969 var authenticating = iD.ui.Loading(context)
33970 .message(t('loading_auth'));
33972 context.connection()
33973 .on('authenticating.ui', function() {
33974 context.container()
33975 .call(authenticating);
33977 .on('authenticated.ui', function() {
33978 authenticating.close();
33982 function ui(container) {
33983 context.container(container);
33984 context.loadLocale(function() {
33989 ui.sidebar = iD.ui.Sidebar(context);
33994 iD.ui.tooltipHtml = function(text, key) {
33995 var s = '<span>' + text + '</span>';
33997 s += '<div class="keyhint-wrap">' +
33998 '<span> ' + (t('tooltip_keyhint')) + ' </span>' +
33999 '<span class="keyhint"> ' + key + '</span></div>';
34003 iD.ui.Account = function(context) {
34004 var connection = context.connection();
34006 function update(selection) {
34007 if (!connection.authenticated()) {
34008 selection.selectAll('#userLink, #logoutLink')
34009 .classed('hide', true);
34013 connection.userDetails(function(err, details) {
34014 var userLink = selection.select('#userLink'),
34015 logoutLink = selection.select('#logoutLink');
34018 logoutLink.html('');
34022 selection.selectAll('#userLink, #logoutLink')
34023 .classed('hide', false);
34026 userLink.append('a')
34027 .attr('href', connection.userURL(details.display_name))
34028 .attr('target', '_blank');
34030 // Add thumbnail or dont
34031 if (details.image_url) {
34032 userLink.append('img')
34033 .attr('class', 'icon pre-text user-icon')
34034 .attr('src', details.image_url);
34037 .call(iD.svg.Icon('#icon-avatar', 'pre-text light'));
34041 userLink.append('span')
34042 .attr('class', 'label')
34043 .text(details.display_name);
34045 logoutLink.append('a')
34046 .attr('class', 'logout')
34049 .on('click.logout', function() {
34050 d3.event.preventDefault();
34051 connection.logout();
34056 return function(selection) {
34057 selection.append('li')
34058 .attr('id', 'logoutLink')
34059 .classed('hide', true);
34061 selection.append('li')
34062 .attr('id', 'userLink')
34063 .classed('hide', true);
34065 connection.on('auth.account', function() { update(selection); });
34069 iD.ui.Attribution = function(context) {
34072 function attribution(data, klass) {
34073 var div = selection.selectAll('.' + klass)
34078 .attr('class', klass);
34080 var background = div.selectAll('.attribution')
34081 .data(data, function(d) { return d.name(); });
34085 .attr('class', 'attribution')
34086 .each(function(d) {
34087 if (d.terms_html) {
34089 .html(d.terms_html);
34093 var source = d.terms_text || d.id || d.name();
34096 source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
34102 .attr('href', d.terms_url)
34103 .attr('target', '_blank')
34114 var copyright = background.selectAll('.copyright-notice')
34115 .data(function(d) {
34116 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
34117 return notice ? [notice] : [];
34122 .attr('class', 'copyright-notice');
34124 copyright.text(String);
34130 function update() {
34131 attribution([context.background().baseLayerSource()], 'base-layer-attribution');
34132 attribution(context.background().overlayLayerSources().filter(function (s) {
34133 return s.validZoom(context.map().zoom());
34134 }), 'overlay-layer-attribution');
34137 return function(select) {
34138 selection = select;
34140 context.background()
34141 .on('change.attribution', update);
34144 .on('move.attribution', _.throttle(update, 400, {leading: false}));
34149 iD.ui.Background = function(context) {
34151 opacities = [1, 0.75, 0.5, 0.25],
34153 ['right', [0.5, 0]],
34154 ['top', [0, -0.5]],
34155 ['left', [-0.5, 0]],
34156 ['bottom', [0, 0.5]]],
34157 opacityDefault = (context.storage('background-opacity') !== null) ?
34158 (+context.storage('background-opacity')) : 1.0,
34159 customTemplate = context.storage('background-custom-template') || '',
34162 // Can be 0 from <1.3.0 use or due to issue #1923.
34163 if (opacityDefault === 0) opacityDefault = 1.0;
34166 function background(selection) {
34168 function sortSources(a, b) {
34169 return a.best() && !b.best() ? -1
34170 : b.best() && !a.best() ? 1
34171 : d3.descending(a.area(), b.area()) || d3.ascending(a.name(), b.name()) || 0;
34174 function setOpacity(d) {
34175 var bg = context.container().selectAll('.layer-background')
34177 .style('opacity', d)
34178 .attr('data-opacity', d);
34180 if (!iD.detect().opera) {
34181 iD.util.setTransform(bg, 0, 0);
34184 opacityList.selectAll('li')
34185 .classed('active', function(_) { return _ === d; });
34187 context.storage('background-opacity', d);
34190 function setTooltips(selection) {
34191 selection.each(function(d) {
34192 var item = d3.select(this);
34193 if (d === previous) {
34194 item.call(bootstrap.tooltip()
34196 .title(function() {
34197 var tip = '<div>' + t('background.switch') + '</div>';
34198 return iD.ui.tooltipHtml(tip, iD.ui.cmd('⌘B'));
34202 } else if (d.description) {
34203 item.call(bootstrap.tooltip()
34204 .title(d.description)
34208 item.call(bootstrap.tooltip().destroy);
34213 function selectLayer() {
34214 function active(d) {
34215 return context.background().showsLayer(d);
34218 content.selectAll('.layer, .custom_layer')
34219 .classed('active', active)
34220 .classed('switch', function(d) { return d === previous; })
34222 .selectAll('input')
34223 .property('checked', active);
34226 function clickSetSource(d) {
34227 previous = context.background().baseLayerSource();
34228 d3.event.preventDefault();
34229 context.background().baseLayerSource(d);
34231 document.activeElement.blur();
34234 function editCustom() {
34235 d3.event.preventDefault();
34236 var template = window.prompt(t('background.custom_prompt'), customTemplate);
34238 template.indexOf('google.com') !== -1 ||
34239 template.indexOf('googleapis.com') !== -1 ||
34240 template.indexOf('google.ru') !== -1) {
34244 setCustom(template);
34247 function setCustom(template) {
34248 context.background().baseLayerSource(iD.BackgroundSource.Custom(template));
34250 context.storage('background-custom-template', template);
34253 function clickSetOverlay(d) {
34254 d3.event.preventDefault();
34255 context.background().toggleOverlayLayer(d);
34257 document.activeElement.blur();
34260 function drawList(layerList, type, change, filter) {
34261 var sources = context.background()
34262 .sources(context.map().extent())
34265 var layerLinks = layerList.selectAll('li.layer')
34266 .data(sources, function(d) { return d.name(); });
34268 var enter = layerLinks.enter()
34269 .insert('li', '.custom_layer')
34270 .attr('class', 'layer')
34271 .classed('best', function(d) { return d.best(); });
34273 enter.filter(function(d) { return d.best(); })
34275 .attr('class', 'best')
34276 .call(bootstrap.tooltip()
34277 .title(t('background.best_imagery'))
34278 .placement('left'))
34282 var label = enter.append('label');
34284 label.append('input')
34285 .attr('type', type)
34286 .attr('name', 'layers')
34287 .on('change', change);
34289 label.append('span')
34290 .text(function(d) { return d.name(); });
34296 layerList.selectAll('li.layer')
34298 .style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
34301 function update() {
34302 backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
34303 overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
34307 var source = context.background().baseLayerSource();
34308 if (source.id === 'custom') {
34309 customTemplate = source.template;
34315 function updateOffsetVal() {
34316 var meters = iD.geo.offsetToMeters(context.background().offset()),
34317 x = +meters[0].toFixed(2),
34318 y = +meters[1].toFixed(2);
34320 d3.selectAll('.nudge-inner-rect')
34322 .classed('error', false)
34323 .property('value', x + ', ' + y);
34325 d3.selectAll('.nudge-reset')
34326 .classed('disabled', function() {
34327 return (x === 0 && y === 0);
34331 function resetOffset() {
34332 context.background().offset([0, 0]);
34336 function nudge(d) {
34337 context.background().nudge(d, context.map().zoom());
34341 function buttonOffset(d) {
34342 var timeout = window.setTimeout(function() {
34343 interval = window.setInterval(nudge.bind(null, d), 100);
34347 d3.select(window).on('mouseup', function() {
34348 window.clearInterval(interval);
34349 window.clearTimeout(timeout);
34350 d3.select(window).on('mouseup', null);
34356 function inputOffset() {
34357 var input = d3.select(this);
34358 var d = input.node().value;
34360 if (d === '') return resetOffset();
34362 d = d.replace(/;/g, ',').split(',').map(function(n) {
34363 // if n is NaN, it will always get mapped to false.
34364 return !isNaN(n) && n;
34367 if (d.length !== 2 || !d[0] || !d[1]) {
34368 input.classed('error', true);
34372 context.background().offset(iD.geo.metersToOffset(d));
34376 function dragOffset() {
34377 var origin = [d3.event.clientX, d3.event.clientY];
34379 context.container()
34381 .attr('class', 'nudge-surface');
34384 .on('mousemove.offset', function() {
34385 var latest = [d3.event.clientX, d3.event.clientY];
34387 -(origin[0] - latest[0]) / 4,
34388 -(origin[1] - latest[1]) / 4
34394 .on('mouseup.offset', function() {
34395 d3.selectAll('.nudge-surface')
34399 .on('mousemove.offset', null)
34400 .on('mouseup.offset', null);
34403 d3.event.preventDefault();
34410 function toggle() {
34411 if (d3.event) d3.event.preventDefault();
34412 tooltip.hide(button);
34413 setVisible(!button.classed('active'));
34416 function quickSwitch() {
34418 clickSetSource(previous);
34422 function setVisible(show) {
34423 if (show !== shown) {
34424 button.classed('active', show);
34428 selection.on('mousedown.background-inside', function() {
34429 return d3.event.stopPropagation();
34431 content.style('display', 'block')
34432 .style('right', '-300px')
34435 .style('right', '0px');
34437 content.style('display', 'block')
34438 .style('right', '0px')
34441 .style('right', '-300px')
34442 .each('end', function() {
34443 d3.select(this).style('display', 'none');
34445 selection.on('mousedown.background-inside', null);
34451 var content = selection.append('div')
34452 .attr('class', 'fillL map-overlay col3 content hide'),
34453 tooltip = bootstrap.tooltip()
34456 .title(iD.ui.tooltipHtml(t('background.description'), key)),
34457 button = selection.append('button')
34458 .attr('tabindex', -1)
34459 .on('click', toggle)
34460 .call(iD.svg.Icon('#icon-layers', 'light'))
34465 /* opacity switcher */
34467 var opa = content.append('div')
34468 .attr('class', 'opacity-options-wrapper');
34471 .text(t('background.title'));
34473 var opacityList = opa.append('ul')
34474 .attr('class', 'opacity-options');
34476 opacityList.selectAll('div.opacity')
34480 .attr('data-original-title', function(d) {
34481 return t('background.percent_brightness', { opacity: (d * 100) });
34483 .on('click.set-opacity', setOpacity)
34484 .html('<div class="select-box"></div>')
34485 .call(bootstrap.tooltip()
34486 .placement('left'))
34488 .attr('class', 'opacity')
34489 .style('opacity', function(d) { return 1.25 - d; });
34492 /* background switcher */
34494 var backgroundList = content.append('ul')
34495 .attr('class', 'layer-list');
34497 var custom = backgroundList.append('li')
34498 .attr('class', 'custom_layer')
34499 .datum(iD.BackgroundSource.Custom());
34501 custom.append('button')
34502 .attr('class', 'layer-browse')
34503 .call(bootstrap.tooltip()
34504 .title(t('background.custom_button'))
34505 .placement('left'))
34506 .on('click', editCustom)
34507 .call(iD.svg.Icon('#icon-search'));
34509 var label = custom.append('label');
34511 label.append('input')
34512 .attr('type', 'radio')
34513 .attr('name', 'layers')
34514 .on('change', function () {
34515 if (customTemplate) {
34516 setCustom(customTemplate);
34522 label.append('span')
34523 .text(t('background.custom'));
34525 content.append('div')
34526 .attr('class', 'imagery-faq')
34528 .attr('target', '_blank')
34529 .attr('tabindex', -1)
34530 .call(iD.svg.Icon('#icon-out-link', 'inline'))
34531 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
34533 .text(t('background.imagery_source_faq'));
34535 var overlayList = content.append('ul')
34536 .attr('class', 'layer-list');
34538 var controls = content.append('div')
34539 .attr('class', 'controls-list');
34542 /* minimap toggle */
34544 var minimapLabel = controls
34546 .call(bootstrap.tooltip()
34548 .title(iD.ui.tooltipHtml(t('background.minimap.tooltip'), '/'))
34552 minimapLabel.classed('minimap-toggle', true)
34554 .attr('type', 'checkbox')
34555 .on('change', function() {
34556 iD.ui.MapInMap.toggle();
34557 d3.event.preventDefault();
34560 minimapLabel.append('span')
34561 .text(t('background.minimap.description'));
34564 /* imagery offset controls */
34566 var adjustments = content.append('div')
34567 .attr('class', 'adjustments');
34569 adjustments.append('a')
34570 .text(t('background.fix_misalignment'))
34572 .classed('hide-toggle', true)
34573 .classed('expanded', false)
34574 .on('click', function() {
34575 var exp = d3.select(this).classed('expanded');
34576 nudgeContainer.style('display', exp ? 'none' : 'block');
34577 d3.select(this).classed('expanded', !exp);
34578 d3.event.preventDefault();
34581 var nudgeContainer = adjustments.append('div')
34582 .attr('class', 'nudge-container cf')
34583 .style('display', 'none');
34585 nudgeContainer.append('div')
34586 .attr('class', 'nudge-instructions')
34587 .text(t('background.offset'));
34589 var nudgeRect = nudgeContainer.append('div')
34590 .attr('class', 'nudge-outer-rect')
34591 .on('mousedown', dragOffset);
34593 nudgeRect.append('div')
34594 .attr('class', 'nudge-inner-rect')
34596 .on('change', inputOffset)
34597 .on('mousedown', function() {
34598 d3.event.stopPropagation();
34601 nudgeContainer.append('div')
34602 .selectAll('button')
34603 .data(directions).enter()
34605 .attr('class', function(d) { return d[0] + ' nudge'; })
34606 .on('mousedown', function(d) {
34607 buttonOffset(d[1]);
34610 nudgeContainer.append('button')
34611 .attr('title', t('background.reset'))
34612 .attr('class', 'nudge-reset disabled')
34613 .on('click', resetOffset)
34614 .call(iD.svg.Icon('#icon-undo'));
34617 .on('move.background-update', _.debounce(update, 1000));
34619 context.background()
34620 .on('change.background-update', update);
34624 setOpacity(opacityDefault);
34626 var keybinding = d3.keybinding('background')
34628 .on(iD.ui.cmd('⌘B'), quickSwitch)
34632 d3.select(document)
34635 context.surface().on('mousedown.background-outside', hide);
34636 context.container().on('mousedown.background-outside', hide);
34641 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
34642 // For example, ⌘Z -> Ctrl+Z
34643 iD.ui.cmd = function(code) {
34644 if (iD.detect().os === 'mac') {
34648 if (iD.detect().os === 'win') {
34649 if (code === '⌘⇧Z') return 'Ctrl+Y';
34661 for (var i = 0; i < code.length; i++) {
34662 if (code[i] in replacements) {
34663 result += replacements[code[i]] + '+';
34671 iD.ui.Commit = function(context) {
34672 var dispatch = d3.dispatch('cancel', 'save');
34674 function commit(selection) {
34675 var changes = context.history().changes(),
34676 summary = context.history().difference().summary();
34678 function zoomToEntity(change) {
34679 var entity = change.entity;
34680 if (change.changeType !== 'deleted' &&
34681 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
34682 context.map().zoomTo(entity);
34683 context.surface().selectAll(
34684 iD.util.entityOrMemberSelector([entity.id], context.graph()))
34685 .classed('hover', true);
34689 var header = selection.append('div')
34690 .attr('class', 'header fillL');
34692 header.append('h3')
34693 .text(t('commit.title'));
34695 var body = selection.append('div')
34696 .attr('class', 'body');
34700 var commentSection = body.append('div')
34701 .attr('class', 'modal-section form-field commit-form');
34703 commentSection.append('label')
34704 .attr('class', 'form-label')
34705 .text(t('commit.message_label'));
34707 var commentField = commentSection.append('textarea')
34708 .attr('placeholder', t('commit.description_placeholder'))
34709 .attr('maxlength', 255)
34710 .property('value', context.storage('comment') || '')
34711 .on('input.save', checkComment)
34712 .on('change.save', checkComment)
34713 .on('blur.save', function() {
34714 context.storage('comment', this.value);
34717 function checkComment() {
34718 d3.selectAll('.save-section .save-button')
34719 .attr('disabled', (this.value.length ? null : true));
34721 var googleWarning = clippyArea
34724 .data(this.value.match(/google/i) ? [true] : []);
34726 googleWarning.exit().remove();
34728 googleWarning.enter()
34730 .attr('target', '_blank')
34731 .attr('tabindex', -1)
34732 .call(iD.svg.Icon('#icon-alert', 'inline'))
34733 .attr('href', t('commit.google_warning_link'))
34735 .text(t('commit.google_warning'));
34738 commentField.node().select();
34740 context.connection().userChangesets(function (err, changesets) {
34745 for (var i = 0; i < changesets.length; i++) {
34746 if (changesets[i].tags.comment) {
34748 title: changesets[i].tags.comment,
34749 value: changesets[i].tags.comment
34754 commentField.call(d3.combobox().caseSensitive(true).data(comments));
34757 var clippyArea = commentSection.append('div')
34758 .attr('class', 'clippy-area');
34761 var changeSetInfo = commentSection.append('div')
34762 .attr('class', 'changeset-info');
34764 changeSetInfo.append('a')
34765 .attr('target', '_blank')
34766 .attr('tabindex', -1)
34767 .call(iD.svg.Icon('#icon-out-link', 'inline'))
34768 .attr('href', t('commit.about_changeset_comments_link'))
34770 .text(t('commit.about_changeset_comments'));
34773 var warnings = body.selectAll('div.warning-section')
34774 .data([context.history().validate(changes)])
34777 .attr('class', 'modal-section warning-section fillL2')
34778 .style('display', function(d) { return _.isEmpty(d) ? 'none' : null; })
34779 .style('background', '#ffb');
34781 warnings.append('h3')
34782 .text(t('commit.warnings'));
34784 var warningLi = warnings.append('ul')
34785 .attr('class', 'changeset-list')
34787 .data(function(d) { return d; })
34791 .on('mouseover', mouseover)
34792 .on('mouseout', mouseout)
34793 .on('click', warningClick);
34796 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
34799 .append('strong').text(function(d) {
34803 warningLi.filter(function(d) { return d.tooltip; })
34804 .call(bootstrap.tooltip()
34805 .title(function(d) { return d.tooltip; })
34810 // Upload Explanation
34811 var saveSection = body.append('div')
34812 .attr('class','modal-section save-section fillL cf');
34814 var prose = saveSection.append('p')
34815 .attr('class', 'commit-info')
34816 .html(t('commit.upload_explanation'));
34818 context.connection().userDetails(function(err, user) {
34821 var userLink = d3.select(document.createElement('div'));
34823 if (user.image_url) {
34824 userLink.append('img')
34825 .attr('src', user.image_url)
34826 .attr('class', 'icon pre-text user-icon');
34829 userLink.append('a')
34830 .attr('class','user-info')
34831 .text(user.display_name)
34832 .attr('href', context.connection().userURL(user.display_name))
34833 .attr('tabindex', -1)
34834 .attr('target', '_blank');
34836 prose.html(t('commit.upload_explanation_with_user', {user: userLink.html()}));
34841 var buttonSection = saveSection.append('div')
34842 .attr('class','buttons fillL cf');
34844 var cancelButton = buttonSection.append('button')
34845 .attr('class', 'secondary-action col5 button cancel-button')
34846 .on('click.cancel', function() { dispatch.cancel(); });
34848 cancelButton.append('span')
34849 .attr('class', 'label')
34850 .text(t('commit.cancel'));
34852 var saveButton = buttonSection.append('button')
34853 .attr('class', 'action col5 button save-button')
34854 .attr('disabled', function() {
34855 var n = d3.select('.commit-form textarea').node();
34856 return (n && n.value.length) ? null : true;
34858 .on('click.save', function() {
34860 comment: commentField.node().value
34864 saveButton.append('span')
34865 .attr('class', 'label')
34866 .text(t('commit.save'));
34870 var changeSection = body.selectAll('div.commit-section')
34874 .attr('class', 'commit-section modal-section fillL2');
34876 changeSection.append('h3')
34877 .text(t('commit.changes', {count: summary.length}));
34879 var li = changeSection.append('ul')
34880 .attr('class', 'changeset-list')
34885 .on('mouseover', mouseover)
34886 .on('mouseout', mouseout)
34887 .on('click', zoomToEntity);
34889 li.each(function(d) {
34891 .call(iD.svg.Icon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
34895 .attr('class', 'change-type')
34896 .text(function(d) {
34897 return t('commit.' + d.changeType) + ' ';
34900 li.append('strong')
34901 .attr('class', 'entity-type')
34902 .text(function(d) {
34903 return context.presets().match(d.entity, d.graph).name();
34907 .attr('class', 'entity-name')
34908 .text(function(d) {
34909 var name = iD.util.displayName(d.entity) || '',
34911 if (name !== '') string += ':';
34912 return string += ' ' + name;
34915 li.style('opacity', 0)
34917 .style('opacity', 1);
34920 function mouseover(d) {
34922 context.surface().selectAll(
34923 iD.util.entityOrMemberSelector([d.entity.id], context.graph())
34924 ).classed('hover', true);
34928 function mouseout() {
34929 context.surface().selectAll('.hover')
34930 .classed('hover', false);
34933 function warningClick(d) {
34935 context.map().zoomTo(d.entity);
34937 iD.modes.Select(context, [d.entity.id])
34938 .suppressMenu(true));
34942 // Call checkComment off the bat, in case a changeset
34943 // comment is recovered from localStorage
34944 commentField.trigger('input');
34947 return d3.rebind(commit, dispatch, 'on');
34949 iD.ui.confirm = function(selection) {
34950 var modal = iD.ui.modal(selection);
34952 modal.select('.modal')
34953 .classed('modal-alert', true);
34955 var section = modal.select('.content');
34957 section.append('div')
34958 .attr('class', 'modal-section header');
34960 section.append('div')
34961 .attr('class', 'modal-section message-text');
34963 var buttons = section.append('div')
34964 .attr('class', 'modal-section buttons cf');
34966 modal.okButton = function() {
34969 .attr('class', 'action col4')
34970 .on('click.confirm', function() {
34973 .text(t('confirm.okay'));
34980 iD.ui.Conflicts = function(context) {
34981 var dispatch = d3.dispatch('download', 'cancel', 'save'),
34984 function conflicts(selection) {
34985 var header = selection
34987 .attr('class', 'header fillL');
34991 .attr('class', 'fr')
34992 .on('click', function() { dispatch.cancel(); })
34993 .call(iD.svg.Icon('#icon-close'));
34997 .text(t('save.conflict.header'));
34999 var body = selection
35001 .attr('class', 'body fillL');
35005 .attr('class', 'conflicts-help')
35006 .text(t('save.conflict.help'))
35008 .attr('class', 'conflicts-download')
35009 .text(t('save.conflict.download_changes'))
35010 .on('click.download', function() { dispatch.download(); });
35014 .attr('class', 'conflict-container fillL3')
35015 .call(showConflict, 0);
35019 .attr('class', 'conflicts-done')
35020 .attr('opacity', 0)
35021 .style('display', 'none')
35022 .text(t('save.conflict.done'));
35026 .attr('class','buttons col12 joined conflicts-buttons');
35030 .attr('disabled', list.length > 1)
35031 .attr('class', 'action conflicts-button col6')
35032 .text(t('save.title'))
35033 .on('click.try_again', function() { dispatch.save(); });
35037 .attr('class', 'secondary-action conflicts-button col6')
35038 .text(t('confirm.cancel'))
35039 .on('click.cancel', function() { dispatch.cancel(); });
35043 function showConflict(selection, index) {
35044 if (index < 0 || index >= list.length) return;
35046 var parent = d3.select(selection.node().parentNode);
35048 // enable save button if this is the last conflict being reviewed..
35049 if (index === list.length - 1) {
35050 window.setTimeout(function() {
35051 parent.select('.conflicts-button')
35052 .attr('disabled', null);
35054 parent.select('.conflicts-done')
35056 .attr('opacity', 1)
35057 .style('display', 'block');
35061 var item = selection
35062 .selectAll('.conflict')
35063 .data([list[index]]);
35065 var enter = item.enter()
35067 .attr('class', 'conflict');
35071 .attr('class', 'conflict-count')
35072 .text(t('save.conflict.count', { num: index + 1, total: list.length }));
35076 .attr('class', 'conflict-description')
35078 .text(function(d) { return d.name; })
35079 .on('click', function(d) {
35080 zoomToEntity(d.id);
35081 d3.event.preventDefault();
35084 var details = enter
35086 .attr('class', 'conflict-detail-container');
35090 .attr('class', 'conflict-detail-list')
35092 .data(function(d) { return d.details || []; })
35095 .attr('class', 'conflict-detail-item')
35096 .html(function(d) { return d; });
35100 .attr('class', 'conflict-choices')
35105 .attr('class', 'conflict-nav-buttons joined cf')
35106 .selectAll('button')
35107 .data(['previous', 'next'])
35110 .text(function(d) { return t('save.conflict.' + d); })
35111 .attr('class', 'conflict-nav-button action col6')
35112 .attr('disabled', function(d, i) {
35113 return (i === 0 && index === 0) ||
35114 (i === 1 && index === list.length - 1) || null;
35116 .on('click', function(d, i) {
35117 var container = parent.select('.conflict-container'),
35118 sign = (i === 0 ? -1 : 1);
35121 .selectAll('.conflict')
35125 .call(showConflict, index + sign);
35127 d3.event.preventDefault();
35135 function addChoices(selection) {
35136 var choices = selection
35138 .attr('class', 'layer-list')
35140 .data(function(d) { return d.choices || []; });
35142 var enter = choices.enter()
35144 .attr('class', 'layer');
35151 .attr('type', 'radio')
35152 .attr('name', function(d) { return d.id; })
35153 .on('change', function(d, i) {
35154 var ul = this.parentNode.parentNode.parentNode;
35155 ul.__data__.chosen = i;
35161 .text(function(d) { return d.text; });
35164 .each(function(d, i) {
35165 var ul = this.parentNode;
35166 if (ul.__data__.chosen === i) choose(ul, d);
35170 function choose(ul, datum) {
35171 if (d3.event) d3.event.preventDefault();
35175 .classed('active', function(d) { return d === datum; })
35176 .selectAll('input')
35177 .property('checked', function(d) { return d === datum; });
35179 var extent = iD.geo.Extent(),
35182 entity = context.graph().hasEntity(datum.id);
35183 if (entity) extent._extend(entity.extent(context.graph()));
35187 entity = context.graph().hasEntity(datum.id);
35188 if (entity) extent._extend(entity.extent(context.graph()));
35190 zoomToEntity(datum.id, extent);
35193 function zoomToEntity(id, extent) {
35194 context.surface().selectAll('.hover')
35195 .classed('hover', false);
35197 var entity = context.graph().hasEntity(id);
35200 context.map().trimmedExtent(extent);
35202 context.map().zoomTo(entity);
35204 context.surface().selectAll(
35205 iD.util.entityOrMemberSelector([entity.id], context.graph()))
35206 .classed('hover', true);
35211 // The conflict list should be an array of objects like:
35214 // name: entityName(local),
35215 // details: merge.conflicts(),
35218 // choice(id, keepMine, forceLocal),
35219 // choice(id, keepTheirs, forceRemote)
35222 conflicts.list = function(_) {
35223 if (!arguments.length) return list;
35228 return d3.rebind(conflicts, dispatch, 'on');
35230 iD.ui.Contributors = function(context) {
35231 var debouncedUpdate = _.debounce(function() { update(); }, 1000),
35234 wrap = d3.select(null);
35236 function update() {
35238 entities = context.intersects(context.map().extent());
35240 entities.forEach(function(entity) {
35241 if (entity && entity.user) users[entity.user] = true;
35244 var u = Object.keys(users),
35245 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
35248 .call(iD.svg.Icon('#icon-nearby', 'pre-text light'));
35250 var userList = d3.select(document.createElement('span'));
35252 userList.selectAll()
35256 .attr('class', 'user-link')
35257 .attr('href', function(d) { return context.connection().userURL(d); })
35258 .attr('target', '_blank')
35259 .attr('tabindex', -1)
35262 if (u.length > limit) {
35263 var count = d3.select(document.createElement('span'));
35266 .attr('target', '_blank')
35267 .attr('tabindex', -1)
35268 .attr('href', function() {
35269 return context.connection().changesetsURL(context.map().center(), context.map().zoom());
35271 .text(u.length - limit + 1);
35273 wrap.append('span')
35274 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
35277 wrap.append('span')
35278 .html(t('contributors.list', { users: userList.html() }));
35285 .style('opacity', 0);
35287 } else if (hidden) {
35290 .style('opacity', 1);
35294 return function(selection) {
35298 context.connection().on('loaded.contributors', debouncedUpdate);
35299 context.map().on('move.contributors', debouncedUpdate);
35302 iD.ui.Disclosure = function() {
35303 var dispatch = d3.dispatch('toggled'),
35306 content = function () {};
35308 var disclosure = function(selection) {
35309 var $link = selection.selectAll('.hide-toggle')
35312 $link.enter().append('a')
35314 .attr('class', 'hide-toggle');
35317 .on('click', toggle)
35318 .classed('expanded', expanded);
35320 var $body = selection.selectAll('div')
35323 $body.enter().append('div');
35325 $body.classed('hide', !expanded)
35328 function toggle() {
35329 expanded = !expanded;
35330 $link.classed('expanded', expanded);
35331 $body.call(iD.ui.Toggle(expanded));
35332 dispatch.toggled(expanded);
35336 disclosure.title = function(_) {
35337 if (!arguments.length) return title;
35342 disclosure.expanded = function(_) {
35343 if (!arguments.length) return expanded;
35348 disclosure.content = function(_) {
35349 if (!arguments.length) return content;
35354 return d3.rebind(disclosure, dispatch, 'on');
35356 iD.ui.EntityEditor = function(context) {
35357 var dispatch = d3.dispatch('choose'),
35359 coalesceChanges = false,
35366 var presetEditor = iD.ui.preset(context)
35367 .on('change', changeTags);
35368 var rawTagEditor = iD.ui.RawTagEditor(context)
35369 .on('change', changeTags);
35371 function entityEditor(selection) {
35372 var entity = context.entity(id),
35373 tags = _.clone(entity.tags);
35375 var $header = selection.selectAll('.header')
35379 var $enter = $header.enter().append('div')
35380 .attr('class', 'header fillL cf');
35382 $enter.append('button')
35383 .attr('class', 'fl preset-reset preset-choose')
35387 $enter.append('button')
35388 .attr('class', 'fr preset-close')
35389 .call(iD.svg.Icon(modified ? '#icon-apply' : '#icon-close'));
35391 $enter.append('h3');
35394 $header.select('h3')
35395 .text(t('inspector.edit'));
35397 $header.select('.preset-close')
35398 .on('click', function() {
35399 context.enter(iD.modes.Browse(context));
35402 var $body = selection.selectAll('.inspector-body')
35406 $enter = $body.enter().append('div')
35407 .attr('class', 'inspector-body');
35409 $enter.append('div')
35410 .attr('class', 'preset-list-item inspector-inner')
35412 .attr('class', 'preset-list-button-wrap')
35414 .attr('class', 'preset-list-button preset-reset')
35415 .call(bootstrap.tooltip()
35416 .title(t('inspector.back_tooltip'))
35417 .placement('bottom'))
35419 .attr('class', 'label');
35421 $body.select('.preset-list-button-wrap')
35422 .call(reference.button);
35424 $body.select('.preset-list-item')
35425 .call(reference.body);
35427 $enter.append('div')
35428 .attr('class', 'inspector-border inspector-preset');
35430 $enter.append('div')
35431 .attr('class', 'inspector-border raw-tag-editor inspector-inner');
35433 $enter.append('div')
35434 .attr('class', 'inspector-border raw-member-editor inspector-inner');
35436 $enter.append('div')
35437 .attr('class', 'raw-membership-editor inspector-inner');
35439 selection.selectAll('.preset-reset')
35440 .on('click', function() {
35441 dispatch.choose(preset);
35445 $body.select('.preset-list-item button')
35446 .call(iD.ui.PresetIcon()
35447 .geometry(context.geometry(id))
35450 $body.select('.preset-list-item .label')
35451 .text(preset.name());
35453 $body.select('.inspector-preset')
35460 $body.select('.raw-tag-editor')
35467 if (entity.type === 'relation') {
35468 $body.select('.raw-member-editor')
35469 .style('display', 'block')
35470 .call(iD.ui.RawMemberEditor(context)
35473 $body.select('.raw-member-editor')
35474 .style('display', 'none');
35477 $body.select('.raw-membership-editor')
35478 .call(iD.ui.RawMembershipEditor(context)
35481 function historyChanged() {
35482 if (state === 'hide') return;
35484 var entity = context.hasEntity(id),
35485 graph = context.graph();
35486 if (!entity) return;
35488 entityEditor.preset(context.presets().match(entity, graph));
35489 entityEditor.modified(base !== graph);
35490 entityEditor(selection);
35494 .on('change.entity-editor', historyChanged);
35497 function clean(o) {
35499 function cleanVal(k, v) {
35500 function keepSpaces(k) {
35501 var whitelist = ['opening_hours', 'service_times', 'collection_times',
35502 'operating_times', 'smoking_hours', 'happy_hours'];
35503 return _.some(whitelist, function(s) { return k.indexOf(s) !== -1; });
35506 var blacklist = ['description', 'note', 'fixme'];
35507 if (_.some(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
35509 var cleaned = v.split(';')
35510 .map(function(s) { return s.trim(); })
35511 .join(keepSpaces(k) ? '; ' : ';');
35513 // The code below is not intended to validate websites and emails.
35514 // It is only intended to prevent obvious copy-paste errors. (#2323)
35516 // clean website- and email-like tags
35517 if (k.indexOf('website') !== -1 ||
35518 k.indexOf('email') !== -1 ||
35519 cleaned.indexOf('http') === 0) {
35521 .replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
35528 var out = {}, k, v;
35530 if (k && (v = o[k]) !== undefined) {
35531 out[k] = cleanVal(k, v);
35537 // Tag changes that fire on input can all get coalesced into a single
35538 // history operation when the user leaves the field. #2342
35539 function changeTags(changed, onInput) {
35540 var entity = context.entity(id),
35541 annotation = t('operations.change_tags.annotation'),
35542 tags = _.extend({}, entity.tags, changed);
35545 tags = clean(tags);
35547 if (!_.isEqual(entity.tags, tags)) {
35548 if (coalesceChanges) {
35549 context.overwrite(iD.actions.ChangeTags(id, tags), annotation);
35551 context.perform(iD.actions.ChangeTags(id, tags), annotation);
35552 coalesceChanges = !!onInput;
35557 entityEditor.modified = function(_) {
35558 if (!arguments.length) return modified;
35560 d3.selectAll('button.preset-close use')
35561 .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
35564 entityEditor.state = function(_) {
35565 if (!arguments.length) return state;
35567 return entityEditor;
35570 entityEditor.entityID = function(_) {
35571 if (!arguments.length) return id;
35573 base = context.graph();
35574 entityEditor.preset(context.presets().match(context.entity(id), base));
35575 entityEditor.modified(false);
35576 coalesceChanges = false;
35577 return entityEditor;
35580 entityEditor.preset = function(_) {
35581 if (!arguments.length) return preset;
35582 if (_ !== preset) {
35584 reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context)
35587 return entityEditor;
35590 return d3.rebind(entityEditor, dispatch, 'on');
35592 iD.ui.FeatureInfo = function(context) {
35593 function update(selection) {
35594 var features = context.features(),
35595 stats = features.stats(),
35597 hiddenList = _.compact(_.map(features.hidden(), function(k) {
35600 return String(stats[k]) + ' ' + t('feature.' + k + '.description');
35604 selection.html('');
35606 if (hiddenList.length) {
35607 var tooltip = bootstrap.tooltip()
35610 .title(function() {
35611 return iD.ui.tooltipHtml(hiddenList.join('<br/>'));
35614 var warning = selection.append('a')
35616 .attr('tabindex', -1)
35617 .html(t('feature_info.hidden_warning', { count: count }))
35619 .on('click', function() {
35620 tooltip.hide(warning);
35621 // open map data panel?
35622 d3.event.preventDefault();
35627 .classed('hide', !hiddenList.length);
35630 return function(selection) {
35633 context.features().on('change.feature_info', function() {
35638 iD.ui.FeatureList = function(context) {
35639 var geocodeResults;
35641 function featureList(selection) {
35642 var header = selection.append('div')
35643 .attr('class', 'header fillL cf');
35645 header.append('h3')
35646 .text(t('inspector.feature_list'));
35648 function keypress() {
35649 var q = search.property('value'),
35650 items = list.selectAll('.feature-list-item');
35651 if (d3.event.keyCode === 13 && q.length && items.size()) {
35652 click(items.datum());
35656 function inputevent() {
35657 geocodeResults = undefined;
35661 var searchWrap = selection.append('div')
35662 .attr('class', 'search-header');
35664 var search = searchWrap.append('input')
35665 .attr('placeholder', t('inspector.search'))
35666 .attr('type', 'search')
35667 .on('keypress', keypress)
35668 .on('input', inputevent);
35671 .call(iD.svg.Icon('#icon-search', 'pre-text'));
35673 var listWrap = selection.append('div')
35674 .attr('class', 'inspector-body');
35676 var list = listWrap.append('div')
35677 .attr('class', 'feature-list cf');
35680 .on('exit.feature-list', clearSearch);
35682 .on('drawn.feature-list', mapDrawn);
35684 function clearSearch() {
35685 search.property('value', '');
35689 function mapDrawn(e) {
35695 function features() {
35698 graph = context.graph(),
35699 q = search.property('value').toLowerCase();
35701 if (!q) return result;
35703 var idMatch = q.match(/^([nwr])([0-9]+)$/);
35708 geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
35709 type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
35714 var locationMatch = sexagesimal.pair(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
35716 if (locationMatch) {
35717 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
35721 type: t('inspector.location'),
35722 name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
35727 function addEntity(entity) {
35728 if (entity.id in entities || result.length > 200)
35731 entities[entity.id] = true;
35733 var name = iD.util.displayName(entity) || '';
35734 if (name.toLowerCase().indexOf(q) >= 0) {
35738 geometry: context.geometry(entity.id),
35739 type: context.presets().match(entity, graph).name(),
35744 graph.parentRelations(entity).forEach(function(parent) {
35749 var visible = context.surface().selectAll('.point, .line, .area')[0];
35750 for (var i = 0; i < visible.length && result.length <= 200; i++) {
35751 addEntity(visible[i].__data__);
35754 (geocodeResults || []).forEach(function(d) {
35755 // https://github.com/openstreetmap/iD/issues/1890
35756 if (d.osm_type && d.osm_id) {
35758 id: iD.Entity.id.fromOSM(d.osm_type, d.osm_id),
35759 geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
35760 type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
35761 : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
35762 name: d.display_name,
35763 extent: new iD.geo.Extent(
35764 [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
35765 [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
35773 function drawList() {
35774 var value = search.property('value'),
35775 results = features();
35777 list.classed('filtered', value.length);
35779 var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
35781 var resultsIndicator = list.selectAll('.no-results-item')
35783 .enter().append('button')
35784 .property('disabled', true)
35785 .attr('class', 'no-results-item')
35786 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
35788 resultsIndicator.append('span')
35789 .attr('class', 'entity-name');
35791 list.selectAll('.no-results-item .entity-name')
35792 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
35794 list.selectAll('.geocode-item')
35796 .enter().append('button')
35797 .attr('class', 'geocode-item')
35798 .on('click', geocode)
35800 .attr('class', 'label')
35802 .attr('class', 'entity-name')
35803 .text(t('geocoder.search'));
35805 list.selectAll('.no-results-item')
35806 .style('display', (value.length && !results.length) ? 'block' : 'none');
35808 list.selectAll('.geocode-item')
35809 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
35811 list.selectAll('.feature-list-item')
35815 var items = list.selectAll('.feature-list-item')
35816 .data(results, function(d) { return d.id; });
35818 var enter = items.enter()
35819 .insert('button', '.geocode-item')
35820 .attr('class', 'feature-list-item')
35821 .on('mouseover', mouseover)
35822 .on('mouseout', mouseout)
35823 .on('click', click);
35827 .attr('class', 'label');
35829 label.each(function(d) {
35831 .call(iD.svg.Icon('#icon-' + d.geometry, 'pre-text'));
35834 label.append('span')
35835 .attr('class', 'entity-type')
35836 .text(function(d) { return d.type; });
35838 label.append('span')
35839 .attr('class', 'entity-name')
35840 .text(function(d) { return d.name; });
35842 enter.style('opacity', 0)
35844 .style('opacity', 1);
35852 function mouseover(d) {
35853 if (d.id === -1) return;
35855 context.surface().selectAll(iD.util.entityOrMemberSelector([d.id], context.graph()))
35856 .classed('hover', true);
35859 function mouseout() {
35860 context.surface().selectAll('.hover')
35861 .classed('hover', false);
35864 function click(d) {
35865 d3.event.preventDefault();
35867 context.map().centerZoom([d.location[1], d.location[0]], 20);
35869 else if (d.entity) {
35870 if (d.entity.type === 'node') {
35871 context.map().center(d.entity.loc);
35872 } else if (d.entity.type === 'way') {
35873 var center = context.projection(context.map().center()),
35874 edge = iD.geo.chooseEdge(context.childNodes(d.entity), center, context.projection);
35875 context.map().center(edge.loc);
35877 context.enter(iD.modes.Select(context, [d.entity.id]).suppressMenu(true));
35879 context.zoomToEntity(d.id);
35883 function geocode() {
35884 var searchVal = encodeURIComponent(search.property('value'));
35885 d3.json('https://nominatim.openstreetmap.org/search/' + searchVal + '?limit=10&format=json', function(err, resp) {
35886 geocodeResults = resp || [];
35892 return featureList;
35894 iD.ui.flash = function(selection) {
35895 var modal = iD.ui.modal(selection);
35897 modal.select('.modal').classed('modal-flash', true);
35899 modal.select('.content')
35900 .classed('modal-section', true)
35902 .attr('class', 'description');
35904 modal.on('click.flash', function() { modal.remove(); });
35906 setTimeout(function() {
35913 iD.ui.FullScreen = function(context) {
35914 var element = context.container().node(),
35915 keybinding = d3.keybinding('full-screen');
35918 function getFullScreenFn() {
35919 if (element.requestFullscreen) {
35920 return element.requestFullscreen;
35921 } else if (element.msRequestFullscreen) {
35922 return element.msRequestFullscreen;
35923 } else if (element.mozRequestFullScreen) {
35924 return element.mozRequestFullScreen;
35925 } else if (element.webkitRequestFullscreen) {
35926 return element.webkitRequestFullscreen;
35930 function getExitFullScreenFn() {
35931 if (document.exitFullscreen) {
35932 return document.exitFullscreen;
35933 } else if (document.msExitFullscreen) {
35934 return document.msExitFullscreen;
35935 } else if (document.mozCancelFullScreen) {
35936 return document.mozCancelFullScreen;
35937 } else if (document.webkitExitFullscreen) {
35938 return document.webkitExitFullscreen;
35942 function isFullScreen() {
35943 return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement ||
35944 document.msFullscreenElement;
35947 function isSupported() {
35948 return !!getFullScreenFn();
35951 function fullScreen() {
35952 d3.event.preventDefault();
35953 if (!isFullScreen()) {
35954 // button.classed('active', true);
35955 getFullScreenFn().apply(element);
35957 // button.classed('active', false);
35958 getExitFullScreenFn().apply(document);
35962 return function() { // selection) {
35963 if (!isSupported())
35966 // var tooltip = bootstrap.tooltip()
35967 // .placement('left');
35969 // button = selection.append('button')
35970 // .attr('title', t('full_screen'))
35971 // .attr('tabindex', -1)
35972 // .on('click', fullScreen)
35975 // button.append('span')
35976 // .attr('class', 'icon full-screen');
35979 .on('f11', fullScreen)
35980 .on(iD.ui.cmd('⌘⇧F'), fullScreen);
35982 d3.select(document)
35986 iD.ui.Geolocate = function(context) {
35987 var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
35988 locating = iD.ui.Loading(context).message(t('geolocate.locating')).blocking(true),
35992 context.enter(iD.modes.Browse(context));
35993 context.container().call(locating);
35994 navigator.geolocation.getCurrentPosition(success, error, geoOptions);
35996 // This timeout ensures that we still call finish() even if
35997 // the user declines to share their location in Firefox
35998 timeoutId = setTimeout(finish, 10000 /* 10sec */ );
36001 function success(position) {
36002 var map = context.map(),
36003 extent = iD.geo.Extent([position.coords.longitude, position.coords.latitude])
36004 .padByMeters(position.coords.accuracy);
36006 map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
36014 function finish() {
36015 locating.close(); // unblock ui
36016 if (timeoutId) { clearTimeout(timeoutId); }
36017 timeoutId = undefined;
36020 return function(selection) {
36021 if (!navigator.geolocation) return;
36023 selection.append('button')
36024 .attr('tabindex', -1)
36025 .attr('title', t('geolocate.title'))
36026 .on('click', click)
36027 .call(iD.svg.Icon('#icon-geolocate', 'light'))
36028 .call(bootstrap.tooltip()
36029 .placement('left'));
36032 iD.ui.Help = function(context) {
36037 'help.editing_saving',
36046 var docs = docKeys.map(function(key) {
36049 title: text.split('\n')[0].replace('#', '').trim(),
36050 html: marked(text.split('\n').slice(1).join('\n'))
36054 function help(selection) {
36060 function toggle() {
36061 if (d3.event) d3.event.preventDefault();
36062 tooltip.hide(button);
36063 setVisible(!button.classed('active'));
36066 function setVisible(show) {
36067 if (show !== shown) {
36068 button.classed('active', show);
36072 selection.on('mousedown.help-inside', function() {
36073 return d3.event.stopPropagation();
36075 pane.style('display', 'block')
36076 .style('right', '-500px')
36079 .style('right', '0px');
36081 pane.style('right', '0px')
36084 .style('right', '-500px')
36085 .each('end', function() {
36086 d3.select(this).style('display', 'none');
36088 selection.on('mousedown.help-inside', null);
36093 function clickHelp(d, i) {
36094 pane.property('scrollTop', 0);
36095 doctitle.html(d.title);
36097 body.selectAll('a')
36098 .attr('target', '_blank');
36099 menuItems.classed('selected', function(m) {
36100 return m.title === d.title;
36106 var prevLink = nav.append('a')
36107 .attr('class', 'previous')
36108 .on('click', function() {
36109 clickHelp(docs[i - 1], i - 1);
36111 prevLink.append('span').html('◄ ' + docs[i - 1].title);
36113 if (i < docs.length - 1) {
36114 var nextLink = nav.append('a')
36115 .attr('class', 'next')
36116 .on('click', function() {
36117 clickHelp(docs[i + 1], i + 1);
36119 nextLink.append('span').html(docs[i + 1].title + ' ►');
36123 function clickWalkthrough() {
36124 d3.select(document.body).call(iD.ui.intro(context));
36129 var pane = selection.append('div')
36130 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
36131 tooltip = bootstrap.tooltip()
36134 .title(iD.ui.tooltipHtml(t('help.title'), key)),
36135 button = selection.append('button')
36136 .attr('tabindex', -1)
36137 .on('click', toggle)
36138 .call(iD.svg.Icon('#icon-help', 'light'))
36143 var toc = pane.append('ul')
36144 .attr('class', 'toc');
36146 var menuItems = toc.selectAll('li')
36151 .html(function(d) { return d.title; })
36152 .on('click', clickHelp);
36155 .attr('class','walkthrough')
36157 .text(t('splash.walkthrough'))
36158 .on('click', clickWalkthrough);
36160 var content = pane.append('div')
36161 .attr('class', 'left-content');
36163 var doctitle = content.append('h2')
36164 .text(t('help.title'));
36166 var body = content.append('div')
36167 .attr('class', 'body');
36169 var nav = content.append('div')
36170 .attr('class', 'nav');
36172 clickHelp(docs[0], 0);
36174 var keybinding = d3.keybinding('help')
36179 d3.select(document)
36182 context.surface().on('mousedown.help-outside', hide);
36183 context.container().on('mousedown.help-outside', hide);
36188 iD.ui.Info = function(context) {
36189 var key = iD.ui.cmd('⌘I'),
36190 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
36193 function info(selection) {
36194 function radiansToMeters(r) {
36195 // using WGS84 authalic radius (6371007.1809 m)
36196 return r * 6371007.1809;
36199 function steradiansToSqmeters(r) {
36200 // http://gis.stackexchange.com/a/124857/40446
36201 return r / 12.56637 * 510065621724000;
36204 function toLineString(feature) {
36205 if (feature.type === 'LineString') return feature;
36207 var result = { type: 'LineString', coordinates: [] };
36208 if (feature.type === 'Polygon') {
36209 result.coordinates = feature.coordinates[0];
36210 } else if (feature.type === 'MultiPolygon') {
36211 result.coordinates = feature.coordinates[0][0];
36217 function displayLength(m) {
36218 var d = m * (imperial ? 3.28084 : 1),
36237 // drop unnecessary precision
36238 p = d > 1000 ? 0 : d > 100 ? 1 : 2;
36240 return String(d.toFixed(p)) + ' ' + unit;
36243 function displayArea(m2) {
36244 var d = m2 * (imperial ? 10.7639111056 : 1),
36245 d1, d2, p1, p2, unit1, unit2;
36248 if (d >= 6969600) { // > 0.25mi² show mi²
36256 if (d > 4356 && d < 43560000) { // 0.1 - 1000 acres
36262 if (d >= 250000) { // > 0.25km² show km²
36270 if (d > 1000 && d < 10000000) { // 0.1 - 1000 hectares
36276 // drop unnecessary precision
36277 p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
36278 p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
36280 return String(d1.toFixed(p1)) + ' ' + unit1 +
36281 (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
36285 function redraw() {
36286 if (hidden) return;
36288 var resolver = context.graph(),
36289 selected = _.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
36290 singular = selected.length === 1 ? selected[0] : null,
36291 extent = iD.geo.Extent(),
36296 .attr('class', 'infobox-heading fillD')
36297 .text(singular || t('infobox.selected', { n: selected.length }));
36299 if (!selected.length) return;
36302 for (var i = 0; i < selected.length; i++) {
36303 entity = context.entity(selected[i]);
36304 extent._extend(entity.extent(resolver));
36306 center = extent.center();
36309 var list = wrap.append('ul');
36311 // multiple wrap, just display extent center..
36314 .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
36318 // single wrap, display details..
36319 if (!entity) return;
36320 var geometry = entity.geometry(resolver);
36322 if (geometry === 'line' || geometry === 'area') {
36323 var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
36324 feature = entity.asGeoJSON(resolver),
36325 length = radiansToMeters(d3.geo.length(toLineString(feature))),
36326 lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')),
36327 centroid = d3.geo.centroid(feature);
36330 .text(t('infobox.geometry') + ': ' +
36331 (closed ? t('infobox.closed') + ' ' : '') + t('geometry.' + geometry) );
36334 var area = steradiansToSqmeters(entity.area(resolver));
36336 .text(t('infobox.area') + ': ' + displayArea(area));
36340 .text(lengthLabel + ': ' + displayLength(length));
36343 .text(t('infobox.centroid') + ': ' + centroid[0].toFixed(5) + ', ' + centroid[1].toFixed(5));
36346 var toggle = imperial ? 'imperial' : 'metric';
36348 .text(t('infobox.' + toggle))
36350 .attr('class', 'button')
36351 .on('click', function() {
36352 d3.event.preventDefault();
36353 imperial = !imperial;
36358 var centerLabel = t('infobox.' + (entity.type === 'node' ? 'location' : 'center'));
36361 .text(t('infobox.geometry') + ': ' + t('geometry.' + geometry));
36364 .text(centerLabel + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
36369 function toggle() {
36370 if (d3.event) d3.event.preventDefault();
36376 .style('display', 'block')
36377 .style('opacity', 1)
36380 .style('opacity', 0)
36381 .each('end', function() {
36382 d3.select(this).style('display', 'none');
36386 .style('display', 'block')
36387 .style('opacity', 0)
36390 .style('opacity', 1);
36397 var wrap = selection.selectAll('.infobox')
36402 .attr('class', 'infobox fillD2')
36403 .style('display', (hidden ? 'none' : 'block'));
36406 .on('drawn.info', redraw);
36410 var keybinding = d3.keybinding('info')
36413 d3.select(document)
36419 iD.ui.Inspector = function(context) {
36420 var presetList = iD.ui.PresetList(context),
36421 entityEditor = iD.ui.EntityEditor(context),
36424 newFeature = false;
36426 function inspector(selection) {
36428 .entityID(entityID)
36429 .autofocus(newFeature)
36430 .on('choose', setPreset);
36434 .entityID(entityID)
36435 .on('choose', showList);
36437 var $wrap = selection.selectAll('.panewrap')
36440 var $enter = $wrap.enter().append('div')
36441 .attr('class', 'panewrap');
36443 $enter.append('div')
36444 .attr('class', 'preset-list-pane pane');
36446 $enter.append('div')
36447 .attr('class', 'entity-editor-pane pane');
36449 var $presetPane = $wrap.select('.preset-list-pane');
36450 var $editorPane = $wrap.select('.entity-editor-pane');
36452 var graph = context.graph(),
36453 entity = context.entity(entityID),
36454 showEditor = state === 'hover' ||
36455 entity.isUsed(graph) ||
36456 entity.isHighwayIntersection(graph);
36459 $wrap.style('right', '0%');
36460 $editorPane.call(entityEditor);
36462 $wrap.style('right', '-100%');
36463 $presetPane.call(presetList);
36466 var $footer = selection.selectAll('.footer')
36469 $footer.enter().append('div')
36470 .attr('class', 'footer');
36472 selection.select('.footer')
36473 .call(iD.ui.ViewOnOSM(context)
36474 .entityID(entityID));
36476 function showList(preset) {
36478 .styleTween('right', function() { return d3.interpolate('0%', '-100%'); });
36480 $presetPane.call(presetList
36485 function setPreset(preset) {
36487 .styleTween('right', function() { return d3.interpolate('-100%', '0%'); });
36489 $editorPane.call(entityEditor
36494 inspector.state = function(_) {
36495 if (!arguments.length) return state;
36497 entityEditor.state(state);
36501 inspector.entityID = function(_) {
36502 if (!arguments.length) return entityID;
36507 inspector.newFeature = function(_) {
36508 if (!arguments.length) return newFeature;
36515 iD.ui.intro = function(context) {
36518 function intro(selection) {
36520 function localizedName(id) {
36522 n2140018997: 'city_hall',
36523 n367813436: 'fire_department',
36524 w203988286: 'memory_isle_park',
36525 w203972937: 'riverwalk_trail',
36526 w203972938: 'riverwalk_trail',
36527 w203972940: 'riverwalk_trail',
36528 w41785752: 'w_michigan_ave',
36529 w134150789: 'w_michigan_ave',
36530 w134150795: 'w_michigan_ave',
36531 w134150800: 'w_michigan_ave',
36532 w134150811: 'w_michigan_ave',
36533 w134150802: 'e_michigan_ave',
36534 w134150836: 'e_michigan_ave',
36535 w41074896: 'e_michigan_ave',
36536 w17965834: 'spring_st',
36537 w203986457: 'scidmore_park',
36538 w203049587: 'petting_zoo',
36539 w17967397: 'n_andrews_st',
36540 w17967315: 's_andrews_st',
36541 w17967326: 'n_constantine_st',
36542 w17966400: 's_constantine_st',
36543 w170848823: 'rocky_river',
36544 w170848824: 'rocky_river',
36545 w170848331: 'rocky_river',
36546 w17967752: 'railroad_dr',
36547 w17965998: 'conrail_rr',
36548 w134150845: 'conrail_rr',
36549 w170989131: 'st_joseph_river',
36550 w143497377: 'n_main_st',
36551 w134150801: 's_main_st',
36552 w134150830: 's_main_st',
36553 w17966462: 's_main_st',
36554 w17967734: 'water_st',
36555 w17964996: 'foster_st',
36556 w170848330: 'portage_river',
36557 w17965351: 'flower_st',
36558 w17965502: 'elm_st',
36559 w17965402: 'walnut_st',
36560 w17964793: 'morris_ave',
36561 w17967444: 'east_st',
36562 w17966984: 'portage_ave'
36564 return features[id] && t('intro.graph.' + features[id]);
36567 context.enter(iD.modes.Browse(context));
36569 // Save current map state
36570 var history = context.history().toJSON(),
36571 hash = window.location.hash,
36572 center = context.map().center(),
36573 zoom = context.map().zoom(),
36574 background = context.background().baseLayerSource(),
36575 opacity = d3.selectAll('#map .layer-background').style('opacity'),
36576 loadedTiles = context.connection().loadedTiles(),
36577 baseEntities = context.history().graph().base().entities,
36581 context.inIntro(true);
36583 // Load semi-real data used in intro
36584 context.connection().toggle(false).flush();
36585 context.history().reset();
36587 introGraph = JSON.parse(iD.introGraph);
36588 for (var key in introGraph) {
36589 introGraph[key] = iD.Entity(introGraph[key]);
36590 name = localizedName(key);
36592 introGraph[key].tags.name = name;
36595 context.history().merge(d3.values(iD.Graph().load(introGraph).entities));
36596 context.background().bing();
36598 d3.selectAll('#map .layer-background').style('opacity', 1);
36600 var curtain = d3.curtain();
36601 selection.call(curtain);
36603 function reveal(box, text, options) {
36604 options = options || {};
36605 if (text) curtain.reveal(box, text, options.tooltipClass, options.duration);
36606 else curtain.reveal(box, '', '', options.duration);
36609 var steps = ['navigation', 'point', 'area', 'line', 'startEditing'].map(function(step, i) {
36610 var s = iD.ui.intro[step](context, reveal)
36611 .on('done', function() {
36612 entered.filter(function(d) {
36613 return d.title === s.title;
36614 }).classed('finished', true);
36615 enter(steps[i + 1]);
36620 steps[steps.length - 1].on('startEditing', function() {
36623 d3.selectAll('#map .layer-background').style('opacity', opacity);
36624 context.connection().toggle(true).flush().loadedTiles(loadedTiles);
36625 context.history().reset().merge(d3.values(baseEntities));
36626 context.background().baseLayerSource(background);
36627 if (history) context.history().fromJSON(history, false);
36628 context.map().centerZoom(center, zoom);
36629 window.location.replace(hash);
36630 context.inIntro(false);
36633 var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
36635 var buttonwrap = navwrap.append('div')
36636 .attr('class', 'joined')
36637 .selectAll('button.step');
36639 var entered = buttonwrap
36643 .attr('class', 'step')
36644 .on('click', enter);
36647 .call(iD.svg.Icon('#icon-apply', 'pre-text'));
36651 .text(function(d) { return t(d.title); });
36655 function enter (newStep) {
36656 if (step) { step.exit(); }
36658 context.enter(iD.modes.Browse(context));
36663 entered.classed('active', function(d) {
36664 return d.title === step.title;
36672 iD.ui.intro.pointBox = function(point, context) {
36673 var rect = context.surfaceRect();
36674 point = context.projection(point);
36676 left: point[0] + rect.left - 30,
36677 top: point[1] + rect.top - 50,
36683 iD.ui.intro.pad = function(box, padding, context) {
36684 if (box instanceof Array) {
36685 var rect = context.surfaceRect();
36686 box = context.projection(box);
36688 left: box[0] + rect.left,
36689 top: box[1] + rect.top
36693 left: box.left - padding,
36694 top: box.top - padding,
36695 width: (box.width || 0) + 2 * padding,
36696 height: (box.width || 0) + 2 * padding
36700 iD.ui.intro.icon = function(name, svgklass) {
36701 return '<svg class="icon ' + (svgklass || '') + '">' +
36702 '<use xlink:href="' + name + '"></use></svg>';
36704 iD.ui.Lasso = function(context) {
36705 var group, polygon;
36707 lasso.coordinates = [];
36709 function lasso(selection) {
36711 context.container().classed('lasso', true);
36713 group = selection.append('g')
36714 .attr('class', 'lasso hide');
36716 polygon = group.append('path')
36717 .attr('class', 'lasso-path');
36719 group.call(iD.ui.Toggle(true));
36725 polygon.data([lasso.coordinates])
36726 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
36730 lasso.extent = function () {
36731 return lasso.coordinates.reduce(function(extent, point) {
36732 return extent.extend(iD.geo.Extent(point));
36733 }, iD.geo.Extent());
36736 lasso.p = function(_) {
36737 if (!arguments.length) return lasso;
36738 lasso.coordinates.push(_);
36743 lasso.close = function() {
36745 group.call(iD.ui.Toggle(false, function() {
36746 d3.select(this).remove();
36749 context.container().classed('lasso', false);
36754 iD.ui.Loading = function(context) {
36759 var loading = function(selection) {
36760 modal = iD.ui.modal(selection, blocking);
36762 var loadertext = modal.select('.content')
36763 .classed('loading-modal', true)
36765 .attr('class', 'modal-section fillL');
36767 loadertext.append('img')
36768 .attr('class', 'loader')
36769 .attr('src', context.imagePath('loader-white.gif'));
36771 loadertext.append('h3')
36774 modal.select('button.close')
36775 .attr('class', 'hide');
36780 loading.message = function(_) {
36781 if (!arguments.length) return message;
36786 loading.blocking = function(_) {
36787 if (!arguments.length) return blocking;
36792 loading.close = function() {
36798 iD.ui.MapData = function(context) {
36800 features = context.features().keys(),
36801 layers = context.layers(),
36802 fills = ['wireframe', 'partial', 'full'],
36803 fillDefault = context.storage('area-fill') || 'partial',
36804 fillSelected = fillDefault;
36807 function map_data(selection) {
36809 function showsFeature(d) {
36810 return context.features().enabled(d);
36813 function autoHiddenFeature(d) {
36814 return context.features().autoHidden(d);
36817 function clickFeature(d) {
36818 context.features().toggle(d);
36822 function showsFill(d) {
36823 return fillSelected === d;
36826 function setFill(d) {
36827 _.each(fills, function(opt) {
36828 context.surface().classed('fill-' + opt, Boolean(opt === d));
36832 if (d !== 'wireframe') {
36834 context.storage('area-fill', d);
36839 function showsLayer(which) {
36840 var layer = layers.layer(which);
36842 return layer.enabled();
36847 function setLayer(which, enabled) {
36848 var layer = layers.layer(which);
36850 layer.enabled(enabled);
36855 function toggleLayer(which) {
36856 setLayer(which, !showsLayer(which));
36859 function clickGpx() {
36860 toggleLayer('gpx');
36863 function clickMapillaryImages() {
36864 toggleLayer('mapillary-images');
36865 if (!showsLayer('mapillary-images')) {
36866 setLayer('mapillary-signs', false);
36870 function clickMapillarySigns() {
36871 toggleLayer('mapillary-signs');
36875 function drawMapillaryItems(selection) {
36876 var mapillaryImages = layers.layer('mapillary-images'),
36877 mapillarySigns = layers.layer('mapillary-signs'),
36878 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
36879 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
36880 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
36881 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
36883 var mapillaryList = selection
36884 .selectAll('.layer-list-mapillary')
36891 .attr('class', 'layer-list layer-list-mapillary');
36893 var mapillaryImageLayerItem = mapillaryList
36894 .selectAll('.list-item-mapillary-images')
36895 .data(supportsMapillaryImages ? [0] : []);
36897 var enterImages = mapillaryImageLayerItem.enter()
36899 .attr('class', 'list-item-mapillary-images');
36901 var labelImages = enterImages.append('label')
36902 .call(bootstrap.tooltip()
36903 .title(t('mapillary_images.tooltip'))
36904 .placement('top'));
36906 labelImages.append('input')
36907 .attr('type', 'checkbox')
36908 .on('change', clickMapillaryImages);
36910 labelImages.append('span')
36911 .text(t('mapillary_images.title'));
36914 var mapillarySignLayerItem = mapillaryList
36915 .selectAll('.list-item-mapillary-signs')
36916 .data(supportsMapillarySigns ? [0] : []);
36918 var enterSigns = mapillarySignLayerItem.enter()
36920 .attr('class', 'list-item-mapillary-signs');
36922 var labelSigns = enterSigns.append('label')
36923 .call(bootstrap.tooltip()
36924 .title(t('mapillary_signs.tooltip'))
36925 .placement('top'));
36927 labelSigns.append('input')
36928 .attr('type', 'checkbox')
36929 .on('change', clickMapillarySigns);
36931 labelSigns.append('span')
36932 .text(t('mapillary_signs.title'));
36935 mapillaryImageLayerItem
36936 .classed('active', showsMapillaryImages)
36937 .selectAll('input')
36938 .property('checked', showsMapillaryImages);
36940 mapillarySignLayerItem
36941 .classed('active', showsMapillarySigns)
36942 .selectAll('input')
36943 .property('disabled', !showsMapillaryImages)
36944 .property('checked', showsMapillarySigns);
36946 mapillarySignLayerItem
36947 .selectAll('label')
36948 .classed('deemphasize', !showsMapillaryImages);
36951 mapillaryImageLayerItem.exit()
36953 mapillarySignLayerItem.exit()
36958 function drawGpxItem(selection) {
36959 var gpx = layers.layer('gpx'),
36960 hasGpx = gpx && gpx.hasGpx(),
36961 showsGpx = hasGpx && gpx.enabled();
36963 var gpxLayerItem = selection
36964 .selectAll('.layer-list-gpx')
36965 .data(gpx ? [0] : []);
36968 var enter = gpxLayerItem.enter()
36970 .attr('class', 'layer-list layer-list-gpx')
36972 .classed('list-item-gpx', true);
36974 enter.append('button')
36975 .attr('class', 'list-item-gpx-extent')
36976 .call(bootstrap.tooltip()
36977 .title(t('gpx.zoom'))
36978 .placement('left'))
36979 .on('click', function() {
36980 d3.event.preventDefault();
36981 d3.event.stopPropagation();
36984 .call(iD.svg.Icon('#icon-search'));
36986 enter.append('button')
36987 .attr('class', 'list-item-gpx-browse')
36988 .call(bootstrap.tooltip()
36989 .title(t('gpx.browse'))
36990 .placement('left'))
36991 .on('click', function() {
36992 d3.select(document.createElement('input'))
36993 .attr('type', 'file')
36994 .on('change', function() {
36995 gpx.files(d3.event.target.files);
36999 .call(iD.svg.Icon('#icon-geolocate'));
37001 var labelGpx = enter.append('label')
37002 .call(bootstrap.tooltip()
37003 .title(t('gpx.drag_drop'))
37004 .placement('top'));
37006 labelGpx.append('input')
37007 .attr('type', 'checkbox')
37008 .on('change', clickGpx);
37010 labelGpx.append('span')
37011 .text(t('gpx.local_layer'));
37015 .classed('active', showsGpx)
37016 .selectAll('input')
37017 .property('disabled', !hasGpx)
37018 .property('checked', showsGpx);
37021 .selectAll('label')
37022 .classed('deemphasize', !hasGpx);
37025 gpxLayerItem.exit()
37030 function drawList(selection, data, type, name, change, active) {
37031 var items = selection.selectAll('li')
37035 var enter = items.enter()
37037 .attr('class', 'layer')
37038 .call(bootstrap.tooltip()
37040 .title(function(d) {
37041 var tip = t(name + '.' + d + '.tooltip'),
37042 key = (d === 'wireframe' ? 'W' : null);
37044 if (name === 'feature' && autoHiddenFeature(d)) {
37045 tip += '<div>' + t('map_data.autohidden') + '</div>';
37047 return iD.ui.tooltipHtml(tip, key);
37052 var label = enter.append('label');
37054 label.append('input')
37055 .attr('type', type)
37056 .attr('name', name)
37057 .on('change', change);
37059 label.append('span')
37060 .text(function(d) { return t(name + '.' + d + '.description'); });
37064 .classed('active', active)
37065 .selectAll('input')
37066 .property('checked', active)
37067 .property('indeterminate', function(d) {
37068 return (name === 'feature' && autoHiddenFeature(d));
37077 function update() {
37078 dataLayerContainer.call(drawMapillaryItems);
37079 dataLayerContainer.call(drawGpxItem);
37081 fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
37083 featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
37086 function hidePanel() {
37090 function togglePanel() {
37091 if (d3.event) d3.event.preventDefault();
37092 tooltip.hide(button);
37093 setVisible(!button.classed('active'));
37096 function toggleWireframe() {
37098 d3.event.preventDefault();
37099 d3.event.stopPropagation();
37101 setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
37102 context.map().pan([0,0]); // trigger a redraw
37105 function setVisible(show) {
37106 if (show !== shown) {
37107 button.classed('active', show);
37112 selection.on('mousedown.map_data-inside', function() {
37113 return d3.event.stopPropagation();
37115 content.style('display', 'block')
37116 .style('right', '-300px')
37119 .style('right', '0px');
37121 content.style('display', 'block')
37122 .style('right', '0px')
37125 .style('right', '-300px')
37126 .each('end', function() {
37127 d3.select(this).style('display', 'none');
37129 selection.on('mousedown.map_data-inside', null);
37135 var content = selection.append('div')
37136 .attr('class', 'fillL map-overlay col3 content hide'),
37137 tooltip = bootstrap.tooltip()
37140 .title(iD.ui.tooltipHtml(t('map_data.description'), key)),
37141 button = selection.append('button')
37142 .attr('tabindex', -1)
37143 .on('click', togglePanel)
37144 .call(iD.svg.Icon('#icon-data', 'light'))
37148 content.append('h4')
37149 .text(t('map_data.title'));
37153 content.append('a')
37154 .text(t('map_data.data_layers'))
37156 .classed('hide-toggle', true)
37157 .classed('expanded', true)
37158 .on('click', function() {
37159 var exp = d3.select(this).classed('expanded');
37160 dataLayerContainer.style('display', exp ? 'none' : 'block');
37161 d3.select(this).classed('expanded', !exp);
37162 d3.event.preventDefault();
37165 var dataLayerContainer = content.append('div')
37166 .attr('class', 'data-data-layers')
37167 .style('display', 'block');
37171 content.append('a')
37172 .text(t('map_data.fill_area'))
37174 .classed('hide-toggle', true)
37175 .classed('expanded', false)
37176 .on('click', function() {
37177 var exp = d3.select(this).classed('expanded');
37178 fillContainer.style('display', exp ? 'none' : 'block');
37179 d3.select(this).classed('expanded', !exp);
37180 d3.event.preventDefault();
37183 var fillContainer = content.append('div')
37184 .attr('class', 'data-area-fills')
37185 .style('display', 'none');
37187 var fillList = fillContainer.append('ul')
37188 .attr('class', 'layer-list layer-fill-list');
37192 content.append('a')
37193 .text(t('map_data.map_features'))
37195 .classed('hide-toggle', true)
37196 .classed('expanded', false)
37197 .on('click', function() {
37198 var exp = d3.select(this).classed('expanded');
37199 featureContainer.style('display', exp ? 'none' : 'block');
37200 d3.select(this).classed('expanded', !exp);
37201 d3.event.preventDefault();
37204 var featureContainer = content.append('div')
37205 .attr('class', 'data-feature-filters')
37206 .style('display', 'none');
37208 var featureList = featureContainer.append('ul')
37209 .attr('class', 'layer-list layer-feature-list');
37213 .on('change.map_data-update', update);
37215 setFill(fillDefault);
37217 var keybinding = d3.keybinding('features')
37218 .on(key, togglePanel)
37219 .on('W', toggleWireframe)
37220 .on('B', hidePanel)
37221 .on('H', hidePanel);
37223 d3.select(document)
37226 context.surface().on('mousedown.map_data-outside', hidePanel);
37227 context.container().on('mousedown.map_data-outside', hidePanel);
37232 iD.ui.MapInMap = function(context) {
37235 function map_in_map(selection) {
37236 var backgroundLayer = iD.TileLayer(context),
37237 overlayLayers = {},
37238 projection = iD.geo.RawMercator(),
37239 gpxLayer = iD.svg.Gpx(projection, context).showLabels(false),
37240 debugLayer = iD.svg.Debug(projection, context),
37241 zoom = d3.behavior.zoom()
37242 .scaleExtent([ztok(0.5), ztok(24)])
37243 .on('zoom', zoomPan),
37244 transformed = false,
37247 zDiff = 6, // by default, minimap renders at (main zoom - 6)
37248 tStart, tLast, tCurr, kLast, kCurr, tiles, viewport, timeoutId;
37250 function ztok(z) { return 256 * Math.pow(2, z); }
37251 function ktoz(k) { return Math.log(k) / Math.LN2 - 8; }
37254 function startMouse() {
37255 context.surface().on('mouseup.map-in-map-outside', endMouse);
37256 context.container().on('mouseup.map-in-map-outside', endMouse);
37258 tStart = tLast = tCurr = projection.translate();
37263 function zoomPan() {
37264 var e = d3.event.sourceEvent,
37265 t = d3.event.translate,
37266 k = d3.event.scale,
37267 zMain = ktoz(context.projection.scale() * 2 * Math.PI),
37270 // restrict minimap zoom to < (main zoom - 3)
37271 if (zMini > zMain - 3) {
37273 zoom.scale(kCurr).translate(tCurr); // restore last good values
37279 zDiff = zMain - zMini;
37281 var scale = kCurr / kLast,
37282 tX = (tCurr[0] / scale - tLast[0]) * scale,
37283 tY = (tCurr[1] / scale - tLast[1]) * scale;
37285 iD.util.setTransform(tiles, tX, tY, scale);
37286 iD.util.setTransform(viewport, 0, 0, scale);
37287 transformed = true;
37291 e.preventDefault();
37292 e.stopPropagation();
37296 function endMouse() {
37297 context.surface().on('mouseup.map-in-map-outside', null);
37298 context.container().on('mouseup.map-in-map-outside', null);
37300 updateProjection();
37303 if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) {
37304 var dMini = wrap.dimensions(),
37305 cMini = [ dMini[0] / 2, dMini[1] / 2 ];
37307 context.map().center(projection.invert(cMini));
37312 function updateProjection() {
37313 var loc = context.map().center(),
37314 dMini = wrap.dimensions(),
37315 cMini = [ dMini[0] / 2, dMini[1] / 2 ],
37316 tMain = context.projection.translate(),
37317 kMain = context.projection.scale(),
37318 zMain = ktoz(kMain * 2 * Math.PI),
37319 zMini = Math.max(zMain - zDiff, 0.5),
37320 kMini = ztok(zMini);
37324 .scale(kMini / (2 * Math.PI));
37326 var s = projection(loc),
37327 mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0],
37329 cMini[0] - s[0] + tMain[0] + mouse[0],
37330 cMini[1] - s[1] + tMain[1] + mouse[1]
37335 .clipExtent([[0, 0], dMini]);
37342 tLast = tCurr = tMini;
37343 kLast = kCurr = kMini;
37346 iD.util.setTransform(tiles, 0, 0);
37347 iD.util.setTransform(viewport, 0, 0);
37348 transformed = false;
37353 function redraw() {
37354 if (hidden) return;
37356 updateProjection();
37358 var dMini = wrap.dimensions(),
37359 zMini = ktoz(projection.scale() * 2 * Math.PI);
37361 // setup tile container
37363 .selectAll('.map-in-map-tiles')
37369 .attr('class', 'map-in-map-tiles');
37371 // redraw background
37373 .source(context.background().baseLayerSource())
37374 .projection(projection)
37375 .dimensions(dMini);
37377 var background = tiles
37378 .selectAll('.map-in-map-background')
37383 .attr('class', 'map-in-map-background');
37386 .call(backgroundLayer);
37390 var overlaySources = context.background().overlayLayerSources();
37391 var activeOverlayLayers = [];
37392 for (var i = 0; i < overlaySources.length; i++) {
37393 if (overlaySources[i].validZoom(zMini)) {
37394 if (!overlayLayers[i]) overlayLayers[i] = iD.TileLayer(context);
37395 activeOverlayLayers.push(overlayLayers[i]
37396 .source(overlaySources[i])
37397 .projection(projection)
37398 .dimensions(dMini));
37402 var overlay = tiles
37403 .selectAll('.map-in-map-overlay')
37408 .attr('class', 'map-in-map-overlay');
37410 var overlays = overlay
37412 .data(activeOverlayLayers, function(d) { return d.source().name(); });
37414 overlays.enter().append('div');
37415 overlays.each(function(layer) {
37416 d3.select(this).call(layer);
37423 var dataLayers = tiles
37424 .selectAll('.map-in-map-data')
37429 .attr('class', 'map-in-map-data');
37439 // redraw viewport bounding box
37441 var getPath = d3.geo.path().projection(projection),
37442 bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
37444 viewport = wrap.selectAll('.map-in-map-viewport')
37449 .attr('class', 'map-in-map-viewport');
37451 var path = viewport.selectAll('.map-in-map-bbox')
37456 .attr('class', 'map-in-map-bbox');
37459 .attr('d', getPath)
37460 .classed('thick', function(d) { return getPath.area(d) < 30; });
37465 function queueRedraw() {
37466 clearTimeout(timeoutId);
37467 timeoutId = setTimeout(function() { redraw(); }, 300);
37471 function toggle() {
37472 if (d3.event) d3.event.preventDefault();
37476 var label = d3.select('.minimap-toggle');
37477 label.classed('active', !hidden)
37478 .select('input').property('checked', !hidden);
37482 .style('display', 'block')
37483 .style('opacity', 1)
37486 .style('opacity', 0)
37487 .each('end', function() {
37488 d3.select(this).style('display', 'none');
37492 .style('display', 'block')
37493 .style('opacity', 0)
37496 .style('opacity', 1);
37502 iD.ui.MapInMap.toggle = toggle;
37504 var wrap = selection.selectAll('.map-in-map')
37509 .attr('class', 'map-in-map')
37510 .style('display', (hidden ? 'none' : 'block'))
37511 .on('mousedown.map-in-map', startMouse)
37512 .on('mouseup.map-in-map', endMouse)
37514 .on('dblclick.zoom', null);
37517 .on('drawn.map-in-map', function(drawn) {
37518 if (drawn.full === true) redraw();
37523 var keybinding = d3.keybinding('map-in-map')
37526 d3.select(document)
37532 iD.ui.modal = function(selection, blocking) {
37533 var keybinding = d3.keybinding('modal');
37534 var previous = selection.select('div.modal');
37535 var animate = previous.empty();
37537 previous.transition()
37539 .style('opacity', 0)
37542 var shaded = selection
37544 .attr('class', 'shaded')
37545 .style('opacity', 0);
37547 shaded.close = function() {
37551 .style('opacity',0)
37556 .style('top','0px');
37562 var modal = shaded.append('div')
37563 .attr('class', 'modal fillL col6');
37566 shaded.on('click.remove-modal', function() {
37567 if (d3.event.target === this) {
37572 modal.append('button')
37573 .attr('class', 'close')
37574 .on('click', shaded.close)
37575 .call(iD.svg.Icon('#icon-close'));
37578 .on('⌫', shaded.close)
37579 .on('⎋', shaded.close);
37581 d3.select(document).call(keybinding);
37584 modal.append('div')
37585 .attr('class', 'content');
37588 shaded.transition().style('opacity', 1);
37590 shaded.style('opacity', 1);
37595 iD.ui.Modes = function(context) {
37597 iD.modes.AddPoint(context),
37598 iD.modes.AddLine(context),
37599 iD.modes.AddArea(context)];
37601 function editable() {
37602 return context.editable() && context.mode().id !== 'save';
37605 return function(selection) {
37606 var buttons = selection.selectAll('button.add-button')
37609 buttons.enter().append('button')
37610 .attr('tabindex', -1)
37611 .attr('class', function(mode) { return mode.id + ' add-button col4'; })
37612 .on('click.mode-buttons', function(mode) {
37613 if (mode.id === context.mode().id) {
37614 context.enter(iD.modes.Browse(context));
37616 context.enter(mode);
37619 .call(bootstrap.tooltip()
37620 .placement('bottom')
37622 .title(function(mode) {
37623 return iD.ui.tooltipHtml(mode.description, mode.key);
37627 .on('move.modes', _.debounce(update, 500));
37630 .on('enter.modes', update);
37632 buttons.each(function(d) {
37634 .call(iD.svg.Icon('#icon-' + d.button, 'pre-text'));
37637 buttons.append('span')
37638 .attr('class', 'label')
37639 .text(function(mode) { return mode.title; });
37641 context.on('enter.editor', function(entered) {
37642 buttons.classed('active', function(mode) { return entered.button === mode.button; });
37643 context.container()
37644 .classed('mode-' + entered.id, true);
37647 context.on('exit.editor', function(exited) {
37648 context.container()
37649 .classed('mode-' + exited.id, false);
37652 var keybinding = d3.keybinding('mode-buttons');
37654 modes.forEach(function(m) {
37655 keybinding.on(m.key, function() { if (editable()) context.enter(m); });
37658 d3.select(document)
37661 function update() {
37662 buttons.property('disabled', !editable());
37666 iD.ui.Notice = function(context) {
37667 return function(selection) {
37668 var div = selection.append('div')
37669 .attr('class', 'notice');
37671 var button = div.append('button')
37672 .attr('class', 'zoom-to notice')
37673 .on('click', function() { context.map().zoom(context.minEditableZoom()); });
37676 .call(iD.svg.Icon('#icon-plus', 'pre-text'))
37678 .attr('class', 'label')
37679 .text(t('zoom_in_edit'));
37681 function disableTooHigh() {
37682 div.style('display', context.editable() ? 'none' : 'block');
37686 .on('move.notice', _.debounce(disableTooHigh, 500));
37691 iD.ui.PresetIcon = function() {
37692 var preset, geometry;
37694 function presetIcon(selection) {
37695 selection.each(render);
37698 function render() {
37699 var selection = d3.select(this),
37700 p = preset.apply(this, arguments),
37701 geom = geometry.apply(this, arguments),
37702 icon = p.icon || (geom === 'line' ? 'other-line' : 'marker-stroked'),
37703 maki = iD.data.featureIcons.hasOwnProperty(icon + '-24');
37705 if (icon === 'dentist') maki = true; // workaround for dentist icon missing in `maki-sprite.json`
37707 function tag_classes(p) {
37709 for (var i in p.tags) {
37711 if (p.tags[i] !== '*') {
37712 s += ' tag-' + i + '-' + p.tags[i];
37718 var $fill = selection.selectAll('.preset-icon-fill')
37721 $fill.enter().append('div');
37723 $fill.attr('class', function() {
37724 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
37727 var $frame = selection.selectAll('.preset-icon-frame')
37732 .call(iD.svg.Icon('#preset-icon-frame'));
37734 $frame.attr('class', function() {
37735 return 'preset-icon-frame ' + (geom === 'area' ? '' : 'hide');
37739 var $icon = selection.selectAll('.preset-icon')
37744 .attr('class', 'preset-icon')
37745 .call(iD.svg.Icon(''));
37748 .attr('class', 'preset-icon preset-icon-' + (maki ? '32' : (geom === 'area' ? '44' : '60')));
37750 $icon.selectAll('svg')
37751 .attr('class', function() {
37752 return 'icon ' + icon + tag_classes(p);
37755 $icon.selectAll('use') // workaround: maki parking-24 broken?
37756 .attr('href', '#' + icon + (maki ? ( icon === 'parking' ? '-18' : '-24') : ''));
37759 presetIcon.preset = function(_) {
37760 if (!arguments.length) return preset;
37761 preset = d3.functor(_);
37765 presetIcon.geometry = function(_) {
37766 if (!arguments.length) return geometry;
37767 geometry = d3.functor(_);
37773 iD.ui.preset = function(context) {
37774 var event = d3.dispatch('change'),
37781 function UIField(field, entity, show) {
37782 field = _.clone(field);
37784 field.input = iD.ui.preset[field.type](field, context)
37785 .on('change', event.change);
37787 if (field.input.entity) field.input.entity(entity);
37789 field.keys = field.keys || [field.key];
37793 field.shown = function() {
37794 return field.id === 'name' || field.show || _.some(field.keys, function(key) { return !!tags[key]; });
37797 field.modified = function() {
37798 var original = context.graph().base().entities[entity.id];
37799 return _.some(field.keys, function(key) {
37800 return original ? tags[key] !== original.tags[key] : tags[key];
37804 field.revert = function() {
37805 var original = context.graph().base().entities[entity.id],
37807 field.keys.forEach(function(key) {
37808 t[key] = original ? original.tags[key] : undefined;
37813 field.present = function() {
37814 return _.some(field.keys, function(key) {
37819 field.remove = function() {
37821 field.keys.forEach(function(key) {
37822 t[key] = undefined;
37830 function fieldKey(field) {
37834 function presets(selection) {
37835 selection.call(iD.ui.Disclosure()
37836 .title(t('inspector.all_fields'))
37837 .expanded(context.storage('preset_fields.expanded') !== 'false')
37838 .on('toggled', toggled)
37839 .content(content));
37841 function toggled(expanded) {
37842 context.storage('preset_fields.expanded', expanded);
37846 function content(selection) {
37848 var entity = context.entity(id),
37849 geometry = context.geometry(id);
37851 fields = [UIField(context.presets().field('name'), entity)];
37853 preset.fields.forEach(function(field) {
37854 if (field.matchGeometry(geometry)) {
37855 fields.push(UIField(field, entity, true));
37859 if (entity.isHighwayIntersection(context.graph())) {
37860 fields.push(UIField(context.presets().field('restrictions'), entity, true));
37863 context.presets().universal().forEach(function(field) {
37864 if (preset.fields.indexOf(field) < 0) {
37865 fields.push(UIField(field, entity));
37870 var shown = fields.filter(function(field) { return field.shown(); }),
37871 notShown = fields.filter(function(field) { return !field.shown(); });
37873 var $form = selection.selectAll('.preset-form')
37876 $form.enter().append('div')
37877 .attr('class', 'preset-form inspector-inner fillL3');
37879 var $fields = $form.selectAll('.form-field')
37880 .data(shown, fieldKey);
37884 var $enter = $fields.enter()
37886 .attr('class', function(field) {
37887 return 'form-field form-field-' + field.id;
37890 var $label = $enter.append('label')
37891 .attr('class', 'form-label')
37892 .attr('for', function(field) { return 'preset-input-' + field.id; })
37893 .text(function(field) { return field.label(); });
37895 var wrap = $label.append('div')
37896 .attr('class', 'form-label-button-wrap');
37898 wrap.append('button')
37899 .attr('class', 'remove-icon')
37900 .attr('tabindex', -1)
37901 .call(iD.svg.Icon('#operation-delete'));
37903 wrap.append('button')
37904 .attr('class', 'modified-icon')
37905 .attr('tabindex', -1)
37906 .call(iD.svg.Icon('#icon-undo'));
37910 $fields.select('.form-label-button-wrap .remove-icon')
37911 .on('click', remove);
37913 $fields.select('.modified-icon')
37914 .on('click', revert);
37918 .classed('modified', function(field) {
37919 return field.modified();
37921 .classed('present', function(field) {
37922 return field.present();
37924 .each(function(field) {
37925 var reference = iD.ui.TagReference(field.reference || {key: field.key}, context);
37927 if (state === 'hover') {
37928 reference.showing(false);
37933 .selectAll('input')
37934 .on('keydown', function() {
37935 // if user presses enter, and combobox is not active, accept edits..
37936 if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) {
37937 context.enter(iD.modes.Browse(context));
37940 .call(reference.body)
37941 .select('.form-label-button-wrap')
37942 .call(reference.button);
37944 field.input.tags(tags);
37950 notShown = notShown.map(function(field) {
37952 title: field.label(),
37953 value: field.label(),
37958 var $more = selection.selectAll('.more-fields')
37959 .data((notShown.length > 0) ? [0] : []);
37961 $more.enter().append('div')
37962 .attr('class', 'more-fields')
37964 .text(t('inspector.add_fields'));
37966 var $input = $more.selectAll('.value')
37969 $input.enter().append('input')
37970 .attr('class', 'value')
37971 .attr('type', 'text');
37974 .attr('placeholder', function() {
37975 var placeholder = [];
37976 for (var field in notShown) {
37977 placeholder.push(notShown[field].title);
37979 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
37981 .call(d3.combobox().data(notShown)
37983 .on('accept', show));
37991 function show(field) {
37992 field = field.field;
37994 content(selection);
37995 field.input.focus();
37998 function revert(field) {
37999 d3.event.stopPropagation();
38000 d3.event.preventDefault();
38001 event.change(field.revert());
38004 function remove(field) {
38005 d3.event.stopPropagation();
38006 d3.event.preventDefault();
38007 event.change(field.remove());
38011 presets.preset = function(_) {
38012 if (!arguments.length) return preset;
38013 if (preset && preset.id === _.id) return presets;
38019 presets.state = function(_) {
38020 if (!arguments.length) return state;
38025 presets.tags = function(_) {
38026 if (!arguments.length) return tags;
38028 // Don't reset fields here.
38032 presets.entityID = function(_) {
38033 if (!arguments.length) return id;
38034 if (id === _) return presets;
38040 return d3.rebind(presets, event, 'on');
38042 iD.ui.PresetList = function(context) {
38043 var dispatch = d3.dispatch('choose'),
38048 function presetList(selection) {
38049 var entity = context.entity(id),
38050 geometry = context.geometry(id);
38052 // Treat entities on addr:interpolation lines as points, not vertices (#3241)
38053 if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
38054 geometry = 'point';
38057 var presets = context.presets().matchGeometry(geometry);
38059 selection.html('');
38061 var messagewrap = selection.append('div')
38062 .attr('class', 'header fillL cf');
38064 var message = messagewrap.append('h3')
38065 .text(t('inspector.choose'));
38067 if (context.entity(id).isUsed(context.graph())) {
38068 messagewrap.append('button')
38069 .attr('class', 'preset-choose')
38070 .on('click', function() { dispatch.choose(currentPreset); })
38074 messagewrap.append('button')
38075 .attr('class', 'close')
38076 .on('click', function() {
38077 context.enter(iD.modes.Browse(context));
38079 .call(iD.svg.Icon('#icon-close'));
38082 function keydown() {
38083 // hack to let delete shortcut work when search is autofocused
38084 if (search.property('value').length === 0 &&
38085 (d3.event.keyCode === d3.keybinding.keyCodes['⌫'] ||
38086 d3.event.keyCode === d3.keybinding.keyCodes['⌦'])) {
38087 d3.event.preventDefault();
38088 d3.event.stopPropagation();
38089 iD.operations.Delete([id], context)();
38090 } else if (search.property('value').length === 0 &&
38091 (d3.event.ctrlKey || d3.event.metaKey) &&
38092 d3.event.keyCode === d3.keybinding.keyCodes.z) {
38093 d3.event.preventDefault();
38094 d3.event.stopPropagation();
38096 } else if (!d3.event.ctrlKey && !d3.event.metaKey) {
38097 d3.select(this).on('keydown', null);
38101 function keypress() {
38103 var value = search.property('value');
38104 if (d3.event.keyCode === 13 && value.length) {
38105 list.selectAll('.preset-list-item:first-child').datum().choose();
38109 function inputevent() {
38110 var value = search.property('value');
38111 list.classed('filtered', value.length);
38112 if (value.length) {
38113 var results = presets.search(value, geometry);
38114 message.text(t('inspector.results', {
38115 n: results.collection.length,
38118 list.call(drawList, results);
38120 list.call(drawList, context.presets().defaults(geometry, 36));
38121 message.text(t('inspector.choose'));
38125 var searchWrap = selection.append('div')
38126 .attr('class', 'search-header');
38128 var search = searchWrap.append('input')
38129 .attr('class', 'preset-search-input')
38130 .attr('placeholder', t('inspector.search'))
38131 .attr('type', 'search')
38132 .on('keydown', keydown)
38133 .on('keypress', keypress)
38134 .on('input', inputevent);
38137 .call(iD.svg.Icon('#icon-search', 'pre-text'));
38140 search.node().focus();
38143 var listWrap = selection.append('div')
38144 .attr('class', 'inspector-body');
38146 var list = listWrap.append('div')
38147 .attr('class', 'preset-list fillL cf')
38148 .call(drawList, context.presets().defaults(geometry, 36));
38151 function drawList(list, presets) {
38152 var collection = presets.collection.map(function(preset) {
38153 return preset.members ? CategoryItem(preset) : PresetItem(preset);
38156 var items = list.selectAll('.preset-list-item')
38157 .data(collection, function(d) { return d.preset.id; });
38159 items.enter().append('div')
38160 .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
38161 .classed('current', function(item) { return item.preset === currentPreset; })
38162 .each(function(item) {
38163 d3.select(this).call(item);
38165 .style('opacity', 0)
38167 .style('opacity', 1);
38175 function CategoryItem(preset) {
38176 var box, sublist, shown = false;
38178 function item(selection) {
38179 var wrap = selection.append('div')
38180 .attr('class', 'preset-list-button-wrap category col12');
38182 wrap.append('button')
38183 .attr('class', 'preset-list-button')
38184 .classed('expanded', false)
38185 .call(iD.ui.PresetIcon()
38186 .geometry(context.geometry(id))
38188 .on('click', function() {
38189 var isExpanded = d3.select(this).classed('expanded');
38190 var triangle = isExpanded ? '▶ ' : '▼ ';
38191 d3.select(this).classed('expanded', !isExpanded);
38192 d3.select(this).selectAll('.label').text(triangle + preset.name());
38196 .attr('class', 'label')
38198 return '▶ ' + preset.name();
38201 box = selection.append('div')
38202 .attr('class', 'subgrid col12')
38203 .style('max-height', '0px')
38204 .style('opacity', 0);
38207 .attr('class', 'arrow');
38209 sublist = box.append('div')
38210 .attr('class', 'preset-list fillL3 cf fl');
38213 item.choose = function() {
38214 if (!box || !sublist) return;
38220 .style('opacity', '0')
38221 .style('max-height', '0px')
38222 .style('padding-bottom', '0px');
38225 sublist.call(drawList, preset.members);
38228 .style('opacity', '1')
38229 .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
38230 .style('padding-bottom', '20px');
38234 item.preset = preset;
38239 function PresetItem(preset) {
38240 function item(selection) {
38241 var wrap = selection.append('div')
38242 .attr('class', 'preset-list-button-wrap col12');
38244 wrap.append('button')
38245 .attr('class', 'preset-list-button')
38246 .call(iD.ui.PresetIcon()
38247 .geometry(context.geometry(id))
38249 .on('click', item.choose)
38251 .attr('class', 'label')
38252 .text(preset.name());
38254 wrap.call(item.reference.button);
38255 selection.call(item.reference.body);
38258 item.choose = function() {
38259 context.presets().choose(preset);
38262 iD.actions.ChangePreset(id, currentPreset, preset),
38263 t('operations.change_tags.annotation'));
38265 dispatch.choose(preset);
38268 item.help = function() {
38269 d3.event.stopPropagation();
38270 item.reference.toggle();
38273 item.preset = preset;
38274 item.reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context);
38279 presetList.autofocus = function(_) {
38280 if (!arguments.length) return autofocus;
38285 presetList.entityID = function(_) {
38286 if (!arguments.length) return id;
38288 presetList.preset(context.presets().match(context.entity(id), context.graph()));
38292 presetList.preset = function(_) {
38293 if (!arguments.length) return currentPreset;
38298 return d3.rebind(presetList, dispatch, 'on');
38300 iD.ui.RadialMenu = function(context, operations) {
38305 var radialMenu = function(selection) {
38306 if (!operations.length)
38309 selection.node().parentNode.focus();
38311 function click(operation) {
38312 d3.event.stopPropagation();
38313 if (operation.disabled())
38316 radialMenu.close();
38319 menu = selection.append('g')
38320 .attr('class', 'radial-menu')
38321 .attr('transform', 'translate(' + center + ')')
38322 .attr('opacity', 0);
38325 .attr('opacity', 1);
38330 a1 = a0 + (operations.length - 1) * a;
38332 menu.append('path')
38333 .attr('class', 'radial-menu-background')
38334 .attr('d', 'M' + r * Math.sin(a0) + ',' +
38336 ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
38337 (r * Math.sin(a1) + 1e-3) + ',' +
38338 (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
38339 .attr('stroke-width', 50)
38340 .attr('stroke-linecap', 'round');
38342 var button = menu.selectAll()
38346 .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
38347 .classed('disabled', function(d) { return d.disabled(); })
38348 .attr('transform', function(d, i) {
38349 return 'translate(' + iD.geo.roundCoords([
38350 r * Math.sin(a0 + i * a),
38351 r * Math.cos(a0 + i * a)]).join(',') + ')';
38354 button.append('circle')
38356 .on('click', click)
38357 .on('mousedown', mousedown)
38358 .on('mouseover', mouseover)
38359 .on('mouseout', mouseout);
38361 button.append('use')
38362 .attr('transform', 'translate(-10,-10)')
38363 .attr('width', '20')
38364 .attr('height', '20')
38365 .attr('xlink:href', function(d) { return '#operation-' + d.id; });
38367 tooltip = d3.select(document.body)
38369 .attr('class', 'tooltip-inner radial-menu-tooltip');
38371 function mousedown() {
38372 d3.event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
38375 function mouseover(d, i) {
38376 var rect = context.surfaceRect(),
38377 angle = a0 + i * a,
38378 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
38379 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
38380 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
38381 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
38384 .style('top', null)
38385 .style('left', null)
38386 .style('bottom', null)
38387 .style('right', null)
38388 .style('display', 'block')
38389 .html(iD.ui.tooltipHtml(d.tooltip(), d.keys[0]));
38393 .style('right', right)
38394 .style('top', top);
38395 } else if (i >= 4) {
38397 .style('left', left)
38398 .style('bottom', bottom);
38401 .style('left', left)
38402 .style('top', top);
38406 function mouseout() {
38407 tooltip.style('display', 'none');
38411 radialMenu.close = function() {
38414 .style('pointer-events', 'none')
38416 .attr('opacity', 0)
38425 radialMenu.center = function(_) {
38426 if (!arguments.length) return center;
38433 iD.ui.RawMemberEditor = function(context) {
38436 function selectMember(d) {
38437 d3.event.preventDefault();
38438 context.enter(iD.modes.Select(context, [d.id]));
38441 function changeRole(d) {
38442 var role = d3.select(this).property('value');
38443 var member = {id: d.id, type: d.type, role: role};
38445 iD.actions.ChangeMember(d.relation.id, member, d.index),
38446 t('operations.change_role.annotation'));
38449 function deleteMember(d) {
38451 iD.actions.DeleteMember(d.relation.id, d.index),
38452 t('operations.delete_member.annotation'));
38454 if (!context.hasEntity(d.relation.id)) {
38455 context.enter(iD.modes.Browse(context));
38459 function rawMemberEditor(selection) {
38460 var entity = context.entity(id),
38463 entity.members.forEach(function(member, index) {
38470 member: context.hasEntity(member.id)
38474 selection.call(iD.ui.Disclosure()
38475 .title(t('inspector.all_members') + ' (' + memberships.length + ')')
38477 .on('toggled', toggled)
38478 .content(content));
38480 function toggled(expanded) {
38482 selection.node().parentNode.scrollTop += 200;
38486 function content($wrap) {
38487 var $list = $wrap.selectAll('.member-list')
38490 $list.enter().append('ul')
38491 .attr('class', 'member-list');
38493 var $items = $list.selectAll('li')
38494 .data(memberships, function(d) {
38495 return iD.Entity.key(d.relation) + ',' + d.index + ',' +
38496 (d.member ? iD.Entity.key(d.member) : 'incomplete');
38499 var $enter = $items.enter().append('li')
38500 .attr('class', 'member-row form-field')
38501 .classed('member-incomplete', function(d) { return !d.member; });
38503 $enter.each(function(d) {
38505 var $label = d3.select(this).append('label')
38506 .attr('class', 'form-label')
38509 .on('click', selectMember);
38511 $label.append('span')
38512 .attr('class', 'member-entity-type')
38513 .text(function(d) { return context.presets().match(d.member, context.graph()).name(); });
38515 $label.append('span')
38516 .attr('class', 'member-entity-name')
38517 .text(function(d) { return iD.util.displayName(d.member); });
38520 d3.select(this).append('label')
38521 .attr('class', 'form-label')
38522 .text(t('inspector.incomplete'));
38526 $enter.append('input')
38527 .attr('class', 'member-role')
38528 .property('type', 'text')
38529 .attr('maxlength', 255)
38530 .attr('placeholder', t('inspector.role'))
38531 .property('value', function(d) { return d.role; })
38532 .on('change', changeRole);
38534 $enter.append('button')
38535 .attr('tabindex', -1)
38536 .attr('class', 'remove button-input-action member-delete minor')
38537 .on('click', deleteMember)
38538 .call(iD.svg.Icon('#operation-delete'));
38545 rawMemberEditor.entityID = function(_) {
38546 if (!arguments.length) return id;
38548 return rawMemberEditor;
38551 return rawMemberEditor;
38553 iD.ui.RawMembershipEditor = function(context) {
38556 function selectRelation(d) {
38557 d3.event.preventDefault();
38558 context.enter(iD.modes.Select(context, [d.relation.id]));
38561 function changeRole(d) {
38562 var role = d3.select(this).property('value');
38564 iD.actions.ChangeMember(d.relation.id, _.extend({}, d.member, {role: role}), d.index),
38565 t('operations.change_role.annotation'));
38568 function addMembership(d, role) {
38573 iD.actions.AddMember(d.relation.id, {id: id, type: context.entity(id).type, role: role}),
38574 t('operations.add_member.annotation'));
38577 var relation = iD.Relation();
38580 iD.actions.AddEntity(relation),
38581 iD.actions.AddMember(relation.id, {id: id, type: context.entity(id).type, role: role}),
38582 t('operations.add.annotation.relation'));
38584 context.enter(iD.modes.Select(context, [relation.id]));
38588 function deleteMembership(d) {
38590 iD.actions.DeleteMember(d.relation.id, d.index),
38591 t('operations.delete_member.annotation'));
38594 function relations(q) {
38595 var newRelation = {
38597 value: t('inspector.new_relation')
38600 graph = context.graph();
38602 context.intersects(context.extent()).forEach(function(entity) {
38603 if (entity.type !== 'relation' || entity.id === id)
38606 var presetName = context.presets().match(entity, graph).name(),
38607 entityName = iD.util.displayName(entity) || '';
38609 var value = presetName + ' ' + entityName;
38610 if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
38619 result.sort(function(a, b) {
38620 return iD.Relation.creationOrder(a.relation, b.relation);
38623 // Dedupe identical names by appending relation id - see #2891
38624 var dupeGroups = _(result)
38626 .filter(function(v) { return v.length > 1; })
38629 dupeGroups.forEach(function(group) {
38630 group.forEach(function(obj) {
38631 obj.value += ' ' + obj.relation.id;
38635 result.unshift(newRelation);
38640 function rawMembershipEditor(selection) {
38641 var entity = context.entity(id),
38644 context.graph().parentRelations(entity).forEach(function(relation) {
38645 relation.members.forEach(function(member, index) {
38646 if (member.id === entity.id) {
38647 memberships.push({relation: relation, member: member, index: index});
38652 selection.call(iD.ui.Disclosure()
38653 .title(t('inspector.all_relations') + ' (' + memberships.length + ')')
38655 .on('toggled', toggled)
38656 .content(content));
38658 function toggled(expanded) {
38660 selection.node().parentNode.scrollTop += 200;
38664 function content($wrap) {
38665 var $list = $wrap.selectAll('.member-list')
38668 $list.enter().append('ul')
38669 .attr('class', 'member-list');
38671 var $items = $list.selectAll('li.member-row-normal')
38672 .data(memberships, function(d) { return iD.Entity.key(d.relation) + ',' + d.index; });
38674 var $enter = $items.enter().append('li')
38675 .attr('class', 'member-row member-row-normal form-field');
38677 var $label = $enter.append('label')
38678 .attr('class', 'form-label')
38681 .on('click', selectRelation);
38683 $label.append('span')
38684 .attr('class', 'member-entity-type')
38685 .text(function(d) { return context.presets().match(d.relation, context.graph()).name(); });
38687 $label.append('span')
38688 .attr('class', 'member-entity-name')
38689 .text(function(d) { return iD.util.displayName(d.relation); });
38691 $enter.append('input')
38692 .attr('class', 'member-role')
38693 .property('type', 'text')
38694 .attr('maxlength', 255)
38695 .attr('placeholder', t('inspector.role'))
38696 .property('value', function(d) { return d.member.role; })
38697 .on('change', changeRole);
38699 $enter.append('button')
38700 .attr('tabindex', -1)
38701 .attr('class', 'remove button-input-action member-delete minor')
38702 .on('click', deleteMembership)
38703 .call(iD.svg.Icon('#operation-delete'));
38709 var $new = $list.selectAll('.member-row-new')
38712 $enter = $new.enter().append('li')
38713 .attr('class', 'member-row member-row-new form-field');
38715 $enter.append('input')
38716 .attr('type', 'text')
38717 .attr('class', 'member-entity-input')
38718 .call(d3.combobox()
38720 .fetcher(function(value, callback) {
38721 callback(relations(value));
38723 .on('accept', function(d) {
38724 addMembership(d, $new.select('.member-role').property('value'));
38727 $enter.append('input')
38728 .attr('class', 'member-role')
38729 .property('type', 'text')
38730 .attr('maxlength', 255)
38731 .attr('placeholder', t('inspector.role'))
38732 .on('change', changeRole);
38734 $enter.append('button')
38735 .attr('tabindex', -1)
38736 .attr('class', 'remove button-input-action member-delete minor')
38737 .on('click', deleteMembership)
38738 .call(iD.svg.Icon('#operation-delete'));
38741 $list.selectAll('.member-row-new')
38745 var $add = $wrap.selectAll('.add-relation')
38750 .attr('class', 'add-relation')
38751 .call(iD.svg.Icon('#icon-plus', 'light'));
38753 $wrap.selectAll('.add-relation')
38754 .on('click', function() {
38757 $list.selectAll('.member-entity-input').node().focus();
38762 rawMembershipEditor.entityID = function(_) {
38763 if (!arguments.length) return id;
38765 return rawMembershipEditor;
38768 return rawMembershipEditor;
38770 iD.ui.RawTagEditor = function(context) {
38771 var event = d3.dispatch('change'),
38778 function rawTagEditor(selection) {
38779 var count = Object.keys(tags).filter(function(d) { return d; }).length;
38781 selection.call(iD.ui.Disclosure()
38782 .title(t('inspector.all_tags') + ' (' + count + ')')
38783 .expanded(context.storage('raw_tag_editor.expanded') === 'true' || preset.isFallback())
38784 .on('toggled', toggled)
38785 .content(content));
38787 function toggled(expanded) {
38788 context.storage('raw_tag_editor.expanded', expanded);
38790 selection.node().parentNode.scrollTop += 200;
38795 function content($wrap) {
38796 var entries = d3.entries(tags);
38798 if (!entries.length || showBlank) {
38800 entries.push({key: '', value: ''});
38803 var $list = $wrap.selectAll('.tag-list')
38806 $list.enter().append('ul')
38807 .attr('class', 'tag-list');
38809 var $newTag = $wrap.selectAll('.add-tag')
38814 .attr('class', 'add-tag')
38815 .call(iD.svg.Icon('#icon-plus', 'light'));
38817 $newTag.on('click', addTag);
38819 var $items = $list.selectAll('li')
38820 .data(entries, function(d) { return d.key; });
38824 var $enter = $items.enter().append('li')
38825 .attr('class', 'tag-row cf');
38827 $enter.append('div')
38828 .attr('class', 'key-wrap')
38830 .property('type', 'text')
38831 .attr('class', 'key')
38832 .attr('maxlength', 255);
38834 $enter.append('div')
38835 .attr('class', 'input-wrap-position')
38837 .property('type', 'text')
38838 .attr('class', 'value')
38839 .attr('maxlength', 255);
38841 $enter.append('button')
38842 .attr('tabindex', -1)
38843 .attr('class', 'remove minor')
38844 .call(iD.svg.Icon('#operation-delete'));
38846 if (context.taginfo()) {
38847 $enter.each(bindTypeahead);
38854 $items.each(function(tag) {
38855 var isRelation = (context.entity(id).type === 'relation'),
38857 if (isRelation && tag.key === 'type')
38858 reference = iD.ui.TagReference({rtype: tag.value}, context);
38860 reference = iD.ui.TagReference({key: tag.key, value: tag.value}, context);
38862 if (state === 'hover') {
38863 reference.showing(false);
38867 .call(reference.button)
38868 .call(reference.body);
38871 $items.select('input.key')
38872 .attr('title', function(d) { return d.key; })
38873 .value(function(d) { return d.key; })
38874 .on('blur', keyChange)
38875 .on('change', keyChange);
38877 $items.select('input.value')
38878 .attr('title', function(d) { return d.value; })
38879 .value(function(d) { return d.value; })
38880 .on('blur', valueChange)
38881 .on('change', valueChange)
38882 .on('keydown.push-more', pushMore);
38884 $items.select('button.remove')
38885 .on('click', removeTag);
38891 function pushMore() {
38892 if (d3.event.keyCode === 9 && !d3.event.shiftKey &&
38893 $list.selectAll('li:last-child input.value').node() === this) {
38898 function bindTypeahead() {
38899 var row = d3.select(this),
38900 key = row.selectAll('input.key'),
38901 value = row.selectAll('input.value');
38903 function sort(value, data) {
38904 var sameletter = [],
38906 for (var i = 0; i < data.length; i++) {
38907 if (data[i].value.substring(0, value.length) === value) {
38908 sameletter.push(data[i]);
38910 other.push(data[i]);
38913 return sameletter.concat(other);
38916 key.call(d3.combobox()
38917 .fetcher(function(value, callback) {
38918 context.taginfo().keys({
38920 geometry: context.geometry(id),
38922 }, function(err, data) {
38923 if (!err) callback(sort(value, data));
38927 value.call(d3.combobox()
38928 .fetcher(function(value, callback) {
38929 context.taginfo().values({
38932 geometry: context.geometry(id),
38934 }, function(err, data) {
38935 if (!err) callback(sort(value, data));
38940 function unbind() {
38941 var row = d3.select(this);
38943 row.selectAll('input.key')
38944 .call(d3.combobox.off);
38946 row.selectAll('input.value')
38947 .call(d3.combobox.off);
38950 function keyChange(d) {
38952 kNew = this.value.trim(),
38955 if (kNew && kNew !== kOld) {
38956 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
38958 suffix = +(match[2] || 1);
38959 while (tags[kNew]) { // rename key if already in use
38960 kNew = base + '_' + suffix++;
38963 tag[kOld] = undefined;
38964 tag[kNew] = d.value;
38965 d.key = kNew; // Maintain DOM identity through the subsequent update.
38970 function valueChange(d) {
38972 tag[d.key] = this.value;
38976 function removeTag(d) {
38978 tag[d.key] = undefined;
38980 d3.select(this.parentNode).remove();
38983 function addTag() {
38984 // Wrapped in a setTimeout in case it's being called from a blur
38985 // handler. Without the setTimeout, the call to `content` would
38986 // wipe out the pending value change.
38987 setTimeout(function() {
38990 $list.selectAll('li:last-child input.key').node().focus();
38995 rawTagEditor.state = function(_) {
38996 if (!arguments.length) return state;
38998 return rawTagEditor;
39001 rawTagEditor.preset = function(_) {
39002 if (!arguments.length) return preset;
39004 return rawTagEditor;
39007 rawTagEditor.tags = function(_) {
39008 if (!arguments.length) return tags;
39010 return rawTagEditor;
39013 rawTagEditor.entityID = function(_) {
39014 if (!arguments.length) return id;
39016 return rawTagEditor;
39019 return d3.rebind(rawTagEditor, event, 'on');
39021 iD.ui.Restore = function(context) {
39022 return function(selection) {
39023 if (!context.history().lock() || !context.history().restorableChanges())
39026 var modal = iD.ui.modal(selection, true);
39028 modal.select('.modal')
39029 .attr('class', 'modal fillL col6');
39031 var introModal = modal.select('.content');
39033 introModal.attr('class','cf');
39035 introModal.append('div')
39036 .attr('class', 'modal-section')
39038 .text(t('restore.heading'));
39040 introModal.append('div')
39041 .attr('class','modal-section')
39043 .text(t('restore.description'));
39045 var buttonWrap = introModal.append('div')
39046 .attr('class', 'modal-actions cf');
39048 var restore = buttonWrap.append('button')
39049 .attr('class', 'restore col6')
39050 .text(t('restore.restore'))
39051 .on('click', function() {
39052 context.history().restore();
39056 buttonWrap.append('button')
39057 .attr('class', 'reset col6')
39058 .text(t('restore.reset'))
39059 .on('click', function() {
39060 context.history().clearSaved();
39064 restore.node().focus();
39067 iD.ui.Save = function(context) {
39068 var history = context.history(),
39069 key = iD.ui.cmd('⌘S');
39072 function saving() {
39073 return context.mode().id === 'save';
39077 d3.event.preventDefault();
39078 if (!context.inIntro() && !saving() && history.hasChanges()) {
39079 context.enter(iD.modes.Save(context));
39083 function getBackground(numChanges) {
39085 if (numChanges === 0) {
39087 } else if (numChanges <= 50) {
39088 step = numChanges / 50;
39089 return d3.interpolateRgb('#fff', '#ff8')(step); // white -> yellow
39091 step = Math.min((numChanges - 50) / 50, 1.0);
39092 return d3.interpolateRgb('#ff8', '#f88')(step); // yellow -> red
39096 return function(selection) {
39097 var tooltip = bootstrap.tooltip()
39098 .placement('bottom')
39100 .title(iD.ui.tooltipHtml(t('save.no_changes'), key));
39102 var button = selection.append('button')
39103 .attr('class', 'save col12 disabled')
39104 .attr('tabindex', -1)
39108 button.append('span')
39109 .attr('class', 'label')
39110 .text(t('save.title'));
39112 button.append('span')
39113 .attr('class', 'count')
39116 var keybinding = d3.keybinding('undo-redo')
39117 .on(key, save, true);
39119 d3.select(document)
39122 var numChanges = 0;
39124 context.history().on('change.save', function() {
39125 var _ = history.difference().summary().length;
39126 if (_ === numChanges)
39130 tooltip.title(iD.ui.tooltipHtml(t(numChanges > 0 ?
39131 'save.help' : 'save.no_changes'), key));
39133 var background = getBackground(numChanges);
39136 .classed('disabled', numChanges === 0)
39137 .classed('has-count', numChanges > 0)
39138 .style('background', background);
39140 button.select('span.count')
39142 .style('background', background)
39143 .style('border-color', background);
39146 context.on('enter.save', function() {
39147 button.property('disabled', saving());
39148 if (saving()) button.call(tooltip.hide);
39152 iD.ui.Scale = function(context) {
39153 var projection = context.projection,
39154 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
39158 function scaleDefs(loc1, loc2) {
39159 var lat = (loc2[1] + loc1[1]) / 2,
39160 conversion = (imperial ? 3.28084 : 1),
39161 dist = iD.geo.lonToMeters(loc2[0] - loc1[0], lat) * conversion,
39162 scale = { dist: 0, px: 0, text: '' },
39163 buckets, i, val, dLon;
39166 buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
39168 buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
39171 // determine a user-friendly endpoint for the scale
39172 for (i = 0; i < buckets.length; i++) {
39175 scale.dist = Math.floor(dist / val) * val;
39180 dLon = iD.geo.metersToLon(scale.dist / conversion, lat);
39181 scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
39184 if (scale.dist >= 5280) {
39185 scale.dist /= 5280;
39186 scale.text = String(scale.dist) + ' mi';
39188 scale.text = String(scale.dist) + ' ft';
39191 if (scale.dist >= 1000) {
39192 scale.dist /= 1000;
39193 scale.text = String(scale.dist) + ' km';
39195 scale.text = String(scale.dist) + ' m';
39202 function update(selection) {
39203 // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
39204 var dims = context.map().dimensions(),
39205 loc1 = projection.invert([0, dims[1]]),
39206 loc2 = projection.invert([maxLength, dims[1]]),
39207 scale = scaleDefs(loc1, loc2);
39209 selection.select('#scalepath')
39210 .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
39212 selection.select('#scaletext')
39213 .attr('x', scale.px + 8)
39214 .attr('y', tickHeight)
39219 return function(selection) {
39220 function switchUnits() {
39221 imperial = !imperial;
39222 selection.call(update);
39225 var g = selection.append('svg')
39226 .attr('id', 'scale')
39227 .on('click', switchUnits)
39229 .attr('transform', 'translate(10,11)');
39231 g.append('path').attr('id', 'scalepath');
39232 g.append('text').attr('id', 'scaletext');
39234 selection.call(update);
39236 context.map().on('move.scale', function() {
39241 iD.ui.SelectionList = function(context, selectedIDs) {
39243 function selectEntity(entity) {
39244 context.enter(iD.modes.Select(context, [entity.id]).suppressMenu(true));
39248 function selectionList(selection) {
39249 selection.classed('selection-list-pane', true);
39251 var header = selection.append('div')
39252 .attr('class', 'header fillL cf');
39254 header.append('h3')
39255 .text(t('inspector.multiselect'));
39257 var listWrap = selection.append('div')
39258 .attr('class', 'inspector-body');
39260 var list = listWrap.append('div')
39261 .attr('class', 'feature-list cf');
39263 context.history().on('change.selection-list', drawList);
39266 function drawList() {
39267 var entities = selectedIDs
39268 .map(function(id) { return context.hasEntity(id); })
39269 .filter(function(entity) { return entity; });
39271 var items = list.selectAll('.feature-list-item')
39272 .data(entities, iD.Entity.key);
39274 var enter = items.enter().append('button')
39275 .attr('class', 'feature-list-item')
39276 .on('click', selectEntity);
39279 var label = enter.append('div')
39280 .attr('class', 'label')
39281 .call(iD.svg.Icon('', 'pre-text'));
39283 label.append('span')
39284 .attr('class', 'entity-type');
39286 label.append('span')
39287 .attr('class', 'entity-name');
39290 items.selectAll('use')
39291 .attr('href', function() {
39292 var entity = this.parentNode.parentNode.__data__;
39293 return '#icon-' + context.geometry(entity.id);
39296 items.selectAll('.entity-type')
39297 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
39299 items.selectAll('.entity-name')
39300 .text(function(entity) { return iD.util.displayName(entity); });
39308 return selectionList;
39311 iD.ui.Sidebar = function(context) {
39312 var inspector = iD.ui.Inspector(context),
39315 function sidebar(selection) {
39316 var featureListWrap = selection.append('div')
39317 .attr('class', 'feature-list-pane')
39318 .call(iD.ui.FeatureList(context));
39320 selection.call(iD.ui.Notice(context));
39322 var inspectorWrap = selection.append('div')
39323 .attr('class', 'inspector-hidden inspector-wrap fr');
39325 function hover(id) {
39326 if (!current && context.hasEntity(id)) {
39327 featureListWrap.classed('inspector-hidden', true);
39328 inspectorWrap.classed('inspector-hidden', false)
39329 .classed('inspector-hover', true);
39331 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
39336 inspectorWrap.call(inspector);
39338 } else if (!current) {
39339 featureListWrap.classed('inspector-hidden', false);
39340 inspectorWrap.classed('inspector-hidden', true);
39341 inspector.state('hide');
39345 sidebar.hover = _.throttle(hover, 200);
39347 sidebar.select = function(id, newFeature) {
39348 if (!current && id) {
39349 featureListWrap.classed('inspector-hidden', true);
39350 inspectorWrap.classed('inspector-hidden', false)
39351 .classed('inspector-hover', false);
39353 if (inspector.entityID() !== id || inspector.state() !== 'select') {
39357 .newFeature(newFeature);
39359 inspectorWrap.call(inspector);
39361 } else if (!current) {
39362 featureListWrap.classed('inspector-hidden', false);
39363 inspectorWrap.classed('inspector-hidden', true);
39364 inspector.state('hide');
39368 sidebar.show = function(component) {
39369 featureListWrap.classed('inspector-hidden', true);
39370 inspectorWrap.classed('inspector-hidden', true);
39371 if (current) current.remove();
39372 current = selection.append('div')
39373 .attr('class', 'sidebar-component')
39377 sidebar.hide = function() {
39378 featureListWrap.classed('inspector-hidden', false);
39379 inspectorWrap.classed('inspector-hidden', true);
39380 if (current) current.remove();
39385 sidebar.hover = function() {};
39386 sidebar.hover.cancel = function() {};
39387 sidebar.select = function() {};
39388 sidebar.show = function() {};
39389 sidebar.hide = function() {};
39393 iD.ui.SourceSwitch = function(context) {
39397 d3.event.preventDefault();
39399 if (context.history().hasChanges() &&
39400 !window.confirm(t('source_switch.lose_changes'))) return;
39402 var live = d3.select(this)
39405 context.connection()
39406 .switch(live ? keys[1] : keys[0]);
39408 context.enter(iD.modes.Browse(context));
39412 .text(live ? t('source_switch.dev') : t('source_switch.live'))
39413 .classed('live', !live);
39416 var sourceSwitch = function(selection) {
39417 selection.append('a')
39419 .text(t('source_switch.live'))
39420 .classed('live', true)
39421 .attr('tabindex', -1)
39422 .on('click', click);
39425 sourceSwitch.keys = function(_) {
39426 if (!arguments.length) return keys;
39428 return sourceSwitch;
39431 return sourceSwitch;
39433 iD.ui.Spinner = function(context) {
39434 var connection = context.connection();
39436 return function(selection) {
39437 var img = selection.append('img')
39438 .attr('src', context.imagePath('loader-black.gif'))
39439 .style('opacity', 0);
39441 connection.on('loading.spinner', function() {
39443 .style('opacity', 1);
39446 connection.on('loaded.spinner', function() {
39448 .style('opacity', 0);
39452 iD.ui.Splash = function(context) {
39453 return function(selection) {
39454 if (context.storage('sawSplash'))
39457 context.storage('sawSplash', true);
39459 var modal = iD.ui.modal(selection);
39461 modal.select('.modal')
39462 .attr('class', 'modal-splash modal col6');
39464 var introModal = modal.select('.content')
39466 .attr('class', 'fillL');
39468 introModal.append('div')
39469 .attr('class','modal-section cf')
39470 .append('h3').text(t('splash.welcome'));
39472 introModal.append('div')
39473 .attr('class','modal-section')
39475 .html(t('splash.text', {
39476 version: iD.version,
39477 website: '<a href="http://ideditor.com/">ideditor.com</a>',
39478 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
39481 var buttons = introModal.append('div').attr('class', 'modal-actions cf');
39483 buttons.append('button')
39484 .attr('class', 'col6 walkthrough')
39485 .text(t('splash.walkthrough'))
39486 .on('click', function() {
39487 d3.select(document.body).call(iD.ui.intro(context));
39491 buttons.append('button')
39492 .attr('class', 'col6 start')
39493 .text(t('splash.start'))
39494 .on('click', modal.close);
39496 modal.select('button.close').attr('class','hide');
39500 iD.ui.Status = function(context) {
39501 var connection = context.connection(),
39504 return function(selection) {
39506 function update() {
39508 connection.status(function(err, apiStatus) {
39510 selection.html('');
39512 if (err && errCount++ < 2) return;
39515 selection.text(t('status.error'));
39517 } else if (apiStatus === 'readonly') {
39518 selection.text(t('status.readonly'));
39520 } else if (apiStatus === 'offline') {
39521 selection.text(t('status.offline'));
39524 selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
39525 if (!err) errCount = 0;
39530 connection.on('auth', function() { update(selection); });
39531 window.setInterval(update, 90000);
39535 iD.ui.Success = function(context) {
39536 var dispatch = d3.dispatch('cancel'),
39539 function success(selection) {
39540 var message = (changeset.comment || t('success.edited_osm')).substring(0, 130) +
39541 ' ' + context.connection().changesetURL(changeset.id);
39543 var header = selection.append('div')
39544 .attr('class', 'header fillL');
39546 header.append('button')
39547 .attr('class', 'fr')
39548 .on('click', function() { dispatch.cancel(); })
39549 .call(iD.svg.Icon('#icon-close'));
39551 header.append('h3')
39552 .text(t('success.just_edited'));
39554 var body = selection.append('div')
39555 .attr('class', 'body save-success fillL');
39558 .html(t('success.help_html'));
39561 .attr('class', 'details')
39562 .attr('target', '_blank')
39563 .attr('tabindex', -1)
39564 .call(iD.svg.Icon('#icon-out-link', 'inline'))
39565 .attr('href', t('success.help_link_url'))
39567 .text(t('success.help_link_text'));
39569 var changesetURL = context.connection().changesetURL(changeset.id);
39572 .attr('class', 'button col12 osm')
39573 .attr('target', '_blank')
39574 .attr('href', changesetURL)
39575 .text(t('success.view_on_osm'));
39578 facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
39579 twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
39580 google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
39583 body.selectAll('.button.social')
39584 .data(d3.entries(sharing))
39587 .attr('class', 'button social col4')
39588 .attr('target', '_blank')
39589 .attr('href', function(d) { return d.value; })
39590 .call(bootstrap.tooltip()
39591 .title(function(d) { return t('success.' + d.key); })
39592 .placement('bottom'))
39593 .each(function(d) { d3.select(this).call(iD.svg.Icon('#logo-' + d.key, 'social')); });
39596 success.changeset = function(_) {
39597 if (!arguments.length) return changeset;
39602 return d3.rebind(success, dispatch, 'on');
39604 iD.ui.TagReference = function(tag, context) {
39605 var tagReference = {},
39611 function findLocal(data) {
39612 var locale = iD.detect().locale.toLowerCase(),
39615 localized = _.find(data, function(d) {
39616 return d.lang.toLowerCase() === locale;
39618 if (localized) return localized;
39620 // try the non-regional version of a language, like
39621 // 'en' if the language is 'en-US'
39622 if (locale.indexOf('-') !== -1) {
39623 var first = locale.split('-')[0];
39624 localized = _.find(data, function(d) {
39625 return d.lang.toLowerCase() === first;
39627 if (localized) return localized;
39630 // finally fall back to english
39631 return _.find(data, function(d) {
39632 return d.lang.toLowerCase() === 'en';
39636 function load(param) {
39637 button.classed('tag-reference-loading', true);
39639 context.taginfo().docs(param, function show(err, data) {
39641 if (!err && data) {
39642 docs = findLocal(data);
39647 if (!docs || !docs.description) {
39648 if (param.hasOwnProperty('value')) {
39649 load(_.omit(param, 'value')); // retry with key only
39651 body.append('p').text(t('inspector.no_documentation_key'));
39657 if (docs.image && docs.image.thumb_url_prefix) {
39660 .attr('class', 'wiki-image')
39661 .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
39662 .on('load', function() { done(); })
39663 .on('error', function() { d3.select(this).remove(); done(); });
39670 .text(docs.description);
39674 .attr('target', '_blank')
39675 .attr('tabindex', -1)
39676 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
39677 .call(iD.svg.Icon('#icon-out-link', 'inline'))
39679 .text(t('inspector.reference'));
39686 button.classed('tag-reference-loading', false);
39690 .style('max-height', '200px')
39691 .style('opacity', '1');
39696 function hide(selection) {
39697 selection = selection || body.transition().duration(200);
39700 .style('max-height', '0px')
39701 .style('opacity', '0');
39706 tagReference.button = function(selection) {
39707 button = selection.selectAll('.tag-reference-button')
39712 .attr('class', 'tag-reference-button')
39713 .attr('tabindex', -1)
39714 .call(iD.svg.Icon('#icon-inspect'));
39716 button.on('click', function () {
39717 d3.event.stopPropagation();
39718 d3.event.preventDefault();
39721 } else if (loaded) {
39724 if (context.taginfo()) {
39731 tagReference.body = function(selection) {
39732 body = selection.selectAll('.tag-reference-body')
39735 body.enter().append('div')
39736 .attr('class', 'tag-reference-body cf')
39737 .style('max-height', '0')
39738 .style('opacity', '0');
39740 if (showing === false) {
39745 tagReference.showing = function(_) {
39746 if (!arguments.length) return showing;
39748 return tagReference;
39751 return tagReference;
39753 // toggles the visibility of ui elements, using a combination of the
39754 // hide class, which sets display=none, and a d3 transition for opacity.
39755 // this will cause blinking when called repeatedly, so check that the
39756 // value actually changes between calls.
39757 iD.ui.Toggle = function(show, callback) {
39758 return function(selection) {
39760 .style('opacity', show ? 0 : 1)
39761 .classed('hide', false)
39763 .style('opacity', show ? 1 : 0)
39764 .each('end', function() {
39766 .classed('hide', !show)
39767 .style('opacity', null);
39768 if (callback) callback.apply(this);
39772 iD.ui.UndoRedo = function(context) {
39775 cmd: iD.ui.cmd('⌘Z'),
39776 action: function() { if (!(context.inIntro() || saving())) context.undo(); },
39777 annotation: function() { return context.history().undoAnnotation(); }
39780 cmd: iD.ui.cmd('⌘⇧Z'),
39781 action: function() {if (!(context.inIntro() || saving())) context.redo(); },
39782 annotation: function() { return context.history().redoAnnotation(); }
39785 function saving() {
39786 return context.mode().id === 'save';
39789 return function(selection) {
39790 var tooltip = bootstrap.tooltip()
39791 .placement('bottom')
39793 .title(function (d) {
39794 return iD.ui.tooltipHtml(d.annotation() ?
39795 t(d.id + '.tooltip', {action: d.annotation()}) :
39796 t(d.id + '.nothing'), d.cmd);
39799 var buttons = selection.selectAll('button')
39801 .enter().append('button')
39802 .attr('class', 'col6 disabled')
39803 .on('click', function(d) { return d.action(); })
39806 buttons.each(function(d) {
39808 .call(iD.svg.Icon('#icon-' + d.id));
39811 var keybinding = d3.keybinding('undo')
39812 .on(commands[0].cmd, function() { d3.event.preventDefault(); commands[0].action(); })
39813 .on(commands[1].cmd, function() { d3.event.preventDefault(); commands[1].action(); });
39815 d3.select(document)
39819 .on('change.undo_redo', update);
39822 .on('enter.undo_redo', update);
39824 function update() {
39826 .property('disabled', saving())
39827 .classed('disabled', function(d) { return !d.annotation(); })
39829 var selection = d3.select(this);
39830 if (selection.property('tooltipVisible')) {
39831 selection.call(tooltip.show);
39837 iD.ui.ViewOnOSM = function(context) {
39840 function viewOnOSM(selection) {
39841 var entity = context.entity(id);
39843 selection.style('display', entity.isNew() ? 'none' : null);
39845 var $link = selection.selectAll('.view-on-osm')
39850 .attr('class', 'view-on-osm')
39851 .attr('target', '_blank')
39852 .call(iD.svg.Icon('#icon-out-link', 'inline'))
39854 .text(t('inspector.view_on_osm'));
39857 .attr('href', context.connection().entityURL(entity));
39860 viewOnOSM.entityID = function(_) {
39861 if (!arguments.length) return id;
39868 iD.ui.Zoom = function(context) {
39872 title: t('zoom.in'),
39873 action: context.zoomIn,
39878 title: t('zoom.out'),
39879 action: context.zoomOut,
39883 function zoomIn() {
39884 d3.event.preventDefault();
39885 if (!context.inIntro()) context.zoomIn();
39888 function zoomOut() {
39889 d3.event.preventDefault();
39890 if (!context.inIntro()) context.zoomOut();
39893 function zoomInFurther() {
39894 d3.event.preventDefault();
39895 if (!context.inIntro()) context.zoomInFurther();
39898 function zoomOutFurther() {
39899 d3.event.preventDefault();
39900 if (!context.inIntro()) context.zoomOutFurther();
39904 return function(selection) {
39905 var button = selection.selectAll('button')
39907 .enter().append('button')
39908 .attr('tabindex', -1)
39909 .attr('class', function(d) { return d.id; })
39910 .on('click.editor', function(d) { d.action(); })
39911 .call(bootstrap.tooltip()
39914 .title(function(d) {
39915 return iD.ui.tooltipHtml(d.title, d.key);
39918 button.each(function(d) {
39920 .call(iD.svg.Icon('#icon-' + d.icon, 'light'));
39923 var keybinding = d3.keybinding('zoom');
39925 _.each(['=','ffequals','plus','ffplus'], function(key) {
39926 keybinding.on(key, zoomIn);
39927 keybinding.on('⇧' + key, zoomIn);
39928 keybinding.on(iD.ui.cmd('⌘' + key), zoomInFurther);
39929 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomInFurther);
39931 _.each(['-','ffminus','_','dash'], function(key) {
39932 keybinding.on(key, zoomOut);
39933 keybinding.on('⇧' + key, zoomOut);
39934 keybinding.on(iD.ui.cmd('⌘' + key), zoomOutFurther);
39935 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomOutFurther);
39938 d3.select(document)
39942 iD.ui.preset.access = function(field) {
39943 var dispatch = d3.dispatch('change'),
39946 function access(selection) {
39947 var wrap = selection.selectAll('.preset-input-wrap')
39950 wrap.enter().append('div')
39951 .attr('class', 'cf preset-input-wrap')
39954 items = wrap.select('ul').selectAll('li')
39959 var enter = items.enter().append('li')
39960 .attr('class', function(d) { return 'cf preset-access-' + d; });
39962 enter.append('span')
39963 .attr('class', 'col6 label preset-label-access')
39964 .attr('for', function(d) { return 'preset-input-access-' + d; })
39965 .text(function(d) { return field.t('types.' + d); });
39967 enter.append('div')
39968 .attr('class', 'col6 preset-input-access-wrap')
39970 .attr('type', 'text')
39971 .attr('class', 'preset-input-access')
39972 .attr('id', function(d) { return 'preset-input-access-' + d; })
39973 .each(function(d) {
39975 .call(d3.combobox()
39976 .data(access.options(d)));
39981 wrap.selectAll('.preset-input-access')
39982 .on('change', change)
39983 .on('blur', change);
39986 function change(d) {
39988 tag[d] = d3.select(this).value() || undefined;
39989 dispatch.change(tag);
39992 access.options = function(type) {
39993 var options = ['no', 'permissive', 'private', 'destination'];
39995 if (type !== 'access') {
39996 options.unshift('yes');
39997 options.push('designated');
39999 if (type === 'bicycle') {
40000 options.push('dismount');
40004 return options.map(function(option) {
40006 title: field.t('options.' + option + '.description'),
40012 var placeholders = {
40014 foot: 'designated',
40015 motor_vehicle: 'no'
40019 motor_vehicle: 'no',
40025 motor_vehicle: 'no'
40028 motor_vehicle: 'no',
40029 bicycle: 'designated'
40032 motor_vehicle: 'no',
40033 horse: 'designated'
40037 motor_vehicle: 'no',
40043 motor_vehicle: 'yes',
40048 motor_vehicle: 'yes'
40052 motor_vehicle: 'yes',
40058 motor_vehicle: 'yes',
40064 motor_vehicle: 'yes',
40070 motor_vehicle: 'yes',
40076 motor_vehicle: 'yes',
40082 motor_vehicle: 'yes',
40088 motor_vehicle: 'yes',
40093 motor_vehicle: 'yes'
40097 motor_vehicle: 'yes',
40103 motor_vehicle: 'yes',
40109 motor_vehicle: 'yes',
40115 access.tags = function(tags) {
40116 items.selectAll('.preset-input-access')
40117 .value(function(d) { return tags[d] || ''; })
40118 .attr('placeholder', function() {
40119 return tags.access ? tags.access : field.placeholder();
40122 // items.selectAll('#preset-input-access-access')
40123 // .attr('placeholder', 'yes');
40125 _.forEach(placeholders[tags.highway], function(v, k) {
40126 items.selectAll('#preset-input-access-' + k)
40127 .attr('placeholder', function() { return (tags.access || v); });
40131 access.focus = function() {
40132 items.selectAll('.preset-input-access')
40136 return d3.rebind(access, dispatch, 'on');
40138 iD.ui.preset.address = function(field, context) {
40139 var dispatch = d3.dispatch('init', 'change'),
40152 function getStreets() {
40153 var extent = entity.extent(context.graph()),
40154 l = extent.center(),
40155 box = iD.geo.Extent(l).padByMeters(200);
40157 return context.intersects(box)
40158 .filter(isAddressable)
40160 var loc = context.projection([
40161 (extent[0][0] + extent[1][0]) / 2,
40162 (extent[0][1] + extent[1][1]) / 2]),
40163 choice = iD.geo.chooseEdge(context.childNodes(d), loc, context.projection);
40165 title: d.tags.name,
40166 value: d.tags.name,
40167 dist: choice.distance
40169 }).sort(function(a, b) {
40170 return a.dist - b.dist;
40173 function isAddressable(d) {
40174 return d.tags.highway && d.tags.name && d.type === 'way';
40178 function getCities() {
40179 var extent = entity.extent(context.graph()),
40180 l = extent.center(),
40181 box = iD.geo.Extent(l).padByMeters(200);
40183 return context.intersects(box)
40184 .filter(isAddressable)
40187 title: d.tags['addr:city'] || d.tags.name,
40188 value: d.tags['addr:city'] || d.tags.name,
40189 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
40191 }).sort(function(a, b) {
40192 return a.dist - b.dist;
40195 function isAddressable(d) {
40197 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
40200 if (d.tags.place && d.tags.name && (
40201 d.tags.place === 'city' ||
40202 d.tags.place === 'town' ||
40203 d.tags.place === 'village'))
40206 if (d.tags['addr:city']) return true;
40212 function getPostCodes() {
40213 var extent = entity.extent(context.graph()),
40214 l = extent.center(),
40215 box = iD.geo.Extent(l).padByMeters(200);
40217 return context.intersects(box)
40218 .filter(isAddressable)
40221 title: d.tags['addr:postcode'],
40222 value: d.tags['addr:postcode'],
40223 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
40225 }).sort(function(a, b) {
40226 return a.dist - b.dist;
40229 function isAddressable(d) {
40230 return d.tags['addr:postcode'];
40234 function address(selection) {
40235 isInitialized = false;
40237 wrap = selection.selectAll('.preset-input-wrap')
40244 .attr('class', 'preset-input-wrap');
40246 var center = entity.extent(context.graph()).center(),
40249 iD.services.nominatim().countryCode(center, function (err, countryCode) {
40250 addressFormat = _.find(iD.data.addressFormats, function (a) {
40251 return a && a.countryCodes && _.includes(a.countryCodes, countryCode);
40252 }) || _.first(iD.data.addressFormats);
40255 // Normalize widths.
40256 var total = _.reduce(r, function(sum, field) {
40257 return sum + (widths[field] || 0.5);
40260 return r.map(function (field) {
40263 width: (widths[field] || 0.5) / total
40268 wrap.selectAll('div')
40269 .data(addressFormat.format)
40272 .attr('class', 'addr-row')
40273 .selectAll('input')
40277 .property('type', 'text')
40278 .attr('placeholder', function (d) { return field.t('placeholders.' + d.id); })
40279 .attr('class', function (d) { return 'addr-' + d.id; })
40280 .style('width', function (d) { return d.width * 100 + '%'; });
40284 wrap.selectAll('.addr-street')
40285 .call(d3.combobox()
40286 .fetcher(function(value, callback) {
40287 callback(getStreets());
40290 wrap.selectAll('.addr-city')
40291 .call(d3.combobox()
40292 .fetcher(function(value, callback) {
40293 callback(getCities());
40296 wrap.selectAll('.addr-postcode')
40297 .call(d3.combobox()
40298 .fetcher(function(value, callback) {
40299 callback(getPostCodes());
40302 wrap.selectAll('input')
40303 .on('blur', change())
40304 .on('change', change());
40306 wrap.selectAll('input:not(.combobox-input)')
40307 .on('input', change(true));
40310 isInitialized = true;
40314 function change(onInput) {
40315 return function() {
40318 wrap.selectAll('input')
40319 .each(function (field) {
40320 tags['addr:' + field.id] = this.value || undefined;
40323 dispatch.change(tags, onInput);
40327 function updateTags(tags) {
40328 wrap.selectAll('input')
40329 .value(function (field) {
40330 return tags['addr:' + field.id] || '';
40334 address.entity = function(_) {
40335 if (!arguments.length) return entity;
40340 address.tags = function(tags) {
40341 if (isInitialized) {
40344 dispatch.on('init', function () {
40350 address.focus = function() {
40351 var node = wrap.selectAll('input').node();
40352 if (node) node.focus();
40355 return d3.rebind(address, dispatch, 'on');
40357 iD.ui.preset.check =
40358 iD.ui.preset.defaultcheck = function(field) {
40359 var dispatch = d3.dispatch('change'),
40360 options = field.strings && field.strings.options,
40363 entity, value, box, text, label;
40366 for (var k in options) {
40367 values.push(k === 'undefined' ? undefined : k);
40368 texts.push(field.t('options.' + k, { 'default': options[k] }));
40371 values = [undefined, 'yes'];
40372 texts = [t('inspector.unknown'), t('inspector.check.yes')];
40373 if (field.type === 'check') {
40375 texts.push(t('inspector.check.no'));
40379 var check = function(selection) {
40380 // hack: pretend oneway field is a oneway_yes field
40381 // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
40382 if (field.id === 'oneway') {
40383 for (var key in entity.tags) {
40384 if (key in iD.oneWayTags && (entity.tags[key] in iD.oneWayTags[key])) {
40385 texts[0] = t('presets.fields.oneway_yes.options.undefined');
40391 selection.classed('checkselect', 'true');
40393 label = selection.selectAll('.preset-input-wrap')
40396 var enter = label.enter().append('label')
40397 .attr('class', 'preset-input-wrap');
40399 enter.append('input')
40400 .property('indeterminate', field.type === 'check')
40401 .attr('type', 'checkbox')
40402 .attr('id', 'preset-input-' + field.id);
40404 enter.append('span')
40406 .attr('class', 'value');
40408 box = label.select('input')
40409 .on('click', function() {
40411 t[field.key] = values[(values.indexOf(value) + 1) % values.length];
40412 dispatch.change(t);
40413 d3.event.stopPropagation();
40416 text = label.select('span.value');
40419 check.entity = function(_) {
40420 if (!arguments.length) return entity;
40425 check.tags = function(tags) {
40426 value = tags[field.key];
40427 box.property('indeterminate', field.type === 'check' && !value);
40428 box.property('checked', value === 'yes');
40429 text.text(texts[values.indexOf(value)]);
40430 label.classed('set', !!value);
40433 check.focus = function() {
40434 box.node().focus();
40437 return d3.rebind(check, dispatch, 'on');
40439 iD.ui.preset.combo =
40440 iD.ui.preset.typeCombo =
40441 iD.ui.preset.multiCombo = function(field, context) {
40442 var dispatch = d3.dispatch('change'),
40443 isMulti = (field.type === 'multiCombo'),
40444 optstrings = field.strings && field.strings.options,
40445 optarray = field.options,
40446 snake_case = (field.snake_case || (field.snake_case === undefined)),
40447 combobox = d3.combobox().minItems(isMulti ? 1 : 2),
40454 // ensure multiCombo field.key ends with a ':'
40455 if (isMulti && field.key.match(/:$/) === null) {
40460 function snake(s) {
40461 return s.replace(/\s+/g, '_');
40464 function unsnake(s) {
40465 return s.replace(/_+/g, ' ');
40468 function clean(s) {
40469 return s.split(';')
40470 .map(function(s) { return s.trim(); })
40475 // returns the tag value for a display value
40476 // (for multiCombo, dval should be the key suffix, not the entire key)
40477 function tagValue(dval) {
40478 dval = clean(dval || '');
40481 var match = _.find(comboData, function(o) {
40482 return o.key && clean(o.value) === dval;
40489 if (field.type === 'typeCombo' && !dval) {
40493 return (snake_case ? snake(dval) : dval) || undefined;
40497 // returns the display value for a tag value
40498 // (for multiCombo, tval should be the key suffix, not the entire key)
40499 function displayValue(tval) {
40503 var match = _.find(comboData, function(o) { return o.key === tval && o.value; });
40505 return match.value;
40509 if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
40513 return snake_case ? unsnake(tval) : tval;
40517 function objectDifference(a, b) {
40518 return _.reject(a, function(d1) {
40519 return _.some(b, function(d2) { return d1.value === d2.value; });
40524 function initCombo(selection, attachTo) {
40526 selection.attr('readonly', 'readonly');
40527 selection.call(combobox, attachTo);
40528 setStaticValues(setPlaceholder);
40530 } else if (optarray) {
40531 selection.call(combobox, attachTo);
40532 setStaticValues(setPlaceholder);
40534 } else if (context.taginfo()) {
40535 selection.call(combobox.fetcher(setTaginfoValues), attachTo);
40536 setTaginfoValues('', setPlaceholder);
40541 function setStaticValues(callback) {
40542 if (!(optstrings || optarray)) return;
40545 comboData = Object.keys(optstrings).map(function(k) {
40546 var v = field.t('options.' + k, { 'default': optstrings[k] });
40554 } else if (optarray) {
40555 comboData = optarray.map(function(k) {
40556 var v = snake_case ? unsnake(k) : k;
40565 combobox.data(objectDifference(comboData, multiData));
40566 if (callback) callback(comboData);
40570 function setTaginfoValues(q, callback) {
40571 var fn = isMulti ? 'multikeys' : 'values';
40572 context.taginfo()[fn]({
40575 geometry: context.geometry(entity.id),
40576 query: (isMulti ? field.key : '') + q
40577 }, function(err, data) {
40579 comboData = _.map(data, 'value').map(function(k) {
40580 if (isMulti) k = k.replace(field.key, '');
40581 var v = snake_case ? unsnake(k) : k;
40588 comboData = objectDifference(comboData, multiData);
40589 if (callback) callback(comboData);
40594 function setPlaceholder(d) {
40597 ph = field.placeholder() || t('inspector.add');
40599 var vals = _.map(d, 'value').filter(function(s) { return s.length < 20; }),
40600 placeholders = vals.length > 1 ? vals : _.map(d, 'key');
40601 ph = field.placeholder() || placeholders.slice(0, 3).join(', ');
40604 input.attr('placeholder', ph + '…');
40608 function change() {
40609 var val = tagValue(input.value()),
40614 container.classed('active', false);
40616 field.keys.push(field.key + val);
40617 t[field.key + val] = 'yes';
40618 window.setTimeout(function() { input.node().focus(); }, 10);
40621 t[field.key] = val;
40624 dispatch.change(t);
40628 function removeMultikey(d) {
40629 d3.event.stopPropagation();
40631 t[d.key] = undefined;
40632 dispatch.change(t);
40636 function combo(selection) {
40638 container = selection.selectAll('ul').data([0]);
40642 .attr('class', 'form-field-multicombo')
40643 .on('click', function() {
40644 window.setTimeout(function() { input.node().focus(); }, 10);
40648 container = selection;
40651 input = container.selectAll('input')
40656 .attr('type', 'text')
40657 .attr('id', 'preset-input-' + field.id)
40658 .call(initCombo, selection);
40661 .on('change', change)
40662 .on('blur', change);
40666 .on('accept', function() {
40667 input.node().blur();
40668 input.node().focus();
40672 .on('focus', function() { container.classed('active', true); });
40677 combo.tags = function(tags) {
40681 // Build multiData array containing keys already set..
40682 Object.keys(tags).forEach(function(key) {
40683 if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return;
40685 var suffix = key.substring(field.key.length);
40688 value: displayValue(suffix)
40692 // Set keys for form-field modified (needed for undo and reset buttons)..
40693 field.keys = _.map(multiData, 'key');
40695 // Exclude existing multikeys from combo options..
40696 var available = objectDifference(comboData, multiData);
40697 combobox.data(available);
40699 // Hide "Add" button if this field uses fixed set of
40700 // translateable optstrings and they're all currently used..
40701 container.selectAll('.combobox-input, .combobox-caret')
40702 .classed('hide', optstrings && !available.length);
40706 var chips = container.selectAll('.chips').data(multiData);
40708 var enter = chips.enter()
40709 .insert('li', 'input')
40710 .attr('class', 'chips');
40712 enter.append('span');
40715 chips.select('span')
40716 .text(function(d) { return d.value; });
40719 .on('click', removeMultikey)
40720 .attr('class', 'remove')
40727 input.value(displayValue(tags[field.key]));
40732 combo.focus = function() {
40733 input.node().focus();
40737 combo.entity = function(_) {
40738 if (!arguments.length) return entity;
40744 return d3.rebind(combo, dispatch, 'on');
40746 iD.ui.preset.cycleway = function(field) {
40747 var dispatch = d3.dispatch('change'),
40750 function cycleway(selection) {
40751 var wrap = selection.selectAll('.preset-input-wrap')
40754 wrap.enter().append('div')
40755 .attr('class', 'cf preset-input-wrap')
40758 items = wrap.select('ul').selectAll('li')
40763 var enter = items.enter().append('li')
40764 .attr('class', function(d) { return 'cf preset-cycleway-' + d; });
40766 enter.append('span')
40767 .attr('class', 'col6 label preset-label-cycleway')
40768 .attr('for', function(d) { return 'preset-input-cycleway-' + d; })
40769 .text(function(d) { return field.t('types.' + d); });
40771 enter.append('div')
40772 .attr('class', 'col6 preset-input-cycleway-wrap')
40774 .attr('type', 'text')
40775 .attr('class', 'preset-input-cycleway')
40776 .attr('id', function(d) { return 'preset-input-cycleway-' + d; })
40777 .each(function(d) {
40779 .call(d3.combobox()
40780 .data(cycleway.options(d)));
40785 wrap.selectAll('.preset-input-cycleway')
40786 .on('change', change)
40787 .on('blur', change);
40790 function change() {
40791 var inputs = d3.selectAll('.preset-input-cycleway')[0],
40792 left = d3.select(inputs[0]).value(),
40793 right = d3.select(inputs[1]).value(),
40795 if (left === 'none' || left === '') { left = undefined; }
40796 if (right === 'none' || right === '') { right = undefined; }
40798 // Always set both left and right as changing one can affect the other
40800 cycleway: undefined,
40801 'cycleway:left': left,
40802 'cycleway:right': right
40805 // If the left and right tags match, use the cycleway tag to tag both
40806 // sides the same way
40807 if (left === right) {
40810 'cycleway:left': undefined,
40811 'cycleway:right': undefined
40815 dispatch.change(tag);
40818 cycleway.options = function() {
40819 return d3.keys(field.strings.options).map(function(option) {
40821 title: field.t('options.' + option + '.description'),
40827 cycleway.tags = function(tags) {
40828 items.selectAll('.preset-input-cycleway')
40829 .value(function(d) {
40830 // If cycleway is set, always return that
40831 if (tags.cycleway) {
40832 return tags.cycleway;
40834 return tags[d] || '';
40836 .attr('placeholder', field.placeholder());
40839 cycleway.focus = function() {
40840 items.selectAll('.preset-input-cycleway')
40844 return d3.rebind(cycleway, dispatch, 'on');
40846 iD.ui.preset.text =
40847 iD.ui.preset.number =
40849 iD.ui.preset.email =
40850 iD.ui.preset.url = function(field, context) {
40852 var dispatch = d3.dispatch('change'),
40856 function i(selection) {
40857 var fieldId = 'preset-input-' + field.id;
40859 input = selection.selectAll('input')
40862 input.enter().append('input')
40863 .attr('type', field.type)
40864 .attr('id', fieldId)
40865 .attr('placeholder', field.placeholder() || t('inspector.unknown'));
40868 .on('input', change(true))
40869 .on('blur', change())
40870 .on('change', change());
40872 if (field.type === 'tel') {
40873 var center = entity.extent(context.graph()).center();
40874 iD.services.nominatim().countryCode(center, function (err, countryCode) {
40875 if (err || !iD.data.phoneFormats[countryCode]) return;
40876 selection.selectAll('#' + fieldId)
40877 .attr('placeholder', iD.data.phoneFormats[countryCode]);
40880 } else if (field.type === 'number') {
40881 input.attr('type', 'text');
40883 var spinControl = selection.selectAll('.spin-control')
40886 var enter = spinControl.enter().append('div')
40887 .attr('class', 'spin-control');
40889 enter.append('button')
40891 .attr('class', 'increment')
40892 .attr('tabindex', -1);
40894 enter.append('button')
40896 .attr('class', 'decrement')
40897 .attr('tabindex', -1);
40899 spinControl.selectAll('button')
40900 .on('click', function(d) {
40901 d3.event.preventDefault();
40902 var num = parseInt(input.node().value || 0, 10);
40903 if (!isNaN(num)) input.node().value = num + d;
40909 function change(onInput) {
40910 return function() {
40912 t[field.key] = input.value() || undefined;
40913 dispatch.change(t, onInput);
40917 i.entity = function(_) {
40918 if (!arguments.length) return entity;
40923 i.tags = function(tags) {
40924 input.value(tags[field.key] || '');
40927 i.focus = function() {
40928 var node = input.node();
40929 if (node) node.focus();
40932 return d3.rebind(i, dispatch, 'on');
40934 iD.ui.preset.localized = function(field, context) {
40935 var dispatch = d3.dispatch('change', 'input'),
40936 wikipedia = iD.services.wikipedia(),
40937 input, localizedInputs, wikiTitles,
40940 function localized(selection) {
40941 input = selection.selectAll('.localized-main')
40944 input.enter().append('input')
40945 .attr('type', 'text')
40946 .attr('id', 'preset-input-' + field.id)
40947 .attr('class', 'localized-main')
40948 .attr('placeholder', field.placeholder());
40950 if (field.id === 'name') {
40951 var preset = context.presets().match(entity, context.graph());
40952 input.call(d3.combobox().fetcher(
40953 iD.util.SuggestNames(preset, iD.data.suggestions)
40958 .on('input', change(true))
40959 .on('blur', change())
40960 .on('change', change());
40962 var translateButton = selection.selectAll('.localized-add')
40965 translateButton.enter()
40967 .attr('class', 'button-input-action localized-add minor')
40968 .attr('tabindex', -1)
40969 .call(iD.svg.Icon('#icon-plus'))
40970 .call(bootstrap.tooltip()
40971 .title(t('translate.translate'))
40972 .placement('left'));
40975 .on('click', addNew);
40977 localizedInputs = selection.selectAll('.localized-wrap')
40980 localizedInputs.enter().append('div')
40981 .attr('class', 'localized-wrap');
40984 function addNew() {
40985 d3.event.preventDefault();
40986 var data = localizedInputs.selectAll('div.entry').data();
40987 var defaultLang = iD.detect().locale.toLowerCase().split('-')[0];
40988 var langExists = _.find(data, function(datum) { return datum.lang === defaultLang;});
40989 var isLangEn = defaultLang.indexOf('en') > -1;
40990 if (isLangEn || langExists) {
40993 data.push({ lang: defaultLang, value: '' });
40994 localizedInputs.call(render, data);
40997 function change(onInput) {
40998 return function() {
41000 t[field.key] = d3.select(this).value() || undefined;
41001 dispatch.change(t, onInput);
41005 function key(lang) { return field.key + ':' + lang; }
41007 function changeLang(d) {
41008 var lang = d3.select(this).value(),
41010 language = _.find(iD.data.wikipedia, function(d) {
41011 return d[0].toLowerCase() === lang.toLowerCase() ||
41012 d[1].toLowerCase() === lang.toLowerCase();
41015 if (language) lang = language[2];
41017 if (d.lang && d.lang !== lang) {
41018 t[key(d.lang)] = undefined;
41021 var value = d3.select(this.parentNode)
41022 .selectAll('.localized-value')
41025 if (lang && value) {
41026 t[key(lang)] = value;
41027 } else if (lang && wikiTitles && wikiTitles[d.lang]) {
41028 t[key(lang)] = wikiTitles[d.lang];
41032 dispatch.change(t);
41035 function changeValue(d) {
41036 if (!d.lang) return;
41038 t[key(d.lang)] = d3.select(this).value() || undefined;
41039 dispatch.change(t);
41042 function fetcher(value, cb) {
41043 var v = value.toLowerCase();
41045 cb(iD.data.wikipedia.filter(function(d) {
41046 return d[0].toLowerCase().indexOf(v) >= 0 ||
41047 d[1].toLowerCase().indexOf(v) >= 0 ||
41048 d[2].toLowerCase().indexOf(v) >= 0;
41049 }).map(function(d) {
41050 return { value: d[1] };
41054 function render(selection, data) {
41055 var wraps = selection.selectAll('div.entry').
41056 data(data, function(d) { return d.lang; });
41058 var innerWrap = wraps.enter()
41059 .insert('div', ':first-child');
41061 innerWrap.attr('class', 'entry')
41063 var wrap = d3.select(this);
41064 var langcombo = d3.combobox().fetcher(fetcher).minItems(0);
41066 var label = wrap.append('label')
41067 .attr('class','form-label')
41068 .text(t('translate.localized_translation_label'))
41069 .attr('for','localized-lang');
41071 label.append('button')
41072 .attr('class', 'minor remove')
41073 .on('click', function(d){
41074 d3.event.preventDefault();
41076 t[key(d.lang)] = undefined;
41077 dispatch.change(t);
41078 d3.select(this.parentNode.parentNode)
41080 .style('max-height','240px')
41082 .style('opacity', '0')
41083 .style('max-height','0px')
41086 .call(iD.svg.Icon('#operation-delete'));
41088 wrap.append('input')
41089 .attr('class', 'localized-lang')
41090 .attr('type', 'text')
41091 .attr('placeholder',t('translate.localized_translation_language'))
41092 .on('blur', changeLang)
41093 .on('change', changeLang)
41096 wrap.append('input')
41097 .on('blur', changeValue)
41098 .on('change', changeValue)
41099 .attr('type', 'text')
41100 .attr('placeholder', t('translate.localized_translation_name'))
41101 .attr('class', 'localized-value');
41105 .style('margin-top', '0px')
41106 .style('max-height', '0px')
41107 .style('opacity', '0')
41110 .style('margin-top', '10px')
41111 .style('max-height', '240px')
41112 .style('opacity', '1')
41113 .each('end', function() {
41115 .style('max-height', '')
41116 .style('overflow', 'visible');
41122 .style('max-height','0px')
41123 .style('opacity', '0')
41124 .style('top','-10px')
41127 var entry = selection.selectAll('.entry');
41129 entry.select('.localized-lang')
41130 .value(function(d) {
41131 var lang = _.find(iD.data.wikipedia, function(lang) { return lang[2] === d.lang; });
41132 return lang ? lang[1] : d.lang;
41135 entry.select('.localized-value')
41136 .value(function(d) { return d.value; });
41139 localized.tags = function(tags) {
41140 // Fetch translations from wikipedia
41141 if (tags.wikipedia && !wikiTitles) {
41143 var wm = tags.wikipedia.match(/([^:]+):(.+)/);
41144 if (wm && wm[0] && wm[1]) {
41145 wikipedia.translations(wm[1], wm[2], function(d) {
41151 input.value(tags[field.key] || '');
41153 var postfixed = [], k, m;
41155 m = k.match(/^(.*):([a-zA-Z_-]+)$/);
41156 if (m && m[1] === field.key && m[2]) {
41157 postfixed.push({ lang: m[2], value: tags[k] });
41161 localizedInputs.call(render, postfixed.reverse());
41164 localized.focus = function() {
41165 input.node().focus();
41168 localized.entity = function(_) {
41169 if (!arguments.length) return entity;
41174 return d3.rebind(localized, dispatch, 'on');
41176 iD.ui.preset.maxspeed = function(field, context) {
41177 var dispatch = d3.dispatch('change'),
41184 var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
41185 imperialValues = [20, 25, 30, 35, 40, 45, 50, 55, 65, 70];
41187 function maxspeed(selection) {
41188 combobox = d3.combobox();
41189 var unitCombobox = d3.combobox().data(['km/h', 'mph'].map(comboValues));
41191 input = selection.selectAll('#preset-input-' + field.id)
41194 input.enter().append('input')
41195 .attr('type', 'text')
41196 .attr('id', 'preset-input-' + field.id)
41197 .attr('placeholder', field.placeholder());
41201 .on('change', change)
41202 .on('blur', change);
41204 var childNodes = context.graph().childNodes(context.entity(entity.id)),
41205 loc = childNodes[~~(childNodes.length/2)].loc;
41207 imperial = _.some(iD.data.imperial.features, function(f) {
41208 return _.some(f.geometry.coordinates, function(d) {
41209 return iD.geo.pointInPolygon(loc, d);
41213 unitInput = selection.selectAll('input.maxspeed-unit')
41216 unitInput.enter().append('input')
41217 .attr('type', 'text')
41218 .attr('class', 'maxspeed-unit');
41221 .on('blur', changeUnits)
41222 .on('change', changeUnits)
41223 .call(unitCombobox);
41225 function changeUnits() {
41226 imperial = unitInput.value() === 'mph';
41227 unitInput.value(imperial ? 'mph' : 'km/h');
41234 function setSuggestions() {
41235 combobox.data((imperial ? imperialValues : metricValues).map(comboValues));
41236 unitInput.value(imperial ? 'mph' : 'km/h');
41239 function comboValues(d) {
41241 value: d.toString(),
41242 title: d.toString()
41246 function change() {
41248 value = input.value();
41251 tag[field.key] = undefined;
41252 } else if (isNaN(value) || !imperial) {
41253 tag[field.key] = value;
41255 tag[field.key] = value + ' mph';
41258 dispatch.change(tag);
41261 maxspeed.tags = function(tags) {
41262 var value = tags[field.key];
41264 if (value && value.indexOf('mph') >= 0) {
41265 value = parseInt(value, 10);
41267 } else if (value) {
41273 input.value(value || '');
41276 maxspeed.focus = function() {
41277 input.node().focus();
41280 maxspeed.entity = function(_) {
41284 return d3.rebind(maxspeed, dispatch, 'on');
41286 iD.ui.preset.radio = function(field) {
41287 var dispatch = d3.dispatch('change'),
41288 labels, radios, placeholder;
41290 function radio(selection) {
41291 selection.classed('preset-radio', true);
41293 var wrap = selection.selectAll('.preset-input-wrap')
41296 var buttonWrap = wrap.enter().append('div')
41297 .attr('class', 'preset-input-wrap toggle-list');
41299 buttonWrap.append('span')
41300 .attr('class', 'placeholder');
41302 placeholder = selection.selectAll('.placeholder');
41304 labels = wrap.selectAll('label')
41305 .data(field.options || field.keys);
41307 var enter = labels.enter().append('label');
41309 enter.append('input')
41310 .attr('type', 'radio')
41311 .attr('name', field.id)
41312 .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
41313 .attr('checked', false);
41315 enter.append('span')
41316 .text(function(d) { return field.t('options.' + d, { 'default': d }); });
41318 radios = labels.selectAll('input')
41319 .on('change', change);
41322 function change() {
41324 if (field.key) t[field.key] = undefined;
41325 radios.each(function(d) {
41326 var active = d3.select(this).property('checked');
41328 if (active) t[field.key] = d;
41330 t[d] = active ? 'yes' : undefined;
41333 dispatch.change(t);
41336 radio.tags = function(tags) {
41337 function checked(d) {
41339 return tags[field.key] === d;
41341 return !!(tags[d] && tags[d] !== 'no');
41345 labels.classed('active', checked);
41346 radios.property('checked', checked);
41347 var selection = radios.filter(function() { return this.checked; });
41348 if (selection.empty()) {
41349 placeholder.text(t('inspector.none'));
41351 placeholder.text(selection.attr('value'));
41355 radio.focus = function() {
41356 radios.node().focus();
41359 return d3.rebind(radio, dispatch, 'on');
41361 iD.ui.preset.restrictions = function(field, context) {
41362 var dispatch = d3.dispatch('change'),
41363 hover = iD.behavior.Hover(context),
41368 function restrictions(selection) {
41369 // if form field is hidden or has detached from dom, clean up.
41370 if (!d3.select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
41371 selection.call(restrictions.off);
41375 var wrap = selection.selectAll('.preset-input-wrap')
41378 var enter = wrap.enter()
41380 .attr('class', 'preset-input-wrap');
41384 .attr('class', 'restriction-help');
41387 var intersection = iD.geo.Intersection(context.graph(), vertexID),
41388 graph = intersection.graph,
41389 vertex = graph.entity(vertexID),
41390 filter = d3.functor(true),
41391 extent = iD.geo.Extent(),
41392 projection = iD.geo.RawMercator();
41394 var d = wrap.dimensions(),
41395 c = [d[0] / 2, d[1] / 2],
41399 .scale(256 * Math.pow(2, z) / (2 * Math.PI));
41401 var s = projection(vertex.loc);
41404 .translate([c[0] - s[0], c[1] - s[1]])
41405 .clipExtent([[0, 0], d]);
41407 var drawLayers = iD.svg.Layers(projection, context).only('osm').dimensions(d),
41408 drawVertices = iD.svg.Vertices(projection, context),
41409 drawLines = iD.svg.Lines(projection, context),
41410 drawTurns = iD.svg.Turns(projection, context);
41414 .selectAll('.surface')
41418 var surface = wrap.selectAll('.surface');
41422 .call(drawVertices, graph, [vertex], filter, extent, z)
41423 .call(drawLines, graph, intersection.ways, filter)
41424 .call(drawTurns, graph, intersection.turns(fromNodeID));
41427 .on('click.restrictions', click)
41428 .on('mouseover.restrictions', mouseover)
41429 .on('mouseout.restrictions', mouseout);
41432 .selectAll('.selected')
41433 .classed('selected', false);
41437 .selectAll('.' + intersection.highways[fromNodeID].id)
41438 .classed('selected', true);
41444 .on('change.restrictions', render);
41447 .on('resize.restrictions', function() {
41448 wrap.dimensions(null);
41453 var datum = d3.event.target.__data__;
41454 if (datum instanceof iD.Entity) {
41455 fromNodeID = intersection.adjacentNodeId(datum.id);
41457 } else if (datum instanceof iD.geo.Turn) {
41458 if (datum.restriction) {
41460 iD.actions.UnrestrictTurn(datum, projection),
41461 t('operations.restriction.annotation.delete'));
41464 iD.actions.RestrictTurn(datum, projection),
41465 t('operations.restriction.annotation.create'));
41470 function mouseover() {
41471 var datum = d3.event.target.__data__;
41472 if (datum instanceof iD.geo.Turn) {
41473 var graph = context.graph(),
41474 presets = context.presets(),
41477 if (datum.restriction) {
41478 preset = presets.match(graph.entity(datum.restriction), graph);
41480 preset = presets.item('type/restriction/' +
41481 iD.geo.inferRestriction(
41489 wrap.selectAll('.restriction-help')
41490 .text(t('operations.restriction.help.' +
41491 (datum.restriction ? 'toggle_off' : 'toggle_on'),
41492 {restriction: preset.name()}));
41496 function mouseout() {
41497 wrap.selectAll('.restriction-help')
41498 .text(t('operations.restriction.help.' +
41499 (fromNodeID ? 'toggle' : 'select')));
41502 function render() {
41503 if (context.hasEntity(vertexID)) {
41504 restrictions(selection);
41509 restrictions.entity = function(_) {
41510 if (!vertexID || vertexID !== _.id) {
41516 restrictions.tags = function() {};
41517 restrictions.focus = function() {};
41519 restrictions.off = function(selection) {
41520 selection.selectAll('.surface')
41522 .on('click.restrictions', null)
41523 .on('mouseover.restrictions', null)
41524 .on('mouseout.restrictions', null);
41527 .on('change.restrictions', null);
41530 .on('resize.restrictions', null);
41533 return d3.rebind(restrictions, dispatch, 'on');
41535 iD.ui.preset.textarea = function(field) {
41536 var dispatch = d3.dispatch('change'),
41539 function textarea(selection) {
41540 input = selection.selectAll('textarea')
41543 input.enter().append('textarea')
41544 .attr('id', 'preset-input-' + field.id)
41545 .attr('placeholder', field.placeholder() || t('inspector.unknown'))
41546 .attr('maxlength', 255);
41549 .on('input', change(true))
41550 .on('blur', change())
41551 .on('change', change());
41554 function change(onInput) {
41555 return function() {
41557 t[field.key] = input.value() || undefined;
41558 dispatch.change(t, onInput);
41562 textarea.tags = function(tags) {
41563 input.value(tags[field.key] || '');
41566 textarea.focus = function() {
41567 input.node().focus();
41570 return d3.rebind(textarea, dispatch, 'on');
41572 iD.ui.preset.wikipedia = function(field, context) {
41573 var dispatch = d3.dispatch('change'),
41574 wikipedia = iD.services.wikipedia(),
41575 wikidata = iD.services.wikidata(),
41576 link, entity, lang, title;
41578 function wiki(selection) {
41579 var langcombo = d3.combobox()
41580 .fetcher(function(value, cb) {
41581 var v = value.toLowerCase();
41583 cb(iD.data.wikipedia.filter(function(d) {
41584 return d[0].toLowerCase().indexOf(v) >= 0 ||
41585 d[1].toLowerCase().indexOf(v) >= 0 ||
41586 d[2].toLowerCase().indexOf(v) >= 0;
41587 }).map(function(d) {
41588 return { value: d[1] };
41592 var titlecombo = d3.combobox()
41593 .fetcher(function(value, cb) {
41595 if (!value) value = context.entity(entity.id).tags.name || '';
41596 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
41598 searchfn(language()[2], value, function(query, data) {
41599 cb(data.map(function(d) {
41600 return { value: d };
41605 lang = selection.selectAll('input.wiki-lang')
41608 lang.enter().append('input')
41609 .attr('type', 'text')
41610 .attr('class', 'wiki-lang')
41611 .attr('placeholder', t('translate.localized_translation_language'))
41616 .on('blur', changeLang)
41617 .on('change', changeLang);
41619 title = selection.selectAll('input.wiki-title')
41622 title.enter().append('input')
41623 .attr('type', 'text')
41624 .attr('class', 'wiki-title')
41625 .attr('id', 'preset-input-' + field.id);
41630 .on('change', change);
41632 link = selection.selectAll('a.wiki-link')
41635 link.enter().append('a')
41636 .attr('class', 'wiki-link button-input-action minor')
41637 .attr('tabindex', -1)
41638 .attr('target', '_blank')
41639 .call(iD.svg.Icon('#icon-out-link', 'inline'));
41642 function language() {
41643 var value = lang.value().toLowerCase();
41644 var locale = iD.detect().locale.toLowerCase();
41645 var localeLanguage;
41646 return _.find(iD.data.wikipedia, function(d) {
41647 if (d[2] === locale) localeLanguage = d;
41648 return d[0].toLowerCase() === value ||
41649 d[1].toLowerCase() === value ||
41651 }) || localeLanguage || ['English', 'English', 'en'];
41654 function changeLang() {
41655 lang.value(language()[1]);
41663 function change(skipWikidata) {
41664 var value = title.value(),
41665 m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
41666 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
41671 // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
41672 value = decodeURIComponent(m[2]).replace(/_/g, ' ');
41675 // Best-effort `anchordecode:` implementation
41676 anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
41678 anchor = decodeURIComponent(m[3]);
41680 value += '#' + anchor.replace(/_/g, ' ');
41682 value = value.slice(0, 1).toUpperCase() + value.slice(1);
41684 title.value(value);
41687 syncTags.wikipedia = value ? language()[2] + ':' + value : undefined;
41688 if (!skipWikidata) {
41689 syncTags.wikidata = undefined;
41692 dispatch.change(syncTags);
41695 if (skipWikidata || !value || !language()[2]) return;
41697 // attempt asynchronous update of wikidata tag..
41698 var initEntityId = entity.id,
41699 initWikipedia = context.entity(initEntityId).tags.wikipedia;
41701 wikidata.itemsByTitle(language()[2], value, function (title, data) {
41702 // 1. most recent change was a tag change
41703 var annotation = t('operations.change_tags.annotation'),
41704 currAnnotation = context.history().undoAnnotation();
41705 if (currAnnotation !== annotation) return;
41707 // 2. same entity exists and still selected
41708 var selectedIds = context.selectedIDs(),
41709 currEntityId = selectedIds.length > 0 && selectedIds[0];
41710 if (currEntityId !== initEntityId) return;
41712 // 3. wikipedia value has not changed
41713 var currTags = _.clone(context.entity(currEntityId).tags),
41714 qids = data && Object.keys(data);
41715 if (initWikipedia !== currTags.wikipedia) return;
41717 // ok to coalesce the update of wikidata tag into the previous tag change
41718 currTags.wikidata = qids && _.find(qids, function (id) {
41719 return id.match(/^Q\d+$/);
41722 context.overwrite(iD.actions.ChangeTags(currEntityId, currTags), annotation);
41723 dispatch.change(currTags);
41727 wiki.tags = function(tags) {
41728 var value = tags[field.key] || '',
41729 m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
41730 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
41731 anchor = m && m[3];
41733 // value in correct format
41736 title.value(m[2] + (anchor ? ('#' + anchor) : ''));
41739 // Best-effort `anchorencode:` implementation
41740 anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
41742 anchor = anchor.replace(/ /g, '_');
41745 link.attr('href', 'https://' + m[1] + '.wikipedia.org/wiki/' +
41746 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : ''));
41748 // unrecognized value format
41750 title.value(value);
41751 if (value && value !== '') {
41754 link.attr('href', 'https://en.wikipedia.org/wiki/Special:Search?search=' + value);
41758 wiki.entity = function(_) {
41759 if (!arguments.length) return entity;
41764 wiki.focus = function() {
41765 title.node().focus();
41768 return d3.rebind(wiki, dispatch, 'on');
41770 iD.ui.intro.area = function(context, reveal) {
41771 var event = d3.dispatch('done'),
41775 title: 'intro.areas.title'
41778 step.enter = function() {
41779 var playground = [-85.63552, 41.94159],
41780 corner = [-85.63565411045074, 41.9417715536927];
41781 context.map().centerZoom(playground, 19);
41782 reveal('button.add-area',
41783 t('intro.areas.add', { button: iD.ui.intro.icon('#icon-area', 'pre-text') }),
41784 { tooltipClass: 'intro-areas-add' });
41786 context.on('enter.intro', addArea);
41788 function addArea(mode) {
41789 if (mode.id !== 'add-area') return;
41790 context.on('enter.intro', drawArea);
41792 var padding = 120 * Math.pow(2, context.map().zoom() - 19);
41793 var pointBox = iD.ui.intro.pad(corner, padding, context);
41794 reveal(pointBox, t('intro.areas.corner'));
41796 context.map().on('move.intro', function() {
41797 padding = 120 * Math.pow(2, context.map().zoom() - 19);
41798 pointBox = iD.ui.intro.pad(corner, padding, context);
41799 reveal(pointBox, t('intro.areas.corner'), {duration: 0});
41803 function drawArea(mode) {
41804 if (mode.id !== 'draw-area') return;
41805 context.on('enter.intro', enterSelect);
41807 var padding = 150 * Math.pow(2, context.map().zoom() - 19);
41808 var pointBox = iD.ui.intro.pad(playground, padding, context);
41809 reveal(pointBox, t('intro.areas.place'));
41811 context.map().on('move.intro', function() {
41812 padding = 150 * Math.pow(2, context.map().zoom() - 19);
41813 pointBox = iD.ui.intro.pad(playground, padding, context);
41814 reveal(pointBox, t('intro.areas.place'), {duration: 0});
41818 function enterSelect(mode) {
41819 if (mode.id !== 'select') return;
41820 context.map().on('move.intro', null);
41821 context.on('enter.intro', null);
41823 timeout = setTimeout(function() {
41824 reveal('.preset-search-input',
41825 t('intro.areas.search',
41826 { name: context.presets().item('leisure/playground').name() }));
41827 d3.select('.preset-search-input').on('keyup.intro', keySearch);
41831 function keySearch() {
41832 var first = d3.select('.preset-list-item:first-child');
41833 if (first.classed('preset-leisure-playground')) {
41834 reveal(first.select('.preset-list-button').node(), t('intro.areas.choose'));
41835 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
41836 d3.select('.preset-search-input').on('keyup.intro', null);
41840 function selectedPreset() {
41842 t('intro.areas.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
41843 context.on('exit.intro', event.done);
41847 step.exit = function() {
41848 window.clearTimeout(timeout);
41849 context.on('enter.intro', null);
41850 context.on('exit.intro', null);
41851 context.history().on('change.intro', null);
41852 context.map().on('move.intro', null);
41853 d3.select('.preset-search-input').on('keyup.intro', null);
41856 return d3.rebind(step, event, 'on');
41858 iD.ui.intro.line = function(context, reveal) {
41859 var event = d3.dispatch('done'),
41863 title: 'intro.lines.title'
41866 function timeout(f, t) {
41867 timeouts.push(window.setTimeout(f, t));
41870 function eventCancel() {
41871 d3.event.stopPropagation();
41872 d3.event.preventDefault();
41875 step.enter = function() {
41876 var centroid = [-85.62830, 41.95699];
41877 var midpoint = [-85.62975395449628, 41.95787501510204];
41878 var start = [-85.6297754121684, 41.95805253325314];
41879 var intersection = [-85.62974496187628, 41.95742515554585];
41881 context.map().centerZoom(start, 18);
41882 reveal('button.add-line',
41883 t('intro.lines.add', { button: iD.ui.intro.icon('#icon-line', 'pre-text') }),
41884 { tooltipClass: 'intro-lines-add' });
41886 context.on('enter.intro', addLine);
41888 function addLine(mode) {
41889 if (mode.id !== 'add-line') return;
41890 context.on('enter.intro', drawLine);
41892 var padding = 150 * Math.pow(2, context.map().zoom() - 18);
41893 var pointBox = iD.ui.intro.pad(start, padding, context);
41894 reveal(pointBox, t('intro.lines.start'));
41896 context.map().on('move.intro', function() {
41897 padding = 150 * Math.pow(2, context.map().zoom() - 18);
41898 pointBox = iD.ui.intro.pad(start, padding, context);
41899 reveal(pointBox, t('intro.lines.start'), {duration: 0});
41903 function drawLine(mode) {
41904 if (mode.id !== 'draw-line') return;
41905 context.history().on('change.intro', addIntersection);
41906 context.on('enter.intro', retry);
41908 var padding = 300 * Math.pow(2, context.map().zoom() - 19);
41909 var pointBox = iD.ui.intro.pad(midpoint, padding, context);
41910 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}));
41912 context.map().on('move.intro', function() {
41913 padding = 300 * Math.pow(2, context.map().zoom() - 19);
41914 pointBox = iD.ui.intro.pad(midpoint, padding, context);
41915 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}), {duration: 0});
41919 // ended line before creating intersection
41920 function retry(mode) {
41921 if (mode.id !== 'select') return;
41922 var pointBox = iD.ui.intro.pad(intersection, 30, context),
41923 ids = mode.selectedIDs();
41924 reveal(pointBox, t('intro.lines.restart', {name: t('intro.graph.flower_st')}));
41925 d3.select(window).on('mousedown.intro', eventCancel, true);
41927 timeout(function() {
41928 context.replace(iD.actions.DeleteMultiple(ids));
41934 function addIntersection(changes) {
41935 if ( _.some(changes.created(), function(d) {
41936 return d.type === 'node' && context.graph().parentWays(d).length > 1;
41938 context.history().on('change.intro', null);
41939 context.on('enter.intro', enterSelect);
41941 var padding = 900 * Math.pow(2, context.map().zoom() - 19);
41942 var pointBox = iD.ui.intro.pad(centroid, padding, context);
41943 reveal(pointBox, t('intro.lines.finish'));
41945 context.map().on('move.intro', function() {
41946 padding = 900 * Math.pow(2, context.map().zoom() - 19);
41947 pointBox = iD.ui.intro.pad(centroid, padding, context);
41948 reveal(pointBox, t('intro.lines.finish'), {duration: 0});
41953 function enterSelect(mode) {
41954 if (mode.id !== 'select') return;
41955 context.map().on('move.intro', null);
41956 context.on('enter.intro', null);
41957 d3.select('#curtain').style('pointer-events', 'all');
41962 function presetCategory() {
41963 timeout(function() {
41964 d3.select('#curtain').style('pointer-events', 'none');
41965 var road = d3.select('.preset-category-road .preset-list-button');
41966 reveal(road.node(), t('intro.lines.road'));
41967 road.one('click.intro', roadCategory);
41971 function roadCategory() {
41972 timeout(function() {
41973 var grid = d3.select('.subgrid');
41974 reveal(grid.node(), t('intro.lines.residential'));
41975 grid.selectAll(':not(.preset-highway-residential) .preset-list-button')
41976 .one('click.intro', retryPreset);
41977 grid.selectAll('.preset-highway-residential .preset-list-button')
41978 .one('click.intro', roadDetails);
41982 // selected wrong road type
41983 function retryPreset() {
41984 timeout(function() {
41985 var preset = d3.select('.entity-editor-pane .preset-list-button');
41986 reveal(preset.node(), t('intro.lines.wrong_preset'));
41987 preset.one('click.intro', presetCategory);
41991 function roadDetails() {
41993 t('intro.lines.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
41994 context.on('exit.intro', event.done);
41999 step.exit = function() {
42000 d3.select(window).on('mousedown.intro', null, true);
42001 d3.select('#curtain').style('pointer-events', 'none');
42002 timeouts.forEach(window.clearTimeout);
42003 context.on('enter.intro', null);
42004 context.on('exit.intro', null);
42005 context.map().on('move.intro', null);
42006 context.history().on('change.intro', null);
42009 return d3.rebind(step, event, 'on');
42011 iD.ui.intro.navigation = function(context, reveal) {
42012 var event = d3.dispatch('done'),
42016 title: 'intro.navigation.title'
42019 function set(f, t) {
42020 timeouts.push(window.setTimeout(f, t));
42023 function eventCancel() {
42024 d3.event.stopPropagation();
42025 d3.event.preventDefault();
42028 step.enter = function() {
42029 var rect = context.surfaceRect(),
42031 left: rect.left + 10,
42032 top: rect.top + 70,
42033 width: rect.width - 70,
42034 height: rect.height - 170
42037 context.map().centerZoom([-85.63591, 41.94285], 19);
42039 reveal(map, t('intro.navigation.drag'));
42041 context.map().on('move.intro', _.debounce(function() {
42042 context.map().on('move.intro', null);
42044 context.on('enter.intro', inspectTownHall);
42047 function townhall() {
42048 var hall = [-85.63645945147184, 41.942986488012565];
42050 var point = context.projection(hall);
42051 if (point[0] < 0 || point[0] > rect.width ||
42052 point[1] < 0 || point[1] > rect.height) {
42053 context.map().center(hall);
42056 var box = iD.ui.intro.pointBox(hall, context);
42057 reveal(box, t('intro.navigation.select'));
42059 context.map().on('move.intro', function() {
42060 var box = iD.ui.intro.pointBox(hall, context);
42061 reveal(box, t('intro.navigation.select'), {duration: 0});
42065 function inspectTownHall(mode) {
42066 if (mode.id !== 'select') return;
42067 context.on('enter.intro', null);
42068 context.map().on('move.intro', null);
42070 reveal('.entity-editor-pane',
42071 t('intro.navigation.pane', { button: iD.ui.intro.icon('#icon-close', 'pre-text') }));
42072 context.on('exit.intro', streetSearch);
42076 function streetSearch() {
42077 context.on('exit.intro', null);
42078 reveal('.search-header input',
42079 t('intro.navigation.search', { name: t('intro.graph.spring_st') }));
42080 d3.select('.search-header input').on('keyup.intro', searchResult);
42083 function searchResult() {
42084 var first = d3.select('.feature-list-item:nth-child(0n+2)'), // skip No Results item
42085 firstName = first.select('.entity-name'),
42086 name = t('intro.graph.spring_st');
42088 if (!firstName.empty() && firstName.text() === name) {
42089 reveal(first.node(), t('intro.navigation.choose', { name: name }));
42090 context.on('exit.intro', selectedStreet);
42091 d3.select('.search-header input')
42092 .on('keydown.intro', eventCancel, true)
42093 .on('keyup.intro', null);
42097 function selectedStreet() {
42098 var springSt = [-85.63585099140167, 41.942506848938926];
42099 context.map().center(springSt);
42100 context.on('exit.intro', event.done);
42102 reveal('.entity-editor-pane',
42103 t('intro.navigation.chosen', {
42104 name: t('intro.graph.spring_st'),
42105 button: iD.ui.intro.icon('#icon-close', 'pre-text')
42111 step.exit = function() {
42112 timeouts.forEach(window.clearTimeout);
42113 context.map().on('move.intro', null);
42114 context.on('enter.intro', null);
42115 context.on('exit.intro', null);
42116 d3.select('.search-header input')
42117 .on('keydown.intro', null)
42118 .on('keyup.intro', null);
42121 return d3.rebind(step, event, 'on');
42123 iD.ui.intro.point = function(context, reveal) {
42124 var event = d3.dispatch('done'),
42128 title: 'intro.points.title'
42131 function setTimeout(f, t) {
42132 timeouts.push(window.setTimeout(f, t));
42135 function eventCancel() {
42136 d3.event.stopPropagation();
42137 d3.event.preventDefault();
42140 step.enter = function() {
42141 context.map().centerZoom([-85.63279, 41.94394], 19);
42142 reveal('button.add-point',
42143 t('intro.points.add', { button: iD.ui.intro.icon('#icon-point', 'pre-text') }),
42144 { tooltipClass: 'intro-points-add' });
42146 var corner = [-85.632481,41.944094];
42148 context.on('enter.intro', addPoint);
42150 function addPoint(mode) {
42151 if (mode.id !== 'add-point') return;
42152 context.on('enter.intro', enterSelect);
42154 var pointBox = iD.ui.intro.pad(corner, 150, context);
42155 reveal(pointBox, t('intro.points.place'));
42157 context.map().on('move.intro', function() {
42158 pointBox = iD.ui.intro.pad(corner, 150, context);
42159 reveal(pointBox, t('intro.points.place'), {duration: 0});
42163 function enterSelect(mode) {
42164 if (mode.id !== 'select') return;
42165 context.map().on('move.intro', null);
42166 context.on('enter.intro', null);
42168 setTimeout(function() {
42169 reveal('.preset-search-input',
42170 t('intro.points.search', {name: context.presets().item('amenity/cafe').name()}));
42171 d3.select('.preset-search-input').on('keyup.intro', keySearch);
42175 function keySearch() {
42176 var first = d3.select('.preset-list-item:first-child');
42177 if (first.classed('preset-amenity-cafe')) {
42178 reveal(first.select('.preset-list-button').node(), t('intro.points.choose'));
42179 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
42180 d3.select('.preset-search-input')
42181 .on('keydown.intro', eventCancel, true)
42182 .on('keyup.intro', null);
42186 function selectedPreset() {
42187 setTimeout(function() {
42188 reveal('.entity-editor-pane', t('intro.points.describe'), {tooltipClass: 'intro-points-describe'});
42189 context.history().on('change.intro', closeEditor);
42190 context.on('exit.intro', selectPoint);
42194 function closeEditor() {
42195 d3.select('.preset-search-input').on('keydown.intro', null);
42196 context.history().on('change.intro', null);
42197 reveal('.entity-editor-pane',
42198 t('intro.points.close', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
42201 function selectPoint() {
42202 context.on('exit.intro', null);
42203 context.history().on('change.intro', null);
42204 context.on('enter.intro', enterReselect);
42206 var pointBox = iD.ui.intro.pad(corner, 150, context);
42207 reveal(pointBox, t('intro.points.reselect'));
42209 context.map().on('move.intro', function() {
42210 pointBox = iD.ui.intro.pad(corner, 150, context);
42211 reveal(pointBox, t('intro.points.reselect'), {duration: 0});
42215 function enterReselect(mode) {
42216 if (mode.id !== 'select') return;
42217 context.map().on('move.intro', null);
42218 context.on('enter.intro', null);
42220 setTimeout(function() {
42221 reveal('.entity-editor-pane',
42222 t('intro.points.fixname', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
42223 context.on('exit.intro', deletePoint);
42227 function deletePoint() {
42228 context.on('exit.intro', null);
42229 context.on('enter.intro', enterDelete);
42231 var pointBox = iD.ui.intro.pad(corner, 150, context);
42232 reveal(pointBox, t('intro.points.reselect_delete'));
42234 context.map().on('move.intro', function() {
42235 pointBox = iD.ui.intro.pad(corner, 150, context);
42236 reveal(pointBox, t('intro.points.reselect_delete'), {duration: 0});
42240 function enterDelete(mode) {
42241 if (mode.id !== 'select') return;
42242 context.map().on('move.intro', null);
42243 context.on('enter.intro', null);
42244 context.on('exit.intro', deletePoint);
42245 context.map().on('move.intro', deletePoint);
42246 context.history().on('change.intro', deleted);
42248 setTimeout(function() {
42249 var node = d3.select('.radial-menu-item-delete').node();
42250 var pointBox = iD.ui.intro.pad(node.getBoundingClientRect(), 50, context);
42252 t('intro.points.delete', { button: iD.ui.intro.icon('#operation-delete', 'pre-text') }));
42256 function deleted(changed) {
42257 if (changed.deleted().length) event.done();
42262 step.exit = function() {
42263 timeouts.forEach(window.clearTimeout);
42264 context.on('exit.intro', null);
42265 context.on('enter.intro', null);
42266 context.map().on('move.intro', null);
42267 context.history().on('change.intro', null);
42268 d3.select('.preset-search-input')
42269 .on('keyup.intro', null)
42270 .on('keydown.intro', null);
42273 return d3.rebind(step, event, 'on');
42275 iD.ui.intro.startEditing = function(context, reveal) {
42276 var event = d3.dispatch('done', 'startEditing'),
42281 title: 'intro.startediting.title'
42284 function timeout(f, t) {
42285 timeouts.push(window.setTimeout(f, t));
42288 step.enter = function() {
42289 reveal('.map-control.help-control',
42290 t('intro.startediting.help', { button: iD.ui.intro.icon('#icon-help', 'pre-text') }));
42292 timeout(function() {
42293 reveal('#bar button.save', t('intro.startediting.save'));
42296 timeout(function() {
42297 reveal('#surface');
42300 timeout(function() {
42301 modal = iD.ui.modal(context.container());
42303 modal.select('.modal')
42304 .attr('class', 'modal-splash modal col6');
42306 modal.selectAll('.close').remove();
42308 var startbutton = modal.select('.content')
42309 .attr('class', 'fillL')
42311 .attr('class', 'modal-section huge-modal-button')
42312 .on('click', function() {
42316 startbutton.append('div')
42317 .attr('class','illustration');
42318 startbutton.append('h2')
42319 .text(t('intro.startediting.start'));
42321 event.startEditing();
42325 step.exit = function() {
42326 if (modal) modal.remove();
42327 timeouts.forEach(window.clearTimeout);
42330 return d3.rebind(step, event, 'on');
42332 iD.presets = function() {
42334 // an iD.presets.Collection with methods for
42335 // loading new data and returning defaults
42337 var all = iD.presets.Collection([]),
42338 defaults = { area: all, line: all, point: all, vertex: all, relation: all },
42341 recent = iD.presets.Collection([]);
42343 // Index of presets by (geometry, tag key).
42352 all.match = function(entity, resolver) {
42353 var geometry = entity.geometry(resolver);
42355 // Treat entities on addr:interpolation lines as points, not vertices (#3241)
42356 if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
42357 geometry = 'point';
42360 var geometryMatches = index[geometry],
42364 for (var k in entity.tags) {
42365 var keyMatches = geometryMatches[k];
42366 if (!keyMatches) continue;
42368 for (var i = 0; i < keyMatches.length; i++) {
42369 var score = keyMatches[i].matchScore(entity);
42370 if (score > best) {
42372 match = keyMatches[i];
42377 return match || all.item(geometry);
42380 // Because of the open nature of tagging, iD will never have a complete
42381 // list of tags used in OSM, so we want it to have logic like "assume
42382 // that a closed way with an amenity tag is an area, unless the amenity
42383 // is one of these specific types". This function computes a structure
42384 // that allows testing of such conditions, based on the presets designated
42385 // as as supporting (or not supporting) the area geometry.
42387 // The returned object L is a whitelist/blacklist of tags. A closed way
42388 // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
42389 // (see `iD.Way#isArea()`). In other words, the keys of L form the whitelist,
42390 // and the subkeys form the blacklist.
42391 all.areaKeys = function() {
42393 ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],
42394 presets = _.reject(all.collection, 'suggestion');
42397 presets.forEach(function(d) {
42398 for (var key in d.tags) break;
42400 if (ignore.indexOf(key) !== -1) return;
42402 if (d.geometry.indexOf('area') !== -1) {
42403 areaKeys[key] = areaKeys[key] || {};
42408 presets.forEach(function(d) {
42409 for (var key in d.tags) break;
42411 if (ignore.indexOf(key) !== -1) return;
42413 var value = d.tags[key];
42414 if (d.geometry.indexOf('area') === -1 &&
42415 d.geometry.indexOf('line') !== -1 &&
42416 key in areaKeys && value !== '*') {
42417 areaKeys[key][value] = true;
42424 all.load = function(d) {
42427 _.forEach(d.fields, function(d, id) {
42428 fields[id] = iD.presets.Field(id, d);
42429 if (d.universal) universal.push(fields[id]);
42434 _.forEach(d.presets, function(d, id) {
42435 all.collection.push(iD.presets.Preset(id, d, fields));
42439 if (d.categories) {
42440 _.forEach(d.categories, function(d, id) {
42441 all.collection.push(iD.presets.Category(id, d, all));
42446 var getItem = _.bind(all.item, all);
42448 area: iD.presets.Collection(d.defaults.area.map(getItem)),
42449 line: iD.presets.Collection(d.defaults.line.map(getItem)),
42450 point: iD.presets.Collection(d.defaults.point.map(getItem)),
42451 vertex: iD.presets.Collection(d.defaults.vertex.map(getItem)),
42452 relation: iD.presets.Collection(d.defaults.relation.map(getItem))
42456 for (var i = 0; i < all.collection.length; i++) {
42457 var preset = all.collection[i],
42458 geometry = preset.geometry;
42460 for (var j = 0; j < geometry.length; j++) {
42461 var g = index[geometry[j]];
42462 for (var k in preset.tags) {
42463 (g[k] = g[k] || []).push(preset);
42471 all.field = function(id) {
42475 all.universal = function() {
42479 all.defaults = function(geometry, n) {
42480 var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
42481 def = _.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
42482 return iD.presets.Collection(_.uniq(rec.concat(def).concat(all.item(geometry))));
42485 all.choose = function(preset) {
42486 if (!preset.isFallback()) {
42487 recent = iD.presets.Collection(_.uniq([preset].concat(recent.collection)));
42494 iD.presets.Category = function(id, category, all) {
42495 category = _.clone(category);
42499 category.members = iD.presets.Collection(category.members.map(function(id) {
42500 return all.item(id);
42503 category.matchGeometry = function(geometry) {
42504 return category.geometry.indexOf(geometry) >= 0;
42507 category.matchScore = function() { return -1; };
42509 category.name = function() {
42510 return t('presets.categories.' + id + '.name', {'default': id});
42513 category.terms = function() {
42519 iD.presets.Collection = function(collection) {
42521 var maxSearchResults = 50,
42522 maxSuggestionResults = 10;
42526 collection: collection,
42528 item: function(id) {
42529 return _.find(collection, function(d) {
42530 return d.id === id;
42534 matchGeometry: function(geometry) {
42535 return iD.presets.Collection(collection.filter(function(d) {
42536 return d.matchGeometry(geometry);
42540 search: function(value, geometry) {
42541 if (!value) return this;
42543 value = value.toLowerCase();
42545 var searchable = _.filter(collection, function(a) {
42546 return a.searchable !== false && a.suggestion !== true;
42548 suggestions = _.filter(collection, function(a) {
42549 return a.suggestion === true;
42552 function leading(a) {
42553 var index = a.indexOf(value);
42554 return index === 0 || a[index - 1] === ' ';
42557 // matches value to preset.name
42558 var leading_name = _.filter(searchable, function(a) {
42559 return leading(a.name().toLowerCase());
42560 }).sort(function(a, b) {
42561 var i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
42562 if (i === 0) return a.name().length - b.name().length;
42566 // matches value to preset.terms values
42567 var leading_terms = _.filter(searchable, function(a) {
42568 return _.some(a.terms() || [], leading);
42571 // matches value to preset.tags values
42572 var leading_tag_values = _.filter(searchable, function(a) {
42573 return _.some(_.without(_.values(a.tags || {}), '*'), leading);
42577 // finds close matches to value in preset.name
42578 var levenstein_name = searchable.map(function(a) {
42581 dist: iD.util.editDistance(value, a.name().toLowerCase())
42583 }).filter(function(a) {
42584 return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
42585 }).sort(function(a, b) {
42586 return a.dist - b.dist;
42587 }).map(function(a) {
42591 // finds close matches to value in preset.terms
42592 var leventstein_terms = _.filter(searchable, function(a) {
42593 return _.some(a.terms() || [], function(b) {
42594 return iD.util.editDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
42598 function suggestionName(name) {
42599 var nameArray = name.split(' - ');
42600 if (nameArray.length > 1) {
42601 name = nameArray.slice(0, nameArray.length-1).join(' - ');
42603 return name.toLowerCase();
42606 var leading_suggestions = _.filter(suggestions, function(a) {
42607 return leading(suggestionName(a.name()));
42608 }).sort(function(a, b) {
42609 a = suggestionName(a.name());
42610 b = suggestionName(b.name());
42611 var i = a.indexOf(value) - b.indexOf(value);
42612 if (i === 0) return a.length - b.length;
42616 var leven_suggestions = suggestions.map(function(a) {
42619 dist: iD.util.editDistance(value, suggestionName(a.name()))
42621 }).filter(function(a) {
42622 return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
42623 }).sort(function(a, b) {
42624 return a.dist - b.dist;
42625 }).map(function(a) {
42629 var other = presets.item(geometry);
42631 var results = leading_name.concat(
42633 leading_tag_values,
42634 leading_suggestions.slice(0, maxSuggestionResults+5),
42637 leven_suggestions.slice(0, maxSuggestionResults)
42638 ).slice(0, maxSearchResults-1);
42640 return iD.presets.Collection(_.uniq(
42641 results.concat(other)
42648 iD.presets.Field = function(id, field) {
42649 field = _.clone(field);
42653 field.matchGeometry = function(geometry) {
42654 return !field.geometry || field.geometry === geometry;
42657 field.t = function(scope, options) {
42658 return t('presets.fields.' + id + '.' + scope, options);
42661 field.label = function() {
42662 return field.t('label', {'default': id});
42665 var placeholder = field.placeholder;
42666 field.placeholder = function() {
42667 return field.t('placeholder', {'default': placeholder});
42672 iD.presets.Preset = function(id, preset, fields) {
42673 preset = _.clone(preset);
42676 preset.fields = (preset.fields || []).map(getFields);
42677 preset.geometry = (preset.geometry || []);
42679 function getFields(f) {
42683 preset.matchGeometry = function(geometry) {
42684 return preset.geometry.indexOf(geometry) >= 0;
42687 var matchScore = preset.matchScore || 1;
42688 preset.matchScore = function(entity) {
42689 var tags = preset.tags,
42692 for (var t in tags) {
42693 if (entity.tags[t] === tags[t]) {
42694 score += matchScore;
42695 } else if (tags[t] === '*' && t in entity.tags) {
42696 score += matchScore / 2;
42705 preset.t = function(scope, options) {
42706 return t('presets.presets.' + id + '.' + scope, options);
42709 var name = preset.name;
42710 preset.name = function() {
42711 if (preset.suggestion) {
42712 id = id.split('/');
42713 id = id[0] + '/' + id[1];
42714 return name + ' - ' + t('presets.presets.' + id + '.name');
42716 return preset.t('name', {'default': name});
42719 preset.terms = function() {
42720 return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
42723 preset.isFallback = function() {
42724 var tagCount = Object.keys(preset.tags).length;
42725 return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
42728 preset.reference = function(geometry) {
42729 var key = Object.keys(preset.tags)[0],
42730 value = preset.tags[key];
42732 if (geometry === 'relation' && key === 'type') {
42733 return { rtype: value };
42734 } else if (value === '*') {
42735 return { key: key };
42737 return { key: key, value: value };
42741 var removeTags = preset.removeTags || preset.tags;
42742 preset.removeTags = function(tags, geometry) {
42743 tags = _.omit(tags, _.keys(removeTags));
42745 for (var f in preset.fields) {
42746 var field = preset.fields[f];
42747 if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
42748 delete tags[field.key];
42756 var applyTags = preset.addTags || preset.tags;
42757 preset.applyTags = function(tags, geometry) {
42760 tags = _.clone(tags);
42762 for (k in applyTags) {
42763 if (applyTags[k] === '*') {
42766 tags[k] = applyTags[k];
42770 // Add area=yes if necessary.
42771 // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
42772 // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
42773 // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
42774 if (geometry === 'area') {
42775 var needsAreaTag = true;
42776 if (preset.geometry.indexOf('line') === -1) {
42777 for (k in applyTags) {
42778 if (k in iD.areaKeys) {
42779 needsAreaTag = false;
42784 if (needsAreaTag) {
42789 for (var f in preset.fields) {
42790 var field = preset.fields[f];
42791 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
42792 tags[field.key] = field.default;
42801 iD.validations = {};
42802 iD.validations.DeprecatedTag = function() {
42804 var validation = function(changes) {
42806 for (var i = 0; i < changes.created.length; i++) {
42807 var change = changes.created[i],
42808 deprecatedTags = change.deprecatedTags();
42810 if (!_.isEmpty(deprecatedTags)) {
42811 var tags = iD.util.tagText({ tags: deprecatedTags });
42813 id: 'deprecated_tags',
42814 message: t('validations.deprecated_tags', { tags: tags }),
42824 iD.validations.ManyDeletions = function() {
42825 var threshold = 100;
42827 var validation = function(changes) {
42829 if (changes.deleted.length > threshold) {
42831 id: 'many_deletions',
42832 message: t('validations.many_deletions', { n: changes.deleted.length })
42840 iD.validations.MissingTag = function() {
42842 // Slightly stricter check than Entity#isUsed (#3091)
42843 function hasTags(entity, graph) {
42844 return _.without(Object.keys(entity.tags), 'area', 'name').length > 0 ||
42845 graph.parentRelations(entity).length > 0;
42848 var validation = function(changes, graph) {
42850 for (var i = 0; i < changes.created.length; i++) {
42851 var change = changes.created[i],
42852 geometry = change.geometry(graph);
42854 if ((geometry === 'point' || geometry === 'line' || geometry === 'area') && !hasTags(change, graph)) {
42857 message: t('validations.untagged_' + geometry),
42858 tooltip: t('validations.untagged_' + geometry + '_tooltip'),
42868 iD.validations.TagSuggestsArea = function() {
42870 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
42871 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
42872 function tagSuggestsArea(tags) {
42873 if (_.isEmpty(tags)) return false;
42875 var presence = ['landuse', 'amenities', 'tourism', 'shop'];
42876 for (var i = 0; i < presence.length; i++) {
42877 if (tags[presence[i]] !== undefined) {
42878 return presence[i] + '=' + tags[presence[i]];
42882 if (tags.building && tags.building === 'yes') return 'building=yes';
42885 var validation = function(changes, graph) {
42887 for (var i = 0; i < changes.created.length; i++) {
42888 var change = changes.created[i],
42889 geometry = change.geometry(graph),
42890 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
42894 id: 'tag_suggests_area',
42895 message: t('validations.tag_suggests_area', { tag: suggestion }),
42906 window.locale = { _current: 'en' };
42908 locale.current = function(_) {
42909 if (!arguments.length) return locale._current;
42910 if (locale[_] !== undefined) locale._current = _;
42911 else if (locale[_.split('-')[0]]) locale._current = _.split('-')[0];
42915 function t(s, o, loc) {
42916 loc = loc || locale._current;
42918 var path = s.split(".").reverse(),
42921 while (rep !== undefined && path.length) rep = rep[path.pop()];
42923 if (rep !== undefined) {
42924 if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
42928 if (loc !== 'en') {
42929 return t(s, o, 'en');
42932 if (o && 'default' in o) {
42933 return o['default'];
42936 var missing = 'Missing ' + loc + ' translation: ' + s;
42937 if (typeof console !== "undefined") console.error(missing);
42941 iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081]},"n185964961":{"id":"n185964961","loc":[-85.6406588,41.942601]},"n185964962":{"id":"n185964962","loc":[-85.6394548,41.94261]},"n185970607":{"id":"n185970607","loc":[-85.641094,41.94006]},"n185970614":{"id":"n185970614","loc":[-85.641825,41.941316]},"n185970616":{"id":"n185970616","loc":[-85.641838,41.941556]},"n185973650":{"id":"n185973650","loc":[-85.639918,41.940064]},"n185973660":{"id":"n185973660","loc":[-85.640645,41.941339]},"n185973659":{"id":"n185973659","loc":[-85.6406115,41.9400658]},"n185974479":{"id":"n185974479","loc":[-85.639402,41.941344]},"n185974481":{"id":"n185974481","loc":[-85.643071,41.941288]},"n185976259":{"id":"n185976259","loc":[-85.642213,41.940043]},"n185976261":{"id":"n185976261","loc":[-85.643056,41.94001]},"n185964959":{"id":"n185964959","loc":[-85.6431031,41.9425754]},"n185964960":{"id":"n185964960","loc":[-85.6418749,41.9425864]},"n185981481":{"id":"n185981481","loc":[-85.6386827,41.9400828]},"n185981482":{"id":"n185981482","loc":[-85.6393664,41.9400854]},"n2138493844":{"id":"n2138493844","loc":[-85.6427969,41.940522]},"n2138493845":{"id":"n2138493845","loc":[-85.6425891,41.9405228]},"n2138493846":{"id":"n2138493846","loc":[-85.6425868,41.9402875]},"n2138493847":{"id":"n2138493847","loc":[-85.6427969,41.9402858]},"n2138493848":{"id":"n2138493848","loc":[-85.6425708,41.9405234]},"n2138493849":{"id":"n2138493849","loc":[-85.642568,41.9402855]},"n2138493850":{"id":"n2138493850","loc":[-85.6423157,41.9402886]},"n2138493851":{"id":"n2138493851","loc":[-85.6423212,41.9404362]},"n2138493852":{"id":"n2138493852","loc":[-85.6422923,41.9404578]},"n2138493853":{"id":"n2138493853","loc":[-85.6422868,41.9404834]},"n2138493854":{"id":"n2138493854","loc":[-85.6423226,41.9405091]},"n2138493855":{"id":"n2138493855","loc":[-85.6423847,41.9405111]},"n2138493856":{"id":"n2138493856","loc":[-85.6424081,41.9405265]},"n2140155811":{"id":"n2140155811","loc":[-85.6419547,41.9410956]},"n2140155814":{"id":"n2140155814","loc":[-85.6427577,41.9410884]},"n2140155816":{"id":"n2140155816","loc":[-85.6427545,41.9410052]},"n2140155818":{"id":"n2140155818","loc":[-85.6428057,41.9410028]},"n2140155821":{"id":"n2140155821","loc":[-85.6427993,41.9407339]},"n2140155823":{"id":"n2140155823","loc":[-85.6427385,41.9407339]},"n2140155825":{"id":"n2140155825","loc":[-85.6427417,41.9406435]},"n2140155827":{"id":"n2140155827","loc":[-85.6419515,41.9406482]},"n2140155828":{"id":"n2140155828","loc":[-85.6429368,41.9412407]},"n2140155829":{"id":"n2140155829","loc":[-85.6417756,41.9412526]},"n2140155830":{"id":"n2140155830","loc":[-85.641766,41.9405983]},"n2140155831":{"id":"n2140155831","loc":[-85.6419803,41.9405983]},"n2140155832":{"id":"n2140155832","loc":[-85.6419611,41.9401366]},"n2140155833":{"id":"n2140155833","loc":[-85.6429336,41.94012]},"n2140155834":{"id":"n2140155834","loc":[-85.6430697,41.9411732]},"n2140155835":{"id":"n2140155835","loc":[-85.6428411,41.9409974]},"n2140155837":{"id":"n2140155837","loc":[-85.6428388,41.9407211]},"n2140155839":{"id":"n2140155839","loc":[-85.6430624,41.9405521]},"n2140155840":{"id":"n2140155840","loc":[-85.6427323,41.9412396]},"n2140155842":{"id":"n2140155842","loc":[-85.6418147,41.9412457]},"n2140155844":{"id":"n2140155844","loc":[-85.641813,41.9411319]},"n2140155845":{"id":"n2140155845","loc":[-85.6418394,41.9411111]},"n2140155847":{"id":"n2140155847","loc":[-85.6418838,41.9410977]},"n2140155849":{"id":"n2140155849","loc":[-85.6427324,41.9410921]},"n2140155851":{"id":"n2140155851","loc":[-85.6427798,41.9412945]},"n2140155852":{"id":"n2140155852","loc":[-85.6427701,41.9411777]},"n2140155854":{"id":"n2140155854","loc":[-85.6427323,41.9411572]},"n2140155856":{"id":"n2140155856","loc":[-85.6418478,41.9411666]},"n2165942818":{"id":"n2165942818","loc":[-85.6437533,41.9415029]},"n2165942819":{"id":"n2165942819","loc":[-85.6437623,41.9421195]},"n2168510551":{"id":"n2168510551","loc":[-85.6423795,41.9422615]},"n2168510552":{"id":"n2168510552","loc":[-85.6423744,41.9419439]},"n2168510553":{"id":"n2168510553","loc":[-85.642518,41.9419427]},"n2168510554":{"id":"n2168510554","loc":[-85.6425186,41.9419801]},"n2168510555":{"id":"n2168510555","loc":[-85.6428314,41.9419773]},"n2168510556":{"id":"n2168510556","loc":[-85.6428368,41.9423116]},"n2168510557":{"id":"n2168510557","loc":[-85.6424947,41.9423146]},"n2168510558":{"id":"n2168510558","loc":[-85.6424938,41.9422605]},"n2189046007":{"id":"n2189046007","loc":[-85.6410866,41.9424327]},"n2189046009":{"id":"n2189046009","loc":[-85.6410805,41.9420061]},"n2189046011":{"id":"n2189046011","loc":[-85.6412443,41.9420048]},"n2189046012":{"id":"n2189046012","loc":[-85.6412505,41.9424314]},"n2189046014":{"id":"n2189046014","loc":[-85.6413311,41.942968]},"n2189046016":{"id":"n2189046016","loc":[-85.6413281,41.942713]},"n2189046018":{"id":"n2189046018","loc":[-85.641521,41.9427117]},"n2189046021":{"id":"n2189046021","loc":[-85.6415234,41.9429236]},"n2189046022":{"id":"n2189046022","loc":[-85.6415045,41.9429238]},"n2189046025":{"id":"n2189046025","loc":[-85.641505,41.9429668]},"n2189046053":{"id":"n2189046053","loc":[-85.6385988,41.942412]},"n2189046054":{"id":"n2189046054","loc":[-85.6385985,41.9423311]},"n2189046055":{"id":"n2189046055","loc":[-85.6387617,41.9423308]},"n2189046056":{"id":"n2189046056","loc":[-85.6387616,41.9423026]},"n2189046058":{"id":"n2189046058","loc":[-85.6388215,41.9423025]},"n2189046059":{"id":"n2189046059","loc":[-85.6388219,41.9424115]},"n2189046060":{"id":"n2189046060","loc":[-85.6391096,41.9424486]},"n2189046061":{"id":"n2189046061","loc":[-85.6391105,41.9423673]},"n2189046063":{"id":"n2189046063","loc":[-85.6392911,41.9423684]},"n2189046065":{"id":"n2189046065","loc":[-85.6392903,41.9424497]},"n2189046067":{"id":"n2189046067","loc":[-85.6397927,41.9423876]},"n2189046069":{"id":"n2189046069","loc":[-85.6397897,41.9422981]},"n2189046070":{"id":"n2189046070","loc":[-85.6399702,41.9422947]},"n2189046072":{"id":"n2189046072","loc":[-85.6399732,41.9423843]},"n2189046074":{"id":"n2189046074","loc":[-85.6396331,41.9430227]},"n2189046075":{"id":"n2189046075","loc":[-85.6398673,41.9430189]},"n2189046077":{"id":"n2189046077","loc":[-85.6398656,41.9429637]},"n2189046079":{"id":"n2189046079","loc":[-85.6398885,41.9429633]},"n2189046082":{"id":"n2189046082","loc":[-85.6398832,41.942779]},"n2189046083":{"id":"n2189046083","loc":[-85.6398513,41.9427796]},"n2189046085":{"id":"n2189046085","loc":[-85.6398502,41.9427401]},"n2189046087":{"id":"n2189046087","loc":[-85.6397889,41.9427411]},"n2189046089":{"id":"n2189046089","loc":[-85.6397892,41.942753]},"n2189046090":{"id":"n2189046090","loc":[-85.6396983,41.9427544]},"n2189046092":{"id":"n2189046092","loc":[-85.6396993,41.9427882]},"n2189046094":{"id":"n2189046094","loc":[-85.6396746,41.9427886]},"n2189046096":{"id":"n2189046096","loc":[-85.6396758,41.9428296]},"n2189046097":{"id":"n2189046097","loc":[-85.6397007,41.9428292]},"n2189046099":{"id":"n2189046099","loc":[-85.6397018,41.9428686]},"n2189046103":{"id":"n2189046103","loc":[-85.6396289,41.9428697]},"n2189046112":{"id":"n2189046112","loc":[-85.6435683,41.9429457]},"n2189046113":{"id":"n2189046113","loc":[-85.643568,41.9427766]},"n2189046115":{"id":"n2189046115","loc":[-85.6434011,41.9427767]},"n2189046116":{"id":"n2189046116","loc":[-85.6434012,41.9428631]},"n2189046117":{"id":"n2189046117","loc":[-85.643448,41.9428631]},"n2189046118":{"id":"n2189046118","loc":[-85.6434481,41.9429457]},"n2189046119":{"id":"n2189046119","loc":[-85.6428363,41.9429809]},"n2189046120":{"id":"n2189046120","loc":[-85.6429171,41.9429791]},"n2189046121":{"id":"n2189046121","loc":[-85.642914,41.9429041]},"n2189046122":{"id":"n2189046122","loc":[-85.6429385,41.9429035]},"n2189046123":{"id":"n2189046123","loc":[-85.6429348,41.9428126]},"n2189046124":{"id":"n2189046124","loc":[-85.6427746,41.9428163]},"n2189046125":{"id":"n2189046125","loc":[-85.6427783,41.942906]},"n2189046126":{"id":"n2189046126","loc":[-85.6428332,41.9429047]},"n2189046127":{"id":"n2189046127","loc":[-85.6423018,41.9428859]},"n2189046128":{"id":"n2189046128","loc":[-85.6422987,41.9427208]},"n2189046130":{"id":"n2189046130","loc":[-85.6424218,41.9427195]},"n2189046131":{"id":"n2189046131","loc":[-85.6424246,41.9428684]},"n2189046132":{"id":"n2189046132","loc":[-85.6423845,41.9428689]},"n2189046133":{"id":"n2189046133","loc":[-85.6423848,41.942885]},"n2189046134":{"id":"n2189046134","loc":[-85.641533,41.9429392]},"n2189046135":{"id":"n2189046135","loc":[-85.6416096,41.9428768]},"n2189046137":{"id":"n2189046137","loc":[-85.6416763,41.9429221]},"n2189046138":{"id":"n2189046138","loc":[-85.6415997,41.9429845]},"n2189046139":{"id":"n2189046139","loc":[-85.6420598,41.9428016]},"n2189046140":{"id":"n2189046140","loc":[-85.6420593,41.9427415]},"n2189046141":{"id":"n2189046141","loc":[-85.6421957,41.9427409]},"n2189046142":{"id":"n2189046142","loc":[-85.6421963,41.9428182]},"n2189046143":{"id":"n2189046143","loc":[-85.6421281,41.9428185]},"n2189046144":{"id":"n2189046144","loc":[-85.6421279,41.9428013]},"n2189046145":{"id":"n2189046145","loc":[-85.6409429,41.9429345]},"n2189046146":{"id":"n2189046146","loc":[-85.6410354,41.9429334]},"n2189046147":{"id":"n2189046147","loc":[-85.6410325,41.9427972]},"n2189046148":{"id":"n2189046148","loc":[-85.640997,41.9427976]},"n2189046149":{"id":"n2189046149","loc":[-85.6409963,41.9427643]},"n2189046150":{"id":"n2189046150","loc":[-85.6408605,41.9427659]},"n2189046152":{"id":"n2189046152","loc":[-85.6408623,41.9428482]},"n2189046153":{"id":"n2189046153","loc":[-85.640941,41.9428473]},"n2189152992":{"id":"n2189152992","loc":[-85.6437661,41.9422257]},"n2189152993":{"id":"n2189152993","loc":[-85.643768,41.9424067]},"n2189152994":{"id":"n2189152994","loc":[-85.6432176,41.9417705]},"n2189152995":{"id":"n2189152995","loc":[-85.6432097,41.941327]},"n2189152996":{"id":"n2189152996","loc":[-85.6436493,41.9413226]},"n2189152997":{"id":"n2189152997","loc":[-85.6436563,41.9417164]},"n2189152998":{"id":"n2189152998","loc":[-85.6435796,41.9417171]},"n2189152999":{"id":"n2189152999","loc":[-85.6435805,41.9417669]},"n2189153000":{"id":"n2189153000","loc":[-85.6438202,41.9414953]},"n2189153001":{"id":"n2189153001","loc":[-85.6438173,41.9413175]},"n2189153004":{"id":"n2189153004","loc":[-85.6432535,41.9418466]},"n2189153005":{"id":"n2189153005","loc":[-85.6433935,41.9418599]},"n2189153006":{"id":"n2189153006","loc":[-85.6434831,41.9418986]},"n2189153007":{"id":"n2189153007","loc":[-85.6435678,41.9419774]},"n2189153008":{"id":"n2189153008","loc":[-85.6435987,41.9420282]},"n2189153009":{"id":"n2189153009","loc":[-85.643438,41.9419573]},"n2189153010":{"id":"n2189153010","loc":[-85.6435284,41.9424676]},"n2189153011":{"id":"n2189153011","loc":[-85.6436207,41.9423631]},"n2189153012":{"id":"n2189153012","loc":[-85.6434957,41.9422973]},"n2189153013":{"id":"n2189153013","loc":[-85.6434457,41.9422458]},"n2189153014":{"id":"n2189153014","loc":[-85.6433976,41.9421772]},"n2189153015":{"id":"n2189153015","loc":[-85.6433861,41.9420785]},"n2189153016":{"id":"n2189153016","loc":[-85.6433765,41.9420313]},"n2189153017":{"id":"n2189153017","loc":[-85.6432207,41.9420284]},"n2189153018":{"id":"n2189153018","loc":[-85.6432245,41.9422759]},"n2189153019":{"id":"n2189153019","loc":[-85.6432649,41.9423474]},"n2189153020":{"id":"n2189153020","loc":[-85.6433226,41.9424132]},"n2189153021":{"id":"n2189153021","loc":[-85.6434111,41.9424704]},"n2189153022":{"id":"n2189153022","loc":[-85.6434591,41.9424347]},"n2189153025":{"id":"n2189153025","loc":[-85.6437669,41.9423073]},"n2189153026":{"id":"n2189153026","loc":[-85.6436611,41.942293]},"n2189153027":{"id":"n2189153027","loc":[-85.6435784,41.9422473]},"n2189153028":{"id":"n2189153028","loc":[-85.6435245,41.9421443]},"n2189153029":{"id":"n2189153029","loc":[-85.6435149,41.9420613]},"n2189153030":{"id":"n2189153030","loc":[-85.6433528,41.9419269]},"n2189153031":{"id":"n2189153031","loc":[-85.6432535,41.9419191]},"n2189153032":{"id":"n2189153032","loc":[-85.6430868,41.9419198]},"n2189153033":{"id":"n2189153033","loc":[-85.6434894,41.9420033]},"n2189153034":{"id":"n2189153034","loc":[-85.6432974,41.9419225]},"n2189153035":{"id":"n2189153035","loc":[-85.6433055,41.9421632]},"n2189153036":{"id":"n2189153036","loc":[-85.6433538,41.9422849]},"n2189153037":{"id":"n2189153037","loc":[-85.6434718,41.9423887]},"n2189153038":{"id":"n2189153038","loc":[-85.6436134,41.9422667]},"n2189153040":{"id":"n2189153040","loc":[-85.6438759,41.9414017]},"n2189153041":{"id":"n2189153041","loc":[-85.6438181,41.9413687]},"n2189153042":{"id":"n2189153042","loc":[-85.6436821,41.9413044]},"n2189153043":{"id":"n2189153043","loc":[-85.6435899,41.9412862]},"n2189153044":{"id":"n2189153044","loc":[-85.6433169,41.9417268]},"n2189153045":{"id":"n2189153045","loc":[-85.643301,41.9412859]},"n2189153046":{"id":"n2189153046","loc":[-85.6435531,41.9416981]},"n2189153047":{"id":"n2189153047","loc":[-85.6435427,41.9412863]},"n185948706":{"id":"n185948706","loc":[-85.6369439,41.940122]},"n185949348":{"id":"n185949348","loc":[-85.640039,41.931135]},"n185949870":{"id":"n185949870","loc":[-85.643195,41.949261]},"n185954680":{"id":"n185954680","loc":[-85.6337802,41.9401143]},"n185954784":{"id":"n185954784","loc":[-85.6487485,41.942527]},"n185958670":{"id":"n185958670","loc":[-85.637255,41.940104]},"n185958672":{"id":"n185958672","loc":[-85.636996,41.941355]},"n185960207":{"id":"n185960207","loc":[-85.634992,41.940118]},"n185963163":{"id":"n185963163","loc":[-85.638831,41.93398]},"n185963165":{"id":"n185963165","loc":[-85.640073,41.933968]},"n185963167":{"id":"n185963167","loc":[-85.641225,41.933972]},"n185963168":{"id":"n185963168","loc":[-85.642386,41.933952]},"n185964695":{"id":"n185964695","loc":[-85.6443608,41.9425645]},"n185964697":{"id":"n185964697","loc":[-85.644384,41.939941]},"n185964963":{"id":"n185964963","loc":[-85.6382347,41.9426146]},"n185964965":{"id":"n185964965","loc":[-85.637022,41.942622]},"n185964967":{"id":"n185964967","loc":[-85.6363706,41.9426606]},"n185964968":{"id":"n185964968","loc":[-85.6357988,41.9427748]},"n185964969":{"id":"n185964969","loc":[-85.6355409,41.9428465]},"n185964970":{"id":"n185964970","loc":[-85.6348729,41.9430443]},"n185966958":{"id":"n185966958","loc":[-85.641946,41.946413]},"n185966960":{"id":"n185966960","loc":[-85.643148,41.946389]},"n185967774":{"id":"n185967774","loc":[-85.641889,41.943852]},"n185967775":{"id":"n185967775","loc":[-85.641922,41.945121]},"n185967776":{"id":"n185967776","loc":[-85.641927,41.947544]},"n185967777":{"id":"n185967777","loc":[-85.641982,41.947622]},"n185969289":{"id":"n185969289","loc":[-85.63928,41.929221]},"n185969704":{"id":"n185969704","loc":[-85.6388186,41.9350099]},"n185969706":{"id":"n185969706","loc":[-85.6400709,41.9349957]},"n185969708":{"id":"n185969708","loc":[-85.6412214,41.9349827]},"n185969710":{"id":"n185969710","loc":[-85.6423509,41.934974]},"n185970602":{"id":"n185970602","loc":[-85.641293,41.931817]},"n185970604":{"id":"n185970604","loc":[-85.641258,41.932705]},"n185970605":{"id":"n185970605","loc":[-85.641148,41.936984]},"n185970606":{"id":"n185970606","loc":[-85.641112,41.938169]},"n185970906":{"id":"n185970906","loc":[-85.639454,41.943871]},"n185970908":{"id":"n185970908","loc":[-85.6394635,41.9450504]},"n185970909":{"id":"n185970909","loc":[-85.6394914,41.9451911]},"n185971368":{"id":"n185971368","loc":[-85.635769,41.940122]},"n185971978":{"id":"n185971978","loc":[-85.640003,41.936988]},"n185971980":{"id":"n185971980","loc":[-85.642299,41.936988]},"n185973633":{"id":"n185973633","loc":[-85.639023,41.92861]},"n185973635":{"id":"n185973635","loc":[-85.639153,41.928969]},"n185973637":{"id":"n185973637","loc":[-85.639213,41.929088]},"n185973639":{"id":"n185973639","loc":[-85.63935,41.929396]},"n185973641":{"id":"n185973641","loc":[-85.640143,41.931462]},"n185973644":{"id":"n185973644","loc":[-85.64019,41.931788]},"n185973646":{"id":"n185973646","loc":[-85.6401365,41.9327199]},"n185973648":{"id":"n185973648","loc":[-85.639983,41.938174]},"n185974477":{"id":"n185974477","loc":[-85.638206,41.941331]},"n185975928":{"id":"n185975928","loc":[-85.640683,41.94513]},"n185975930":{"id":"n185975930","loc":[-85.643102,41.945103]},"n185976255":{"id":"n185976255","loc":[-85.642424,41.931817]},"n185976257":{"id":"n185976257","loc":[-85.64242,41.932699]},"n185976258":{"id":"n185976258","loc":[-85.6422621,41.9381489]},"n185977452":{"id":"n185977452","loc":[-85.6457497,41.9398834]},"n185978772":{"id":"n185978772","loc":[-85.646656,41.939869]},"n185981472":{"id":"n185981472","loc":[-85.6388962,41.9321266]},"n185981474":{"id":"n185981474","loc":[-85.6388769,41.9327334]},"n185981476":{"id":"n185981476","loc":[-85.638829,41.934116]},"n185981478":{"id":"n185981478","loc":[-85.63876,41.937002]},"n185981480":{"id":"n185981480","loc":[-85.638682,41.93819]},"n185981999":{"id":"n185981999","loc":[-85.638194,41.9400866]},"n185982001":{"id":"n185982001","loc":[-85.646302,41.93988]},"n185982877":{"id":"n185982877","loc":[-85.640676,41.943867]},"n185982879":{"id":"n185982879","loc":[-85.640734,41.945887]},"n185985823":{"id":"n185985823","loc":[-85.643106,41.943841]},"n185985824":{"id":"n185985824","loc":[-85.643145,41.947641]},"n185985825":{"id":"n185985825","loc":[-85.643219,41.950829]},"n1475301385":{"id":"n1475301385","loc":[-85.6360612,41.9427042]},"n1475301397":{"id":"n1475301397","loc":[-85.6366651,41.9426328]},"n2139795811":{"id":"n2139795811","loc":[-85.6469154,41.9425427]},"n2139795830":{"id":"n2139795830","loc":[-85.6443194,41.9399444]},"n2139795834":{"id":"n2139795834","loc":[-85.6453506,41.9399002]},"n2139795837":{"id":"n2139795837","loc":[-85.645806,41.9398831]},"n2139858932":{"id":"n2139858932","loc":[-85.6351721,41.9429557]},"n2140019000":{"id":"n2140019000","loc":[-85.6359935,41.9427224]},"n2165942817":{"id":"n2165942817","loc":[-85.6442017,41.9414993]},"n2165942820":{"id":"n2165942820","loc":[-85.6442107,41.9421159]},"n2189152990":{"id":"n2189152990","loc":[-85.6442328,41.942404]},"n2189152991":{"id":"n2189152991","loc":[-85.6442309,41.9422229]},"n2189153002":{"id":"n2189153002","loc":[-85.6441329,41.9413147]},"n2189153003":{"id":"n2189153003","loc":[-85.6441357,41.9414925]},"n2189153023":{"id":"n2189153023","loc":[-85.6443453,41.9423074]},"n2189153024":{"id":"n2189153024","loc":[-85.6442318,41.9423045]},"n2189153039":{"id":"n2189153039","loc":[-85.6441343,41.9414025]},"w208643102":{"id":"w208643102","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153034","n2189153035","n2189153036","n2189153037","n2189153038"]},"w17966942":{"id":"w17966942","tags":{"highway":"residential","name":"Millard St"},"nodes":["n185954680","n185960207","n185971368","n185948706","n185958670","n185981999","n185981481","n185981482","n185973650","n185973659","n185970607","n185976259","n185976261","n2139795830","n185964697","n2139795834","n185977452","n2139795837","n185982001","n185978772"]},"w208643105":{"id":"w208643105","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153046","n2189153047"]},"w208631637":{"id":"w208631637","tags":{"area":"yes","building":"yes"},"nodes":["n2189046014","n2189046016","n2189046018","n2189046021","n2189046022","n2189046025","n2189046014"]},"w208643096":{"id":"w208643096","tags":{"amenity":"parking","area":"yes","fee":"no"},"nodes":["n2189152990","n2189153024","n2189152991","n2189152992","n2189153025","n2189152993","n2189152990"]},"w208631656":{"id":"w208631656","tags":{"area":"yes","building":"yes"},"nodes":["n2189046134","n2189046135","n2189046137","n2189046138","n2189046134"]},"w204003417":{"id":"w204003417","tags":{"area":"yes","building":"school"},"nodes":["n2140155811","n2140155814","n2140155816","n2140155818","n2140155821","n2140155823","n2140155825","n2140155827","n2140155811"]},"w208631654":{"id":"w208631654","tags":{"area":"yes","building":"yes"},"nodes":["n2189046127","n2189046128","n2189046130","n2189046131","n2189046132","n2189046133","n2189046127"]},"w17966327":{"id":"w17966327","tags":{"highway":"residential","name":"S Douglas Ave"},"nodes":["n185976261","n2140155839","n2140155834","n185974481","n2189153032","n185964959"]},"w41785752":{"id":"w41785752","tags":{"highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60","access":"yes"},"nodes":["n185954784","n2139795811","n185964695","n185964959","n185964960","n185964961","n185964962","n185964963","n185964965","n1475301397","n185964967","n1475301385","n2140019000","n185964968","n185964969","n2139858932","n185964970"]},"w203841842":{"id":"w203841842","tags":{"area":"yes","leisure":"playground"},"nodes":["n2138493848","n2138493849","n2138493850","n2138493851","n2138493852","n2138493853","n2138493854","n2138493855","n2138493856","n2138493848"]},"w208643103":{"id":"w208643103","tags":{"highway":"service"},"nodes":["n2189153039","n2189153040","n2189153041","n2189153042","n2189153043","n2189153047","n2189153045","n185974481"]},"w208643098":{"id":"w208643098","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153000","n2189153041","n2189153001","n2189153002","n2189153039","n2189153003","n2189153000"]},"w208631646":{"id":"w208631646","tags":{"area":"yes","building":"yes"},"nodes":["n2189046067","n2189046069","n2189046070","n2189046072","n2189046067"]},"w208631653":{"id":"w208631653","tags":{"area":"yes","building":"yes"},"nodes":["n2189046119","n2189046120","n2189046121","n2189046122","n2189046123","n2189046124","n2189046125","n2189046126","n2189046119"]},"w17966041":{"id":"w17966041","tags":{"highway":"residential","name":"S Lincoln Ave"},"nodes":["n185973659","n185973660","n185964961"]},"w208631645":{"id":"w208631645","tags":{"area":"yes","building":"yes"},"nodes":["n2189046060","n2189046061","n2189046063","n2189046065","n2189046060"]},"w206803397":{"id":"w206803397","tags":{"area":"yes","building":"yes"},"nodes":["n2168510551","n2168510552","n2168510553","n2168510554","n2168510555","n2168510556","n2168510557","n2168510558","n2168510551"]},"w17965792":{"id":"w17965792","tags":{"highway":"residential","name":"N Hooker Ave"},"nodes":["n185964962","n185970906","n185970908","n185970909"]},"w208631651":{"id":"w208631651","tags":{"area":"yes","building":"yes"},"nodes":["n2189046112","n2189046113","n2189046115","n2189046116","n2189046117","n2189046118","n2189046112"]},"w208631643":{"id":"w208631643","tags":{"area":"yes","building":"yes"},"nodes":["n2189046053","n2189046054","n2189046055","n2189046056","n2189046058","n2189046059","n2189046053"]},"w17966878":{"id":"w17966878","tags":{"highway":"residential","name":"S Hooker Ave"},"nodes":["n185981472","n185981474","n185963163","n185981476","n185969704","n185981478","n185981480","n185981481"]},"w17966102":{"id":"w17966102","tags":{"highway":"residential","name":"South St"},"nodes":["n185958672","n185974477","n185974479","n185973660","n185970614"]},"w208631660":{"id":"w208631660","tags":{"area":"yes","building":"yes"},"nodes":["n2189046145","n2189046146","n2189046147","n2189046148","n2189046149","n2189046150","n2189046152","n2189046153","n2189046145"]},"w208643101":{"id":"w208643101","tags":{"highway":"service"},"nodes":["n2189153023","n2189153024","n2189153025","n2189153026","n2189153038","n2189153027","n2189153028","n2189153029","n2189153033","n2189153009","n2189153030","n2189153034","n2189153031","n2189153032"]},"w204000205":{"id":"w204000205","tags":{"highway":"residential","name":"South St","oneway":"yes"},"nodes":["n185974481","n2140155851","n185970614"]},"w203841841":{"id":"w203841841","tags":{"area":"yes","leisure":"pitch","pitch":"basketball"},"nodes":["n2138493844","n2138493845","n2138493846","n2138493847","n2138493844"]},"w17965444":{"id":"w17965444","tags":{"highway":"residential","name":"N Grant Ave"},"nodes":["n185964960","n185967774","n185967775","n185966958","n185967776","n185967777"]},"w208631648":{"id":"w208631648","tags":{"area":"yes","building":"yes"},"nodes":["n2189046074","n2189046075","n2189046077","n2189046079","n2189046082","n2189046083","n2189046085","n2189046087","n2189046089","n2189046090","n2189046092","n2189046094","n2189046096","n2189046097","n2189046099","n2189046103","n2189046074"]},"w208643100":{"id":"w208643100","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153010","n2189153011","n2189153012","n2189153013","n2189153014","n2189153015","n2189153016","n2189153017","n2189153018","n2189153019","n2189153020","n2189153021","n2189153022","n2189153010"]},"w17965749":{"id":"w17965749","tags":{"highway":"residential","name":"S Grant Ave"},"nodes":["n185970614","n185970616","n185964960"]},"w206574482":{"id":"w206574482","tags":{"amenity":"library","area":"yes","building":"yes","name":"Three Rivers Public Library"},"nodes":["n2165942817","n2165942818","n2165942819","n2165942820","n2165942817"]},"w208643097":{"id":"w208643097","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189152994","n2189152995","n2189152996","n2189152997","n2189152998","n2189152999","n2189152994"]},"w17966879":{"id":"w17966879","tags":{"highway":"residential","name":"S Hooker Ave"},"nodes":["n185981482","n185974479","n185964962"]},"w17966325":{"id":"w17966325","tags":{"highway":"residential","name":"S Douglas Ave"},"nodes":["n185976255","n185976257","n185963168","n185969710","n185971980","n185976258","n185954700","n185976259"]},"w17967390":{"id":"w17967390","tags":{"highway":"residential","name":"N Douglas Ave"},"nodes":["n185964959","n185985823","n185975930","n185966960","n185985824","n185949870","n185985825"]},"w208631635":{"id":"w208631635","tags":{"area":"yes","building":"yes"},"nodes":["n2189046007","n2189046009","n2189046011","n2189046012","n2189046007"]},"w208643099":{"id":"w208643099","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153031","n2189153004","n2189153005","n2189153006","n2189153007","n2189153008","n2189153029","n2189153033","n2189153009","n2189153030","n2189153031"]},"w208631658":{"id":"w208631658","tags":{"area":"yes","building":"yes"},"nodes":["n2189046139","n2189046140","n2189046141","n2189046142","n2189046143","n2189046144","n2189046139"]},"w208643104":{"id":"w208643104","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153044","n2189153045"]},"w17966039":{"id":"w17966039","tags":{"highway":"residential","name":"S Lincoln Ave"},"nodes":["n185973633","n185973635","n185973637","n185969289","n185973639","n185949348","n185973641","n185973644","n185973646","n185963165","n185969706","n185971978","n185973648","n185973650"]},"w204003420":{"id":"w204003420","tags":{"amenity":"parking","area":"yes"},"nodes":["n2140155840","n2140155842","n2140155844","n2140155845","n2140155847","n2140155849","n2140155854","n2140155840"]},"w204003419":{"id":"w204003419","tags":{"highway":"service"},"nodes":["n2140155834","n2140155835","n2140155837","n2140155839"]},"w204003418":{"id":"w204003418","tags":{"amenity":"school","area":"yes","name":"Andrews Elementary School"},"nodes":["n2140155828","n2140155829","n2140155830","n2140155831","n2140155832","n2140155833","n2140155828"]},"w17965747":{"id":"w17965747","tags":{"highway":"residential","name":"S Grant Ave"},"nodes":["n185970602","n185970604","n185963167","n185969708","n185970605","n185970606","n185970607"]},"w17967073":{"id":"w17967073","tags":{"highway":"residential","name":"N Lincoln Ave"},"nodes":["n185964961","n185982877","n185975928","n185982879"]},"w204003421":{"id":"w204003421","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2140155851","n2140155852","n2140155854","n2140155856"]},"r1943857":{"id":"r1943857","tags":{"modifier":"Business","name":"US 131 Business (Three Rivers, MI)","network":"US:US","ref":"131","route":"road","type":"route"},"members":[{"id":"w17966509","type":"way","role":"forward"},{"id":"w143497377","type":"way","role":""},{"id":"w134150811","type":"way","role":""},{"id":"w134150800","type":"way","role":""},{"id":"w134150789","type":"way","role":""},{"id":"w134150795","type":"way","role":""},{"id":"w41785752","type":"way","role":""},{"id":"w17965146","type":"way","role":"forward"},{"id":"w17964031","type":"way","role":"forward"}]},"r270277":{"id":"r270277","tags":{"network":"US:MI","ref":"60","route":"road","state_id":"MI","type":"route","url":"http://en.wikipedia.org/wiki/M-60_%28Michigan_highway%29"},"members":[{"id":"w17751087","type":"way","role":"east"},{"id":"w117148312","type":"way","role":"east"},{"id":"w40942155","type":"way","role":"west"},{"id":"w17751017","type":"way","role":""},{"id":"w17751083","type":"way","role":""},{"id":"w17747780","type":"way","role":""},{"id":"w41068082","type":"way","role":""},{"id":"w197025212","type":"way","role":""},{"id":"w17743874","type":"way","role":""},{"id":"w17751044","type":"way","role":""},{"id":"w17752167","type":"way","role":""},{"id":"w17751089","type":"way","role":""},{"id":"w17743879","type":"way","role":""},{"id":"w17751064","type":"way","role":""},{"id":"w197057073","type":"way","role":""},{"id":"w167699963","type":"way","role":""},{"id":"w167699972","type":"way","role":""},{"id":"w17967584","type":"way","role":""},{"id":"w167699964","type":"way","role":""},{"id":"w17967582","type":"way","role":"west"},{"id":"w41260270","type":"way","role":"west"},{"id":"w17965146","type":"way","role":"west"},{"id":"w41785752","type":"way","role":""},{"id":"w134150795","type":"way","role":""},{"id":"w134150789","type":"way","role":""},{"id":"w134150800","type":"way","role":""},{"id":"w134150811","type":"way","role":""},{"id":"w134150836","type":"way","role":""},{"id":"w134150802","type":"way","role":""},{"id":"w41074896","type":"way","role":""},{"id":"w17966773","type":"way","role":""},{"id":"w17967415","type":"way","role":""},{"id":"w41074899","type":"way","role":""},{"id":"w17967581","type":"way","role":""},{"id":"w41074902","type":"way","role":""},{"id":"w41074906","type":"way","role":""},{"id":"w209707997","type":"way","role":""},{"id":"w209707998","type":"way","role":""},{"id":"w17964798","type":"way","role":""},{"id":"w17966034","type":"way","role":""},{"id":"w17967593","type":"way","role":""},{"id":"w41074888","type":"way","role":""},{"id":"w17733772","type":"way","role":""},{"id":"w41074813","type":"way","role":""},{"id":"w17742213","type":"way","role":""},{"id":"w17746863","type":"way","role":""},{"id":"w17745772","type":"way","role":""},{"id":"w17742222","type":"way","role":""},{"id":"w17745922","type":"way","role":""},{"id":"w17742198","type":"way","role":""},{"id":"w17747675","type":"way","role":""},{"id":"w17739927","type":"way","role":""},{"id":"w17745708","type":"way","role":""},{"id":"w41006323","type":"way","role":""},{"id":"w17744233","type":"way","role":""},{"id":"w17739436","type":"way","role":""},{"id":"w17742201","type":"way","role":""},{"id":"w151418616","type":"way","role":""},{"id":"w17750062","type":"way","role":""},{"id":"w17742227","type":"way","role":"east"},{"id":"w41006348","type":"way","role":"east"},{"id":"w41260984","type":"way","role":""},{"id":"w17832427","type":"way","role":""},{"id":"w17838408","type":"way","role":""},{"id":"w17835846","type":"way","role":""},{"id":"w17832923","type":"way","role":""},{"id":"w17839388","type":"way","role":""},{"id":"w17838390","type":"way","role":""},{"id":"w17831272","type":"way","role":""},{"id":"w17828581","type":"way","role":""},{"id":"w38240686","type":"way","role":""},{"id":"w17838405","type":"way","role":"east"},{"id":"w123323711","type":"way","role":"east"},{"id":"w17830167","type":"way","role":"east"},{"id":"w99011909","type":"way","role":"east"},{"id":"w41911361","type":"way","role":"east"},{"id":"w41911355","type":"way","role":"east"},{"id":"w41911356","type":"way","role":"east"},{"id":"w117148326","type":"way","role":"west"},{"id":"w41911352","type":"way","role":"west"},{"id":"w41911353","type":"way","role":"west"},{"id":"w41911354","type":"way","role":"west"},{"id":"w41911360","type":"way","role":"west"},{"id":"w38240676","type":"way","role":"west"},{"id":"w123323710","type":"way","role":"west"},{"id":"w41260271","type":"way","role":"east"},{"id":"w41260273","type":"way","role":"east"},{"id":"w17964031","type":"way","role":"east"},{"id":"w41006344","type":"way","role":"west"},{"id":"w41006351","type":"way","role":"west"}]},"n367813436":{"id":"n367813436","loc":[-85.63605205663384,41.94305506683346],"tags":{"amenity":"fire_station","name":"Three Rivers Fire Department"}},"n185948708":{"id":"n185948708","loc":[-85.6369828,41.9408789]},"n185948710":{"id":"n185948710","loc":[-85.6370184,41.9411346]},"n185954691":{"id":"n185954691","loc":[-85.634476,41.941475]},"n185954692":{"id":"n185954692","loc":[-85.635008,41.941846]},"n185954693":{"id":"n185954693","loc":[-85.635362,41.941962]},"n185954695":{"id":"n185954695","loc":[-85.63578,41.941978]},"n185972903":{"id":"n185972903","loc":[-85.63295,41.9430062]},"n185964971":{"id":"n185964971","loc":[-85.6346811,41.9431023]},"n1819805854":{"id":"n1819805854","loc":[-85.6331275,41.9404837]},"n1819805918":{"id":"n1819805918","loc":[-85.6331168,41.942798]},"n1819805762":{"id":"n1819805762","loc":[-85.6333034,41.9424123]},"n1819805907":{"id":"n1819805907","loc":[-85.6334819,41.9419121]},"n1819805915":{"id":"n1819805915","loc":[-85.6334554,41.9413588]},"n1819848888":{"id":"n1819848888","loc":[-85.6331625,41.942679]},"n1819848930":{"id":"n1819848930","loc":[-85.6338684,41.9431252]},"n1819858505":{"id":"n1819858505","loc":[-85.6346782,41.9429092]},"n1819858507":{"id":"n1819858507","loc":[-85.6339003,41.9414534]},"n1819858508":{"id":"n1819858508","loc":[-85.6345709,41.9427742]},"n1819858509":{"id":"n1819858509","loc":[-85.63419,41.9417322]},"n1819858511":{"id":"n1819858511","loc":[-85.6340666,41.9415652]},"n1819858512":{"id":"n1819858512","loc":[-85.6343295,41.9423027]},"n1819858514":{"id":"n1819858514","loc":[-85.6343241,41.942207]},"n1819858521":{"id":"n1819858521","loc":[-85.633391,41.941231]},"n1819858528":{"id":"n1819858528","loc":[-85.6343027,41.9419716]},"n185954683":{"id":"n185954683","loc":[-85.6335412,41.940147]},"n185954685":{"id":"n185954685","loc":[-85.6334296,41.9403023]},"n185954687":{"id":"n185954687","loc":[-85.6333988,41.9404704]},"n185954689":{"id":"n185954689","loc":[-85.6335511,41.9410225]},"n185954690":{"id":"n185954690","loc":[-85.6336721,41.9411669]},"n1820938802":{"id":"n1820938802","loc":[-85.6330671,41.941845]},"n1821006702":{"id":"n1821006702","loc":[-85.6344047,41.9395496]},"n2130304133":{"id":"n2130304133","loc":[-85.6349025,41.9427659]},"n2130304136":{"id":"n2130304136","loc":[-85.6346027,41.9422017]},"n2130304138":{"id":"n2130304138","loc":[-85.6348577,41.9421517]},"n2130304140":{"id":"n2130304140","loc":[-85.6348419,41.9422694]},"n2130304142":{"id":"n2130304142","loc":[-85.6349071,41.9423135]},"n2130304144":{"id":"n2130304144","loc":[-85.6350495,41.9423312]},"n2130304146":{"id":"n2130304146","loc":[-85.6351009,41.9422812]},"n2130304147":{"id":"n2130304147","loc":[-85.6351227,41.9421532]},"n2130304148":{"id":"n2130304148","loc":[-85.635526,41.9421547]},"n2130304149":{"id":"n2130304149","loc":[-85.6355339,41.9425768]},"n2130304150":{"id":"n2130304150","loc":[-85.6351582,41.9426562]},"n2130304151":{"id":"n2130304151","loc":[-85.6351207,41.9427032]},"n2138493807":{"id":"n2138493807","loc":[-85.6350923,41.9415216]},"n2138493808":{"id":"n2138493808","loc":[-85.6353603,41.9411061]},"n2138493809":{"id":"n2138493809","loc":[-85.6354421,41.9410942]},"n2138493810":{"id":"n2138493810","loc":[-85.6355079,41.9411044]},"n2138493811":{"id":"n2138493811","loc":[-85.6355693,41.9411246]},"n2138493812":{"id":"n2138493812","loc":[-85.6355829,41.9411061]},"n2138493813":{"id":"n2138493813","loc":[-85.6355624,41.9409777]},"n2138493814":{"id":"n2138493814","loc":[-85.6355011,41.9409152]},"n2138493815":{"id":"n2138493815","loc":[-85.635383,41.9409219]},"n2138493816":{"id":"n2138493816","loc":[-85.635299,41.9409658]},"n2138493817":{"id":"n2138493817","loc":[-85.6351695,41.941204]},"n2138493818":{"id":"n2138493818","loc":[-85.6348879,41.9415166]},"n2138493819":{"id":"n2138493819","loc":[-85.634897,41.9415757]},"n2138493820":{"id":"n2138493820","loc":[-85.6349606,41.9416399]},"n2138493821":{"id":"n2138493821","loc":[-85.6350219,41.9416669]},"n2138493822":{"id":"n2138493822","loc":[-85.6351241,41.9416314]},"n2138493823":{"id":"n2138493823","loc":[-85.6350855,41.9415622]},"n2138493824":{"id":"n2138493824","loc":[-85.6350401,41.9413603]},"n2138493825":{"id":"n2138493825","loc":[-85.6352206,41.9410765]},"n2138493826":{"id":"n2138493826","loc":[-85.6343865,41.9415594]},"n2138493827":{"id":"n2138493827","loc":[-85.6343506,41.9415873]},"n2138493828":{"id":"n2138493828","loc":[-85.6344158,41.9417557]},"n2138493829":{"id":"n2138493829","loc":[-85.6344614,41.9417968]},"n2138493830":{"id":"n2138493830","loc":[-85.6345005,41.9418186]},"n2138493831":{"id":"n2138493831","loc":[-85.6345965,41.9418162]},"n2138493832":{"id":"n2138493832","loc":[-85.6347317,41.9417242]},"n2138493833":{"id":"n2138493833","loc":[-85.6346722,41.941775]},"n2139858909":{"id":"n2139858909","loc":[-85.633403,41.9391006]},"n2139858910":{"id":"n2139858910","loc":[-85.6332973,41.9393967]},"n2139858911":{"id":"n2139858911","loc":[-85.633205,41.9396742]},"n2139858912":{"id":"n2139858912","loc":[-85.6332203,41.9397772]},"n2139858913":{"id":"n2139858913","loc":[-85.6333453,41.939936]},"n2139858914":{"id":"n2139858914","loc":[-85.6333761,41.9400018]},"n2139858915":{"id":"n2139858915","loc":[-85.63328,41.9402249]},"n2139858916":{"id":"n2139858916","loc":[-85.6332357,41.9403523]},"n2139858917":{"id":"n2139858917","loc":[-85.6332838,41.9405831]},"n2139858918":{"id":"n2139858918","loc":[-85.6333643,41.9408744]},"n2139858919":{"id":"n2139858919","loc":[-85.6334394,41.9410519]},"n2139858920":{"id":"n2139858920","loc":[-85.6335815,41.9411717]},"n2139858921":{"id":"n2139858921","loc":[-85.6337478,41.9412734]},"n2139858922":{"id":"n2139858922","loc":[-85.6343174,41.9415268]},"n2139858923":{"id":"n2139858923","loc":[-85.6343886,41.9417397]},"n2139858924":{"id":"n2139858924","loc":[-85.6344407,41.9418015]},"n2139858925":{"id":"n2139858925","loc":[-85.6345139,41.9418366]},"n2139858926":{"id":"n2139858926","loc":[-85.6344846,41.942005]},"n2139858927":{"id":"n2139858927","loc":[-85.6345775,41.9422218]},"n2139858928":{"id":"n2139858928","loc":[-85.6348771,41.9427814]},"n2139858929":{"id":"n2139858929","loc":[-85.6349487,41.9427995]},"n2139858930":{"id":"n2139858930","loc":[-85.6350415,41.9427874]},"n2139858931":{"id":"n2139858931","loc":[-85.6351246,41.9428589]},"n2139858978":{"id":"n2139858978","loc":[-85.6349658,41.9431481]},"n2139858979":{"id":"n2139858979","loc":[-85.6350081,41.9431287]},"n2139858980":{"id":"n2139858980","loc":[-85.6349967,41.9430997]},"n2139858981":{"id":"n2139858981","loc":[-85.6352158,41.9430352]},"n2139858982":{"id":"n2139858982","loc":[-85.6348174,41.94267]},"n2139858983":{"id":"n2139858983","loc":[-85.6346142,41.9425989]},"n2139858984":{"id":"n2139858984","loc":[-85.6344938,41.9423809]},"n2139858985":{"id":"n2139858985","loc":[-85.6344856,41.9422997]},"n2139870380":{"id":"n2139870380","loc":[-85.6346707,41.9417955]},"n2139870381":{"id":"n2139870381","loc":[-85.6345949,41.9418311]},"n2139870382":{"id":"n2139870382","loc":[-85.6343322,41.9418659]},"n2139870383":{"id":"n2139870383","loc":[-85.6342072,41.941885]},"n2139870384":{"id":"n2139870384","loc":[-85.6341325,41.9418919]},"n2139870385":{"id":"n2139870385","loc":[-85.6341314,41.9422028]},"n2139870386":{"id":"n2139870386","loc":[-85.6340472,41.9423271]},"n2139870387":{"id":"n2139870387","loc":[-85.6342185,41.9427933]},"n2139870388":{"id":"n2139870388","loc":[-85.6340605,41.9423924]},"n2139870389":{"id":"n2139870389","loc":[-85.6339889,41.9424069]},"n2139870390":{"id":"n2139870390","loc":[-85.633971,41.942356]},"n2139870391":{"id":"n2139870391","loc":[-85.63361,41.9424235]},"n2139870392":{"id":"n2139870392","loc":[-85.6337137,41.9426819]},"n2139870393":{"id":"n2139870393","loc":[-85.6336977,41.9428632]},"n2139870394":{"id":"n2139870394","loc":[-85.6338823,41.9428647]},"n2139870395":{"id":"n2139870395","loc":[-85.6339412,41.9430069]},"n2139870396":{"id":"n2139870396","loc":[-85.6338873,41.9430353]},"n2139870397":{"id":"n2139870397","loc":[-85.6337676,41.942815]},"n2139870398":{"id":"n2139870398","loc":[-85.6336822,41.9423505]},"n2139870399":{"id":"n2139870399","loc":[-85.634037,41.9422725]},"n2139870400":{"id":"n2139870400","loc":[-85.6340294,41.9422518]},"n2139870401":{"id":"n2139870401","loc":[-85.6336726,41.9423312]},"n2139870402":{"id":"n2139870402","loc":[-85.6342188,41.9425715]},"n2139870403":{"id":"n2139870403","loc":[-85.6342524,41.942565]},"n2139870404":{"id":"n2139870404","loc":[-85.6341438,41.942299]},"n2139870405":{"id":"n2139870405","loc":[-85.6341149,41.9423061]},"n2139870407":{"id":"n2139870407","loc":[-85.6340846,41.9431458]},"n2139870408":{"id":"n2139870408","loc":[-85.6339436,41.9429032]},"n2139870409":{"id":"n2139870409","loc":[-85.6343143,41.9428207]},"n2139870410":{"id":"n2139870410","loc":[-85.6343507,41.94277]},"n2139870411":{"id":"n2139870411","loc":[-85.6341527,41.942254]},"n2139870412":{"id":"n2139870412","loc":[-85.6340925,41.9422199]},"n2139870413":{"id":"n2139870413","loc":[-85.6335435,41.9423433]},"n2139870414":{"id":"n2139870414","loc":[-85.6335023,41.9423975]},"n2139870415":{"id":"n2139870415","loc":[-85.6335086,41.9424552]},"n2139870416":{"id":"n2139870416","loc":[-85.6336296,41.942665]},"n2139870417":{"id":"n2139870417","loc":[-85.6341396,41.9428596]},"n2139870418":{"id":"n2139870418","loc":[-85.6339701,41.9424487]},"n2139870419":{"id":"n2139870419","loc":[-85.6335514,41.9425294]},"n2139870420":{"id":"n2139870420","loc":[-85.6337406,41.9424929]},"n2139870421":{"id":"n2139870421","loc":[-85.6338939,41.9428687]},"n2139870422":{"id":"n2139870422","loc":[-85.6341323,41.9419538]},"n2139870423":{"id":"n2139870423","loc":[-85.6340321,41.9420376]},"n2139870424":{"id":"n2139870424","loc":[-85.6337648,41.942238]},"n2139870425":{"id":"n2139870425","loc":[-85.6337604,41.9422685]},"n2139870426":{"id":"n2139870426","loc":[-85.6337682,41.9422928]},"n2139870427":{"id":"n2139870427","loc":[-85.6338086,41.9423862]},"n2139870428":{"id":"n2139870428","loc":[-85.6349465,41.9416631]},"n2139870429":{"id":"n2139870429","loc":[-85.6351097,41.9416973]},"n2139870430":{"id":"n2139870430","loc":[-85.6353371,41.9416798]},"n2139870431":{"id":"n2139870431","loc":[-85.6349627,41.9422506]},"n2139870432":{"id":"n2139870432","loc":[-85.634979,41.9421815]},"n2139870433":{"id":"n2139870433","loc":[-85.634885,41.9421679]},"n2139870434":{"id":"n2139870434","loc":[-85.6348689,41.9422377]},"n2139870435":{"id":"n2139870435","loc":[-85.6349779,41.9419486]},"n2139870436":{"id":"n2139870436","loc":[-85.6349505,41.9418933]},"n2139870437":{"id":"n2139870437","loc":[-85.6347327,41.9419505]},"n2139870438":{"id":"n2139870438","loc":[-85.6347614,41.9420087]},"n2139870439":{"id":"n2139870439","loc":[-85.6351889,41.9416912]},"n2139870440":{"id":"n2139870440","loc":[-85.6351092,41.9418426]},"n2139870441":{"id":"n2139870441","loc":[-85.635086,41.9419659]},"n2139870442":{"id":"n2139870442","loc":[-85.6350584,41.9421466]},"n2139870443":{"id":"n2139870443","loc":[-85.6350993,41.9421606]},"n2139870444":{"id":"n2139870444","loc":[-85.6350993,41.9422132]},"n2139870445":{"id":"n2139870445","loc":[-85.6350794,41.9422855]},"n2139870446":{"id":"n2139870446","loc":[-85.6350474,41.9423159]},"n2139870447":{"id":"n2139870447","loc":[-85.6349251,41.9422998]},"n2139870448":{"id":"n2139870448","loc":[-85.634911,41.9422755]},"n2139870449":{"id":"n2139870449","loc":[-85.6349157,41.9422553]},"n2139870450":{"id":"n2139870450","loc":[-85.6347213,41.9419324]},"n2139870451":{"id":"n2139870451","loc":[-85.6349535,41.9418771]},"n2139870452":{"id":"n2139870452","loc":[-85.6350135,41.9419421]},"n2139870453":{"id":"n2139870453","loc":[-85.6348584,41.9418997]},"n2139870454":{"id":"n2139870454","loc":[-85.6348113,41.9418101]},"n2139870455":{"id":"n2139870455","loc":[-85.6347306,41.9417449]},"n2139870456":{"id":"n2139870456","loc":[-85.6349123,41.941776]},"n2139870457":{"id":"n2139870457","loc":[-85.6349423,41.9421448]},"n2139870458":{"id":"n2139870458","loc":[-85.6349436,41.9420652]},"n2139870459":{"id":"n2139870459","loc":[-85.6349136,41.9419963]},"n2139870460":{"id":"n2139870460","loc":[-85.6349814,41.9419789]},"n2139989328":{"id":"n2139989328","loc":[-85.6334188,41.9421725]},"n2139989330":{"id":"n2139989330","loc":[-85.6335087,41.9416308]},"n2139989335":{"id":"n2139989335","loc":[-85.6336856,41.9429371]},"n2139989337":{"id":"n2139989337","loc":[-85.6333713,41.9427217]},"n2139989339":{"id":"n2139989339","loc":[-85.6332912,41.9425383]},"n2139989341":{"id":"n2139989341","loc":[-85.6339369,41.9409198]},"n2139989344":{"id":"n2139989344","loc":[-85.634097,41.9409469]},"n2139989346":{"id":"n2139989346","loc":[-85.634137,41.9412852]},"n2139989348":{"id":"n2139989348","loc":[-85.6344536,41.9414151]},"n2139989350":{"id":"n2139989350","loc":[-85.6350794,41.9412392]},"n2139989351":{"id":"n2139989351","loc":[-85.6352541,41.9409387]},"n2139989353":{"id":"n2139989353","loc":[-85.6357198,41.9408007]},"n2139989355":{"id":"n2139989355","loc":[-85.6357235,41.9427088]},"n2139989357":{"id":"n2139989357","loc":[-85.6337119,41.9421256]},"n2139989359":{"id":"n2139989359","loc":[-85.6336913,41.9420655]},"n2139989360":{"id":"n2139989360","loc":[-85.633582,41.9420867]},"n2139989362":{"id":"n2139989362","loc":[-85.6336058,41.9421491]},"n2139989364":{"id":"n2139989364","loc":[-85.6339685,41.9410995]},"n2139989366":{"id":"n2139989366","loc":[-85.6339067,41.9411383]},"n2139989368":{"id":"n2139989368","loc":[-85.6339685,41.9411972]},"n2139989370":{"id":"n2139989370","loc":[-85.6340398,41.9411619]},"n2139870379":{"id":"n2139870379","loc":[-85.6348391,41.9416651]},"n2140006363":{"id":"n2140006363","loc":[-85.6353144,41.9430345]},"n2140006364":{"id":"n2140006364","loc":[-85.6349191,41.9431422]},"n2140018997":{"id":"n2140018997","loc":[-85.63645945147184,41.942986488012565],"tags":{"amenity":"townhall","name":"Three Rivers City Hall"}},"n2140018998":{"id":"n2140018998","loc":[-85.6370319,41.9427919]},"n2140018999":{"id":"n2140018999","loc":[-85.6360687,41.9427808]},"n2199856288":{"id":"n2199856288","loc":[-85.6344968,41.9407307]},"n2199856289":{"id":"n2199856289","loc":[-85.634492,41.9406036]},"n2199856290":{"id":"n2199856290","loc":[-85.634891,41.9406001]},"n2199856291":{"id":"n2199856291","loc":[-85.6348894,41.9405288]},"n2199856292":{"id":"n2199856292","loc":[-85.6349166,41.94053]},"n2199856293":{"id":"n2199856293","loc":[-85.6349166,41.9404956]},"n2199856294":{"id":"n2199856294","loc":[-85.6350219,41.9404956]},"n2199856295":{"id":"n2199856295","loc":[-85.6350251,41.94053]},"n2199856296":{"id":"n2199856296","loc":[-85.6350538,41.9405288]},"n2199856297":{"id":"n2199856297","loc":[-85.6350602,41.94079]},"n2199856298":{"id":"n2199856298","loc":[-85.6351703,41.9407912]},"n2199856299":{"id":"n2199856299","loc":[-85.6351688,41.9409171]},"n2199856300":{"id":"n2199856300","loc":[-85.6347889,41.9409135]},"n2199856301":{"id":"n2199856301","loc":[-85.6347921,41.94079]},"n2199856302":{"id":"n2199856302","loc":[-85.6348942,41.9407888]},"n2199856303":{"id":"n2199856303","loc":[-85.6348926,41.9407283]},"n185951869":{"id":"n185951869","loc":[-85.6387639,41.957288]},"n185958643":{"id":"n185958643","loc":[-85.636746,41.929221]},"n185958645":{"id":"n185958645","loc":[-85.636791,41.929363]},"n185958647":{"id":"n185958647","loc":[-85.6375975,41.9314987]},"n185958649":{"id":"n185958649","loc":[-85.637669,41.931667]},"n185958651":{"id":"n185958651","loc":[-85.637728,41.931901]},"n185958653":{"id":"n185958653","loc":[-85.637724,41.932187]},"n185958656":{"id":"n185958656","loc":[-85.637732,41.932761]},"n185958658":{"id":"n185958658","loc":[-85.637688,41.93398]},"n185958660":{"id":"n185958660","loc":[-85.637685,41.934223]},"n185958662":{"id":"n185958662","loc":[-85.6376468,41.9350232]},"n185958664":{"id":"n185958664","loc":[-85.637564,41.937028]},"n185958666":{"id":"n185958666","loc":[-85.637458,41.938197]},"n185958668":{"id":"n185958668","loc":[-85.637424,41.938692]},"n185964972":{"id":"n185964972","loc":[-85.6341901,41.9432732]},"n185971361":{"id":"n185971361","loc":[-85.635762,41.938208]},"n185971364":{"id":"n185971364","loc":[-85.635732,41.9384]},"n185971366":{"id":"n185971366","loc":[-85.635736,41.938697]},"n185972775":{"id":"n185972775","loc":[-85.635638,42.070357]},"n185972777":{"id":"n185972777","loc":[-85.635724,42.069929]},"n185972779":{"id":"n185972779","loc":[-85.635804,42.069248]},"n185972781":{"id":"n185972781","loc":[-85.635869,42.068361]},"n185972783":{"id":"n185972783","loc":[-85.635883,42.067582]},"n185972785":{"id":"n185972785","loc":[-85.635875,42.067114]},"n185972787":{"id":"n185972787","loc":[-85.635778,42.065359]},"n185972788":{"id":"n185972788","loc":[-85.635728,42.063416]},"n185972789":{"id":"n185972789","loc":[-85.635665,42.062491]},"n185972790":{"id":"n185972790","loc":[-85.635617,42.061928]},"n185972791":{"id":"n185972791","loc":[-85.635614,42.061898]},"n185972793":{"id":"n185972793","loc":[-85.635379,42.060288]},"n185972795":{"id":"n185972795","loc":[-85.635092,42.05799]},"n185972797":{"id":"n185972797","loc":[-85.634843,42.055781]},"n185972798":{"id":"n185972798","loc":[-85.634817,42.055549]},"n185972800":{"id":"n185972800","loc":[-85.634708,42.053942]},"n185972802":{"id":"n185972802","loc":[-85.634447,42.051809]},"n185972805":{"id":"n185972805","loc":[-85.634241,42.04946]},"n185972807":{"id":"n185972807","loc":[-85.633787,42.045926]},"n185972809":{"id":"n185972809","loc":[-85.633811,42.045645]},"n185972811":{"id":"n185972811","loc":[-85.63373,42.043626]},"n185972813":{"id":"n185972813","loc":[-85.633698,42.042184]},"n185972814":{"id":"n185972814","loc":[-85.63369,42.04181]},"n185972815":{"id":"n185972815","loc":[-85.633681,42.040714]},"n185972816":{"id":"n185972816","loc":[-85.633571,42.036322]},"n185972817":{"id":"n185972817","loc":[-85.633537,42.034044]},"n185972819":{"id":"n185972819","loc":[-85.633481,42.030785]},"n185972821":{"id":"n185972821","loc":[-85.633452,42.027538]},"n185972824":{"id":"n185972824","loc":[-85.633438,42.027427]},"n185972826":{"id":"n185972826","loc":[-85.633342,42.022656]},"n185972830":{"id":"n185972830","loc":[-85.63327,42.020724]},"n185972832":{"id":"n185972832","loc":[-85.633198,42.019106]},"n185972834":{"id":"n185972834","loc":[-85.633249,42.018363]},"n185972835":{"id":"n185972835","loc":[-85.633139,42.012944]},"n185972836":{"id":"n185972836","loc":[-85.63309,42.008284]},"n185972839":{"id":"n185972839","loc":[-85.63298,42.00005]},"n185972845":{"id":"n185972845","loc":[-85.6325369,41.9764959]},"n185972847":{"id":"n185972847","loc":[-85.6327549,41.9750005]},"n185972849":{"id":"n185972849","loc":[-85.6329374,41.9742527]},"n185972851":{"id":"n185972851","loc":[-85.6331387,41.9736039]},"n185972862":{"id":"n185972862","loc":[-85.6383589,41.9585023]},"n185972868":{"id":"n185972868","loc":[-85.6393633,41.9551716]},"n185972878":{"id":"n185972878","loc":[-85.639377,41.95335]},"n185972882":{"id":"n185972882","loc":[-85.6389179,41.9516944]},"n185972885":{"id":"n185972885","loc":[-85.6387444,41.9512105]},"n185972891":{"id":"n185972891","loc":[-85.636421,41.946392]},"n185972895":{"id":"n185972895","loc":[-85.635965,41.945809]},"n185972897":{"id":"n185972897","loc":[-85.635683,41.945449]},"n185972899":{"id":"n185972899","loc":[-85.635281,41.9450252]},"n185972905":{"id":"n185972905","loc":[-85.6324428,41.9425743]},"n185985217":{"id":"n185985217","loc":[-85.638243,41.943674]},"n185985219":{"id":"n185985219","loc":[-85.638228,41.943747]},"n185985221":{"id":"n185985221","loc":[-85.638163,41.943797]},"n185985222":{"id":"n185985222","loc":[-85.638089,41.943832]},"n185985223":{"id":"n185985223","loc":[-85.637969,41.943841]},"n185985225":{"id":"n185985225","loc":[-85.637841,41.943833]},"n185985227":{"id":"n185985227","loc":[-85.637601,41.943789]},"n185985229":{"id":"n185985229","loc":[-85.637449,41.943754]},"n185985231":{"id":"n185985231","loc":[-85.637342,41.943734]},"n185985233":{"id":"n185985233","loc":[-85.637218,41.943703]},"n185985235":{"id":"n185985235","loc":[-85.637151,41.943663]},"n185985238":{"id":"n185985238","loc":[-85.637118,41.943615]},"n185985240":{"id":"n185985240","loc":[-85.637073,41.943494]},"n185990434":{"id":"n185990434","loc":[-85.6329028,41.9984292],"tags":{"railway":"level_crossing"}},"n1475284023":{"id":"n1475284023","loc":[-85.6336163,41.9435806],"tags":{"railway":"level_crossing"}},"n1475293222":{"id":"n1475293222","loc":[-85.6394045,41.953658],"tags":{"railway":"level_crossing"}},"n1475293226":{"id":"n1475293226","loc":[-85.6364975,41.9638663],"tags":{"railway":"level_crossing"}},"n1475293234":{"id":"n1475293234","loc":[-85.6390449,41.9565145]},"n1475293240":{"id":"n1475293240","loc":[-85.636943,41.9473114]},"n1475293252":{"id":"n1475293252","loc":[-85.6392115,41.9559003]},"n1475293254":{"id":"n1475293254","loc":[-85.6348931,41.9685127],"tags":{"railway":"level_crossing"}},"n1475293260":{"id":"n1475293260","loc":[-85.6375999,41.9485401]},"n1475293261":{"id":"n1475293261","loc":[-85.6391256,41.9523817],"tags":{"railway":"level_crossing"}},"n1475293264":{"id":"n1475293264","loc":[-85.6394155,41.9546493],"tags":{"railway":"level_crossing"}},"n1819805614":{"id":"n1819805614","loc":[-85.6345652,41.9363097]},"n1819805618":{"id":"n1819805618","loc":[-85.6295334,41.9426862]},"n1819805622":{"id":"n1819805622","loc":[-85.6308208,41.9430773]},"n1819805626":{"id":"n1819805626","loc":[-85.6274734,41.9406592]},"n1819805629":{"id":"n1819805629","loc":[-85.6296943,41.9430533]},"n1819805632":{"id":"n1819805632","loc":[-85.6340931,41.9354477]},"n1819805636":{"id":"n1819805636","loc":[-85.6304131,41.9436598]},"n1819805639":{"id":"n1819805639","loc":[-85.6304882,41.9426623]},"n1819805641":{"id":"n1819805641","loc":[-85.6336103,41.9367487]},"n1819805643":{"id":"n1819805643","loc":[-85.6300376,41.9418084]},"n1819805645":{"id":"n1819805645","loc":[-85.6365286,41.9336679]},"n1819805647":{"id":"n1819805647","loc":[-85.632016,41.9429221]},"n1819805666":{"id":"n1819805666","loc":[-85.6314753,41.9442663]},"n1819805669":{"id":"n1819805669","loc":[-85.6268619,41.9402203]},"n1819805673":{"id":"n1819805673","loc":[-85.6296728,41.9412099]},"n1819805676":{"id":"n1819805676","loc":[-85.6354557,41.932766]},"n1819805680":{"id":"n1819805680","loc":[-85.632752,41.9431012]},"n1819805683":{"id":"n1819805683","loc":[-85.631147,41.9432014]},"n1819805687":{"id":"n1819805687","loc":[-85.635284,41.9343942]},"n1819805690":{"id":"n1819805690","loc":[-85.6249736,41.9405794]},"n1819805694":{"id":"n1819805694","loc":[-85.6294153,41.9417925]},"n1819805698":{"id":"n1819805698","loc":[-85.6323486,41.9426986]},"n1819805702":{"id":"n1819805702","loc":[-85.6340287,41.9373871]},"n1819805707":{"id":"n1819805707","loc":[-85.6353698,41.9316326]},"n1819805711":{"id":"n1819805711","loc":[-85.6284176,41.940356]},"n1819805715":{"id":"n1819805715","loc":[-85.6291471,41.9412897]},"n1819805718":{"id":"n1819805718","loc":[-85.6311105,41.943979]},"n1819805722":{"id":"n1819805722","loc":[-85.6320868,41.9400128]},"n1819805724":{"id":"n1819805724","loc":[-85.635166,41.9324627]},"n1819805727":{"id":"n1819805727","loc":[-85.6344686,41.9350567]},"n1819805728":{"id":"n1819805728","loc":[-85.6357132,41.9332369]},"n1819805731":{"id":"n1819805731","loc":[-85.629984,41.9434444]},"n1819805760":{"id":"n1819805760","loc":[-85.6330996,41.9378784]},"n1819805766":{"id":"n1819805766","loc":[-85.625274,41.9411141]},"n1819805770":{"id":"n1819805770","loc":[-85.6326321,41.9412173]},"n1819805774":{"id":"n1819805774","loc":[-85.6347047,41.9312096]},"n1819805777":{"id":"n1819805777","loc":[-85.6363569,41.9339552]},"n1819805780":{"id":"n1819805780","loc":[-85.6327392,41.941926]},"n1819805783":{"id":"n1819805783","loc":[-85.6357239,41.9338435]},"n1819805786":{"id":"n1819805786","loc":[-85.6356595,41.9346576]},"n1819805789":{"id":"n1819805789","loc":[-85.6316469,41.9436598]},"n1819805792":{"id":"n1819805792","loc":[-85.6350587,41.9354557]},"n1819805795":{"id":"n1819805795","loc":[-85.6360028,41.9322791]},"n1819805798":{"id":"n1819805798","loc":[-85.63125,41.9443062]},"n1819805802":{"id":"n1819805802","loc":[-85.6263362,41.9408109]},"n1819805805":{"id":"n1819805805","loc":[-85.6315075,41.9438753]},"n1819805808":{"id":"n1819805808","loc":[-85.6340008,41.9316051]},"n1819805810":{"id":"n1819805810","loc":[-85.6345545,41.9320557]},"n1819805812":{"id":"n1819805812","loc":[-85.6250809,41.9408587]},"n1819805814":{"id":"n1819805814","loc":[-85.6257783,41.9400926]},"n1819805834":{"id":"n1819805834","loc":[-85.6326408,41.9424363]},"n1819805838":{"id":"n1819805838","loc":[-85.6365607,41.9334365]},"n1819805842":{"id":"n1819805842","loc":[-85.6288253,41.9410343]},"n1819805846":{"id":"n1819805846","loc":[-85.6279133,41.9402921]},"n1819805849":{"id":"n1819805849","loc":[-85.6289433,41.9405156]},"n1819805852":{"id":"n1819805852","loc":[-85.6313787,41.9439152]},"n1819805858":{"id":"n1819805858","loc":[-85.6300805,41.9420398]},"n1819805861":{"id":"n1819805861","loc":[-85.6321941,41.9396297]},"n1819805864":{"id":"n1819805864","loc":[-85.6329129,41.9393903]},"n1819805868":{"id":"n1819805868","loc":[-85.632001,41.9434922]},"n1819805870":{"id":"n1819805870","loc":[-85.6314903,41.9431535]},"n1819805873":{"id":"n1819805873","loc":[-85.6251667,41.9401166]},"n1819805876":{"id":"n1819805876","loc":[-85.63287,41.939941]},"n1819805878":{"id":"n1819805878","loc":[-85.6307886,41.9437317]},"n1819805880":{"id":"n1819805880","loc":[-85.6321727,41.940348]},"n1819805883":{"id":"n1819805883","loc":[-85.6265872,41.940113]},"n1819805885":{"id":"n1819805885","loc":[-85.6268404,41.9406672]},"n1819805887":{"id":"n1819805887","loc":[-85.6325267,41.9389035]},"n1819805889":{"id":"n1819805889","loc":[-85.6364964,41.933189]},"n1819805911":{"id":"n1819805911","loc":[-85.6248663,41.9401804]},"n1819805922":{"id":"n1819805922","loc":[-85.633267,41.9387199]},"n1819805925":{"id":"n1819805925","loc":[-85.6293402,41.9408428]},"n1819848849":{"id":"n1819848849","loc":[-85.6464957,41.9695178]},"n1819848850":{"id":"n1819848850","loc":[-85.6497642,41.9611355]},"n1819848851":{"id":"n1819848851","loc":[-85.6480943,41.9624818]},"n1819848854":{"id":"n1819848854","loc":[-85.6500362,41.9657367]},"n1819848855":{"id":"n1819848855","loc":[-85.6493673,41.9783496]},"n1819848856":{"id":"n1819848856","loc":[-85.6457409,41.9548007]},"n1819848857":{"id":"n1819848857","loc":[-85.651313,41.9760426]},"n1819848858":{"id":"n1819848858","loc":[-85.6495819,41.9784772]},"n1819848859":{"id":"n1819848859","loc":[-85.6495105,41.9833722]},"n1819848860":{"id":"n1819848860","loc":[-85.6405053,41.9492792]},"n1819848863":{"id":"n1819848863","loc":[-85.6502293,41.9786826]},"n1819848865":{"id":"n1819848865","loc":[-85.6406877,41.9495106]},"n1819848870":{"id":"n1819848870","loc":[-85.6493136,41.9704611]},"n1819848871":{"id":"n1819848871","loc":[-85.6372249,41.9441284]},"n1819848873":{"id":"n1819848873","loc":[-85.6512379,41.9659441]},"n1819848875":{"id":"n1819848875","loc":[-85.6508087,41.9650187]},"n1819848877":{"id":"n1819848877","loc":[-85.6487166,41.9605352]},"n1819848878":{"id":"n1819848878","loc":[-85.6506478,41.9760665]},"n1819848879":{"id":"n1819848879","loc":[-85.651431,41.9758512]},"n1819848886":{"id":"n1819848886","loc":[-85.6477617,41.9563945]},"n1819848889":{"id":"n1819848889","loc":[-85.6497895,41.9832286]},"n1819848892":{"id":"n1819848892","loc":[-85.6504868,41.9791931]},"n1819848893":{"id":"n1819848893","loc":[-85.6498002,41.9615085]},"n1819848894":{"id":"n1819848894","loc":[-85.6404302,41.9502846]},"n1819848901":{"id":"n1819848901","loc":[-85.6354412,41.9439886]},"n1819848903":{"id":"n1819848903","loc":[-85.6472145,41.9698528]},"n1819848904":{"id":"n1819848904","loc":[-85.6401979,41.9486233]},"n1819848905":{"id":"n1819848905","loc":[-85.6475042,41.963503]},"n1819848909":{"id":"n1819848909","loc":[-85.6343405,41.94358]},"n1819848914":{"id":"n1819848914","loc":[-85.6503474,41.9737773]},"n1819848915":{"id":"n1819848915","loc":[-85.6389533,41.9470992]},"n1819848916":{"id":"n1819848916","loc":[-85.6483625,41.9577907]},"n1819848917":{"id":"n1819848917","loc":[-85.6484768,41.9617419]},"n1819848918":{"id":"n1819848918","loc":[-85.644078,41.9545693]},"n1819848919":{"id":"n1819848919","loc":[-85.6437169,41.9543041]},"n1819848920":{"id":"n1819848920","loc":[-85.6478331,41.9627949]},"n1819848922":{"id":"n1819848922","loc":[-85.6499144,41.9785889]},"n1819848924":{"id":"n1819848924","loc":[-85.647633,41.9720066]},"n1819848926":{"id":"n1819848926","loc":[-85.6487987,41.978868]},"n1819848927":{"id":"n1819848927","loc":[-85.6495105,41.9730355]},"n1819848928":{"id":"n1819848928","loc":[-85.648223,41.9829654]},"n1819848929":{"id":"n1819848929","loc":[-85.6514846,41.9659122]},"n1819848931":{"id":"n1819848931","loc":[-85.6498753,41.9731871]},"n1819848932":{"id":"n1819848932","loc":[-85.640906,41.9508575]},"n1819848933":{"id":"n1819848933","loc":[-85.649775,41.9799767]},"n1819848934":{"id":"n1819848934","loc":[-85.6507014,41.9739927]},"n1819848937":{"id":"n1819848937","loc":[-85.6479763,41.9840899]},"n1819848938":{"id":"n1819848938","loc":[-85.6501113,41.9600884]},"n1819848939":{"id":"n1819848939","loc":[-85.6389962,41.9478253]},"n1819848941":{"id":"n1819848941","loc":[-85.637469,41.9445791]},"n1819848942":{"id":"n1819848942","loc":[-85.6494569,41.9601682]},"n1819848943":{"id":"n1819848943","loc":[-85.6368803,41.9439351]},"n1819848945":{"id":"n1819848945","loc":[-85.6474398,41.9724213]},"n1819848946":{"id":"n1819848946","loc":[-85.6382629,41.9463666]},"n1819848948":{"id":"n1819848948","loc":[-85.6489633,41.9830771]},"n1819848952":{"id":"n1819848952","loc":[-85.6488882,41.9600326]},"n1819848953":{"id":"n1819848953","loc":[-85.6488094,41.9774324]},"n1819848954":{"id":"n1819848954","loc":[-85.6491135,41.9600485]},"n1819848955":{"id":"n1819848955","loc":[-85.6501435,41.9734583]},"n1819848956":{"id":"n1819848956","loc":[-85.6495534,41.960958]},"n1819848958":{"id":"n1819848958","loc":[-85.6474683,41.9561491]},"n1819848959":{"id":"n1819848959","loc":[-85.6401083,41.9485451]},"n1819848960":{"id":"n1819848960","loc":[-85.6481764,41.9678686]},"n1819848961":{"id":"n1819848961","loc":[-85.6484017,41.967382]},"n1819848962":{"id":"n1819848962","loc":[-85.6501328,41.959897]},"n1819848964":{"id":"n1819848964","loc":[-85.6403695,41.9504586]},"n1819848966":{"id":"n1819848966","loc":[-85.6398975,41.9491499]},"n1819848967":{"id":"n1819848967","loc":[-85.6412455,41.9510187]},"n1819848968":{"id":"n1819848968","loc":[-85.6482622,41.9619493]},"n1819848969":{"id":"n1819848969","loc":[-85.6405841,41.9501474]},"n1819848970":{"id":"n1819848970","loc":[-85.6478583,41.9703394]},"n1819848971":{"id":"n1819848971","loc":[-85.6493388,41.9832845]},"n1819848972":{"id":"n1819848972","loc":[-85.6485664,41.9829415]},"n1819848974":{"id":"n1819848974","loc":[-85.6491457,41.9779887]},"n1819848975":{"id":"n1819848975","loc":[-85.6468889,41.9697033]},"n1819848976":{"id":"n1819848976","loc":[-85.6452726,41.9546072]},"n1819848977":{"id":"n1819848977","loc":[-85.6448435,41.9546072]},"n1819848979":{"id":"n1819848979","loc":[-85.6485342,41.9763138]},"n1819848980":{"id":"n1819848980","loc":[-85.6495282,41.9664087]},"n1819848986":{"id":"n1819848986","loc":[-85.6486307,41.9603278]},"n1819848987":{"id":"n1819848987","loc":[-85.6492278,41.9791871]},"n1819848990":{"id":"n1819848990","loc":[-85.6501934,41.9800724]},"n1819848992":{"id":"n1819848992","loc":[-85.6482445,41.9819685]},"n1819848993":{"id":"n1819848993","loc":[-85.6481871,41.9704451]},"n1819848994":{"id":"n1819848994","loc":[-85.6371364,41.9457602]},"n1819848996":{"id":"n1819848996","loc":[-85.6500362,41.9801023]},"n1819849000":{"id":"n1819849000","loc":[-85.639007,41.9485914]},"n1819849001":{"id":"n1819849001","loc":[-85.6488882,41.9669253]},"n1819849002":{"id":"n1819849002","loc":[-85.6484698,41.9565062]},"n1819849004":{"id":"n1819849004","loc":[-85.6510769,41.9761064]},"n1819849005":{"id":"n1819849005","loc":[-85.6503581,41.9799029]},"n1819849006":{"id":"n1819849006","loc":[-85.6489381,41.9703893]},"n1819849008":{"id":"n1819849008","loc":[-85.6497457,41.9833588]},"n1819849011":{"id":"n1819849011","loc":[-85.6497358,41.9717593]},"n1819849012":{"id":"n1819849012","loc":[-85.6494676,41.9796796]},"n1819849019":{"id":"n1819849019","loc":[-85.6486093,41.9771034]},"n1819849021":{"id":"n1819849021","loc":[-85.6504546,41.9796556]},"n1819849022":{"id":"n1819849022","loc":[-85.6371294,41.9454154]},"n1819849023":{"id":"n1819849023","loc":[-85.6503436,41.9759249]},"n1819849025":{"id":"n1819849025","loc":[-85.6462382,41.9693822]},"n1819849026":{"id":"n1819849026","loc":[-85.6497573,41.983093]},"n1819849028":{"id":"n1819849028","loc":[-85.6497465,41.9602799]},"n1819849029":{"id":"n1819849029","loc":[-85.6374728,41.9460698]},"n1819849030":{"id":"n1819849030","loc":[-85.6486592,41.9566039]},"n1819849031":{"id":"n1819849031","loc":[-85.6515989,41.9654993]},"n1819849032":{"id":"n1819849032","loc":[-85.6387028,41.9482658]},"n1819849033":{"id":"n1819849033","loc":[-85.6464742,41.9688398]},"n1819849034":{"id":"n1819849034","loc":[-85.6495212,41.9589236]},"n1819849035":{"id":"n1819849035","loc":[-85.6490599,41.9790096]},"n1819849036":{"id":"n1819849036","loc":[-85.6489918,41.9800724]},"n1819849038":{"id":"n1819849038","loc":[-85.6499182,41.9659042]},"n1819849040":{"id":"n1819849040","loc":[-85.639758,41.9490143]},"n1819849041":{"id":"n1819849041","loc":[-85.6514846,41.9755241]},"n1819849042":{"id":"n1819849042","loc":[-85.6436633,41.9540647]},"n1819849045":{"id":"n1819849045","loc":[-85.6475541,41.9726387]},"n1819849046":{"id":"n1819849046","loc":[-85.6488308,41.9718331]},"n1819849047":{"id":"n1819849047","loc":[-85.6377694,41.9460953]},"n1819849048":{"id":"n1819849048","loc":[-85.6490706,41.9804452]},"n1819849049":{"id":"n1819849049","loc":[-85.6485449,41.9766248]},"n1819849051":{"id":"n1819849051","loc":[-85.6483625,41.9790256]},"n1819849052":{"id":"n1819849052","loc":[-85.6490706,41.9585167]},"n1819849053":{"id":"n1819849053","loc":[-85.6425008,41.9522874]},"n1819849054":{"id":"n1819849054","loc":[-85.6475793,41.9632158]},"n1819849055":{"id":"n1819849055","loc":[-85.6408631,41.9499399]},"n1819849056":{"id":"n1819849056","loc":[-85.6483373,41.9814681]},"n1819849057":{"id":"n1819849057","loc":[-85.6313548,41.9442876]},"n1819849058":{"id":"n1819849058","loc":[-85.6432663,41.9529796]},"n1819849059":{"id":"n1819849059","loc":[-85.6487128,41.9582873]},"n1819849060":{"id":"n1819849060","loc":[-85.6482338,41.9817612]},"n1819849062":{"id":"n1819849062","loc":[-85.6485664,41.9788661]},"n1819849063":{"id":"n1819849063","loc":[-85.6373081,41.9448824]},"n1819849064":{"id":"n1819849064","loc":[-85.6472215,41.9557582]},"n1819849065":{"id":"n1819849065","loc":[-85.6348984,41.9440414]},"n1819849066":{"id":"n1819849066","loc":[-85.6501972,41.9647315]},"n1819849067":{"id":"n1819849067","loc":[-85.6489741,41.9808281]},"n1819849068":{"id":"n1819849068","loc":[-85.6420111,41.9515034]},"n1819849069":{"id":"n1819849069","loc":[-85.6397972,41.9488882]},"n1819849070":{"id":"n1819849070","loc":[-85.6499718,41.9593465]},"n1819849071":{"id":"n1819849071","loc":[-85.6486844,41.9811311]},"n1819849072":{"id":"n1819849072","loc":[-85.6390392,41.9474663]},"n1819849074":{"id":"n1819849074","loc":[-85.6495642,41.9616362]},"n1819849075":{"id":"n1819849075","loc":[-85.6483518,41.9791931]},"n1819849076":{"id":"n1819849076","loc":[-85.6478974,41.9833104]},"n1819849077":{"id":"n1819849077","loc":[-85.640155,41.948719]},"n1819849078":{"id":"n1819849078","loc":[-85.6399366,41.9487845]},"n1819849079":{"id":"n1819849079","loc":[-85.6492959,41.9825348]},"n1819849080":{"id":"n1819849080","loc":[-85.6505083,41.9648352]},"n1819849081":{"id":"n1819849081","loc":[-85.6492959,41.9645241]},"n1819849082":{"id":"n1819849082","loc":[-85.6402049,41.9491835]},"n1819849083":{"id":"n1819849083","loc":[-85.6495175,41.9826963]},"n1819849084":{"id":"n1819849084","loc":[-85.6480836,41.9728361]},"n1819849085":{"id":"n1819849085","loc":[-85.6374349,41.9443425]},"n1819849086":{"id":"n1819849086","loc":[-85.6478331,41.9681238]},"n1819849089":{"id":"n1819849089","loc":[-85.639368,41.9486169]},"n1819849092":{"id":"n1819849092","loc":[-85.6503581,41.9788022]},"n1819849093":{"id":"n1819849093","loc":[-85.64862,41.9568014]},"n1819849094":{"id":"n1819849094","loc":[-85.6496999,41.9828877]},"n1819849095":{"id":"n1819849095","loc":[-85.647472,41.972198]},"n1819849096":{"id":"n1819849096","loc":[-85.6485771,41.9644523]},"n1819849097":{"id":"n1819849097","loc":[-85.6388353,41.9480488]},"n1819849099":{"id":"n1819849099","loc":[-85.6472752,41.9683312]},"n1819849104":{"id":"n1819849104","loc":[-85.6479548,41.9836035]},"n1819849105":{"id":"n1819849105","loc":[-85.6462489,41.9691668]},"n1819849107":{"id":"n1819849107","loc":[-85.6511912,41.9746328]},"n1819849108":{"id":"n1819849108","loc":[-85.6498646,41.9714881]},"n1819849111":{"id":"n1819849111","loc":[-85.6488239,41.961684]},"n1819849112":{"id":"n1819849112","loc":[-85.6469356,41.9553812]},"n1819849114":{"id":"n1819849114","loc":[-85.6479548,41.9640853]},"n1819849119":{"id":"n1819849119","loc":[-85.6491565,41.961692]},"n1819849121":{"id":"n1819849121","loc":[-85.651667,41.9656728]},"n1819849124":{"id":"n1819849124","loc":[-85.6388423,41.9484414]},"n1819849126":{"id":"n1819849126","loc":[-85.6371686,41.9450978]},"n1819849127":{"id":"n1819849127","loc":[-85.6502615,41.9656728]},"n1819849129":{"id":"n1819849129","loc":[-85.6498501,41.9613031]},"n1819849131":{"id":"n1819849131","loc":[-85.6513881,41.9653298]},"n1819849133":{"id":"n1819849133","loc":[-85.639883,41.9485291]},"n1819849139":{"id":"n1819849139","loc":[-85.6508693,41.9658264]},"n1819849140":{"id":"n1819849140","loc":[-85.6486806,41.9761642]},"n1819849141":{"id":"n1819849141","loc":[-85.6483159,41.9717613]},"n1819849144":{"id":"n1819849144","loc":[-85.6443714,41.9546232]},"n1819849146":{"id":"n1819849146","loc":[-85.641775,41.9513359]},"n1819849147":{"id":"n1819849147","loc":[-85.6495604,41.9757335]},"n1819849148":{"id":"n1819849148","loc":[-85.6465671,41.9551678]},"n1819849150":{"id":"n1819849150","loc":[-85.6485127,41.9794084]},"n1819849151":{"id":"n1819849151","loc":[-85.6499144,41.9757096]},"n1819849152":{"id":"n1819849152","loc":[-85.6433736,41.9531072]},"n1819849154":{"id":"n1819849154","loc":[-85.6489741,41.9607426]},"n1819849155":{"id":"n1819849155","loc":[-85.640627,41.9507697]},"n1819849156":{"id":"n1819849156","loc":[-85.6509659,41.9743058]},"n1819849157":{"id":"n1819849157","loc":[-85.6486844,41.9704431]},"n1819849158":{"id":"n1819849158","loc":[-85.6498538,41.9711132]},"n1819849159":{"id":"n1819849159","loc":[-85.6358937,41.943719]},"n1819849160":{"id":"n1819849160","loc":[-85.6497358,41.9707702]},"n1819849161":{"id":"n1819849161","loc":[-85.6480476,41.9564842]},"n1819849162":{"id":"n1819849162","loc":[-85.6482982,41.9574556]},"n1819849163":{"id":"n1819849163","loc":[-85.6501757,41.9757794]},"n1819849164":{"id":"n1819849164","loc":[-85.6372973,41.9459916]},"n1819849165":{"id":"n1819849165","loc":[-85.6513773,41.9750775]},"n1819849166":{"id":"n1819849166","loc":[-85.6436418,41.9537455]},"n1819849167":{"id":"n1819849167","loc":[-85.6483625,41.9571524]},"n1819849169":{"id":"n1819849169","loc":[-85.647751,41.9727962]},"n1819849170":{"id":"n1819849170","loc":[-85.6504546,41.9656808]},"n1819849171":{"id":"n1819849171","loc":[-85.6479977,41.971839]},"n1819849172":{"id":"n1819849172","loc":[-85.6482767,41.9642449]},"n1819849174":{"id":"n1819849174","loc":[-85.6414317,41.9512086]},"n1819849176":{"id":"n1819849176","loc":[-85.6469034,41.9685287]},"n1819849179":{"id":"n1819849179","loc":[-85.6408631,41.9497564]},"n1819849182":{"id":"n1819849182","loc":[-85.6476721,41.96384]},"n1819849183":{"id":"n1819849183","loc":[-85.6479725,41.983111]},"n1819849184":{"id":"n1819849184","loc":[-85.640788,41.9500516]},"n1819849185":{"id":"n1819849185","loc":[-85.6427798,41.9528778]},"n1819849186":{"id":"n1819849186","loc":[-85.6435308,41.9534124]},"n1819849187":{"id":"n1819849187","loc":[-85.6483733,41.9821998]},"n1819849189":{"id":"n1819849189","loc":[-85.6351752,41.9440796]},"n1819849191":{"id":"n1819849191","loc":[-85.6487021,41.9601463]},"n1819849192":{"id":"n1819849192","loc":[-85.6363811,41.9437605]},"n1819849193":{"id":"n1819849193","loc":[-85.6490883,41.9759728]},"n1819849194":{"id":"n1819849194","loc":[-85.6423292,41.9520081]},"n1819849195":{"id":"n1819849195","loc":[-85.6500003,41.960242]},"n1819849196":{"id":"n1819849196","loc":[-85.6385778,41.9466443]},"n1819849197":{"id":"n1819849197","loc":[-85.6494032,41.9718789]},"n1819849198":{"id":"n1819849198","loc":[-85.6404339,41.9506501]},"n1819849199":{"id":"n1819849199","loc":[-85.6426226,41.9527083]},"n1819849200":{"id":"n1819849200","loc":[-85.6439101,41.9545035]},"n1819849201":{"id":"n1819849201","loc":[-85.6516563,41.9657845]},"n1819849202":{"id":"n1819849202","loc":[-85.6473395,41.9699585]},"n1819858501":{"id":"n1819858501","loc":[-85.6361263,41.9437126]},"n1819858503":{"id":"n1819858503","loc":[-85.6350068,41.944034]},"n1819858513":{"id":"n1819858513","loc":[-85.6371402,41.9453282]},"n1819858518":{"id":"n1819858518","loc":[-85.6348713,41.9432923]},"n1819858523":{"id":"n1819858523","loc":[-85.6357047,41.943799]},"n1819858526":{"id":"n1819858526","loc":[-85.6349947,41.9435756]},"n1819858531":{"id":"n1819858531","loc":[-85.6350376,41.943827]},"n1820937508":{"id":"n1820937508","loc":[-85.1026013,42.0881722]},"n1820937509":{"id":"n1820937509","loc":[-85.0558088,42.102493]},"n1820937511":{"id":"n1820937511","loc":[-85.3030116,41.9724451]},"n1820937513":{"id":"n1820937513","loc":[-85.0353221,42.1027398]},"n1820937514":{"id":"n1820937514","loc":[-85.0835468,42.1015469]},"n1820937515":{"id":"n1820937515","loc":[-85.2421298,42.0106305]},"n1820937517":{"id":"n1820937517","loc":[-85.0090632,42.0910452]},"n1820937518":{"id":"n1820937518","loc":[-85.086626,42.0948838]},"n1820937520":{"id":"n1820937520","loc":[-85.2552039,42.0015448]},"n1820937521":{"id":"n1820937521","loc":[-85.3739614,41.9969917]},"n1820937522":{"id":"n1820937522","loc":[-85.4831166,41.993898]},"n1820937523":{"id":"n1820937523","loc":[-85.0341084,42.0977657]},"n1820937524":{"id":"n1820937524","loc":[-85.3272802,41.9710333]},"n1820937525":{"id":"n1820937525","loc":[-85.2125568,42.0414521]},"n1820937526":{"id":"n1820937526","loc":[-85.3798022,41.9992458]},"n1820937527":{"id":"n1820937527","loc":[-85.2652021,41.999768]},"n1820937528":{"id":"n1820937528","loc":[-85.3852739,42.0004896]},"n1820937529":{"id":"n1820937529","loc":[-85.3911919,42.0030513]},"n1820937530":{"id":"n1820937530","loc":[-85.5440349,41.9717109]},"n1820937531":{"id":"n1820937531","loc":[-85.2790155,41.9911764]},"n1820937532":{"id":"n1820937532","loc":[-85.4723277,41.9950518]},"n1820937533":{"id":"n1820937533","loc":[-85.5690546,41.9653931]},"n1820937535":{"id":"n1820937535","loc":[-85.5674882,41.9649623]},"n1820937536":{"id":"n1820937536","loc":[-85.6362815,41.9189165]},"n1820937537":{"id":"n1820937537","loc":[-85.5659003,41.963638]},"n1820937539":{"id":"n1820937539","loc":[-85.6391353,41.9122262]},"n1820937540":{"id":"n1820937540","loc":[-85.4834385,41.9894803]},"n1820937541":{"id":"n1820937541","loc":[-85.6399078,41.9160744]},"n1820937542":{"id":"n1820937542","loc":[-85.632874,41.941031]},"n1820937543":{"id":"n1820937543","loc":[-85.1307591,42.0726961]},"n1820937544":{"id":"n1820937544","loc":[-85.6444397,41.9128378]},"n1820937545":{"id":"n1820937545","loc":[-85.6197204,41.9420365]},"n1820937546":{"id":"n1820937546","loc":[-85.1164857,42.0864631]},"n1820937547":{"id":"n1820937547","loc":[-85.6476111,41.9142222]},"n1820937548":{"id":"n1820937548","loc":[-85.2915747,41.9774223]},"n1820937549":{"id":"n1820937549","loc":[-85.6430192,41.9102461]},"n1820937550":{"id":"n1820937550","loc":[-85.1597495,42.0639017]},"n1820937551":{"id":"n1820937551","loc":[-85.5504079,41.9701793]},"n1820937553":{"id":"n1820937553","loc":[-85.2781317,41.9948951]},"n1820937555":{"id":"n1820937555","loc":[-85.3724594,41.997518]},"n1820937556":{"id":"n1820937556","loc":[-85.5629434,41.9665155]},"n1820937557":{"id":"n1820937557","loc":[-85.3791971,41.9990808]},"n1820937558":{"id":"n1820937558","loc":[-85.001891,42.0878843]},"n1820937560":{"id":"n1820937560","loc":[-85.3140838,41.9709056]},"n1820937561":{"id":"n1820937561","loc":[-85.2468032,42.0146987]},"n1820937563":{"id":"n1820937563","loc":[-85.0877378,42.097255]},"n1820937564":{"id":"n1820937564","loc":[-85.2442498,42.0150654]},"n1820937566":{"id":"n1820937566","loc":[-85.3108973,41.9701478]},"n1820937568":{"id":"n1820937568","loc":[-85.0344584,42.1016572]},"n1820937569":{"id":"n1820937569","loc":[-85.2331025,42.0297387]},"n1820937570":{"id":"n1820937570","loc":[-85.5058446,41.9746996]},"n1820937571":{"id":"n1820937571","loc":[-85.5622739,41.9676427]},"n1820937572":{"id":"n1820937572","loc":[-85.2792687,41.9890337]},"n1820937574":{"id":"n1820937574","loc":[-84.9909302,42.08695]},"n1820937575":{"id":"n1820937575","loc":[-85.6218233,41.9418609]},"n1820937576":{"id":"n1820937576","loc":[-85.3577437,41.9931062]},"n1820937577":{"id":"n1820937577","loc":[-85.639028,41.9165853]},"n1820937578":{"id":"n1820937578","loc":[-84.9956576,42.0865348]},"n1820937579":{"id":"n1820937579","loc":[-85.4828376,41.990198]},"n1820937580":{"id":"n1820937580","loc":[-85.3244478,41.9720543]},"n1820937582":{"id":"n1820937582","loc":[-85.0517479,42.1035159]},"n1820937583":{"id":"n1820937583","loc":[-85.225646,42.0338025]},"n1820937584":{"id":"n1820937584","loc":[-84.9941019,42.0862163]},"n1820937586":{"id":"n1820937586","loc":[-85.1051762,42.0879452]},"n1820937587":{"id":"n1820937587","loc":[-85.1245203,42.0753162]},"n1820937588":{"id":"n1820937588","loc":[-85.3250808,41.9719506]},"n1820937589":{"id":"n1820937589","loc":[-85.2720109,41.997933]},"n1820937590":{"id":"n1820937590","loc":[-85.2556653,42.0027248]},"n1820937591":{"id":"n1820937591","loc":[-85.0872483,42.0943544]},"n1820937592":{"id":"n1820937592","loc":[-85.2778353,41.9955023]},"n1820937593":{"id":"n1820937593","loc":[-85.2984733,41.9735538]},"n1820937594":{"id":"n1820937594","loc":[-85.101578,42.0889552]},"n1820937595":{"id":"n1820937595","loc":[-85.3888745,42.0016959]},"n1820937596":{"id":"n1820937596","loc":[-84.9903508,42.0870654]},"n1820937597":{"id":"n1820937597","loc":[-85.6405558,41.9146261]},"n1820937598":{"id":"n1820937598","loc":[-85.6460704,41.9141311]},"n1820937599":{"id":"n1820937599","loc":[-85.0377468,42.1037428]},"n1820937600":{"id":"n1820937600","loc":[-85.2298345,42.0312899]},"n1820937601":{"id":"n1820937601","loc":[-85.1080958,42.0861964]},"n1820937602":{"id":"n1820937602","loc":[-85.6325307,41.9402329]},"n1820937603":{"id":"n1820937603","loc":[-85.1165984,42.0832184]},"n1820937604":{"id":"n1820937604","loc":[-85.6354446,41.9190602]},"n1820937605":{"id":"n1820937605","loc":[-85.1114592,42.0862959]},"n1820937606":{"id":"n1820937606","loc":[-85.0858763,42.1001646]},"n1820937607":{"id":"n1820937607","loc":[-85.0472083,42.1015151]},"n1820937608":{"id":"n1820937608","loc":[-85.0802477,42.1027609]},"n1820937610":{"id":"n1820937610","loc":[-85.0924585,42.0928564]},"n1820937611":{"id":"n1820937611","loc":[-85.0329617,42.09827]},"n1820937612":{"id":"n1820937612","loc":[-85.2814617,41.993465]},"n1820937613":{"id":"n1820937613","loc":[-85.3097708,41.9700282]},"n1820937614":{"id":"n1820937614","loc":[-85.2809427,41.993695]},"n1820937615":{"id":"n1820937615","loc":[-85.0583233,42.1026494]},"n1820937617":{"id":"n1820937617","loc":[-85.2801592,41.9840021]},"n1820937619":{"id":"n1820937619","loc":[-85.1064154,42.0863449]},"n1820937620":{"id":"n1820937620","loc":[-85.0423173,42.1014662]},"n1820937621":{"id":"n1820937621","loc":[-85.2168913,42.0398107]},"n1820937622":{"id":"n1820937622","loc":[-85.2798481,41.9833401]},"n1820937623":{"id":"n1820937623","loc":[-85.0575468,42.1028672]},"n1820937625":{"id":"n1820937625","loc":[-85.0130369,42.0893067]},"n1820937626":{"id":"n1820937626","loc":[-85.0346985,42.1018256]},"n1820937627":{"id":"n1820937627","loc":[-85.2231569,42.0372768]},"n1820937628":{"id":"n1820937628","loc":[-85.2956195,41.9732268]},"n1820937629":{"id":"n1820937629","loc":[-85.1052312,42.086893]},"n1820937630":{"id":"n1820937630","loc":[-85.4813356,41.9958436]},"n1820937631":{"id":"n1820937631","loc":[-85.0961599,42.0914672]},"n1820937632":{"id":"n1820937632","loc":[-85.308419,41.9704749]},"n1820937633":{"id":"n1820937633","loc":[-85.295952,41.9715119]},"n1820937634":{"id":"n1820937634","loc":[-85.3310933,41.9703923]},"n1820937635":{"id":"n1820937635","loc":[-85.2940745,41.9739686]},"n1820937636":{"id":"n1820937636","loc":[-85.3803343,42.000484]},"n1820937637":{"id":"n1820937637","loc":[-85.1174231,42.0845533]},"n1820937638":{"id":"n1820937638","loc":[-85.0095836,42.089839]},"n1820937639":{"id":"n1820937639","loc":[-85.3179354,41.9705866]},"n1820937640":{"id":"n1820937640","loc":[-85.257708,42.0001189]},"n1820937641":{"id":"n1820937641","loc":[-85.2563522,42.0002771]},"n1820937642":{"id":"n1820937642","loc":[-85.3181929,41.970419]},"n1820937643":{"id":"n1820937643","loc":[-85.2911884,41.9757154]},"n1820937644":{"id":"n1820937644","loc":[-85.2714423,41.9975862]},"n1820937645":{"id":"n1820937645","loc":[-85.0193669,42.089888]},"n1820937646":{"id":"n1820937646","loc":[-85.3889818,42.0039921]},"n1820937647":{"id":"n1820937647","loc":[-85.3408093,41.9853965]},"n1820937648":{"id":"n1820937648","loc":[-85.1258091,42.0748332]},"n1820937649":{"id":"n1820937649","loc":[-85.5722561,41.962782]},"n1820937650":{"id":"n1820937650","loc":[-85.3266902,41.9721819]},"n1820937651":{"id":"n1820937651","loc":[-85.1473255,42.065192]},"n1820937652":{"id":"n1820937652","loc":[-85.1462526,42.0655106]},"n1820937653":{"id":"n1820937653","loc":[-85.4641051,42.0013929]},"n1820937654":{"id":"n1820937654","loc":[-85.5620379,41.9700677]},"n1820937655":{"id":"n1820937655","loc":[-85.3226025,41.971121]},"n1820937656":{"id":"n1820937656","loc":[-85.0200965,42.0899516]},"n1820937657":{"id":"n1820937657","loc":[-85.0624714,42.1044711]},"n1820937658":{"id":"n1820937658","loc":[-85.5649562,41.9637178]},"n1820937659":{"id":"n1820937659","loc":[-85.2360315,42.0253315]},"n1820937660":{"id":"n1820937660","loc":[-85.3881449,41.9994475]},"n1820937661":{"id":"n1820937661","loc":[-85.5032911,41.976263]},"n1820937662":{"id":"n1820937662","loc":[-85.481297,41.9871414]},"n1820937663":{"id":"n1820937663","loc":[-85.1167056,42.0841898]},"n1820937664":{"id":"n1820937664","loc":[-85.2891714,41.9787223]},"n1820937665":{"id":"n1820937665","loc":[-85.4393429,42.0058736]},"n1820937666":{"id":"n1820937666","loc":[-85.0077007,42.0895762]},"n1820937667":{"id":"n1820937667","loc":[-85.2736202,41.9979171]},"n1820937668":{"id":"n1820937668","loc":[-84.9935332,42.0859296]},"n1820937669":{"id":"n1820937669","loc":[-85.0622769,42.1046713]},"n1820937670":{"id":"n1820937670","loc":[-85.2309031,42.0311249]},"n1820937671":{"id":"n1820937671","loc":[-85.0343726,42.10069]},"n1820937672":{"id":"n1820937672","loc":[-85.0596551,42.1048612]},"n1820937673":{"id":"n1820937673","loc":[-85.1338597,42.0707449]},"n1820937674":{"id":"n1820937674","loc":[-85.3117663,41.9689194]},"n1820937675":{"id":"n1820937675","loc":[-85.0705649,42.1057499]},"n1820937676":{"id":"n1820937676","loc":[-85.2441425,42.0180944]},"n1820937677":{"id":"n1820937677","loc":[-85.1171174,42.0862692]},"n1820937678":{"id":"n1820937678","loc":[-85.0346824,42.1005519]},"n1820937680":{"id":"n1820937680","loc":[-85.2389927,42.0229245]},"n1820937681":{"id":"n1820937681","loc":[-85.0834892,42.1018642]},"n1820937682":{"id":"n1820937682","loc":[-85.0619443,42.1049459]},"n1820937683":{"id":"n1820937683","loc":[-85.2845366,41.9811868]},"n1820937684":{"id":"n1820937684","loc":[-85.210411,42.0394123]},"n1820937685":{"id":"n1820937685","loc":[-85.4377383,42.0055942]},"n1820937686":{"id":"n1820937686","loc":[-85.2882058,41.9789138]},"n1820937687":{"id":"n1820937687","loc":[-85.2741191,41.9955808]},"n1820937688":{"id":"n1820937688","loc":[-85.3442211,41.9903575]},"n1820937689":{"id":"n1820937689","loc":[-85.2641413,41.9995237]},"n1820937690":{"id":"n1820937690","loc":[-85.2804489,41.9829174]},"n1820937691":{"id":"n1820937691","loc":[-85.5593342,41.9729074]},"n1820937692":{"id":"n1820937692","loc":[-85.3590912,41.9932601]},"n1820937694":{"id":"n1820937694","loc":[-85.4826445,41.9957479]},"n1820937695":{"id":"n1820937695","loc":[-85.4539127,42.0063041]},"n1820937696":{"id":"n1820937696","loc":[-85.2456767,42.0153683]},"n1820937697":{"id":"n1820937697","loc":[-85.5794015,41.9489631]},"n1820937698":{"id":"n1820937698","loc":[-85.4108686,42.0078507]},"n1820937699":{"id":"n1820937699","loc":[-85.0616386,42.1051529]},"n1820937700":{"id":"n1820937700","loc":[-85.4977979,41.978241]},"n1820937701":{"id":"n1820937701","loc":[-85.2488417,42.0086319]},"n1820937702":{"id":"n1820937702","loc":[-85.5588836,41.9728116]},"n1820937703":{"id":"n1820937703","loc":[-85.4557366,42.0051241]},"n1820937705":{"id":"n1820937705","loc":[-85.0723151,42.1056094]},"n1820937706":{"id":"n1820937706","loc":[-85.0057909,42.0887323]},"n1820937707":{"id":"n1820937707","loc":[-85.0756786,42.105677]},"n1820937708":{"id":"n1820937708","loc":[-85.0901504,42.0940001]},"n1820937709":{"id":"n1820937709","loc":[-85.0979999,42.0910213]},"n1820937710":{"id":"n1820937710","loc":[-85.2376301,42.0239686]},"n1820937711":{"id":"n1820937711","loc":[-85.2780671,41.9902299]},"n1820937712":{"id":"n1820937712","loc":[-85.251481,42.0113188]},"n1820937713":{"id":"n1820937713","loc":[-85.3114767,41.9690311]},"n1820937714":{"id":"n1820937714","loc":[-85.2649621,41.9975662]},"n1820937715":{"id":"n1820937715","loc":[-85.283807,41.9813383]},"n1820937716":{"id":"n1820937716","loc":[-85.5515451,41.9703867]},"n1820937717":{"id":"n1820937717","loc":[-85.1176605,42.0850896]},"n1820937718":{"id":"n1820937718","loc":[-85.1069317,42.0862441]},"n1820937719":{"id":"n1820937719","loc":[-85.2739314,41.9976938]},"n1820937720":{"id":"n1820937720","loc":[-85.5550212,41.9702112]},"n1820937721":{"id":"n1820937721","loc":[-85.3076679,41.9719904]},"n1820937722":{"id":"n1820937722","loc":[-85.592319,41.9440316]},"n1820937723":{"id":"n1820937723","loc":[-85.3139979,41.9704031]},"n1820937724":{"id":"n1820937724","loc":[-85.0421134,42.1013149]},"n1820937725":{"id":"n1820937725","loc":[-85.2508373,42.0102741]},"n1820937726":{"id":"n1820937726","loc":[-85.0830922,42.1038821]},"n1820937727":{"id":"n1820937727","loc":[-85.6342473,41.9360031]},"n1820937730":{"id":"n1820937730","loc":[-85.0500192,42.1024942]},"n1820937731":{"id":"n1820937731","loc":[-85.3498644,41.9926221]},"n1820937732":{"id":"n1820937732","loc":[-85.0234117,42.0918903]},"n1820937733":{"id":"n1820937733","loc":[-85.0464425,42.1009408]},"n1820937734":{"id":"n1820937734","loc":[-85.033938,42.099886]},"n1820937736":{"id":"n1820937736","loc":[-85.0152752,42.0886009]},"n1820937737":{"id":"n1820937737","loc":[-85.0441894,42.1012671]},"n1820937738":{"id":"n1820937738","loc":[-85.4668731,41.9979804]},"n1820937739":{"id":"n1820937739","loc":[-85.4407377,42.006033]},"n1820937740":{"id":"n1820937740","loc":[-85.2262253,42.0344878]},"n1820937741":{"id":"n1820937741","loc":[-85.2550001,42.0033706]},"n1820937742":{"id":"n1820937742","loc":[-85.3071422,41.9722617]},"n1820937743":{"id":"n1820937743","loc":[-85.6147852,41.942228]},"n1820937744":{"id":"n1820937744","loc":[-85.0183853,42.0901825]},"n1820937745":{"id":"n1820937745","loc":[-85.6323161,41.9228489]},"n1820937746":{"id":"n1820937746","loc":[-85.0095568,42.0901376]},"n1820937747":{"id":"n1820937747","loc":[-85.2524037,42.0113826]},"n1820937748":{"id":"n1820937748","loc":[-85.3186864,41.9708578]},"n1820937749":{"id":"n1820937749","loc":[-85.2805669,41.9870883]},"n1820937750":{"id":"n1820937750","loc":[-85.0585768,42.1038144]},"n1820937751":{"id":"n1820937751","loc":[-85.2970786,41.9715358]},"n1820937752":{"id":"n1820937752","loc":[-85.1315758,42.0723445]},"n1820937753":{"id":"n1820937753","loc":[-85.2448291,42.0175444]},"n1820937754":{"id":"n1820937754","loc":[-85.2446468,42.0174248]},"n1820937755":{"id":"n1820937755","loc":[-85.229165,42.032129]},"n1820937756":{"id":"n1820937756","loc":[-85.5612654,41.9724926]},"n1820937757":{"id":"n1820937757","loc":[-85.2331776,42.030854]},"n1820937758":{"id":"n1820937758","loc":[-85.2271909,42.0334519]},"n1820937759":{"id":"n1820937759","loc":[-85.1032396,42.0879214]},"n1820937760":{"id":"n1820937760","loc":[-85.0638447,42.1044154]},"n1820937761":{"id":"n1820937761","loc":[-85.1260706,42.0745556]},"n1820937762":{"id":"n1820937762","loc":[-85.3454485,41.99132]},"n1820937763":{"id":"n1820937763","loc":[-85.2639321,41.9980088]},"n1820937764":{"id":"n1820937764","loc":[-85.0837681,42.1013746]},"n1820937765":{"id":"n1820937765","loc":[-85.2808137,41.9869368]},"n1820937766":{"id":"n1820937766","loc":[-85.6338997,41.9309373]},"n1820937767":{"id":"n1820937767","loc":[-85.2267403,42.0332766]},"n1820937768":{"id":"n1820937768","loc":[-85.0605831,42.1052074]},"n1820937769":{"id":"n1820937769","loc":[-85.0259021,42.0930037]},"n1820937770":{"id":"n1820937770","loc":[-85.232963,42.0313162]},"n1820937771":{"id":"n1820937771","loc":[-85.2404947,42.0125381]},"n1820937772":{"id":"n1820937772","loc":[-85.0910892,42.0935742]},"n1820937773":{"id":"n1820937773","loc":[-85.2554829,42.0019435]},"n1820937774":{"id":"n1820937774","loc":[-85.2799339,41.9867773]},"n1820937775":{"id":"n1820937775","loc":[-85.1075432,42.0852767]},"n1820937776":{"id":"n1820937776","loc":[-85.1176927,42.0854001]},"n1820937777":{"id":"n1820937777","loc":[-85.1067064,42.0863357]},"n1820937778":{"id":"n1820937778","loc":[-85.2517492,42.0106333]},"n1820937779":{"id":"n1820937779","loc":[-85.0987174,42.0909031]},"n1820937780":{"id":"n1820937780","loc":[-85.1160083,42.0863994]},"n1820937781":{"id":"n1820937781","loc":[-85.1268645,42.0739703]},"n1820937782":{"id":"n1820937782","loc":[-85.0454702,42.1002852]},"n1820937783":{"id":"n1820937783","loc":[-85.1334145,42.0705418]},"n1820937784":{"id":"n1820937784","loc":[-85.5866542,41.947431]},"n1820937786":{"id":"n1820937786","loc":[-85.2359886,42.0250366]},"n1820937787":{"id":"n1820937787","loc":[-85.3138048,41.9698527]},"n1820937788":{"id":"n1820937788","loc":[-85.1274291,42.0733081]},"n1820937790":{"id":"n1820937790","loc":[-85.6292905,41.9411267]},"n1820937791":{"id":"n1820937791","loc":[-85.5958809,41.9417333]},"n1820937792":{"id":"n1820937792","loc":[-85.1271019,42.0737581]},"n1820937793":{"id":"n1820937793","loc":[-85.2312679,42.0314437]},"n1820937794":{"id":"n1820937794","loc":[-85.1081387,42.0863516]},"n1820937795":{"id":"n1820937795","loc":[-85.2424473,42.0212109]},"n1820937796":{"id":"n1820937796","loc":[-85.2710654,41.9975236]},"n1820937797":{"id":"n1820937797","loc":[-85.4798408,41.9863223]},"n1820937798":{"id":"n1820937798","loc":[-85.035939,42.104296]},"n1820937799":{"id":"n1820937799","loc":[-85.2178139,42.0395398]},"n1820937800":{"id":"n1820937800","loc":[-85.0630709,42.1042614]},"n1820937801":{"id":"n1820937801","loc":[-85.0440124,42.1014861]},"n1820937802":{"id":"n1820937802","loc":[-85.1321874,42.0720458]},"n1820937804":{"id":"n1820937804","loc":[-85.079427,42.1029121]},"n1820937805":{"id":"n1820937805","loc":[-85.2962632,41.9738968]},"n1820937806":{"id":"n1820937806","loc":[-85.6334748,41.9274627]},"n1820937807":{"id":"n1820937807","loc":[-85.1057341,42.0872804]},"n1820937808":{"id":"n1820937808","loc":[-85.4960169,41.9778263]},"n1820937809":{"id":"n1820937809","loc":[-85.2821226,41.9910273]},"n1820937810":{"id":"n1820937810","loc":[-85.0013868,42.0885054]},"n1820937811":{"id":"n1820937811","loc":[-85.2952547,41.9729795]},"n1820937812":{"id":"n1820937812","loc":[-85.1298375,42.0667842]},"n1820937813":{"id":"n1820937813","loc":[-85.1339201,42.0710025]},"n1820937814":{"id":"n1820937814","loc":[-85.0374356,42.103691]},"n1820937815":{"id":"n1820937815","loc":[-85.0061115,42.0880607]},"n1820937817":{"id":"n1820937817","loc":[-85.2398402,42.0226934]},"n1820937818":{"id":"n1820937818","loc":[-85.123501,42.076236]},"n1820937819":{"id":"n1820937819","loc":[-85.1209489,42.0791294]},"n1820937820":{"id":"n1820937820","loc":[-85.0818624,42.1025778]},"n1820937821":{"id":"n1820937821","loc":[-85.4428835,42.0054749]},"n1820937822":{"id":"n1820937822","loc":[-85.4710359,41.9961147]},"n1820937823":{"id":"n1820937823","loc":[-85.4253354,42.006198]},"n1820937824":{"id":"n1820937824","loc":[-85.5486483,41.9709451]},"n1820937825":{"id":"n1820937825","loc":[-85.2303238,42.0310452]},"n1820937826":{"id":"n1820937826","loc":[-85.6450405,41.9136361]},"n1820937828":{"id":"n1820937828","loc":[-85.2606853,41.9964073]},"n1820937830":{"id":"n1820937830","loc":[-85.097383,42.0911447]},"n1820937831":{"id":"n1820937831","loc":[-85.0498207,42.102136]},"n1820937832":{"id":"n1820937832","loc":[-85.1232435,42.0763793]},"n1820937833":{"id":"n1820937833","loc":[-85.394093,42.0055921]},"n1820937834":{"id":"n1820937834","loc":[-85.3566665,41.9928295]},"n1820937835":{"id":"n1820937835","loc":[-85.3543276,41.9920002]},"n1820937837":{"id":"n1820937837","loc":[-85.084668,42.1034932]},"n1820937838":{"id":"n1820937838","loc":[-85.4400296,42.0060649]},"n1820937839":{"id":"n1820937839","loc":[-85.2362246,42.025714]},"n1820937840":{"id":"n1820937840","loc":[-85.0409225,42.1012791]},"n1820937841":{"id":"n1820937841","loc":[-85.2442283,42.019832]},"n1820937842":{"id":"n1820937842","loc":[-85.1123001,42.084824]},"n1820937843":{"id":"n1820937843","loc":[-85.1603074,42.0638061]},"n1820937844":{"id":"n1820937844","loc":[-85.1359744,42.0650646]},"n1820937845":{"id":"n1820937845","loc":[-85.1757569,42.053849]},"n1820937846":{"id":"n1820937846","loc":[-85.5200925,41.9716686]},"n1820937848":{"id":"n1820937848","loc":[-85.5525322,41.9701315]},"n1820937849":{"id":"n1820937849","loc":[-85.0406489,42.10149]},"n1820937850":{"id":"n1820937850","loc":[-85.0142547,42.088825]},"n1820937851":{"id":"n1820937851","loc":[-85.343749,41.9881884]},"n1820937852":{"id":"n1820937852","loc":[-85.074996,42.1060205]},"n1820937853":{"id":"n1820937853","loc":[-85.2436275,42.0136864]},"n1820937854":{"id":"n1820937854","loc":[-85.2641453,41.9980897]},"n1820937856":{"id":"n1820937856","loc":[-85.2802343,41.9870086]},"n1820937857":{"id":"n1820937857","loc":[-85.0099256,42.0909946]},"n1820937858":{"id":"n1820937858","loc":[-85.493957,41.9786079]},"n1820937859":{"id":"n1820937859","loc":[-85.0739405,42.1059795]},"n1820937860":{"id":"n1820937860","loc":[-85.2331605,42.0301423]},"n1820937862":{"id":"n1820937862","loc":[-85.2035231,42.0438425]},"n1820937863":{"id":"n1820937863","loc":[-85.0884928,42.0986971]},"n1820937864":{"id":"n1820937864","loc":[-85.131597,42.0690142]},"n1820937865":{"id":"n1820937865","loc":[-85.3937454,42.0052677]},"n1820937866":{"id":"n1820937866","loc":[-85.2212729,42.0378561]},"n1820937867":{"id":"n1820937867","loc":[-85.0886068,42.0982421]},"n1820937868":{"id":"n1820937868","loc":[-85.0875004,42.0968064]},"n1820937869":{"id":"n1820937869","loc":[-85.0771323,42.1042642]},"n1820937870":{"id":"n1820937870","loc":[-85.0164554,42.0894887]},"n1820937871":{"id":"n1820937871","loc":[-85.6069102,41.9415577]},"n1820937872":{"id":"n1820937872","loc":[-85.3273875,41.9704908]},"n1820937873":{"id":"n1820937873","loc":[-85.3890891,41.9997983]},"n1820937875":{"id":"n1820937875","loc":[-85.5091276,41.9723705]},"n1820937876":{"id":"n1820937876","loc":[-85.0770626,42.1047696]},"n1820937877":{"id":"n1820937877","loc":[-85.612575,41.9419567]},"n1820937878":{"id":"n1820937878","loc":[-85.3868146,42.0036094]},"n1820937879":{"id":"n1820937879","loc":[-85.2722738,41.9981204]},"n1820937880":{"id":"n1820937880","loc":[-85.3064878,41.9723733]},"n1820937882":{"id":"n1820937882","loc":[-85.1270845,42.0727678]},"n1820937884":{"id":"n1820937884","loc":[-85.3316512,41.97923]},"n1820937885":{"id":"n1820937885","loc":[-85.3932519,42.0042472]},"n1820937886":{"id":"n1820937886","loc":[-85.2457411,42.0175444]},"n1820937887":{"id":"n1820937887","loc":[-85.1397509,42.0648415]},"n1820937891":{"id":"n1820937891","loc":[-85.3196735,41.9719665]},"n1820937892":{"id":"n1820937892","loc":[-85.3372473,41.9845033]},"n1820937894":{"id":"n1820937894","loc":[-85.3254778,41.9719745]},"n1820937897":{"id":"n1820937897","loc":[-85.3185148,41.9691268]},"n1820937899":{"id":"n1820937899","loc":[-85.5419106,41.9714556]},"n1820937901":{"id":"n1820937901","loc":[-85.3293509,41.9748368]},"n1820937903":{"id":"n1820937903","loc":[-85.0798078,42.1028365]},"n1820937905":{"id":"n1820937905","loc":[-85.3954191,42.0056025]},"n1820937909":{"id":"n1820937909","loc":[-85.3417534,41.9857155]},"n1820937913":{"id":"n1820937913","loc":[-84.9927822,42.0857107]},"n1820937915":{"id":"n1820937915","loc":[-85.5444212,41.9712801]},"n1820937917":{"id":"n1820937917","loc":[-85.259088,41.9981682]},"n1820937921":{"id":"n1820937921","loc":[-85.2784576,41.9876358]},"n1820937922":{"id":"n1820937922","loc":[-84.9971918,42.087753]},"n1820937924":{"id":"n1820937924","loc":[-85.5310688,41.966899]},"n1820937928":{"id":"n1820937928","loc":[-85.3766436,41.9979326]},"n1820937930":{"id":"n1820937930","loc":[-85.5494852,41.9704346]},"n1820937933":{"id":"n1820937933","loc":[-85.5548281,41.9695412]},"n1820937935":{"id":"n1820937935","loc":[-85.0768588,42.105088]},"n1820937937":{"id":"n1820937937","loc":[-85.2646885,41.9978054]},"n1820937939":{"id":"n1820937939","loc":[-85.2441532,42.0176082]},"n1820937941":{"id":"n1820937941","loc":[-85.105553,42.0877928]},"n1820937943":{"id":"n1820937943","loc":[-85.0879457,42.0958909]},"n1820937944":{"id":"n1820937944","loc":[-85.3187015,41.9704402]},"n1820937945":{"id":"n1820937945","loc":[-85.5624456,41.970626]},"n1820937946":{"id":"n1820937946","loc":[-85.0580176,42.1028644]},"n1820937948":{"id":"n1820937948","loc":[-85.3016061,41.9726286]},"n1820937949":{"id":"n1820937949","loc":[-85.4310388,42.0069418]},"n1820937950":{"id":"n1820937950","loc":[-85.2945144,41.9740723]},"n1820937951":{"id":"n1820937951","loc":[-85.1170222,42.082657]},"n1820937952":{"id":"n1820937952","loc":[-85.0864503,42.0947632]},"n1820937953":{"id":"n1820937953","loc":[-85.4285926,42.0059533]},"n1820937970":{"id":"n1820937970","loc":[-85.3629965,41.9938023]},"n1820937972":{"id":"n1820937972","loc":[-85.2438099,42.0199755]},"n1820937974":{"id":"n1820937974","loc":[-85.1327654,42.0699285]},"n1820937977":{"id":"n1820937977","loc":[-85.1515956,42.0611935]},"n1820937978":{"id":"n1820937978","loc":[-85.0107369,42.0896638]},"n1820937979":{"id":"n1820937979","loc":[-85.1152626,42.0862083]},"n1820937980":{"id":"n1820937980","loc":[-85.4531831,42.0062881]},"n1820937981":{"id":"n1820937981","loc":[-85.0341473,42.0985924]},"n1820937982":{"id":"n1820937982","loc":[-85.0877485,42.0960171]},"n1820937983":{"id":"n1820937983","loc":[-85.2756373,41.9951742]},"n1820937984":{"id":"n1820937984","loc":[-85.2965421,41.9714401]},"n1820937985":{"id":"n1820937985","loc":[-85.2409775,42.0226934]},"n1820937986":{"id":"n1820937986","loc":[-85.0170723,42.0900579]},"n1820937987":{"id":"n1820937987","loc":[-85.1034663,42.0880555]},"n1820937988":{"id":"n1820937988","loc":[-85.0585071,42.1031577]},"n1820937990":{"id":"n1820937990","loc":[-85.0819174,42.1032373]},"n1820937992":{"id":"n1820937992","loc":[-85.0546608,42.1030542]},"n1820937993":{"id":"n1820937993","loc":[-85.0100811,42.0906125]},"n1820937995":{"id":"n1820937995","loc":[-85.6304278,41.9432655]},"n1820937997":{"id":"n1820937997","loc":[-85.0255628,42.092778]},"n1820938011":{"id":"n1820938011","loc":[-85.2316756,42.0317146]},"n1820938012":{"id":"n1820938012","loc":[-85.4067917,42.008042]},"n1820938013":{"id":"n1820938013","loc":[-85.390398,42.0028759]},"n1820938014":{"id":"n1820938014","loc":[-85.0161604,42.0886527]},"n1820938015":{"id":"n1820938015","loc":[-85.125337,42.0744589]},"n1820938016":{"id":"n1820938016","loc":[-85.2151317,42.0404801]},"n1820938017":{"id":"n1820938017","loc":[-85.3165085,41.9706025]},"n1820938018":{"id":"n1820938018","loc":[-85.5641193,41.9640688]},"n1820938019":{"id":"n1820938019","loc":[-85.147583,42.0642203]},"n1820938022":{"id":"n1820938022","loc":[-85.2803781,41.9947886]},"n1820938024":{"id":"n1820938024","loc":[-85.2692469,41.9982053]},"n1820938026":{"id":"n1820938026","loc":[-85.4321975,42.0067505]},"n1820938028":{"id":"n1820938028","loc":[-85.572535,41.9633405]},"n1820938030":{"id":"n1820938030","loc":[-85.3237505,41.9716475]},"n1820938032":{"id":"n1820938032","loc":[-85.6487698,41.9141583]},"n1820938033":{"id":"n1820938033","loc":[-85.0526371,42.1038315]},"n1820938034":{"id":"n1820938034","loc":[-85.088069,42.0978731]},"n1820938035":{"id":"n1820938035","loc":[-85.2516312,42.0102267]},"n1820938039":{"id":"n1820938039","loc":[-85.2731374,41.9982958]},"n1820938040":{"id":"n1820938040","loc":[-85.5453224,41.9713439]},"n1820938041":{"id":"n1820938041","loc":[-85.4480548,42.0049647]},"n1820938043":{"id":"n1820938043","loc":[-85.2504081,42.010322]},"n1820938045":{"id":"n1820938045","loc":[-85.2663447,41.99919]},"n1820938046":{"id":"n1820938046","loc":[-85.0507287,42.102907]},"n1820938047":{"id":"n1820938047","loc":[-85.0408246,42.1024743]},"n1820938048":{"id":"n1820938048","loc":[-85.2796335,41.9866099]},"n1820938050":{"id":"n1820938050","loc":[-85.452475,42.0061127]},"n1820938051":{"id":"n1820938051","loc":[-85.2410569,42.0128147]},"n1820938052":{"id":"n1820938052","loc":[-85.0413302,42.1011477]},"n1820938053":{"id":"n1820938053","loc":[-85.6327409,41.9197627]},"n1820938056":{"id":"n1820938056","loc":[-85.1072039,42.0857994]},"n1820938057":{"id":"n1820938057","loc":[-85.2001114,42.0448145]},"n1820938058":{"id":"n1820938058","loc":[-85.2655347,41.9978186]},"n1820938059":{"id":"n1820938059","loc":[-85.2330918,42.0304874]},"n1820938060":{"id":"n1820938060","loc":[-85.2601113,41.9966545]},"n1820938061":{"id":"n1820938061","loc":[-85.5397863,41.9708494]},"n1820938062":{"id":"n1820938062","loc":[-85.2702085,41.9977217]},"n1820938063":{"id":"n1820938063","loc":[-85.2219982,42.03699]},"n1820938064":{"id":"n1820938064","loc":[-85.0668957,42.105121]},"n1820938065":{"id":"n1820938065","loc":[-85.2328665,42.0270769]},"n1820938066":{"id":"n1820938066","loc":[-85.3189654,41.9694778]},"n1820938067":{"id":"n1820938067","loc":[-85.3814115,42.0022915]},"n1820938068":{"id":"n1820938068","loc":[-85.2759108,41.9956008]},"n1820938069":{"id":"n1820938069","loc":[-85.0391938,42.1034853]},"n1820938070":{"id":"n1820938070","loc":[-85.2850623,41.9810353]},"n1820938071":{"id":"n1820938071","loc":[-85.538074,41.970855]},"n1820938073":{"id":"n1820938073","loc":[-85.1319661,42.0670932]},"n1820938074":{"id":"n1820938074","loc":[-85.2816763,41.9913678]},"n1820938075":{"id":"n1820938075","loc":[-85.3182144,41.9700282]},"n1820938076":{"id":"n1820938076","loc":[-85.5909028,41.9458989]},"n1820938077":{"id":"n1820938077","loc":[-85.4057617,42.0074361]},"n1820938078":{"id":"n1820938078","loc":[-85.2620438,41.9967729]},"n1820938079":{"id":"n1820938079","loc":[-85.1122143,42.0851107]},"n1820938080":{"id":"n1820938080","loc":[-85.2443785,42.0174567]},"n1820938081":{"id":"n1820938081","loc":[-85.0319733,42.0953853]},"n1820938082":{"id":"n1820938082","loc":[-85.0878276,42.09443]},"n1820938083":{"id":"n1820938083","loc":[-85.0271789,42.0935809]},"n1820938084":{"id":"n1820938084","loc":[-85.0326399,42.0974222]},"n1820938085":{"id":"n1820938085","loc":[-85.3989167,42.0065592]},"n1820938086":{"id":"n1820938086","loc":[-85.3263361,41.9721261]},"n1820938087":{"id":"n1820938087","loc":[-85.2547855,42.0037134]},"n1820938088":{"id":"n1820938088","loc":[-85.4373259,42.005746]},"n1820938089":{"id":"n1820938089","loc":[-85.3094275,41.9699245]},"n1820938090":{"id":"n1820938090","loc":[-85.2783246,41.9872793]},"n1820938092":{"id":"n1820938092","loc":[-85.0815633,42.1025169]},"n1820938093":{"id":"n1820938093","loc":[-85.1788511,42.0522134]},"n1820938095":{"id":"n1820938095","loc":[-85.2830345,41.9816733]},"n1820938096":{"id":"n1820938096","loc":[-85.0744984,42.1059835]},"n1820938097":{"id":"n1820938097","loc":[-85.2788396,41.9879333]},"n1820938098":{"id":"n1820938098","loc":[-85.3640093,41.9946531]},"n1820938099":{"id":"n1820938099","loc":[-85.291167,41.9787463]},"n1820938100":{"id":"n1820938100","loc":[-85.0772436,42.1038156]},"n1820938101":{"id":"n1820938101","loc":[-85.00563,42.0887482]},"n1820938102":{"id":"n1820938102","loc":[-85.0326881,42.0961245]},"n1820938104":{"id":"n1820938104","loc":[-85.0530448,42.1038634]},"n1820938105":{"id":"n1820938105","loc":[-85.2625266,41.9970639]},"n1820938106":{"id":"n1820938106","loc":[-85.2827556,41.9823512]},"n1820938107":{"id":"n1820938107","loc":[-85.2784319,41.9910752]},"n1820938108":{"id":"n1820938108","loc":[-85.0882099,42.094393]},"n1820938109":{"id":"n1820938109","loc":[-85.5718484,41.9645371]},"n1820938110":{"id":"n1820938110","loc":[-85.2559764,42.0099317]},"n1820938111":{"id":"n1820938111","loc":[-85.2969284,41.973179]},"n1820938113":{"id":"n1820938113","loc":[-85.3875055,42.0019726]},"n1820938114":{"id":"n1820938114","loc":[-85.4250779,42.0068199]},"n1820938115":{"id":"n1820938115","loc":[-85.0645367,42.104889]},"n1820938116":{"id":"n1820938116","loc":[-85.1636762,42.0623724]},"n1820938117":{"id":"n1820938117","loc":[-85.0757322,42.1055935]},"n1820938118":{"id":"n1820938118","loc":[-85.3695197,41.9981559]},"n1820938120":{"id":"n1820938120","loc":[-85.1297516,42.0671027]},"n1820938121":{"id":"n1820938121","loc":[-85.1057448,42.0875551]},"n1820938122":{"id":"n1820938122","loc":[-85.2805175,41.9943182]},"n1820938123":{"id":"n1820938123","loc":[-85.2545173,42.0040722]},"n1820938124":{"id":"n1820938124","loc":[-84.9966607,42.0871319]},"n1820938125":{"id":"n1820938125","loc":[-85.0099899,42.0904612]},"n1820938126":{"id":"n1820938126","loc":[-85.2489919,42.0091102]},"n1820938127":{"id":"n1820938127","loc":[-85.0342706,42.0979476]},"n1820938128":{"id":"n1820938128","loc":[-85.1080891,42.0855884]},"n1820938129":{"id":"n1820938129","loc":[-85.0128183,42.0905356]},"n1820938130":{"id":"n1820938130","loc":[-85.631608,41.9434251]},"n1820938131":{"id":"n1820938131","loc":[-85.2551975,42.0008524]},"n1820938132":{"id":"n1820938132","loc":[-85.6421823,41.9096233]},"n1820938133":{"id":"n1820938133","loc":[-85.0125059,42.0906284]},"n1820938134":{"id":"n1820938134","loc":[-85.5499358,41.9701793]},"n1820938135":{"id":"n1820938135","loc":[-85.5472107,41.9712323]},"n1820938136":{"id":"n1820938136","loc":[-85.2760758,41.9958691]},"n1820938137":{"id":"n1820938137","loc":[-85.276678,41.9960433]},"n1820938138":{"id":"n1820938138","loc":[-85.0570319,42.1024731]},"n1820938140":{"id":"n1820938140","loc":[-85.2394325,42.0227492]},"n1820938142":{"id":"n1820938142","loc":[-85.5666341,41.9638829]},"n1820938144":{"id":"n1820938144","loc":[-85.258101,41.9996353]},"n1820938147":{"id":"n1820938147","loc":[-85.2129645,42.0413565]},"n1820938149":{"id":"n1820938149","loc":[-84.9962369,42.0868373]},"n1820938151":{"id":"n1820938151","loc":[-85.2570386,42.0084968]},"n1820938153":{"id":"n1820938153","loc":[-85.3971142,42.0050285]},"n1820938155":{"id":"n1820938155","loc":[-85.1072093,42.0855566]},"n1820938157":{"id":"n1820938157","loc":[-85.2840323,41.9920959]},"n1820938159":{"id":"n1820938159","loc":[-85.1187924,42.0816458]},"n1820938161":{"id":"n1820938161","loc":[-85.2681324,41.9985788]},"n1820938163":{"id":"n1820938163","loc":[-85.0887034,42.0984969]},"n1820938165":{"id":"n1820938165","loc":[-85.4133405,42.0073141]},"n1820938166":{"id":"n1820938166","loc":[-85.0097445,42.0902888]},"n1820938167":{"id":"n1820938167","loc":[-85.0828133,42.1037388]},"n1820938168":{"id":"n1820938168","loc":[-85.0549599,42.1030833]},"n1820938169":{"id":"n1820938169","loc":[-85.4571528,42.0010421]},"n1820938178":{"id":"n1820938178","loc":[-85.2706644,41.9975941]},"n1820938180":{"id":"n1820938180","loc":[-85.2258606,42.0335794]},"n1820938182":{"id":"n1820938182","loc":[-85.2832276,41.9814659]},"n1820938184":{"id":"n1820938184","loc":[-85.1082299,42.0860928]},"n1820938185":{"id":"n1820938185","loc":[-85.3839392,42.0022381]},"n1820938186":{"id":"n1820938186","loc":[-85.2772131,41.995905]},"n1820938187":{"id":"n1820938187","loc":[-85.1044895,42.0879214]},"n1820938188":{"id":"n1820938188","loc":[-85.2135267,42.0407087]},"n1820938189":{"id":"n1820938189","loc":[-85.2543993,42.0044628]},"n1820938190":{"id":"n1820938190","loc":[-85.1501793,42.0617351]},"n1820938191":{"id":"n1820938191","loc":[-85.3350587,41.9820469]},"n1820938192":{"id":"n1820938192","loc":[-85.1350731,42.0655735]},"n1820938193":{"id":"n1820938193","loc":[-85.0404008,42.1028843]},"n1820938194":{"id":"n1820938194","loc":[-85.6323161,41.943042]},"n1820938195":{"id":"n1820938195","loc":[-85.1259593,42.0742837]},"n1820938196":{"id":"n1820938196","loc":[-85.4562988,42.0033758]},"n1820938197":{"id":"n1820938197","loc":[-85.256824,42.0056826]},"n1820938198":{"id":"n1820938198","loc":[-85.2742103,41.9963862]},"n1820938199":{"id":"n1820938199","loc":[-85.0380888,42.1037877]},"n1820938200":{"id":"n1820938200","loc":[-85.47404,41.9944721]},"n1820938201":{"id":"n1820938201","loc":[-85.103021,42.087948]},"n1820938202":{"id":"n1820938202","loc":[-85.4030151,42.0065113]},"n1820938203":{"id":"n1820938203","loc":[-85.2113981,42.040735]},"n1820938204":{"id":"n1820938204","loc":[-85.2603433,41.9965137]},"n1820938206":{"id":"n1820938206","loc":[-85.1669378,42.0607634]},"n1820938207":{"id":"n1820938207","loc":[-85.0642027,42.1046076]},"n1820938208":{"id":"n1820938208","loc":[-85.2812428,41.9915696]},"n1820938209":{"id":"n1820938209","loc":[-85.0839559,42.1038343]},"n1820938210":{"id":"n1820938210","loc":[-85.1239946,42.0769368]},"n1820938211":{"id":"n1820938211","loc":[-85.2311177,42.0283042]},"n1820938212":{"id":"n1820938212","loc":[-85.2791614,41.9882682]},"n1820938213":{"id":"n1820938213","loc":[-85.2674941,41.9987582]},"n1820938214":{"id":"n1820938214","loc":[-85.352787,41.9919579]},"n1820938215":{"id":"n1820938215","loc":[-85.0874146,42.0952182]},"n1820938216":{"id":"n1820938216","loc":[-85.0069711,42.0877092]},"n1820938217":{"id":"n1820938217","loc":[-85.2059049,42.0404004]},"n1820938218":{"id":"n1820938218","loc":[-85.2403552,42.0227332]},"n1820938219":{"id":"n1820938219","loc":[-85.2492923,42.0098915]},"n1820938220":{"id":"n1820938220","loc":[-85.269778,41.9979541]},"n1820938221":{"id":"n1820938221","loc":[-85.2097673,42.0389024]},"n1820938222":{"id":"n1820938222","loc":[-85.0845942,42.1032015]},"n1820938223":{"id":"n1820938223","loc":[-84.993206,42.0858142]},"n1820938224":{"id":"n1820938224","loc":[-85.2108187,42.0402729]},"n1820938225":{"id":"n1820938225","loc":[-84.9893959,42.0873043]},"n1820938226":{"id":"n1820938226","loc":[-85.2952332,41.9719984]},"n1820938227":{"id":"n1820938227","loc":[-85.4100961,42.0081536]},"n1820938228":{"id":"n1820938228","loc":[-85.3299088,41.9785696]},"n1820938229":{"id":"n1820938229","loc":[-85.2258176,42.0340097]},"n1820938230":{"id":"n1820938230","loc":[-85.3146739,41.9711449]},"n1820938231":{"id":"n1820938231","loc":[-85.5447645,41.9712801]},"n1820938232":{"id":"n1820938232","loc":[-85.5510087,41.9705941]},"n1820938233":{"id":"n1820938233","loc":[-85.5122389,41.9703445]},"n1820938234":{"id":"n1820938234","loc":[-85.2792687,41.9865381]},"n1820938235":{"id":"n1820938235","loc":[-85.1475229,42.0630151]},"n1820938237":{"id":"n1820938237","loc":[-85.0332889,42.0996034]},"n1820938238":{"id":"n1820938238","loc":[-85.2588882,41.9986877]},"n1820938239":{"id":"n1820938239","loc":[-85.0656458,42.1050892]},"n1820938240":{"id":"n1820938240","loc":[-84.9913915,42.086098]},"n1820938241":{"id":"n1820938241","loc":[-85.4752416,41.9944402]},"n1820938242":{"id":"n1820938242","loc":[-85.1214304,42.0791147]},"n1820938243":{"id":"n1820938243","loc":[-85.0075183,42.0886925]},"n1820938244":{"id":"n1820938244","loc":[-85.1052888,42.0872087]},"n1820938245":{"id":"n1820938245","loc":[-85.3104252,41.9703393]},"n1820938246":{"id":"n1820938246","loc":[-85.232109,42.0318158]},"n1820938247":{"id":"n1820938247","loc":[-85.0756075,42.1059528]},"n1820938248":{"id":"n1820938248","loc":[-85.0075612,42.0890866]},"n1820938249":{"id":"n1820938249","loc":[-85.1013312,42.0897474]},"n1820938250":{"id":"n1820938250","loc":[-85.1168076,42.0828919]},"n1820938251":{"id":"n1820938251","loc":[-85.2951367,41.9723334]},"n1820938252":{"id":"n1820938252","loc":[-85.0879363,42.0976053]},"n1820938253":{"id":"n1820938253","loc":[-85.0354763,42.1021838]},"n1820938254":{"id":"n1820938254","loc":[-85.2379627,42.0236339]},"n1820938255":{"id":"n1820938255","loc":[-85.1308245,42.0685364]},"n1820938256":{"id":"n1820938256","loc":[-85.0914446,42.0934774]},"n1820938257":{"id":"n1820938257","loc":[-85.2436812,42.014069]},"n1820938258":{"id":"n1820938258","loc":[-85.0682529,42.1056106]},"n1820938259":{"id":"n1820938259","loc":[-85.290652,41.9766805]},"n1820938260":{"id":"n1820938260","loc":[-85.0133494,42.0897434]},"n1820938261":{"id":"n1820938261","loc":[-85.2753047,41.9949429]},"n1820938262":{"id":"n1820938262","loc":[-85.0314691,42.0950788]},"n1820938263":{"id":"n1820938263","loc":[-85.3444786,41.9908359]},"n1820938264":{"id":"n1820938264","loc":[-85.0443115,42.1009061]},"n1820938265":{"id":"n1820938265","loc":[-85.0634853,42.1043159]},"n1820938267":{"id":"n1820938267","loc":[-85.3978223,42.0053952]},"n1820938268":{"id":"n1820938268","loc":[-85.0228659,42.0911885]},"n1820938269":{"id":"n1820938269","loc":[-85.0220237,42.0906272]},"n1820938270":{"id":"n1820938270","loc":[-85.1061525,42.0863369]},"n1820938271":{"id":"n1820938271","loc":[-85.2382309,42.0233708]},"n1820938272":{"id":"n1820938272","loc":[-85.310672,41.9702755]},"n1820938273":{"id":"n1820938273","loc":[-85.1448192,42.0652613]},"n1820938274":{"id":"n1820938274","loc":[-85.6036057,41.9403766]},"n1820938275":{"id":"n1820938275","loc":[-85.0778941,42.1032413]},"n1820938276":{"id":"n1820938276","loc":[-85.1279374,42.0723974]},"n1820938277":{"id":"n1820938277","loc":[-85.2806635,41.9847836]},"n1820938278":{"id":"n1820938278","loc":[-85.2653201,41.9976352]},"n1820938279":{"id":"n1820938279","loc":[-85.0351665,42.1001805]},"n1820938280":{"id":"n1820938280","loc":[-85.0718269,42.1056253]},"n1820938281":{"id":"n1820938281","loc":[-85.2574248,42.0075322]},"n1820938282":{"id":"n1820938282","loc":[-85.126666,42.0740778]},"n1820938283":{"id":"n1820938283","loc":[-85.077705,42.1034733]},"n1820938284":{"id":"n1820938284","loc":[-85.3535552,41.9919045]},"n1820938286":{"id":"n1820938286","loc":[-85.2810711,41.9866657]},"n1820938287":{"id":"n1820938287","loc":[-85.4567494,42.0019885]},"n1820938288":{"id":"n1820938288","loc":[-85.2642419,41.9992936]},"n1820938289":{"id":"n1820938289","loc":[-85.2643344,41.9980925]},"n1820938290":{"id":"n1820938290","loc":[-85.3270335,41.9776125]},"n1820938291":{"id":"n1820938291","loc":[-85.1200584,42.0795077]},"n1820938292":{"id":"n1820938292","loc":[-85.2290792,42.0340256]},"n1820938293":{"id":"n1820938293","loc":[-85.6015887,41.9401372]},"n1820938294":{"id":"n1820938294","loc":[-85.5370869,41.970488]},"n1820938295":{"id":"n1820938295","loc":[-85.3108866,41.9698048]},"n1820938297":{"id":"n1820938297","loc":[-85.1556511,42.0628184]},"n1820938298":{"id":"n1820938298","loc":[-85.0027922,42.0875221]},"n1820938300":{"id":"n1820938300","loc":[-85.3873338,42.0040614]},"n1820938301":{"id":"n1820938301","loc":[-85.0350753,42.1004034]},"n1820938302":{"id":"n1820938302","loc":[-85.6239476,41.9411906]},"n1820938304":{"id":"n1820938304","loc":[-85.0118246,42.0897964]},"n1820938306":{"id":"n1820938306","loc":[-85.4796877,41.995275]},"n1820938307":{"id":"n1820938307","loc":[-85.5388636,41.9707856]},"n1820938309":{"id":"n1820938309","loc":[-85.2971902,41.9727773]},"n1820938310":{"id":"n1820938310","loc":[-85.5426831,41.9715513]},"n1820938311":{"id":"n1820938311","loc":[-85.2798373,41.9836671]},"n1820938312":{"id":"n1820938312","loc":[-85.2432198,42.0104017]},"n1820938313":{"id":"n1820938313","loc":[-85.2650412,41.9987554]},"n1820938317":{"id":"n1820938317","loc":[-85.0015423,42.0882386]},"n1820938318":{"id":"n1820938318","loc":[-85.1409783,42.064879]},"n1820938319":{"id":"n1820938319","loc":[-85.1691908,42.058995]},"n1820938320":{"id":"n1820938320","loc":[-85.1059165,42.0864882]},"n1820938321":{"id":"n1820938321","loc":[-85.3664941,41.9965771]},"n1820938323":{"id":"n1820938323","loc":[-85.3143198,41.9710971]},"n1820938324":{"id":"n1820938324","loc":[-85.0016067,42.0880675]},"n1820938325":{"id":"n1820938325","loc":[-85.0148139,42.0887164]},"n1820938326":{"id":"n1820938326","loc":[-85.0324682,42.0959056]},"n1820938327":{"id":"n1820938327","loc":[-85.0898661,42.0939921]},"n1820938328":{"id":"n1820938328","loc":[-85.2556427,42.0004936]},"n1820938329":{"id":"n1820938329","loc":[-85.6287112,41.9407437]},"n1820938330":{"id":"n1820938330","loc":[-84.9913392,42.0866701]},"n1820938331":{"id":"n1820938331","loc":[-85.2685777,41.9984632]},"n1820938332":{"id":"n1820938332","loc":[-85.0078884,42.0901614]},"n1820938333":{"id":"n1820938333","loc":[-84.999642,42.0878616]},"n1820938334":{"id":"n1820938334","loc":[-85.0188909,42.0899186]},"n1820938335":{"id":"n1820938335","loc":[-85.2830238,41.9819843]},"n1820938336":{"id":"n1820938336","loc":[-85.2491421,42.0096204]},"n1820938337":{"id":"n1820938337","loc":[-85.0585701,42.1034295]},"n1820938338":{"id":"n1820938338","loc":[-85.0651965,42.1051636]},"n1820938339":{"id":"n1820938339","loc":[-85.0583944,42.104292]},"n1820938340":{"id":"n1820938340","loc":[-85.119876,42.0801567]},"n1820938341":{"id":"n1820938341","loc":[-85.0943937,42.0931323]},"n1820938342":{"id":"n1820938342","loc":[-85.1504583,42.0613209]},"n1820938343":{"id":"n1820938343","loc":[-85.0425426,42.1019836]},"n1820938345":{"id":"n1820938345","loc":[-84.9991391,42.0878206]},"n1820938346":{"id":"n1820938346","loc":[-85.2563841,42.0094614]},"n1820938347":{"id":"n1820938347","loc":[-85.0515387,42.103297]},"n1820938348":{"id":"n1820938348","loc":[-85.0857261,42.1003636]},"n1820938349":{"id":"n1820938349","loc":[-85.078971,42.1029241]},"n1820938350":{"id":"n1820938350","loc":[-85.5699558,41.958931]},"n1820938351":{"id":"n1820938351","loc":[-85.3181285,41.9696533]},"n1820938352":{"id":"n1820938352","loc":[-85.5998506,41.9402329]},"n1820938353":{"id":"n1820938353","loc":[-85.2567277,42.000317]},"n1820938354":{"id":"n1820938354","loc":[-85.3082795,41.9708338]},"n1820938355":{"id":"n1820938355","loc":[-85.3127856,41.9692784]},"n1820938356":{"id":"n1820938356","loc":[-85.0340775,42.1010721]},"n1820938357":{"id":"n1820938357","loc":[-85.3158111,41.9706583]},"n1820938359":{"id":"n1820938359","loc":[-85.2312035,42.0280412]},"n1820938360":{"id":"n1820938360","loc":[-85.2448613,42.018477]},"n1820938361":{"id":"n1820938361","loc":[-85.29077,41.9759068]},"n1820938364":{"id":"n1820938364","loc":[-85.3677387,41.9976615]},"n1820938365":{"id":"n1820938365","loc":[-85.0785204,42.1030355]},"n1820938366":{"id":"n1820938366","loc":[-85.2262039,42.0333722]},"n1820938367":{"id":"n1820938367","loc":[-85.1226011,42.0780902]},"n1820938368":{"id":"n1820938368","loc":[-85.3229673,41.971129]},"n1820938369":{"id":"n1820938369","loc":[-85.385334,42.0000056]},"n1820938370":{"id":"n1820938370","loc":[-85.000098,42.0879094]},"n1820938372":{"id":"n1820938372","loc":[-85.3852481,42.0025091]},"n1820938373":{"id":"n1820938373","loc":[-85.3770513,41.9982515]},"n1820938374":{"id":"n1820938374","loc":[-85.6278314,41.9405362]},"n1820938375":{"id":"n1820938375","loc":[-85.6355133,41.9344068]},"n1820938376":{"id":"n1820938376","loc":[-85.635642,41.9324753]},"n1820938377":{"id":"n1820938377","loc":[-85.3154463,41.970778]},"n1820938378":{"id":"n1820938378","loc":[-85.0920334,42.093411]},"n1820938379":{"id":"n1820938379","loc":[-85.3269155,41.9722297]},"n1820938381":{"id":"n1820938381","loc":[-85.1134334,42.0849184]},"n1820938382":{"id":"n1820938382","loc":[-85.005968,42.088585]},"n1820938384":{"id":"n1820938384","loc":[-85.1245203,42.0757183]},"n1820938385":{"id":"n1820938385","loc":[-85.020704,42.0905396]},"n1820938386":{"id":"n1820938386","loc":[-85.119585,42.0808984]},"n1820938387":{"id":"n1820938387","loc":[-85.0072447,42.0880117]},"n1820938388":{"id":"n1820938388","loc":[-85.2742908,41.9960273]},"n1820938389":{"id":"n1820938389","loc":[-85.3275807,41.9696852]},"n1820938390":{"id":"n1820938390","loc":[-85.2385635,42.0231556]},"n1820938392":{"id":"n1820938392","loc":[-85.0202856,42.0900778]},"n1820938393":{"id":"n1820938393","loc":[-85.2067847,42.0395398]},"n1820938394":{"id":"n1820938394","loc":[-85.5183544,41.9713495]},"n1820938396":{"id":"n1820938396","loc":[-85.5073037,41.9736787]},"n1820938397":{"id":"n1820938397","loc":[-85.2519638,42.0114225]},"n1820938398":{"id":"n1820938398","loc":[-85.287487,41.9793285]},"n1820938399":{"id":"n1820938399","loc":[-85.2298088,42.0336431]},"n1820938400":{"id":"n1820938400","loc":[-85.229444,42.0339141]},"n1820938401":{"id":"n1820938401","loc":[-85.2421791,42.0220239]},"n1820938402":{"id":"n1820938402","loc":[-85.2976687,41.9737612]},"n1820938403":{"id":"n1820938403","loc":[-85.3622069,41.993473]},"n1820938404":{"id":"n1820938404","loc":[-85.2465458,42.014906]},"n1820938405":{"id":"n1820938405","loc":[-85.5724663,41.9639412]},"n1820938406":{"id":"n1820938406","loc":[-85.3708501,41.9982037]},"n1820938408":{"id":"n1820938408","loc":[-85.2564592,42.0055311]},"n1820938409":{"id":"n1820938409","loc":[-85.1192846,42.0810856]},"n1820938410":{"id":"n1820938410","loc":[-85.5623812,41.971663]},"n1820938411":{"id":"n1820938411","loc":[-85.3221948,41.9719665]},"n1820938412":{"id":"n1820938412","loc":[-85.5168738,41.9710305]},"n1820938413":{"id":"n1820938413","loc":[-85.4546852,42.0061127]},"n1820938414":{"id":"n1820938414","loc":[-85.5896153,41.9463617]},"n1820938415":{"id":"n1820938415","loc":[-85.2978189,41.9722138]},"n1820938416":{"id":"n1820938416","loc":[-85.1021681,42.0883581]},"n1820938417":{"id":"n1820938417","loc":[-85.2797193,41.9912984]},"n1820938419":{"id":"n1820938419","loc":[-85.2362461,42.0248533]},"n1820938420":{"id":"n1820938420","loc":[-85.4833639,41.9846252]},"n1820938422":{"id":"n1820938422","loc":[-85.3281064,41.9689433]},"n1820938424":{"id":"n1820938424","loc":[-85.2416963,42.0130088]},"n1820938425":{"id":"n1820938425","loc":[-85.5718655,41.9564577]},"n1820938426":{"id":"n1820938426","loc":[-85.0512812,42.1030701]},"n1820938427":{"id":"n1820938427","loc":[-85.1273527,42.0723616]},"n1820938428":{"id":"n1820938428","loc":[-85.0215033,42.0904083]},"n1820938429":{"id":"n1820938429","loc":[-85.6169953,41.942228]},"n1820938430":{"id":"n1820938430","loc":[-85.2829165,41.9907243]},"n1820938431":{"id":"n1820938431","loc":[-85.2240796,42.0374203]},"n1820938432":{"id":"n1820938432","loc":[-85.0167598,42.0898442]},"n1820938433":{"id":"n1820938433","loc":[-85.2132649,42.0411334]},"n1820938434":{"id":"n1820938434","loc":[-85.2293839,42.031513]},"n1820938435":{"id":"n1820938435","loc":[-85.1203374,42.0792608]},"n1820938436":{"id":"n1820938436","loc":[-85.109571,42.086268]},"n1820938437":{"id":"n1820938437","loc":[-85.1079026,42.0853842]},"n1820938438":{"id":"n1820938438","loc":[-85.109237,42.0862413]},"n1820938439":{"id":"n1820938439","loc":[-85.2259936,42.0350831]},"n1820938440":{"id":"n1820938440","loc":[-85.3669705,41.99679]},"n1820938441":{"id":"n1820938441","loc":[-85.2418143,42.0223507]},"n1820938442":{"id":"n1820938442","loc":[-85.3101248,41.9702515]},"n1820938443":{"id":"n1820938443","loc":[-85.069315,42.1059688]},"n1820938444":{"id":"n1820938444","loc":[-85.205862,42.0410378]},"n1820938445":{"id":"n1820938445","loc":[-85.0388076,42.1036604]},"n1820938446":{"id":"n1820938446","loc":[-85.2225389,42.0370115]},"n1820938447":{"id":"n1820938447","loc":[-85.3241474,41.9719346]},"n1820938448":{"id":"n1820938448","loc":[-85.3125496,41.9690789]},"n1820938449":{"id":"n1820938449","loc":[-85.1146497,42.0857039]},"n1820938450":{"id":"n1820938450","loc":[-85.1333944,42.0714963]},"n1820938451":{"id":"n1820938451","loc":[-85.5619306,41.9720937]},"n1820938452":{"id":"n1820938452","loc":[-85.2553651,42.0006479]},"n1820938453":{"id":"n1820938453","loc":[-85.3151137,41.9710093]},"n1820938454":{"id":"n1820938454","loc":[-85.2592315,41.9977947]},"n1820938455":{"id":"n1820938455","loc":[-85.2655723,41.9995966]},"n1820938456":{"id":"n1820938456","loc":[-85.4820652,41.9959233]},"n1820938459":{"id":"n1820938459","loc":[-85.450737,42.0055068]},"n1820938460":{"id":"n1820938460","loc":[-85.2428658,42.0205573]},"n1820938461":{"id":"n1820938461","loc":[-85.0835576,42.1021559]},"n1820938462":{"id":"n1820938462","loc":[-85.244636,42.0194733]},"n1820938463":{"id":"n1820938463","loc":[-85.5702562,41.9581332]},"n1820938465":{"id":"n1820938465","loc":[-85.5680031,41.9659515]},"n1820938467":{"id":"n1820938467","loc":[-85.2798752,41.9948353]},"n1820938468":{"id":"n1820938468","loc":[-85.0477407,42.1015537]},"n1820938469":{"id":"n1820938469","loc":[-85.6403842,41.913732]},"n1820938470":{"id":"n1820938470","loc":[-85.0396029,42.103289]},"n1820938471":{"id":"n1820938471","loc":[-85.2824702,41.9907777]},"n1820938472":{"id":"n1820938472","loc":[-85.2969284,41.9735538]},"n1820938474":{"id":"n1820938474","loc":[-85.401041,42.0070853]},"n1820938475":{"id":"n1820938475","loc":[-85.4116625,42.0073883]},"n1820938476":{"id":"n1820938476","loc":[-85.0437764,42.1016214]},"n1820938477":{"id":"n1820938477","loc":[-85.3643269,41.9958436]},"n1820938478":{"id":"n1820938478","loc":[-85.3895182,42.0009465]},"n1820938479":{"id":"n1820938479","loc":[-85.636157,41.9333373]},"n1820938480":{"id":"n1820938480","loc":[-85.2811355,41.9858044]},"n1820938481":{"id":"n1820938481","loc":[-85.0239052,42.092153]},"n1820938482":{"id":"n1820938482","loc":[-85.2558798,42.0053557]},"n1820938483":{"id":"n1820938483","loc":[-85.2544422,42.0047339]},"n1820938484":{"id":"n1820938484","loc":[-85.4864683,41.9843183]},"n1820938485":{"id":"n1820938485","loc":[-85.2554185,42.0031075]},"n1820938486":{"id":"n1820938486","loc":[-85.3082795,41.9712486]},"n1820938487":{"id":"n1820938487","loc":[-85.2433378,42.0133436]},"n1820938488":{"id":"n1820938488","loc":[-85.0216696,42.0904162]},"n1820938489":{"id":"n1820938489","loc":[-85.2546138,42.0050289]},"n1820938490":{"id":"n1820938490","loc":[-85.2717521,41.9977349]},"n1820938491":{"id":"n1820938491","loc":[-85.0100489,42.0908195]},"n1820938492":{"id":"n1820938492","loc":[-85.207879,42.0392211]},"n1820938493":{"id":"n1820938493","loc":[-85.0007363,42.0882836]},"n1820938494":{"id":"n1820938494","loc":[-85.5775303,41.9504097]},"n1820938495":{"id":"n1820938495","loc":[-85.1131584,42.0847683]},"n1820938496":{"id":"n1820938496","loc":[-85.0887825,42.0941633]},"n1820938497":{"id":"n1820938497","loc":[-85.1185926,42.0818938]},"n1820938498":{"id":"n1820938498","loc":[-85.2748487,41.9948712]},"n1820938499":{"id":"n1820938499","loc":[-85.2566952,42.0090788]},"n1820938500":{"id":"n1820938500","loc":[-85.0774757,42.1036234]},"n1820938501":{"id":"n1820938501","loc":[-85.4190869,42.008903]},"n1820938502":{"id":"n1820938502","loc":[-85.1140395,42.0850577]},"n1820938503":{"id":"n1820938503","loc":[-85.1136104,42.0848627]},"n1820938504":{"id":"n1820938504","loc":[-85.5828089,41.9480638]},"n1820938505":{"id":"n1820938505","loc":[-85.625514,41.9405202]},"n1820938506":{"id":"n1820938506","loc":[-85.2063384,42.0398322]},"n1820938507":{"id":"n1820938507","loc":[-85.3395476,41.9851636]},"n1820938508":{"id":"n1820938508","loc":[-85.0328853,42.0963606]},"n1820938510":{"id":"n1820938510","loc":[-85.1170369,42.0843702]},"n1820938511":{"id":"n1820938511","loc":[-85.2784748,41.9868487]},"n1820938512":{"id":"n1820938512","loc":[-85.6310501,41.9435528]},"n1820938514":{"id":"n1820938514","loc":[-85.0334284,42.0981028]},"n1820938515":{"id":"n1820938515","loc":[-84.9912091,42.0868226]},"n1820938516":{"id":"n1820938516","loc":[-85.2806141,41.9940351]},"n1820938517":{"id":"n1820938517","loc":[-85.1233025,42.0776734]},"n1820938518":{"id":"n1820938518","loc":[-85.2047891,42.0429023]},"n1820938519":{"id":"n1820938519","loc":[-85.1475443,42.0648312]},"n1820938520":{"id":"n1820938520","loc":[-85.2644685,41.9990891]},"n1820938521":{"id":"n1820938521","loc":[-85.1056281,42.0872553]},"n1820938522":{"id":"n1820938522","loc":[-85.4813184,41.9930105]},"n1820938523":{"id":"n1820938523","loc":[-85.321551,41.9722936]},"n1820938524":{"id":"n1820938524","loc":[-85.1564664,42.0631211]},"n1820938525":{"id":"n1820938525","loc":[-85.4149885,42.0079144]},"n1820938527":{"id":"n1820938527","loc":[-85.2861888,41.9803653]},"n1820938528":{"id":"n1820938528","loc":[-85.1301379,42.0682178]},"n1820938529":{"id":"n1820938529","loc":[-85.4156537,42.0084247]},"n1820938530":{"id":"n1820938530","loc":[-85.245151,42.0176082]},"n1820938531":{"id":"n1820938531","loc":[-85.457818,42.0001651]},"n1820938532":{"id":"n1820938532","loc":[-85.310951,41.9694538]},"n1820938533":{"id":"n1820938533","loc":[-85.1509089,42.0611298]},"n1820938534":{"id":"n1820938534","loc":[-85.1108249,42.086321]},"n1820938535":{"id":"n1820938535","loc":[-85.1260344,42.0740687]},"n1820938536":{"id":"n1820938536","loc":[-85.4561228,42.0042791]},"n1820938537":{"id":"n1820938537","loc":[-85.2805082,41.9945761]},"n1820938538":{"id":"n1820938538","loc":[-85.273352,41.9981921]},"n1820938539":{"id":"n1820938539","loc":[-85.1084216,42.0864364]},"n1820938540":{"id":"n1820938540","loc":[-85.5009737,41.9773637]},"n1820938541":{"id":"n1820938541","loc":[-85.3960843,42.0051879]},"n1820938542":{"id":"n1820938542","loc":[-85.3425088,41.9865034]},"n1820938545":{"id":"n1820938545","loc":[-84.9937907,42.0860849]},"n1820938546":{"id":"n1820938546","loc":[-85.1084176,42.086065]},"n1820938547":{"id":"n1820938547","loc":[-85.3492851,41.9924786]},"n1820938548":{"id":"n1820938548","loc":[-85.2512235,42.0101147]},"n1820938549":{"id":"n1820938549","loc":[-85.3717298,41.9979326]},"n1820938551":{"id":"n1820938551","loc":[-85.2573712,42.0064081]},"n1820938552":{"id":"n1820938552","loc":[-85.2514596,42.010139]},"n1820938553":{"id":"n1820938553","loc":[-85.416512,42.0088073]},"n1820938554":{"id":"n1820938554","loc":[-85.4365964,42.0061606]},"n1820938555":{"id":"n1820938555","loc":[-85.4552431,42.0057301]},"n1820938556":{"id":"n1820938556","loc":[-85.2916283,41.9778769]},"n1820938557":{"id":"n1820938557","loc":[-85.100709,42.0902968]},"n1820938558":{"id":"n1820938558","loc":[-85.4703064,41.9965771]},"n1820938559":{"id":"n1820938559","loc":[-85.3134722,41.9696134]},"n1820938560":{"id":"n1820938560","loc":[-85.4834213,41.9885768]},"n1820938561":{"id":"n1820938561","loc":[-85.2740641,41.9975236]},"n1820938562":{"id":"n1820938562","loc":[-85.148334,42.0623405]},"n1820938563":{"id":"n1820938563","loc":[-85.2358598,42.0263675]},"n1820938565":{"id":"n1820938565","loc":[-85.2902979,41.9790892]},"n1820938566":{"id":"n1820938566","loc":[-85.2528865,42.0112869]},"n1820938567":{"id":"n1820938567","loc":[-85.2595319,41.9973003]},"n1820938568":{"id":"n1820938568","loc":[-85.071151,42.105689]},"n1820938570":{"id":"n1820938570","loc":[-85.299278,41.9732188]},"n1820938571":{"id":"n1820938571","loc":[-85.0354669,42.1024771]},"n1820938583":{"id":"n1820938583","loc":[-85.3313937,41.972562]},"n1820938585":{"id":"n1820938585","loc":[-85.0756933,42.1058334]},"n1820938587":{"id":"n1820938587","loc":[-85.3130324,41.9694219]},"n1820938590":{"id":"n1820938590","loc":[-85.0934227,42.0931681]},"n1820938592":{"id":"n1820938592","loc":[-85.3517956,41.9922553]},"n1820938593":{"id":"n1820938593","loc":[-85.4023971,42.0065169]},"n1820938594":{"id":"n1820938594","loc":[-85.3506798,41.9925583]},"n1820938595":{"id":"n1820938595","loc":[-85.3673524,41.9971193]},"n1820938596":{"id":"n1820938596","loc":[-85.1073608,42.0853523]},"n1820938597":{"id":"n1820938597","loc":[-85.2976579,41.972477]},"n1820938598":{"id":"n1820938598","loc":[-85.5616517,41.9694295]},"n1820938599":{"id":"n1820938599","loc":[-85.3552074,41.9921915]},"n1820938600":{"id":"n1820938600","loc":[-85.4665126,41.9999953]},"n1820938601":{"id":"n1820938601","loc":[-85.2740695,41.9966226]},"n1820938602":{"id":"n1820938602","loc":[-85.279376,41.9886669]},"n1820938603":{"id":"n1820938603","loc":[-85.0771109,42.1040413]},"n1820938604":{"id":"n1820938604","loc":[-85.2636049,41.9977895]},"n1820938605":{"id":"n1820938605","loc":[-85.3762145,41.9976456]},"n1820938606":{"id":"n1820938606","loc":[-85.2321369,42.0289577]},"n1820938620":{"id":"n1820938620","loc":[-85.4947724,41.9776189]},"n1820938622":{"id":"n1820938622","loc":[-85.1547069,42.0622768]},"n1820938624":{"id":"n1820938624","loc":[-85.0005056,42.0880249]},"n1820938626":{"id":"n1820938626","loc":[-85.0735596,42.1059357]},"n1820938628":{"id":"n1820938628","loc":[-85.4665298,41.99932]},"n1820938629":{"id":"n1820938629","loc":[-85.434515,42.0065273]},"n1820938630":{"id":"n1820938630","loc":[-85.117462,42.0823823]},"n1820938631":{"id":"n1820938631","loc":[-85.0131777,42.0890707]},"n1820938632":{"id":"n1820938632","loc":[-85.0875326,42.0961934]},"n1820938634":{"id":"n1820938634","loc":[-85.6433839,41.9112042]},"n1820938635":{"id":"n1820938635","loc":[-85.1366181,42.064969]},"n1820938636":{"id":"n1820938636","loc":[-85.073109,42.1057925]},"n1820938638":{"id":"n1820938638","loc":[-85.161406,42.0632541]},"n1820938640":{"id":"n1820938640","loc":[-85.6343932,41.9188845]},"n1820938642":{"id":"n1820938642","loc":[-85.2500004,42.010306]},"n1820938644":{"id":"n1820938644","loc":[-85.291918,41.9753166]},"n1820938663":{"id":"n1820938663","loc":[-85.2841611,41.9916812]},"n1820938664":{"id":"n1820938664","loc":[-85.1052955,42.0868134]},"n1820938665":{"id":"n1820938665","loc":[-85.4606118,42.0005534]},"n1820938666":{"id":"n1820938666","loc":[-85.5672736,41.9642922]},"n1820938667":{"id":"n1820938667","loc":[-85.6348481,41.9316932]},"n1820938668":{"id":"n1820938668","loc":[-85.0224904,42.0909576]},"n1820938669":{"id":"n1820938669","loc":[-85.0133856,42.0899755]},"n1820938670":{"id":"n1820938670","loc":[-85.344779,41.991139]},"n1820938671":{"id":"n1820938671","loc":[-85.632874,41.9425313]},"n1820938673":{"id":"n1820938673","loc":[-85.4941501,41.9779698]},"n1820938675":{"id":"n1820938675","loc":[-85.0862559,42.0997519]},"n1820938676":{"id":"n1820938676","loc":[-85.0097874,42.0898032]},"n1820938678":{"id":"n1820938678","loc":[-84.9913553,42.0863675]},"n1820938680":{"id":"n1820938680","loc":[-85.0533666,42.1038315]},"n1820938682":{"id":"n1820938682","loc":[-85.2950294,41.9743914]},"n1820938684":{"id":"n1820938684","loc":[-85.2517385,42.0104499]},"n1820938686":{"id":"n1820938686","loc":[-85.0247971,42.0922514]},"n1820938688":{"id":"n1820938688","loc":[-85.0807037,42.1026017]},"n1820938690":{"id":"n1820938690","loc":[-85.52462,41.9722748]},"n1820938694":{"id":"n1820938694","loc":[-85.2586535,41.9988818]},"n1820938695":{"id":"n1820938695","loc":[-85.0931612,42.092948]},"n1820938697":{"id":"n1820938697","loc":[-85.2470822,42.016564]},"n1820938698":{"id":"n1820938698","loc":[-85.4143018,42.0075158]},"n1820938699":{"id":"n1820938699","loc":[-85.0771484,42.104487]},"n1820938700":{"id":"n1820938700","loc":[-85.0291208,42.0942775]},"n1820938701":{"id":"n1820938701","loc":[-85.6367964,41.9185971]},"n1820938702":{"id":"n1820938702","loc":[-85.085419,42.1010693]},"n1820938703":{"id":"n1820938703","loc":[-85.0583877,42.1040584]},"n1820938705":{"id":"n1820938705","loc":[-85.2573379,42.0003182]},"n1820938706":{"id":"n1820938706","loc":[-85.2655937,41.9981575]},"n1820938707":{"id":"n1820938707","loc":[-85.023181,42.0915758]},"n1820938708":{"id":"n1820938708","loc":[-85.2318687,42.0274674]},"n1820938709":{"id":"n1820938709","loc":[-85.1056389,42.0866184]},"n1820938710":{"id":"n1820938710","loc":[-85.5276265,41.9700978]},"n1820938711":{"id":"n1820938711","loc":[-85.0864128,42.0945761]},"n1820938712":{"id":"n1820938712","loc":[-84.9897071,42.0871888]},"n1820938714":{"id":"n1820938714","loc":[-85.1328845,42.0665611]},"n1820938715":{"id":"n1820938715","loc":[-85.0336537,42.0991377]},"n1820938716":{"id":"n1820938716","loc":[-85.087597,42.0986692]},"n1820938717":{"id":"n1820938717","loc":[-85.1241394,42.0761882]},"n1820938718":{"id":"n1820938718","loc":[-85.1176002,42.0847723]},"n1820938719":{"id":"n1820938719","loc":[-85.2423615,42.0216572]},"n1820938721":{"id":"n1820938721","loc":[-85.2196378,42.0387908]},"n1820938722":{"id":"n1820938722","loc":[-85.0164272,42.0890082]},"n1820938723":{"id":"n1820938723","loc":[-85.5917182,41.9451807]},"n1820938724":{"id":"n1820938724","loc":[-85.2458806,42.0086638]},"n1820938725":{"id":"n1820938725","loc":[-85.1264474,42.0740527]},"n1820938726":{"id":"n1820938726","loc":[-85.1961631,42.04738]},"n1820938727":{"id":"n1820938727","loc":[-85.2784643,41.9943648]},"n1820938728":{"id":"n1820938728","loc":[-85.2905554,41.9763216]},"n1820938729":{"id":"n1820938729","loc":[-85.2913386,41.9771511]},"n1820938730":{"id":"n1820938730","loc":[-85.0112519,42.0895683]},"n1820938732":{"id":"n1820938732","loc":[-85.4290261,42.0064531]},"n1820938733":{"id":"n1820938733","loc":[-85.3867073,42.0031629]},"n1820938734":{"id":"n1820938734","loc":[-85.4943647,41.9836005]},"n1820938735":{"id":"n1820938735","loc":[-85.4900303,41.9860728]},"n1820938736":{"id":"n1820938736","loc":[-85.0866153,42.0944539]},"n1820938737":{"id":"n1820938737","loc":[-85.0869532,42.0990911]},"n1820938738":{"id":"n1820938738","loc":[-85.6321659,41.9208851]},"n1820938739":{"id":"n1820938739","loc":[-85.5930485,41.9433453]},"n1820938740":{"id":"n1820938740","loc":[-85.0406851,42.102733]},"n1820938741":{"id":"n1820938741","loc":[-85.1051131,42.0869846]},"n1820938742":{"id":"n1820938742","loc":[-85.1377554,42.0648893]},"n1820938743":{"id":"n1820938743","loc":[-85.2795694,41.994604]},"n1820938745":{"id":"n1820938745","loc":[-85.4948153,41.9826594]},"n1820938746":{"id":"n1820938746","loc":[-85.4488916,42.0050923]},"n1820938747":{"id":"n1820938747","loc":[-85.1052526,42.0866144]},"n1820938748":{"id":"n1820938748","loc":[-85.1468749,42.0653991]},"n1820938749":{"id":"n1820938749","loc":[-85.0856886,42.1006104]},"n1820938750":{"id":"n1820938750","loc":[-85.2144022,42.0404004]},"n1820938751":{"id":"n1820938751","loc":[-85.277771,41.9907458]},"n1820938752":{"id":"n1820938752","loc":[-85.1474542,42.0636149]},"n1820938753":{"id":"n1820938753","loc":[-85.0820515,42.1028075]},"n1820938754":{"id":"n1820938754","loc":[-85.1122948,42.08525]},"n1820938756":{"id":"n1820938756","loc":[-85.0173352,42.0901933]},"n1820938757":{"id":"n1820938757","loc":[-85.2259721,42.0354018]},"n1820938758":{"id":"n1820938758","loc":[-85.0872389,42.0987795]},"n1820938759":{"id":"n1820938759","loc":[-85.2291436,42.031874]},"n1820938760":{"id":"n1820938760","loc":[-85.3802485,42.0016002]},"n1820938761":{"id":"n1820938761","loc":[-85.3945822,42.0057938]},"n1820938762":{"id":"n1820938762","loc":[-85.5273237,41.9713017]},"n1820938763":{"id":"n1820938763","loc":[-85.2868862,41.9798629]},"n1820938764":{"id":"n1820938764","loc":[-85.2516677,42.0107899]},"n1820938766":{"id":"n1820938766","loc":[-85.3183002,41.9693103]},"n1820938768":{"id":"n1820938768","loc":[-85.2159042,42.0401932]},"n1820938770":{"id":"n1820938770","loc":[-85.0094481,42.0911141]},"n1820938771":{"id":"n1820938771","loc":[-85.0244538,42.0922155]},"n1820938772":{"id":"n1820938772","loc":[-85.231697,42.028862]},"n1820938773":{"id":"n1820938773","loc":[-85.2102394,42.0390617]},"n1820938774":{"id":"n1820938774","loc":[-85.2463419,42.0151212]},"n1820938775":{"id":"n1820938775","loc":[-85.0726195,42.1056424]},"n1820938776":{"id":"n1820938776","loc":[-85.0060431,42.0883262]},"n1820938778":{"id":"n1820938778","loc":[-85.425889,42.0056982]},"n1820938779":{"id":"n1820938779","loc":[-85.1183042,42.0820638]},"n1820938780":{"id":"n1820938780","loc":[-85.441596,42.0058257]},"n1820938781":{"id":"n1820938781","loc":[-85.1124879,42.0847086]},"n1820938782":{"id":"n1820938782","loc":[-85.2452733,42.0153894]},"n1820938783":{"id":"n1820938783","loc":[-85.2741191,41.9969244]},"n1820938784":{"id":"n1820938784","loc":[-85.2829487,41.9822236]},"n1820938785":{"id":"n1820938785","loc":[-85.3202743,41.972142]},"n1820938786":{"id":"n1820938786","loc":[-85.2345402,42.0266465]},"n1820938787":{"id":"n1820938787","loc":[-85.3037626,41.9724611]},"n1820938789":{"id":"n1820938789","loc":[-85.2474792,42.0161973]},"n1820938790":{"id":"n1820938790","loc":[-85.2951045,41.9727323]},"n1820938791":{"id":"n1820938791","loc":[-85.322345,41.9712726]},"n1820938792":{"id":"n1820938792","loc":[-85.2402372,42.0110394]},"n1820938793":{"id":"n1820938793","loc":[-85.5135693,41.9698659]},"n1820938794":{"id":"n1820938794","loc":[-85.4695339,41.9967366]},"n1820938796":{"id":"n1820938796","loc":[-85.0418492,42.1011131]},"n1820938797":{"id":"n1820938797","loc":[-85.3334107,41.9806337]},"n1820938798":{"id":"n1820938798","loc":[-85.5625314,41.9711685]},"n1820938799":{"id":"n1820938799","loc":[-85.3755707,41.9973585]},"n1820938800":{"id":"n1820938800","loc":[-85.5227532,41.9722429]},"n1820938801":{"id":"n1820938801","loc":[-85.4267687,42.0052836]},"n1820938803":{"id":"n1820938803","loc":[-85.0284704,42.0940837]},"n1820938804":{"id":"n1820938804","loc":[-85.015585,42.0885305]},"n1820938805":{"id":"n1820938805","loc":[-85.0765905,42.1053865]},"n1820938806":{"id":"n1820938806","loc":[-85.2614953,41.9964551]},"n1820938808":{"id":"n1820938808","loc":[-85.0307355,42.0947313]},"n1820938810":{"id":"n1820938810","loc":[-85.3894753,42.0003565]},"n1820938812":{"id":"n1820938812","loc":[-85.0868848,42.095006]},"n1820938813":{"id":"n1820938813","loc":[-85.3854198,42.0009465]},"n1820938814":{"id":"n1820938814","loc":[-85.2659692,41.9993534]},"n1820938815":{"id":"n1820938815","loc":[-85.1234259,42.0765266]},"n1820938816":{"id":"n1820938816","loc":[-85.1426906,42.0648893]},"n1820938818":{"id":"n1820938818","loc":[-85.1014533,42.0893067]},"n1820938819":{"id":"n1820938819","loc":[-85.0883064,42.098067]},"n1820938820":{"id":"n1820938820","loc":[-85.0503156,42.102704]},"n1820938821":{"id":"n1820938821","loc":[-85.1179649,42.0821884]},"n1820938822":{"id":"n1820938822","loc":[-85.3484697,41.9921596]},"n1820938823":{"id":"n1820938823","loc":[-85.3732962,41.9970874]},"n1820938824":{"id":"n1820938824","loc":[-85.2784104,41.9898312]},"n1820938825":{"id":"n1820938825","loc":[-85.4441709,42.0052198]},"n1820938826":{"id":"n1820938826","loc":[-85.3925438,42.0038326]},"n1820938829":{"id":"n1820938829","loc":[-85.5717582,41.9621861]},"n1820938830":{"id":"n1820938830","loc":[-85.0866314,42.0995051]},"n1820938831":{"id":"n1820938831","loc":[-85.576672,41.9522769]},"n1820938832":{"id":"n1820938832","loc":[-85.1587238,42.0636205]},"n1820938833":{"id":"n1820938833","loc":[-85.3804245,41.9999155]},"n1820938834":{"id":"n1820938834","loc":[-85.280083,41.9948843]},"n1820938836":{"id":"n1820938836","loc":[-85.561892,41.9686693]},"n1820938837":{"id":"n1820938837","loc":[-85.0158975,42.0885253]},"n1820938838":{"id":"n1820938838","loc":[-85.4248204,42.007633]},"n1820938839":{"id":"n1820938839","loc":[-85.0352738,42.1039657]},"n1820938840":{"id":"n1820938840","loc":[-85.211956,42.0411812]},"n1820938841":{"id":"n1820938841","loc":[-85.4816575,41.9908997]},"n1820938842":{"id":"n1820938842","loc":[-85.3807635,42.0020308]},"n1820938843":{"id":"n1820938843","loc":[-85.0100865,42.0898521]},"n1820938844":{"id":"n1820938844","loc":[-85.0103936,42.0897434]},"n1820938848":{"id":"n1820938848","loc":[-85.2430052,42.0131363]},"n1820938849":{"id":"n1820938849","loc":[-85.112559,42.0853723]},"n1820938851":{"id":"n1820938851","loc":[-85.3641553,41.9952535]},"n1820938852":{"id":"n1820938852","loc":[-85.2087373,42.0390777]},"n1820938853":{"id":"n1820938853","loc":[-85.2473933,42.0148263]},"n1820938854":{"id":"n1820938854","loc":[-85.0213464,42.090509]},"n1820938855":{"id":"n1820938855","loc":[-85.0673208,42.1052353]},"n1820938856":{"id":"n1820938856","loc":[-85.1003053,42.0905528]},"n1820938857":{"id":"n1820938857","loc":[-85.2617367,41.9965389]},"n1820938858":{"id":"n1820938858","loc":[-85.280363,41.9916015]},"n1820938859":{"id":"n1820938859","loc":[-85.0038866,42.0873469]},"n1820938860":{"id":"n1820938860","loc":[-85.2476401,42.0151451]},"n1820938861":{"id":"n1820938861","loc":[-85.193717,42.0499294]},"n1820938862":{"id":"n1820938862","loc":[-85.3478689,41.9917609]},"n1820938863":{"id":"n1820938863","loc":[-85.5638017,41.9648881]},"n1820938864":{"id":"n1820938864","loc":[-85.4356308,42.0064476]},"n1820938865":{"id":"n1820938865","loc":[-85.0561722,42.1023509]},"n1820938867":{"id":"n1820938867","loc":[-85.2256031,42.0356034]},"n1820938868":{"id":"n1820938868","loc":[-85.6102576,41.9420844]},"n1820938869":{"id":"n1820938869","loc":[-85.2285213,42.0339938]},"n1820938870":{"id":"n1820938870","loc":[-85.0326238,42.0978003]},"n1820938871":{"id":"n1820938871","loc":[-85.0131389,42.0903736]},"n1820938872":{"id":"n1820938872","loc":[-85.2550859,42.0012259]},"n1820938873":{"id":"n1820938873","loc":[-85.1130029,42.0846966]},"n1820938874":{"id":"n1820938874","loc":[-85.1579041,42.06336]},"n1820938875":{"id":"n1820938875","loc":[-85.0430522,42.1020234]},"n1820938876":{"id":"n1820938876","loc":[-85.2786679,41.9865935]},"n1820938877":{"id":"n1820938877","loc":[-85.1221666,42.0788706]},"n1820938878":{"id":"n1820938878","loc":[-85.2554614,42.0103303]},"n1820938879":{"id":"n1820938879","loc":[-85.2349801,42.0265748]},"n1820938880":{"id":"n1820938880","loc":[-85.0997434,42.0907864]},"n1820938881":{"id":"n1820938881","loc":[-85.0045464,42.0878167]},"n1820938882":{"id":"n1820938882","loc":[-85.2728048,41.9982519]},"n1820938883":{"id":"n1820938883","loc":[-85.3111333,41.9691587]},"n1820938884":{"id":"n1820938884","loc":[-85.3219802,41.9721899]},"n1820938885":{"id":"n1820938885","loc":[-85.3091378,41.9699325]},"n1820938887":{"id":"n1820938887","loc":[-85.4242367,42.0085203]},"n1820938888":{"id":"n1820938888","loc":[-84.9968377,42.0874504]},"n1820938890":{"id":"n1820938890","loc":[-85.5443139,41.9714078]},"n1820938891":{"id":"n1820938891","loc":[-85.6404013,41.9154676]},"n1820938892":{"id":"n1820938892","loc":[-85.3644986,41.9962582]},"n1820938893":{"id":"n1820938893","loc":[-85.0496772,42.1018323]},"n1820938894":{"id":"n1820938894","loc":[-85.297261,41.9737373]},"n1820938895":{"id":"n1820938895","loc":[-85.0327096,42.098071]},"n1820938896":{"id":"n1820938896","loc":[-85.3856773,41.9996867]},"n1820938897":{"id":"n1820938897","loc":[-85.0493862,42.1015509]},"n1820938898":{"id":"n1820938898","loc":[-84.9969879,42.0876614]},"n1820938899":{"id":"n1820938899","loc":[-85.0848625,42.1013587]},"n1820938900":{"id":"n1820938900","loc":[-85.5853195,41.9479201]},"n1820938901":{"id":"n1820938901","loc":[-85.6329169,41.9387964]},"n1820938902":{"id":"n1820938902","loc":[-85.0843046,42.1029468]},"n1820938903":{"id":"n1820938903","loc":[-85.1228747,42.0778474]},"n1820938904":{"id":"n1820938904","loc":[-85.4855456,41.984095]},"n1820938905":{"id":"n1820938905","loc":[-85.0573269,42.1026801]},"n1820938906":{"id":"n1820938906","loc":[-85.2425868,42.0131523]},"n1820938907":{"id":"n1820938907","loc":[-85.1149622,42.0860053]},"n1820938908":{"id":"n1820938908","loc":[-85.4833097,41.9951578]},"n1820938909":{"id":"n1820938909","loc":[-85.075979,42.1056372]},"n1820938910":{"id":"n1820938910","loc":[-85.0338509,42.0977139]},"n1820938911":{"id":"n1820938911","loc":[-85.6384272,41.9115715]},"n1820938912":{"id":"n1820938912","loc":[-85.0458363,42.1004074]},"n1820938913":{"id":"n1820938913","loc":[-85.0592138,42.1048305]},"n1820938914":{"id":"n1820938914","loc":[-85.2807493,41.9916653]},"n1820938915":{"id":"n1820938915","loc":[-85.1103274,42.0864193]},"n1820938916":{"id":"n1820938916","loc":[-85.6267156,41.9404404]},"n1820938918":{"id":"n1820938918","loc":[-85.0331374,42.0982911]},"n1820938919":{"id":"n1820938919","loc":[-85.5637331,41.965409]},"n1820938920":{"id":"n1820938920","loc":[-85.5457515,41.9714237]},"n1820938922":{"id":"n1820938922","loc":[-85.082073,42.1030104]},"n1820938923":{"id":"n1820938923","loc":[-85.0780765,42.103102]},"n1820938924":{"id":"n1820938924","loc":[-85.4208035,42.0089508]},"n1820938925":{"id":"n1820938925","loc":[-85.3469934,41.9914795]},"n1820938926":{"id":"n1820938926","loc":[-85.0322,42.095619]},"n1820938927":{"id":"n1820938927","loc":[-85.4784431,41.9949401]},"n1820938928":{"id":"n1820938928","loc":[-85.1303095,42.0667523]},"n1820938929":{"id":"n1820938929","loc":[-85.2463784,42.0084781]},"n1820938930":{"id":"n1820938930","loc":[-85.6299986,41.9427707]},"n1820938931":{"id":"n1820938931","loc":[-85.6325907,41.9238499]},"n1820938932":{"id":"n1820938932","loc":[-85.4808464,41.9914476]},"n1820938934":{"id":"n1820938934","loc":[-85.2411599,42.0105292]},"n1820938935":{"id":"n1820938935","loc":[-85.0163213,42.0892379]},"n1820938936":{"id":"n1820938936","loc":[-85.3290934,41.9682322]},"n1820938937":{"id":"n1820938937","loc":[-85.4925623,41.9853231]},"n1820938938":{"id":"n1820938938","loc":[-85.0338294,42.09892]},"n1820938940":{"id":"n1820938940","loc":[-85.4174561,42.008903]},"n1820938941":{"id":"n1820938941","loc":[-85.1165595,42.0838845]},"n1820938942":{"id":"n1820938942","loc":[-85.2954585,41.9717192]},"n1820938943":{"id":"n1820938943","loc":[-85.6330199,41.9257338]},"n1820938944":{"id":"n1820938944","loc":[-85.2294654,42.0324478]},"n1820938945":{"id":"n1820938945","loc":[-85.5601282,41.9728914]},"n1820938946":{"id":"n1820938946","loc":[-85.1176324,42.08568]},"n1820938947":{"id":"n1820938947","loc":[-85.0210245,42.0906005]},"n1820938948":{"id":"n1820938948","loc":[-85.0251887,42.09253]},"n1820938949":{"id":"n1820938949","loc":[-85.0895832,42.0939551]},"n1820938950":{"id":"n1820938950","loc":[-84.9915109,42.085842]},"n1820938951":{"id":"n1820938951","loc":[-85.2187366,42.0393486]},"n1820938952":{"id":"n1820938952","loc":[-85.006605,42.087579]},"n1820938953":{"id":"n1820938953","loc":[-85.046641,42.1012393]},"n1820938954":{"id":"n1820938954","loc":[-85.052102,42.103695]},"n1820938955":{"id":"n1820938955","loc":[-85.283925,41.9912825]},"n1820938956":{"id":"n1820938956","loc":[-85.2326626,42.0316349]},"n1820938957":{"id":"n1820938957","loc":[-85.1174298,42.0859694]},"n1820938958":{"id":"n1820938958","loc":[-85.3802056,41.9994794]},"n1820938959":{"id":"n1820938959","loc":[-85.4586334,41.9999737]},"n1820938960":{"id":"n1820938960","loc":[-85.4302234,42.0069418]},"n1820938961":{"id":"n1820938961","loc":[-85.092201,42.0930674]},"n1820938962":{"id":"n1820938962","loc":[-85.3684511,41.9979382]},"n1820938963":{"id":"n1820938963","loc":[-85.4618735,42.0011856]},"n1820938964":{"id":"n1820938964","loc":[-85.4828205,41.9877793]},"n1820938965":{"id":"n1820938965","loc":[-85.0837789,42.1025726]},"n1820938966":{"id":"n1820938966","loc":[-85.0176195,42.090253]},"n1820938967":{"id":"n1820938967","loc":[-85.3801627,42.001074]},"n1820938968":{"id":"n1820938968","loc":[-85.4767007,41.994488]},"n1820938969":{"id":"n1820938969","loc":[-85.274268,41.9957495]},"n1820938970":{"id":"n1820938970","loc":[-85.2977438,41.9719506]},"n1820938971":{"id":"n1820938971","loc":[-85.2425546,42.0208682]},"n1820938972":{"id":"n1820938972","loc":[-85.2557082,42.002382]},"n1820938973":{"id":"n1820938973","loc":[-85.3187937,41.9691986]},"n1820938975":{"id":"n1820938975","loc":[-85.2448077,42.0153045]},"n1820938977":{"id":"n1820938977","loc":[-85.0343015,42.0997718]},"n1820938978":{"id":"n1820938978","loc":[-85.2449364,42.01874]},"n1820938979":{"id":"n1820938979","loc":[-85.2598391,41.9969602]},"n1820938980":{"id":"n1820938980","loc":[-85.4294724,42.0067665]},"n1820938981":{"id":"n1820938981","loc":[-85.428082,42.0055124]},"n1820938983":{"id":"n1820938983","loc":[-85.5436315,41.9717484]},"n1820938985":{"id":"n1820938985","loc":[-85.5978336,41.9407437]},"n1820938986":{"id":"n1820938986","loc":[-85.491661,41.9860249]},"n1820938987":{"id":"n1820938987","loc":[-85.4942789,41.9801392]},"n1820938988":{"id":"n1820938988","loc":[-85.0416306,42.1010841]},"n1820938989":{"id":"n1820938989","loc":[-85.2653644,41.9984433]},"n1820938990":{"id":"n1820938990","loc":[-85.1028266,42.0881124]},"n1820938991":{"id":"n1820938991","loc":[-85.0163146,42.0887932]},"n1820938992":{"id":"n1820938992","loc":[-85.5282209,41.9678112]},"n1820938993":{"id":"n1820938993","loc":[-85.5442752,41.9715888]},"n1820938994":{"id":"n1820938994","loc":[-85.5634327,41.9658558]},"n1820938995":{"id":"n1820938995","loc":[-85.0384227,42.1037627]},"n1820938996":{"id":"n1820938996","loc":[-85.1144258,42.0854439]},"n1820938997":{"id":"n1820938997","loc":[-85.1870651,42.0506305]},"n1820938998":{"id":"n1820938998","loc":[-85.1256159,42.0747376]},"n1820938999":{"id":"n1820938999","loc":[-85.3272695,41.9715836]},"n1820939000":{"id":"n1820939000","loc":[-85.0543067,42.103098]},"n1820939001":{"id":"n1820939001","loc":[-85.4678173,41.9973585]},"n1820939003":{"id":"n1820939003","loc":[-85.0266626,42.0933154]},"n1820939004":{"id":"n1820939004","loc":[-85.0353046,42.1019728]},"n1820939005":{"id":"n1820939005","loc":[-85.1237961,42.0762798]},"n1820939006":{"id":"n1820939006","loc":[-85.2812214,41.9826702]},"n1820939007":{"id":"n1820939007","loc":[-85.2927763,41.9747343]},"n1820939008":{"id":"n1820939008","loc":[-85.3270979,41.9720862]},"n1820939009":{"id":"n1820939009","loc":[-85.488657,41.9856581]},"n1820939010":{"id":"n1820939010","loc":[-85.3087301,41.9701399]},"n1820939011":{"id":"n1820939011","loc":[-85.0276939,42.093768]},"n1820939012":{"id":"n1820939012","loc":[-85.2956516,41.9748779]},"n1820939013":{"id":"n1820939013","loc":[-85.1298579,42.0726443]},"n1820939014":{"id":"n1820939014","loc":[-85.105144,42.0870893]},"n1820939015":{"id":"n1820939015","loc":[-85.0677486,42.1053917]},"n1820939016":{"id":"n1820939016","loc":[-85.0333681,42.0993459]},"n1820939017":{"id":"n1820939017","loc":[-85.6384272,41.910805]},"n1820939018":{"id":"n1820939018","loc":[-85.399496,42.006894]},"n1820939019":{"id":"n1820939019","loc":[-85.2648427,41.9998318]},"n1820939020":{"id":"n1820939020","loc":[-85.1237424,42.0766779]},"n1820939021":{"id":"n1820939021","loc":[-85.2515025,42.0109442]},"n1820939022":{"id":"n1820939022","loc":[-85.5566306,41.9718385]},"n1820939023":{"id":"n1820939023","loc":[-85.090644,42.0938369]},"n1820939024":{"id":"n1820939024","loc":[-85.1245525,42.074914]},"n1820939025":{"id":"n1820939025","loc":[-85.1099934,42.0863926]},"n1820939026":{"id":"n1820939026","loc":[-85.1251653,42.0744589]},"n1820939027":{"id":"n1820939027","loc":[-85.401792,42.0068143]},"n1820939028":{"id":"n1820939028","loc":[-85.0094763,42.0899584]},"n1820939029":{"id":"n1820939029","loc":[-85.1330779,42.0705605]},"n1820939030":{"id":"n1820939030","loc":[-85.4935064,41.984398]},"n1820939031":{"id":"n1820939031","loc":[-85.5713334,41.9613939]},"n1820939032":{"id":"n1820939032","loc":[-85.0873945,42.0964669]},"n1820939033":{"id":"n1820939033","loc":[-85.0886497,42.0986481]},"n1820939034":{"id":"n1820939034","loc":[-85.3276343,41.9758897]},"n1820939035":{"id":"n1820939035","loc":[-85.1304386,42.0727387]},"n1820939036":{"id":"n1820939036","loc":[-85.2551932,42.0052999]},"n1820939037":{"id":"n1820939037","loc":[-85.2206936,42.0384458]},"n1820939038":{"id":"n1820939038","loc":[-85.2313645,42.0286389]},"n1820939039":{"id":"n1820939039","loc":[-85.0754586,42.1059835]},"n1820939040":{"id":"n1820939040","loc":[-85.0663324,42.1050812]},"n1820939041":{"id":"n1820939041","loc":[-85.2406234,42.0106887]},"n1820939042":{"id":"n1820939042","loc":[-85.0685962,42.1058175]},"n1820939043":{"id":"n1820939043","loc":[-85.0689462,42.1059437]},"n1820939044":{"id":"n1820939044","loc":[-85.0586144,42.1046144]},"n1820939045":{"id":"n1820939045","loc":[-85.3650565,41.9965452]},"n1820939047":{"id":"n1820939047","loc":[-85.5752558,41.9536014]},"n1820939048":{"id":"n1820939048","loc":[-85.5110159,41.9710624]},"n1820939050":{"id":"n1820939050","loc":[-85.2832641,41.9926477]},"n1820939051":{"id":"n1820939051","loc":[-85.0078402,42.0898947]},"n1820939052":{"id":"n1820939052","loc":[-85.3882737,42.0017916]},"n1820939053":{"id":"n1820939053","loc":[-85.1718945,42.0564937]},"n1820939054":{"id":"n1820939054","loc":[-85.0947048,42.0929293]},"n1820939055":{"id":"n1820939055","loc":[-85.4456944,42.0051082]},"n1820939056":{"id":"n1820939056","loc":[-85.3139872,41.9706903]},"n1820939057":{"id":"n1820939057","loc":[-85.3893895,42.0034021]},"n1820939058":{"id":"n1820939058","loc":[-85.2425332,42.0106089]},"n1820939059":{"id":"n1820939059","loc":[-85.6085624,41.9420844]},"n1820939060":{"id":"n1820939060","loc":[-85.210411,42.0397789]},"n1820939061":{"id":"n1820939061","loc":[-85.2762542,41.9960473]},"n1820939062":{"id":"n1820939062","loc":[-85.4686584,41.9969973]},"n1820939063":{"id":"n1820939063","loc":[-85.3860421,42.0018394]},"n1820939064":{"id":"n1820939064","loc":[-85.5636944,41.9644414]},"n1820939065":{"id":"n1820939065","loc":[-85.3267331,41.9766554]},"n1820939066":{"id":"n1820939066","loc":[-85.0868996,42.0943822]},"n1820939067":{"id":"n1820939067","loc":[-85.104861,42.0880038]},"n1820939068":{"id":"n1820939068","loc":[-85.5537123,41.9695093]},"n1820939069":{"id":"n1820939069","loc":[-85.6325092,41.9396743]},"n1820939070":{"id":"n1820939070","loc":[-85.3869648,42.0024454]},"n1820939071":{"id":"n1820939071","loc":[-85.2775349,41.9957335]},"n1820939072":{"id":"n1820939072","loc":[-85.2055616,42.0421533]},"n1820939073":{"id":"n1820939073","loc":[-85.4731431,41.9946531]},"n1820939074":{"id":"n1820939074","loc":[-85.0399609,42.1030833]},"n1820939075":{"id":"n1820939075","loc":[-85.3055758,41.9725169]},"n1820939076":{"id":"n1820939076","loc":[-85.4834599,41.994488]},"n1820939077":{"id":"n1820939077","loc":[-85.3819866,42.0023018]},"n1820939078":{"id":"n1820939078","loc":[-85.1218756,42.0789992]},"n1820939079":{"id":"n1820939079","loc":[-85.2793159,41.9944458]},"n1820939080":{"id":"n1820939080","loc":[-85.2495498,42.0101466]},"n1820939081":{"id":"n1820939081","loc":[-85.0035969,42.0872434]},"n1820939082":{"id":"n1820939082","loc":[-85.1054243,42.0865626]},"n1820939083":{"id":"n1820939083","loc":[-85.0917665,42.0934774]},"n1820939084":{"id":"n1820939084","loc":[-85.3442211,41.988938]},"n1820939086":{"id":"n1820939086","loc":[-85.273989,41.9953588]},"n1820939087":{"id":"n1820939087","loc":[-85.1142541,42.0852488]},"n1820939089":{"id":"n1820939089","loc":[-85.1526684,42.0615758]},"n1820939090":{"id":"n1820939090","loc":[-85.2538843,42.0110159]},"n1820939091":{"id":"n1820939091","loc":[-85.28341,41.9909635]},"n1820939092":{"id":"n1820939092","loc":[-85.3963178,42.0050217]},"n1820939093":{"id":"n1820939093","loc":[-85.0851682,42.1012472]},"n1820939095":{"id":"n1820939095","loc":[-85.2811784,41.986243]},"n1820939096":{"id":"n1820939096","loc":[-85.4274125,42.0052995]},"n1820939097":{"id":"n1820939097","loc":[-85.0871262,42.0951652]},"n1820939099":{"id":"n1820939099","loc":[-85.1314253,42.0671665]},"n1820939100":{"id":"n1820939100","loc":[-85.2778997,41.991001]},"n1820939101":{"id":"n1820939101","loc":[-85.112107,42.0862812]},"n1820939102":{"id":"n1820939102","loc":[-85.299911,41.9729955]},"n1820939103":{"id":"n1820939103","loc":[-85.639822,41.9094796]},"n1820939104":{"id":"n1820939104","loc":[-85.122294,42.0785334]},"n1820939105":{"id":"n1820939105","loc":[-85.2476294,42.015719]},"n1820939106":{"id":"n1820939106","loc":[-85.4946007,41.9814631]},"n1820939107":{"id":"n1820939107","loc":[-85.0879524,42.0986919]},"n1820939108":{"id":"n1820939108","loc":[-85.0342814,42.098274]},"n1820939109":{"id":"n1820939109","loc":[-85.2450695,42.0095463]},"n1820939110":{"id":"n1820939110","loc":[-85.3847546,42.0024135]},"n1820939111":{"id":"n1820939111","loc":[-85.2961344,41.9742558]},"n1820939112":{"id":"n1820939112","loc":[-85.27899,41.994317]},"n1820939114":{"id":"n1820939114","loc":[-85.1017644,42.0886618]},"n1820939115":{"id":"n1820939115","loc":[-85.076215,42.1056333]},"n1820939116":{"id":"n1820939116","loc":[-85.1198009,42.0805349]},"n1820939117":{"id":"n1820939117","loc":[-85.11988,42.0798513]},"n1820939118":{"id":"n1820939118","loc":[-85.147819,42.0625476]},"n1820939119":{"id":"n1820939119","loc":[-85.0585969,42.1029042]},"n1820939120":{"id":"n1820939120","loc":[-85.1248596,42.0745744]},"n1820939121":{"id":"n1820939121","loc":[-85.3023786,41.9725249]},"n1820939123":{"id":"n1820939123","loc":[-85.0119332,42.0900699]},"n1820939124":{"id":"n1820939124","loc":[-85.2466852,42.0170343]},"n1820939125":{"id":"n1820939125","loc":[-85.0033019,42.0872792]},"n1820939126":{"id":"n1820939126","loc":[-85.0042084,42.0875778]},"n1820939128":{"id":"n1820939128","loc":[-85.0052961,42.0885424]},"n1820939130":{"id":"n1820939130","loc":[-85.0647942,42.10508]},"n1820939131":{"id":"n1820939131","loc":[-85.2824123,41.9825107]},"n1820939132":{"id":"n1820939132","loc":[-85.3210039,41.9723255]},"n1820939133":{"id":"n1820939133","loc":[-85.0491033,42.1014184]},"n1820939134":{"id":"n1820939134","loc":[-85.1127776,42.0855168]},"n1820939135":{"id":"n1820939135","loc":[-85.1243768,42.0759322]},"n1820939137":{"id":"n1820939137","loc":[-85.125974,42.0747547]},"n1820939138":{"id":"n1820939138","loc":[-85.1071248,42.0859973]},"n1820939139":{"id":"n1820939139","loc":[-85.5326175,41.9674833]},"n1820939140":{"id":"n1820939140","loc":[-85.1338715,42.0660833]},"n1820939142":{"id":"n1820939142","loc":[-85.649671,41.9135675]},"n1820939144":{"id":"n1820939144","loc":[-85.0236545,42.0920444]},"n1820939145":{"id":"n1820939145","loc":[-85.1084391,42.0859376]},"n1820939146":{"id":"n1820939146","loc":[-85.1539988,42.0618626]},"n1820939147":{"id":"n1820939147","loc":[-85.2354521,42.026511]},"n1820939148":{"id":"n1820939148","loc":[-85.2362246,42.0260408]},"n1820939149":{"id":"n1820939149","loc":[-85.2401342,42.0115233]},"n1820939150":{"id":"n1820939150","loc":[-85.295319,41.9747423]},"n1820939151":{"id":"n1820939151","loc":[-85.1164696,42.0835409]},"n1820939152":{"id":"n1820939152","loc":[-85.3232891,41.9712885]},"n1820939153":{"id":"n1820939153","loc":[-85.2574463,42.0068944]},"n1820939155":{"id":"n1820939155","loc":[-85.5704064,41.9598246]},"n1820939156":{"id":"n1820939156","loc":[-85.0349077,42.0998116]},"n1820939157":{"id":"n1820939157","loc":[-85.0949529,42.0925619]},"n1820939159":{"id":"n1820939159","loc":[-85.0179829,42.0902343]},"n1820939160":{"id":"n1820939160","loc":[-85.0405832,42.1016942]},"n1820939161":{"id":"n1820939161","loc":[-85.2534015,42.0111833]},"n1820939162":{"id":"n1820939162","loc":[-85.0839881,42.102708]},"n1820939163":{"id":"n1820939163","loc":[-85.0341996,42.1008385]},"n1820939164":{"id":"n1820939164","loc":[-85.1037761,42.0879731]},"n1820939173":{"id":"n1820939173","loc":[-85.0460616,42.1005786]},"n1820939177":{"id":"n1820939177","loc":[-85.0061651,42.0878059]},"n1820939181":{"id":"n1820939181","loc":[-85.1456775,42.0654684]},"n1820939183":{"id":"n1820939183","loc":[-85.1325508,42.0718439]},"n1820939185":{"id":"n1820939185","loc":[-85.2485842,42.008329]},"n1820939187":{"id":"n1820939187","loc":[-85.2744128,41.9949322]},"n1820939189":{"id":"n1820939189","loc":[-85.2579025,41.9999542]},"n1820939191":{"id":"n1820939191","loc":[-85.3358998,41.9828987]},"n1820939193":{"id":"n1820939193","loc":[-85.3192658,41.9716714]},"n1820939194":{"id":"n1820939194","loc":[-85.6400795,41.9130725]},"n1820939195":{"id":"n1820939195","loc":[-85.3278489,41.9780591]},"n1820939196":{"id":"n1820939196","loc":[-85.2800197,41.983061]},"n1820939197":{"id":"n1820939197","loc":[-85.3278167,41.9692943]},"n1820939198":{"id":"n1820939198","loc":[-85.3366894,41.9838653]},"n1820939199":{"id":"n1820939199","loc":[-85.0328383,42.0969923]},"n1820939201":{"id":"n1820939201","loc":[-85.3259284,41.9720383]},"n1820939217":{"id":"n1820939217","loc":[-85.1840181,42.0503277]},"n1820939220":{"id":"n1820939220","loc":[-85.422563,42.0089986]},"n1820939222":{"id":"n1820939222","loc":[-85.555386,41.9707856]},"n1820939224":{"id":"n1820939224","loc":[-85.3830809,42.002254]},"n1820939226":{"id":"n1820939226","loc":[-84.9917938,42.0857517]},"n1820939227":{"id":"n1820939227","loc":[-85.2936775,41.9740484]},"n1820939228":{"id":"n1820939228","loc":[-85.2632133,41.9975024]},"n1820939229":{"id":"n1820939229","loc":[-85.2809424,41.9853259]},"n1820939230":{"id":"n1820939230","loc":[-85.242104,42.0131204]},"n1820939232":{"id":"n1820939232","loc":[-85.2610246,41.9963901]},"n1820939233":{"id":"n1820939233","loc":[-85.2335531,42.0268378]},"n1820939234":{"id":"n1820939234","loc":[-85.3188839,41.9713575]},"n1820939235":{"id":"n1820939235","loc":[-85.2413637,42.0225658]},"n1820939237":{"id":"n1820939237","loc":[-85.0010796,42.0887215]},"n1820939239":{"id":"n1820939239","loc":[-85.2241697,42.0362624]},"n1820939243":{"id":"n1820939243","loc":[-85.0368456,42.1040134]},"n1820939244":{"id":"n1820939244","loc":[-85.1327986,42.069524]},"n1820939260":{"id":"n1820939260","loc":[-85.5408163,41.9711206]},"n1820939261":{"id":"n1820939261","loc":[-85.2959199,41.9746546]},"n1820939262":{"id":"n1820939262","loc":[-85.3298659,41.9683598]},"n1820939263":{"id":"n1820939263","loc":[-85.2240581,42.0358425]},"n1820939264":{"id":"n1820939264","loc":[-85.2438206,42.0101944]},"n1820939265":{"id":"n1820939265","loc":[-85.3984489,42.0059589]},"n1820939266":{"id":"n1820939266","loc":[-85.2330811,42.0294279]},"n1820939268":{"id":"n1820939268","loc":[-85.1126877,42.0857704]},"n1820939271":{"id":"n1820939271","loc":[-85.254925,42.0106253]},"n1820939273":{"id":"n1820939273","loc":[-85.4328046,42.0064662]},"n1820939277":{"id":"n1820939277","loc":[-85.289622,41.9789616]},"n1820939279":{"id":"n1820939279","loc":[-85.4574532,42.0004043]},"n1820939281":{"id":"n1820939281","loc":[-85.4803486,41.9867211]},"n1820939283":{"id":"n1820939283","loc":[-85.157475,42.0631848]},"n1820939285":{"id":"n1820939285","loc":[-85.2571458,42.0059935]},"n1820939287":{"id":"n1820939287","loc":[-85.2818544,41.9825984]},"n1820939289":{"id":"n1820939289","loc":[-85.2298302,42.0328781]},"n1820939291":{"id":"n1820939291","loc":[-85.4819523,41.984821]},"n1820939301":{"id":"n1820939301","loc":[-85.3139765,41.9701159]},"n1820939304":{"id":"n1820939304","loc":[-85.0424447,42.101742]},"n1820939306":{"id":"n1820939306","loc":[-85.6360283,41.9338482]},"n1820939310":{"id":"n1820939310","loc":[-85.3463025,41.9913622]},"n1820939312":{"id":"n1820939312","loc":[-85.4664869,41.9988097]},"n1820939314":{"id":"n1820939314","loc":[-85.149364,42.0622449]},"n1820939316":{"id":"n1820939316","loc":[-85.2460415,42.0153125]},"n1820939318":{"id":"n1820939318","loc":[-85.4806103,41.9924523]},"n1820939320":{"id":"n1820939320","loc":[-85.2449042,42.0190987]},"n1820939322":{"id":"n1820939322","loc":[-85.5280165,41.9689263]},"n1820939324":{"id":"n1820939324","loc":[-85.0051204,42.0882625]},"n1820939326":{"id":"n1820939326","loc":[-85.1240925,42.0771546]},"n1820939329":{"id":"n1820939329","loc":[-85.2261653,42.0342225]},"n1820939331":{"id":"n1820939331","loc":[-85.5259933,41.972211]},"n1820939333":{"id":"n1820939333","loc":[-85.0074754,42.0883183]},"n1820939335":{"id":"n1820939335","loc":[-85.0764014,42.1055549]},"n1820939336":{"id":"n1820939336","loc":[-85.2908773,41.9769597]},"n1820939337":{"id":"n1820939337","loc":[-85.4095382,42.0083449]},"n1820939346":{"id":"n1820939346","loc":[-85.2514166,42.0111753]},"n1820939348":{"id":"n1820939348","loc":[-85.0030377,42.0873799]},"n1820939350":{"id":"n1820939350","loc":[-85.3659362,41.9964974]},"n1820939352":{"id":"n1820939352","loc":[-85.226058,42.0348281]},"n1820939355":{"id":"n1820939355","loc":[-85.1902408,42.0507101]},"n1820939357":{"id":"n1820939357","loc":[-85.2781854,41.9946001]},"n1820939359":{"id":"n1820939359","loc":[-85.2139988,42.0405175]},"n1820939361":{"id":"n1820939361","loc":[-85.0086609,42.0908262]},"n1820939363":{"id":"n1820939363","loc":[-85.0627128,42.1043398]},"n1820939365":{"id":"n1820939365","loc":[-85.1311346,42.072501]},"n1820939369":{"id":"n1820939369","loc":[-85.248198,42.0082652]},"n1820939370":{"id":"n1820939370","loc":[-84.99792,42.087794]},"n1820939371":{"id":"n1820939371","loc":[-85.2786775,41.9942783]},"n1820939372":{"id":"n1820939372","loc":[-85.0342103,42.1013957]},"n1820939373":{"id":"n1820939373","loc":[-85.2022357,42.0444799]},"n1820939374":{"id":"n1820939374","loc":[-85.2279205,42.0337388]},"n1820939375":{"id":"n1820939375","loc":[-85.1337699,42.0712614]},"n1820939376":{"id":"n1820939376","loc":[-85.317517,41.9707062]},"n1820939377":{"id":"n1820939377","loc":[-85.1326326,42.070218]},"n1820939394":{"id":"n1820939394","loc":[-85.0197746,42.0899118]},"n1820939397":{"id":"n1820939397","loc":[-85.2590076,41.9984632]},"n1820939399":{"id":"n1820939399","loc":[-85.2469964,42.0083449]},"n1820939400":{"id":"n1820939400","loc":[-85.2470929,42.0146668]},"n1820939401":{"id":"n1820939401","loc":[-84.9984095,42.0878087]},"n1820939402":{"id":"n1820939402","loc":[-85.2372653,42.0243273]},"n1820939403":{"id":"n1820939403","loc":[-85.2454986,42.0091955]},"n1820939404":{"id":"n1820939404","loc":[-85.0539205,42.1035995]},"n1820939405":{"id":"n1820939405","loc":[-85.550601,41.9706101]},"n1820939406":{"id":"n1820939406","loc":[-85.0351343,42.0999656]},"n1820939407":{"id":"n1820939407","loc":[-85.0082908,42.0905755]},"n1820939408":{"id":"n1820939408","loc":[-85.0132904,42.0902251]},"n1820939410":{"id":"n1820939410","loc":[-85.0892546,42.094012]},"n1820939412":{"id":"n1820939412","loc":[-85.0350793,42.1030315]},"n1820939416":{"id":"n1820939416","loc":[-85.0012406,42.0886777]},"n1820939418":{"id":"n1820939418","loc":[-85.0577453,42.1029229]},"n1820939420":{"id":"n1820939420","loc":[-85.1230786,42.0776722]},"n1820939422":{"id":"n1820939422","loc":[-85.571136,41.9649304]},"n1820939436":{"id":"n1820939436","loc":[-85.1137968,42.0848997]},"n1820939437":{"id":"n1820939437","loc":[-85.3559584,41.9925105]},"n1820939438":{"id":"n1820939438","loc":[-85.0080172,42.0903565]},"n1820939439":{"id":"n1820939439","loc":[-85.0048897,42.0880913]},"n1820939441":{"id":"n1820939441","loc":[-85.0406959,42.1018574]},"n1820939443":{"id":"n1820939443","loc":[-85.3897328,42.0029078]},"n1820939445":{"id":"n1820939445","loc":[-85.122349,42.0782814]},"n1820939448":{"id":"n1820939448","loc":[-85.4872193,41.985036]},"n1820939450":{"id":"n1820939450","loc":[-85.0120459,42.0904919]},"n1820939452":{"id":"n1820939452","loc":[-85.6320543,41.921982]},"n1820939456":{"id":"n1820939456","loc":[-85.0844749,42.1036843]},"n1820939458":{"id":"n1820939458","loc":[-85.0968037,42.091296]},"n1820939463":{"id":"n1820939463","loc":[-85.5339747,41.9681841]},"n1820939465":{"id":"n1820939465","loc":[-85.4125423,42.0072129]},"n1820939467":{"id":"n1820939467","loc":[-85.6335563,41.9303626]},"n1820939469":{"id":"n1820939469","loc":[-85.2821014,41.9932126]},"n1820939471":{"id":"n1820939471","loc":[-85.374691,41.9969917]},"n1820939485":{"id":"n1820939485","loc":[-85.4471321,42.0049806]},"n1820939487":{"id":"n1820939487","loc":[-85.3752532,41.9972206]},"n1820939489":{"id":"n1820939489","loc":[-85.4517283,42.005927]},"n1820939492":{"id":"n1820939492","loc":[-85.4662552,42.0005693]},"n1820939494":{"id":"n1820939494","loc":[-85.0120083,42.0902928]},"n1820939496":{"id":"n1820939496","loc":[-85.044463,42.1004631]},"n1820939498":{"id":"n1820939498","loc":[-85.418293,42.0089667]},"n1820939500":{"id":"n1820939500","loc":[-85.0554762,42.1027358]},"n1820939504":{"id":"n1820939504","loc":[-85.1246289,42.0746858]},"n1820939507":{"id":"n1820939507","loc":[-85.0408139,42.1021838]},"n1820939508":{"id":"n1820939508","loc":[-85.1236204,42.0775169]},"n1820939509":{"id":"n1820939509","loc":[-85.0350109,42.1037428]},"n1820939510":{"id":"n1820939510","loc":[-85.0551583,42.1029878]},"n1820939511":{"id":"n1820939511","loc":[-85.0956771,42.0916662]},"n1820939512":{"id":"n1820939512","loc":[-85.2323408,42.0273638]},"n1820939513":{"id":"n1820939513","loc":[-85.1232771,42.0762388]},"n1820939531":{"id":"n1820939531","loc":[-85.264608,41.9997828]},"n1820939533":{"id":"n1820939533","loc":[-85.4198808,42.0087914]},"n1820939535":{"id":"n1820939535","loc":[-85.3080864,41.9715677]},"n1820939536":{"id":"n1820939536","loc":[-85.1189426,42.0812596]},"n1820939537":{"id":"n1820939537","loc":[-85.2642741,41.9996764]},"n1820939538":{"id":"n1820939538","loc":[-85.2572531,42.0079627]},"n1820939539":{"id":"n1820939539","loc":[-85.2907807,41.9790174]},"n1820939540":{"id":"n1820939540","loc":[-85.3171415,41.9707301]},"n1820939541":{"id":"n1820939541","loc":[-85.08777,42.0953841]},"n1820939542":{"id":"n1820939542","loc":[-85.1239262,42.0773218]},"n1820939543":{"id":"n1820939543","loc":[-84.9973956,42.0877968]},"n1820939544":{"id":"n1820939544","loc":[-85.011606,42.0896161]},"n1820939545":{"id":"n1820939545","loc":[-85.4077358,42.0082971]},"n1820939546":{"id":"n1820939546","loc":[-85.3614945,41.9933717]},"n1820939547":{"id":"n1820939547","loc":[-85.3189118,41.9697649]},"n1820939550":{"id":"n1820939550","loc":[-85.1262691,42.0740221]},"n1820939551":{"id":"n1820939551","loc":[-85.3863639,41.9994635]},"n1820939552":{"id":"n1820939552","loc":[-85.2836034,41.9923953]},"n1820939554":{"id":"n1820939554","loc":[-85.3222377,41.9715916]},"n1820939555":{"id":"n1820939555","loc":[-85.0122658,42.0906312]},"n1820939556":{"id":"n1820939556","loc":[-85.0022652,42.0877581]},"n1820939557":{"id":"n1820939557","loc":[-85.1011314,42.0899954]},"n1820939559":{"id":"n1820939559","loc":[-85.0008181,42.0885293]},"n1820939561":{"id":"n1820939561","loc":[-85.3637046,41.9942488]},"n1820939562":{"id":"n1820939562","loc":[-85.4500117,42.0052892]},"n1820939563":{"id":"n1820939563","loc":[-85.0537636,42.1036365]},"n1820939565":{"id":"n1820939565","loc":[-85.2367503,42.0246939]},"n1820939566":{"id":"n1820939566","loc":[-85.0448479,42.1002653]},"n1820939567":{"id":"n1820939567","loc":[-85.6337065,41.9295006]},"n1820939568":{"id":"n1820939568","loc":[-85.0879792,42.095623]},"n1820939569":{"id":"n1820939569","loc":[-85.6347623,41.9352369]},"n1820939570":{"id":"n1820939570","loc":[-85.1497931,42.0620378]},"n1820939571":{"id":"n1820939571","loc":[-85.5676169,41.9656324]},"n1820939572":{"id":"n1820939572","loc":[-85.638041,41.9166971]},"n1820939573":{"id":"n1820939573","loc":[-85.4993429,41.9781293]},"n1820939574":{"id":"n1820939574","loc":[-85.5352831,41.9692127]},"n1820939575":{"id":"n1820939575","loc":[-84.9924429,42.0857118]},"n1820939577":{"id":"n1820939577","loc":[-85.0581101,42.1026721]},"n1820939578":{"id":"n1820939578","loc":[-85.641088,41.9094477]},"n1820939579":{"id":"n1820939579","loc":[-85.2548821,42.0052282]},"n1820939580":{"id":"n1820939580","loc":[-85.1124463,42.0859734]},"n1820939581":{"id":"n1820939581","loc":[-85.1083479,42.0857624]},"n1820939583":{"id":"n1820939583","loc":[-85.1387424,42.0648893]},"n1820939584":{"id":"n1820939584","loc":[-85.5152645,41.9700892]},"n1820939585":{"id":"n1820939585","loc":[-85.5463738,41.9713439]},"n1820939586":{"id":"n1820939586","loc":[-85.360207,41.9933717]},"n1820939587":{"id":"n1820939587","loc":[-85.2402372,42.0120917]},"n1820939588":{"id":"n1820939588","loc":[-85.3936381,42.0047255]},"n1820939589":{"id":"n1820939589","loc":[-85.3310246,41.973784]},"n1820939590":{"id":"n1820939590","loc":[-85.0329403,42.096642]},"n1820939591":{"id":"n1820939591","loc":[-85.0097271,42.0910981]},"n1820939593":{"id":"n1820939593","loc":[-85.0446562,42.1003437]},"n1820939595":{"id":"n1820939595","loc":[-85.0856671,42.1008452]},"n1820939596":{"id":"n1820939596","loc":[-85.4087228,42.0083449]},"n1820939597":{"id":"n1820939597","loc":[-85.0609519,42.1052564]},"n1820939598":{"id":"n1820939598","loc":[-85.3432126,41.9874548]},"n1820939599":{"id":"n1820939599","loc":[-85.4041738,42.0067027]},"n1820939600":{"id":"n1820939600","loc":[-85.0825437,42.1035768]},"n1820939601":{"id":"n1820939601","loc":[-85.048422,42.101498]},"n1820939602":{"id":"n1820939602","loc":[-85.0336256,42.0999031]},"n1820939603":{"id":"n1820939603","loc":[-85.046818,42.1014104]},"n1820939605":{"id":"n1820939605","loc":[-85.2856524,41.98078]},"n1820939607":{"id":"n1820939607","loc":[-85.1118173,42.0864245]},"n1820939609":{"id":"n1820939609","loc":[-85.0443397,42.1006263]},"n1820939610":{"id":"n1820939610","loc":[-85.0336698,42.0978361]},"n1820939611":{"id":"n1820939611","loc":[-85.4630322,42.0014248]},"n1820939612":{"id":"n1820939612","loc":[-85.0613127,42.1052353]},"n1820939613":{"id":"n1820939613","loc":[-85.0137571,42.0887801]},"n1820939614":{"id":"n1820939614","loc":[-85.272487,41.9982013]},"n1820939616":{"id":"n1820939616","loc":[-85.4665727,41.9983791]},"n1820939617":{"id":"n1820939617","loc":[-85.1288078,42.0725476]},"n1820939618":{"id":"n1820939618","loc":[-85.4653282,42.00109]},"n1820939619":{"id":"n1820939619","loc":[-85.2314717,42.0276746]},"n1820939620":{"id":"n1820939620","loc":[-85.255982,42.0003569]},"n1820939621":{"id":"n1820939621","loc":[-85.2886779,41.9787223]},"n1820939622":{"id":"n1820939622","loc":[-85.22438,42.0367509]},"n1820939623":{"id":"n1820939623","loc":[-85.0334713,42.0998382]},"n1820939624":{"id":"n1820939624","loc":[-85.2236504,42.037484]},"n1820939625":{"id":"n1820939625","loc":[-85.636908,41.9175162]},"n1820939627":{"id":"n1820939627","loc":[-85.2669187,41.9989707]},"n1820939628":{"id":"n1820939628","loc":[-85.3247268,41.9720702]},"n1820939629":{"id":"n1820939629","loc":[-85.3785104,41.9987299]},"n1820939630":{"id":"n1820939630","loc":[-85.5267658,41.9720515]},"n1820939631":{"id":"n1820939631","loc":[-85.2445116,42.0098811]},"n1820939632":{"id":"n1820939632","loc":[-85.1271448,42.0725077]},"n1820939633":{"id":"n1820939633","loc":[-85.0345751,42.099724]},"n1820939634":{"id":"n1820939634","loc":[-85.4217476,42.0089986]},"n1820939635":{"id":"n1820939635","loc":[-85.3121848,41.9689433]},"n1820939636":{"id":"n1820939636","loc":[-85.2826419,41.9929985]},"n1820939637":{"id":"n1820939637","loc":[-85.3160257,41.9706344]},"n1820939638":{"id":"n1820939638","loc":[-85.5684967,41.9657919]},"n1820939640":{"id":"n1820939640","loc":[-85.225131,42.0356194]},"n1820939642":{"id":"n1820939642","loc":[-85.1324124,42.0693328]},"n1820939644":{"id":"n1820939644","loc":[-84.9994073,42.0878843]},"n1820939645":{"id":"n1820939645","loc":[-85.1087596,42.0863329]},"n1820939646":{"id":"n1820939646","loc":[-85.2915532,41.9782996]},"n1820939647":{"id":"n1820939647","loc":[-84.9988708,42.0877808]},"n1820939648":{"id":"n1820939648","loc":[-85.2243628,42.0356728]},"n1820939649":{"id":"n1820939649","loc":[-85.0427397,42.1020524]},"n1820939650":{"id":"n1820939650","loc":[-85.6388392,41.9100752]},"n1820939651":{"id":"n1820939651","loc":[-85.0133709,42.0888557]},"n1820939652":{"id":"n1820939652","loc":[-85.318798,41.9701211]},"n1820939653":{"id":"n1820939653","loc":[-85.6335778,41.9190602]},"n1820939654":{"id":"n1820939654","loc":[-85.6338396,41.9370247]},"n1820939655":{"id":"n1820939655","loc":[-85.0939069,42.0931988]},"n1820939656":{"id":"n1820939656","loc":[-85.5702347,41.9651378]},"n1820939657":{"id":"n1820939657","loc":[-85.4235286,42.0088392]},"n1820939658":{"id":"n1820939658","loc":[-85.2740856,41.9972206]},"n1820939659":{"id":"n1820939659","loc":[-85.4824299,41.9934195]},"n1820939660":{"id":"n1820939660","loc":[-85.3857846,42.0014408]},"n1820939661":{"id":"n1820939661","loc":[-85.0451658,42.10028]},"n1820939662":{"id":"n1820939662","loc":[-85.3893036,42.001377]},"n1820939664":{"id":"n1820939664","loc":[-85.2455845,42.0088607]},"n1820939665":{"id":"n1820939665","loc":[-85.2741071,41.9951116]},"n1820939666":{"id":"n1820939666","loc":[-85.1298375,42.0677718]},"n1820939667":{"id":"n1820939667","loc":[-85.5491848,41.9707377]},"n1820939669":{"id":"n1820939669","loc":[-85.2780298,41.995238]},"n1820939670":{"id":"n1820939670","loc":[-85.1330068,42.0716926]},"n1820939671":{"id":"n1820939671","loc":[-85.0811342,42.1025129]},"n1820939672":{"id":"n1820939672","loc":[-85.2325124,42.0290135]},"n1820939673":{"id":"n1820939673","loc":[-85.2975077,41.9716953]},"n1820939674":{"id":"n1820939674","loc":[-85.0951729,42.0922394]},"n1820939676":{"id":"n1820939676","loc":[-85.0363252,42.1043119]},"n1820939677":{"id":"n1820939677","loc":[-85.2960057,41.97349]},"n1820939678":{"id":"n1820939678","loc":[-85.3701849,41.9982515]},"n1820939679":{"id":"n1820939679","loc":[-85.3381486,41.9848861]},"n1820939680":{"id":"n1820939680","loc":[-85.2058448,42.0417286]},"n1820939682":{"id":"n1820939682","loc":[-85.0819335,42.1034443]},"n1820939683":{"id":"n1820939683","loc":[-85.3872223,41.9993359]},"n1820939684":{"id":"n1820939684","loc":[-85.095366,42.091909]},"n1820939685":{"id":"n1820939685","loc":[-85.2327914,42.0291888]},"n1820939686":{"id":"n1820939686","loc":[-85.0433459,42.1018773]},"n1820939687":{"id":"n1820939687","loc":[-85.0585339,42.1027318]},"n1820939688":{"id":"n1820939688","loc":[-85.0062885,42.0876347]},"n1820939689":{"id":"n1820939689","loc":[-85.246299,42.017377]},"n1820939690":{"id":"n1820939690","loc":[-85.2932376,41.9742877]},"n1820939691":{"id":"n1820939691","loc":[-85.2962846,41.9736815]},"n1820939692":{"id":"n1820939692","loc":[-85.6052365,41.9409193]},"n1820939693":{"id":"n1820939693","loc":[-85.2570536,42.0003341]},"n1820939694":{"id":"n1820939694","loc":[-85.0488458,42.1014064]},"n1820939695":{"id":"n1820939695","loc":[-85.4050321,42.0069578]},"n1820939696":{"id":"n1820939696","loc":[-85.4847517,41.9845894]},"n1820939697":{"id":"n1820939697","loc":[-85.0844655,42.1013826]},"n1820939698":{"id":"n1820939698","loc":[-85.1437206,42.0650008]},"n1820939699":{"id":"n1820939699","loc":[-85.1168183,42.0864034]},"n1820939700":{"id":"n1820939700","loc":[-85.5479831,41.9711366]},"n1820939701":{"id":"n1820939701","loc":[-85.0349948,42.1034124]},"n1820939702":{"id":"n1820939702","loc":[-85.0835589,42.1038821]},"n1820939703":{"id":"n1820939703","loc":[-85.0203875,42.0902649]},"n1820939704":{"id":"n1820939704","loc":[-85.0371191,42.1038184]},"n1820939705":{"id":"n1820939705","loc":[-85.1273312,42.0735681]},"n1820939707":{"id":"n1820939707","loc":[-85.1272239,42.0730226]},"n1820939710":{"id":"n1820939710","loc":[-85.0349881,42.1019012]},"n1820939712":{"id":"n1820939712","loc":[-85.2440459,42.0178313]},"n1820939713":{"id":"n1820939713","loc":[-85.2444751,42.0182618]},"n1820939714":{"id":"n1820939714","loc":[-85.0539996,42.1032863]},"n1820939715":{"id":"n1820939715","loc":[-85.2215905,42.0373246]},"n1820939716":{"id":"n1820939716","loc":[-85.0649712,42.1051994]},"n1820939717":{"id":"n1820939717","loc":[-85.0927146,42.0927581]},"n1820939718":{"id":"n1820939718","loc":[-85.3884668,42.0042312]},"n1820939719":{"id":"n1820939719","loc":[-85.0840672,42.1013241]},"n1820939720":{"id":"n1820939720","loc":[-85.304739,41.9725408]},"n1820939721":{"id":"n1820939721","loc":[-85.2243585,42.0371334]},"n1820939722":{"id":"n1820939722","loc":[-85.0599823,42.1049686]},"n1820939723":{"id":"n1820939723","loc":[-85.0298825,42.0944288]},"n1820939724":{"id":"n1820939724","loc":[-85.0366095,42.1042443]},"n1820939725":{"id":"n1820939725","loc":[-85.0698783,42.1058135]},"n1820939726":{"id":"n1820939726","loc":[-85.1054551,42.0873361]},"n1820939727":{"id":"n1820939727","loc":[-84.9952324,42.0864285]},"n1820939728":{"id":"n1820939728","loc":[-85.3442211,41.9897993]},"n1820939729":{"id":"n1820939729","loc":[-85.4386134,42.0056822]},"n1820939730":{"id":"n1820939730","loc":[-85.2438528,42.0146589]},"n1820939731":{"id":"n1820939731","loc":[-85.0355581,42.1041846]},"n1820939732":{"id":"n1820939732","loc":[-85.557682,41.9724447]},"n1820939734":{"id":"n1820939734","loc":[-85.2299418,42.033314]},"n1820939735":{"id":"n1820939735","loc":[-85.6297412,41.9419088]},"n1820939736":{"id":"n1820939736","loc":[-85.2645101,41.9980259]},"n1820939738":{"id":"n1820939738","loc":[-85.082195,42.1035649]},"n1820939739":{"id":"n1820939739","loc":[-85.234272,42.0267102]},"n1820939740":{"id":"n1820939740","loc":[-85.0130758,42.0895006]},"n1820939741":{"id":"n1820939741","loc":[-85.4594702,42.0000375]},"n1820939742":{"id":"n1820939742","loc":[-84.9946745,42.0863687]},"n1820939743":{"id":"n1820939743","loc":[-85.6438775,41.9120186]},"n1820939744":{"id":"n1820939744","loc":[-85.6372685,41.9168089]},"n1820939745":{"id":"n1820939745","loc":[-85.2789468,41.9893208]},"n1820939747":{"id":"n1820939747","loc":[-85.3775019,41.998427]},"n1820939749":{"id":"n1820939749","loc":[-85.0993571,42.0909178]},"n1820939750":{"id":"n1820939750","loc":[-85.1308503,42.0669339]},"n1820939751":{"id":"n1820939751","loc":[-85.4802566,41.9856659]},"n1820939752":{"id":"n1820939752","loc":[-85.2543563,42.0108804]},"n1820939753":{"id":"n1820939753","loc":[-85.1041033,42.0878815]},"n1820939755":{"id":"n1820939755","loc":[-85.4000969,42.0071651]},"n1820939757":{"id":"n1820939757","loc":[-85.3858275,42.0022381]},"n1820939758":{"id":"n1820939758","loc":[-85.3653998,41.996609]},"n1820939759":{"id":"n1820939759","loc":[-85.2432949,42.0202305]},"n1820939760":{"id":"n1820939760","loc":[-85.3878874,42.0042472]},"n1820939761":{"id":"n1820939761","loc":[-85.2516741,42.0114145]},"n1820939762":{"id":"n1820939762","loc":[-85.2788825,41.9865142]},"n1820939763":{"id":"n1820939763","loc":[-85.0009147,42.0886686]},"n1820939764":{"id":"n1820939764","loc":[-85.3918142,42.003434]},"n1820939765":{"id":"n1820939765","loc":[-85.5532832,41.9696848]},"n1820939766":{"id":"n1820939766","loc":[-85.5545063,41.969254]},"n1820939768":{"id":"n1820939768","loc":[-85.1327989,42.0704769]},"n1820939770":{"id":"n1820939770","loc":[-85.0588558,42.1047696]},"n1820939772":{"id":"n1820939772","loc":[-85.555798,41.9713017]},"n1820939773":{"id":"n1820939773","loc":[-85.0565853,42.1023589]},"n1820939774":{"id":"n1820939774","loc":[-85.2582941,41.9992765]},"n1820939775":{"id":"n1820939775","loc":[-85.3007264,41.9727642]},"n1820939776":{"id":"n1820939776","loc":[-85.2477045,42.0082652]},"n1820939777":{"id":"n1820939777","loc":[-85.2415247,42.0104973]},"n1821006698":{"id":"n1821006698","loc":[-85.6345227,41.9382009]},"n1821006700":{"id":"n1821006700","loc":[-85.6344894,41.938975]},"n1821006704":{"id":"n1821006704","loc":[-85.6351181,41.9370157]},"n1821006706":{"id":"n1821006706","loc":[-85.6357554,41.9361657]},"n1821006708":{"id":"n1821006708","loc":[-85.6351235,41.9368481]},"n1821006710":{"id":"n1821006710","loc":[-85.6352844,41.9364211]},"n1821006712":{"id":"n1821006712","loc":[-85.6351503,41.937307]},"n1821006716":{"id":"n1821006716","loc":[-85.6350366,41.9379774]},"n1821006725":{"id":"n1821006725","loc":[-85.6352147,41.9375903]},"n1821137607":{"id":"n1821137607","loc":[-85.5297057,41.9669915]},"n1821137608":{"id":"n1821137608","loc":[-85.5288598,41.9673094]},"n1821139530":{"id":"n1821139530","loc":[-85.4832228,41.9881686]},"n1821139531":{"id":"n1821139531","loc":[-85.4812101,41.9851258]},"n1821139532":{"id":"n1821139532","loc":[-85.4799127,41.9860244]},"n1821139533":{"id":"n1821139533","loc":[-85.4800313,41.9865555]},"n1841425201":{"id":"n1841425201","loc":[-85.4334577,42.0063713]},"n1841425222":{"id":"n1841425222","loc":[-85.4382449,42.0055785]},"n1914861007":{"id":"n1914861007","loc":[-85.394959,42.0057472]},"n1914861057":{"id":"n1914861057","loc":[-85.3967185,42.0049695]},"n1914861112":{"id":"n1914861112","loc":[-85.394179,42.0056906]},"n1914861306":{"id":"n1914861306","loc":[-85.3900226,42.0028488]},"n2114807565":{"id":"n2114807565","loc":[-85.6385979,41.9577824]},"n2114807568":{"id":"n2114807568","loc":[-85.6325097,41.9775713]},"n2114807572":{"id":"n2114807572","loc":[-85.6328996,41.9980965]},"n2114807578":{"id":"n2114807578","loc":[-85.6344818,41.9696956]},"n2114807583":{"id":"n2114807583","loc":[-85.6326289,41.9757853]},"n2114807593":{"id":"n2114807593","loc":[-85.6360828,41.9650674]},"n2130304159":{"id":"n2130304159","loc":[-85.6352537,41.9450015],"tags":{"railway":"level_crossing"}},"n2139795852":{"id":"n2139795852","loc":[-85.6374708,41.9311633]},"n2139858882":{"id":"n2139858882","loc":[-85.635178,41.9356158]},"n2139858883":{"id":"n2139858883","loc":[-85.63533,41.9355886]},"n2139858884":{"id":"n2139858884","loc":[-85.6353819,41.93556]},"n2139858885":{"id":"n2139858885","loc":[-85.6353665,41.9355157]},"n2139858886":{"id":"n2139858886","loc":[-85.6353165,41.9354971]},"n2139858887":{"id":"n2139858887","loc":[-85.6352454,41.9355328]},"n2139858888":{"id":"n2139858888","loc":[-85.6350184,41.9357846]},"n2139858889":{"id":"n2139858889","loc":[-85.634978,41.9359448]},"n2139858890":{"id":"n2139858890","loc":[-85.6347723,41.9361523]},"n2139858891":{"id":"n2139858891","loc":[-85.6347165,41.9362667]},"n2139858892":{"id":"n2139858892","loc":[-85.6346992,41.9364312]},"n2139858893":{"id":"n2139858893","loc":[-85.634603,41.9366329]},"n2139858894":{"id":"n2139858894","loc":[-85.6345973,41.9367488]},"n2139858895":{"id":"n2139858895","loc":[-85.6345127,41.9369734]},"n2139858896":{"id":"n2139858896","loc":[-85.634478,41.9371923]},"n2139858897":{"id":"n2139858897","loc":[-85.6344838,41.9373768]},"n2139858898":{"id":"n2139858898","loc":[-85.6346242,41.9375299]},"n2139858899":{"id":"n2139858899","loc":[-85.6347723,41.9376357]},"n2139858900":{"id":"n2139858900","loc":[-85.6347607,41.9377788]},"n2139858901":{"id":"n2139858901","loc":[-85.6346204,41.9379533]},"n2139858902":{"id":"n2139858902","loc":[-85.6344184,41.9380105]},"n2139858903":{"id":"n2139858903","loc":[-85.6341627,41.9380406]},"n2139858904":{"id":"n2139858904","loc":[-85.634005,41.9381679]},"n2139858905":{"id":"n2139858905","loc":[-85.63393,41.9383353]},"n2139858906":{"id":"n2139858906","loc":[-85.6338588,41.9384597]},"n2139858907":{"id":"n2139858907","loc":[-85.6336627,41.9387759]},"n2139858908":{"id":"n2139858908","loc":[-85.6335127,41.9389361]},"n2139858933":{"id":"n2139858933","loc":[-85.6353118,41.9432646]},"n2139858934":{"id":"n2139858934","loc":[-85.6353952,41.9433002]},"n2139858935":{"id":"n2139858935","loc":[-85.6356496,41.9433255]},"n2139858936":{"id":"n2139858936","loc":[-85.6363128,41.9433373]},"n2139858937":{"id":"n2139858937","loc":[-85.6365467,41.9433779]},"n2139858938":{"id":"n2139858938","loc":[-85.6368692,41.9435265]},"n2139858939":{"id":"n2139858939","loc":[-85.6370986,41.9437039]},"n2139858940":{"id":"n2139858940","loc":[-85.6372371,41.9437732]},"n2139858941":{"id":"n2139858941","loc":[-85.6374756,41.9438171]},"n2139858942":{"id":"n2139858942","loc":[-85.6376164,41.9439286]},"n2139858943":{"id":"n2139858943","loc":[-85.6377504,41.944138]},"n2139858944":{"id":"n2139858944","loc":[-85.6384204,41.9443137]},"n2139858945":{"id":"n2139858945","loc":[-85.6385726,41.9444506]},"n2139858946":{"id":"n2139858946","loc":[-85.638702,41.9445739]},"n2139858947":{"id":"n2139858947","loc":[-85.6387179,41.9446516]},"n2139858948":{"id":"n2139858948","loc":[-85.6387088,41.9447985]},"n2139858949":{"id":"n2139858949","loc":[-85.6387656,41.9449877]},"n2139858950":{"id":"n2139858950","loc":[-85.638777,41.9451448]},"n2139858951":{"id":"n2139858951","loc":[-85.6387088,41.9452631]},"n2139858964":{"id":"n2139858964","loc":[-85.6383346,41.9442912]},"n2139858966":{"id":"n2139858966","loc":[-85.6384724,41.9443605]},"n2139858967":{"id":"n2139858967","loc":[-85.6354078,41.9434285]},"n2139858968":{"id":"n2139858968","loc":[-85.635271,41.943654]},"n2139858969":{"id":"n2139858969","loc":[-85.6352657,41.9437437]},"n2139858970":{"id":"n2139858970","loc":[-85.635271,41.9438195]},"n2139858971":{"id":"n2139858971","loc":[-85.6351563,41.9438906]},"n2139858972":{"id":"n2139858972","loc":[-85.6351384,41.9438882]},"n2139858973":{"id":"n2139858973","loc":[-85.6351514,41.9438034]},"n2139858974":{"id":"n2139858974","loc":[-85.6351237,41.9436641]},"n2139858975":{"id":"n2139858975","loc":[-85.6351498,41.9436108]},"n2139858976":{"id":"n2139858976","loc":[-85.6351058,41.9435345]},"n2139858977":{"id":"n2139858977","loc":[-85.6349641,41.9432051]},"n2139858986":{"id":"n2139858986","loc":[-85.6341205,41.9380746]},"n2139858990":{"id":"n2139858990","loc":[-85.6345671,41.9381816]},"n2139858995":{"id":"n2139858995","loc":[-85.6339783,41.9382273]},"n2139859003":{"id":"n2139859003","loc":[-85.6340477,41.9373489]},"n2139859004":{"id":"n2139859004","loc":[-85.6339784,41.9374752]},"n2139870406":{"id":"n2139870406","loc":[-85.6342265,41.9432605]},"n2139877106":{"id":"n2139877106","loc":[-85.6346323,41.9438746]},"n2139982399":{"id":"n2139982399","loc":[-85.6324055,41.9408537]},"n2139982400":{"id":"n2139982400","loc":[-85.632488,41.941063],"tags":{"leisure":"slipway"}},"n2139982401":{"id":"n2139982401","loc":[-85.6327261,41.9415366]},"n2139982402":{"id":"n2139982402","loc":[-85.6326391,41.9413598]},"n2139982403":{"id":"n2139982403","loc":[-85.6327041,41.9414391]},"n2139982405":{"id":"n2139982405","loc":[-85.6322891,41.9406009]},"n2139982406":{"id":"n2139982406","loc":[-85.6325412,41.9425257]},"n2139989333":{"id":"n2139989333","loc":[-85.6340584,41.9431731]},"n2140006331":{"id":"n2140006331","loc":[-85.6361751,41.9459744]},"n2140006334":{"id":"n2140006334","loc":[-85.636528,41.9459751]},"n2140006336":{"id":"n2140006336","loc":[-85.6370918,41.9458926]},"n2140006338":{"id":"n2140006338","loc":[-85.6378806,41.9456474]},"n2140006340":{"id":"n2140006340","loc":[-85.6385831,41.9454343]},"n2140006342":{"id":"n2140006342","loc":[-85.639341,41.945157]},"n2140006344":{"id":"n2140006344","loc":[-85.6393497,41.9450232]},"n2140006346":{"id":"n2140006346","loc":[-85.6388245,41.9450145]},"n2140006348":{"id":"n2140006348","loc":[-85.6388167,41.9441739]},"n2140006351":{"id":"n2140006351","loc":[-85.6382915,41.9441797]},"n2140006353":{"id":"n2140006353","loc":[-85.63828,41.9438109]},"n2140006355":{"id":"n2140006355","loc":[-85.6381949,41.9436009]},"n2140006357":{"id":"n2140006357","loc":[-85.6371904,41.9435918]},"n2140006359":{"id":"n2140006359","loc":[-85.6366966,41.9432727]},"n2140006361":{"id":"n2140006361","loc":[-85.6353755,41.9432744]},"n2140006365":{"id":"n2140006365","loc":[-85.6350906,41.9435472]},"n2140006366":{"id":"n2140006366","loc":[-85.6343461,41.9441573]},"n2140006395":{"id":"n2140006395","loc":[-85.6351171,41.9437175]},"n2140006397":{"id":"n2140006397","loc":[-85.635352,41.9450206]},"n2140006399":{"id":"n2140006399","loc":[-85.6358194,41.9454937]},"n2140006401":{"id":"n2140006401","loc":[-85.6348693,41.9445739]},"n2140006431":{"id":"n2140006431","loc":[-85.6376737,41.9438023]},"n2140006437":{"id":"n2140006437","loc":[-85.6382631,41.9442724]},"n2189123379":{"id":"n2189123379","loc":[-85.6342671,41.9352665]},"w203974076":{"id":"w203974076","tags":{"highway":"footway"},"nodes":["n2139870442","n2139870457","n2139870458","n2139870459","n2139870460","n2139870452"]},"w170989131":{"id":"w170989131","tags":{"name":"St Joseph River","waterway":"river"},"nodes":["n1820938225","n1820938712","n1820937596","n1820937574","n1820938515","n1820938330","n1820938678","n1820938240","n1820938950","n1820939226","n1820939575","n1820937913","n1820938223","n1820937668","n1820938545","n1820937584","n1820939742","n1820939727","n1820937578","n1820938149","n1820938124","n1820938888","n1820938898","n1820937922","n1820939543","n1820939370","n1820939401","n1820939647","n1820938345","n1820939644","n1820938333","n1820938370","n1820938624","n1820938493","n1820939559","n1820939763","n1820939237","n1820939416","n1820937810","n1820938317","n1820938324","n1820937558","n1820939556","n1820938298","n1820939348","n1820939125","n1820939081","n1820938859","n1820939126","n1820938881","n1820939439","n1820939324","n1820939128","n1820938101","n1820937706","n1820938382","n1820938776","n1820937815","n1820939177","n1820939688","n1820938952","n1820938216","n1820938387","n1820939333","n1820938243","n1820938248","n1820937666","n1820939051","n1820938332","n1820939438","n1820939407","n1820939361","n1820937517","n1820938770","n1820939591","n1820937857","n1820938491","n1820937993","n1820938125","n1820938166","n1820937746","n1820939028","n1820937638","n1820938676","n1820938843","n1820938844","n1820937978","n1820938730","n1820939544","n1820938304","n1820939123","n1820939494","n1820939450","n1820939555","n1820938133","n1820938129","n1820938871","n1820939408","n1820938669","n1820938260","n1820939740","n1820937625","n1820938631","n1820939651","n1820939613","n1820937850","n1820938325","n1820937736","n1820938804","n1820938837","n1820938014","n1820938991","n1820938722","n1820938935","n1820937870","n1820938432","n1820937986","n1820938756","n1820938966","n1820939159","n1820937744","n1820938334","n1820937645","n1820939394","n1820937656","n1820938392","n1820939703","n1820938385","n1820938947","n1820938854","n1820938428","n1820938488","n1820938269","n1820938668","n1820938268","n1820938707","n1820937732","n1820939144","n1820938481","n1820938771","n1820938686","n1820938948","n1820937997","n1820937769","n1820939003","n1820938083","n1820939011","n1820938803","n1820938700","n1820939723","n1820938808","n1820938262","n1820938081","n1820938926","n1820938326","n1820938102","n1820938508","n1820939590","n1820939199","n1820938084","n1820938870","n1820938895","n1820937611","n1820938918","n1820938514","n1820939610","n1820938910","n1820937523","n1820938127","n1820939108","n1820937981","n1820938938","n1820938715","n1820939016","n1820938237","n1820939623","n1820939602","n1820937734","n1820938977","n1820939633","n1820939156","n1820939406","n1820938279","n1820938301","n1820937678","n1820937671","n1820939163","n1820938356","n1820939372","n1820937568","n1820937626","n1820939710","n1820939004","n1820938253","n1820938571","n1820937513","n1820939412","n1820939701","n1820939509","n1820938839","n1820939731","n1820937798","n1820939676","n1820939724","n1820939243","n1820939704","n1820937814","n1820937599","n1820938199","n1820938995","n1820938445","n1820938069","n1820938470","n1820939074","n1820938193","n1820938740","n1820938047","n1820939507","n1820939441","n1820939160","n1820937849","n1820937840","n1820938052","n1820938988","n1820938796","n1820937724","n1820937620","n1820939304","n1820938343","n1820939649","n1820938875","n1820939686","n1820938476","n1820937801","n1820937737","n1820938264","n1820939609","n1820939496","n1820939593","n1820939566","n1820939661","n1820937782","n1820938912","n1820939173","n1820937733","n1820938953","n1820939603","n1820937607","n1820938468","n1820939601","n1820939694","n1820939133","n1820938897","n1820938893","n1820937831","n1820937730","n1820938820","n1820938046","n1820938426","n1820938347","n1820937582","n1820938954","n1820938033","n1820938104","n1820938680","n1820939563","n1820939404","n1820939714","n1820939000","n1820937992","n1820938168","n1820939510","n1820939500","n1820937509","n1820938865","n1820939773","n1820938138","n1820938905","n1820937623","n1820939418","n1820937946","n1820939577","n1820937615","n1820939687","n1820939119","n1820937988","n1820938337","n1820937750","n1820938703","n1820938339","n1820939044","n1820939770","n1820938913","n1820937672","n1820939722","n1820937768","n1820939597","n1820939612","n1820937699","n1820937682","n1820937669","n1820937657","n1820939363","n1820937800","n1820938265","n1820937760","n1820938207","n1820938115","n1820939130","n1820939716","n1820938338","n1820938239","n1820939040","n1820938064","n1820938855","n1820939015","n1820938258","n1820939042","n1820939043","n1820938443","n1820939725","n1820937675","n1820938568","n1820938280","n1820937705","n1820938775","n1820938636","n1820938626","n1820937859","n1820938096","n1820937852","n1820939039","n1820938247","n1820938585","n1820937707","n1820938117","n1820938909","n1820939115","n1820939335","n1820938805","n1820937935","n1820937876","n1820938699","n1820937869","n1820938603","n1820938100","n1820938500","n1820938283","n1820938275","n1820938923","n1820938365","n1820938349","n1820937804","n1820937903","n1820937608","n1820938688","n1820939671","n1820938092","n1820937820","n1820938753","n1820938922","n1820937990","n1820939682","n1820939738","n1820939600","n1820938167","n1820937726","n1820939702","n1820938209","n1820939456","n1820937837","n1820938222","n1820938902","n1820939162","n1820938965","n1820938461","n1820937681","n1820937514","n1820937764","n1820939719","n1820939697","n1820938899","n1820939093","n1820938702","n1820939595","n1820938749","n1820938348","n1820937606","n1820938675","n1820938830","n1820938737","n1820938758","n1820938716","n1820939107","n1820937863","n1820939033","n1820938163","n1820937867","n1820938819","n1820938034","n1820938252","n1820937563","n1820937868","n1820939032","n1820938632","n1820937982","n1820937943","n1820939568","n1820939541","n1820938215","n1820939097","n1820938812","n1820937518","n1820937952","n1820938711","n1820938736","n1820939066","n1820937591","n1820938082","n1820938108","n1820938496","n1820939410","n1820938949","n1820938327","n1820937708","n1820939023","n1820937772","n1820938256","n1820939083","n1820938378","n1820938961","n1820937610","n1820939717","n1820938695","n1820938590","n1820939655","n1820938341","n1820939054","n1820939157","n1820939674","n1820939684","n1820939511","n1820937631","n1820939458","n1820937830","n1820937709","n1820937779","n1820939749","n1820938880","n1820938856","n1820938557","n1820939557","n1820938249","n1820938818","n1820937594","n1820939114","n1820938416","n1820937508","n1820938990","n1820938201","n1820937759","n1820937987","n1820939164","n1820939753","n1820938187","n1820939067","n1820937586","n1820937941","n1820938121","n1820937807","n1820938521","n1820939726","n1820938244","n1820939014","n1820938741","n1820937629","n1820938664","n1820938747","n1820939082","n1820938709","n1820938320","n1820938270","n1820937619","n1820937777","n1820937718","n1820939138","n1820938056","n1820938155","n1820938596","n1820937775","n1820938437","n1820938128","n1820939581","n1820939145","n1820938546","n1820938184","n1820937601","n1820937794","n1820938539","n1820939645","n1820938438","n1820938436","n1820939025","n1820938915","n1820938534","n1820937605","n1820939607","n1820939101","n1820939580","n1820939268","n1820939134","n1820938849","n1820938754","n1820938079","n1820937842","n1820938781","n1820938873","n1820938495","n1820938381","n1820938503","n1820939436","n1820938502","n1820939087","n1820938996","n1820938449","n1820938907","n1820937979","n1820937780","n1820937546","n1820939699","n1820937677","n1820938957","n1820938946","n1820937776","n1820937717","n1820938718","n1820937637","n1820938510","n1820937663","n1820938941","n1820939151","n1820937603","n1820938250","n1820937951","n1820938630","n1820938821","n1820938779","n1820938497","n1820938159","n1820939536","n1820938409","n1820938386","n1820939116","n1820938340","n1820939117","n1820938291","n1820938435","n1820937819","n1820938242","n1820939078","n1820938877","n1820939104","n1820939445","n1820938367","n1820938903","n1820939420","n1820938517","n1820939508","n1820939542","n1820939326","n1820938210","n1820939020","n1820938815","n1820937832","n1820939513","n1820937818","n1820939005","n1820938717","n1820939135","n1820938384","n1820937587","n1820939024","n1820939504","n1820939120","n1820939026","n1820938015","n1820938998","n1820937648","n1820939137","n1820937761","n1820938195","n1820938535","n1820939550","n1820938725","n1820938282","n1820937781","n1820937792","n1820939705","n1820937788","n1820939707","n1820937882","n1820939632","n1820938427","n1820938276","n1820939617","n1820939013","n1820939035","n1820937543","n1820939365","n1820937752","n1820937802","n1820939183","n1820939670","n1820938450","n1820939375","n1820937813","n1820937673","n1820937783","n1820939029","n1820939768","n1820939377","n1820937974","n1820939244","n1820939642","n1820937864","n1820938255","n1820938528","n1820939666","n1820938120","n1820937812","n1820938928","n1820939750","n1820939099","n1820938073","n1820938714","n1820939140","n1820938192","n1820937844","n1820938635","n1820938742","n1820939583","n1820937887","n1820938318","n1820938816","n1820939698","n1820938273","n1820939181","n1820937652","n1820938748","n1820937651","n1820938519","n1820938019","n1820938752","n1820938235","n1820939118","n1820938562","n1820939314","n1820939570","n1820938190","n1820938342","n1820938533","n1820937977","n1820939089","n1820939146","n1820938622","n1820938297","n1820938524","n1820939283","n1820938874","n1820938832","n1820937550","n1820937843","n1820938638","n1820938116","n1820938206","n1820938319","n1820939053","n1820937845","n1820938093","n1820939217","n1820938997","n1820939355","n1820938861","n1820938726","n1820938057","n1820939373","n1820937862","n1820938518","n1820939072","n1820939680","n1820938444","n1820938217","n1820938506","n1820938393","n1820938492","n1820938852","n1820938221","n1820938773","n1820937684","n1820939060","n1820938224","n1820938203","n1820938840","n1820937525","n1820938147","n1820938433","n1820938188","n1820939359","n1820938750","n1820938016","n1820938768","n1820937621","n1820937799","n1820938951","n1820938721","n1820939037","n1820937866","n1820939715","n1820938063","n1820938446","n1820937627","n1820939624","n1820938431","n1820939721","n1820939622","n1820939239","n1820939263","n1820939648","n1820939640","n1820938867","n1820938757","n1820938439","n1820939352","n1820937740","n1820939329","n1820938229","n1820937583","n1820938180","n1820938366","n1820937767","n1820937758","n1820939374","n1820938869","n1820938292","n1820938400","n1820938399","n1820939734","n1820939289","n1820938944","n1820937755","n1820938759","n1820938434","n1820937600","n1820937825","n1820937670","n1820937793","n1820938011","n1820938246","n1820938956","n1820937770","n1820937757","n1820938059","n1820937860","n1820937569","n1820939266","n1820939685","n1820939672","n1820938606","n1820938772","n1820939038","n1820938211","n1820938359","n1820939619","n1820938708","n1820939512","n1820938065","n1820939233","n1820939739","n1820938786","n1820938879","n1820939147","n1820938563","n1820939148","n1820937839","n1820937659","n1820937786","n1820938419","n1820939565","n1820939402","n1820937710","n1820938254","n1820938271","n1820938390","n1820937680","n1820938140","n1820937817","n1820938218","n1820937985","n1820939235","n1820938441","n1820938401","n1820938719","n1820937795","n1820938971","n1820938460","n1820939759","n1820937972","n1820937841","n1820938462","n1820939320","n1820938978","n1820938360","n1820939713","n1820937676","n1820939712","n1820937939","n1820938080","n1820937754","n1820937753","n1820938530","n1820937886","n1820939689","n1820939124","n1820938697","n1820938789","n1820939105","n1820938860","n1820938853","n1820939400","n1820937561","n1820938404","n1820938774","n1820939316","n1820937696","n1820938782","n1820938975","n1820937564","n1820939730","n1820938257","n1820937853","n1820938487","n1820938848","n1820938906","n1820939230","n1820938424","n1820938051","n1820937771","n1820939587","n1820939149","n1820938792","n1820939041","n1820938934","n1820939777","n1820937515","n1820939058","n1820938312","n1820939264","n1820939631","n1820939109","n1820939403","n1820939664","n1820938724","n1820938929","n1820939399","n1820939776","n1820939369","n1820939185","n1820937701","n1820938126","n1820938336","n1820938219","n1820939080","n1820938642","n1820938043","n1820937725","n1820938548","n1820938552","n1820938035","n1820938684","n1820937778","n1820938764","n1820939021","n1820939346","n1820937712","n1820939761","n1820938397","n1820937747","n1820938566","n1820939161","n1820939090","n1820939752","n1820939271","n1820938878","n1820938110","n1820938346","n1820938499","n1820938151","n1820939538","n1820938281","n1820939153","n1820938551","n1820939285","n1820938197","n1820938408","n1820938482","n1820939036","n1820939579","n1820938489","n1820938483","n1820938189","n1820938123","n1820938087","n1820937741","n1820938485","n1820937590","n1820938972","n1820937773","n1820937520","n1820938872","n1820938131","n1820938452","n1820938328","n1820939620","n1820937641","n1820938353","n1820939693","n1820938705","n1820937640","n1820939189","n1820938144","n1820939774","n1820938694","n1820938238","n1820939397","n1820937917","n1820938454","n1820938567","n1820938979","n1820938060","n1820938204","n1820937828","n1820939232","n1820938806","n1820938857","n1820938078","n1820938105","n1820939228","n1820938604","n1820937763","n1820937854","n1820938289","n1820939736","n1820937937","n1820937714","n1820938278","n1820938058","n1820938706","n1820938989","n1820938313","n1820938520","n1820938288","n1820937689","n1820939537","n1820939531","n1820939019","n1820937527","n1820938455","n1820938814","n1820938045","n1820939627","n1820938213","n1820938161","n1820938331","n1820938024","n1820938220","n1820938062","n1820938178","n1820937796","n1820937644","n1820938490","n1820937589","n1820937879","n1820939614","n1820938882","n1820938039","n1820938538","n1820937667","n1820937719","n1820938561","n1820939658","n1820938783","n1820938601","n1820938198","n1820938388","n1820938969","n1820937687","n1820939086","n1820939665","n1820939187","n1820938498","n1820938261","n1820937983","n1820938068","n1820938136","n1820939061","n1820938137","n1820938186","n1820939071","n1820937592","n1820939669","n1820937553","n1820939357","n1820938727","n1820939371","n1820939112","n1820939079","n1820938743","n1820938467","n1820938834","n1820938022","n1820938537","n1820938122","n1820938516","n1820937614","n1820937612","n1820939469","n1820939636","n1820939050","n1820939552","n1820938157","n1820938663","n1820938955","n1820939091","n1820938430","n1820938471","n1820937809","n1820938074","n1820938208","n1820938914","n1820938858","n1820938417","n1820937531","n1820938107","n1820939100","n1820938751","n1820937711","n1820938824","n1820939745","n1820937572","n1820938602","n1820938212","n1820938097","n1820937921","n1820938090","n1820938511","n1820938876","n1820939762","n1820938234","n1820938048","n1820937774","n1820937856","n1820937749","n1820937765","n1820938286","n1820939095","n1820938480","n1820939229","n1820938277","n1820937617","n1820938311","n1820937622","n1820939196","n1820937690","n1820939006","n1820939287","n1820939131","n1820938106","n1820938784","n1820938335","n1820938095","n1820938182","n1820937715","n1820937683","n1820938070","n1820939605","n1820938527","n1820938763","n1820938398","n1820937686","n1820939621","n1820937664","n1820939277","n1820938565","n1820939539","n1820938099","n1820939646","n1820938556","n1820937548","n1820938729","n1820939336","n1820938259","n1820938728","n1820938361","n1820937643","n1820938644","n1820939007","n1820939690","n1820939227","n1820937635","n1820937950","n1820938682","n1820939150","n1820939012","n1820939261","n1820939111","n1820937805","n1820939691","n1820939677","n1820937628","n1820937811","n1820938790","n1820938251","n1820938226","n1820938942","n1820937633","n1820937984","n1820937751","n1820939673","n1820938970","n1820938415","n1820938597","n1820938309","n1820938111","n1820938472","n1820938894","n1820938402","n1820937593","n1820938570","n1820939102","n1820939775","n1820937948","n1820939121","n1820937511","n1820938787","n1820939720","n1820939075","n1820937880","n1820937742","n1820937721","n1820939535","n1820938486","n1820938354","n1820937632","n1820939010","n1820938885","n1820938089","n1820937613","n1820938442","n1820938245","n1820938272","n1820937566","n1820938295","n1820938532","n1820938883","n1820937713","n1820937674","n1820939635","n1820938448","n1820938355","n1820938587","n1820938559","n1820937787","n1820939301","n1820937723","n1820939056","n1820937560","n1820938323","n1820938230","n1820938453","n1820938377","n1820938357","n1820939637","n1820938017","n1820939540","n1820939376","n1820937639","n1820937642","n1820938075","n1820938351","n1820938766","n1820937897","n1820938973","n1820938066","n1820939547","n1820939652","n1820937944","n1820937748","n1820939234","n1820939193","n1820937891","n1820938785","n1820939132","n1820938523","n1820938884","n1820938411","n1820939554","n1820938791","n1820937655","n1820938368","n1820939152","n1820938030","n1820938447","n1820937580","n1820939628","n1820937588","n1820937894","n1820939201","n1820938086","n1820937650","n1820938379","n1820939008","n1820938999","n1820937524","n1820937872","n1820938389","n1820939197","n1820938422","n1820938936","n1820939262","n1820937634","n1820938583","n1820939589","n1820937901","n1820939034","n1820939065","n1820938290","n1820939195","n1820938228","n1820937884","n1820938797","n1820938191","n1820939191","n1820939198","n1820937892","n1820939679","n1820938507","n1820937647","n1820937909","n1820938542","n1820939598","n1820937851","n1820939084","n1820939728","n1820937688","n1820938263","n1820938670","n1820937762","n1820939310","n1820938925","n1820938862","n1820938822","n1820938547","n1820937731","n1820938594","n1820938592","n1820938214","n1820938284","n1820937835","n1820938599","n1820939437","n1820937834","n1820937576","n1820937692","n1820939586","n1820939546","n1820938403","n1820937970","n1820939561","n1820938098","n1820938851","n1820938477","n1820938892","n1820939045","n1820939758","n1820939350","n1820938321","n1820938440","n1820938595","n1820938364","n1820938962","n1820938118","n1820939678","n1820938406","n1820938549","n1820937555","n1820938823","n1820937521","n1820939471","n1820939487","n1820938799","n1820938605","n1820937928","n1820938373","n1820939747","n1820939629","n1820937557","n1820937526","n1820938958","n1820938833","n1820937636","n1820938967","n1820938760","n1820938842","n1820938067","n1820939077","n1820939224","n1820938185","n1820939110","n1820938372","n1820939757","n1820939063","n1820939660","n1820938813","n1820937528","n1820938369","n1820938896","n1820939551","n1820939683","n1820937660","n1820937873","n1820938810","n1820938478","n1820939662","n1820937595","n1820939052","n1820938113","n1820939070","n1820938733","n1820937878","n1820938300","n1820939760","n1820939718","n1820937646","n1820939057","n1820939443","n1914861306","n1820938013","n1820937529","n1820939764","n1820938826","n1820937885","n1820939588","n1820937865","n1820937833","n1914861112","n1820938761","n1914861007","n1820937905","n1820938541","n1820939092","n1914861057","n1820938153","n1820938267","n1820939265","n1820938085","n1820939018","n1820939755","n1820938474","n1820939027","n1820938593","n1820938202","n1820939599","n1820939695","n1820938077","n1820938012","n1820939545","n1820939596","n1820939337","n1820938227","n1820937698","n1820938475","n1820939465","n1820938165","n1820938698","n1820938525","n1820938529","n1820938553","n1820938940","n1820939498","n1820938501","n1820939533","n1820938924","n1820939634","n1820939220","n1820939657","n1820938887","n1820938838","n1820938114","n1820937823","n1820938778","n1820938801","n1820939096","n1820938981","n1820937953","n1820938732","n1820938980","n1820938960","n1820937949","n1820938026","n1820939273","n1841425201","n1820938629","n1820938864","n1820938554","n1820938088","n1820937685","n1841425222","n1820939729","n1820937665","n1820937838","n1820937739","n1820938780","n1820937821","n1820938825","n1820939055","n1820939485","n1820938041","n1820938746","n1820939562","n1820938459","n1820939489","n1820938050","n1820937980","n1820937695","n1820938413","n1820938555","n1820937703","n1820938536","n1820938196","n1820938287","n1820938169","n1820939279","n1820938531","n1820938959","n1820939741","n1820938665","n1820938963","n1820939611","n1820937653","n1820939618","n1820939492","n1820938600","n1820938628","n1820939312","n1820939616","n1820937738","n1820939001","n1820939062","n1820938794","n1820938558","n1820937822","n1820937532","n1820939073","n1820938200","n1820938241","n1820938968","n1820938927","n1820938306","n1820937630","n1820938456","n1820937694","n1820938908","n1820939076","n1820937522","n1820939659","n1820938522","n1820939318","n1820938932","n1820938841","n1820937579","n1820937540","n1820938560","n1821139530","n1820938964","n1820937662","n1820939281","n1821139533","n1820937797","n1821139532","n1820939751","n1821139531","n1820939291","n1820938420","n1820939696","n1820938904","n1820938484","n1820939448","n1820939009","n1820938735","n1820938986","n1820938937","n1820939030","n1820938734","n1820938745","n1820939106","n1820938987","n1820937858","n1820938673","n1820938620","n1820937808","n1820937700","n1820939573","n1820938540","n1820937661","n1820937570","n1820938396","n1820937875","n1820939048","n1820938233","n1820938793","n1820939584","n1820938412","n1820938394","n1820937846","n1820938800","n1820938690","n1820939331","n1820939630","n1820938762","n1820938710","n1820939322","n1820938992","n1821137608","n1821137607","n1820937924","n1820939139","n1820939463","n1820939574","n1820938294","n1820938071","n1820938307","n1820938061","n1820939260","n1820937899","n1820938310","n1820938983","n1820937530","n1820938993","n1820938890","n1820937915","n1820938231","n1820938040","n1820938920","n1820939585","n1820938135","n1820939700","n1820937824","n1820939667","n1820937930","n1820938134","n1820937551","n1820939405","n1820938232","n1820937716","n1820937848","n1820939765","n1820939068","n1820939766","n1820937933","n1820937720","n1820939222","n1820939772","n1820939022","n1820939732","n1820937702","n1820937691","n1820938945","n1820937756","n1820938451","n1820938410","n1820938798","n1820937945","n1820937654","n1820938598","n1820938836","n1820937571","n1820937556","n1820938994","n1820938919","n1820938863","n1820939064","n1820938018","n1820937658","n1820937537","n1820938142","n1820938666","n1820937535","n1820939571","n1820938465","n1820939638","n1820937533","n1820939656","n1820939422","n1820938109","n1820938405","n1820938028","n1820937649","n1820938829","n1820939031","n1820939155","n1820938350","n1820938463","n1820938425","n1820939047","n1820938831","n1820938494","n1820937697","n1820938504","n1820938900","n1820937784","n1820938414","n1820938076","n1820938723","n1820937722","n1820938739","n1820937791","n1820938985","n1820938352","n1820938293","n1820938274","n1820939692","n1820937871","n1820939059","n1820938868","n1820937877","n1820937743","n1820938429","n1820937545","n1820937575","n1820938302","n1820938505","n1820938916","n1820938374","n1820938329","n1820937790","n1820939735","n1820938930","n1820937995","n1820938512","n1820938130","n1820938194","n1820938671","n1820938802","n1820937542","n1820937602","n1820939069","n1820938901","n1820939654","n1820937727","n1820939569","n1820938375","n1820939306","n1820938479","n1820938376","n1820938667","n1820937766","n1820939467","n1820939567","n1820937806","n1820938943","n1820938931","n1820937745","n1820939452","n1820938738","n1820938053","n1820939653","n1820938640","n1820937604","n1820937536","n1820938701","n1820939625","n1820939744","n1820939572","n1820937577","n1820937541","n1820938891","n1820937597","n1820938469","n1820939194","n1820937539","n1820938911","n1820939017","n1820939650","n1820939103","n1820939578","n1820938132","n1820937549","n1820938634","n1820939743","n1820937544","n1820937826","n1820937598","n1820937547","n1820938032","n1820939142"]},"w17963021":{"id":"w17963021","tags":{"highway":"residential"},"nodes":["n185948706","n185948708","n185948710"]},"w203974069":{"id":"w203974069","tags":{"amenity":"shelter","area":"yes","building":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139870431","n2139870432","n2139870433","n2139870434","n2139870431"]},"w209816575":{"id":"w209816575","tags":{"area":"yes","building":"yes"},"nodes":["n2199856288","n2199856289","n2199856290","n2199856291","n2199856292","n2199856293","n2199856294","n2199856295","n2199856296","n2199856297","n2199856298","n2199856299","n2199856300","n2199856301","n2199856302","n2199856303","n2199856288"]},"w203841838":{"id":"w203841838","tags":{"area":"yes","natural":"water"},"nodes":["n2138493826","n2138493827","n2138493828","n2138493829","n2138493830","n2138493831","n2138493833","n2138493832","n2138493826"]},"w203972937":{"id":"w203972937","tags":{"highway":"path","name":"Riverwalk Trail","surface":"asphalt","width":"3"},"nodes":["n2139858882","n2139858883","n2139858884","n2139858885","n2139858886","n2139858887","n2139858882","n2139858888","n2139858889","n2139858890","n2139858891","n2139858892","n2139858893","n2139858894","n2139858895","n2139858896","n2139858897","n2139858898","n2139858899","n2139858900","n2139858901","n2139858902","n2139858903","n2139858986","n2139858904","n2139858995","n2139858905","n2139858906","n2139858907","n2139858908","n2139858909","n2139858910","n2139858911","n2139858912","n2139858913","n2139858914","n2139858915","n2139858916","n2139858917","n2139858918","n2139858919","n2139858920","n2139858921","n2139858922","n2139858923","n2139858924","n2139858925","n2139858926","n2139858927","n2139858982","n2139858928","n2139858929","n2139858930","n2139858931","n2139858932","n2139858981","n2139858933","n2139858934","n2139858935","n2139858936","n2139858937","n2139858938","n2139858939","n2139858940","n2139858941","n2139858942","n2139858943","n2140006437","n2139858964","n2139858944","n2139858966","n2139858945","n2139858946","n2139858947","n2139858948","n2139858949","n2139858950","n2139858951"]},"w17964015":{"id":"w17964015","tags":{"highway":"residential"},"nodes":["n185954680","n185954683","n185954685","n185954687","n185954689","n185954690","n185954691","n2139870379","n2139870456","n185954692","n185954693","n185954695"]},"w17967315":{"id":"w17967315","tags":{"highway":"residential","name":"South Andrews Street"},"nodes":["n185981999","n185974477","n185964963"]},"w203974071":{"id":"w203974071","tags":{"highway":"footway"},"nodes":["n2139870439","n2139870440","n2139870441","n2139870442","n2139870443","n2139870444","n2139870445","n2139870446","n2139870447","n2139870448","n2139870449"]},"w170848824":{"id":"w170848824","tags":{"name":"Rocky River","waterway":"river"},"nodes":["n1819858503","n1819858531","n1819858526","n1819858518","n1819858505","n1819858508","n1819858512","n1819858514","n1819858528","n1819858509","n1819858511","n1819858507","n1819858521"]},"w203986458":{"id":"w203986458","tags":{"amenity":"shelter","area":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139989357","n2139989359","n2139989360","n2139989362","n2139989357"]},"w170844917":{"id":"w170844917","tags":{"waterway":"riverbank"},"nodes":["n1819805911","n1819805690","n1819805812","n1819805766","n1819805802","n1819805885","n1819805626","n1819805842","n1819805715","n1819805694","n1819805618","n1819805629","n1819805731","n1819805636","n1819805878","n1819805718","n1819805798","n1819849057","n1819805666","n1819805852","n1819805805","n1819805789","n1819805868","n1819805680","n1819805918","n1819848888","n1819805762","n2139989328","n1819805907","n2139989330","n1819805915","n1819858521","n1819805854","n1819805876","n1819805864","n1819805922","n2139859004","n1819805702","n2139859003","n1819805614","n1819805792","n1819805786","n1819805777","n1819805645","n1819805838","n1819805889","n1819805795","n1819805707","n1819805774","n1819805808","n1819805810","n1819805724","n1819805676","n1819805728","n1819805783","n1819805687","n1819805727","n2189123379","n1819805632","n1819805641","n1819805760","n1819805887","n1819805861","n1819805722","n1819805880","n2139982405","n2139982399","n2139982400","n1819805770","n2139982402","n2139982403","n2139982401","n1819805780","n1819805834","n2139982406","n1819805698","n1819805647","n1819805870","n1819805683","n1819805622","n1819805639","n1819805858","n1819805643","n1819805673","n1819805925","n1819805849","n1819805711","n1819805846","n1819805669","n1819805883","n1819805814","n1819805873","n1819805911"]},"w17967326":{"id":"w17967326","tags":{"highway":"residential","name":"North Constantine Street"},"nodes":["n185985217","n185985219","n185985221","n185985222","n185985223","n185985225","n2140006431","n185985227","n185985229","n185985231","n185985233","n185985235","n185985238","n185985240","n2140018998","n185964965"]},"w134150789":{"id":"w134150789","tags":{"highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964971","n2139870406","n185964972"]},"w17966400":{"id":"w17966400","tags":{"highway":"tertiary","name":"South Constantine Street"},"nodes":["n185958672","n185964965"]},"w203974066":{"id":"w203974066","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139870417","n2139870418","n2139870420","n2139870419"]},"w17965998":{"id":"w17965998","tags":{"name":"Conrail Railroad","railway":"rail"},"nodes":["n185972775","n185972777","n185972779","n185972781","n185972783","n185972785","n185972787","n185972788","n185972789","n185972790","n185972791","n185972793","n185972795","n185972797","n185972798","n185972800","n185972802","n185972805","n185972807","n185972809","n185972811","n185972813","n185972814","n185972815","n185972816","n185972817","n185972819","n185972821","n185972824","n185972826","n185972830","n185972832","n185972834","n185972835","n185972836","n185972839","n185990434","n2114807572","n2114807568","n185972845","n2114807583","n185972847","n185972849","n185972851","n2114807578","n1475293254","n2114807593","n1475293226","n185972862","n2114807565","n185951869","n1475293234","n1475293252","n185972868","n1475293264","n1475293222","n185972878","n1475293261","n185972882","n185972885","n1475293260","n1475293240","n185972891","n185972895","n185972897","n185972899","n2130304159","n1475284023","n185972903"]},"w134150795":{"id":"w134150795","tags":{"bridge":"yes","highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964970","n185964971"]},"w203974067":{"id":"w203974067","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139870420","n2139870421"]},"w170995908":{"id":"w170995908","tags":{"highway":"residential","name":"Thomas Street"},"nodes":["n1821006702","n1821006700","n1821006698","n2139858990","n1821006716","n1821006725","n1821006712","n1821006704","n1821006708","n1821006710","n1821006706"]},"w17965834":{"id":"w17965834","tags":{"highway":"residential","name":"Spring Street"},"nodes":["n185971361","n185971364","n185971366","n185971368","n185954695","n185964968"]},"w203974070":{"id":"w203974070","tags":{"amenity":"shelter","area":"yes","building":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139870435","n2139870436","n2139870437","n2139870438","n2139870435"]},"w203989879":{"id":"w203989879","tags":{"highway":"service"},"nodes":["n2140018998","n2140018999","n2140019000"]},"w203974062":{"id":"w203974062","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139870387","n2139870388","n2139870389","n2139870390","n2139870391","n2139870392","n2139870397","n2139870393","n2139870396","n2139870395","n2139870394","n2139870387"]},"w203974061":{"id":"w203974061","tags":{"bridge":"yes","highway":"footway"},"nodes":["n2139870382","n2139870383"]},"w203049587":{"id":"w203049587","tags":{"area":"yes","name":"Scidmore Park Petting Zoo","tourism":"zoo","zoo":"petting_zoo"},"nodes":["n2130304133","n2130304136","n2130304138","n2130304140","n2130304142","n2130304144","n2130304146","n2130304147","n2130304148","n2130304149","n2130304150","n2130304151","n2130304133"]},"w203972941":{"id":"w203972941","tags":{"highway":"path"},"nodes":["n2139858982","n2139858983","n2139858984","n2139858985","n2139858927"]},"w203974065":{"id":"w203974065","tags":{"highway":"service"},"nodes":["n2139870406","n2139870407","n2139870408","n2139870417","n2139870409","n2139870410","n2139870411","n2139870412","n2139870426","n2139870413","n2139870414","n2139870415","n2139870419","n2139870416","n2139870421","n2139870408"]},"w203972940":{"id":"w203972940","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139858934","n2139858967","n2139858968","n2139858969","n2139858970","n2139858971","n2139858972","n2139858973","n2139858974","n2139858975","n2139858976","n2139858977","n2139858978","n2139858979","n2139858980","n2139858981"]},"w203974072":{"id":"w203974072","tags":{"highway":"footway"},"nodes":["n2139858925","n2139870450","n2139870453","n2139870451","n2139870452","n2139870441"]},"w203974074":{"id":"w203974074","tags":{"highway":"footway"},"nodes":["n2139870454","n2139870456","n2139870429"]},"w203974060":{"id":"w203974060","tags":{"highway":"footway"},"nodes":["n2139870383","n2139870384","n2139870422","n2139870385","n2139870386","n2139870388"]},"w203841837":{"id":"w203841837","tags":{"area":"yes","natural":"water"},"nodes":["n2138493807","n2138493808","n2138493809","n2138493810","n2138493811","n2138493812","n2138493813","n2138493814","n2138493815","n2138493816","n2138493825","n2138493817","n2138493824","n2138493818","n2138493819","n2138493820","n2138493821","n2138493822","n2138493823","n2138493807"]},"w134150845":{"id":"w134150845","tags":{"bridge":"yes","name":"Conrail Railroad","railway":"rail"},"nodes":["n185972903","n185972905"]},"w203974059":{"id":"w203974059","tags":{"highway":"footway"},"nodes":["n2139870430","n2139870439","n2139870429","n2139870428","n2139870379","n2139870455","n2139870380","n2139870381","n2139858925","n2139870382"]},"w203986457":{"id":"w203986457","tags":{"area":"yes","leisure":"park","name":"Scidmore Park"},"nodes":["n2139989333","n2139989335","n2139989337","n2139989339","n1819805762","n2139989328","n1819805907","n2139989330","n1819805915","n2139989341","n2139989344","n2139989346","n2139989348","n2139989350","n2139989351","n2139989353","n2139989355","n2139989333"]},"w170848331":{"id":"w170848331","tags":{"name":"Rocky River","waterway":"river"},"nodes":["n1819848937","n1819849104","n1819849076","n1819849183","n1819848928","n1819848972","n1819848948","n1819848971","n1819848859","n1819849008","n1819848889","n1819849026","n1819849094","n1819849083","n1819849079","n1819849187","n1819848992","n1819849060","n1819849056","n1819849071","n1819849067","n1819849048","n1819849036","n1819849150","n1819849075","n1819849051","n1819849062","n1819848926","n1819849035","n1819848987","n1819849012","n1819848933","n1819848996","n1819848990","n1819849005","n1819849021","n1819848892","n1819849092","n1819848863","n1819848922","n1819848858","n1819848855","n1819848974","n1819848953","n1819849019","n1819849049","n1819848979","n1819849140","n1819849193","n1819849147","n1819849151","n1819849163","n1819849023","n1819848878","n1819849004","n1819848857","n1819848879","n1819849041","n1819849165","n1819849107","n1819849156","n1819848934","n1819848914","n1819848955","n1819848931","n1819848927","n1819849084","n1819849169","n1819849045","n1819848945","n1819849095","n1819848924","n1819849171","n1819849141","n1819849046","n1819849197","n1819849011","n1819849108","n1819849158","n1819849160","n1819848870","n1819849006","n1819849157","n1819848993","n1819848970","n1819849202","n1819848903","n1819848975","n1819848849","n1819849025","n1819849105","n1819849033","n1819849176","n1819849099","n1819849086","n1819848960","n1819848961","n1819849001","n1819848980","n1819849038","n1819848854","n1819849127","n1819849170","n1819849139","n1819848873","n1819848929","n1819849201","n1819849121","n1819849031","n1819849131","n1819848875","n1819849080","n1819849066","n1819849081","n1819849096","n1819849172","n1819849114","n1819849182","n1819848905","n1819849054","n1819848920","n1819848851","n1819848968","n1819848917","n1819849111","n1819849119","n1819849074","n1819848893","n1819849129","n1819848850","n1819848956","n1819849154","n1819848877","n1819848986","n1819849191","n1819848952","n1819848954","n1819848942","n1819849028","n1819849195","n1819848938","n1819848962","n1819849070","n1819849034","n1819849052","n1819849059","n1819848916","n1819849162","n1819849167","n1819849093","n1819849030","n1819849002","n1819849161","n1819848886","n1819848958","n1819849064","n1819849112","n1819849148","n1819848856","n1819848976","n1819848977","n1819849144","n1819848918","n1819849200","n1819848919","n1819849042","n1819849166","n1819849186","n1819849152","n1819849058","n1819849185","n1819849199","n1819849053","n1819849194","n1819849068","n1819849146","n1819849174","n1819848967","n1819848932","n1819849155","n1819849198","n1819848964","n1819848894","n1819848969","n1819849184","n1819849055","n1819849179","n1819848865","n1819848860","n1819849082","n1819848966","n1819849040","n1819849069","n1819849078","n1819849077","n1819848904","n1819848959","n1819849133","n1819849089","n1819849000","n1819849124","n1819849032","n1819849097","n1819848939","n1819849072","n1819848915","n1819849196","n1819848946","n1819849047","n1819849029","n1819849164","n1819848994","n1819849022","n1819858513","n1819849126","n1819849063","n1819848941","n1819849085","n1819848871","n1819848943","n1819849192","n1819858501","n1819849159","n1819858523","n1819848901","n1819849189","n1819858503","n1819849065","n2139877106","n1819848909","n1819848930","n1819848888"]},"w17967397":{"id":"w17967397","tags":{"highway":"residential","name":"North Andrews Street"},"nodes":["n185964963","n185985217"]},"w17964497":{"id":"w17964497","tags":{"highway":"tertiary","name":"Constantine St"},"nodes":["n185958643","n185958645","n2139795852","n185958647","n185958649","n185958651","n185958653","n185958656","n185958658","n185958660","n185958662","n185958664","n185958666","n185958668","n185958670","n185948710","n185958672"]},"w203974068":{"id":"w203974068","tags":{"highway":"footway"},"nodes":["n2139870422","n2139870423","n2139870424","n2139870425","n2139870426","n2139870427"]},"w203974063":{"id":"w203974063","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139870398","n2139870399","n2139870400","n2139870401","n2139870398"]},"w203986459":{"id":"w203986459","tags":{"amenity":"shelter","area":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139989364","n2139989366","n2139989368","n2139989370","n2139989364"]},"w203988286":{"id":"w203988286","tags":{"area":"yes","leisure":"park","name":"Memory Isle Park"},"nodes":["n2140006331","n2140006334","n2140006336","n2140006338","n2140006340","n2140006342","n2140006344","n2140006346","n2140006348","n2140006351","n2140006353","n2140006355","n2140006357","n2140006359","n2140006361","n2140006363","n2140006364","n2140006365","n2140006395","n2140006366","n2140006401","n2140006397","n2140006399","n2140006331"]},"w203974073":{"id":"w203974073","tags":{"highway":"footway"},"nodes":["n2139870453","n2139870454","n2139870455"]},"w203974064":{"id":"w203974064","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139870402","n2139870403","n2139870404","n2139870405","n2139870402"]},"n185966959":{"id":"n185966959","loc":[-85.642185,41.946411]},"n1475283980":{"id":"n1475283980","loc":[-85.6398249,41.9451425]},"n1475284013":{"id":"n1475284013","loc":[-85.6396448,41.9451666]},"n1475284042":{"id":"n1475284042","loc":[-85.6386382,41.9454789]},"n185975925":{"id":"n185975925","loc":[-85.6393332,41.9452388]},"n185975919":{"id":"n185975919","loc":[-85.6391279,41.9453044]},"n185975917":{"id":"n185975917","loc":[-85.6389034,41.9453872]},"n2140006369":{"id":"n2140006369","loc":[-85.6386163,41.9451631]},"n2140006370":{"id":"n2140006370","loc":[-85.6385144,41.9449357]},"n2140006417":{"id":"n2140006417","loc":[-85.6385785,41.9450299]},"n2140006419":{"id":"n2140006419","loc":[-85.6385781,41.9452152]},"n2189123361":{"id":"n2189123361","loc":[-85.6404948,41.947015]},"n2189123363":{"id":"n2189123363","loc":[-85.6395765,41.946495]},"n2189123365":{"id":"n2189123365","loc":[-85.6389347,41.9460875]},"n185966962":{"id":"n185966962","loc":[-85.644417,41.946364]},"n185975911":{"id":"n185975911","loc":[-85.637532,41.9458276]},"n185975913":{"id":"n185975913","loc":[-85.6376323,41.9457936]},"n185975915":{"id":"n185975915","loc":[-85.6383596,41.9455425]},"n185975932":{"id":"n185975932","loc":[-85.644403,41.945088]},"n185975934":{"id":"n185975934","loc":[-85.645486,41.945084]},"n185979974":{"id":"n185979974","loc":[-85.644381,41.943831]},"n2139795809":{"id":"n2139795809","loc":[-85.6464756,41.9450813]},"n2139795810":{"id":"n2139795810","loc":[-85.6466646,41.945174]},"n2139858952":{"id":"n2139858952","loc":[-85.6383567,41.9454039]},"n2139858953":{"id":"n2139858953","loc":[-85.6380506,41.9455301]},"n2139858954":{"id":"n2139858954","loc":[-85.6377321,41.9455546]},"n2139858955":{"id":"n2139858955","loc":[-85.6376571,41.9455245]},"n2139858956":{"id":"n2139858956","loc":[-85.6375859,41.9454544]},"n2139858957":{"id":"n2139858957","loc":[-85.6376686,41.9453185]},"n2139858958":{"id":"n2139858958","loc":[-85.6378936,41.9451712]},"n2139858959":{"id":"n2139858959","loc":[-85.6379225,41.9450825]},"n2139858960":{"id":"n2139858960","loc":[-85.6379302,41.9447564]},"n2139858961":{"id":"n2139858961","loc":[-85.6379763,41.9446963]},"n2139858962":{"id":"n2139858962","loc":[-85.6380436,41.9446706]},"n2139858963":{"id":"n2139858963","loc":[-85.6381286,41.9445969]},"n2139858965":{"id":"n2139858965","loc":[-85.6382523,41.9444134]},"n2140006367":{"id":"n2140006367","loc":[-85.6380923,41.9454418]},"n2140006368":{"id":"n2140006368","loc":[-85.6384089,41.9453146]},"n2140006372":{"id":"n2140006372","loc":[-85.6383252,41.9447706]},"n2140006374":{"id":"n2140006374","loc":[-85.6381033,41.9447436]},"n2140006376":{"id":"n2140006376","loc":[-85.6379759,41.9447815]},"n2140006378":{"id":"n2140006378","loc":[-85.6379832,41.9448654]},"n2140006380":{"id":"n2140006380","loc":[-85.6380632,41.9450738]},"n2140006382":{"id":"n2140006382","loc":[-85.6380414,41.9452064]},"n2140006389":{"id":"n2140006389","loc":[-85.6379068,41.9453092]},"n2140006391":{"id":"n2140006391","loc":[-85.637925,41.9453904]},"n2140006393":{"id":"n2140006393","loc":[-85.6379977,41.94545]},"n2189123275":{"id":"n2189123275","loc":[-85.6371346,41.9462544]},"n2189123278":{"id":"n2189123278","loc":[-85.6368371,41.9466153]},"n2189123280":{"id":"n2189123280","loc":[-85.6379537,41.9489088]},"n2189123282":{"id":"n2189123282","loc":[-85.6383816,41.9497858]},"n2189123285":{"id":"n2189123285","loc":[-85.6393673,41.9512417]},"n2189123287":{"id":"n2189123287","loc":[-85.640554,41.9517766]},"n2189123289":{"id":"n2189123289","loc":[-85.6411,41.9522344]},"n2189123291":{"id":"n2189123291","loc":[-85.6417418,41.9526574]},"n2189123293":{"id":"n2189123293","loc":[-85.642321,41.9529407]},"n2189123295":{"id":"n2189123295","loc":[-85.6427697,41.9532278]},"n2189123297":{"id":"n2189123297","loc":[-85.6433332,41.9538254]},"n2189123300":{"id":"n2189123300","loc":[-85.6435785,41.9543648]},"n2189123301":{"id":"n2189123301","loc":[-85.6444394,41.9541048]},"n2189123303":{"id":"n2189123303","loc":[-85.6450603,41.954]},"n2189123312":{"id":"n2189123312","loc":[-85.6454829,41.9539108]},"n2189123314":{"id":"n2189123314","loc":[-85.6460464,41.9538526]},"n2189123315":{"id":"n2189123315","loc":[-85.6463178,41.9537167]},"n2189123316":{"id":"n2189123316","loc":[-85.646276,41.9534141]},"n2189123317":{"id":"n2189123317","loc":[-85.6459995,41.9531541]},"n2189123318":{"id":"n2189123318","loc":[-85.645222,41.9531929]},"n2189123319":{"id":"n2189123319","loc":[-85.6447316,41.9531813]},"n2189123320":{"id":"n2189123320","loc":[-85.6440637,41.9532977]},"n2189123321":{"id":"n2189123321","loc":[-85.6438185,41.9531774]},"n2189123322":{"id":"n2189123322","loc":[-85.6440011,41.9528398]},"n2189123323":{"id":"n2189123323","loc":[-85.6442672,41.9525914]},"n2189123324":{"id":"n2189123324","loc":[-85.6442881,41.9523276]},"n2189123326":{"id":"n2189123326","loc":[-85.644262,41.952153]},"n2189123328":{"id":"n2189123328","loc":[-85.6441681,41.9520404]},"n2189123330":{"id":"n2189123330","loc":[-85.6442098,41.9517494]},"n2189123333":{"id":"n2189123333","loc":[-85.6438498,41.9515864]},"n2189123336":{"id":"n2189123336","loc":[-85.6435889,41.9513225]},"n2189123339":{"id":"n2189123339","loc":[-85.6425349,41.9510315]},"n2189123342":{"id":"n2189123342","loc":[-85.6422688,41.9508802]},"n2189123345":{"id":"n2189123345","loc":[-85.6418775,41.9508142]},"n2189123348":{"id":"n2189123348","loc":[-85.6415488,41.9508064]},"n2189123351":{"id":"n2189123351","loc":[-85.6411027,41.9505488]},"n2189123353":{"id":"n2189123353","loc":[-85.6410374,41.9498208]},"n2189123355":{"id":"n2189123355","loc":[-85.6410061,41.9494327]},"n2189123357":{"id":"n2189123357","loc":[-85.6411522,41.9482569]},"n2189123359":{"id":"n2189123359","loc":[-85.6410548,41.9473036]},"n2189123368":{"id":"n2189123368","loc":[-85.6380216,41.9458974]},"n2189123370":{"id":"n2189123370","loc":[-85.6386721,41.9507782]},"w17968193":{"id":"w17968193","tags":{"highway":"residential","name":"French St"},"nodes":["n185970906","n185982877","n185967774","n185985823","n185979974"]},"w203972939":{"id":"w203972939","tags":{"highway":"path"},"nodes":["n2139858965","n2139858966"]},"w203988289":{"id":"w203988289","tags":{"area":"yes","natural":"water"},"nodes":["n2140006367","n2140006368","n2140006419","n2140006369","n2140006417","n2140006370","n2140006372","n2140006374","n2140006376","n2140006378","n2140006380","n2140006382","n2140006389","n2140006391","n2140006393","n2140006367"]},"w208640157":{"id":"w208640157","tags":{"area":"yes","natural":"wetland"},"nodes":["n1819849029","n2189123275","n2189123278","n2189123280","n2189123282","n2189123370","n2189123285","n2189123287","n2189123289","n2189123291","n2189123293","n2189123295","n2189123297","n2189123300","n2189123301","n2189123303","n2189123312","n2189123314","n2189123315","n2189123316","n2189123317","n2189123318","n2189123319","n2189123320","n2189123321","n2189123322","n2189123323","n2189123324","n2189123326","n2189123328","n2189123330","n2189123333","n2189123336","n2189123339","n2189123342","n2189123345","n2189123348","n2189123351","n2189123353","n2189123355","n2189123357","n2189123359","n2189123361","n2189123363","n2189123365","n2189123368","n1819849029"]},"w17966281":{"id":"w17966281","tags":{"highway":"residential","name":"Pealer St"},"nodes":["n185975911","n185975913","n185975915","n1475284042","n185975917","n185975919","n185975925","n185970909","n1475284013","n1475283980","n185975928","n185967775","n185975930","n185975932","n185975934","n2139795809","n2139795810"]},"w17965353":{"id":"w17965353","tags":{"highway":"residential","name":"Yauney St"},"nodes":["n185966958","n185966959","n185966960","n185966962"]},"w203972938":{"id":"w203972938","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139858964","n2139858965","n2139858963","n2139858962","n2139858961","n2139858960","n2139858959","n2139858958","n2139858957","n2139858956","n2139858955","n2139858954","n2139858953","n2139858952","n2139858951"]},"n354002665":{"id":"n354002665","loc":[-85.6366599,41.9444923],"tags":{"name":"Memory Isle","place":"island"}},"n354031301":{"id":"n354031301","loc":[-85.635,41.9463889],"tags":{"amenity":"post_office","name":"Three Rivers Post Office"}},"n185963454":{"id":"n185963454","loc":[-85.633686,41.946072]},"n185963455":{"id":"n185963455","loc":[-85.633815,41.946131]},"n185963456":{"id":"n185963456","loc":[-85.633951,41.946174]},"n185978375":{"id":"n185978375","loc":[-85.634385,41.94559]},"n185978377":{"id":"n185978377","loc":[-85.634544,41.945725]},"n185978379":{"id":"n185978379","loc":[-85.634573,41.945764]},"n185978381":{"id":"n185978381","loc":[-85.634616,41.945849]},"n185978383":{"id":"n185978383","loc":[-85.634629,41.945893]},"n185984011":{"id":"n185984011","loc":[-85.636058,41.946201]},"n185984013":{"id":"n185984013","loc":[-85.636112,41.946366]},"n185984015":{"id":"n185984015","loc":[-85.636143,41.946551]},"n185988237":{"id":"n185988237","loc":[-85.6354162,41.946044]},"n185988969":{"id":"n185988969","loc":[-85.635374,41.945325]},"n185988971":{"id":"n185988971","loc":[-85.635643,41.945585]},"n185988972":{"id":"n185988972","loc":[-85.635853,41.94586]},"n1475283992":{"id":"n1475283992","loc":[-85.6372968,41.9459007]},"n1475284011":{"id":"n1475284011","loc":[-85.6359415,41.9459797]},"n1475284019":{"id":"n1475284019","loc":[-85.6364433,41.9460423]},"n185984009":{"id":"n185984009","loc":[-85.6360524,41.9460485]},"n185988239":{"id":"n185988239","loc":[-85.6358187,41.9460423]},"n185988243":{"id":"n185988243","loc":[-85.6366156,41.9460282]},"n185988244":{"id":"n185988244","loc":[-85.6368316,41.9460046]},"n185988245":{"id":"n185988245","loc":[-85.6370133,41.9459704]},"n185988241":{"id":"n185988241","loc":[-85.636291,41.9460461]},"n185964976":{"id":"n185964976","loc":[-85.633923,41.9434157]},"n185964980":{"id":"n185964980","loc":[-85.6333656,41.9437293]},"n185978388":{"id":"n185978388","loc":[-85.6346449,41.9460571]},"n1819858504":{"id":"n1819858504","loc":[-85.6365343,41.9447926]},"n1819858506":{"id":"n1819858506","loc":[-85.6370546,41.9451882]},"n1819858516":{"id":"n1819858516","loc":[-85.6358369,41.9444654]},"n1819858519":{"id":"n1819858519","loc":[-85.6361534,41.9446176]},"n1819858525":{"id":"n1819858525","loc":[-85.6368025,41.9449442]},"n1819858527":{"id":"n1819858527","loc":[-85.6334199,41.9457495]},"n185963452":{"id":"n185963452","loc":[-85.633564,41.9458519]},"n185963453":{"id":"n185963453","loc":[-85.6336152,41.9459804]},"n185963451":{"id":"n185963451","loc":[-85.6332888,41.9456871]},"n2130304152":{"id":"n2130304152","loc":[-85.6359466,41.9454599]},"n2130304153":{"id":"n2130304153","loc":[-85.6362773,41.9452683]},"n2130304154":{"id":"n2130304154","loc":[-85.6352028,41.9442868]},"n2130304155":{"id":"n2130304155","loc":[-85.6348756,41.9444769]},"n2130304156":{"id":"n2130304156","loc":[-85.6349723,41.9444207]},"n2130304157":{"id":"n2130304157","loc":[-85.6338698,41.9434443]},"n2130304158":{"id":"n2130304158","loc":[-85.635094,41.9451026]},"n2130304160":{"id":"n2130304160","loc":[-85.6353716,41.9449322]},"n2130304162":{"id":"n2130304162","loc":[-85.6365942,41.9459352]},"n2130304163":{"id":"n2130304163","loc":[-85.6369006,41.9457469]},"n2130304164":{"id":"n2130304164","loc":[-85.6363292,41.9452278]},"n2130304165":{"id":"n2130304165","loc":[-85.6360248,41.9454175]},"n2139824683":{"id":"n2139824683","loc":[-85.6339825,41.9446441]},"n2139824689":{"id":"n2139824689","loc":[-85.6340437,41.9446925]},"n2139824702":{"id":"n2139824702","loc":[-85.6340961,41.9447551]},"n2139824705":{"id":"n2139824705","loc":[-85.6337467,41.944809]},"n2139824707":{"id":"n2139824707","loc":[-85.6341598,41.9448129]},"n2139824710":{"id":"n2139824710","loc":[-85.6342771,41.9448223]},"n2139824712":{"id":"n2139824712","loc":[-85.6346058,41.944841]},"n2139824713":{"id":"n2139824713","loc":[-85.633808,41.9448574]},"n2139824714":{"id":"n2139824714","loc":[-85.6340889,41.9448589]},"n2139824716":{"id":"n2139824716","loc":[-85.6343335,41.944871]},"n2139824717":{"id":"n2139824717","loc":[-85.6343341,41.9448717]},"n2139824720":{"id":"n2139824720","loc":[-85.6338757,41.9449069]},"n2139824721":{"id":"n2139824721","loc":[-85.6341445,41.9449071]},"n2139824724":{"id":"n2139824724","loc":[-85.6334787,41.9449262]},"n2139824726":{"id":"n2139824726","loc":[-85.6347119,41.9449332]},"n2139824727":{"id":"n2139824727","loc":[-85.6347175,41.9449418]},"n2139824728":{"id":"n2139824728","loc":[-85.6344284,41.9449538]},"n2139824729":{"id":"n2139824729","loc":[-85.6339339,41.9449573]},"n2139824730":{"id":"n2139824730","loc":[-85.6339179,41.9449682]},"n2139824732":{"id":"n2139824732","loc":[-85.6335472,41.9449895]},"n2139824733":{"id":"n2139824733","loc":[-85.6339736,41.9450164]},"n2139824735":{"id":"n2139824735","loc":[-85.6336034,41.9450415]},"n2139824736":{"id":"n2139824736","loc":[-85.6348317,41.945043]},"n2139824737":{"id":"n2139824737","loc":[-85.63403,41.9450651]},"n2139824738":{"id":"n2139824738","loc":[-85.6336611,41.9450949]},"n2139824740":{"id":"n2139824740","loc":[-85.6336582,41.9450966]},"n2139824744":{"id":"n2139824744","loc":[-85.6331702,41.9451107]},"n2139824745":{"id":"n2139824745","loc":[-85.6333388,41.9451142]},"n2139824746":{"id":"n2139824746","loc":[-85.6337131,41.9451341]},"n2139824747":{"id":"n2139824747","loc":[-85.6337021,41.9451372]},"n2139824748":{"id":"n2139824748","loc":[-85.6341244,41.9451472]},"n2139824749":{"id":"n2139824749","loc":[-85.6333952,41.945166]},"n2139824750":{"id":"n2139824750","loc":[-85.633395,41.9451661]},"n2139824751":{"id":"n2139824751","loc":[-85.6346258,41.9451725]},"n2139824752":{"id":"n2139824752","loc":[-85.6332387,41.9451741]},"n2139824753":{"id":"n2139824753","loc":[-85.6346901,41.9451853]},"n2139824754":{"id":"n2139824754","loc":[-85.6346611,41.9452035]},"n2139824755":{"id":"n2139824755","loc":[-85.6346574,41.9452059]},"n2139824756":{"id":"n2139824756","loc":[-85.6345611,41.9452133]},"n2139824757":{"id":"n2139824757","loc":[-85.633453,41.9452194]},"n2139824758":{"id":"n2139824758","loc":[-85.6335508,41.9452283]},"n2139824759":{"id":"n2139824759","loc":[-85.6347424,41.9452312]},"n2139824760":{"id":"n2139824760","loc":[-85.6342305,41.9452395]},"n2139824761":{"id":"n2139824761","loc":[-85.6342319,41.9452449]},"n2139824762":{"id":"n2139824762","loc":[-85.6334969,41.94526]},"n2139824763":{"id":"n2139824763","loc":[-85.63468,41.9452706]},"n2139824764":{"id":"n2139824764","loc":[-85.6346772,41.9452724]},"n2139824765":{"id":"n2139824765","loc":[-85.6338611,41.9452763]},"n2139824766":{"id":"n2139824766","loc":[-85.6347811,41.9452939]},"n2139824767":{"id":"n2139824767","loc":[-85.6347375,41.9453211]},"n2139824768":{"id":"n2139824768","loc":[-85.6339171,41.9453301]},"n2139824769":{"id":"n2139824769","loc":[-85.6348307,41.9453377]},"n2139824770":{"id":"n2139824770","loc":[-85.6347067,41.9453405]},"n2139824771":{"id":"n2139824771","loc":[-85.6343461,41.9453461]},"n2139824772":{"id":"n2139824772","loc":[-85.6343481,41.9453475]},"n2139824773":{"id":"n2139824773","loc":[-85.634805,41.9453538]},"n2139824774":{"id":"n2139824774","loc":[-85.6336997,41.9453692]},"n2139824775":{"id":"n2139824775","loc":[-85.6339709,41.9453818]},"n2139824776":{"id":"n2139824776","loc":[-85.6336229,41.9454134]},"n2139824777":{"id":"n2139824777","loc":[-85.6349022,41.9454141]},"n2139824778":{"id":"n2139824778","loc":[-85.6348854,41.9454246]},"n2139824779":{"id":"n2139824779","loc":[-85.6340286,41.9454373]},"n2139824780":{"id":"n2139824780","loc":[-85.6336963,41.9454572]},"n2139824781":{"id":"n2139824781","loc":[-85.6336789,41.9454672]},"n2139824782":{"id":"n2139824782","loc":[-85.6344933,41.945475]},"n2139824783":{"id":"n2139824783","loc":[-85.6340854,41.9454918]},"n2139824784":{"id":"n2139824784","loc":[-85.6350036,41.9455034]},"n2139824785":{"id":"n2139824785","loc":[-85.6337501,41.9455089]},"n2139824786":{"id":"n2139824786","loc":[-85.6337497,41.9455091]},"n2139824787":{"id":"n2139824787","loc":[-85.6345425,41.9455186]},"n2139824788":{"id":"n2139824788","loc":[-85.6341459,41.9455372]},"n2139824789":{"id":"n2139824789","loc":[-85.6341376,41.945542]},"n2139824790":{"id":"n2139824790","loc":[-85.6338394,41.9455462]},"n2139824791":{"id":"n2139824791","loc":[-85.6349171,41.9455588]},"n2139824792":{"id":"n2139824792","loc":[-85.6338074,41.9455646]},"n2139824793":{"id":"n2139824793","loc":[-85.6346229,41.9455894]},"n2139824794":{"id":"n2139824794","loc":[-85.6338983,41.9455995]},"n2139824795":{"id":"n2139824795","loc":[-85.6338962,41.9456007]},"n2139824796":{"id":"n2139824796","loc":[-85.6342475,41.9456348]},"n2139824797":{"id":"n2139824797","loc":[-85.6339505,41.9456497]},"n2139824798":{"id":"n2139824798","loc":[-85.6347243,41.9456788]},"n2139824799":{"id":"n2139824799","loc":[-85.635057,41.9456831]},"n2139824800":{"id":"n2139824800","loc":[-85.635287,41.9457056]},"n2139824801":{"id":"n2139824801","loc":[-85.6350753,41.9457068]},"n2139824802":{"id":"n2139824802","loc":[-85.6347753,41.9457252]},"n2139824803":{"id":"n2139824803","loc":[-85.6340521,41.9457473]},"n2139824804":{"id":"n2139824804","loc":[-85.6352875,41.9457611]},"n2139824805":{"id":"n2139824805","loc":[-85.6352941,41.9457611]},"n2139824806":{"id":"n2139824806","loc":[-85.6350758,41.9457623]},"n2139824807":{"id":"n2139824807","loc":[-85.6348194,41.9457638]},"n2139824808":{"id":"n2139824808","loc":[-85.635296,41.9459428]},"n2139824809":{"id":"n2139824809","loc":[-85.6348212,41.9459455]},"n2139832635":{"id":"n2139832635","loc":[-85.6354612,41.9448791]},"n2139832636":{"id":"n2139832636","loc":[-85.6360241,41.9453844]},"n2139832637":{"id":"n2139832637","loc":[-85.6361452,41.9453121]},"n2139832639":{"id":"n2139832639","loc":[-85.6355997,41.944797]},"n2139832641":{"id":"n2139832641","loc":[-85.6351346,41.9443541]},"n2139832647":{"id":"n2139832647","loc":[-85.6329883,41.9453692]},"n2139832653":{"id":"n2139832653","loc":[-85.6333643,41.9456293]},"n2139832663":{"id":"n2139832663","loc":[-85.6335394,41.9455339]},"n2139832665":{"id":"n2139832665","loc":[-85.6332375,41.9452476]},"n2139832667":{"id":"n2139832667","loc":[-85.6331664,41.9452161]},"n2139832669":{"id":"n2139832669","loc":[-85.6331144,41.9451875]},"n2139832671":{"id":"n2139832671","loc":[-85.6330779,41.9451274]},"n2139832673":{"id":"n2139832673","loc":[-85.6330664,41.9450802]},"n2139832678":{"id":"n2139832678","loc":[-85.6332218,41.9453585]},"n2139832686":{"id":"n2139832686","loc":[-85.6334246,41.945541]},"n2139832691":{"id":"n2139832691","loc":[-85.6329898,41.9454997]},"n2139832693":{"id":"n2139832693","loc":[-85.6343554,41.9443274]},"n2139832694":{"id":"n2139832694","loc":[-85.6336339,41.9437089]},"n2139832696":{"id":"n2139832696","loc":[-85.633532,41.9437708]},"n2139832697":{"id":"n2139832697","loc":[-85.6338316,41.9440868]},"n2139832698":{"id":"n2139832698","loc":[-85.6342258,41.9444141]},"n2139832699":{"id":"n2139832699","loc":[-85.6339164,41.9442166]},"n2139832700":{"id":"n2139832700","loc":[-85.6341389,41.944384]},"n2139832701":{"id":"n2139832701","loc":[-85.634235,41.9443259]},"n2139832702":{"id":"n2139832702","loc":[-85.633613,41.9437875]},"n2139832703":{"id":"n2139832703","loc":[-85.633915,41.9436132]},"n2139832704":{"id":"n2139832704","loc":[-85.6340019,41.9435613]},"n2139832706":{"id":"n2139832706","loc":[-85.6343197,41.9438427]},"n2139832708":{"id":"n2139832708","loc":[-85.6342361,41.9438936]},"n2139832709":{"id":"n2139832709","loc":[-85.6353839,41.9460401]},"n2139832710":{"id":"n2139832710","loc":[-85.6354032,41.9456763]},"n2139832711":{"id":"n2139832711","loc":[-85.6356839,41.9459252]},"n2139832712":{"id":"n2139832712","loc":[-85.6356109,41.945735]},"n2139832713":{"id":"n2139832713","loc":[-85.6353997,41.9457421]},"n2139832714":{"id":"n2139832714","loc":[-85.6353895,41.9459347]},"n2139832715":{"id":"n2139832715","loc":[-85.6334777,41.9436628]},"n2139832716":{"id":"n2139832716","loc":[-85.6333137,41.9435382]},"n2139832717":{"id":"n2139832717","loc":[-85.6330938,41.9435406]},"n2139832721":{"id":"n2139832721","loc":[-85.6333023,41.9434922]},"n2139832722":{"id":"n2139832722","loc":[-85.6330466,41.943623]},"n2139832723":{"id":"n2139832723","loc":[-85.6332746,41.9435624]},"n2139832724":{"id":"n2139832724","loc":[-85.6333511,41.9435176]},"n2139832725":{"id":"n2139832725","loc":[-85.6332241,41.9434001]},"n2139832726":{"id":"n2139832726","loc":[-85.6332355,41.9433686]},"n2139870373":{"id":"n2139870373","loc":[-85.6351783,41.9439117]},"n2139870374":{"id":"n2139870374","loc":[-85.6351431,41.9439217]},"n2139870375":{"id":"n2139870375","loc":[-85.6348853,41.9439117]},"n2139870376":{"id":"n2139870376","loc":[-85.6348317,41.9439105]},"n2139870377":{"id":"n2139870377","loc":[-85.6346384,41.944007]},"n2139870378":{"id":"n2139870378","loc":[-85.6345563,41.9440523]},"n2140006403":{"id":"n2140006403","loc":[-85.6359942,41.9450097]},"n2140006405":{"id":"n2140006405","loc":[-85.6363884,41.9446079]},"n2140006407":{"id":"n2140006407","loc":[-85.6362148,41.9447874]},"n2140006409":{"id":"n2140006409","loc":[-85.6379476,41.9445869]},"n2140006411":{"id":"n2140006411","loc":[-85.6378485,41.9445674]},"n2140006413":{"id":"n2140006413","loc":[-85.6378952,41.9444547]},"n2140006415":{"id":"n2140006415","loc":[-85.6379962,41.944477]},"n2140006421":{"id":"n2140006421","loc":[-85.6355248,41.9433702]},"n2140006423":{"id":"n2140006423","loc":[-85.6378471,41.9439233]},"n2140006425":{"id":"n2140006425","loc":[-85.6378913,41.9441238]},"n2140006426":{"id":"n2140006426","loc":[-85.6381674,41.9442289]},"n2140006427":{"id":"n2140006427","loc":[-85.6382359,41.9440975]},"n2140006428":{"id":"n2140006428","loc":[-85.6382071,41.9440252]},"n2140006429":{"id":"n2140006429","loc":[-85.6381409,41.9439973]},"n2140006430":{"id":"n2140006430","loc":[-85.6380569,41.9440153]},"n2140006433":{"id":"n2140006433","loc":[-85.6379071,41.9442467]},"n2140006435":{"id":"n2140006435","loc":[-85.6381634,41.9443125]},"n2140006436":{"id":"n2140006436","loc":[-85.6382407,41.944301]},"n2140006438":{"id":"n2140006438","loc":[-85.6382761,41.9442188]},"n2140006439":{"id":"n2140006439","loc":[-85.6382429,41.9441761]},"n2140006440":{"id":"n2140006440","loc":[-85.6382016,41.9441632]},"n2140006441":{"id":"n2140006441","loc":[-85.6378185,41.9439835]},"n2166205688":{"id":"n2166205688","loc":[-85.6349963,41.9444392]},"n2168544780":{"id":"n2168544780","loc":[-85.633944,41.945807]},"n2168544781":{"id":"n2168544781","loc":[-85.6340783,41.9458621]},"n2168544782":{"id":"n2168544782","loc":[-85.6338184,41.9457548]},"n2168544783":{"id":"n2168544783","loc":[-85.6339925,41.9459777]},"n2168544784":{"id":"n2168544784","loc":[-85.6337317,41.9458698]},"n2168544785":{"id":"n2168544785","loc":[-85.6337297,41.9460042]},"n2168544786":{"id":"n2168544786","loc":[-85.633919,41.9460797]},"n2168544787":{"id":"n2168544787","loc":[-85.6338672,41.9459263]},"n2168544788":{"id":"n2168544788","loc":[-85.6338246,41.9459853]},"n2168544789":{"id":"n2168544789","loc":[-85.6337615,41.9459601]},"n2168544790":{"id":"n2168544790","loc":[-85.6342079,41.9460399]},"n2168544791":{"id":"n2168544791","loc":[-85.6343346,41.9458503]},"n2168544792":{"id":"n2168544792","loc":[-85.6343759,41.9458116]},"n2168544793":{"id":"n2168544793","loc":[-85.6344394,41.9458109]},"n2168544795":{"id":"n2168544795","loc":[-85.6344827,41.945851]},"n2168544797":{"id":"n2168544797","loc":[-85.6344807,41.945969]},"n2168544798":{"id":"n2168544798","loc":[-85.6344404,41.9459697]},"n2168544799":{"id":"n2168544799","loc":[-85.6344413,41.9460333]},"n2168544800":{"id":"n2168544800","loc":[-85.6342173,41.9460705]},"n2168544801":{"id":"n2168544801","loc":[-85.6342162,41.9460392]},"n2168544802":{"id":"n2168544802","loc":[-85.6344251,41.9460351]},"n2168544805":{"id":"n2168544805","loc":[-85.6344257,41.9460507]},"n2168544807":{"id":"n2168544807","loc":[-85.6344721,41.9460498]},"n2168544809":{"id":"n2168544809","loc":[-85.6344754,41.9461427]},"n2168544811":{"id":"n2168544811","loc":[-85.6344311,41.9461435]},"n2168544813":{"id":"n2168544813","loc":[-85.6344317,41.9461592]},"n2168544815":{"id":"n2168544815","loc":[-85.6343708,41.9461604]},"n2168544817":{"id":"n2168544817","loc":[-85.6343715,41.9461786]},"n2168544819":{"id":"n2168544819","loc":[-85.6343229,41.9461795]},"n2168544821":{"id":"n2168544821","loc":[-85.6343222,41.9461606]},"n2168544823":{"id":"n2168544823","loc":[-85.6342476,41.9461621]},"n2168544825":{"id":"n2168544825","loc":[-85.6342444,41.94607]},"n2168544827":{"id":"n2168544827","loc":[-85.634138,41.9461632]},"n2168544829":{"id":"n2168544829","loc":[-85.6342016,41.9460703]},"n2168544830":{"id":"n2168544830","loc":[-85.6332929,41.9463092]},"n2168544831":{"id":"n2168544831","loc":[-85.633122,41.946239]},"n2168544832":{"id":"n2168544832","loc":[-85.6332954,41.9460055]},"n2168544833":{"id":"n2168544833","loc":[-85.6333954,41.9460466]},"n2168544834":{"id":"n2168544834","loc":[-85.6334044,41.9460345]},"n2168544835":{"id":"n2168544835","loc":[-85.6334594,41.9460571]},"n2168544836":{"id":"n2168544836","loc":[-85.6333871,41.9461544]},"n2168544837":{"id":"n2168544837","loc":[-85.633403,41.9461609]},"n2168544838":{"id":"n2168544838","loc":[-85.6341683,41.9464167]},"n2168544839":{"id":"n2168544839","loc":[-85.6341711,41.9463411]},"n2168544840":{"id":"n2168544840","loc":[-85.6344471,41.9463469]},"n2168544841":{"id":"n2168544841","loc":[-85.6344441,41.9464243]},"n2168544842":{"id":"n2168544842","loc":[-85.6343622,41.9464226]},"n2168544843":{"id":"n2168544843","loc":[-85.6343593,41.9464989]},"n2168544844":{"id":"n2168544844","loc":[-85.6342812,41.9464973]},"n2168544845":{"id":"n2168544845","loc":[-85.634283,41.9464504]},"n2168544846":{"id":"n2168544846","loc":[-85.6342609,41.9464499]},"n2168544847":{"id":"n2168544847","loc":[-85.6342621,41.9464187]},"n2168544848":{"id":"n2168544848","loc":[-85.6348414,41.9463396]},"n2168544849":{"id":"n2168544849","loc":[-85.6348387,41.9461872]},"n2168544850":{"id":"n2168544850","loc":[-85.6351186,41.9461844]},"n2168544851":{"id":"n2168544851","loc":[-85.635119,41.9462112]},"n2168544852":{"id":"n2168544852","loc":[-85.6351918,41.9462104]},"n2168544853":{"id":"n2168544853","loc":[-85.6351944,41.9463515]},"n2168544854":{"id":"n2168544854","loc":[-85.6351049,41.9463524]},"n2168544855":{"id":"n2168544855","loc":[-85.6351046,41.946337]},"n2189153180":{"id":"n2189153180","loc":[-85.6340369,41.9469572]},"n2189153181":{"id":"n2189153181","loc":[-85.6342531,41.946953]},"n2189153183":{"id":"n2189153183","loc":[-85.6348115,41.9465468]},"n2189153184":{"id":"n2189153184","loc":[-85.6348105,41.9464569]},"n2189153185":{"id":"n2189153185","loc":[-85.6351431,41.9464549]},"n2189153186":{"id":"n2189153186","loc":[-85.6351441,41.9465448]},"n2189153187":{"id":"n2189153187","loc":[-85.6350077,41.9465456]},"n2189153188":{"id":"n2189153188","loc":[-85.635008,41.9465721]},"n2189153189":{"id":"n2189153189","loc":[-85.6348965,41.9465727]},"n2189153190":{"id":"n2189153190","loc":[-85.6348962,41.9465463]},"n2189153191":{"id":"n2189153191","loc":[-85.6348963,41.9471586]},"n2189153192":{"id":"n2189153192","loc":[-85.6348944,41.947032]},"n2189153193":{"id":"n2189153193","loc":[-85.6350241,41.947031]},"n2189153194":{"id":"n2189153194","loc":[-85.635026,41.9471575]},"n2189153195":{"id":"n2189153195","loc":[-85.6352328,41.9471053]},"n2189153196":{"id":"n2189153196","loc":[-85.6352359,41.9469906]},"n2189153197":{"id":"n2189153197","loc":[-85.6353694,41.9469925]},"n2189153198":{"id":"n2189153198","loc":[-85.6353664,41.9471072]},"n2189153199":{"id":"n2189153199","loc":[-85.6348241,41.9469287]},"n2189153200":{"id":"n2189153200","loc":[-85.6348248,41.9468185]},"n2189153201":{"id":"n2189153201","loc":[-85.6351199,41.9468195]},"n2189153202":{"id":"n2189153202","loc":[-85.6351192,41.9469298]},"n2189153203":{"id":"n2189153203","loc":[-85.6347965,41.9468057]},"n2189153204":{"id":"n2189153204","loc":[-85.634792,41.9466044]},"n2189153205":{"id":"n2189153205","loc":[-85.6349483,41.9466025]},"n2189153206":{"id":"n2189153206","loc":[-85.6349493,41.9466448]},"n2189153207":{"id":"n2189153207","loc":[-85.6349753,41.9466445]},"n2189153208":{"id":"n2189153208","loc":[-85.6349743,41.9465995]},"n2189153209":{"id":"n2189153209","loc":[-85.6351173,41.9465977]},"n2189153210":{"id":"n2189153210","loc":[-85.6351219,41.9468015]},"n2189153211":{"id":"n2189153211","loc":[-85.6349806,41.9468032]},"n2189153212":{"id":"n2189153212","loc":[-85.6349794,41.9467519]},"n2189153213":{"id":"n2189153213","loc":[-85.6349521,41.9467523]},"n2189153214":{"id":"n2189153214","loc":[-85.6349532,41.9468037]},"n2189153215":{"id":"n2189153215","loc":[-85.6346302,41.9468381]},"n2189153216":{"id":"n2189153216","loc":[-85.6343028,41.9468449]},"n2189153217":{"id":"n2189153217","loc":[-85.6342006,41.9468297]},"n2189153218":{"id":"n2189153218","loc":[-85.6336698,41.9465918]},"n2189153219":{"id":"n2189153219","loc":[-85.6344663,41.9466639]},"n2189153220":{"id":"n2189153220","loc":[-85.6344639,41.9466015]},"n2189153221":{"id":"n2189153221","loc":[-85.6342283,41.9466065]},"n2189153222":{"id":"n2189153222","loc":[-85.6342303,41.9466587]},"n2189153223":{"id":"n2189153223","loc":[-85.6342843,41.9466575]},"n2189153224":{"id":"n2189153224","loc":[-85.6342851,41.9466794]},"n2189153225":{"id":"n2189153225","loc":[-85.6343475,41.9466781]},"n2189153226":{"id":"n2189153226","loc":[-85.634347,41.9466664]},"n2189153227":{"id":"n2189153227","loc":[-85.6354428,41.9470148]},"n2189153228":{"id":"n2189153228","loc":[-85.6354432,41.9468005]},"n2189153229":{"id":"n2189153229","loc":[-85.6360277,41.9468011]},"n2189153230":{"id":"n2189153230","loc":[-85.6360273,41.9470154]},"n2189153231":{"id":"n2189153231","loc":[-85.6354565,41.9465823]},"n2189153232":{"id":"n2189153232","loc":[-85.6354496,41.946218]},"n2189153233":{"id":"n2189153233","loc":[-85.6356355,41.9465788]},"n2189153234":{"id":"n2189153234","loc":[-85.6357155,41.9468008]},"n2189153235":{"id":"n2189153235","loc":[-85.6359539,41.9467969]},"n2189153236":{"id":"n2189153236","loc":[-85.6359561,41.9463036]},"n2189153237":{"id":"n2189153237","loc":[-85.6360129,41.9464793]},"n2189153238":{"id":"n2189153238","loc":[-85.6360152,41.9463898]},"n2189153239":{"id":"n2189153239","loc":[-85.6359607,41.9464928]},"n2189153240":{"id":"n2189153240","loc":[-85.6356903,41.9462227]},"n2189153242":{"id":"n2189153242","loc":[-85.6354163,41.946142]},"n2189153243":{"id":"n2189153243","loc":[-85.6357546,41.9462214]},"n2189153244":{"id":"n2189153244","loc":[-85.6357937,41.9462542]},"n2189153245":{"id":"n2189153245","loc":[-85.6358723,41.9467048]},"n2189153246":{"id":"n2189153246","loc":[-85.6361494,41.946757]},"n2189153247":{"id":"n2189153247","loc":[-85.6354173,41.9469082]},"n2189153248":{"id":"n2189153248","loc":[-85.635443,41.9469079]},"n2189153249":{"id":"n2189153249","loc":[-85.6360275,41.9469093]},"n2189153250":{"id":"n2189153250","loc":[-85.6361542,41.946915]},"n2189153251":{"id":"n2189153251","loc":[-85.6358654,41.9464843]},"n2189153252":{"id":"n2189153252","loc":[-85.6359549,41.9467499]},"n2189153253":{"id":"n2189153253","loc":[-85.6357172,41.9466335]},"n2189153254":{"id":"n2189153254","loc":[-85.6355644,41.9461768]},"n2189153255":{"id":"n2189153255","loc":[-85.6355655,41.946528]},"n2189153256":{"id":"n2189153256","loc":[-85.6357055,41.9465971]},"n2189153257":{"id":"n2189153257","loc":[-85.635869,41.9465971]},"n2189153259":{"id":"n2189153259","loc":[-85.6354561,41.9470278]},"n2189153260":{"id":"n2189153260","loc":[-85.6357961,41.9470233]},"n2189153261":{"id":"n2189153261","loc":[-85.6357977,41.9470907]},"n2189153262":{"id":"n2189153262","loc":[-85.6357297,41.9470916]},"n2189153263":{"id":"n2189153263","loc":[-85.635733,41.947233]},"n2189153264":{"id":"n2189153264","loc":[-85.6362674,41.9468637]},"n2189153265":{"id":"n2189153265","loc":[-85.6362646,41.9467047]},"n2189153266":{"id":"n2189153266","loc":[-85.6363267,41.9467047]},"n2189153267":{"id":"n2189153267","loc":[-85.6362633,41.9465848]},"n2189153268":{"id":"n2189153268","loc":[-85.6363805,41.9465468]},"n2189153269":{"id":"n2189153269","loc":[-85.6364604,41.9466842]},"n2189153270":{"id":"n2189153270","loc":[-85.6364604,41.9468647]},"n2199109756":{"id":"n2199109756","loc":[-85.6337134,41.9471841]},"n2199109757":{"id":"n2199109757","loc":[-85.6336514,41.94716]},"n2199109758":{"id":"n2199109758","loc":[-85.6337043,41.9470847]},"n2199109759":{"id":"n2199109759","loc":[-85.6335997,41.9470441]},"n2199109760":{"id":"n2199109760","loc":[-85.6335064,41.9471771]},"n185960195":{"id":"n185960195","loc":[-85.6295992,41.9524346]},"n185960796":{"id":"n185960796","loc":[-85.634723,41.953681]},"n185961396":{"id":"n185961396","loc":[-85.634767,41.959009]},"n185962625":{"id":"n185962625","loc":[-85.635175,41.97201]},"n185964982":{"id":"n185964982","loc":[-85.632799,41.9440543]},"n185965289":{"id":"n185965289","loc":[-85.634621,41.947323]},"n185965291":{"id":"n185965291","loc":[-85.636166,41.947296]},"n185965399":{"id":"n185965399","loc":[-85.634776,41.959834]},"n185966937":{"id":"n185966937","loc":[-85.633183,41.947315]},"n185966948":{"id":"n185966948","loc":[-85.626406,41.957188]},"n185967422":{"id":"n185967422","loc":[-85.6320229,41.9490123]},"n185967917":{"id":"n185967917","loc":[-85.634763,41.958292]},"n185967918":{"id":"n185967918","loc":[-85.636271,41.958311]},"n185968100":{"id":"n185968100","loc":[-85.630835,41.950656]},"n185970515":{"id":"n185970515","loc":[-85.634832,41.963866]},"n185971578":{"id":"n185971578","loc":[-85.634641,41.948627]},"n185971580":{"id":"n185971580","loc":[-85.6361818,41.9486135]},"n185971631":{"id":"n185971631","loc":[-85.634729,41.954667]},"n185971632":{"id":"n185971632","loc":[-85.636236,41.954656]},"n185972155":{"id":"n185972155","loc":[-85.623333,41.961987]},"n185974583":{"id":"n185974583","loc":[-85.634686,41.951158]},"n185974585":{"id":"n185974585","loc":[-85.6362059,41.9511457]},"n185975064":{"id":"n185975064","loc":[-85.636218,41.953667]},"n185975735":{"id":"n185975735","loc":[-85.634923,41.969269]},"n185978390":{"id":"n185978390","loc":[-85.634668,41.949875]},"n185978392":{"id":"n185978392","loc":[-85.634686,41.952415]},"n185978394":{"id":"n185978394","loc":[-85.634726,41.955921]},"n185978399":{"id":"n185978399","loc":[-85.6347861,41.9606613]},"n185978402":{"id":"n185978402","loc":[-85.634806,41.961485]},"n185978406":{"id":"n185978406","loc":[-85.6348298,41.964783]},"n185978410":{"id":"n185978410","loc":[-85.6348766,41.9677088]},"n185978414":{"id":"n185978414","loc":[-85.634938,41.971566]},"n185978415":{"id":"n185978415","loc":[-85.634942,41.971611]},"n185978417":{"id":"n185978417","loc":[-85.634952,41.971655]},"n185978419":{"id":"n185978419","loc":[-85.634989,41.971741]},"n185978420":{"id":"n185978420","loc":[-85.635063,41.971864]},"n185978787":{"id":"n185978787","loc":[-85.627936,41.954693]},"n185978790":{"id":"n185978790","loc":[-85.626832,41.954677]},"n185978967":{"id":"n185978967","loc":[-85.632278,41.948613]},"n185980735":{"id":"n185980735","loc":[-85.628639,41.953725]},"n185982163":{"id":"n185982163","loc":[-85.636233,41.952398]},"n185982193":{"id":"n185982193","loc":[-85.6313855,41.9499125]},"n185982195":{"id":"n185982195","loc":[-85.6304857,41.9511945]},"n185982196":{"id":"n185982196","loc":[-85.626336,41.957291]},"n185982197":{"id":"n185982197","loc":[-85.625578,41.958664]},"n185982198":{"id":"n185982198","loc":[-85.624619,41.960145]},"n185982200":{"id":"n185982200","loc":[-85.624494,41.960338]},"n185984017":{"id":"n185984017","loc":[-85.636163,41.947382]},"n185984020":{"id":"n185984020","loc":[-85.636188,41.9498803]},"n185984022":{"id":"n185984022","loc":[-85.636276,41.955919]},"n185984024":{"id":"n185984024","loc":[-85.636279,41.956901]},"n185988036":{"id":"n185988036","loc":[-85.631422,41.948294]},"n185988867":{"id":"n185988867","loc":[-85.63102,41.948805]},"n185988869":{"id":"n185988869","loc":[-85.630773,41.949209]},"n185988871":{"id":"n185988871","loc":[-85.63005,41.95016]},"n185988872":{"id":"n185988872","loc":[-85.629423,41.951016]},"n185988873":{"id":"n185988873","loc":[-85.629252,41.951256]},"n185988875":{"id":"n185988875","loc":[-85.629126,41.951489]},"n185988877":{"id":"n185988877","loc":[-85.628991,41.951704]},"n185988878":{"id":"n185988878","loc":[-85.628689,41.952112]},"n185988879":{"id":"n185988879","loc":[-85.628313,41.952666]},"n185988880":{"id":"n185988880","loc":[-85.627687,41.953529]},"n185988882":{"id":"n185988882","loc":[-85.627394,41.953947]},"n185988884":{"id":"n185988884","loc":[-85.627287,41.954128]},"n1819858502":{"id":"n1819858502","loc":[-85.6328435,41.9455473]},"n1819858510":{"id":"n1819858510","loc":[-85.6324841,41.9453438]},"n1819858515":{"id":"n1819858515","loc":[-85.6318511,41.9446409]},"n1819858520":{"id":"n1819858520","loc":[-85.6326558,41.9454708]},"n1819858522":{"id":"n1819858522","loc":[-85.6319048,41.9447407]},"n1819858524":{"id":"n1819858524","loc":[-85.6317718,41.9443666]},"n1819858530":{"id":"n1819858530","loc":[-85.632055,41.9449128]},"n2139795768":{"id":"n2139795768","loc":[-85.6243023,41.9606102]},"n2139832645":{"id":"n2139832645","loc":[-85.6324455,41.9448607]},"n2139832649":{"id":"n2139832649","loc":[-85.6328043,41.9454773]},"n2139832651":{"id":"n2139832651","loc":[-85.6322547,41.9449621]},"n2139832675":{"id":"n2139832675","loc":[-85.6327356,41.944757]},"n2139832677":{"id":"n2139832677","loc":[-85.6325433,41.9448599]},"n2139832680":{"id":"n2139832680","loc":[-85.6328885,41.9455614]},"n2139832682":{"id":"n2139832682","loc":[-85.6320913,41.9449492]},"n2139832684":{"id":"n2139832684","loc":[-85.6325366,41.9447133]},"n2139832688":{"id":"n2139832688","loc":[-85.6322786,41.94485]},"n2139832718":{"id":"n2139832718","loc":[-85.6327486,41.9432475]},"n2139832719":{"id":"n2139832719","loc":[-85.6327926,41.9431773]},"n2139832720":{"id":"n2139832720","loc":[-85.6329033,41.943153]},"n2139832727":{"id":"n2139832727","loc":[-85.6328975,41.9430783]},"n2139844839":{"id":"n2139844839","loc":[-85.6326261,41.9432308]},"n2189015992":{"id":"n2189015992","loc":[-85.6347706,41.9593383]},"n2189153179":{"id":"n2189153179","loc":[-85.6340476,41.9472565]},"n2189153182":{"id":"n2189153182","loc":[-85.6342638,41.9472522]},"n2189153241":{"id":"n2189153241","loc":[-85.6354184,41.9473091]},"n2189153258":{"id":"n2189153258","loc":[-85.6354611,41.9472366]},"n2189153277":{"id":"n2189153277","loc":[-85.6328948,41.9462374]},"n2199109755":{"id":"n2199109755","loc":[-85.6336729,41.9472417]},"w203970139":{"id":"w203970139","tags":{"building":"yes"},"nodes":["n2139824793","n2139824787","n2139824773","n2139824778","n2139824793"]},"w203970098":{"id":"w203970098","tags":{"building":"yes"},"nodes":["n2139824748","n2139824712","n2139824726","n2139824760","n2139824748"]},"w208643132":{"id":"w208643132","tags":{"area":"yes","building":"yes"},"nodes":["n2189153195","n2189153196","n2189153197","n2189153198","n2189153195"]},"w203970094":{"id":"w203970094","tags":{"building":"yes"},"nodes":["n2139824755","n2139824753","n2139824759","n2139824764","n2139824763","n2139824767","n2139824770","n2139824782","n2139824772","n2139824756","n2139824751","n2139824754","n2139824755"]},"w208643138":{"id":"w208643138","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153231","n2189153232","n2189153240","n2189153244","n2189153236","n2189153238","n2189153237","n2189153239","n2189153252","n2189153235","n2189153234","n2189153253","n2189153233","n2189153231"]},"w203970125":{"id":"w203970125","tags":{"building":"yes"},"nodes":["n2139824735","n2139824738","n2139824757","n2139824749","n2139824735"]},"w170848823":{"id":"w170848823","tags":{"name":"Rocky River","waterway":"river"},"nodes":["n1819849189","n1819858516","n1819858519","n1819858504","n1819858525","n1819858506","n1819858513"]},"w203970898":{"id":"w203970898","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832645","n2139832647","n2139832649","n2139832651","n2139832645"]},"w203970134":{"id":"w203970134","tags":{"building":"yes"},"nodes":["n2139824796","n2139824803","n2139824797","n2139824788","n2139824796"]},"w203970104":{"id":"w203970104","tags":{"building":"yes"},"nodes":["n2139824733","n2139824730","n2139824714","n2139824721","n2139824733"]},"w206805245":{"id":"w206805245","tags":{"area":"yes","building":"yes"},"nodes":["n2168544780","n2168544781","n2139824796","n2139824803","n2168544780"]},"w206805252":{"id":"w206805252","tags":{"area":"yes","building":"yes"},"nodes":["n2168544838","n2168544839","n2168544840","n2168544841","n2168544842","n2168544843","n2168544844","n2168544845","n2168544846","n2168544847","n2168544838"]},"w203970099":{"id":"w203970099","tags":{"building":"yes"},"nodes":["n2139824783","n2139824795","n2139824790","n2139824779","n2139824783"]},"w17967730":{"id":"w17967730","tags":{"highway":"residential","name":"Water St"},"nodes":["n185963451","n2189153277","n185988036","n185988867","n185988869","n185988871","n185988872","n185988873","n185988875","n185988877","n185988878","n185988879","n185988880","n185988882","n185988884","n185978790"]},"w208643133":{"id":"w208643133","tags":{"area":"yes","building":"yes"},"nodes":["n2189153199","n2189153200","n2189153201","n2189153202","n2189153199"]},"w203970127":{"id":"w203970127","tags":{"building":"yes"},"nodes":["n2139824794","n2139824783","n2139824789","n2139824797","n2139824794"]},"w208643139":{"id":"w208643139","tags":{"highway":"service"},"nodes":["n185988237","n2189153242","n2189153247","n2189153241"]},"w203988297":{"id":"w203988297","tags":{"amenity":"parking","area":"yes"},"nodes":["n2140006423","n2140006441","n2140006425","n2140006426","n2140006440","n2140006427","n2140006428","n2140006429","n2140006430","n2140006423"]},"w206805250":{"id":"w206805250","tags":{"area":"yes","building":"yes"},"nodes":["n2168544827","n2168544823","n2168544825","n2168544800","n2168544829","n2168544827"]},"w208643140":{"id":"w208643140","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153242","n2189153254","n2189153243","n2189153244","n2189153251","n2189153257","n2189153245","n2189153252","n2189153246"]},"w203974055":{"id":"w203974055","tags":{"bridge":"yes","highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870376","n2139870377"]},"w206805247":{"id":"w206805247","tags":{"area":"yes","building":"yes"},"nodes":["n2168544785","n2168544786","n2168544783","n2168544787","n2168544788","n2168544789","n2168544785"]},"w17964996":{"id":"w17964996","tags":{"highway":"residential","name":"Foster St"},"nodes":["n1819858524","n1819858515","n1819858522","n1819858530","n2139832682","n1819858510","n1819858520","n1819858502","n2139832680","n185963451","n1819858527","n185963452","n185963453","n185963454","n185963455","n185963456"]},"w208643144":{"id":"w208643144","tags":{"area":"yes","building":"yes"},"nodes":["n2189153264","n2189153265","n2189153266","n2189153267","n2189153268","n2189153269","n2189153270","n2189153264"]},"w203970914":{"id":"w203970914","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832722","n2139832723","n2139832724","n2139832725","n2139832726","n2139832727","n2139844839","n2139832722"]},"w208643143":{"id":"w208643143","tags":{"area":"yes","building":"yes"},"nodes":["n2189153258","n2189153259","n2189153260","n2189153261","n2189153262","n2189153263","n2189153258"]},"w203049590":{"id":"w203049590","tags":{"amenity":"parking","area":"yes"},"nodes":["n2130304152","n2130304153","n2140006403","n2130304154","n2130304156","n2130304155","n2130304160","n2130304152"]},"w203974054":{"id":"w203974054","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139858971","n2139870373","n2139870374"]},"w203049595":{"id":"w203049595","tags":{"highway":"service"},"nodes":["n2130304158","n2130304159","n2130304160","n2139832635","n2139832639"]},"w203970913":{"id":"w203970913","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832715","n2139832716","n2139832717","n2139832718","n2139832719","n2139832720","n2139832721","n2139832716"]},"w208643134":{"id":"w208643134","tags":{"area":"yes","building":"yes"},"nodes":["n2189153203","n2189153204","n2189153205","n2189153206","n2189153207","n2189153208","n2189153209","n2189153210","n2189153211","n2189153212","n2189153213","n2189153214","n2189153203"]},"w134150808":{"id":"w134150808","tags":{"bridge":"yes","highway":"residential","name":"Moore St"},"nodes":["n185988239","n185984009","n185988241","n1475284019"]},"w203970115":{"id":"w203970115","tags":{"building":"yes"},"nodes":["n2139824761","n2139824727","n2139824736","n2139824771","n2139824761"]},"w208643130":{"id":"w208643130","tags":{"area":"yes","building":"yes"},"nodes":["n2189153183","n2189153184","n2189153185","n2189153186","n2189153187","n2189153188","n2189153189","n2189153190","n2189153183"]},"w206805246":{"id":"w206805246","tags":{"area":"yes","building":"yes"},"nodes":["n2168544782","n2168544780","n2168544781","n2168544783","n2168544787","n2168544784","n2168544782"]},"w203970138":{"id":"w203970138","tags":{"building":"yes"},"nodes":["n2139824729","n2139824720","n2139824702","n2139824707","n2139824729"]},"w203970133":{"id":"w203970133","tags":{"building":"yes"},"nodes":["n2139824748","n2139824737","n2139824717","n2139824728","n2139824748"]},"w203970907":{"id":"w203970907","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832700","n2139832701","n2139832702"]},"w203974056":{"id":"w203974056","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870377","n2139870378"]},"w203970897":{"id":"w203970897","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2130304156","n2166205688","n2139832635","n2139832636","n2139832637","n2139832639","n2139832641","n2166205688"]},"w203974057":{"id":"w203974057","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870375","n2139870376"]},"w203049594":{"id":"w203049594","tags":{"highway":"service"},"nodes":["n2130304156","n2139870378","n2139832706","n2139832704","n2130304157"]},"w203970122":{"id":"w203970122","tags":{"building":"yes"},"nodes":["n2139824757","n2139824740","n2139824747","n2139824762","n2139824757"]},"w208643136":{"id":"w208643136","tags":{"area":"yes","building":"yes"},"nodes":["n2189153219","n2189153220","n2189153221","n2189153222","n2189153223","n2189153224","n2189153225","n2189153226","n2189153219"]},"w203970128":{"id":"w203970128","tags":{"building":"yes"},"nodes":["n2139824732","n2139824752","n2139824744","n2139824724","n2139824732"]},"w203970097":{"id":"w203970097","tags":{"building":"yes"},"nodes":["n2139824737","n2139824733","n2139824710","n2139824716","n2139824737"]},"w203970137":{"id":"w203970137","tags":{"building":"yes"},"nodes":["n2139824765","n2139824774","n2139824758","n2139824746","n2139824765"]},"w134150840":{"id":"w134150840","tags":{"highway":"residential","name":"Moore St"},"nodes":["n1475284019","n185988243","n185988244","n185988245"]},"w17967628":{"id":"w17967628","tags":{"highway":"residential","name":"Moore St"},"nodes":["n185978388","n2139832709","n185988237","n185988239"]},"w203988292":{"id":"w203988292","tags":{"bridge":"yes","highway":"footway"},"nodes":["n2140006407","n2140006405"]},"w203970118":{"id":"w203970118","tags":{"building":"yes"},"nodes":["n2139824775","n2139824785","n2139824780","n2139824768","n2139824775"]},"w203970121":{"id":"w203970121","tags":{"building":"yes"},"nodes":["n2139824768","n2139824781","n2139824776","n2139824765","n2139824768"]},"w17967752":{"id":"w17967752","tags":{"highway":"residential","name":"Railroad Drive"},"nodes":["n185964980","n2139832699","n2139832700","n2130304158","n185988969","n185988971","n185988972","n1475284011"]},"w203970136":{"id":"w203970136","tags":{"building":"yes"},"nodes":["n2139824798","n2139824793","n2139824777","n2139824784","n2139824798"]},"w203970142":{"id":"w203970142","tags":{"building":"yes"},"nodes":["n2139824808","n2139824809","n2139824807","n2139824806","n2139824801","n2139824800","n2139824804","n2139824805","n2139824808"]},"w208643137":{"id":"w208643137","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153227","n2189153248","n2189153228","n2189153234","n2189153235","n2189153229","n2189153249","n2189153230","n2189153227"]},"w208643129":{"id":"w208643129","tags":{"area":"yes","building":"yes"},"nodes":["n2189153179","n2189153180","n2189153181","n2189153182","n2189153179"]},"w203970909":{"id":"w203970909","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832703","n2139832704","n2139832706","n2139832708","n2139832703"]},"w203970905":{"id":"w203970905","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832688","n2139832691"]},"w203988298":{"id":"w203988298","tags":{"highway":"service"},"nodes":["n2140006431","n2140006433","n2140006435","n2140006436","n2140006437","n2140006438","n2140006439","n2140006440"]},"w203970106":{"id":"w203970106","tags":{"building":"yes"},"nodes":["n2139824798","n2139824791","n2139824799","n2139824802","n2139824798"]},"w203970129":{"id":"w203970129","tags":{"building":"yes"},"nodes":["n2139824787","n2139824782","n2139824766","n2139824769","n2139824787"]},"w208643131":{"id":"w208643131","tags":{"area":"yes","building":"yes"},"nodes":["n2189153191","n2189153192","n2189153193","n2189153194","n2189153191"]},"w206805249":{"id":"w206805249","tags":{"area":"yes","building":"yes"},"nodes":["n2168544800","n2168544801","n2168544802","n2168544805","n2168544807","n2168544809","n2168544811","n2168544813","n2168544815","n2168544817","n2168544819","n2168544821","n2168544823","n2168544825","n2168544800"]},"w134150800":{"id":"w134150800","tags":{"bridge":"yes","highway":"primary","name":"W Michigan Ave","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964972","n185964976"]},"w17966984":{"id":"w17966984","tags":{"highway":"residential","name":"Portage Avenue"},"nodes":["n185978375","n185963456","n2189153218","n185966937","n185978967","n185967422","n185982193","n185968100","n185982195","n185960195","n185980735","n185978787","n185966948","n185982196","n185982197","n185982198","n185982200","n2139795768","n185972155"]},"w203988294":{"id":"w203988294","tags":{"amenity":"shelter","area":"yes","building":"yes","shelter_type":"picnic_shelter"},"nodes":["n2140006409","n2140006411","n2140006413","n2140006415","n2140006409"]},"w203970912":{"id":"w203970912","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832711","n2139832712","n2139832713","n2139832714","n2139832711"]},"w203970119":{"id":"w203970119","tags":{"building":"yes"},"nodes":["n2139824713","n2139824705","n2139824683","n2139824689","n2139824713"]},"w203970114":{"id":"w203970114","tags":{"building":"yes"},"nodes":["n2139824735","n2139824750","n2139824745","n2139824732","n2139824735"]},"w208643142":{"id":"w208643142","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153254","n2189153255","n2189153256","n2189153257"]},"w206805253":{"id":"w206805253","tags":{"area":"yes","building":"yes"},"nodes":["n2168544848","n2168544849","n2168544850","n2168544851","n2168544852","n2168544853","n2168544854","n2168544855","n2168544848"]},"w143497377":{"id":"w143497377","tags":{"highway":"primary","name":"North Main Street","old_ref":"US 131","ref":"US 131 Business"},"nodes":["n185962625","n185978420","n185978419","n185978417","n185978415","n185978414","n185975735","n1475293254","n185978410","n185978406","n185970515","n185978402","n185978399","n185965399","n2189015992","n185961396","n185967917","n185978394","n185971631","n185960796","n185978392","n185974583","n185978390","n185971578","n185965289","n2189153215","n185978388","n185978383","n185978381","n185978379","n185978377","n185978375","n185964982"]},"w134150811":{"id":"w134150811","tags":{"highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964976","n2130304157","n1475284023","n2139832715","n185964980","n185964982"]},"w208643135":{"id":"w208643135","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153215","n2189153216","n2189153217","n2189153218"]},"w17967183":{"id":"w17967183","tags":{"highway":"residential","name":"West Street"},"nodes":["n1475284011","n185984011","n185984013","n185984015","n2189153246","n2189153250","n185965291","n185984017","n185971580","n185984020","n185974585","n185982163","n185975064","n185971632","n185984022","n185984024","n185967918"]},"w134150778":{"id":"w134150778","tags":{"bridge":"yes","highway":"residential","name":"Moore St"},"nodes":["n185988245","n1475283992","n185975911"]},"w206805248":{"id":"w206805248","tags":{"area":"yes","building":"yes"},"nodes":["n2168544790","n2168544791","n2168544792","n2168544793","n2168544795","n2168544797","n2168544798","n2168544799","n2168544802","n2168544801","n2168544790"]},"w203974058":{"id":"w203974058","tags":{"bridge":"yes","highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870374","n2139870375"]},"w203970902":{"id":"w203970902","tags":{"highway":"service"},"nodes":["n2139832678","n2139832691","n2139832680"]},"w203988296":{"id":"w203988296","tags":{"highway":"path"},"nodes":["n2139858967","n2140006421","n2139858935"]},"w206805251":{"id":"w206805251","tags":{"area":"yes","building":"yes"},"nodes":["n2168544830","n2168544831","n2168544832","n2168544833","n2168544834","n2168544835","n2168544836","n2168544837","n2168544830"]},"w203970906":{"id":"w203970906","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832693","n2139832694","n2139832696","n2139832697","n2139832698","n2139832693"]},"w203049598":{"id":"w203049598","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2130304162","n2130304163","n2130304164","n2130304165","n2130304162"]},"w203970911":{"id":"w203970911","tags":{"highway":"service"},"nodes":["n2139832709","n2139832714","n2139832713","n2139832710","n185988971"]},"w203970105":{"id":"w203970105","tags":{"building":"yes"},"nodes":["n2139824779","n2139824792","n2139824786","n2139824775","n2139824779"]},"w203988290":{"id":"w203988290","tags":{"highway":"footway"},"nodes":["n2140006403","n2140006407"]},"w203970900":{"id":"w203970900","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832653","n2139832663","n2139832665","n2139832667","n2139832669","n2139832671","n2139832673","n2139832675","n2139832677","n2139832653"]},"w209717048":{"id":"w209717048","tags":{"area":"yes","building":"yes"},"nodes":["n2199109755","n2199109756","n2199109757","n2199109758","n2199109759","n2199109760","n2199109755"]},"w208643141":{"id":"w208643141","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153247","n2189153248","n2189153249","n2189153250"]},"w203970903":{"id":"w203970903","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832682","n2139832688","n2139832684","n2139832678","n2139832686"]},"n354002527":{"id":"n354002527","loc":[-85.6236039,41.9458813],"tags":{"amenity":"school","name":"Barrows School"}},"n185963396":{"id":"n185963396","loc":[-85.627401,41.943496]},"n185963397":{"id":"n185963397","loc":[-85.627403,41.943625]},"n185965101":{"id":"n185965101","loc":[-85.626409,41.943215]},"n185971474":{"id":"n185971474","loc":[-85.624884,41.943508]},"n185971475":{"id":"n185971475","loc":[-85.625191,41.943509]},"n185971482":{"id":"n185971482","loc":[-85.624882,41.94382]},"n185983135":{"id":"n185983135","loc":[-85.624893,41.945616]},"n185983137":{"id":"n185983137","loc":[-85.624912,41.946524]},"n185988027":{"id":"n185988027","loc":[-85.622721,41.946535]},"n185963398":{"id":"n185963398","loc":[-85.6273993,41.9446899]},"n185983238":{"id":"n185983238","loc":[-85.6227157,41.9456321]},"n185980374":{"id":"n185980374","loc":[-85.6248856,41.9447242]},"n185980373":{"id":"n185980373","loc":[-85.6226744,41.9447371]},"n2196831342":{"id":"n2196831342","loc":[-85.6250924,41.945063]},"n2196831343":{"id":"n2196831343","loc":[-85.6252335,41.9450636]},"n2196831344":{"id":"n2196831344","loc":[-85.6252286,41.9448707]},"n2196831345":{"id":"n2196831345","loc":[-85.6250661,41.9448707]},"n2196831346":{"id":"n2196831346","loc":[-85.6250243,41.9449012]},"n2196831347":{"id":"n2196831347","loc":[-85.6250251,41.9449244]},"n2196831348":{"id":"n2196831348","loc":[-85.6250867,41.9449257]},"n2196831349":{"id":"n2196831349","loc":[-85.625349,41.9445058]},"n2196831350":{"id":"n2196831350","loc":[-85.6253471,41.9443882]},"n2196831351":{"id":"n2196831351","loc":[-85.6251516,41.94439]},"n2196831352":{"id":"n2196831352","loc":[-85.6251522,41.9444308]},"n2196831353":{"id":"n2196831353","loc":[-85.6251344,41.9444309]},"n2196831354":{"id":"n2196831354","loc":[-85.6251356,41.9445077]},"n2196831355":{"id":"n2196831355","loc":[-85.6232357,41.9463406]},"n2196831356":{"id":"n2196831356","loc":[-85.6232409,41.9460668]},"n2196831357":{"id":"n2196831357","loc":[-85.6232072,41.9460665]},"n2196831358":{"id":"n2196831358","loc":[-85.6232117,41.9458272]},"n2196831359":{"id":"n2196831359","loc":[-85.6229808,41.9458248]},"n2196831360":{"id":"n2196831360","loc":[-85.6229763,41.9460627]},"n2196831361":{"id":"n2196831361","loc":[-85.623006,41.946063]},"n2196831362":{"id":"n2196831362","loc":[-85.6230023,41.9462557]},"n2196831363":{"id":"n2196831363","loc":[-85.6230755,41.9462565]},"n2196831364":{"id":"n2196831364","loc":[-85.6230739,41.9463389]},"n185947349":{"id":"n185947349","loc":[-85.618327,41.945607]},"n185947359":{"id":"n185947359","loc":[-85.615453,41.945597]},"n185947378":{"id":"n185947378","loc":[-85.617231,41.945603]},"n185947474":{"id":"n185947474","loc":[-85.616136,41.945602]},"n185948972":{"id":"n185948972","loc":[-85.615273,41.945637]},"n185955019":{"id":"n185955019","loc":[-85.620172,41.945627]},"n185960682":{"id":"n185960682","loc":[-85.622759,41.951845]},"n185961369":{"id":"n185961369","loc":[-85.622758,41.947444]},"n185961371":{"id":"n185961371","loc":[-85.624908,41.947416]},"n185963392":{"id":"n185963392","loc":[-85.6270462,41.9409953]},"n185963393":{"id":"n185963393","loc":[-85.627295,41.941304]},"n185963394":{"id":"n185963394","loc":[-85.627352,41.94148]},"n185963395":{"id":"n185963395","loc":[-85.62737,41.942261]},"n185965099":{"id":"n185965099","loc":[-85.6264,41.942263]},"n185965108":{"id":"n185965108","loc":[-85.622769,41.949224]},"n185965110":{"id":"n185965110","loc":[-85.624937,41.949237]},"n185966295":{"id":"n185966295","loc":[-85.6299942,41.9446689]},"n185966342":{"id":"n185966342","loc":[-85.624873,41.942022]},"n185970222":{"id":"n185970222","loc":[-85.622761,41.948357]},"n185970224":{"id":"n185970224","loc":[-85.624924,41.9483338]},"n185971477":{"id":"n185971477","loc":[-85.620051,41.94383]},"n185971478":{"id":"n185971478","loc":[-85.621219,41.943801]},"n185971481":{"id":"n185971481","loc":[-85.621812,41.943807]},"n185973866":{"id":"n185973866","loc":[-85.627629,41.946498]},"n185974699":{"id":"n185974699","loc":[-85.6227688,41.950119]},"n185978800":{"id":"n185978800","loc":[-85.623953,41.954684]},"n185980372":{"id":"n185980372","loc":[-85.621459,41.944756]},"n185980378":{"id":"n185980378","loc":[-85.6286375,41.9446764]},"n185980380":{"id":"n185980380","loc":[-85.630139,41.944661]},"n185980382":{"id":"n185980382","loc":[-85.630298,41.944635]},"n185980384":{"id":"n185980384","loc":[-85.630759,41.94454]},"n185980386":{"id":"n185980386","loc":[-85.6312369,41.9444548]},"n185983133":{"id":"n185983133","loc":[-85.6248672,41.9415903]},"n185983139":{"id":"n185983139","loc":[-85.624951,41.950239]},"n185983140":{"id":"n185983140","loc":[-85.624934,41.950681]},"n185983141":{"id":"n185983141","loc":[-85.624813,41.950983]},"n185983143":{"id":"n185983143","loc":[-85.6246225,41.951591]},"n185983144":{"id":"n185983144","loc":[-85.623908,41.9539165]},"n185983145":{"id":"n185983145","loc":[-85.6238903,41.9540956]},"n185983146":{"id":"n185983146","loc":[-85.623898,41.95431]},"n185983236":{"id":"n185983236","loc":[-85.628481,41.945611]},"n185985914":{"id":"n185985914","loc":[-85.620072,41.946538]},"n185986812":{"id":"n185986812","loc":[-85.6227785,41.9510005]},"n185988028":{"id":"n185988028","loc":[-85.6281401,41.9469632]},"n185988030":{"id":"n185988030","loc":[-85.6282451,41.9470314]},"n185988032":{"id":"n185988032","loc":[-85.6283312,41.9470656]},"w17964989":{"id":"w17964989","tags":{"highway":"residential","name":"Middle St"},"nodes":["n185963392","n185963393","n185963394","n185963395","n185963396","n185963397","n185963398"]},"w17965158":{"id":"w17965158","tags":{"access":"private","highway":"service","name":"Battle St"},"nodes":["n185965099","n185965101"]},"w41074896":{"id":"w41074896","tags":{"highway":"secondary","name":"East Michigan Avenue","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185980372","n185980373","n185980374","n185963398","n185980378","n185966295","n185980380","n185980382","n185980384","n185980386"]},"w17965846":{"id":"w17965846","tags":{"highway":"residential","name":"2nd Ave"},"nodes":["n185971477","n185971478","n185971481","n185971482"]},"w209470306":{"id":"w209470306","tags":{"area":"yes","building":"yes"},"nodes":["n2196831349","n2196831350","n2196831351","n2196831352","n2196831353","n2196831354","n2196831349"]},"w17965845":{"id":"w17965845","tags":{"highway":"residential","name":"2nd Ave"},"nodes":["n185971474","n185971475","n185963396"]},"w209470307":{"id":"w209470307","tags":{"area":"yes","building":"yes"},"nodes":["n2196831355","n2196831356","n2196831357","n2196831358","n2196831359","n2196831360","n2196831361","n2196831362","n2196831363","n2196831364","n2196831355"]},"w17968192":{"id":"w17968192","tags":{"highway":"residential","name":"Washington St"},"nodes":["n185980373","n185983238","n185988027","n185961369","n185970222","n185965108","n185974699","n185986812","n185960682"]},"w17967603":{"id":"w17967603","tags":{"highway":"residential","name":"5th Ave"},"nodes":["n185985914","n185988027","n185983137","n185973866","n185988028","n185988030","n185988032"]},"w209470305":{"id":"w209470305","tags":{"area":"yes","building":"yes"},"nodes":["n2196831342","n2196831343","n2196831344","n2196831345","n2196831346","n2196831347","n2196831348","n2196831342"]},"w17967092":{"id":"w17967092","tags":{"highway":"residential","name":"Wood St"},"nodes":["n185983133","n185966342","n185971474","n185971482","n185980374","n185983135","n185983137","n185961371","n185970224","n185965110","n185983139","n185983140","n185983141","n185983143","n185983144","n185983145","n185983146","n185978800"]},"w17967107":{"id":"w17967107","tags":{"highway":"residential","name":"4th Ave"},"nodes":["n185983236","n185983135","n185983238","n185955019","n185947349","n185947378","n185947474","n185947359","n185948972"]},"n354030330":{"id":"n354030330","loc":[-85.6297222,41.9444444],"tags":{"leisure":"park","name":"Scouter Park"}},"n185966296":{"id":"n185966296","loc":[-85.629998,41.944078]},"n185966298":{"id":"n185966298","loc":[-85.629972,41.943927]},"n185966300":{"id":"n185966300","loc":[-85.629948,41.943783]},"n185980391":{"id":"n185980391","loc":[-85.6322992,41.9442766]},"n185980393":{"id":"n185980393","loc":[-85.6324925,41.9442136]},"n185980389":{"id":"n185980389","loc":[-85.6320272,41.9443281]},"n185980388":{"id":"n185980388","loc":[-85.6315778,41.9443959]},"n354031320":{"id":"n354031320","loc":[-85.6280556,41.9447222],"tags":{"amenity":"place_of_worship","name":"Riverside Church","religion":"christian"}},"n185987309":{"id":"n185987309","loc":[-85.6286497,41.9453531]},"n185987311":{"id":"n185987311","loc":[-85.6285942,41.9454805]},"n185988034":{"id":"n185988034","loc":[-85.6285815,41.9471692]},"n185988896":{"id":"n185988896","loc":[-85.6318433,41.9437929]},"n185977764":{"id":"n185977764","loc":[-85.6322988,41.943472]},"n1819848852":{"id":"n1819848852","loc":[-85.6315188,41.9448808]},"n1819848912":{"id":"n1819848912","loc":[-85.6284289,41.9472189]},"n1819848925":{"id":"n1819848925","loc":[-85.6314501,41.9451617]},"n1819848949":{"id":"n1819848949","loc":[-85.6309394,41.9455192]},"n1819848951":{"id":"n1819848951","loc":[-85.6290297,41.9457187]},"n1819848963":{"id":"n1819848963","loc":[-85.630521,41.9455591]},"n1819848981":{"id":"n1819848981","loc":[-85.6292936,41.9455846]},"n1819848989":{"id":"n1819848989","loc":[-85.6298451,41.9455431]},"n1819848998":{"id":"n1819848998","loc":[-85.6314973,41.9446254]},"n1819849018":{"id":"n1819849018","loc":[-85.6302807,41.9455527]},"n1819849043":{"id":"n1819849043","loc":[-85.6285533,41.9469731]},"n1819849087":{"id":"n1819849087","loc":[-85.6314501,41.9453532]},"n1819849090":{"id":"n1819849090","loc":[-85.628843,41.9461033]},"n1819849109":{"id":"n1819849109","loc":[-85.6311926,41.9454729]},"n1819849116":{"id":"n1819849116","loc":[-85.6288967,41.9459437]},"n1819849177":{"id":"n1819849177","loc":[-85.6287894,41.9464544]},"n1819858529":{"id":"n1819858529","loc":[-85.6325485,41.9445625]},"n2189112797":{"id":"n2189112797","loc":[-85.6275271,41.944555]},"n2189112798":{"id":"n2189112798","loc":[-85.6275196,41.9437258]},"n2189112799":{"id":"n2189112799","loc":[-85.6278937,41.943723]},"n2189112800":{"id":"n2189112800","loc":[-85.6278969,41.9439191]},"n2189112801":{"id":"n2189112801","loc":[-85.6279907,41.9439345]},"n2189112802":{"id":"n2189112802","loc":[-85.6280817,41.9439663]},"n2189112803":{"id":"n2189112803","loc":[-85.6281768,41.9440145]},"n2189112804":{"id":"n2189112804","loc":[-85.6281933,41.9440483]},"n2189112805":{"id":"n2189112805","loc":[-85.6281671,41.9440535]},"n2189112806":{"id":"n2189112806","loc":[-85.6281933,41.9440935]},"n2189112807":{"id":"n2189112807","loc":[-85.6282126,41.9441437]},"n2189112808":{"id":"n2189112808","loc":[-85.628214,41.9441991]},"n2189112809":{"id":"n2189112809","loc":[-85.6283298,41.944196]},"n2189112810":{"id":"n2189112810","loc":[-85.6283285,41.9442616]},"n2189112811":{"id":"n2189112811","loc":[-85.6281727,41.9442616]},"n2189112812":{"id":"n2189112812","loc":[-85.6281713,41.9442934]},"n2189112813":{"id":"n2189112813","loc":[-85.6280386,41.9442963]},"n2189112814":{"id":"n2189112814","loc":[-85.6280405,41.9443292]},"n2189112815":{"id":"n2189112815","loc":[-85.627829,41.9443349]},"n2189112816":{"id":"n2189112816","loc":[-85.6278347,41.9445495]},"n2189153271":{"id":"n2189153271","loc":[-85.6321053,41.9460342]},"n2189153272":{"id":"n2189153272","loc":[-85.632278,41.9457841]},"n2189153273":{"id":"n2189153273","loc":[-85.632823,41.9459936]},"n2189153274":{"id":"n2189153274","loc":[-85.6326845,41.9461963]},"n2189153275":{"id":"n2189153275","loc":[-85.6325664,41.9461507]},"n2189153276":{"id":"n2189153276","loc":[-85.6325323,41.946198]},"n2189153278":{"id":"n2189153278","loc":[-85.6321916,41.9459733]},"n2189153279":{"id":"n2189153279","loc":[-85.6322598,41.9458703]},"n2189153280":{"id":"n2189153280","loc":[-85.6327208,41.9460358]},"n2189153281":{"id":"n2189153281","loc":[-85.6326413,41.9461422]},"n185959079":{"id":"n185959079","loc":[-85.6293702,41.9474668]},"n185966301":{"id":"n185966301","loc":[-85.629692,41.943136]},"n185966304":{"id":"n185966304","loc":[-85.629565,41.942916]},"n185966308":{"id":"n185966308","loc":[-85.629501,41.942751]},"n185966315":{"id":"n185966315","loc":[-85.629472,41.942578]},"n185966319":{"id":"n185966319","loc":[-85.629444,41.942414]},"n185966321":{"id":"n185966321","loc":[-85.629391,41.94205]},"n185966323":{"id":"n185966323","loc":[-85.629369,41.941858]},"n185966327":{"id":"n185966327","loc":[-85.629297,41.941604]},"n185966331":{"id":"n185966331","loc":[-85.629233,41.941549]},"n185966336":{"id":"n185966336","loc":[-85.628504,41.941364]},"n185966338":{"id":"n185966338","loc":[-85.628275,41.941303]},"n185966340":{"id":"n185966340","loc":[-85.6269038,41.9410983]},"n185973867":{"id":"n185973867","loc":[-85.626843,41.947333]},"n185977762":{"id":"n185977762","loc":[-85.6318441,41.9429453]},"n1819848853":{"id":"n1819848853","loc":[-85.625854,41.9492218]},"n1819848861":{"id":"n1819848861","loc":[-85.6251459,41.9552376]},"n1819848874":{"id":"n1819848874","loc":[-85.6267445,41.9482961]},"n1819848882":{"id":"n1819848882","loc":[-85.6257209,41.9552396]},"n1819848883":{"id":"n1819848883","loc":[-85.624706,41.9523173]},"n1819848907":{"id":"n1819848907","loc":[-85.62609,41.9561471]},"n1819848908":{"id":"n1819848908","loc":[-85.6244013,41.9549284]},"n1819848911":{"id":"n1819848911","loc":[-85.6265578,41.9553672]},"n1819848923":{"id":"n1819848923","loc":[-85.6246802,41.9550959]},"n1819848936":{"id":"n1819848936","loc":[-85.6241588,41.9539291]},"n1819848940":{"id":"n1819848940","loc":[-85.62506,41.9511129]},"n1819848944":{"id":"n1819848944","loc":[-85.624942,41.9515912]},"n1819848950":{"id":"n1819848950","loc":[-85.6273989,41.9475461]},"n1819848957":{"id":"n1819848957","loc":[-85.627695,41.947404]},"n1819849009":{"id":"n1819849009","loc":[-85.6259248,41.94896]},"n1819849037":{"id":"n1819849037","loc":[-85.6257252,41.9502112]},"n1819849061":{"id":"n1819849061","loc":[-85.6270084,41.9479626]},"n1819849073":{"id":"n1819849073","loc":[-85.6243734,41.9534583]},"n1819849091":{"id":"n1819849091","loc":[-85.6241373,41.9543918]},"n1819849130":{"id":"n1819849130","loc":[-85.6282572,41.9473067]},"n1819849143":{"id":"n1819849143","loc":[-85.625281,41.9506596]},"n1819849153":{"id":"n1819849153","loc":[-85.6258647,41.9498043]},"n1819849168":{"id":"n1819849168","loc":[-85.6265084,41.9559317]},"n1819849173":{"id":"n1819849173","loc":[-85.6263325,41.9552156]},"n1819849175":{"id":"n1819849175","loc":[-85.6266372,41.9556764]},"n1819849178":{"id":"n1819849178","loc":[-85.6242232,41.9545993]},"n1819849181":{"id":"n1819849181","loc":[-85.6262187,41.9486712]},"n1819849188":{"id":"n1819849188","loc":[-85.6245558,41.9530434]},"n1819849190":{"id":"n1819849190","loc":[-85.6255982,41.9563017]},"n2168544738":{"id":"n2168544738","loc":[-85.6245707,41.9529711]},"w208643145":{"id":"w208643145","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153271","n2189153272","n2189153273","n2189153274","n2189153275","n2189153276","n2189153271"]},"w17967561":{"id":"w17967561","tags":{"highway":"residential","name":"Garden St"},"nodes":["n185980378","n185987309","n185987311","n185983236","n185973866"]},"w134150802":{"id":"w134150802","tags":{"bridge":"yes","highway":"secondary","name":"East Michigan Avenue","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185980386","n185980388"]},"w208639462":{"id":"w208639462","tags":{"area":"yes","building":"yes"},"nodes":["n2189112797","n2189112798","n2189112799","n2189112800","n2189112801","n2189112802","n2189112803","n2189112804","n2189112805","n2189112806","n2189112807","n2189112808","n2189112809","n2189112810","n2189112811","n2189112812","n2189112813","n2189112814","n2189112815","n2189112816","n2189112797"]},"w134150830":{"id":"w134150830","tags":{"bridge":"yes","highway":"secondary","name":"South Main Street","old_ref":"US 131","ref":"M 86"},"nodes":["n185977762","n185977764"]},"w134150801":{"id":"w134150801","tags":{"highway":"secondary","name":"South Main Street","old_ref":"US 131","ref":"M 86"},"nodes":["n185977764","n185964982"]},"w208643146":{"id":"w208643146","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153277","n2189153281","n2189153278","n2189153279","n2189153280","n2189153281"]},"w17966061":{"id":"w17966061","tags":{"highway":"residential","name":"John Glenn Ct"},"nodes":["n185973866","n185973867"]},"w134150772":{"id":"w134150772","tags":{"highway":"residential","name":"5th Ave"},"nodes":["n185988034","n185959079","n185988036","n185978967"]},"w134150836":{"id":"w134150836","tags":{"highway":"secondary","name":"East Michigan Avenue","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185980388","n1819858524","n185980389","n185980391","n185980393","n185964982"]},"w17967734":{"id":"w17967734","tags":{"highway":"residential","name":"Water Street"},"nodes":["n185988896","n185980391","n1819858529"]},"w17965305":{"id":"w17965305","tags":{"highway":"residential","name":"River Dr"},"nodes":["n185966295","n185966296","n185966298","n185966300","n185966301","n185966304","n185966308","n185966315","n185966319","n185966321","n185966323","n185966327","n185966331","n185966336","n185966338","n185963392","n185966340","n185966342"]},"w134150826":{"id":"w134150826","tags":{"bridge":"yes","highway":"residential","name":"5th Ave"},"nodes":["n185988032","n185988034"]},"w170848330":{"id":"w170848330","tags":{"name":"Portage River","waterway":"river"},"nodes":["n1819849190","n1819848907","n1819849168","n1819849175","n1819848911","n1819849173","n1819848882","n1819848861","n1819848923","n1819848908","n1819849178","n1819849091","n1819848936","n1819849073","n1819849188","n2168544738","n1819848883","n1819848944","n1819848940","n1819849143","n1819849037","n1819849153","n1819848853","n1819849009","n1819849181","n1819848874","n1819849061","n1819848950","n1819848957","n1819849130","n1819848912","n1819849043","n1819849177","n1819849090","n1819849116","n1819848951","n1819848981","n1819848989","n1819849018","n1819848963","n1819848949","n1819849109","n1819849087","n1819848925","n1819848852","n1819848998","n1819849057"]},"r270264":{"id":"r270264","tags":{"network":"US:MI","ref":"86","route":"road","state_id":"MI","type":"route","url":"http://en.wikipedia.org/wiki/M-86_%28Michigan_highway%29"},"members":[{"id":"w17737723","type":"way","role":""},{"id":"w17735949","type":"way","role":""},{"id":"w17740404","type":"way","role":""},{"id":"w17966273","type":"way","role":""},{"id":"w17964745","type":"way","role":""},{"id":"w151538068","type":"way","role":""},{"id":"w151538067","type":"way","role":""},{"id":"w17964960","type":"way","role":""},{"id":"w17966099","type":"way","role":""},{"id":"w17968009","type":"way","role":""},{"id":"w41259499","type":"way","role":""},{"id":"w151540401","type":"way","role":""},{"id":"w151540418","type":"way","role":""},{"id":"w17967997","type":"way","role":""},{"id":"w17966029","type":"way","role":""},{"id":"w17964801","type":"way","role":""},{"id":"w41259496","type":"way","role":""},{"id":"w151540399","type":"way","role":""},{"id":"w17968004","type":"way","role":""},{"id":"w17966462","type":"way","role":""},{"id":"w134150830","type":"way","role":""},{"id":"w134150801","type":"way","role":""},{"id":"w17732295","type":"way","role":""}]},"n185980093":{"id":"n185980093","loc":[-85.6271414,41.9407274]},"n185964330":{"id":"n185964330","loc":[-85.6235688,41.9399111]},"n185964328":{"id":"n185964328","loc":[-85.6235609,41.9391301]},"n185958034":{"id":"n185958034","loc":[-85.627102,41.939125]},"n185964331":{"id":"n185964331","loc":[-85.623571,41.940124]},"n185964329":{"id":"n185964329","loc":[-85.623562,41.9392411]},"n185972756":{"id":"n185972756","loc":[-85.623802,41.939102]},"n185972757":{"id":"n185972757","loc":[-85.623584,41.93913]},"n185975325":{"id":"n185975325","loc":[-85.624835,41.939318]},"n185975326":{"id":"n185975326","loc":[-85.624811,41.939435]},"n185975327":{"id":"n185975327","loc":[-85.624635,41.939703]},"n185975328":{"id":"n185975328","loc":[-85.624366,41.940055]},"n185975330":{"id":"n185975330","loc":[-85.624287,41.940113]},"n185975332":{"id":"n185975332","loc":[-85.624215,41.940134]},"n185980088":{"id":"n185980088","loc":[-85.627127,41.940086]},"n185988943":{"id":"n185988943","loc":[-85.622643,41.940128]},"n185988961":{"id":"n185988961","loc":[-85.627263,41.940082]},"n185990192":{"id":"n185990192","loc":[-85.622933,41.939224]},"n185990194":{"id":"n185990194","loc":[-85.621976,41.939203]},"n185991378":{"id":"n185991378","loc":[-85.622643,41.940635]},"n1475283999":{"id":"n1475283999","loc":[-85.6271165,41.9408429]},"n185980090":{"id":"n185980090","loc":[-85.6271315,41.9402001]},"n185958036":{"id":"n185958036","loc":[-85.6248366,41.9391615]},"n1819800188":{"id":"n1819800188","loc":[-85.6246947,41.9401644]},"n1819800199":{"id":"n1819800199","loc":[-85.6233686,41.9430896]},"n1819800204":{"id":"n1819800204","loc":[-85.6223236,41.9408587]},"n1819800213":{"id":"n1819800213","loc":[-85.6247526,41.9414138]},"n1819800216":{"id":"n1819800216","loc":[-85.6230961,41.9407151]},"n1819800218":{"id":"n1819800218","loc":[-85.621991,41.9429336]},"n1819800221":{"id":"n1819800221","loc":[-85.6246088,41.9424708]},"n1819800227":{"id":"n1819800227","loc":[-85.6241368,41.9403081]},"n1819800230":{"id":"n1819800230","loc":[-85.6226776,41.9431012]},"n1819800231":{"id":"n1819800231","loc":[-85.6243728,41.9401644]},"n1819800232":{"id":"n1819800232","loc":[-85.6249629,41.9408907]},"n1819800248":{"id":"n1819800248","loc":[-85.6238685,41.9405555]},"n1819800266":{"id":"n1819800266","loc":[-85.6246882,41.9418367]},"n1819800271":{"id":"n1819800271","loc":[-85.62492,41.9413695]},"n1819800294":{"id":"n1819800294","loc":[-85.6243556,41.9427465]},"n1819800304":{"id":"n1819800304","loc":[-85.6251453,41.94117]},"n1819800325":{"id":"n1819800325","loc":[-85.6248234,41.9405714]},"n1819800362":{"id":"n1819800362","loc":[-85.6239544,41.9429416]},"n1819800368":{"id":"n1819800368","loc":[-85.6243406,41.9402283]},"n1819800375":{"id":"n1819800375","loc":[-85.6226562,41.940755]},"n1819800377":{"id":"n1819800377","loc":[-85.6232033,41.9406512]},"n185945133":{"id":"n185945133","loc":[-85.623501,41.933232]},"n185945135":{"id":"n185945135","loc":[-85.624776,41.933205]},"n185945395":{"id":"n185945395","loc":[-85.624741,41.93019]},"n185952239":{"id":"n185952239","loc":[-85.615166,41.9382]},"n185954490":{"id":"n185954490","loc":[-85.624721,41.929278]},"n185957831":{"id":"n185957831","loc":[-85.625041,41.938662]},"n185958030":{"id":"n185958030","loc":[-85.629033,41.93913]},"n185958032":{"id":"n185958032","loc":[-85.628429,41.939143]},"n185958498":{"id":"n185958498","loc":[-85.621605,41.940143]},"n185961186":{"id":"n185961186","loc":[-85.624792,41.935214]},"n185963099":{"id":"n185963099","loc":[-85.6204461,41.9401485]},"n185963698":{"id":"n185963698","loc":[-85.6297342,41.9400783]},"n185964320":{"id":"n185964320","loc":[-85.623511,41.934216]},"n185964322":{"id":"n185964322","loc":[-85.6235312,41.9362084]},"n185964324":{"id":"n185964324","loc":[-85.6235488,41.9371726]},"n185964326":{"id":"n185964326","loc":[-85.6235512,41.9381718]},"n185967077":{"id":"n185967077","loc":[-85.617359,41.940161]},"n185967634":{"id":"n185967634","loc":[-85.6248039,41.9362012]},"n185970833":{"id":"n185970833","loc":[-85.6248019,41.9381684]},"n185972752":{"id":"n185972752","loc":[-85.624582,41.938848]},"n185972754":{"id":"n185972754","loc":[-85.6242,41.939008]},"n185973251":{"id":"n185973251","loc":[-85.602727,41.936012]},"n185974509":{"id":"n185974509","loc":[-85.62478,41.93217]},"n185975315":{"id":"n185975315","loc":[-85.624703,41.925597]},"n185975316":{"id":"n185975316","loc":[-85.624716,41.927359]},"n185975317":{"id":"n185975317","loc":[-85.62475,41.93119]},"n185975318":{"id":"n185975318","loc":[-85.624782,41.934218]},"n185975320":{"id":"n185975320","loc":[-85.6247949,41.9371708]},"n185977754":{"id":"n185977754","loc":[-85.6276,41.937412]},"n185980075":{"id":"n185980075","loc":[-85.627451,41.937549]},"n185980077":{"id":"n185980077","loc":[-85.627375,41.937618]},"n185980078":{"id":"n185980078","loc":[-85.627278,41.937728]},"n185980079":{"id":"n185980079","loc":[-85.627199,41.937842]},"n185980081":{"id":"n185980081","loc":[-85.627141,41.937981]},"n185980083":{"id":"n185980083","loc":[-85.627109,41.938153]},"n185980085":{"id":"n185980085","loc":[-85.627101,41.938699]},"n185981173":{"id":"n185981173","loc":[-85.61433,41.940167]},"n185987021":{"id":"n185987021","loc":[-85.628311,41.942261]},"n185988963":{"id":"n185988963","loc":[-85.628439,41.940086]},"n185990195":{"id":"n185990195","loc":[-85.621225,41.939143]},"n185990196":{"id":"n185990196","loc":[-85.620576,41.939033]},"n185990198":{"id":"n185990198","loc":[-85.619081,41.938804]},"n185990200":{"id":"n185990200","loc":[-85.617593,41.938552]},"n185990202":{"id":"n185990202","loc":[-85.617372,41.938535]},"n185990204":{"id":"n185990204","loc":[-85.616087,41.93832]},"n185990206":{"id":"n185990206","loc":[-85.615754,41.938289]},"n185990209":{"id":"n185990209","loc":[-85.615438,41.938251]},"n185990211":{"id":"n185990211","loc":[-85.613469,41.937867]},"n185990212":{"id":"n185990212","loc":[-85.610172,41.937298]},"n185990213":{"id":"n185990213","loc":[-85.605537,41.936497]},"n185990214":{"id":"n185990214","loc":[-85.604014,41.936234]},"n1819800180":{"id":"n1819800180","loc":[-85.588775,41.9455032]},"n1819800181":{"id":"n1819800181","loc":[-85.6074212,41.9408827]},"n1819800182":{"id":"n1819800182","loc":[-85.6131397,41.9427022]},"n1819800183":{"id":"n1819800183","loc":[-85.6171523,41.9416807]},"n1819800184":{"id":"n1819800184","loc":[-85.602465,41.9397415]},"n1819800185":{"id":"n1819800185","loc":[-85.6109296,41.9410583]},"n1819800186":{"id":"n1819800186","loc":[-85.6165729,41.9418004]},"n1819800189":{"id":"n1819800189","loc":[-85.5866293,41.9458224]},"n1819800191":{"id":"n1819800191","loc":[-85.5853311,41.9466603]},"n1819800201":{"id":"n1819800201","loc":[-85.6101142,41.9433406]},"n1819800202":{"id":"n1819800202","loc":[-85.600963,41.9428618]},"n1819800206":{"id":"n1819800206","loc":[-85.6154357,41.9427501]},"n1819800207":{"id":"n1819800207","loc":[-85.6040309,41.9414094]},"n1819800209":{"id":"n1819800209","loc":[-85.6113694,41.943189]},"n1819800211":{"id":"n1819800211","loc":[-85.618032,41.9416408]},"n1819800214":{"id":"n1819800214","loc":[-85.5959419,41.9402602]},"n1819800219":{"id":"n1819800219","loc":[-85.5972117,41.9420043]},"n1819800223":{"id":"n1819800223","loc":[-85.6117171,41.9430019]},"n1819800224":{"id":"n1819800224","loc":[-85.5977873,41.9395579]},"n1819800226":{"id":"n1819800226","loc":[-85.5917362,41.9432209]},"n1819800228":{"id":"n1819800228","loc":[-85.6055759,41.9419122]},"n1819800229":{"id":"n1819800229","loc":[-85.6203395,41.9425595]},"n1819800233":{"id":"n1819800233","loc":[-85.6107579,41.9433007]},"n1819800234":{"id":"n1819800234","loc":[-85.6039773,41.9412498]},"n1819800235":{"id":"n1819800235","loc":[-85.6000977,41.9412861]},"n1819800236":{"id":"n1819800236","loc":[-85.6026689,41.9407231]},"n1819800237":{"id":"n1819800237","loc":[-85.615161,41.9428662]},"n1819800238":{"id":"n1819800238","loc":[-85.5878953,41.9454314]},"n1819800239":{"id":"n1819800239","loc":[-85.6035267,41.941569]},"n1819800240":{"id":"n1819800240","loc":[-85.5929738,41.9450208]},"n1819800241":{"id":"n1819800241","loc":[-85.6186329,41.9416488]},"n1819800242":{"id":"n1819800242","loc":[-85.5881136,41.9483963]},"n1819800243":{"id":"n1819800243","loc":[-85.5909208,41.9466922]},"n1819800244":{"id":"n1819800244","loc":[-85.5997721,41.9394941]},"n1819800245":{"id":"n1819800245","loc":[-85.6202064,41.9425712]},"n1819800246":{"id":"n1819800246","loc":[-85.591071,41.9448808]},"n1819800247":{"id":"n1819800247","loc":[-85.5866078,41.9490622]},"n1819800250":{"id":"n1819800250","loc":[-85.602383,41.9420841]},"n1819800251":{"id":"n1819800251","loc":[-85.5957418,41.9426906]},"n1819800255":{"id":"n1819800255","loc":[-85.6157039,41.9416727]},"n1819800256":{"id":"n1819800256","loc":[-85.6080328,41.9410982]},"n1819800258":{"id":"n1819800258","loc":[-85.6192551,41.9414892]},"n1819800260":{"id":"n1819800260","loc":[-85.6104253,41.94117]},"n1819800261":{"id":"n1819800261","loc":[-85.6204503,41.9425709]},"n1819800263":{"id":"n1819800263","loc":[-85.5872194,41.9455431]},"n1819800264":{"id":"n1819800264","loc":[-85.616176,41.9418244]},"n1819800268":{"id":"n1819800268","loc":[-85.6120883,41.9426703]},"n1819800269":{"id":"n1819800269","loc":[-85.5894547,41.9474946]},"n1819800272":{"id":"n1819800272","loc":[-85.6209181,41.9425027]},"n1819800274":{"id":"n1819800274","loc":[-85.6122814,41.9412817]},"n1819800276":{"id":"n1819800276","loc":[-85.5895153,41.9452798]},"n1819800277":{"id":"n1819800277","loc":[-85.5884317,41.9455272]},"n1819800279":{"id":"n1819800279","loc":[-85.5884103,41.9480966]},"n1819800287":{"id":"n1819800287","loc":[-85.5904917,41.9453915]},"n1819800288":{"id":"n1819800288","loc":[-85.6212292,41.9412977]},"n1819800289":{"id":"n1819800289","loc":[-85.5954377,41.9406832]},"n1819800290":{"id":"n1819800290","loc":[-85.593721,41.9420957]},"n1819800291":{"id":"n1819800291","loc":[-85.6162832,41.9427102]},"n1819800292":{"id":"n1819800292","loc":[-85.605018,41.9401804]},"n1819800293":{"id":"n1819800293","loc":[-85.6086443,41.941146]},"n1819800296":{"id":"n1819800296","loc":[-85.6204675,41.9413775]},"n1819800297":{"id":"n1819800297","loc":[-85.612496,41.9424947]},"n1819800299":{"id":"n1819800299","loc":[-85.6065629,41.9423431]},"n1819800301":{"id":"n1819800301","loc":[-85.6036125,41.9398452]},"n1819800303":{"id":"n1819800303","loc":[-85.6114767,41.94117]},"n1819800306":{"id":"n1819800306","loc":[-85.592616,41.9428139]},"n1819800308":{"id":"n1819800308","loc":[-85.6023041,41.9419521]},"n1819800310":{"id":"n1819800310","loc":[-85.6218944,41.9411061]},"n1819800311":{"id":"n1819800311","loc":[-85.6097816,41.941162]},"n1819800312":{"id":"n1819800312","loc":[-85.5922549,41.9457869]},"n1819800313":{"id":"n1819800313","loc":[-85.5986027,41.9417206]},"n1819800314":{"id":"n1819800314","loc":[-85.5918687,41.946138]},"n1819800315":{"id":"n1819800315","loc":[-85.5872875,41.948883]},"n1819800316":{"id":"n1819800316","loc":[-85.594272,41.9436642]},"n1819800317":{"id":"n1819800317","loc":[-85.6176351,41.941577]},"n1819800318":{"id":"n1819800318","loc":[-85.6137834,41.9430853]},"n1819800319":{"id":"n1819800319","loc":[-85.6195383,41.942622],"tags":{"leisure":"slipway"}},"n1819800320":{"id":"n1819800320","loc":[-85.5971006,41.9398053]},"n1819800321":{"id":"n1819800321","loc":[-85.601714,41.9406752]},"n1819800322":{"id":"n1819800322","loc":[-85.5908028,41.9453117]},"n1819800323":{"id":"n1819800323","loc":[-85.6062732,41.9404597]},"n1819800324":{"id":"n1819800324","loc":[-85.62124,41.9425905]},"n1819800327":{"id":"n1819800327","loc":[-85.6008664,41.942766]},"n1819800328":{"id":"n1819800328","loc":[-85.6179355,41.9428538]},"n1819800330":{"id":"n1819800330","loc":[-85.6045566,41.9415131]},"n1819800331":{"id":"n1819800331","loc":[-85.5944935,41.9414653]},"n1819800333":{"id":"n1819800333","loc":[-85.6088911,41.943181]},"n1819800334":{"id":"n1819800334","loc":[-85.5946367,41.943369]},"n1819800336":{"id":"n1819800336","loc":[-85.6150494,41.9429656]},"n1819800343":{"id":"n1819800343","loc":[-85.6096099,41.9433326]},"n1819800345":{"id":"n1819800345","loc":[-85.5915216,41.9435401]},"n1819800347":{"id":"n1819800347","loc":[-85.607786,41.9428698]},"n1819800349":{"id":"n1819800349","loc":[-85.6187616,41.9426623]},"n1819800350":{"id":"n1819800350","loc":[-85.6012527,41.9426064]},"n1819800352":{"id":"n1819800352","loc":[-85.6214867,41.9428379]},"n1819800354":{"id":"n1819800354","loc":[-85.61338,41.94293]},"n1819800355":{"id":"n1819800355","loc":[-85.5923156,41.9428139]},"n1819800357":{"id":"n1819800357","loc":[-85.5901591,41.9453197]},"n1819800359":{"id":"n1819800359","loc":[-85.6033979,41.9408827]},"n1819800360":{"id":"n1819800360","loc":[-85.6186543,41.9414653]},"n1819800363":{"id":"n1819800363","loc":[-85.6128607,41.9425665]},"n1819800365":{"id":"n1819800365","loc":[-85.614234,41.9412977]},"n1819800367":{"id":"n1819800367","loc":[-85.6089662,41.9410902]},"n1819800369":{"id":"n1819800369","loc":[-85.6197379,41.9413695]},"n1819800370":{"id":"n1819800370","loc":[-85.6037348,41.941733]},"n1819800371":{"id":"n1819800371","loc":[-85.5993467,41.9415654]},"n1819800372":{"id":"n1819800372","loc":[-85.598077,41.94196]},"n1819800373":{"id":"n1819800373","loc":[-85.5984203,41.9394781]},"n1819800374":{"id":"n1819800374","loc":[-85.6013315,41.9427066]},"n1819800376":{"id":"n1819800376","loc":[-85.5934673,41.944167]},"n1819800378":{"id":"n1819800378","loc":[-85.6011062,41.9407753]},"n1819800379":{"id":"n1819800379","loc":[-85.6150602,41.9415131]},"n1819800380":{"id":"n1819800380","loc":[-85.6132148,41.9412338]},"n1819800381":{"id":"n1819800381","loc":[-85.5889038,41.9453835]},"n2139966621":{"id":"n2139966621","loc":[-85.6198719,41.9426184]},"n2139966622":{"id":"n2139966622","loc":[-85.6197551,41.9426123]},"n2139966623":{"id":"n2139966623","loc":[-85.6196467,41.9426279]},"n2139966624":{"id":"n2139966624","loc":[-85.6191519,41.9426221]},"n2139966625":{"id":"n2139966625","loc":[-85.6194153,41.9426256]},"n2139966626":{"id":"n2139966626","loc":[-85.6200497,41.9425812]},"n2139966629":{"id":"n2139966629","loc":[-85.6192123,41.9426229]},"n2203933101":{"id":"n2203933101","loc":[-85.6030009,41.9360592]},"w17967539":{"id":"w17967539","tags":{"highway":"residential","name":"1st Ave"},"nodes":["n185965099","n185963395","n185987021"]},"w17967751":{"id":"w17967751","tags":{"highway":"residential","name":"River St"},"nodes":["n185980088","n185988961","n185988963","n185963698"]},"w17965088":{"id":"w17965088","tags":{"highway":"residential","name":"9th St"},"nodes":["n185945133","n185964320","n185964322","n185964324","n185964326","n185964328","n185964329","n185964330","n185964331"]},"w17964467":{"id":"w17964467","tags":{"highway":"residential","name":"Mechanic St"},"nodes":["n185958030","n185958032","n185958034","n185958036"]},"w134150842":{"id":"w134150842","tags":{"bridge":"yes","highway":"residential","name":"6th St"},"nodes":["n185980090","n185980093"]},"w17966740":{"id":"w17966740","tags":{"highway":"residential","name":"6th St"},"nodes":["n185977754","n185980075","n185980077","n185980078","n185980079","n185980081","n185980083","n185980085","n185958034","n185980088","n185980090"]},"w170844765":{"id":"w170844765","tags":{"waterway":"dam"},"nodes":["n1819800304","n1819800232","n1819800325","n1819800188"]},"w17967745":{"id":"w17967745","tags":{"highway":"residential","name":"River St"},"nodes":["n185981173","n185967077","n185963099","n185958498","n185988943","n185964331","n185975332"]},"w17968113":{"id":"w17968113","tags":{"highway":"residential","name":"Green St"},"nodes":["n185988943","n185991378"]},"w134150833":{"id":"w134150833","tags":{"highway":"residential","name":"6th St"},"nodes":["n185980093","n1475283999","n185963392"]},"w17967935":{"id":"w17967935","tags":{"name":"Michigan Central Railroad","railway":"abandoned"},"nodes":["n185972757","n185990192","n185990194","n185990195","n185990196","n185990198","n185990200","n185990202","n185990204","n185990206","n185990209","n185952239","n185990211","n185990212","n185990213","n185990214","n2203933101","n185973251"]},"w17965993":{"id":"w17965993","tags":{"name":"Conrail Railroad","railway":"abandoned"},"nodes":["n185957831","n185972752","n185972754","n185972756","n185972757"]},"w17966211":{"id":"w17966211","tags":{"highway":"residential","name":"8th St"},"nodes":["n185975315","n185975316","n185954490","n185945395","n185975317","n185974509","n185945135","n185975318","n185961186","n185967634","n185975320","n185970833","n185958036","n185975325","n185975326","n185975327","n185975328","n185975330","n185975332"]},"w170844766":{"id":"w170844766","tags":{"waterway":"riverbank"},"nodes":["n1819800229","n1819800245","n2139966626","n2139966621","n2139966622","n2139966623","n1819800319","n2139966625","n2139966629","n2139966624","n1819800349","n1819800328","n1819800291","n1819800206","n1819800237","n1819800336","n1819800318","n1819800354","n1819800182","n1819800363","n1819800297","n1819800268","n1819800223","n1819800209","n1819800233","n1819800201","n1819800343","n1819800333","n1819800347","n1819800299","n1819800228","n1819800330","n1819800370","n1819800250","n1819800374","n1819800202","n1819800327","n1819800350","n1819800308","n1819800239","n1819800207","n1819800234","n1819800359","n1819800236","n1819800321","n1819800378","n1819800235","n1819800371","n1819800313","n1819800372","n1819800219","n1819800251","n1819800334","n1819800316","n1819800376","n1819800240","n1819800312","n1819800314","n1819800243","n1819800269","n1819800279","n1819800242","n1819800315","n1819800247","n1819800191","n1819800189","n1819800263","n1819800238","n1819800277","n1819800180","n1819800381","n1819800276","n1819800357","n1819800287","n1819800322","n1819800246","n1819800345","n1819800226","n1819800355","n1819800306","n1819800290","n1819800331","n1819800289","n1819800214","n1819800320","n1819800224","n1819800373","n1819800244","n1819800184","n1819800301","n1819800292","n1819800323","n1819800181","n1819800256","n1819800293","n1819800367","n1819800311","n1819800260","n1819800185","n1819800303","n1819800274","n1819800380","n1819800365","n1819800379","n1819800255","n1819800264","n1819800186","n1819800183","n1819800317","n1819800211","n1819800241","n1819800360","n1819800258","n1819800369","n1819800296","n1819800288","n1819800310","n1819800204","n1819800375","n1819800216","n1819800377","n1819800248","n1819800227","n1819800368","n1819800231","n1819800188","n1819800325","n1819800232","n1819800304","n1819800271","n1819800213","n1819800266","n1819800221","n1819800294","n1819800362","n1819800199","n1819800230","n1819800218","n1819800352","n1819800324","n1819800272","n1819800261","n1819800229"]},"n1875654132":{"id":"n1875654132","loc":[-85.6297439,41.939808]},"n1475293263":{"id":"n1475293263","loc":[-85.6296235,41.939922]},"n185947850":{"id":"n185947850","loc":[-85.631594,41.942613]},"n185952745":{"id":"n185952745","loc":[-85.630986,41.941786]},"n185972907":{"id":"n185972907","loc":[-85.631797,41.9420055]},"n185972911":{"id":"n185972911","loc":[-85.6309723,41.9411623]},"n185972915":{"id":"n185972915","loc":[-85.6295971,41.939267]},"n1475293223":{"id":"n1475293223","loc":[-85.6313962,41.9416114],"tags":{"railway":"level_crossing"}},"n1475293231":{"id":"n1475293231","loc":[-85.6318779,41.9415447]},"n1475293241":{"id":"n1475293241","loc":[-85.6304613,41.9405499]},"n1475293246":{"id":"n1475293246","loc":[-85.6297512,41.9395393],"tags":{"railway":"level_crossing"}},"n1475293251":{"id":"n1475293251","loc":[-85.6316633,41.9415128]},"n2139982404":{"id":"n2139982404","loc":[-85.6313283,41.9413748]},"n2139982407":{"id":"n2139982407","loc":[-85.6325545,41.9417787]},"n2139982408":{"id":"n2139982408","loc":[-85.6324499,41.9417693]},"n2139982409":{"id":"n2139982409","loc":[-85.6324753,41.9416444]},"n2139982410":{"id":"n2139982410","loc":[-85.6325814,41.9416538]},"n2139982411":{"id":"n2139982411","loc":[-85.6319572,41.9413515]},"n2139982412":{"id":"n2139982412","loc":[-85.6322925,41.941139]},"n2139982413":{"id":"n2139982413","loc":[-85.6323153,41.941153]},"n2139982414":{"id":"n2139982414","loc":[-85.6323019,41.9412617]},"n2139982415":{"id":"n2139982415","loc":[-85.6323703,41.9412667]},"n2139982416":{"id":"n2139982416","loc":[-85.6323555,41.941538]},"n2139982417":{"id":"n2139982417","loc":[-85.6321343,41.9416777]},"n2139982418":{"id":"n2139982418","loc":[-85.6319425,41.9416866]},"n2139982419":{"id":"n2139982419","loc":[-85.6320303,41.9416941]},"n2139982420":{"id":"n2139982420","loc":[-85.6321665,41.9415554]},"n2139982421":{"id":"n2139982421","loc":[-85.632412,41.9414164]},"n2139982422":{"id":"n2139982422","loc":[-85.6324801,41.9413421]},"n2139982423":{"id":"n2139982423","loc":[-85.6325023,41.9412585]},"n2139982424":{"id":"n2139982424","loc":[-85.6324532,41.9411607]},"n2139982425":{"id":"n2139982425","loc":[-85.6323502,41.941103]},"n2139982426":{"id":"n2139982426","loc":[-85.6322362,41.9411183]},"n2139982427":{"id":"n2139982427","loc":[-85.6318941,41.9413551]},"n2139982428":{"id":"n2139982428","loc":[-85.6318592,41.9414105]},"n2139982429":{"id":"n2139982429","loc":[-85.6320111,41.9415866]},"n2139982430":{"id":"n2139982430","loc":[-85.632446,41.9413792]},"n2139982431":{"id":"n2139982431","loc":[-85.6325112,41.941416]},"n2139982432":{"id":"n2139982432","loc":[-85.6325449,41.9416345]},"n2139982433":{"id":"n2139982433","loc":[-85.6326122,41.94164]},"n2139982434":{"id":"n2139982434","loc":[-85.6325954,41.9421966]},"n2139982435":{"id":"n2139982435","loc":[-85.6325655,41.9422411]},"n2139982436":{"id":"n2139982436","loc":[-85.632515,41.9422564]},"n2139982437":{"id":"n2139982437","loc":[-85.6324495,41.94223]},"n2139982438":{"id":"n2139982438","loc":[-85.6324009,41.9421743]},"n2139982439":{"id":"n2139982439","loc":[-85.6323915,41.9421145]},"n2139982440":{"id":"n2139982440","loc":[-85.6320287,41.9418585]},"n2139982441":{"id":"n2139982441","loc":[-85.6318285,41.9416387]},"n1475293258":{"id":"n1475293258","loc":[-85.6318289,41.9415077]},"n2168544754":{"id":"n2168544754","loc":[-85.6312814,41.9431198]},"n2168544755":{"id":"n2168544755","loc":[-85.6314212,41.9430646]},"n2168544756":{"id":"n2168544756","loc":[-85.6313387,41.942949]},"n2168544757":{"id":"n2168544757","loc":[-85.6311989,41.9430041]},"n2168544758":{"id":"n2168544758","loc":[-85.6311024,41.9429313]},"n2168544759":{"id":"n2168544759","loc":[-85.6310087,41.9428087]},"n2168544760":{"id":"n2168544760","loc":[-85.6313831,41.9426504]},"n2168544761":{"id":"n2168544761","loc":[-85.6314768,41.9427729]},"n2168544762":{"id":"n2168544762","loc":[-85.6306376,41.942809]},"n2168544763":{"id":"n2168544763","loc":[-85.6307378,41.9429427]},"n2168544764":{"id":"n2168544764","loc":[-85.630841,41.9428998]},"n2168544765":{"id":"n2168544765","loc":[-85.6307408,41.9427662]},"n2168544766":{"id":"n2168544766","loc":[-85.6305404,41.9426029]},"n2168544767":{"id":"n2168544767","loc":[-85.6304976,41.9426194]},"n2168544768":{"id":"n2168544768","loc":[-85.6305673,41.9427184]},"n2168544769":{"id":"n2168544769","loc":[-85.6306164,41.9426984]},"n2168544770":{"id":"n2168544770","loc":[-85.6306418,41.9427302]},"n2168544771":{"id":"n2168544771","loc":[-85.6306861,41.9427137]},"n2168544772":{"id":"n2168544772","loc":[-85.6307146,41.9427537]},"n2168544773":{"id":"n2168544773","loc":[-85.6308999,41.9426807]},"n2168544774":{"id":"n2168544774","loc":[-85.6308429,41.9426053]},"n2168544775":{"id":"n2168544775","loc":[-85.6308999,41.9425806]},"n2168544776":{"id":"n2168544776","loc":[-85.6308318,41.9424875]},"n2168544777":{"id":"n2168544777","loc":[-85.6307732,41.9425087]},"n2168544778":{"id":"n2168544778","loc":[-85.6307178,41.9424357]},"n2168544779":{"id":"n2168544779","loc":[-85.630485,41.942524]},"n2189099387":{"id":"n2189099387","loc":[-85.631203,41.9393371]},"n2189099404":{"id":"n2189099404","loc":[-85.6301963,41.9391363]},"n2189099405":{"id":"n2189099405","loc":[-85.6304447,41.9391352]},"n2189099406":{"id":"n2189099406","loc":[-85.6304463,41.9393391]},"n2189099407":{"id":"n2189099407","loc":[-85.6308435,41.9393373]},"n2189099408":{"id":"n2189099408","loc":[-85.6308418,41.9391251]},"n2189099409":{"id":"n2189099409","loc":[-85.6310929,41.939124]},"n2189099410":{"id":"n2189099410","loc":[-85.6310946,41.9393376]},"n2189112720":{"id":"n2189112720","loc":[-85.6314677,41.9412327]},"n2189112721":{"id":"n2189112721","loc":[-85.6313337,41.9411397]},"n2189112722":{"id":"n2189112722","loc":[-85.6320521,41.9405678]},"n2189112723":{"id":"n2189112723","loc":[-85.6321899,41.9406633]},"n2189112724":{"id":"n2189112724","loc":[-85.6313229,41.9408344]},"n2189112725":{"id":"n2189112725","loc":[-85.6311223,41.9410018]},"n2189112726":{"id":"n2189112726","loc":[-85.6313205,41.9411333]},"n2189112727":{"id":"n2189112727","loc":[-85.6315211,41.9409659]},"n2189112728":{"id":"n2189112728","loc":[-85.6311035,41.9402529]},"n2189112729":{"id":"n2189112729","loc":[-85.631226,41.9402107]},"n2189112730":{"id":"n2189112730","loc":[-85.6315966,41.9408051]},"n2189112731":{"id":"n2189112731","loc":[-85.6314741,41.9408473]},"n2189112732":{"id":"n2189112732","loc":[-85.6318114,41.940534]},"n2189112733":{"id":"n2189112733","loc":[-85.631588,41.94061]},"n2189112734":{"id":"n2189112734","loc":[-85.6314379,41.940366]},"n2189112735":{"id":"n2189112735","loc":[-85.6316613,41.94029]},"n2189112736":{"id":"n2189112736","loc":[-85.6306214,41.9400415]},"n2189112737":{"id":"n2189112737","loc":[-85.6304362,41.9397728]},"n2189112738":{"id":"n2189112738","loc":[-85.6305899,41.9397142]},"n2189112739":{"id":"n2189112739","loc":[-85.6307751,41.9399828]},"n2189112740":{"id":"n2189112740","loc":[-85.6304695,41.9401673]},"n2189112741":{"id":"n2189112741","loc":[-85.6301298,41.9396855]},"n2189112742":{"id":"n2189112742","loc":[-85.6303016,41.9396184]},"n2189112743":{"id":"n2189112743","loc":[-85.6306413,41.9401003]},"n2189112744":{"id":"n2189112744","loc":[-85.6309656,41.9406189]},"n2189112745":{"id":"n2189112745","loc":[-85.6308738,41.940493]},"n2189112746":{"id":"n2189112746","loc":[-85.6309333,41.940469]},"n2189112747":{"id":"n2189112747","loc":[-85.6307634,41.9402358]},"n2189112748":{"id":"n2189112748","loc":[-85.6308798,41.9401889]},"n2189112749":{"id":"n2189112749","loc":[-85.6311416,41.940548]},"n2189112750":{"id":"n2189112750","loc":[-85.6309577,41.9408708]},"n2189112751":{"id":"n2189112751","loc":[-85.630874,41.9407777]},"n2189112752":{"id":"n2189112752","loc":[-85.6310622,41.9406841]},"n2189112753":{"id":"n2189112753","loc":[-85.6311459,41.9407772]},"n2189112754":{"id":"n2189112754","loc":[-85.6320308,41.9405747]},"n2189112755":{"id":"n2189112755","loc":[-85.6317769,41.9401857]},"n2189112756":{"id":"n2189112756","loc":[-85.6313462,41.9401785]},"n2189112757":{"id":"n2189112757","loc":[-85.6313423,41.9401199]},"n2189112758":{"id":"n2189112758","loc":[-85.6318308,41.9401184]},"n2189112759":{"id":"n2189112759","loc":[-85.6321154,41.9405433]},"n2189112760":{"id":"n2189112760","loc":[-85.6310307,41.941683]},"n2189112761":{"id":"n2189112761","loc":[-85.6309808,41.9416078]},"n2189112762":{"id":"n2189112762","loc":[-85.6312094,41.9415156]},"n2189112763":{"id":"n2189112763","loc":[-85.6312636,41.9415865]},"n2189112764":{"id":"n2189112764","loc":[-85.6309384,41.94155]},"n2189112765":{"id":"n2189112765","loc":[-85.631156,41.9414619]},"n2189112766":{"id":"n2189112766","loc":[-85.6311968,41.94152]},"n2189112767":{"id":"n2189112767","loc":[-85.6308946,41.9414851]},"n2189112768":{"id":"n2189112768","loc":[-85.6308237,41.9413888]},"n2189112769":{"id":"n2189112769","loc":[-85.6309858,41.9413228]},"n2189112770":{"id":"n2189112770","loc":[-85.6310567,41.9414192]},"n2189112771":{"id":"n2189112771","loc":[-85.6307774,41.9413276]},"n2189112772":{"id":"n2189112772","loc":[-85.6309068,41.9412735]},"n2189112773":{"id":"n2189112773","loc":[-85.6309531,41.9413347]},"n2189112774":{"id":"n2189112774","loc":[-85.6307975,41.9412466]},"n2189112775":{"id":"n2189112775","loc":[-85.6307006,41.9411699]},"n2189112776":{"id":"n2189112776","loc":[-85.6308289,41.941113]},"n2189112777":{"id":"n2189112777","loc":[-85.6308997,41.9412012]},"n2189112778":{"id":"n2189112778","loc":[-85.630765,41.9412062]},"n2189112779":{"id":"n2189112779","loc":[-85.630739,41.9412177]},"n2189112780":{"id":"n2189112780","loc":[-85.6305822,41.9410391]},"n2189112781":{"id":"n2189112781","loc":[-85.6304117,41.9408177]},"n2189112782":{"id":"n2189112782","loc":[-85.6305086,41.9407769]},"n2189112783":{"id":"n2189112783","loc":[-85.6306779,41.9410044]},"n2189112784":{"id":"n2189112784","loc":[-85.6307734,41.9421663]},"n2189112785":{"id":"n2189112785","loc":[-85.630708,41.9420741]},"n2189112786":{"id":"n2189112786","loc":[-85.630863,41.9420133]},"n2189112787":{"id":"n2189112787","loc":[-85.6309285,41.9421055]},"n2189112788":{"id":"n2189112788","loc":[-85.6307014,41.9420263]},"n2189112789":{"id":"n2189112789","loc":[-85.6306648,41.941971]},"n2189112790":{"id":"n2189112790","loc":[-85.6307927,41.9419178]},"n2189112791":{"id":"n2189112791","loc":[-85.6308366,41.9419696]},"n2189112792":{"id":"n2189112792","loc":[-85.6307574,41.9418708]},"n2189112793":{"id":"n2189112793","loc":[-85.6306288,41.9419231]},"n2189112794":{"id":"n2189112794","loc":[-85.6306943,41.9417835]},"n2189112795":{"id":"n2189112795","loc":[-85.6305344,41.9418474]},"n2189112796":{"id":"n2189112796","loc":[-85.6305981,41.9419355]},"n2189123410":{"id":"n2189123410","loc":[-85.6315476,41.9393801]},"n2189123412":{"id":"n2189123412","loc":[-85.6315247,41.9399188]},"n2189123415":{"id":"n2189123415","loc":[-85.6316484,41.9400433]},"n185945138":{"id":"n185945138","loc":[-85.627073,41.93319]},"n185945142":{"id":"n185945142","loc":[-85.6296891,41.9331674]},"n185945401":{"id":"n185945401","loc":[-85.6269,41.930199]},"n185945405":{"id":"n185945405","loc":[-85.6296598,41.9301676]},"n185956891":{"id":"n185956891","loc":[-85.6251617,41.9255049]},"n185959979":{"id":"n185959979","loc":[-85.626333,41.928347]},"n185959983":{"id":"n185959983","loc":[-85.6296419,41.9283288]},"n185961192":{"id":"n185961192","loc":[-85.627053,41.9352031]},"n185961200":{"id":"n185961200","loc":[-85.6297088,41.9351902]},"n185963655":{"id":"n185963655","loc":[-85.6296112,41.9273948]},"n185963665":{"id":"n185963665","loc":[-85.626047,41.92737]},"n185963688":{"id":"n185963688","loc":[-85.6296503,41.9292199]},"n185963689":{"id":"n185963689","loc":[-85.6296694,41.931157]},"n185963690":{"id":"n185963690","loc":[-85.6296791,41.9321485]},"n185963691":{"id":"n185963691","loc":[-85.6296991,41.9341973]},"n185967638":{"id":"n185967638","loc":[-85.627089,41.9361884]},"n185972917":{"id":"n185972917","loc":[-85.6293759,41.9388605]},"n185972919":{"id":"n185972919","loc":[-85.6290337,41.9380234]},"n185972921":{"id":"n185972921","loc":[-85.628424,41.936212]},"n185972923":{"id":"n185972923","loc":[-85.628367,41.936029]},"n185974511":{"id":"n185974511","loc":[-85.627064,41.932169]},"n185977728":{"id":"n185977728","loc":[-85.625605,41.925842]},"n185977729":{"id":"n185977729","loc":[-85.625685,41.926163]},"n185977731":{"id":"n185977731","loc":[-85.6257845,41.9264872]},"n185977733":{"id":"n185977733","loc":[-85.62663,41.929251]},"n185977734":{"id":"n185977734","loc":[-85.627008,41.930642]},"n185977736":{"id":"n185977736","loc":[-85.627029,41.930775]},"n185977738":{"id":"n185977738","loc":[-85.627041,41.930946]},"n185977739":{"id":"n185977739","loc":[-85.6270379,41.9311746]},"n185977742":{"id":"n185977742","loc":[-85.627055,41.934206]},"n185977744":{"id":"n185977744","loc":[-85.627084,41.936804]},"n185977746":{"id":"n185977746","loc":[-85.627104,41.936914]},"n185977748":{"id":"n185977748","loc":[-85.627156,41.937026]},"n185977750":{"id":"n185977750","loc":[-85.6272406,41.9371672]},"n185977752":{"id":"n185977752","loc":[-85.627317,41.93723]},"n185977753":{"id":"n185977753","loc":[-85.627422,41.937312]},"n185977755":{"id":"n185977755","loc":[-85.627754,41.937504]},"n185977757":{"id":"n185977757","loc":[-85.627883,41.937623]},"n185977761":{"id":"n185977761","loc":[-85.627984,41.93773]},"n1475283996":{"id":"n1475283996","loc":[-85.6270514,41.9317122],"tags":{"railway":"level_crossing"}},"n1475284004":{"id":"n1475284004","loc":[-85.6278177,41.9342117],"tags":{"railway":"level_crossing"}},"n1475284014":{"id":"n1475284014","loc":[-85.6251877,41.9255913],"tags":{"railway":"level_crossing"}},"n1475284017":{"id":"n1475284017","loc":[-85.6274992,41.9331816],"tags":{"railway":"level_crossing"}},"n1475284021":{"id":"n1475284021","loc":[-85.6297108,41.9353939],"tags":{"railway":"level_crossing"}},"n1475284027":{"id":"n1475284027","loc":[-85.62811,41.935198],"tags":{"railway":"level_crossing"}},"n1475284035":{"id":"n1475284035","loc":[-85.626888,41.9311757],"tags":{"railway":"level_crossing"}},"n1475293245":{"id":"n1475293245","loc":[-85.6286047,41.9367881]},"n1875654302":{"id":"n1875654302","loc":[-85.6296367,41.927491]},"n2189099388":{"id":"n2189099388","loc":[-85.6312007,41.9389988]},"n2189099389":{"id":"n2189099389","loc":[-85.6311003,41.9389992]},"n2189099390":{"id":"n2189099390","loc":[-85.6310988,41.9387847]},"n2189099391":{"id":"n2189099391","loc":[-85.6312165,41.9387843]},"n2189099392":{"id":"n2189099392","loc":[-85.6312152,41.9385857]},"n2189099393":{"id":"n2189099393","loc":[-85.6310877,41.9385862]},"n2189099394":{"id":"n2189099394","loc":[-85.6310858,41.9383161]},"n2189099395":{"id":"n2189099395","loc":[-85.6302002,41.9383196]},"n2189099396":{"id":"n2189099396","loc":[-85.6302011,41.9384472]},"n2189099397":{"id":"n2189099397","loc":[-85.6301018,41.9384476]},"n2189099398":{"id":"n2189099398","loc":[-85.6301025,41.9385419]},"n2189099399":{"id":"n2189099399","loc":[-85.6299275,41.9385427]},"n2189099400":{"id":"n2189099400","loc":[-85.62993,41.9388653]},"n2189099401":{"id":"n2189099401","loc":[-85.630107,41.9388645]},"n2189099402":{"id":"n2189099402","loc":[-85.6301079,41.9389908]},"n2189099403":{"id":"n2189099403","loc":[-85.6301951,41.9389904]},"n2189123382":{"id":"n2189123382","loc":[-85.6336279,41.9354365]},"n2189123384":{"id":"n2189123384","loc":[-85.6328492,41.9355177]},"n2189123387":{"id":"n2189123387","loc":[-85.6323762,41.9357396]},"n2189123388":{"id":"n2189123388","loc":[-85.6315174,41.9358966]},"n2189123389":{"id":"n2189123389","loc":[-85.6304331,41.936124]},"n2189123390":{"id":"n2189123390","loc":[-85.6302075,41.9364271]},"n2189123391":{"id":"n2189123391","loc":[-85.6303458,41.9367953]},"n2189123392":{"id":"n2189123392","loc":[-85.6299601,41.9369739]},"n2189123393":{"id":"n2189123393","loc":[-85.6299164,41.9374882]},"n2189123394":{"id":"n2189123394","loc":[-85.6299455,41.9378022]},"n2189123395":{"id":"n2189123395","loc":[-85.6299771,41.9379053]},"n2189123396":{"id":"n2189123396","loc":[-85.6301597,41.9379091]},"n2189123397":{"id":"n2189123397","loc":[-85.6308042,41.9377913]},"n2189123398":{"id":"n2189123398","loc":[-85.6316885,41.9378082]},"n2189123399":{"id":"n2189123399","loc":[-85.6316848,41.9380079]},"n2189123400":{"id":"n2189123400","loc":[-85.6318449,41.9381161]},"n2189123401":{"id":"n2189123401","loc":[-85.6320705,41.9381811]},"n2189123402":{"id":"n2189123402","loc":[-85.6321433,41.9383706]},"n2189123404":{"id":"n2189123404","loc":[-85.632056,41.9384355]},"n2189123406":{"id":"n2189123406","loc":[-85.6317867,41.9384572]},"n2189123409":{"id":"n2189123409","loc":[-85.6316572,41.9387281]},"n2189123417":{"id":"n2189123417","loc":[-85.6315946,41.93775]},"n2189123419":{"id":"n2189123419","loc":[-85.6302641,41.9378393]},"w208640158":{"id":"w208640158","tags":{"area":"yes","natural":"wetland"},"nodes":["n2189123379","n2189123382","n2189123384","n2189123387","n2189123388","n2189123389","n2189123390","n2189123391","n2189123392","n2189123393","n2189123394","n2189123395","n2189123396","n2189123419","n2189123397","n2189123417","n2189123398","n2189123399","n2189123400","n2189123401","n2189123402","n2189123404","n2189123406","n2189123409","n2189123410","n2189123412","n2189123415","n1819805722","n1819805861","n1819805887","n1819805760","n1819805641","n1819805632","n2189123379"]},"w134150787":{"id":"w134150787","tags":{"name":"Conrail Railroad","railway":"rail"},"nodes":["n185972905","n185972907","n1475293223","n185972911","n1475293241","n1475293246","n185972915","n185972917","n185972919","n1475293245","n185972921","n185972923","n1475284027","n1475284004","n1475284017","n1475283996","n1475284035","n1475284014","n185956891"]},"w208639443":{"id":"w208639443","tags":{"area":"yes","building":"yes"},"nodes":["n2189112720","n2189112721","n2189112722","n2189112723","n2189112720"]},"w17966462":{"id":"w17966462","tags":{"highway":"secondary","name":"South Main Street","old_ref":"US 131","ref":"M 86"},"nodes":["n185977728","n185977729","n185977731","n185963665","n185959979","n185977733","n185945401","n185977734","n185977736","n185977738","n185977739","n1475283996","n185974511","n185945138","n185977742","n185961192","n185967638","n185977744","n185977746","n185977748","n185977750","n185977752","n185977753","n185977754","n185977755","n185977757","n185977761","n185958030","n1475293263","n185963698","n185952745","n185947850","n185977762"]},"w203985741":{"id":"w203985741","tags":{"area":"yes","leisure":"park","name":"Conservation Park"},"nodes":["n2139982404","n2139982405","n2139982399","n2139982400","n1819805770","n2139982402","n2139982403","n2139982401","n1819805780","n1819805834","n2139982406","n2139982404"]},"w17963676":{"id":"w17963676","tags":{"highway":"service"},"nodes":["n1475293258","n2139982428","n2139982427","n2139982426","n2139982425","n2139982424","n2139982423","n2139982422","n2139982430","n2139982421","n2139982420","n2139982429","n1475293231","n1475293258","n1475293251","n1475293223","n185952745"]},"w203985745":{"id":"w203985745","tags":{"highway":"footway"},"nodes":["n2139982430","n2139982431","n2139982432","n2139982433","n2139982434","n2139982435","n2139982436","n2139982437","n2139982438","n2139982439","n2139982440","n2139982441","n1475293231"]},"w208639451":{"id":"w208639451","tags":{"area":"yes","building":"yes"},"nodes":["n2189112754","n2189112755","n2189112756","n2189112757","n2189112758","n2189112759","n2189112754"]},"w208639452":{"id":"w208639452","tags":{"area":"yes","building":"yes"},"nodes":["n2189112760","n2189112761","n2189112766","n2189112762","n2189112763","n2189112760"]},"w206805244":{"id":"w206805244","tags":{"area":"yes","building":"yes"},"nodes":["n2168544766","n2168544767","n2168544768","n2168544769","n2168544770","n2168544771","n2168544772","n2168544773","n2168544774","n2168544775","n2168544776","n2168544777","n2168544778","n2168544779","n2168544766"]},"w208639444":{"id":"w208639444","tags":{"area":"yes","building":"yes"},"nodes":["n2189112724","n2189112725","n2189112726","n2189112727","n2189112724"]},"w208639450":{"id":"w208639450","tags":{"area":"yes","building":"yes"},"nodes":["n2189112750","n2189112751","n2189112752","n2189112753","n2189112750"]},"w208639448":{"id":"w208639448","tags":{"area":"yes","building":"yes"},"nodes":["n2189112740","n2189112741","n2189112742","n2189112743","n2189112740"]},"w208637859":{"id":"w208637859","tags":{"area":"yes","building":"yes"},"nodes":["n2189099387","n2189099388","n2189099389","n2189099390","n2189099391","n2189099392","n2189099393","n2189099394","n2189099395","n2189099396","n2189099397","n2189099398","n2189099399","n2189099400","n2189099401","n2189099402","n2189099403","n2189099404","n2189099405","n2189099406","n2189099407","n2189099408","n2189099409","n2189099410","n2189099387"]},"w208639453":{"id":"w208639453","tags":{"area":"yes","building":"yes"},"nodes":["n2189112764","n2189112765","n2189112766","n2189112761","n2189112764"]},"w208639456":{"id":"w208639456","tags":{"area":"yes","building":"yes"},"nodes":["n2189112774","n2189112778","n2189112779","n2189112775","n2189112776","n2189112777","n2189112774"]},"w208639445":{"id":"w208639445","tags":{"area":"yes","building":"yes"},"nodes":["n2189112728","n2189112729","n2189112730","n2189112731","n2189112728"]},"w17967776":{"id":"w17967776","tags":{"highway":"residential","name":"5th St"},"nodes":["n185958032","n185988963"]},"w208639461":{"id":"w208639461","tags":{"area":"yes","building":"yes"},"nodes":["n2189112792","n2189112794","n2189112795","n2189112796","n2189112793","n2189112792"]},"w206805241":{"id":"w206805241","tags":{"area":"yes","building":"yes"},"nodes":["n2168544754","n2168544755","n2168544756","n2168544757","n2168544754"]},"w208639449":{"id":"w208639449","tags":{"area":"yes","building":"yes"},"nodes":["n2189112744","n2189112745","n2189112746","n2189112747","n2189112748","n2189112749","n2189112744"]},"w208639455":{"id":"w208639455","tags":{"area":"yes","building":"yes"},"nodes":["n2189112771","n2189112772","n2189112773","n2189112768","n2189112771"]},"w208639457":{"id":"w208639457","tags":{"area":"yes","building":"yes"},"nodes":["n2189112780","n2189112781","n2189112782","n2189112783","n2189112780"]},"w208639446":{"id":"w208639446","tags":{"area":"yes","building":"yes"},"nodes":["n2189112732","n2189112733","n2189112734","n2189112735","n2189112732"]},"w208639454":{"id":"w208639454","tags":{"area":"yes","building":"yes"},"nodes":["n2189112767","n2189112768","n2189112773","n2189112769","n2189112770","n2189112767"]},"w203985743":{"id":"w203985743","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139982411","n2139982412","n2139982413","n2139982414","n2139982415","n2139982416","n2139982417","n2139982419","n2139982418","n2139982411"]},"w17965023":{"id":"w17965023","tags":{"highway":"residential","name":"4th St"},"nodes":["n185963655","n1875654302","n185959983","n185963688","n185945405","n185963689","n185963690","n185945142","n185963691","n185961200","n1475284021","n1475293246","n1875654132","n1475293263"]},"w206805242":{"id":"w206805242","tags":{"area":"yes","building":"yes"},"nodes":["n2168544758","n2168544759","n2168544760","n2168544761","n2168544758"]},"w208639460":{"id":"w208639460","tags":{"area":"yes","building":"yes"},"nodes":["n2189112792","n2189112793","n2189112789","n2189112790","n2189112792"]},"w208639447":{"id":"w208639447","tags":{"area":"yes","building":"yes"},"nodes":["n2189112736","n2189112737","n2189112738","n2189112739","n2189112736"]},"w208639458":{"id":"w208639458","tags":{"area":"yes","building":"yes"},"nodes":["n2189112784","n2189112785","n2189112786","n2189112787","n2189112784"]},"w203985744":{"id":"w203985744","tags":{"highway":"service"},"nodes":["n2139982425","n2139982400"]},"w208639459":{"id":"w208639459","tags":{"area":"yes","building":"yes"},"nodes":["n2189112788","n2189112789","n2189112790","n2189112791","n2189112788"]},"w203985742":{"id":"w203985742","tags":{"amenity":"shelter","area":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139982407","n2139982408","n2139982409","n2139982410","n2139982407"]},"w206805243":{"id":"w206805243","tags":{"area":"yes","building":"yes"},"nodes":["n2168544762","n2168544763","n2168544764","n2168544765","n2168544762"]},"n185959081":{"id":"n185959081","loc":[-85.628469,41.948674]},"n185967427":{"id":"n185967427","loc":[-85.632054,41.951174]},"n185967424":{"id":"n185967424","loc":[-85.6320391,41.9499109]},"n185968101":{"id":"n185968101","loc":[-85.6308395,41.9511969]},"n185960792":{"id":"n185960792","loc":[-85.632074,41.953707]},"n185961389":{"id":"n185961389","loc":[-85.630935,41.959037]},"n185961391":{"id":"n185961391","loc":[-85.632169,41.959025]},"n185965395":{"id":"n185965395","loc":[-85.63216,41.959859]},"n185966953":{"id":"n185966953","loc":[-85.630894,41.957428]},"n185966955":{"id":"n185966955","loc":[-85.632122,41.957427]},"n185967430":{"id":"n185967430","loc":[-85.632077,41.952453]},"n185967432":{"id":"n185967432","loc":[-85.632095,41.954685]},"n185967434":{"id":"n185967434","loc":[-85.632121,41.955914]},"n185967436":{"id":"n185967436","loc":[-85.632128,41.9583]},"n185967438":{"id":"n185967438","loc":[-85.632187,41.960681]},"n185967440":{"id":"n185967440","loc":[-85.632182,41.961493]},"n185968102":{"id":"n185968102","loc":[-85.630855,41.952452]},"n185968104":{"id":"n185968104","loc":[-85.630887,41.953714]},"n185968106":{"id":"n185968106","loc":[-85.630883,41.954692]},"n185968108":{"id":"n185968108","loc":[-85.630904,41.955913]},"n185968110":{"id":"n185968110","loc":[-85.630904,41.958058]},"n185968112":{"id":"n185968112","loc":[-85.630952,41.960667]},"n185968114":{"id":"n185968114","loc":[-85.630972,41.961495]},"n185968116":{"id":"n185968116","loc":[-85.630962,41.961967]},"n185978969":{"id":"n185978969","loc":[-85.633214,41.948618]},"n185985812":{"id":"n185985812","loc":[-85.633274,41.951159]},"n185986155":{"id":"n185986155","loc":[-85.633258,41.949893]},"n2208608826":{"id":"n2208608826","loc":[-85.6339222,41.9486225]},"w17964531":{"id":"w17964531","tags":{"highway":"residential","name":"Willow Dr"},"nodes":["n185959079","n185959081"]},"w17967386":{"id":"w17967386","tags":{"highway":"residential","name":"East Armitage Street"},"nodes":["n185982195","n185968101","n185967427","n185985812","n185974583"]},"w17965502":{"id":"w17965502","tags":{"highway":"residential","name":"Elm Street"},"nodes":["n185968100","n185968101","n185968102","n185968104","n185968106","n185968108","n185966953","n185968110","n185961389","n185968112","n185968114","n185968116"]},"w17967844":{"id":"w17967844","tags":{"highway":"residential","name":"East Bennett Street"},"nodes":["n185982193","n185967424","n185986155","n185978390"]},"w17966581":{"id":"w17966581","tags":{"highway":"residential","name":"E Kelsey St"},"nodes":["n185978967","n185978969","n2208608826","n185971578"]},"w17965402":{"id":"w17965402","tags":{"highway":"residential","name":"Walnut Street"},"nodes":["n185967422","n185967424","n185967427","n185967430","n185960792","n185967432","n185967434","n185966955","n185967436","n185961391","n185965395","n185967438","n185967440"]},"n2199093506":{"id":"n2199093506","loc":[-85.6251879,41.9478322]},"n2199093505":{"id":"n2199093505","loc":[-85.6252076,41.9477749]},"n2199093504":{"id":"n2199093504","loc":[-85.6252289,41.9477602]},"n2199093503":{"id":"n2199093503","loc":[-85.625201,41.9477492]},"n2199093502":{"id":"n2199093502","loc":[-85.6251682,41.9477066]},"n2199093501":{"id":"n2199093501","loc":[-85.6251715,41.947609]},"n2199093500":{"id":"n2199093500","loc":[-85.6252125,41.9475639]},"n2199093499":{"id":"n2199093499","loc":[-85.6252896,41.9475602]},"n2199093498":{"id":"n2199093498","loc":[-85.6253027,41.9475334]},"n2199093497":{"id":"n2199093497","loc":[-85.6253437,41.9474822]},"n2199093496":{"id":"n2199093496","loc":[-85.6254421,41.9474675]},"n2199093495":{"id":"n2199093495","loc":[-85.6256503,41.9474944]},"n2199093494":{"id":"n2199093494","loc":[-85.6257257,41.9476127]},"n2199093493":{"id":"n2199093493","loc":[-85.6257028,41.9477285]},"n2199093492":{"id":"n2199093492","loc":[-85.6255339,41.9478102]},"n2199093491":{"id":"n2199093491","loc":[-85.6253912,41.9478224]},"n2199093490":{"id":"n2199093490","loc":[-85.6253043,41.947859]},"n2199093489":{"id":"n2199093489","loc":[-85.6252027,41.9478846]},"n2199093458":{"id":"n2199093458","loc":[-85.6246876,41.9486617]},"n2199093457":{"id":"n2199093457","loc":[-85.6243127,41.9486583]},"n2199093456":{"id":"n2199093456","loc":[-85.624306,41.9490569]},"n2199093455":{"id":"n2199093455","loc":[-85.624681,41.9490603]},"n2199093514":{"id":"n2199093514","loc":[-85.6236228,41.9496059]},"n2199093513":{"id":"n2199093513","loc":[-85.6236231,41.9496997]},"n2199093512":{"id":"n2199093512","loc":[-85.623357,41.9497002]},"n2199093511":{"id":"n2199093511","loc":[-85.6233567,41.9496136]},"n2199093508":{"id":"n2199093508","loc":[-85.6239735,41.9494287]},"n2199093507":{"id":"n2199093507","loc":[-85.6239741,41.9496052]},"n2199093488":{"id":"n2199093488","loc":[-85.624497,41.9512286]},"n2199093487":{"id":"n2199093487","loc":[-85.6244966,41.9511259]},"n2199093486":{"id":"n2199093486","loc":[-85.6243151,41.9511263]},"n2199093485":{"id":"n2199093485","loc":[-85.6243154,41.951229]},"n2199093484":{"id":"n2199093484","loc":[-85.6241205,41.9508665]},"n2199093483":{"id":"n2199093483","loc":[-85.624115,41.9505249]},"n2199093482":{"id":"n2199093482","loc":[-85.6243149,41.9505231]},"n2199093481":{"id":"n2199093481","loc":[-85.6243203,41.9508648]},"n2199093480":{"id":"n2199093480","loc":[-85.624393,41.9508668]},"n2199093479":{"id":"n2199093479","loc":[-85.6243904,41.9505956]},"n2199093478":{"id":"n2199093478","loc":[-85.6246727,41.950594]},"n2199093477":{"id":"n2199093477","loc":[-85.624675,41.9508203]},"n2199093476":{"id":"n2199093476","loc":[-85.6245097,41.9508212]},"n2199093475":{"id":"n2199093475","loc":[-85.6245101,41.9508662]},"n2199093474":{"id":"n2199093474","loc":[-85.6241008,41.9493459]},"n2199093473":{"id":"n2199093473","loc":[-85.6242442,41.9493459]},"n2199093472":{"id":"n2199093472","loc":[-85.6242442,41.9493681]},"n2199093471":{"id":"n2199093471","loc":[-85.6243397,41.9493681]},"n2199093470":{"id":"n2199093470","loc":[-85.6243417,41.9493511]},"n2199093469":{"id":"n2199093469","loc":[-85.6247251,41.9493485]},"n2199093468":{"id":"n2199093468","loc":[-85.6247548,41.9504949]},"n2199093467":{"id":"n2199093467","loc":[-85.6241214,41.9505017]},"n2199093466":{"id":"n2199093466","loc":[-85.6254398,41.950174]},"n2199093465":{"id":"n2199093465","loc":[-85.6254412,41.9499872]},"n2199093464":{"id":"n2199093464","loc":[-85.6255363,41.9499876]},"n2199093463":{"id":"n2199093463","loc":[-85.6255374,41.9498439]},"n2199093462":{"id":"n2199093462","loc":[-85.6255638,41.949844]},"n2199093461":{"id":"n2199093461","loc":[-85.6255652,41.9496672]},"n2199093460":{"id":"n2199093460","loc":[-85.6251823,41.9496656]},"n2199093459":{"id":"n2199093459","loc":[-85.6251785,41.9501729]},"n2199093510":{"id":"n2199093510","loc":[-85.6229922,41.9496143]},"n2199093509":{"id":"n2199093509","loc":[-85.6229915,41.9494306]},"n185948903":{"id":"n185948903","loc":[-85.616514,41.947449]},"n185955120":{"id":"n185955120","loc":[-85.620103,41.951]},"n185955143":{"id":"n185955143","loc":[-85.619784,41.94746]},"n185960124":{"id":"n185960124","loc":[-85.615238,41.947468]},"n185961362":{"id":"n185961362","loc":[-85.617437,41.947451]},"n185961364":{"id":"n185961364","loc":[-85.61861,41.947456]},"n185961367":{"id":"n185961367","loc":[-85.620088,41.947458]},"n185965105":{"id":"n185965105","loc":[-85.620087,41.94924]},"n185970220":{"id":"n185970220","loc":[-85.62156,41.948333]},"n185974697":{"id":"n185974697","loc":[-85.6201059,41.950132]},"n2138420778":{"id":"n2138420778","loc":[-85.616948,41.9474499]},"w17967535":{"id":"w17967535","tags":{"highway":"residential","name":"10th Ave"},"nodes":["n185955120","n185986812","n185983141"]},"w209716130":{"id":"w209716130","tags":{"area":"yes","building":"yes"},"nodes":["n2199093485","n2199093486","n2199093487","n2199093488","n2199093485"]},"w17964788":{"id":"w17964788","tags":{"highway":"residential","name":"6th Ave"},"nodes":["n185960124","n185948903","n2138420778","n185961362","n185961364","n185955143","n185961367","n185961369","n185961371"]},"w17965159":{"id":"w17965159","tags":{"highway":"residential","name":"8th Ave"},"nodes":["n185965105","n185965108","n185965110"]},"w209716125":{"id":"w209716125","tags":{"area":"yes","building":"yes"},"nodes":["n2199093459","n2199093460","n2199093461","n2199093462","n2199093463","n2199093464","n2199093465","n2199093466","n2199093459"]},"w17965699":{"id":"w17965699","tags":{"highway":"residential","name":"7th Ave"},"nodes":["n185970220","n185970222","n185970224"]},"w209716132":{"id":"w209716132","tags":{"area":"yes","building":"yes"},"nodes":["n2199093507","n2199093508","n2199093509","n2199093510","n2199093511","n2199093512","n2199093513","n2199093514","n2199093507"]},"w17966129":{"id":"w17966129","tags":{"highway":"residential","name":"9th Ave"},"nodes":["n185974697","n185974699"]},"w209716127":{"id":"w209716127","tags":{"area":"yes","building":"yes"},"nodes":["n2199093475","n2199093476","n2199093477","n2199093478","n2199093479","n2199093480","n2199093475"]},"w209716131":{"id":"w209716131","tags":{"area":"yes","natural":"water","water":"pond"},"nodes":["n2199093489","n2199093490","n2199093491","n2199093492","n2199093493","n2199093494","n2199093495","n2199093496","n2199093497","n2199093498","n2199093499","n2199093500","n2199093501","n2199093502","n2199093503","n2199093504","n2199093505","n2199093506","n2199093489"]},"w209716126":{"id":"w209716126","tags":{"area":"yes","building":"yes"},"nodes":["n2199093467","n2199093468","n2199093469","n2199093470","n2199093471","n2199093472","n2199093473","n2199093474","n2199093467"]},"w209716124":{"id":"w209716124","tags":{"area":"yes","building":"yes"},"nodes":["n2199093455","n2199093456","n2199093457","n2199093458","n2199093455"]},"w209716128":{"id":"w209716128","tags":{"area":"yes","building":"yes"},"nodes":["n2199093481","n2199093482","n2199093483","n2199093484","n2199093481"]},"n185949872":{"id":"n185949872","loc":[-85.643009,41.949264]},"n185949875":{"id":"n185949875","loc":[-85.642598,41.94929]},"n185949877":{"id":"n185949877","loc":[-85.642127,41.949382]},"n185949881":{"id":"n185949881","loc":[-85.64169,41.949936]},"n185988165":{"id":"n185988165","loc":[-85.642167,41.947657]},"n185988167":{"id":"n185988167","loc":[-85.642347,41.947662]},"n185988169":{"id":"n185988169","loc":[-85.642621,41.947659]},"n185965019":{"id":"n185965019","loc":[-85.6385084,41.951127]},"n1475293248":{"id":"n1475293248","loc":[-85.6386095,41.9512214]},"n185962639":{"id":"n185962639","loc":[-85.649669,41.949161]},"n185962810":{"id":"n185962810","loc":[-85.649907,41.949157]},"n185964355":{"id":"n185964355","loc":[-85.637412,41.9511359]},"n185965021":{"id":"n185965021","loc":[-85.638661,41.952386]},"n185965023":{"id":"n185965023","loc":[-85.638654,41.953665]},"n185965025":{"id":"n185965025","loc":[-85.638694,41.954649]},"n185965027":{"id":"n185965027","loc":[-85.638724,41.955913]},"n185971415":{"id":"n185971415","loc":[-85.644466,41.949246]},"n185971417":{"id":"n185971417","loc":[-85.647021,41.949193]},"n185971420":{"id":"n185971420","loc":[-85.648476,41.949169]},"n185979975":{"id":"n185979975","loc":[-85.644429,41.947633]},"n185988171":{"id":"n185988171","loc":[-85.645377,41.947622]},"w17963211":{"id":"w17963211","tags":{"highway":"residential"},"nodes":["n185949870","n185949872","n185949875","n185949877","n185949881"]},"w17965839":{"id":"w17965839","tags":{"highway":"residential","name":"Arnold St"},"nodes":["n185949870","n185971415","n185971417","n185971420","n185962639","n185962810"]},"w17967618":{"id":"w17967618","tags":{"highway":"residential","name":"Pierson St"},"nodes":["n185967777","n185988165","n185988167","n185988169","n185985824","n185979975","n185988171"]},"w17965149":{"id":"w17965149","tags":{"highway":"residential","name":"Oak St"},"nodes":["n185965019","n1475293248","n185965021","n185965023","n185965025","n185965027"]},"w17966118":{"id":"w17966118","tags":{"highway":"residential","name":"West Armitage Street"},"nodes":["n185974583","n185974585","n185964355","n185965019"]},"n2208608800":{"id":"n2208608800","loc":[-85.6354294,41.9486201]},"n2199109806":{"id":"n2199109806","loc":[-85.6350474,41.9477884]},"n2199109804":{"id":"n2199109804","loc":[-85.6350476,41.9477962]},"n2199109802":{"id":"n2199109802","loc":[-85.635002,41.9477969]},"n2199109799":{"id":"n2199109799","loc":[-85.6350018,41.9477883]},"n2199109797":{"id":"n2199109797","loc":[-85.6349141,41.9477897]},"n2199109795":{"id":"n2199109795","loc":[-85.6349131,41.9477535]},"n2199109793":{"id":"n2199109793","loc":[-85.6349395,41.9477531]},"n2199109791":{"id":"n2199109791","loc":[-85.6349382,41.9477077]},"n2199109789":{"id":"n2199109789","loc":[-85.6351236,41.9477049]},"n2199109787":{"id":"n2199109787","loc":[-85.6351259,41.9477872]},"n2199109785":{"id":"n2199109785","loc":[-85.634972,41.9475992]},"n2199109783":{"id":"n2199109783","loc":[-85.6349206,41.9475997]},"n2199109770":{"id":"n2199109770","loc":[-85.6348499,41.9475461]},"n2199109768":{"id":"n2199109768","loc":[-85.6348499,41.9475084]},"n2199109765":{"id":"n2199109765","loc":[-85.6349241,41.9474569]},"n2199109763":{"id":"n2199109763","loc":[-85.634967,41.9474564]},"n2199109762":{"id":"n2199109762","loc":[-85.6350405,41.9475121]},"n2199109761":{"id":"n2199109761","loc":[-85.6350405,41.9475419]},"n2199109753":{"id":"n2199109753","loc":[-85.6342443,41.9478391]},"n2199109751":{"id":"n2199109751","loc":[-85.6342427,41.9477927]},"n2199109745":{"id":"n2199109745","loc":[-85.6342439,41.9476859]},"n2199109743":{"id":"n2199109743","loc":[-85.6342429,41.9476575]},"n2199109741":{"id":"n2199109741","loc":[-85.6344615,41.9476533]},"n2199109739":{"id":"n2199109739","loc":[-85.6344678,41.9478348]},"n2199109737":{"id":"n2199109737","loc":[-85.634416,41.9480059]},"n2199109735":{"id":"n2199109735","loc":[-85.6344145,41.9478983]},"n2199109733":{"id":"n2199109733","loc":[-85.6342749,41.9478993]},"n2199109731":{"id":"n2199109731","loc":[-85.6342753,41.9479272]},"n2199109729":{"id":"n2199109729","loc":[-85.6342498,41.9479274]},"n2199109727":{"id":"n2199109727","loc":[-85.6342505,41.9479762]},"n2199109725":{"id":"n2199109725","loc":[-85.6342743,41.947976]},"n2199109723":{"id":"n2199109723","loc":[-85.6342747,41.948007]},"n2199109721":{"id":"n2199109721","loc":[-85.6343415,41.9476355]},"n2199109719":{"id":"n2199109719","loc":[-85.6343391,41.9474973]},"n2199109717":{"id":"n2199109717","loc":[-85.6343133,41.9474798]},"n2199109715":{"id":"n2199109715","loc":[-85.6342874,41.9474737]},"n2199109709":{"id":"n2199109709","loc":[-85.6349804,41.94815]},"n2199109707":{"id":"n2199109707","loc":[-85.6348915,41.9481505]},"n2199109705":{"id":"n2199109705","loc":[-85.6348917,41.9481692]},"n2199109702":{"id":"n2199109702","loc":[-85.6348522,41.9481694]},"n2199109700":{"id":"n2199109700","loc":[-85.6348532,41.9482679]},"n2199109698":{"id":"n2199109698","loc":[-85.6348315,41.948268]},"n2199109696":{"id":"n2199109696","loc":[-85.6348318,41.9482955]},"n2199109694":{"id":"n2199109694","loc":[-85.6349653,41.9482946]},"n2199109692":{"id":"n2199109692","loc":[-85.6349656,41.9483211]},"n2199109690":{"id":"n2199109690","loc":[-85.634999,41.9483209]},"n2199109688":{"id":"n2199109688","loc":[-85.6349987,41.9482947]},"n2199109686":{"id":"n2199109686","loc":[-85.6351753,41.9482935]},"n2199109684":{"id":"n2199109684","loc":[-85.6351749,41.9482617]},"n2199109682":{"id":"n2199109682","loc":[-85.6351588,41.9482618]},"n2199109680":{"id":"n2199109680","loc":[-85.6351575,41.9481518]},"n2199109678":{"id":"n2199109678","loc":[-85.6350671,41.9481524]},"n2199109676":{"id":"n2199109676","loc":[-85.6350649,41.9479659]},"n2199109674":{"id":"n2199109674","loc":[-85.6349785,41.9479665]},"n2199109671":{"id":"n2199109671","loc":[-85.6343069,41.9483263]},"n2199109669":{"id":"n2199109669","loc":[-85.6343052,41.9482981]},"n2199109658":{"id":"n2199109658","loc":[-85.6343314,41.9480549]},"n2199109656":{"id":"n2199109656","loc":[-85.6343305,41.9480461]},"n2199109654":{"id":"n2199109654","loc":[-85.634435,41.9480468]},"n2199109652":{"id":"n2199109652","loc":[-85.6344342,41.9483746]},"n2199109650":{"id":"n2199109650","loc":[-85.6344629,41.9483727]},"n2199109648":{"id":"n2199109648","loc":[-85.6344637,41.9484561]},"n2199109645":{"id":"n2199109645","loc":[-85.63443,41.9484567]},"n2199109642":{"id":"n2199109642","loc":[-85.6344317,41.948505]},"n185964352":{"id":"n185964352","loc":[-85.6373958,41.9489943]},"n185964351":{"id":"n185964351","loc":[-85.637113,41.9486]},"n2208608825":{"id":"n2208608825","loc":[-85.6354483,41.9494241]},"n2208608823":{"id":"n2208608823","loc":[-85.6360418,41.949416]},"n2208608821":{"id":"n2208608821","loc":[-85.6360458,41.9495802]},"n2208608811":{"id":"n2208608811","loc":[-85.6357458,41.9495843]},"n2208608808":{"id":"n2208608808","loc":[-85.6357508,41.9497835]},"n2208608806":{"id":"n2208608806","loc":[-85.6354573,41.9497875]},"n2208608795":{"id":"n2208608795","loc":[-85.6354595,41.9498778]},"n2199109638":{"id":"n2199109638","loc":[-85.6349605,41.949749]},"n2199109636":{"id":"n2199109636","loc":[-85.6349605,41.9497639]},"n2199109634":{"id":"n2199109634","loc":[-85.6349061,41.94971]},"n2199109632":{"id":"n2199109632","loc":[-85.6349048,41.9496569]},"n2199109630":{"id":"n2199109630","loc":[-85.6348835,41.9496571]},"n2199109628":{"id":"n2199109628","loc":[-85.6348829,41.9497103]},"n2199109626":{"id":"n2199109626","loc":[-85.635227,41.9497738]},"n2199109624":{"id":"n2199109624","loc":[-85.6352184,41.9497787]},"n2199109622":{"id":"n2199109622","loc":[-85.6351181,41.9497806]},"n2199109620":{"id":"n2199109620","loc":[-85.6351181,41.9497456]},"n2199109618":{"id":"n2199109618","loc":[-85.6348842,41.9497651]},"n2199109616":{"id":"n2199109616","loc":[-85.6348827,41.9496238]},"n2199109615":{"id":"n2199109615","loc":[-85.6351268,41.9496206]},"n2199109614":{"id":"n2199109614","loc":[-85.6351261,41.9495891]},"n2199109613":{"id":"n2199109613","loc":[-85.6351957,41.9495881]},"n2199109612":{"id":"n2199109612","loc":[-85.6351924,41.9494515]},"n2199109611":{"id":"n2199109611","loc":[-85.6353997,41.9494488]},"n2199109610":{"id":"n2199109610","loc":[-85.6354074,41.9497715]},"n2189015681":{"id":"n2189015681","loc":[-85.6344229,41.9509639]},"n2189015677":{"id":"n2189015677","loc":[-85.634424,41.9507396]},"n2138493843":{"id":"n2138493843","loc":[-85.6343935,41.9502836]},"n2138493840":{"id":"n2138493840","loc":[-85.634398,41.9506264]},"n354002838":{"id":"n354002838","loc":[-85.6345197,41.9510631]},"n2114807590":{"id":"n2114807590","loc":[-85.634511,41.9499767]},"n185964353":{"id":"n185964353","loc":[-85.6374092,41.9498755]},"n1819849180":{"id":"n1819849180","loc":[-85.6348236,41.94996]},"n1819849115":{"id":"n1819849115","loc":[-85.6354372,41.9499538]},"n1819848921":{"id":"n1819848921","loc":[-85.6348439,41.951064]},"n1819848885":{"id":"n1819848885","loc":[-85.6354575,41.9510578]},"n185984281":{"id":"n185984281","loc":[-85.638075,41.949872]},"n2208608827":{"id":"n2208608827","loc":[-85.6339169,41.9473191]},"n2199109749":{"id":"n2199109749","loc":[-85.6342082,41.9477934]},"n2199109747":{"id":"n2199109747","loc":[-85.6342045,41.9476867]},"n2199109713":{"id":"n2199109713","loc":[-85.6342404,41.9474746]},"n2199109711":{"id":"n2199109711","loc":[-85.6342404,41.9476355]},"n2199109673":{"id":"n2199109673","loc":[-85.6340886,41.9483282]},"n2199109667":{"id":"n2199109667","loc":[-85.6342403,41.9482988]},"n2199109665":{"id":"n2199109665","loc":[-85.6342386,41.9482116]},"n2199109662":{"id":"n2199109662","loc":[-85.6340861,41.9482135]},"n2199109660":{"id":"n2199109660","loc":[-85.6340802,41.9480562]},"n2199109640":{"id":"n2199109640","loc":[-85.6340928,41.9485063]},"n354031366":{"id":"n354031366","loc":[-85.6341667,41.9477778],"tags":{"amenity":"place_of_worship","name":"Faith Tabernacle Church","religion":"christian"}},"n2189015686":{"id":"n2189015686","loc":[-85.6337798,41.95099]},"n2189015684":{"id":"n2189015684","loc":[-85.6337794,41.9509674]},"n2189015673":{"id":"n2189015673","loc":[-85.6337501,41.9507457]},"n2189015669":{"id":"n2189015669","loc":[-85.6337501,41.9506974]},"n2189015665":{"id":"n2189015665","loc":[-85.6339034,41.9506959]},"n2189015662":{"id":"n2189015662","loc":[-85.6339015,41.950436]},"n2189015658":{"id":"n2189015658","loc":[-85.6334916,41.9504376]},"n2189015655":{"id":"n2189015655","loc":[-85.6334939,41.9507558]},"n2189015650":{"id":"n2189015650","loc":[-85.6334543,41.950756]},"n2189015649":{"id":"n2189015649","loc":[-85.633456,41.9509915]},"n2138493842":{"id":"n2138493842","loc":[-85.6339937,41.9502836]},"n2138493841":{"id":"n2138493841","loc":[-85.6339983,41.9506281]},"n2114807579":{"id":"n2114807579","loc":[-85.6333644,41.9510682]},"n2114807573":{"id":"n2114807573","loc":[-85.6333557,41.9499819]},"n354031330":{"id":"n354031330","loc":[-85.6341667,41.9497222],"tags":{"amenity":"place_of_worship","name":"Trinity Episcopal Church","religion":"christian"}},"n185960794":{"id":"n185960794","loc":[-85.633307,41.9537]},"n185964357":{"id":"n185964357","loc":[-85.637432,41.952399]},"n185964358":{"id":"n185964358","loc":[-85.637452,41.953665]},"n185964359":{"id":"n185964359","loc":[-85.63746,41.954658]},"n185964360":{"id":"n185964360","loc":[-85.637473,41.95592]},"n185964361":{"id":"n185964361","loc":[-85.637468,41.956906]},"n185964362":{"id":"n185964362","loc":[-85.637483,41.958313]},"n185966957":{"id":"n185966957","loc":[-85.633361,41.957422]},"n185975351":{"id":"n185975351","loc":[-85.63334,41.9559]},"n185978784":{"id":"n185978784","loc":[-85.633311,41.954679]},"n185986157":{"id":"n185986157","loc":[-85.633287,41.952426]},"n185986158":{"id":"n185986158","loc":[-85.6333607,41.9582301],"tags":{"highway":"turning_circle"}},"w17965182":{"id":"w17965182","tags":{"highway":"residential","name":"W Prutzman St"},"nodes":["n185965289","n2189153241","n185965291"]},"w208627205":{"id":"w208627205","tags":{"area":"yes","building":"yes"},"nodes":["n2189015649","n2189015650","n2189015655","n2189015658","n2189015662","n2189015665","n2189015669","n2189015673","n2189015677","n2189015681","n2189015684","n2189015686","n2189015649"]},"w209717042":{"id":"w209717042","tags":{"amenity":"place_of_worship","area":"yes","building":"yes","denomination":"presbyterian","name":"First Presbyterian Church","religion":"christian"},"nodes":["n2199109610","n2199109611","n2199109612","n2199109613","n2199109614","n2199109615","n2199109616","n2199109630","n2199109632","n2199109634","n2199109628","n2199109618","n2199109636","n2199109638","n2199109620","n2199109622","n2199109624","n2199109626","n2199109610"]},"w209717045":{"id":"w209717045","tags":{"area":"yes","building":"yes"},"nodes":["n2199109711","n2199109713","n2199109715","n2199109717","n2199109719","n2199109721","n2199109711"]},"w209717047":{"id":"w209717047","tags":{"area":"yes","building":"yes"},"nodes":["n2199109739","n2199109741","n2199109743","n2199109745","n2199109747","n2199109749","n2199109751","n2199109753","n2199109739"]},"w209717044":{"id":"w209717044","tags":{"area":"yes","building":"yes"},"nodes":["n2199109674","n2199109676","n2199109678","n2199109680","n2199109682","n2199109684","n2199109686","n2199109688","n2199109690","n2199109692","n2199109694","n2199109696","n2199109698","n2199109700","n2199109702","n2199109705","n2199109707","n2199109709","n2199109674"]},"w210822776":{"id":"w210822776","tags":{"highway":"service","service":"alley","surface":"unpaved"},"nodes":["n2208608795","n2208608806","n2208608825","n2208608800","n2189153241"]},"w210822778":{"id":"w210822778","tags":{"highway":"service","service":"alley"},"nodes":["n2208608826","n2208608827"]},"w209717050":{"id":"w209717050","tags":{"area":"yes","building":"yes"},"nodes":["n2199109787","n2199109789","n2199109791","n2199109793","n2199109795","n2199109797","n2199109799","n2199109802","n2199109804","n2199109806","n2199109787"]},"w17965097":{"id":"w17965097","tags":{"highway":"residential","name":"Maple Street"},"nodes":["n185964351","n185964352","n185964353","n185964355","n185964357","n185964358","n185964359","n185964360","n185964361","n185964362"]},"w17965856":{"id":"w17965856","tags":{"highway":"residential","name":"W Kelsey St"},"nodes":["n185971578","n2208608800","n185971580","n185964351"]},"w17967444":{"id":"w17967444","tags":{"highway":"residential","name":"East Street"},"nodes":["n185966937","n185978969","n185986155","n185985812","n185986157","n185960794","n185978784","n185975351","n185966957","n185986158"]},"w17967764":{"id":"w17967764","tags":{"highway":"residential","name":"Rock River Ave"},"nodes":["n185984017","n185964351"]},"w170848329":{"id":"w170848329","tags":{"leisure":"park","name":"LaFayette Park"},"nodes":["n1819849180","n1819849115","n1819848885","n1819848921","n1819849180"]},"w17967208":{"id":"w17967208","tags":{"highway":"residential","name":"West Bennett Street"},"nodes":["n185978390","n2208608795","n185984020","n185964353","n185984281"]},"w17965349":{"id":"w17965349","tags":{"highway":"residential","name":"E Prutzman St"},"nodes":["n185966937","n2208608827","n185965289"]},"w209717049":{"id":"w209717049","tags":{"area":"yes","building":"yes"},"nodes":["n2199109761","n2199109762","n2199109763","n2199109765","n2199109768","n2199109770","n2199109783","n2199109785","n2199109761"]},"w203841840":{"id":"w203841840","tags":{"area":"yes","leisure":"playground"},"nodes":["n2138493840","n2138493841","n2138493842","n2138493843","n2138493840"]},"w209717043":{"id":"w209717043","tags":{"amenity":"place_of_worship","area":"yes","building":"church","denomination":"methodist","name":"First United Methodist Church","religion":"christian"},"nodes":["n2199109640","n2199109642","n2199109645","n2199109648","n2199109650","n2199109652","n2199109654","n2199109656","n2199109658","n2199109660","n2199109662","n2199109665","n2199109667","n2199109669","n2199109671","n2199109673","n2199109640"]},"w201484341":{"id":"w201484341","tags":{"amenity":"school","name":"Hoppin School"},"nodes":["n354002838","n2114807579","n2114807573","n2114807590","n354002838"]},"w209717046":{"id":"w209717046","tags":{"area":"yes","building":"yes"},"nodes":["n2199109723","n2199109725","n2199109727","n2199109729","n2199109731","n2199109733","n2199109735","n2199109737","n2199109723"]},"w210822777":{"id":"w210822777","tags":{"amenity":"parking","area":"yes"},"nodes":["n2208608806","n2208608808","n2208608811","n2208608821","n2208608823","n2208608825","n2208608806"]},"n185954965":{"id":"n185954965","loc":[-85.6191189,41.9441922]},"n185954968":{"id":"n185954968","loc":[-85.6194384,41.9442405]},"n185954970":{"id":"n185954970","loc":[-85.6196543,41.9443252]},"n185954972":{"id":"n185954972","loc":[-85.6197862,41.9444539]},"n354002931":{"id":"n354002931","loc":[-85.6198991,41.9455269]},"n354030853":{"id":"n354030853","loc":[-85.6219444,41.9455556],"tags":{"amenity":"place_of_worship","name":"Grant Chapel","religion":"christian"}},"n367815963":{"id":"n367815963","loc":[-85.6202778,41.9461111],"tags":{"building":"yes","name":"George Washington Carver Community Center"}},"n185947331":{"id":"n185947331","loc":[-85.618779,41.943269]},"n185947333":{"id":"n185947333","loc":[-85.618795,41.943511]},"n185947336":{"id":"n185947336","loc":[-85.618711,41.94413]},"n185947338":{"id":"n185947338","loc":[-85.618704,41.944189]},"n185947339":{"id":"n185947339","loc":[-85.618597,41.944337]},"n185947340":{"id":"n185947340","loc":[-85.618485,41.944528]},"n185947343":{"id":"n185947343","loc":[-85.618442,41.944716]},"n185947345":{"id":"n185947345","loc":[-85.618457,41.945107]},"n185947347":{"id":"n185947347","loc":[-85.618296,41.945338]},"n185947374":{"id":"n185947374","loc":[-85.616748,41.944453]},"n185947375":{"id":"n185947375","loc":[-85.616813,41.944646]},"n185947376":{"id":"n185947376","loc":[-85.616859,41.945196]},"n185947377":{"id":"n185947377","loc":[-85.616941,41.945352]},"n185947406":{"id":"n185947406","loc":[-85.618184,41.944227]},"n185947409":{"id":"n185947409","loc":[-85.617911,41.943875]},"n185947410":{"id":"n185947410","loc":[-85.617579,41.943682]},"n185947411":{"id":"n185947411","loc":[-85.61713,41.943589]},"n185947412":{"id":"n185947412","loc":[-85.616549,41.943559]},"n185947414":{"id":"n185947414","loc":[-85.616482,41.943556]},"n185947464":{"id":"n185947464","loc":[-85.616526,41.943788]},"n185947466":{"id":"n185947466","loc":[-85.616504,41.944002]},"n185948863":{"id":"n185948863","loc":[-85.619017,41.943391]},"n185948865":{"id":"n185948865","loc":[-85.619059,41.943368]},"n185955022":{"id":"n185955022","loc":[-85.620088,41.945571]},"n185955025":{"id":"n185955025","loc":[-85.620051,41.945505]},"n185955028":{"id":"n185955028","loc":[-85.62001,41.94541]},"n185980371":{"id":"n185980371","loc":[-85.620982,41.944742]},"n185980398":{"id":"n185980398","loc":[-85.621305,41.944782]},"n185980401":{"id":"n185980401","loc":[-85.621174,41.944819]},"n185980403":{"id":"n185980403","loc":[-85.621029,41.944871]},"n185980405":{"id":"n185980405","loc":[-85.620741,41.945011]},"n185980407":{"id":"n185980407","loc":[-85.620616,41.945085]},"n185980409":{"id":"n185980409","loc":[-85.620506,41.945172]},"n185980411":{"id":"n185980411","loc":[-85.620394,41.945273]},"n185980413":{"id":"n185980413","loc":[-85.620316,41.94536]},"n185980415":{"id":"n185980415","loc":[-85.620257,41.945452]},"n185980417":{"id":"n185980417","loc":[-85.620212,41.945535]},"n185985910":{"id":"n185985910","loc":[-85.620101,41.945811]},"n185985912":{"id":"n185985912","loc":[-85.620081,41.945937]},"n1475283972":{"id":"n1475283972","loc":[-85.6198991,41.9437179]},"n1475283982":{"id":"n1475283982","loc":[-85.6195022,41.9433463]},"n1475284007":{"id":"n1475284007","loc":[-85.6193037,41.9433383]},"n1475284040":{"id":"n1475284040","loc":[-85.6197329,41.9434121]},"n1475284044":{"id":"n1475284044","loc":[-85.6198756,41.9435363]},"n1475284050":{"id":"n1475284050","loc":[-85.6199689,41.9432106]},"n1475284053":{"id":"n1475284053","loc":[-85.6198943,41.9432921]},"n185954974":{"id":"n185954974","loc":[-85.6198296,41.94473]},"n185954977":{"id":"n185954977","loc":[-85.6200474,41.9447384]},"n2196831365":{"id":"n2196831365","loc":[-85.6202259,41.9460883]},"n2196831366":{"id":"n2196831366","loc":[-85.6202245,41.9458642]},"n2196831367":{"id":"n2196831367","loc":[-85.6205184,41.9458631]},"n2196831368":{"id":"n2196831368","loc":[-85.6205189,41.9459437]},"n2196831369":{"id":"n2196831369","loc":[-85.6203879,41.9459441]},"n2196831370":{"id":"n2196831370","loc":[-85.6203888,41.9460878]},"n2196831371":{"id":"n2196831371","loc":[-85.6184046,41.9465663]},"n2196831372":{"id":"n2196831372","loc":[-85.6191563,41.9465618]},"n2196831373":{"id":"n2196831373","loc":[-85.6191536,41.946319]},"n2196831374":{"id":"n2196831374","loc":[-85.6187356,41.9463216]},"n2196831375":{"id":"n2196831375","loc":[-85.6187334,41.9461197]},"n2196831376":{"id":"n2196831376","loc":[-85.6193167,41.9461162]},"n2196831377":{"id":"n2196831377","loc":[-85.6193156,41.9460229]},"n2196831378":{"id":"n2196831378","loc":[-85.619622,41.946021]},"n2196831379":{"id":"n2196831379","loc":[-85.6196237,41.9461712]},"n2196831380":{"id":"n2196831380","loc":[-85.6197702,41.9461703]},"n2196831381":{"id":"n2196831381","loc":[-85.6197685,41.9460202]},"n2196831382":{"id":"n2196831382","loc":[-85.6197323,41.9460204]},"n2196831383":{"id":"n2196831383","loc":[-85.6197305,41.9458563]},"n2196831384":{"id":"n2196831384","loc":[-85.6196165,41.945857]},"n2196831385":{"id":"n2196831385","loc":[-85.6196156,41.9457764]},"n2196831386":{"id":"n2196831386","loc":[-85.6194472,41.9457775]},"n2196831387":{"id":"n2196831387","loc":[-85.6194151,41.9457777]},"n2196831388":{"id":"n2196831388","loc":[-85.6183779,41.9457883]},"n2196831389":{"id":"n2196831389","loc":[-85.6183842,41.9461317]},"n2196831390":{"id":"n2196831390","loc":[-85.6185026,41.9461304]},"n2196831391":{"id":"n2196831391","loc":[-85.6185061,41.9463194]},"n2196831392":{"id":"n2196831392","loc":[-85.6184001,41.9463205]},"n2196831393":{"id":"n2196831393","loc":[-85.6182482,41.9464163]},"n2196831394":{"id":"n2196831394","loc":[-85.6182467,41.9463193]},"n2196831395":{"id":"n2196831395","loc":[-85.6180389,41.946321]},"n2196831397":{"id":"n2196831397","loc":[-85.6180404,41.946418]},"n185947303":{"id":"n185947303","loc":[-85.611074,41.943389]},"n185947304":{"id":"n185947304","loc":[-85.611332,41.943267]},"n185947305":{"id":"n185947305","loc":[-85.611635,41.943218]},"n185947306":{"id":"n185947306","loc":[-85.612762,41.943311]},"n185947308":{"id":"n185947308","loc":[-85.613027,41.943327]},"n185947310":{"id":"n185947310","loc":[-85.615377,41.942996]},"n185947312":{"id":"n185947312","loc":[-85.615701,41.943007]},"n185947314":{"id":"n185947314","loc":[-85.61604,41.943067]},"n185947315":{"id":"n185947315","loc":[-85.61626,41.943083]},"n185947316":{"id":"n185947316","loc":[-85.616507,41.943048]},"n185947319":{"id":"n185947319","loc":[-85.616702,41.94299]},"n185947321":{"id":"n185947321","loc":[-85.617078,41.942918]},"n185947322":{"id":"n185947322","loc":[-85.617366,41.942973]},"n185947323":{"id":"n185947323","loc":[-85.617601,41.943033]},"n185947325":{"id":"n185947325","loc":[-85.617799,41.943027]},"n185947327":{"id":"n185947327","loc":[-85.618264,41.942961]},"n185947328":{"id":"n185947328","loc":[-85.618508,41.942972]},"n185947329":{"id":"n185947329","loc":[-85.618707,41.943076]},"n185947361":{"id":"n185947361","loc":[-85.615356,41.944922]},"n185947363":{"id":"n185947363","loc":[-85.61536,41.944893]},"n185947365":{"id":"n185947365","loc":[-85.615406,41.944547]},"n185947367":{"id":"n185947367","loc":[-85.61548,41.944351]},"n185947369":{"id":"n185947369","loc":[-85.615805,41.94419]},"n185947371":{"id":"n185947371","loc":[-85.616166,41.944156]},"n185947373":{"id":"n185947373","loc":[-85.616411,41.944197]},"n185947416":{"id":"n185947416","loc":[-85.616335,41.94343]},"n185947417":{"id":"n185947417","loc":[-85.616069,41.943293]},"n185947419":{"id":"n185947419","loc":[-85.615803,41.943249]},"n185947420":{"id":"n185947420","loc":[-85.615524,41.943342]},"n185947421":{"id":"n185947421","loc":[-85.615311,41.94353]},"n185947422":{"id":"n185947422","loc":[-85.614338,41.943558]},"n185947423":{"id":"n185947423","loc":[-85.61422,41.94369]},"n185947425":{"id":"n185947425","loc":[-85.614221,41.944224]},"n185947427":{"id":"n185947427","loc":[-85.614198,41.944888]},"n185947429":{"id":"n185947429","loc":[-85.614221,41.945439]},"n185947468":{"id":"n185947468","loc":[-85.615908,41.944756]},"n185947470":{"id":"n185947470","loc":[-85.615871,41.944888]},"n185947472":{"id":"n185947472","loc":[-85.615878,41.94507]},"n185955153":{"id":"n185955153","loc":[-85.620087,41.947701]},"n185960690":{"id":"n185960690","loc":[-85.620141,41.951901]},"n185978817":{"id":"n185978817","loc":[-85.617193,41.954706]},"n185985916":{"id":"n185985916","loc":[-85.620088,41.94758]},"n185985918":{"id":"n185985918","loc":[-85.620133,41.951538]},"n185985919":{"id":"n185985919","loc":[-85.62013,41.952104]},"n185985920":{"id":"n185985920","loc":[-85.620104,41.952305]},"n185985921":{"id":"n185985921","loc":[-85.620062,41.952499]},"n185985922":{"id":"n185985922","loc":[-85.619993,41.952702]},"n185985925":{"id":"n185985925","loc":[-85.619879,41.952986]},"n185985927":{"id":"n185985927","loc":[-85.619689,41.95329]},"n185985928":{"id":"n185985928","loc":[-85.619508,41.953521]},"n185985929":{"id":"n185985929","loc":[-85.619286,41.953728]},"n185985930":{"id":"n185985930","loc":[-85.618925,41.954007]},"n185985931":{"id":"n185985931","loc":[-85.618638,41.954189]},"n185985932":{"id":"n185985932","loc":[-85.61831,41.954358]},"n185985934":{"id":"n185985934","loc":[-85.618015,41.954485]},"n185985936":{"id":"n185985936","loc":[-85.617606,41.954611]},"n1475283975":{"id":"n1475283975","loc":[-85.6150935,41.9434118]},"n1475283979":{"id":"n1475283979","loc":[-85.6193367,41.9430252]},"n1475283989":{"id":"n1475283989","loc":[-85.6104771,41.9455269]},"n1475283990":{"id":"n1475283990","loc":[-85.6104771,41.9437179]},"n1475283994":{"id":"n1475283994","loc":[-85.6198042,41.9429763]},"n1475283998":{"id":"n1475283998","loc":[-85.6192101,41.9426716]},"n1475284000":{"id":"n1475284000","loc":[-85.6198622,41.942836]},"n1475284002":{"id":"n1475284002","loc":[-85.6163262,41.9427688]},"n1475284006":{"id":"n1475284006","loc":[-85.6179527,41.9429168]},"n1475284029":{"id":"n1475284029","loc":[-85.6197195,41.9427278]},"n1475284038":{"id":"n1475284038","loc":[-85.6194405,41.9427837]},"n1475284052":{"id":"n1475284052","loc":[-85.6153225,41.942841]},"n1475284055":{"id":"n1475284055","loc":[-85.6129233,41.9437179]},"n2139966627":{"id":"n2139966627","loc":[-85.61958,41.9427558]},"w17966773":{"id":"w17966773","tags":{"highway":"secondary","name":"E Michigan Ave","ref":"M 60"},"nodes":["n185980372","n185980398","n185980401","n185980403","n185980405","n185980407","n185980409","n185980411","n185980413","n185980415","n185980417","n185955019"]},"w17964043":{"id":"w17964043","tags":{"highway":"residential"},"nodes":["n185955019","n185955022","n185955025","n185955028","n185954977","n185971477","n1475284050","n1475284000","n1475284029","n2139966627","n1475284038"]},"w17962834":{"id":"w17962834","tags":{"highway":"service"},"nodes":["n185947316","n185947414","n185947464","n185947466","n185947373","n185947468","n185947470","n185947472","n185947474"]},"w209470310":{"id":"w209470310","tags":{"area":"yes","building":"yes"},"nodes":["n2196831393","n2196831394","n2196831395","n2196831397","n2196831393"]},"w17963058":{"id":"w17963058","tags":{"highway":"service"},"nodes":["n185947333","n185948863","n185948865","n1475284007","n1475283982","n1475284040","n1475284044"]},"w17962823":{"id":"w17962823","tags":{"highway":"service"},"nodes":["n185947359","n185947361","n185947363","n185947365","n185947367","n185947369","n185947371","n185947373","n185947374","n185947375","n185947376","n185947377","n185947378"]},"w17962821":{"id":"w17962821","tags":{"highway":"service"},"nodes":["n185947303","n185947304","n185947305","n185947306","n185947308","n185947310","n185947312","n185947314","n185947315","n185947316","n185947319","n185947321","n185947322","n185947323","n185947325","n185947327","n185947328","n185947329","n185947331","n185947333","n185947336","n185947338","n185947339","n185947340","n185947343","n185947345","n185947347","n185947349"]},"w134150798":{"id":"w134150798","tags":{"amenity":"grave_yard","name":"Riverside Cemetery"},"nodes":["n354002931","n1475283972","n1475284053","n1475283994","n1475283979","n1475283998","n1475284006","n1475284002","n1475284052","n1475283975","n1475284055","n1475283990","n1475283989","n354002931"]},"w17964040":{"id":"w17964040","tags":{"highway":"service"},"nodes":["n185947336","n185954965","n185954968","n185954970","n185954972","n185954974","n185954977"]},"w209470308":{"id":"w209470308","tags":{"area":"yes","building":"yes"},"nodes":["n2196831365","n2196831366","n2196831367","n2196831368","n2196831369","n2196831370","n2196831365"]},"w17962828":{"id":"w17962828","tags":{"highway":"service"},"nodes":["n185947340","n185947406","n185947409","n185947410","n185947411","n185947412","n185947414","n185947416","n185947417","n185947419","n185947420","n185947421","n185947422","n185947423","n185947425","n185947427","n185947429"]},"w209470309":{"id":"w209470309","tags":{"area":"yes","building":"yes"},"nodes":["n2196831371","n2196831372","n2196831373","n2196831374","n2196831375","n2196831376","n2196831377","n2196831378","n2196831379","n2196831380","n2196831381","n2196831382","n2196831383","n2196831384","n2196831385","n2196831386","n2196831387","n2196831388","n2196831389","n2196831390","n2196831391","n2196831392","n2196831371"]},"w17967415":{"id":"w17967415","tags":{"highway":"secondary","name":"Jefferson St","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185955019","n185985910","n185985912","n185985914","n185961367","n185985916","n185955153","n185965105","n185974697","n185955120","n185985918","n185960690","n185985919","n185985920","n185985921","n185985922","n185985925","n185985927","n185985928","n185985929","n185985930","n185985931","n185985932","n185985934","n185985936","n185978817"]},"w17966772":{"id":"w17966772","tags":{"highway":"unclassified","name":"E Michigan Ave","name_1":"State Highway 60"},"nodes":["n185954977","n185980371","n185980372"]},"n185958500":{"id":"n185958500","loc":[-85.621591,41.941075]},"n185963110":{"id":"n185963110","loc":[-85.6204416,41.9408882]},"n2139966628":{"id":"n2139966628","loc":[-85.6196431,41.9426467],"tags":{"leisure":"fishing"}},"n2139966630":{"id":"n2139966630","loc":[-85.6199354,41.9429616]},"n2199127051":{"id":"n2199127051","loc":[-85.6170556,41.939696]},"n2199127052":{"id":"n2199127052","loc":[-85.6170536,41.9392909]},"n2199127053":{"id":"n2199127053","loc":[-85.6172067,41.9392905]},"n2199127054":{"id":"n2199127054","loc":[-85.6172061,41.9391853]},"n2199127055":{"id":"n2199127055","loc":[-85.6171481,41.9391854]},"n2199127060":{"id":"n2199127060","loc":[-85.6167389,41.9392896]},"n2199127061":{"id":"n2199127061","loc":[-85.6168728,41.9392892]},"n2199127062":{"id":"n2199127062","loc":[-85.6168747,41.9396965]},"n2199127071":{"id":"n2199127071","loc":[-85.620196,41.9399446]},"n2199127072":{"id":"n2199127072","loc":[-85.620193,41.9397316]},"n2199127073":{"id":"n2199127073","loc":[-85.6200381,41.9397328]},"n2199127074":{"id":"n2199127074","loc":[-85.6200412,41.9399458]},"n2199127075":{"id":"n2199127075","loc":[-85.6203606,41.9399939]},"n2199127076":{"id":"n2199127076","loc":[-85.6205527,41.9399922]},"n2199127077":{"id":"n2199127077","loc":[-85.6205482,41.9397115]},"n2199127078":{"id":"n2199127078","loc":[-85.6204132,41.9397124]},"n2199127079":{"id":"n2199127079","loc":[-85.6204144,41.9396341]},"n2199127080":{"id":"n2199127080","loc":[-85.6205699,41.9396324]},"n2199127081":{"id":"n2199127081","loc":[-85.6205722,41.939498]},"n2199127082":{"id":"n2199127082","loc":[-85.6204064,41.9394997]},"n2199127083":{"id":"n2199127083","loc":[-85.6204087,41.939561]},"n2199127084":{"id":"n2199127084","loc":[-85.6203103,41.9395618]},"n2199127085":{"id":"n2199127085","loc":[-85.620308,41.9396069]},"n2199127086":{"id":"n2199127086","loc":[-85.6200347,41.9396086]},"n2199127087":{"id":"n2199127087","loc":[-85.6200382,41.9397141]},"n2199127088":{"id":"n2199127088","loc":[-85.6202257,41.9397149]},"n2199127089":{"id":"n2199127089","loc":[-85.6202269,41.9399182]},"n2199127090":{"id":"n2199127090","loc":[-85.6203595,41.9399199]},"n2199127091":{"id":"n2199127091","loc":[-85.6212335,41.939688]},"n2199127092":{"id":"n2199127092","loc":[-85.6212328,41.939595]},"n2199127093":{"id":"n2199127093","loc":[-85.6208807,41.9395966]},"n2199127094":{"id":"n2199127094","loc":[-85.6208815,41.9396896]},"n2199127095":{"id":"n2199127095","loc":[-85.6208676,41.9396872]},"n2199127096":{"id":"n2199127096","loc":[-85.6208583,41.9393539]},"n2199127097":{"id":"n2199127097","loc":[-85.6207006,41.9393563]},"n2199127098":{"id":"n2199127098","loc":[-85.6207099,41.9396896]},"n185967054":{"id":"n185967054","loc":[-85.6173384,41.9356126]},"n185967063":{"id":"n185967063","loc":[-85.617371,41.936243]},"n185967065":{"id":"n185967065","loc":[-85.617337,41.936299]},"n185967068":{"id":"n185967068","loc":[-85.617321,41.936373]},"n185967070":{"id":"n185967070","loc":[-85.6173562,41.9366969]},"n185967074":{"id":"n185967074","loc":[-85.6173635,41.9377414]},"n185967075":{"id":"n185967075","loc":[-85.6173696,41.9381886]},"n185967076":{"id":"n185967076","loc":[-85.617372,41.938535]},"n2199127056":{"id":"n2199127056","loc":[-85.617147,41.9389616]},"n2199127057":{"id":"n2199127057","loc":[-85.6172136,41.9389614]},"n2199127058":{"id":"n2199127058","loc":[-85.6172123,41.9386909]},"n2199127059":{"id":"n2199127059","loc":[-85.616736,41.9386922]},"n2203921041":{"id":"n2203921041","loc":[-85.6173018,41.9346369]},"w203983952":{"id":"w203983952","tags":{"highway":"service"},"nodes":["n2139966627","n1819800319"]},"w209718301":{"id":"w209718301","tags":{"area":"yes","building":"yes"},"nodes":["n2199127051","n2199127052","n2199127053","n2199127054","n2199127055","n2199127056","n2199127057","n2199127058","n2199127059","n2199127060","n2199127061","n2199127062","n2199127051"]},"w209718304":{"id":"w209718304","tags":{"area":"yes","building":"yes"},"nodes":["n2199127071","n2199127072","n2199127073","n2199127074","n2199127071"]},"w17964961":{"id":"w17964961","tags":{"highway":"residential","name":"Whipple St"},"nodes":["n185963099","n185963110"]},"w17964489":{"id":"w17964489","tags":{"highway":"residential","name":"Jackson St"},"nodes":["n185958498","n185958500"]},"w203983953":{"id":"w203983953","tags":{"area":"yes","leisure":"park","name":"Marina Park"},"nodes":["n1475283994","n1475283979","n1475283998","n2139966629","n2139966625","n1819800319","n2139966623","n2139966622","n2139966621","n2139966630","n1475283994"]},"w17965366":{"id":"w17965366","tags":{"highway":"residential","name":"14th St"},"nodes":["n2203921041","n185967054","n185967063","n185967065","n185967068","n185967070","n185967074","n185967075","n185967076","n185967077"]},"w209718306":{"id":"w209718306","tags":{"area":"yes","building":"yes"},"nodes":["n2199127091","n2199127092","n2199127093","n2199127094","n2199127091"]},"w209718307":{"id":"w209718307","tags":{"area":"yes","building":"yes"},"nodes":["n2199127095","n2199127096","n2199127097","n2199127098","n2199127095"]},"w209718305":{"id":"w209718305","tags":{"area":"yes","building":"yes"},"nodes":["n2199127075","n2199127076","n2199127077","n2199127078","n2199127079","n2199127080","n2199127081","n2199127082","n2199127083","n2199127084","n2199127085","n2199127086","n2199127087","n2199127088","n2199127089","n2199127090","n2199127075"]},"n185960199":{"id":"n185960199","loc":[-85.62965,41.95469]},"n185980737":{"id":"n185980737","loc":[-85.629083,41.953725]},"n2114807561":{"id":"n2114807561","loc":[-85.6297681,41.9524688]},"n2114807597":{"id":"n2114807597","loc":[-85.6296517,41.952563]},"n185960197":{"id":"n185960197","loc":[-85.629676,41.9537314]},"n185978791":{"id":"n185978791","loc":[-85.6244542,41.9547066]},"w17967573":{"id":"w17967573","tags":{"highway":"residential","name":"E Wheeler St"},"nodes":["n185960195","n2114807561","n185968102","n185967430","n185986157","n185978392"]},"w17966553":{"id":"w17966553","tags":{"highway":"residential","name":"East Hoffman Street"},"nodes":["n185971631","n185978784","n185967432","n185968106","n185960199","n185978787","n185978790","n185978791"]},"w17966787":{"id":"w17966787","tags":{"highway":"residential","name":"East Cushman Street"},"nodes":["n185980735","n185980737","n185960197","n185968104","n185960792"]},"w17964723":{"id":"w17964723","tags":{"highway":"residential","name":"Cushman Street"},"nodes":["n185960792","n185960794","n185960796"]},"w17964654":{"id":"w17964654","tags":{"highway":"residential","name":"Pine Street"},"nodes":["n185960195","n2114807597","n185960197","n185960199"]},"n1819848862":{"id":"n1819848862","loc":[-85.6346087,41.9545845]},"n1819848935":{"id":"n1819848935","loc":[-85.6345948,41.9537717]},"n1819848973":{"id":"n1819848973","loc":[-85.6334247,41.9537827]},"n1819848997":{"id":"n1819848997","loc":[-85.6334386,41.9545956]},"n2189015861":{"id":"n2189015861","loc":[-85.6375906,41.954836]},"n2189015865":{"id":"n2189015865","loc":[-85.6383307,41.9548291]},"n2189015867":{"id":"n2189015867","loc":[-85.6383337,41.9550072]},"n2189015868":{"id":"n2189015868","loc":[-85.6380986,41.9550094]},"n2189015869":{"id":"n2189015869","loc":[-85.6381005,41.9551226]},"n2199109808":{"id":"n2199109808","loc":[-85.6372702,41.9522894]},"n2199109810":{"id":"n2199109810","loc":[-85.6372677,41.9521583]},"n2199109812":{"id":"n2199109812","loc":[-85.6369505,41.9521617]},"n2199109814":{"id":"n2199109814","loc":[-85.636953,41.9522927]},"n185952156":{"id":"n185952156","loc":[-85.640983,41.9546557]},"n185953423":{"id":"n185953423","loc":[-85.641871,41.954652]},"n185971637":{"id":"n185971637","loc":[-85.641583,41.95465]},"n185971639":{"id":"n185971639","loc":[-85.6421344,41.9546444]},"n185971642":{"id":"n185971642","loc":[-85.6428264,41.9545612]},"n185971648":{"id":"n185971648","loc":[-85.6436023,41.9544262]},"n185975066":{"id":"n185975066","loc":[-85.640532,41.953638]},"n185975067":{"id":"n185975067","loc":[-85.64079,41.953638]},"n185982166":{"id":"n185982166","loc":[-85.6399012,41.9523817]},"n2189015858":{"id":"n2189015858","loc":[-85.6376104,41.9560138]},"n2189015870":{"id":"n2189015870","loc":[-85.6386794,41.9551172]},"n2189015871":{"id":"n2189015871","loc":[-85.6386817,41.955256]},"n2189015873":{"id":"n2189015873","loc":[-85.6385437,41.9552573]},"n2189015876":{"id":"n2189015876","loc":[-85.638555,41.9559278]},"n2189015879":{"id":"n2189015879","loc":[-85.6384954,41.9559283]},"n2189015882":{"id":"n2189015882","loc":[-85.6384965,41.9559935]},"n2189015885":{"id":"n2189015885","loc":[-85.6383533,41.9559949]},"n2189015888":{"id":"n2189015888","loc":[-85.638351,41.9558607]},"n2189015891":{"id":"n2189015891","loc":[-85.6382178,41.9558619]},"n2189015894":{"id":"n2189015894","loc":[-85.6382203,41.956008]},"w208627223":{"id":"w208627223","tags":{"area":"yes","building":"yes"},"nodes":["n2189015858","n2189015861","n2189015865","n2189015867","n2189015868","n2189015869","n2189015870","n2189015871","n2189015873","n2189015876","n2189015879","n2189015882","n2189015885","n2189015888","n2189015891","n2189015894","n2189015858"]},"w170848328":{"id":"w170848328","tags":{"leisure":"park","name":"Bowman Park"},"nodes":["n1819848935","n1819848973","n1819848997","n1819848862","n1819848935"]},"w17965866":{"id":"w17965866","tags":{"highway":"residential","name":"West Hoffman Street"},"nodes":["n185971631","n185971632","n185964359","n185965025","n1475293264","n185952156","n185971637","n185953423","n185971639","n185971642","n185971648"]},"w209717051":{"id":"w209717051","tags":{"amenity":"place_of_worship","area":"yes","building":"yes","denomination":"baptist","name":"Calvary Missionary Baptist Church","religion":"christian"},"nodes":["n2199109808","n2199109810","n2199109812","n2199109814","n2199109808"]},"w17966172":{"id":"w17966172","tags":{"highway":"residential","name":"West Cushman Street"},"nodes":["n185960796","n185975064","n185964358","n185965023","n1475293222","n185975066","n185975067"]},"w17966975":{"id":"w17966975","tags":{"highway":"residential","name":"W Wheeler St"},"nodes":["n185978392","n185982163","n185964357","n185965021","n1475293261","n185982166"]},"n185960684":{"id":"n185960684","loc":[-85.622687,41.951885]},"n185960686":{"id":"n185960686","loc":[-85.622492,41.951901]},"n185978795":{"id":"n185978795","loc":[-85.6240991,41.954708]},"n185978803":{"id":"n185978803","loc":[-85.623348,41.954547]},"n185978806":{"id":"n185978806","loc":[-85.623123,41.954502]},"n185978808":{"id":"n185978808","loc":[-85.622923,41.954469]},"n185978810":{"id":"n185978810","loc":[-85.622787,41.954457]},"n185978811":{"id":"n185978811","loc":[-85.622612,41.954458]},"n185978813":{"id":"n185978813","loc":[-85.622368,41.954472]},"n1819790545":{"id":"n1819790545","loc":[-85.6240295,41.9548949]},"n1819790621":{"id":"n1819790621","loc":[-85.6235789,41.954855]},"n1819790664":{"id":"n1819790664","loc":[-85.6238363,41.9549507]},"n1819790683":{"id":"n1819790683","loc":[-85.6224727,41.9545921]},"n1819790730":{"id":"n1819790730","loc":[-85.6227527,41.9545795]},"n1819790740":{"id":"n1819790740","loc":[-85.6240402,41.9550784]},"n1819790831":{"id":"n1819790831","loc":[-85.624126,41.9549986]},"n1819790861":{"id":"n1819790861","loc":[-85.6231712,41.9546872]},"n1819790887":{"id":"n1819790887","loc":[-85.6242762,41.955206]},"n2168544739":{"id":"n2168544739","loc":[-85.6249102,41.952801]},"n2168544740":{"id":"n2168544740","loc":[-85.6251859,41.9527564]},"n2168544741":{"id":"n2168544741","loc":[-85.6255515,41.9527921]},"n2168544742":{"id":"n2168544742","loc":[-85.626001,41.9529481]},"n2168544743":{"id":"n2168544743","loc":[-85.6265284,41.9529838]},"n2168544744":{"id":"n2168544744","loc":[-85.626942,41.9528857]},"n2168544745":{"id":"n2168544745","loc":[-85.6270918,41.9526851]},"n2168544746":{"id":"n2168544746","loc":[-85.6272117,41.95244]},"n2168544747":{"id":"n2168544747","loc":[-85.6271578,41.952226]},"n2168544748":{"id":"n2168544748","loc":[-85.6270019,41.9519719]},"n2168544749":{"id":"n2168544749","loc":[-85.6268221,41.9518382]},"n2168544750":{"id":"n2168544750","loc":[-85.6265284,41.951807]},"n2168544751":{"id":"n2168544751","loc":[-85.6256534,41.9518516]},"n2168544752":{"id":"n2168544752","loc":[-85.6253477,41.9518338]},"n2168544753":{"id":"n2168544753","loc":[-85.6251139,41.9517669]},"n185955747":{"id":"n185955747","loc":[-85.620674,41.954709]},"n185960688":{"id":"n185960688","loc":[-85.621032,41.951913]},"n185972054":{"id":"n185972054","loc":[-85.6186728,41.9547335]},"n185978814":{"id":"n185978814","loc":[-85.6201708,41.9547403]},"n1819790532":{"id":"n1819790532","loc":[-85.6244908,41.9555731]},"n1819790536":{"id":"n1819790536","loc":[-85.6217925,41.9583135]},"n1819790538":{"id":"n1819790538","loc":[-85.6233954,41.9600014]},"n1819790539":{"id":"n1819790539","loc":[-85.6204611,41.9562117]},"n1819790546":{"id":"n1819790546","loc":[-85.6210898,41.9567657]},"n1819790548":{"id":"n1819790548","loc":[-85.6202465,41.9562237]},"n1819790550":{"id":"n1819790550","loc":[-85.6250165,41.9560677]},"n1819790551":{"id":"n1819790551","loc":[-85.6227946,41.9597023]},"n1819790553":{"id":"n1819790553","loc":[-85.6215726,41.9584571]},"n1819790556":{"id":"n1819790556","loc":[-85.6196306,41.9573002]},"n1819790557":{"id":"n1819790557","loc":[-85.6209503,41.9563109]},"n1819790558":{"id":"n1819790558","loc":[-85.6196939,41.9574085]},"n1819790561":{"id":"n1819790561","loc":[-85.621079,41.957751]},"n1819790562":{"id":"n1819790562","loc":[-85.6224255,41.9611417]},"n1819790565":{"id":"n1819790565","loc":[-85.6232506,41.9604841]},"n1819790566":{"id":"n1819790566","loc":[-85.6190835,41.9562909]},"n1819790567":{"id":"n1819790567","loc":[-85.622227,41.9593028]},"n1819790569":{"id":"n1819790569","loc":[-85.620976,41.9591039]},"n1819790571":{"id":"n1819790571","loc":[-85.6212078,41.9565303]},"n1819790572":{"id":"n1819790572","loc":[-85.6235306,41.9595102]},"n1819790581":{"id":"n1819790581","loc":[-85.6235563,41.9579351]},"n1819790584":{"id":"n1819790584","loc":[-85.6230371,41.9574598]},"n1819790586":{"id":"n1819790586","loc":[-85.6211748,41.9564272]},"n1819790588":{"id":"n1819790588","loc":[-85.6226508,41.9601086]},"n1819790591":{"id":"n1819790591","loc":[-85.6218032,41.9607468]},"n1819790593":{"id":"n1819790593","loc":[-85.6207915,41.9618735]},"n1819790596":{"id":"n1819790596","loc":[-85.6252955,41.9567858]},"n1819790598":{"id":"n1819790598","loc":[-85.6196618,41.9568939]},"n1819790600":{"id":"n1819790600","loc":[-85.6224416,41.9587084]},"n1819790602":{"id":"n1819790602","loc":[-85.6217442,41.9558641]},"n1819790603":{"id":"n1819790603","loc":[-85.6213355,41.9592116]},"n1819790604":{"id":"n1819790604","loc":[-85.622801,41.9573042]},"n1819790608":{"id":"n1819790608","loc":[-85.6199729,41.9574325]},"n1819790610":{"id":"n1819790610","loc":[-85.6195555,41.9557165]},"n1819790611":{"id":"n1819790611","loc":[-85.622978,41.9586007]},"n1819790613":{"id":"n1819790613","loc":[-85.6253963,41.9562636]},"n1819790614":{"id":"n1819790614","loc":[-85.6235252,41.9580342]},"n1819790616":{"id":"n1819790616","loc":[-85.6232988,41.9596305]},"n1819790617":{"id":"n1819790617","loc":[-85.6226776,41.9598732]},"n1819790619":{"id":"n1819790619","loc":[-85.625553,41.9561794]},"n1819790620":{"id":"n1819790620","loc":[-85.6235574,41.959231]},"n1819790624":{"id":"n1819790624","loc":[-85.6228429,41.9573726]},"n1819790626":{"id":"n1819790626","loc":[-85.6193785,41.9556766]},"n1819790628":{"id":"n1819790628","loc":[-85.620092,41.9554253]},"n1819790630":{"id":"n1819790630","loc":[-85.6226658,41.9604402]},"n1819790638":{"id":"n1819790638","loc":[-85.6219964,41.9602561]},"n1819790640":{"id":"n1819790640","loc":[-85.6232731,41.9599969]},"n1819790643":{"id":"n1819790643","loc":[-85.6247698,41.9568895]},"n1819790650":{"id":"n1819790650","loc":[-85.6216412,41.9550149]},"n1819790652":{"id":"n1819790652","loc":[-85.6224952,41.9603918]},"n1819790656":{"id":"n1819790656","loc":[-85.61918,41.9555649]},"n1819790661":{"id":"n1819790661","loc":[-85.6200169,41.955505]},"n1819790662":{"id":"n1819790662","loc":[-85.6217389,41.9563149]},"n1819790666":{"id":"n1819790666","loc":[-85.6229566,41.9598373]},"n1819790667":{"id":"n1819790667","loc":[-85.6209117,41.9609189]},"n1819790669":{"id":"n1819790669","loc":[-85.6252311,41.9562353]},"n1819790670":{"id":"n1819790670","loc":[-85.6209758,41.961868]},"n1819790672":{"id":"n1819790672","loc":[-85.6209557,41.9589078]},"n1819790673":{"id":"n1819790673","loc":[-85.6190352,41.9561393]},"n1819790675":{"id":"n1819790675","loc":[-85.6236432,41.9586685]},"n1819790676":{"id":"n1819790676","loc":[-85.6194901,41.9565389]},"n1819790678":{"id":"n1819790678","loc":[-85.6219266,41.9582417]},"n1819790680":{"id":"n1819790680","loc":[-85.6208258,41.9557211]},"n1819790681":{"id":"n1819790681","loc":[-85.6212024,41.9613212]},"n1819790682":{"id":"n1819790682","loc":[-85.624877,41.9559401]},"n1819790684":{"id":"n1819790684","loc":[-85.6206499,41.9583693]},"n1819790699":{"id":"n1819790699","loc":[-85.6215243,41.956279]},"n1819790701":{"id":"n1819790701","loc":[-85.6246625,41.9559321]},"n1819790703":{"id":"n1819790703","loc":[-85.6230478,41.9585089]},"n1819790708":{"id":"n1819790708","loc":[-85.6211102,41.9575402]},"n1819790710":{"id":"n1819790710","loc":[-85.6215082,41.9548468]},"n1819790711":{"id":"n1819790711","loc":[-85.6206552,41.9586007]},"n1819790713":{"id":"n1819790713","loc":[-85.6215404,41.9549705]},"n1819790715":{"id":"n1819790715","loc":[-85.6216906,41.955521]},"n1819790717":{"id":"n1819790717","loc":[-85.6215404,41.9547391]},"n1819790722":{"id":"n1819790722","loc":[-85.6219964,41.9599131]},"n1819790723":{"id":"n1819790723","loc":[-85.622286,41.9606989]},"n1819790725":{"id":"n1819790725","loc":[-85.6228439,41.9572005]},"n1819790727":{"id":"n1819790727","loc":[-85.6202518,41.9554458]},"n1819790728":{"id":"n1819790728","loc":[-85.623434,41.9575276]},"n1819790729":{"id":"n1819790729","loc":[-85.6234287,41.9568576]},"n1819790732":{"id":"n1819790732","loc":[-85.6229566,41.9571369]},"n1819790733":{"id":"n1819790733","loc":[-85.6225543,41.9590275]},"n1819790734":{"id":"n1819790734","loc":[-85.6232892,41.9583135]},"n1819790736":{"id":"n1819790736","loc":[-85.622977,41.9608551]},"n1819790737":{"id":"n1819790737","loc":[-85.624008,41.9569533]},"n1819790741":{"id":"n1819790741","loc":[-85.6212775,41.9608545]},"n1819790742":{"id":"n1819790742","loc":[-85.6231282,41.9569932]},"n1819790743":{"id":"n1819790743","loc":[-85.6224523,41.9591831]},"n1819790744":{"id":"n1819790744","loc":[-85.6210951,41.9610819]},"n1819790745":{"id":"n1819790745","loc":[-85.6220114,41.960544]},"n1819790755":{"id":"n1819790755","loc":[-85.6216369,41.9553854]},"n1819790757":{"id":"n1819790757","loc":[-85.6209986,41.9592709]},"n1819790758":{"id":"n1819790758","loc":[-85.6200437,41.9563468]},"n1819790764":{"id":"n1819790764","loc":[-85.6219363,41.9596823]},"n1819790765":{"id":"n1819790765","loc":[-85.6237612,41.9568496]},"n1819790769":{"id":"n1819790769","loc":[-85.6212389,41.9593433]},"n1819790771":{"id":"n1819790771","loc":[-85.6210726,41.9560123]},"n1819790772":{"id":"n1819790772","loc":[-85.6212711,41.9561838]},"n1819790776":{"id":"n1819790776","loc":[-85.6234437,41.9577795]},"n1819790777":{"id":"n1819790777","loc":[-85.6212502,41.9618599]},"n1819790783":{"id":"n1819790783","loc":[-85.6216895,41.9610585]},"n1819790784":{"id":"n1819790784","loc":[-85.6200115,41.9556367]},"n1819790785":{"id":"n1819790785","loc":[-85.6210576,41.9573002]},"n1819790786":{"id":"n1819790786","loc":[-85.621138,41.9576632]},"n1819790788":{"id":"n1819790788","loc":[-85.6207733,41.9578946]},"n1819790789":{"id":"n1819790789","loc":[-85.6200705,41.9571566]},"n1819790790":{"id":"n1819790790","loc":[-85.6245337,41.9558443]},"n1819790792":{"id":"n1819790792","loc":[-85.621932,41.9608066]},"n1819790793":{"id":"n1819790793","loc":[-85.6233578,41.9581385]},"n1819790794":{"id":"n1819790794","loc":[-85.6204557,41.9555136]},"n1819790797":{"id":"n1819790797","loc":[-85.6235038,41.9576074]},"n1819790800":{"id":"n1819790800","loc":[-85.6214438,41.9607508]},"n1819790801":{"id":"n1819790801","loc":[-85.623492,41.9602129]},"n1819790802":{"id":"n1819790802","loc":[-85.6216691,41.9546553]},"n1819790803":{"id":"n1819790803","loc":[-85.6231057,41.9586851]},"n1819790804":{"id":"n1819790804","loc":[-85.6209224,41.9578673]},"n1819790813":{"id":"n1819790813","loc":[-85.620092,41.9572962]},"n1819790814":{"id":"n1819790814","loc":[-85.6216691,41.9552218]},"n1819790816":{"id":"n1819790816","loc":[-85.6216144,41.9609668]},"n1819790818":{"id":"n1819790818","loc":[-85.6216906,41.9557324]},"n1819790820":{"id":"n1819790820","loc":[-85.6192069,41.9564186]},"n1819790823":{"id":"n1819790823","loc":[-85.6211155,41.9566027]},"n1819790825":{"id":"n1819790825","loc":[-85.6233106,41.9569294]},"n1819790839":{"id":"n1819790839","loc":[-85.625671,41.9564986]},"n1819790842":{"id":"n1819790842","loc":[-85.6235252,41.9567379]},"n1819790844":{"id":"n1819790844","loc":[-85.6253813,41.9566342]},"n1819790847":{"id":"n1819790847","loc":[-85.6200963,41.9567702]},"n1819790849":{"id":"n1819790849","loc":[-85.6238031,41.9587449]},"n1819790851":{"id":"n1819790851","loc":[-85.6234984,41.9584571]},"n1819790856":{"id":"n1819790856","loc":[-85.6242226,41.9570092]},"n1819790865":{"id":"n1819790865","loc":[-85.6200265,41.9569458]},"n1819790869":{"id":"n1819790869","loc":[-85.6230049,41.9601245]},"n1819790871":{"id":"n1819790871","loc":[-85.6190727,41.9558322]},"n1819790873":{"id":"n1819790873","loc":[-85.6217442,41.9550104]},"n1819790875":{"id":"n1819790875","loc":[-85.6208044,41.9587808]},"n1819790879":{"id":"n1819790879","loc":[-85.6198444,41.9574484]},"n1819790883":{"id":"n1819790883","loc":[-85.623713,41.9588719]},"n1819790885":{"id":"n1819790885","loc":[-85.6223289,41.9605075]},"n1819790889":{"id":"n1819790889","loc":[-85.6208044,41.9562437]},"n1819790893":{"id":"n1819790893","loc":[-85.6218183,41.9559684]},"n1819790906":{"id":"n1819790906","loc":[-85.6214052,41.958697]},"n1819790913":{"id":"n1819790913","loc":[-85.6209981,41.9609957]},"n1819790917":{"id":"n1819790917","loc":[-85.6216208,41.9604436]},"n1819790919":{"id":"n1819790919","loc":[-85.6209406,41.9616373]},"n1819790920":{"id":"n1819790920","loc":[-85.6221948,41.9583334]},"n1819790922":{"id":"n1819790922","loc":[-85.6216681,41.9615292]},"n1819790924":{"id":"n1819790924","loc":[-85.6210147,41.9570489]},"n1819790929":{"id":"n1819790929","loc":[-85.6193678,41.955521]},"w17964707":{"id":"w17964707","tags":{"highway":"residential","name":"11th Ave"},"nodes":["n185960682","n185960684","n185960686","n185960688","n185960690"]},"w201484345":{"id":"w201484345","tags":{"bridge":"yes","highway":"residential","name":"E Hoffman St"},"nodes":["n185978791","n185978795"]},"w201484348":{"id":"w201484348","tags":{"highway":"residential","name":"E Hoffman St"},"nodes":["n185978795","n185978800","n185978803","n185978806","n185978808","n185978810","n185978811","n185978813","n185955747","n185978814","n185972054","n185978817"]},"w170843845":{"id":"w170843845","tags":{"landuse":"reservoir","name":"Hoffman Pond","natural":"water"},"nodes":["n1819790732","n1819790742","n1819790825","n1819790729","n1819790842","n1819790765","n1819790737","n1819790856","n1819790643","n1819790596","n1819790844","n1819790839","n1819849190","n1819790619","n1819790613","n1819790669","n1819790550","n1819790682","n1819790701","n1819790790","n1819790532","n1819790887","n1819790740","n1819790831","n1819790545","n1819790664","n1819790621","n1819790861","n1819790730","n1819790683","n1819790802","n1819790717","n1819790710","n1819790713","n1819790650","n1819790873","n1819790814","n1819790755","n1819790715","n1819790818","n1819790602","n1819790893","n1819790662","n1819790699","n1819790772","n1819790771","n1819790680","n1819790794","n1819790727","n1819790628","n1819790661","n1819790784","n1819790610","n1819790626","n1819790929","n1819790656","n1819790871","n1819790673","n1819790566","n1819790820","n1819790676","n1819790598","n1819790556","n1819790558","n1819790879","n1819790608","n1819790813","n1819790789","n1819790865","n1819790847","n1819790758","n1819790548","n1819790539","n1819790889","n1819790557","n1819790586","n1819790571","n1819790823","n1819790546","n1819790924","n1819790785","n1819790708","n1819790786","n1819790561","n1819790804","n1819790788","n1819790684","n1819790711","n1819790875","n1819790672","n1819790569","n1819790757","n1819790769","n1819790603","n1819790906","n1819790553","n1819790536","n1819790678","n1819790920","n1819790600","n1819790733","n1819790743","n1819790567","n1819790764","n1819790722","n1819790638","n1819790917","n1819790800","n1819790741","n1819790667","n1819790913","n1819790744","n1819790816","n1819790591","n1819790745","n1819790885","n1819790652","n1819790588","n1819790617","n1819790551","n1819790666","n1819790869","n1819790630","n1819790723","n1819790792","n1819790783","n1819790681","n1819790919","n1819790593","n1819790670","n1819790777","n1819790922","n1819790562","n1819790736","n1819790565","n1819790801","n1819790538","n1819790640","n1819790616","n1819790572","n1819790620","n1819790883","n1819790849","n1819790675","n1819790851","n1819790803","n1819790611","n1819790703","n1819790734","n1819790793","n1819790614","n1819790581","n1819790776","n1819790797","n1819790728","n1819790584","n1819790624","n1819790604","n1819790725","n1819790732"]},"w206805240":{"id":"w206805240","tags":{"waterway":"river"},"nodes":["n2168544738","n2168544739","n2168544740","n2168544741","n2168544742","n2168544743","n2168544744","n2168544745","n2168544746","n2168544747","n2168544748","n2168544749","n2168544750","n2168544751","n2168544752","n2168544753","n1819848944"]},"n394490429":{"id":"n394490429","loc":[-85.643883,41.954365]},"n185953421":{"id":"n185953421","loc":[-85.641876,41.954946]},"n185953417":{"id":"n185953417","loc":[-85.6418306,41.9551597]},"n185977233":{"id":"n185977233","loc":[-85.642987,41.95486]},"n185977232":{"id":"n185977232","loc":[-85.642894,41.9547842]},"n1475293244":{"id":"n1475293244","loc":[-85.63974,41.9521543]},"n1819848890":{"id":"n1819848890","loc":[-85.6410004,41.9552822]},"n1819848965":{"id":"n1819848965","loc":[-85.6409795,41.9553892]},"n2189015846":{"id":"n2189015846","loc":[-85.6420457,41.9549528]},"n2189015849":{"id":"n2189015849","loc":[-85.6425867,41.9551392]},"n2189015852":{"id":"n2189015852","loc":[-85.6426877,41.9549771]},"n2199109816":{"id":"n2199109816","loc":[-85.6399215,41.9540925]},"n2199109818":{"id":"n2199109818","loc":[-85.6399182,41.9538236]},"n2199109820":{"id":"n2199109820","loc":[-85.6402201,41.9538216]},"n2199109822":{"id":"n2199109822","loc":[-85.640222,41.9539771]},"n2199109825":{"id":"n2199109825","loc":[-85.6402904,41.9539766]},"n2199109827":{"id":"n2199109827","loc":[-85.6402918,41.95409]},"n2199109829":{"id":"n2199109829","loc":[-85.6395845,41.9544626]},"n2199109831":{"id":"n2199109831","loc":[-85.6395792,41.9540671]},"n2199109833":{"id":"n2199109833","loc":[-85.6397173,41.9540661]},"n2199109835":{"id":"n2199109835","loc":[-85.6397226,41.9544616]},"n2199109837":{"id":"n2199109837","loc":[-85.6399641,41.9545058]},"n2199109839":{"id":"n2199109839","loc":[-85.6399637,41.9541859]},"n2199109841":{"id":"n2199109841","loc":[-85.6401098,41.9541858]},"n2199109843":{"id":"n2199109843","loc":[-85.64011,41.9543272]},"n2199109845":{"id":"n2199109845","loc":[-85.6400783,41.9543273]},"n2199109847":{"id":"n2199109847","loc":[-85.6400785,41.9545058]},"n2199109853":{"id":"n2199109853","loc":[-85.6396184,41.9554049]},"n2199109855":{"id":"n2199109855","loc":[-85.6396825,41.9553713]},"n185949745":{"id":"n185949745","loc":[-85.6442727,41.9553112]},"n185949748":{"id":"n185949748","loc":[-85.6448804,41.9555238]},"n185949755":{"id":"n185949755","loc":[-85.6420011,41.9603536]},"n185949763":{"id":"n185949763","loc":[-85.6408843,41.9555822]},"n185949765":{"id":"n185949765","loc":[-85.6414548,41.9557751]},"n185952158":{"id":"n185952158","loc":[-85.640066,41.956854]},"n185952160":{"id":"n185952160","loc":[-85.639848,41.957229]},"n185952161":{"id":"n185952161","loc":[-85.6396089,41.9576192]},"n185952163":{"id":"n185952163","loc":[-85.63892,41.957957]},"n185953413":{"id":"n185953413","loc":[-85.64162,41.955475]},"n185971651":{"id":"n185971651","loc":[-85.6440766,41.9543462]},"n185977234":{"id":"n185977234","loc":[-85.645044,41.955581]},"n394490395":{"id":"n394490395","loc":[-85.657336,41.936762]},"n394490396":{"id":"n394490396","loc":[-85.653896,41.936978]},"n394490397":{"id":"n394490397","loc":[-85.653732,41.937386]},"n394490398":{"id":"n394490398","loc":[-85.65182,41.937378]},"n394490399":{"id":"n394490399","loc":[-85.651843,41.938445]},"n394490400":{"id":"n394490400","loc":[-85.652536,41.938447]},"n394490401":{"id":"n394490401","loc":[-85.652533,41.938901]},"n394490402":{"id":"n394490402","loc":[-85.652084,41.9389]},"n394490403":{"id":"n394490403","loc":[-85.6521,41.939627]},"n394490404":{"id":"n394490404","loc":[-85.652301,41.939628]},"n394490405":{"id":"n394490405","loc":[-85.652302,41.939755]},"n394490406":{"id":"n394490406","loc":[-85.652783,41.939747]},"n394490407":{"id":"n394490407","loc":[-85.652835,41.94112]},"n394490408":{"id":"n394490408","loc":[-85.651968,41.941123]},"n394490409":{"id":"n394490409","loc":[-85.651983,41.941969]},"n394490410":{"id":"n394490410","loc":[-85.652908,41.941961]},"n394490411":{"id":"n394490411","loc":[-85.65292,41.94278]},"n394490412":{"id":"n394490412","loc":[-85.651698,41.942816]},"n394490413":{"id":"n394490413","loc":[-85.651509,41.942823]},"n394490414":{"id":"n394490414","loc":[-85.651272,41.942837]},"n394490415":{"id":"n394490415","loc":[-85.651272,41.943325]},"n394490416":{"id":"n394490416","loc":[-85.65122,41.944053]},"n394490417":{"id":"n394490417","loc":[-85.651193,41.944449]},"n394490418":{"id":"n394490418","loc":[-85.651088,41.944969]},"n394490419":{"id":"n394490419","loc":[-85.650949,41.945554]},"n394490420":{"id":"n394490420","loc":[-85.650907,41.945719]},"n394490421":{"id":"n394490421","loc":[-85.650808,41.946016]},"n394490422":{"id":"n394490422","loc":[-85.650712,41.946516]},"n394490423":{"id":"n394490423","loc":[-85.650493,41.947166]},"n394490424":{"id":"n394490424","loc":[-85.650626,41.947213]},"n394490425":{"id":"n394490425","loc":[-85.650201,41.948109]},"n394490426":{"id":"n394490426","loc":[-85.649868,41.948797]},"n394490427":{"id":"n394490427","loc":[-85.649669,41.949161]},"n394490428":{"id":"n394490428","loc":[-85.64659,41.954067]},"n394490430":{"id":"n394490430","loc":[-85.644034,41.95444]},"n394490431":{"id":"n394490431","loc":[-85.644248,41.954507]},"n394490432":{"id":"n394490432","loc":[-85.64491,41.954481]},"n394490433":{"id":"n394490433","loc":[-85.645213,41.954433]},"n394490434":{"id":"n394490434","loc":[-85.645426,41.954477]},"n394490435":{"id":"n394490435","loc":[-85.6458,41.954704]},"n394490436":{"id":"n394490436","loc":[-85.64605,41.954804]},"n394490437":{"id":"n394490437","loc":[-85.646125,41.954817]},"n394490438":{"id":"n394490438","loc":[-85.646002,41.954997]},"n394490439":{"id":"n394490439","loc":[-85.645764,41.955366]},"n394490440":{"id":"n394490440","loc":[-85.645525,41.955734]},"n394490441":{"id":"n394490441","loc":[-85.64443,41.957424]},"n394490442":{"id":"n394490442","loc":[-85.641712,41.961723]},"n394490443":{"id":"n394490443","loc":[-85.640747,41.963246]},"n394490444":{"id":"n394490444","loc":[-85.637803,41.967894]},"n394490445":{"id":"n394490445","loc":[-85.637673,41.967861]},"n394490446":{"id":"n394490446","loc":[-85.636637,41.969275]},"n394490447":{"id":"n394490447","loc":[-85.634923,41.969269]},"n394490448":{"id":"n394490448","loc":[-85.634893,41.968537]},"n394490449":{"id":"n394490449","loc":[-85.634544,41.96927]},"n394490450":{"id":"n394490450","loc":[-85.630835,41.969274]},"n394490451":{"id":"n394490451","loc":[-85.630834,41.968348]},"n394490452":{"id":"n394490452","loc":[-85.630857,41.968179]},"n394490453":{"id":"n394490453","loc":[-85.630924,41.968044]},"n394490454":{"id":"n394490454","loc":[-85.631004,41.967925]},"n394490455":{"id":"n394490455","loc":[-85.631143,41.967811]},"n394490456":{"id":"n394490456","loc":[-85.631311,41.967736]},"n394490457":{"id":"n394490457","loc":[-85.631595,41.967693]},"n394490458":{"id":"n394490458","loc":[-85.63325,41.967702]},"n394490459":{"id":"n394490459","loc":[-85.633247,41.967021]},"n394490460":{"id":"n394490460","loc":[-85.634858,41.967021]},"n394490461":{"id":"n394490461","loc":[-85.634865,41.967711]},"n394490462":{"id":"n394490462","loc":[-85.634884,41.968231]},"n394490463":{"id":"n394490463","loc":[-85.636559,41.963867]},"n394490464":{"id":"n394490464","loc":[-85.634832,41.963866]},"n394490465":{"id":"n394490465","loc":[-85.63481,41.961899]},"n394490466":{"id":"n394490466","loc":[-85.637219,41.961842]},"n394490467":{"id":"n394490467","loc":[-85.637837,41.960019]},"n394490468":{"id":"n394490468","loc":[-85.637459,41.960022]},"n394490469":{"id":"n394490469","loc":[-85.635295,41.959987]},"n394490470":{"id":"n394490470","loc":[-85.634783,41.959979]},"n394490471":{"id":"n394490471","loc":[-85.634776,41.959834]},"n394490472":{"id":"n394490472","loc":[-85.634767,41.959009]},"n394490473":{"id":"n394490473","loc":[-85.634763,41.958292]},"n394490474":{"id":"n394490474","loc":[-85.633346,41.958287]},"n394490475":{"id":"n394490475","loc":[-85.632128,41.9583]},"n394490476":{"id":"n394490476","loc":[-85.631414,41.958318]},"n394490477":{"id":"n394490477","loc":[-85.63137,41.959033]},"n394490478":{"id":"n394490478","loc":[-85.631325,41.959753]},"n394490479":{"id":"n394490479","loc":[-85.631494,41.95977]},"n394490480":{"id":"n394490480","loc":[-85.631456,41.960673]},"n394490481":{"id":"n394490481","loc":[-85.631421,41.961494]},"n394490482":{"id":"n394490482","loc":[-85.631404,41.961887]},"n394490483":{"id":"n394490483","loc":[-85.631401,41.961968]},"n394490484":{"id":"n394490484","loc":[-85.630962,41.961967]},"n394490485":{"id":"n394490485","loc":[-85.6299,41.961973]},"n394490486":{"id":"n394490486","loc":[-85.624929,41.962002]},"n394490487":{"id":"n394490487","loc":[-85.623333,41.961987]},"n394490488":{"id":"n394490488","loc":[-85.621894,41.963956]},"n394490489":{"id":"n394490489","loc":[-85.62131,41.963727]},"n394490490":{"id":"n394490490","loc":[-85.621216,41.963868]},"n394490491":{"id":"n394490491","loc":[-85.620356,41.965119]},"n394490492":{"id":"n394490492","loc":[-85.620848,41.965341]},"n394490493":{"id":"n394490493","loc":[-85.620684,41.965558]},"n394490494":{"id":"n394490494","loc":[-85.620621,41.965658]},"n394490495":{"id":"n394490495","loc":[-85.618165,41.965759]},"n394490496":{"id":"n394490496","loc":[-85.618071,41.965759]},"n394490497":{"id":"n394490497","loc":[-85.617986,41.965759]},"n394490498":{"id":"n394490498","loc":[-85.605673,41.965764]},"n394490499":{"id":"n394490499","loc":[-85.605668,41.963548]},"n394490500":{"id":"n394490500","loc":[-85.605664,41.962094]},"n394490501":{"id":"n394490501","loc":[-85.595828,41.962159]},"n394490502":{"id":"n394490502","loc":[-85.587869,41.962169]},"n394490503":{"id":"n394490503","loc":[-85.586289,41.962179]},"n394490504":{"id":"n394490504","loc":[-85.583774,41.962178]},"n394490505":{"id":"n394490505","loc":[-85.583774,41.961789]},"n394490506":{"id":"n394490506","loc":[-85.581303,41.961783]},"n394490507":{"id":"n394490507","loc":[-85.581304,41.961616]},"n394490508":{"id":"n394490508","loc":[-85.581292,41.961616]},"n394490509":{"id":"n394490509","loc":[-85.581247,41.959244]},"n394490510":{"id":"n394490510","loc":[-85.581245,41.958394]},"n394490511":{"id":"n394490511","loc":[-85.581276,41.958372]},"n394490512":{"id":"n394490512","loc":[-85.581302,41.958353]},"n394490513":{"id":"n394490513","loc":[-85.581376,41.9583]},"n394490514":{"id":"n394490514","loc":[-85.582256,41.957663]},"n394490515":{"id":"n394490515","loc":[-85.585299,41.955483]},"n394490516":{"id":"n394490516","loc":[-85.585588,41.955331]},"n394490517":{"id":"n394490517","loc":[-85.586053,41.955163]},"n394490518":{"id":"n394490518","loc":[-85.58632,41.955076]},"n394490519":{"id":"n394490519","loc":[-85.586478,41.955025]},"n394490520":{"id":"n394490520","loc":[-85.58692,41.954947]},"n394490521":{"id":"n394490521","loc":[-85.587327,41.954914]},"n394490522":{"id":"n394490522","loc":[-85.587345,41.954913]},"n394490523":{"id":"n394490523","loc":[-85.587358,41.954913]},"n394490524":{"id":"n394490524","loc":[-85.58963,41.954877]},"n394490525":{"id":"n394490525","loc":[-85.591077,41.954865]},"n394490526":{"id":"n394490526","loc":[-85.594824,41.954843]},"n394490527":{"id":"n394490527","loc":[-85.594804,41.95331]},"n394490528":{"id":"n394490528","loc":[-85.599336,41.95331]},"n394490529":{"id":"n394490529","loc":[-85.599336,41.954825]},"n394490530":{"id":"n394490530","loc":[-85.597828,41.954839]},"n394490531":{"id":"n394490531","loc":[-85.597833,41.95614]},"n394490532":{"id":"n394490532","loc":[-85.596586,41.956151]},"n394490533":{"id":"n394490533","loc":[-85.596586,41.956394]},"n394490534":{"id":"n394490534","loc":[-85.595933,41.956394]},"n394490535":{"id":"n394490535","loc":[-85.595933,41.958176]},"n394490536":{"id":"n394490536","loc":[-85.597635,41.958179]},"n394490537":{"id":"n394490537","loc":[-85.597717,41.958177]},"n394490538":{"id":"n394490538","loc":[-85.601671,41.958194]},"n394490539":{"id":"n394490539","loc":[-85.605619,41.958194]},"n394490540":{"id":"n394490540","loc":[-85.608054,41.958187]},"n394490542":{"id":"n394490542","loc":[-85.6080762,41.9547864]},"n394490545":{"id":"n394490545","loc":[-85.6104354,41.9548263]},"n394490546":{"id":"n394490546","loc":[-85.610274,41.951106]},"n394490547":{"id":"n394490547","loc":[-85.610278,41.950829]},"n394490548":{"id":"n394490548","loc":[-85.610309,41.948377]},"n394490549":{"id":"n394490549","loc":[-85.610314,41.947986]},"n394490550":{"id":"n394490550","loc":[-85.610464,41.947985]},"n394490551":{"id":"n394490551","loc":[-85.610447,41.947468]},"n394490552":{"id":"n394490552","loc":[-85.612469,41.947471]},"n394490553":{"id":"n394490553","loc":[-85.612494,41.945576]},"n394490554":{"id":"n394490554","loc":[-85.610292,41.94558]},"n394490555":{"id":"n394490555","loc":[-85.608412,41.945625]},"n394490556":{"id":"n394490556","loc":[-85.608412,41.943036]},"n394490557":{"id":"n394490557","loc":[-85.608702,41.943087]},"n394490558":{"id":"n394490558","loc":[-85.609196,41.943224]},"n394490559":{"id":"n394490559","loc":[-85.609571,41.943263]},"n394490560":{"id":"n394490560","loc":[-85.610116,41.943295]},"n394490561":{"id":"n394490561","loc":[-85.610273,41.943275]},"n394490562":{"id":"n394490562","loc":[-85.611339,41.943075]},"n394490563":{"id":"n394490563","loc":[-85.611575,41.942997]},"n394490564":{"id":"n394490564","loc":[-85.611847,41.942849]},"n394490565":{"id":"n394490565","loc":[-85.612164,41.942568]},"n394490566":{"id":"n394490566","loc":[-85.612341,41.942529]},"n394490567":{"id":"n394490567","loc":[-85.612562,41.942524]},"n394490568":{"id":"n394490568","loc":[-85.612768,41.942546]},"n394490569":{"id":"n394490569","loc":[-85.612938,41.942633]},"n394490570":{"id":"n394490570","loc":[-85.6131,41.942782]},"n394490571":{"id":"n394490571","loc":[-85.613299,41.942919]},"n394490572":{"id":"n394490572","loc":[-85.613498,41.942996]},"n394490573":{"id":"n394490573","loc":[-85.614698,41.942842]},"n394490574":{"id":"n394490574","loc":[-85.615288,41.942698]},"n394490575":{"id":"n394490575","loc":[-85.616054,41.942693]},"n394490576":{"id":"n394490576","loc":[-85.61603,41.942175]},"n394490577":{"id":"n394490577","loc":[-85.616004,41.941741]},"n394490578":{"id":"n394490578","loc":[-85.615994,41.940156]},"n394490579":{"id":"n394490579","loc":[-85.615144,41.940159]},"n394490580":{"id":"n394490580","loc":[-85.614915,41.940161]},"n394490582":{"id":"n394490582","loc":[-85.614875,41.938532]},"n394490583":{"id":"n394490583","loc":[-85.616167,41.938787]},"n394490585":{"id":"n394490585","loc":[-85.616176,41.938589]},"n394490586":{"id":"n394490586","loc":[-85.614537,41.938282]},"n394490588":{"id":"n394490588","loc":[-85.610141,41.937459]},"n394490589":{"id":"n394490589","loc":[-85.610172,41.937298]},"n394490590":{"id":"n394490590","loc":[-85.609918,41.935495]},"n394490592":{"id":"n394490592","loc":[-85.610092,41.935451]},"n394490594":{"id":"n394490594","loc":[-85.610681,41.935247]},"n394490595":{"id":"n394490595","loc":[-85.611446,41.934955]},"n394490596":{"id":"n394490596","loc":[-85.612057,41.934696]},"n394490598":{"id":"n394490598","loc":[-85.613256,41.934084]},"n394490599":{"id":"n394490599","loc":[-85.613948,41.933682]},"n394490601":{"id":"n394490601","loc":[-85.61436,41.933417]},"n394490602":{"id":"n394490602","loc":[-85.614638,41.933212]},"n394490604":{"id":"n394490604","loc":[-85.615249,41.9332]},"n394490605":{"id":"n394490605","loc":[-85.618218,41.933223]},"n394490607":{"id":"n394490607","loc":[-85.618241,41.933479]},"n394490608":{"id":"n394490608","loc":[-85.618257,41.93365]},"n394490609":{"id":"n394490609","loc":[-85.618298,41.935067]},"n394490611":{"id":"n394490611","loc":[-85.619791,41.935067]},"n394490612":{"id":"n394490612","loc":[-85.619794,41.933301]},"n394490613":{"id":"n394490613","loc":[-85.619795,41.932692]},"n394490614":{"id":"n394490614","loc":[-85.619729,41.929517]},"n394490615":{"id":"n394490615","loc":[-85.619801,41.929305]},"n394490616":{"id":"n394490616","loc":[-85.619809,41.927391]},"n394490617":{"id":"n394490617","loc":[-85.620883,41.927378]},"n394490618":{"id":"n394490618","loc":[-85.620988,41.927368]},"n394490619":{"id":"n394490619","loc":[-85.621076,41.927368]},"n394490620":{"id":"n394490620","loc":[-85.621156,41.927376]},"n394490621":{"id":"n394490621","loc":[-85.621685,41.92737]},"n394490622":{"id":"n394490622","loc":[-85.624716,41.927359]},"n394490623":{"id":"n394490623","loc":[-85.625308,41.92737]},"n394490624":{"id":"n394490624","loc":[-85.625655,41.927377]},"n394490625":{"id":"n394490625","loc":[-85.625093,41.925591]},"n394490626":{"id":"n394490626","loc":[-85.625174,41.92559]},"n394490627":{"id":"n394490627","loc":[-85.625249,41.925597]},"n394490628":{"id":"n394490628","loc":[-85.625532,41.925604]},"n394490629":{"id":"n394490629","loc":[-85.625761,41.925597]},"n394490630":{"id":"n394490630","loc":[-85.625955,41.926153]},"n394490631":{"id":"n394490631","loc":[-85.626209,41.926155]},"n394490632":{"id":"n394490632","loc":[-85.627757,41.926151]},"n394490633":{"id":"n394490633","loc":[-85.627825,41.926298]},"n394490634":{"id":"n394490634","loc":[-85.627994,41.926315]},"n394490635":{"id":"n394490635","loc":[-85.628049,41.927196]},"n394490636":{"id":"n394490636","loc":[-85.62949,41.927221]},"n394490637":{"id":"n394490637","loc":[-85.629602,41.927277]},"n394490638":{"id":"n394490638","loc":[-85.6297102,41.9273279]},"n394490639":{"id":"n394490639","loc":[-85.630958,41.927398]},"n394490699":{"id":"n394490699","loc":[-85.632741,41.927388]},"n394490700":{"id":"n394490700","loc":[-85.632997,41.927391]},"n394490701":{"id":"n394490701","loc":[-85.633149,41.927393]},"n394490702":{"id":"n394490702","loc":[-85.633334,41.927393]},"n394490703":{"id":"n394490703","loc":[-85.633468,41.927561]},"n394490704":{"id":"n394490704","loc":[-85.633563,41.927755]},"n394490705":{"id":"n394490705","loc":[-85.633662,41.928192]},"n394490706":{"id":"n394490706","loc":[-85.633679,41.928807]},"n394490707":{"id":"n394490707","loc":[-85.633687,41.929107]},"n394490708":{"id":"n394490708","loc":[-85.633927,41.929109]},"n394490709":{"id":"n394490709","loc":[-85.634126,41.929111]},"n394490710":{"id":"n394490710","loc":[-85.634207,41.92911]},"n394490711":{"id":"n394490711","loc":[-85.634323,41.929111]},"n394490712":{"id":"n394490712","loc":[-85.636712,41.929128]},"n394490713":{"id":"n394490713","loc":[-85.63808,41.9291]},"n394490714":{"id":"n394490714","loc":[-85.639213,41.929088]},"n394490715":{"id":"n394490715","loc":[-85.639189,41.92852]},"n394490716":{"id":"n394490716","loc":[-85.639204,41.925488]},"n394490717":{"id":"n394490717","loc":[-85.644204,41.925452]},"n394490718":{"id":"n394490718","loc":[-85.651425,41.925406]},"n394490719":{"id":"n394490719","loc":[-85.651449,41.926321]},"n394490720":{"id":"n394490720","loc":[-85.651451,41.926969]},"n394490721":{"id":"n394490721","loc":[-85.651458,41.928052]},"n394490722":{"id":"n394490722","loc":[-85.651446,41.928892]},"n394490723":{"id":"n394490723","loc":[-85.651456,41.929447]},"n394490724":{"id":"n394490724","loc":[-85.651707,41.929454]},"n394490725":{"id":"n394490725","loc":[-85.652369,41.929473]},"n394490726":{"id":"n394490726","loc":[-85.6525,41.929452]},"n394490727":{"id":"n394490727","loc":[-85.654066,41.92946]},"n394490728":{"id":"n394490728","loc":[-85.654816,41.92946]},"n394490729":{"id":"n394490729","loc":[-85.654816,41.930337]},"n394490730":{"id":"n394490730","loc":[-85.654587,41.930337]},"n394490731":{"id":"n394490731","loc":[-85.654548,41.931072]},"n394490732":{"id":"n394490732","loc":[-85.654538,41.931701]},"n394490733":{"id":"n394490733","loc":[-85.654898,41.931689]},"n394490734":{"id":"n394490734","loc":[-85.654898,41.932505]},"n394490735":{"id":"n394490735","loc":[-85.654854,41.932514]},"n394490736":{"id":"n394490736","loc":[-85.655497,41.932499]},"n394490737":{"id":"n394490737","loc":[-85.656405,41.932493]},"n394490738":{"id":"n394490738","loc":[-85.656422,41.933416]},"n394490739":{"id":"n394490739","loc":[-85.657322,41.933438]},"n1475293233":{"id":"n1475293233","loc":[-85.6385522,41.9585167]},"n1475293242":{"id":"n1475293242","loc":[-85.64609,41.9540815]},"n1475293249":{"id":"n1475293249","loc":[-85.6358079,41.9692721]},"n1475293256":{"id":"n1475293256","loc":[-85.6387369,41.9581583]},"n1475293259":{"id":"n1475293259","loc":[-85.6455882,41.9541138]},"n1475293266":{"id":"n1475293266","loc":[-85.6451008,41.9541821]},"n1819800253":{"id":"n1819800253","loc":[-85.6134286,41.9429692]},"n2114807558":{"id":"n2114807558","loc":[-85.6365609,41.963866],"tags":{"railway":"level_crossing"}},"n2189015728":{"id":"n2189015728","loc":[-85.6383956,41.9590576]},"n2189015838":{"id":"n2189015838","loc":[-85.6435144,41.9563705]},"n2189015842":{"id":"n2189015842","loc":[-85.6415782,41.9557035]},"n2189015855":{"id":"n2189015855","loc":[-85.6440829,41.9554577]},"n2199109849":{"id":"n2199109849","loc":[-85.6393434,41.9565591]},"n2199109851":{"id":"n2199109851","loc":[-85.6393208,41.9565002]},"n2199109857":{"id":"n2199109857","loc":[-85.6401986,41.955545]},"n2199109859":{"id":"n2199109859","loc":[-85.6402362,41.955587]},"n2199109861":{"id":"n2199109861","loc":[-85.6395958,41.9565675]},"n2199109863":{"id":"n2199109863","loc":[-85.639528,41.9566011]},"w209717053":{"id":"w209717053","tags":{"area":"yes","building":"yes"},"nodes":["n2199109829","n2199109831","n2199109833","n2199109835","n2199109829"]},"w17966415":{"id":"w17966415","tags":{"access":"private","highway":"service","name":"Manufacturing Way"},"nodes":["n185971642","n185977232","n185977233","n185949745","n185949748","n185977234"]},"w209717054":{"id":"w209717054","tags":{"area":"yes","building":"yes"},"nodes":["n2199109837","n2199109839","n2199109841","n2199109843","n2199109845","n2199109847","n2199109837"]},"w208627214":{"id":"w208627214","tags":{"highway":"service"},"nodes":["n185949755","n2189015728","n1475293233","n1475293256","n185952163","n185952161","n185952160","n185952158","n185949763","n1819848965","n1819848890","n185952156"]},"w17963817":{"id":"w17963817","tags":{"access":"private","highway":"service"},"nodes":["n185949765","n185953413","n185953417","n185953421","n185953423"]},"w34369809":{"id":"w34369809","tags":{"admin_level":"8","boundary":"administrative","landuse":"residential"},"nodes":["n394490395","n394490396","n394490397","n394490398","n394490399","n394490400","n394490401","n394490402","n394490403","n394490404","n394490405","n394490406","n394490407","n394490408","n394490409","n394490410","n394490411","n394490412","n394490413","n394490414","n394490415","n394490416","n394490417","n394490418","n394490419","n394490420","n394490421","n394490422","n394490423","n394490424","n394490425","n394490426","n394490427","n394490428","n1475293242","n1475293259","n1475293266","n394490429","n394490430","n394490431","n394490432","n394490433","n394490434","n394490435","n394490436","n394490437","n394490438","n394490439","n394490440","n394490441","n394490442","n394490443","n394490444","n394490445","n394490446","n1475293249","n394490447","n394490448","n394490449","n394490450","n394490451","n394490452","n394490453","n394490454","n394490455","n394490456","n394490457","n394490458","n394490459","n394490460","n394490461","n394490462","n2114807558","n394490463","n1475293226","n394490464","n394490465","n394490466","n394490467","n394490468","n394490469","n394490470","n394490471","n394490472","n394490473","n394490474","n394490475","n394490476","n394490477","n394490478","n394490479","n394490480","n394490481","n394490482","n394490483","n394490484","n394490485","n394490486","n394490487","n394490488","n394490489","n394490490","n394490491","n394490492","n394490493","n394490494","n394490495","n394490496","n394490497","n394490498","n394490499","n394490500","n394490501","n394490502","n394490503","n394490504","n394490505","n394490506","n394490507","n394490508","n394490509","n394490510","n394490511","n394490512","n394490513","n394490514","n394490515","n394490516","n394490517","n394490518","n394490519","n394490520","n394490521","n394490522","n394490523","n394490524","n394490525","n394490526","n394490527","n394490528","n394490529","n394490530","n394490531","n394490532","n394490533","n394490534","n394490535","n394490536","n394490537","n394490538","n394490539","n394490540","n394490542","n394490545","n394490546","n394490547","n394490548","n394490549","n394490550","n394490551","n394490552","n394490553","n394490554","n394490555","n394490556","n394490557","n394490558","n394490559","n394490560","n394490561","n394490562","n394490563","n394490564","n394490565","n394490566","n394490567","n394490568","n394490569","n394490570","n394490571","n1819800253","n394490572","n394490573","n394490574","n394490575","n394490576","n394490577","n394490578","n394490579","n394490580","n394490582","n394490583","n394490585","n394490586","n394490588","n394490589","n394490590","n394490592","n394490594","n394490595","n394490596","n394490598","n394490599","n394490601","n394490602","n394490604","n394490605","n394490607","n394490608","n394490609","n394490611","n394490612","n394490613","n394490614","n394490615","n394490616","n394490617","n394490618","n394490619","n394490620","n394490621","n394490622","n394490623","n394490624","n394490625","n394490626","n394490627","n394490628","n394490629","n394490630","n394490631","n394490632","n394490633","n394490634","n394490635","n394490636","n394490637","n394490638","n394490639","n394490699","n394490700","n394490701","n394490702","n394490703","n394490704","n394490705","n394490706","n394490707","n394490708","n394490709","n394490710","n394490711","n394490712","n394490713","n394490714","n394490715","n394490716","n394490717","n394490718","n394490719","n394490720","n394490721","n394490722","n394490723","n394490724","n394490725","n394490726","n394490727","n394490728","n394490729","n394490730","n394490731","n394490732","n394490733","n394490734","n394490735","n394490736","n394490737","n394490738","n394490739","n394490395"]},"w208627221":{"id":"w208627221","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189015838","n2189015842","n2189015846","n2189015849","n2189015852","n2189015855","n2189015838"]},"w209717052":{"id":"w209717052","tags":{"area":"yes","building":"yes"},"nodes":["n2199109816","n2199109818","n2199109820","n2199109822","n2199109825","n2199109827","n2199109816"]},"w134151784":{"id":"w134151784","tags":{"bridge":"yes","highway":"residential","name":"W Hoffman St"},"nodes":["n185971648","n185971651"]},"w209717055":{"id":"w209717055","tags":{"area":"yes","landuse":"basin"},"nodes":["n2199109849","n2199109851","n2199109853","n2199109855","n2199109857","n2199109859","n2199109861","n2199109863","n2199109849"]},"w17967763":{"id":"w17967763","tags":{"highway":"residential","name":"Rock River Ave"},"nodes":["n1475293244","n185982166","n185975067","n185971637"]},"r134949":{"id":"r134949","tags":{"admin_level":"8","border_type":"city","boundary":"administrative","name":"Three Rivers","place":"city","type":"boundary"},"members":[{"id":"w34369809","type":"way","role":"outer"},{"id":"w34369821","type":"way","role":"outer"},{"id":"w34369822","type":"way","role":"outer"},{"id":"w34369823","type":"way","role":"outer"},{"id":"w34369824","type":"way","role":"outer"},{"id":"w34369825","type":"way","role":"outer"},{"id":"w34369826","type":"way","role":"outer"},{"id":"w34369810","type":"way","role":"inner"},{"id":"w34369811","type":"way","role":"inner"},{"id":"w34369812","type":"way","role":"inner"},{"id":"w34367079","type":"way","role":"inner"},{"id":"w34369814","type":"way","role":"inner"},{"id":"w34367080","type":"way","role":"inner"},{"id":"w34369815","type":"way","role":"inner"},{"id":"w34369820","type":"way","role":"inner"}]},"n1819848881":{"id":"n1819848881","loc":[-85.638562,41.9569965]},"n1819848947":{"id":"n1819848947","loc":[-85.6384348,41.9576565]},"n1819849044":{"id":"n1819849044","loc":[-85.6385749,41.9573345]},"n2114807547":{"id":"n2114807547","loc":[-85.6384626,41.9583756]},"n2114807564":{"id":"n2114807564","loc":[-85.638535,41.9581283]},"n2189015691":{"id":"n2189015691","loc":[-85.6435584,41.9565243]},"n2189015696":{"id":"n2189015696","loc":[-85.6435805,41.9566049]},"n2189015722":{"id":"n2189015722","loc":[-85.6435035,41.9567438]},"n2189015744":{"id":"n2189015744","loc":[-85.6437991,41.9569582]},"n2189015747":{"id":"n2189015747","loc":[-85.6433042,41.9567742]},"n2189015750":{"id":"n2189015750","loc":[-85.6433827,41.9566844]},"n2189015753":{"id":"n2189015753","loc":[-85.6430447,41.9565588]},"n2189015756":{"id":"n2189015756","loc":[-85.6431111,41.956451]},"n2189015759":{"id":"n2189015759","loc":[-85.6420247,41.956083]},"n2189015760":{"id":"n2189015760","loc":[-85.6419945,41.9561369]},"n2189015764":{"id":"n2189015764","loc":[-85.6413729,41.9558945]},"n2189015766":{"id":"n2189015766","loc":[-85.6412884,41.9560606]},"n2189015770":{"id":"n2189015770","loc":[-85.6411798,41.9560112]},"n2189015771":{"id":"n2189015771","loc":[-85.6410651,41.9562132]},"n2189015774":{"id":"n2189015774","loc":[-85.6409504,41.9561728]},"n2189015778":{"id":"n2189015778","loc":[-85.6407996,41.9564241]},"n2189015781":{"id":"n2189015781","loc":[-85.6406889,41.9563892]},"n2189015785":{"id":"n2189015785","loc":[-85.6404857,41.9567024]},"n2189015789":{"id":"n2189015789","loc":[-85.6406909,41.9567877]},"n2189015793":{"id":"n2189015793","loc":[-85.6405642,41.9570165]},"n2189015796":{"id":"n2189015796","loc":[-85.6415359,41.9573711]},"n2189015800":{"id":"n2189015800","loc":[-85.6411738,41.9579501]},"n2189015804":{"id":"n2189015804","loc":[-85.6411119,41.957921]},"n2189015808":{"id":"n2189015808","loc":[-85.6403186,41.9591751]},"n2189015909":{"id":"n2189015909","loc":[-85.6389293,41.9564636]},"n2189015926":{"id":"n2189015926","loc":[-85.6385431,41.9564617]},"n2189015929":{"id":"n2189015929","loc":[-85.6385457,41.9561823]},"n2189015932":{"id":"n2189015932","loc":[-85.6389319,41.9561843]},"n2199109865":{"id":"n2199109865","loc":[-85.6400768,41.956776]},"n2199109867":{"id":"n2199109867","loc":[-85.639902,41.9567153]},"n2199109869":{"id":"n2199109869","loc":[-85.640004,41.956553]},"n2199109871":{"id":"n2199109871","loc":[-85.6401788,41.9566137]},"n2199109873":{"id":"n2199109873","loc":[-85.6399316,41.9564506],"tags":{"man_made":"water_tower"}},"n2199109876":{"id":"n2199109876","loc":[-85.6397689,41.9572354]},"n2199109878":{"id":"n2199109878","loc":[-85.6399229,41.9569826]},"n2199109880":{"id":"n2199109880","loc":[-85.639706,41.9569095]},"n2199109882":{"id":"n2199109882","loc":[-85.639552,41.9571623]},"n2199109884":{"id":"n2199109884","loc":[-85.6391028,41.9569517]},"n2199109886":{"id":"n2199109886","loc":[-85.6392876,41.956646]},"n2199109888":{"id":"n2199109888","loc":[-85.639484,41.9567117]},"n2199109889":{"id":"n2199109889","loc":[-85.6394322,41.9567973]},"n2199109890":{"id":"n2199109890","loc":[-85.6393718,41.9567771]},"n2199109891":{"id":"n2199109891","loc":[-85.6392387,41.9569972]},"n1819848900":{"id":"n1819848900","loc":[-85.638281,41.9576578]},"n1819848978":{"id":"n1819848978","loc":[-85.6377186,41.9580867]},"n1819849039":{"id":"n1819849039","loc":[-85.6384217,41.9573405]},"n1819849050":{"id":"n1819849050","loc":[-85.6377011,41.9570042]},"n1819849088":{"id":"n1819849088","loc":[-85.6382879,41.9580817]},"n2114807549":{"id":"n2114807549","loc":[-85.6362551,41.96473]},"n2114807587":{"id":"n2114807587","loc":[-85.6368694,41.9629829]},"n2189015725":{"id":"n2189015725","loc":[-85.644156,41.9569753]},"n2189015741":{"id":"n2189015741","loc":[-85.6419825,41.9597632]},"w208627217":{"id":"w208627217","tags":{"area":"yes","building":"yes"},"nodes":["n2189015741","n2189015744","n2189015747","n2189015750","n2189015753","n2189015756","n2189015759","n2189015760","n2189015764","n2189015766","n2189015770","n2189015771","n2189015774","n2189015778","n2189015781","n2189015785","n2189015789","n2189015793","n2189015796","n2189015800","n2189015804","n2189015808","n2189015741"]},"w208627212":{"id":"w208627212","tags":{"highway":"service"},"nodes":["n2189015691","n2189015696","n2189015722","n2189015725"]},"w209717057":{"id":"w209717057","tags":{"area":"yes","building":"yes"},"nodes":["n2199109876","n2199109878","n2199109880","n2199109882","n2199109876"]},"w209717056":{"id":"w209717056","tags":{"area":"yes","building":"yes"},"nodes":["n2199109865","n2199109867","n2199109869","n2199109871","n2199109865"]},"w208627231":{"id":"w208627231","tags":{"area":"yes","building":"yes"},"nodes":["n2189015909","n2189015926","n2189015929","n2189015932","n2189015909"]},"w170848326":{"id":"w170848326","tags":{"building":"yes"},"nodes":["n1819848881","n1819849050","n1819848978","n1819849088","n1819848900","n1819848947","n1819849039","n1819849044","n1819848881"]},"w17963182":{"id":"w17963182","tags":{"highway":"service"},"nodes":["n185949763","n185949765","n2189015691","n185949745"]},"w201484340":{"id":"w201484340","tags":{"railway":"rail","service":"siding"},"nodes":["n2114807565","n2114807564","n2114807547","n2114807587","n2114807558","n2114807549","n2114807593"]},"w209717058":{"id":"w209717058","tags":{"area":"yes","building":"yes"},"nodes":["n2199109884","n2199109886","n2199109888","n2199109889","n2199109890","n2199109891","n2199109884"]},"n185954650":{"id":"n185954650","loc":[-85.627331,41.957439]},"n185966949":{"id":"n185966949","loc":[-85.626868,41.957314]},"n185989335":{"id":"n185989335","loc":[-85.62529,41.958568]},"n185989337":{"id":"n185989337","loc":[-85.624962,41.958453]},"n185989339":{"id":"n185989339","loc":[-85.624832,41.958399]},"n185989340":{"id":"n185989340","loc":[-85.624707,41.958325]},"n185989342":{"id":"n185989342","loc":[-85.624636,41.958251]},"n185989345":{"id":"n185989345","loc":[-85.624578,41.95818]},"n185989347":{"id":"n185989347","loc":[-85.624533,41.958099]},"n185989349":{"id":"n185989349","loc":[-85.624507,41.957985]},"n185989351":{"id":"n185989351","loc":[-85.624495,41.957807]},"n185989353":{"id":"n185989353","loc":[-85.624514,41.957663]},"n185989354":{"id":"n185989354","loc":[-85.624577,41.957593]},"n185989356":{"id":"n185989356","loc":[-85.624685,41.95754]},"n185989357":{"id":"n185989357","loc":[-85.624802,41.957523]},"n185989359":{"id":"n185989359","loc":[-85.624996,41.957524]},"n185989361":{"id":"n185989361","loc":[-85.625409,41.957515]},"n185989364":{"id":"n185989364","loc":[-85.625634,41.957496]},"n185989367":{"id":"n185989367","loc":[-85.625832,41.957453]},"n185989368":{"id":"n185989368","loc":[-85.626044,41.957394]},"n354031352":{"id":"n354031352","loc":[-85.6252778,41.9586111],"tags":{"amenity":"place_of_worship","denomination":"baptist","name":"First Baptist Church","religion":"christian"}},"n2199109892":{"id":"n2199109892","loc":[-85.6261578,41.9589963]},"n2199109893":{"id":"n2199109893","loc":[-85.6263191,41.9586865]},"n2199109894":{"id":"n2199109894","loc":[-85.6261186,41.9586288]},"n2199109895":{"id":"n2199109895","loc":[-85.6260644,41.9587329]},"n2199109896":{"id":"n2199109896","loc":[-85.6261547,41.9587589]},"n2199109898":{"id":"n2199109898","loc":[-85.6260476,41.9589646]},"n185966951":{"id":"n185966951","loc":[-85.628404,41.957438]},"w17965351":{"id":"w17965351","tags":{"highway":"residential","name":"Flower Street"},"nodes":["n185966948","n185966949","n185954650","n185966951","n185966953","n185966955","n185966957"]},"w17967809":{"id":"w17967809","tags":{"highway":"residential","name":"Azaleamum Drive"},"nodes":["n185982197","n185989335","n185989337","n185989339","n185989340","n185989342","n185989345","n185989347","n185989349","n185989351","n185989353","n185989354","n185989356","n185989357","n185989359","n185989361","n185989364","n185989367","n185989368","n185982196"]},"w209717059":{"id":"w209717059","tags":{"area":"yes","building":"yes"},"nodes":["n2199109892","n2199109893","n2199109894","n2199109895","n2199109896","n2199109898","n2199109892"]},"n185961390":{"id":"n185961390","loc":[-85.63137,41.959033]},"n185961393":{"id":"n185961393","loc":[-85.634315,41.959017]},"w17966214":{"id":"w17966214","tags":{"highway":"residential","name":"East Adams Street"},"nodes":["n185975351","n185967434","n185968108"]},"w17964793":{"id":"w17964793","tags":{"highway":"residential","name":"Morris Ave"},"nodes":["n185961389","n185961390","n185961391","n185961393","n185961396"]},"n185952166":{"id":"n185952166","loc":[-85.638174,41.95831]},"n2114807552":{"id":"n2114807552","loc":[-85.6383526,41.9593788]},"n2114807591":{"id":"n2114807591","loc":[-85.6383741,41.9593968]},"n2189015731":{"id":"n2189015731","loc":[-85.6368404,41.9592785]},"n2189015734":{"id":"n2189015734","loc":[-85.6368404,41.9585918]},"n2189015737":{"id":"n2189015737","loc":[-85.6376009,41.9585918]},"n2189015738":{"id":"n2189015738","loc":[-85.6376009,41.9592785]},"n2189015897":{"id":"n2189015897","loc":[-85.6376839,41.9566137]},"n2189015900":{"id":"n2189015900","loc":[-85.6376831,41.9564865]},"n2189015903":{"id":"n2189015903","loc":[-85.6381161,41.9564851]},"n2189015906":{"id":"n2189015906","loc":[-85.6381168,41.9566122]},"n2189015937":{"id":"n2189015937","loc":[-85.6364789,41.9590634]},"n2189015940":{"id":"n2189015940","loc":[-85.6361137,41.9590672]},"n2189015943":{"id":"n2189015943","loc":[-85.6361169,41.9594033]},"n2189015945":{"id":"n2189015945","loc":[-85.6363456,41.9594021]},"n2189015952":{"id":"n2189015952","loc":[-85.636112,41.958892]},"n2189015955":{"id":"n2189015955","loc":[-85.6364757,41.9588894]},"n2189015957":{"id":"n2189015957","loc":[-85.6364729,41.9586747]},"n2189015958":{"id":"n2189015958","loc":[-85.6361103,41.9586765]},"n2189015959":{"id":"n2189015959","loc":[-85.6364719,41.9585562]},"n2189015960":{"id":"n2189015960","loc":[-85.6361093,41.958558]},"n2189015961":{"id":"n2189015961","loc":[-85.6355494,41.9586403]},"n2189015962":{"id":"n2189015962","loc":[-85.635549,41.9584711]},"n2189015963":{"id":"n2189015963","loc":[-85.6351831,41.9584715]},"n2189015964":{"id":"n2189015964","loc":[-85.6351834,41.9586408]},"n2189015966":{"id":"n2189015966","loc":[-85.6359579,41.9586359]},"n2189015968":{"id":"n2189015968","loc":[-85.6359561,41.9585465]},"n2189015971":{"id":"n2189015971","loc":[-85.6355476,41.9585509]},"n2189015974":{"id":"n2189015974","loc":[-85.6359516,41.9592934]},"n2189015977":{"id":"n2189015977","loc":[-85.635949,41.9586697]},"n2189015980":{"id":"n2189015980","loc":[-85.6351329,41.9586716]},"n2189015983":{"id":"n2189015983","loc":[-85.6351318,41.9583949]},"n2189015986":{"id":"n2189015986","loc":[-85.6349148,41.9583954]},"n2189015989":{"id":"n2189015989","loc":[-85.6349186,41.9592958]},"n2189015995":{"id":"n2189015995","loc":[-85.6360173,41.9593286]},"n2189015998":{"id":"n2189015998","loc":[-85.6360278,41.9583079]},"n2114807550":{"id":"n2114807550","loc":[-85.6383392,41.9595404]},"n2114807551":{"id":"n2114807551","loc":[-85.6375855,41.9616107]},"n2114807559":{"id":"n2114807559","loc":[-85.6373978,41.9621273]},"n2114807562":{"id":"n2114807562","loc":[-85.6373361,41.9622609]},"n2114807563":{"id":"n2114807563","loc":[-85.6376472,41.9613953]},"n2114807574":{"id":"n2114807574","loc":[-85.636974,41.9627695]},"n2114807589":{"id":"n2114807589","loc":[-85.6383017,41.9595005]},"n2114807592":{"id":"n2114807592","loc":[-85.6377169,41.9613494]},"n2114807595":{"id":"n2114807595","loc":[-85.6371081,41.962574]},"n2189015934":{"id":"n2189015934","loc":[-85.6364855,41.9595098]},"n2189015949":{"id":"n2189015949","loc":[-85.6363466,41.9595105]},"w208627244":{"id":"w208627244","tags":{"highway":"service"},"nodes":["n2189015992","n2189015995","n2189015998"]},"w208627240":{"id":"w208627240","tags":{"area":"yes","building":"yes"},"nodes":["n2189015961","n2189015971","n2189015962","n2189015963","n2189015964","n2189015961"]},"w17967437":{"id":"w17967437","tags":{"highway":"residential","name":"Lyman St"},"nodes":["n185964361","n185984024"]},"w208627237":{"id":"w208627237","tags":{"area":"yes","building":"yes"},"nodes":["n2189015955","n2189015957","n2189015958","n2189015952","n2189015955"]},"w17967465":{"id":"w17967465","tags":{"highway":"residential","name":"W Adams St"},"nodes":["n185978394","n185984022","n185964360"]},"w208627228":{"id":"w208627228","tags":{"area":"yes","building":"yes"},"nodes":["n2189015897","n2189015900","n2189015903","n2189015906","n2189015897"]},"w201484351":{"id":"w201484351","tags":{"railway":"rail","service":"siding"},"nodes":["n2114807587","n2114807574","n2114807595","n2114807562","n2114807559","n2114807551","n2114807563","n2114807589","n2114807552"]},"w208627239":{"id":"w208627239","tags":{"area":"yes","building":"yes"},"nodes":["n2189015957","n2189015959","n2189015960","n2189015958","n2189015957"]},"w208627233":{"id":"w208627233","tags":{"area":"yes","building":"yes"},"nodes":["n2189015934","n2189015937","n2189015940","n2189015943","n2189015945","n2189015949","n2189015934"]},"w208627241":{"id":"w208627241","tags":{"area":"yes","building":"yes"},"nodes":["n2189015961","n2189015966","n2189015968","n2189015971","n2189015961"]},"w17967970":{"id":"w17967970","tags":{"highway":"residential","name":"Adams St"},"nodes":["n185975351","n185978394"]},"w208627235":{"id":"w208627235","tags":{"area":"yes","building":"yes"},"nodes":["n2189015940","n2189015952","n2189015955","n2189015937","n2189015940"]},"w17965468":{"id":"w17965468","tags":{"highway":"residential","name":"Armstrong Blvd"},"nodes":["n185967917","n2189015998","n185967918","n185964362","n185952166"]},"w201484346":{"id":"w201484346","tags":{"railway":"rail","service":"siding"},"nodes":["n2114807551","n2114807592","n2114807550","n2114807591"]},"w208627242":{"id":"w208627242","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189015974","n2189015977","n2189015980","n2189015983","n2189015986","n2189015989","n2189015974"]},"w208627216":{"id":"w208627216","tags":{"area":"yes","building":"yes"},"nodes":["n2189015731","n2189015734","n2189015737","n2189015738","n2189015731"]},"n185984309":{"id":"n185984309","loc":[-85.631421,41.961494]},"n185987987":{"id":"n185987987","loc":[-85.631456,41.960673]},"n185965397":{"id":"n185965397","loc":[-85.634603,41.959838]},"w17965196":{"id":"w17965196","tags":{"highway":"residential","name":"Burke Ave"},"nodes":["n185965395","n185965397","n185965399"]},"w17967215":{"id":"w17967215","tags":{"highway":"residential","name":"Kellogg Ave"},"nodes":["n185968114","n185984309","n185967440","n185978402"]},"w17967597":{"id":"w17967597","tags":{"highway":"residential","name":"Barnard Ave"},"nodes":["n185968112","n185987987","n185967438","n185978399"]},"n394490857":{"id":"n394490857","loc":[-85.633952,41.960664]},"n394490858":{"id":"n394490858","loc":[-85.633938,41.960227]},"n394490859":{"id":"n394490859","loc":[-85.634794,41.960212]},"n394490860":{"id":"n394490860","loc":[-85.634815,41.960662]},"n394490861":{"id":"n394490861","loc":[-85.634103,41.961268]},"n394490862":{"id":"n394490862","loc":[-85.634103,41.961001]},"n394490863":{"id":"n394490863","loc":[-85.634504,41.961003]},"n394490864":{"id":"n394490864","loc":[-85.634561,41.961269]},"n1057629869":{"id":"n1057629869","loc":[-85.6382599,41.9612134]},"n1057629937":{"id":"n1057629937","loc":[-85.6380035,41.9616137]},"n2189016014":{"id":"n2189016014","loc":[-85.6360365,41.9626496]},"n2189016017":{"id":"n2189016017","loc":[-85.6360374,41.9623228]},"n2189016020":{"id":"n2189016020","loc":[-85.6367557,41.9623239]},"n2189016022":{"id":"n2189016022","loc":[-85.6367566,41.9619919]},"n2189016025":{"id":"n2189016025","loc":[-85.6351794,41.9619893]},"n2189016028":{"id":"n2189016028","loc":[-85.6351788,41.9622011]},"n2189016031":{"id":"n2189016031","loc":[-85.6350855,41.9622009]},"n2189016034":{"id":"n2189016034","loc":[-85.6350845,41.962527]},"n2189016037":{"id":"n2189016037","loc":[-85.6352732,41.9625273]},"n2189016039":{"id":"n2189016039","loc":[-85.6352738,41.9623178]},"n2189016042":{"id":"n2189016042","loc":[-85.6357712,41.9623186]},"n2189016044":{"id":"n2189016044","loc":[-85.6357702,41.9626492]},"n1057629880":{"id":"n1057629880","loc":[-85.638817,41.9619017]},"n1057629923":{"id":"n1057629923","loc":[-85.6390733,41.9615014]},"w91092312":{"id":"w91092312","tags":{"power":"station"},"nodes":["n1057629923","n1057629869","n1057629937","n1057629880","n1057629923"]},"w34369826":{"id":"w34369826","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490861","n394490862","n394490863","n394490864","n394490861"]},"w34369825":{"id":"w34369825","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490857","n394490858","n394490859","n394490860","n394490857"]},"w208627248":{"id":"w208627248","tags":{"area":"yes","building":"yes"},"nodes":["n2189016014","n2189016017","n2189016020","n2189016022","n2189016025","n2189016028","n2189016031","n2189016034","n2189016037","n2189016039","n2189016042","n2189016044","n2189016014"]},"n394490766":{"id":"n394490766","loc":[-85.616777,41.955642]},"n394490768":{"id":"n394490768","loc":[-85.617239,41.955644]},"n394490792":{"id":"n394490792","loc":[-85.619034,41.95543]},"n185972055":{"id":"n185972055","loc":[-85.6185905,41.9568211]},"n185972057":{"id":"n185972057","loc":[-85.6186688,41.9570086]},"n185972059":{"id":"n185972059","loc":[-85.6186924,41.9581453]},"n185972060":{"id":"n185972060","loc":[-85.6187082,41.9588211],"tags":{"highway":"turning_circle"}},"n1819790724":{"id":"n1819790724","loc":[-85.6182155,41.9555703]},"n1819790735":{"id":"n1819790735","loc":[-85.6184059,41.9566188]},"n1819790799":{"id":"n1819790799","loc":[-85.6182372,41.9563771]},"n1819790896":{"id":"n1819790896","loc":[-85.6181431,41.9557227]},"n185971405":{"id":"n185971405","loc":[-85.6186766,41.9577468]},"n185971565":{"id":"n185971565","loc":[-85.6181613,41.9560879]},"n185967985":{"id":"n185967985","loc":[-85.6186798,41.9585791]},"n185955753":{"id":"n185955753","loc":[-85.620773,41.9555854]},"n185955755":{"id":"n185955755","loc":[-85.6212652,41.9559891]},"n185955748":{"id":"n185955748","loc":[-85.620722,41.954858]},"n185955751":{"id":"n185955751","loc":[-85.6206912,41.955367]},"n185967987":{"id":"n185967987","loc":[-85.6159351,41.9585809]},"n185971407":{"id":"n185971407","loc":[-85.6159142,41.9577578]},"n185971570":{"id":"n185971570","loc":[-85.6162248,41.95603]},"n185971572":{"id":"n185971572","loc":[-85.6160402,41.9560749]},"n185971574":{"id":"n185971574","loc":[-85.61593,41.956201]},"n185981301":{"id":"n185981301","loc":[-85.6158973,41.9581601]},"n394490762":{"id":"n394490762","loc":[-85.617193,41.954706]},"n394490764":{"id":"n394490764","loc":[-85.616773,41.954737]},"n394490787":{"id":"n394490787","loc":[-85.618972,41.954737]},"n394490790":{"id":"n394490790","loc":[-85.619046,41.954929]},"n394490794":{"id":"n394490794","loc":[-85.619922,41.955296]},"n394490796":{"id":"n394490796","loc":[-85.61991,41.95501]},"n394490798":{"id":"n394490798","loc":[-85.619974,41.954751]},"n1819790677":{"id":"n1819790677","loc":[-85.6187031,41.9550522]},"n1819790787":{"id":"n1819790787","loc":[-85.6186436,41.9552022]},"n1819790828":{"id":"n1819790828","loc":[-85.6185127,41.9553393]},"w17966857":{"id":"w17966857","tags":{"access":"private","highway":"service","name":"Sable River Rd"},"nodes":["n185972059","n185981301"]},"w34369814":{"id":"w34369814","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490787","n394490790","n394490792","n394490794","n394490796","n394490798","n394490787"]},"w17964176":{"id":"w17964176","tags":{"highway":"residential"},"nodes":["n185955747","n185955748","n185955751","n185955753","n185955755"]},"w17965838":{"id":"w17965838","tags":{"access":"private","highway":"service","name":"Pine River Rd"},"nodes":["n185971405","n185971407"]},"w17965476":{"id":"w17965476","tags":{"access":"private","highway":"service","name":"Raisin River Rd"},"nodes":["n185967985","n185967987"]},"w17965913":{"id":"w17965913","tags":{"access":"private","highway":"service","name":"Shiawassee River Rd"},"nodes":["n185972054","n1819790677","n1819790787","n1819790828","n1819790724","n1819790896","n185971565","n1819790799","n1819790735","n185972055","n185972057","n185971405","n185972059","n185967985","n185972060"]},"w34369811":{"id":"w34369811","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490762","n394490764","n394490766","n394490768","n394490762"]},"w17965854":{"id":"w17965854","tags":{"access":"private","highway":"service","name":"Sturgeon River Rd"},"nodes":["n185971565","n185971570","n185971572","n185971574"]},"n2139795769":{"id":"n2139795769","loc":[-85.6250804,41.9608796]},"n2139795770":{"id":"n2139795770","loc":[-85.6250315,41.9613684]},"n2139795771":{"id":"n2139795771","loc":[-85.6249671,41.9614362]},"n2139795772":{"id":"n2139795772","loc":[-85.6249698,41.961522]},"n2139795773":{"id":"n2139795773","loc":[-85.6250798,41.9615838]},"n2139795774":{"id":"n2139795774","loc":[-85.6252273,41.9615639]},"n2139795775":{"id":"n2139795775","loc":[-85.6252863,41.9614622]},"n2139795776":{"id":"n2139795776","loc":[-85.6252273,41.9613764]},"n2139795777":{"id":"n2139795777","loc":[-85.6251227,41.9613525]},"n2139795778":{"id":"n2139795778","loc":[-85.6249564,41.9612527]},"n2139795779":{"id":"n2139795779","loc":[-85.6249846,41.9610254]},"n2139795780":{"id":"n2139795780","loc":[-85.6266725,41.9599647]},"n2139795781":{"id":"n2139795781","loc":[-85.6259162,41.9599711]},"n2139795782":{"id":"n2139795782","loc":[-85.6257185,41.960019]},"n2139795783":{"id":"n2139795783","loc":[-85.6255509,41.9601213]},"n185963539":{"id":"n185963539","loc":[-85.615718,41.983893]},"n185964418":{"id":"n185964418","loc":[-85.616626,42.049512]},"n185966614":{"id":"n185966614","loc":[-85.615514,41.976603]},"n185966635":{"id":"n185966635","loc":[-85.616118,42.013017]},"n185969040":{"id":"n185969040","loc":[-85.615632,41.972357]},"n185969070":{"id":"n185969070","loc":[-85.619145,41.967648]},"n185972156":{"id":"n185972156","loc":[-85.621894,41.963956]},"n185972157":{"id":"n185972157","loc":[-85.621806,41.964077]},"n185972158":{"id":"n185972158","loc":[-85.620848,41.965341]},"n185972159":{"id":"n185972159","loc":[-85.620684,41.965558]},"n185972160":{"id":"n185972160","loc":[-85.620621,41.965658]},"n185972161":{"id":"n185972161","loc":[-85.617844,41.969359]},"n185972162":{"id":"n185972162","loc":[-85.616843,41.97068]},"n185972164":{"id":"n185972164","loc":[-85.616714,41.970839]},"n185972166":{"id":"n185972166","loc":[-85.615879,41.971969]},"n185972168":{"id":"n185972168","loc":[-85.615748,41.972159]},"n185972170":{"id":"n185972170","loc":[-85.615589,41.972502]},"n185972172":{"id":"n185972172","loc":[-85.615542,41.972733]},"n185972175":{"id":"n185972175","loc":[-85.615524,41.972947]},"n185972177":{"id":"n185972177","loc":[-85.615512,41.973715]},"n185972179":{"id":"n185972179","loc":[-85.615513,41.976496]},"n185972180":{"id":"n185972180","loc":[-85.615538,41.977246]},"n185972181":{"id":"n185972181","loc":[-85.61558,41.982139]},"n185972184":{"id":"n185972184","loc":[-85.61557,41.983317]},"n185972186":{"id":"n185972186","loc":[-85.615591,41.983463]},"n185972188":{"id":"n185972188","loc":[-85.615763,41.984146]},"n185972190":{"id":"n185972190","loc":[-85.615814,41.98435]},"n185972192":{"id":"n185972192","loc":[-85.615965,41.998453]},"n185972194":{"id":"n185972194","loc":[-85.615982,42.001237]},"n185972195":{"id":"n185972195","loc":[-85.616055,42.00555]},"n185972197":{"id":"n185972197","loc":[-85.616134,42.014887]},"n185972199":{"id":"n185972199","loc":[-85.616177,42.018465]},"n185972201":{"id":"n185972201","loc":[-85.616298,42.027627]},"n185972203":{"id":"n185972203","loc":[-85.616513,42.042212]},"w203968015":{"id":"w203968015","tags":{"highway":"residential"},"nodes":["n2139795768","n2139795769"]},"w17965932":{"id":"w17965932","tags":{"highway":"residential","name":"Buckhorn Road","name_1":"County Highway 122"},"nodes":["n185972155","n185972156","n185972157","n185972158","n185972159","n185972160","n185969070","n185972161","n185972162","n185972164","n185972166","n185972168","n185969040","n185972170","n185972172","n185972175","n185972177","n185972179","n185966614","n185972180","n185972181","n185972184","n185972186","n185963539","n185972188","n185972190","n185972192","n185972194","n185972195","n185966635","n185972197","n185972199","n185972201","n185972203","n185964418"]},"w203968016":{"id":"w203968016","tags":{"highway":"residential","name":"New Jersey Court"},"nodes":["n2139795770","n2139795771","n2139795772","n2139795773","n2139795774","n2139795775","n2139795776","n2139795777","n2139795770","n2139795778","n2139795779","n2139795769"]},"w203968017":{"id":"w203968017","tags":{"highway":"residential","name":"Oklahoma Drive"},"nodes":["n2139795780","n2139795781","n2139795782","n2139795783","n2139795769"]},"n1819790528":{"id":"n1819790528","loc":[-85.6184827,41.960025]},"n1819790530":{"id":"n1819790530","loc":[-85.6168626,41.9605834]},"n1819790534":{"id":"n1819790534","loc":[-85.6197379,41.9617163]},"n1819790541":{"id":"n1819790541","loc":[-85.6198881,41.9620833]},"n1819790543":{"id":"n1819790543","loc":[-85.619695,41.9619397]},"n1819790547":{"id":"n1819790547","loc":[-85.6190298,41.9609504]},"n1819790555":{"id":"n1819790555","loc":[-85.6180471,41.9609788]},"n1819790559":{"id":"n1819790559","loc":[-85.6203817,41.9605436]},"n1819790583":{"id":"n1819790583","loc":[-85.6201564,41.9603282]},"n1819790590":{"id":"n1819790590","loc":[-85.617045,41.9598894]},"n1819790609":{"id":"n1819790609","loc":[-85.6177638,41.9598495]},"n1819790618":{"id":"n1819790618","loc":[-85.6195234,41.9610143]},"n1819790642":{"id":"n1819790642","loc":[-85.6181179,41.9627933]},"n1819790659":{"id":"n1819790659","loc":[-85.6174634,41.962897]},"n1819790665":{"id":"n1819790665","loc":[-85.6170343,41.9630885]},"n1819790674":{"id":"n1819790674","loc":[-85.6194697,41.9601925]},"n1819790685":{"id":"n1819790685","loc":[-85.6207722,41.9610665]},"n1819790687":{"id":"n1819790687","loc":[-85.6202315,41.9622109]},"n1819790697":{"id":"n1819790697","loc":[-85.6184505,41.9624662]},"n1819790726":{"id":"n1819790726","loc":[-85.6178926,41.9628492]},"n1819790738":{"id":"n1819790738","loc":[-85.6173347,41.9598016]},"n1819790762":{"id":"n1819790762","loc":[-85.6186221,41.9609105]},"n1819790774":{"id":"n1819790774","loc":[-85.6175922,41.9608308]},"n1819790781":{"id":"n1819790781","loc":[-85.6167768,41.9633198]},"n1819790796":{"id":"n1819790796","loc":[-85.619856,41.961461]},"n1819790811":{"id":"n1819790811","loc":[-85.6208215,41.9620195]},"n1819790833":{"id":"n1819790833","loc":[-85.618311,41.9612536]},"n1819790854":{"id":"n1819790854","loc":[-85.6183646,41.9626417]},"n1819790863":{"id":"n1819790863","loc":[-85.6204997,41.9608547]},"n1819790867":{"id":"n1819790867","loc":[-85.6184934,41.9621391]},"n1819790877":{"id":"n1819790877","loc":[-85.6206928,41.9621152]},"n1819790881":{"id":"n1819790881","loc":[-85.6170879,41.960735]},"n1819790891":{"id":"n1819790891","loc":[-85.6168304,41.9601207]},"n1819790898":{"id":"n1819790898","loc":[-85.619813,41.9612297]},"n1819790909":{"id":"n1819790909","loc":[-85.6167982,41.960376]},"n1819790912":{"id":"n1819790912","loc":[-85.6205855,41.9610462]},"n1819790544":{"id":"n1819790544","loc":[-85.612968,41.9707781]},"n1819790549":{"id":"n1819790549","loc":[-85.614395,41.9697172]},"n1819790552":{"id":"n1819790552","loc":[-85.6180535,41.9655536]},"n1819790554":{"id":"n1819790554","loc":[-85.6111227,41.9703713]},"n1819790560":{"id":"n1819790560","loc":[-85.6112729,41.9701958]},"n1819790563":{"id":"n1819790563","loc":[-85.6137512,41.9689917]},"n1819790564":{"id":"n1819790564","loc":[-85.6181072,41.9659205]},"n1819790595":{"id":"n1819790595","loc":[-85.6170021,41.9666863]},"n1819790605":{"id":"n1819790605","loc":[-85.6168948,41.9644527]},"n1819790606":{"id":"n1819790606","loc":[-85.6128071,41.9701081]},"n1819790607":{"id":"n1819790607","loc":[-85.6129251,41.9704032]},"n1819790612":{"id":"n1819790612","loc":[-85.6177638,41.9663912]},"n1819790615":{"id":"n1819790615","loc":[-85.6152533,41.9670373]},"n1819790622":{"id":"n1819790622","loc":[-85.6146739,41.9673804]},"n1819790623":{"id":"n1819790623","loc":[-85.6180428,41.9661838]},"n1819790625":{"id":"n1819790625","loc":[-85.6172918,41.9646202]},"n1819790645":{"id":"n1819790645","loc":[-85.6178067,41.965043]},"n1819790647":{"id":"n1819790647","loc":[-85.6143306,41.9712488]},"n1819790649":{"id":"n1819790649","loc":[-85.6147383,41.9707702]},"n1819790654":{"id":"n1819790654","loc":[-85.6157361,41.9668459]},"n1819790657":{"id":"n1819790657","loc":[-85.6145666,41.9710733]},"n1819790668":{"id":"n1819790668","loc":[-85.6166909,41.9642692]},"n1819790671":{"id":"n1819790671","loc":[-85.6141482,41.9696538]},"n1819790679":{"id":"n1819790679","loc":[-85.6148349,41.9705388]},"n1819790686":{"id":"n1819790686","loc":[-85.6139551,41.9695501]},"n1819790696":{"id":"n1819790696","loc":[-85.6119703,41.9699087]},"n1819790704":{"id":"n1819790704","loc":[-85.6140731,41.9684174]},"n1819790706":{"id":"n1819790706","loc":[-85.6124745,41.9699246]},"n1819790718":{"id":"n1819790718","loc":[-85.6165407,41.9636868]},"n1819790720":{"id":"n1819790720","loc":[-85.61388,41.9687365]},"n1819790731":{"id":"n1819790731","loc":[-85.6165193,41.9639421]},"n1819790739":{"id":"n1819790739","loc":[-85.6146739,41.9699964]},"n1819790753":{"id":"n1819790753","loc":[-85.6173883,41.9665747]},"n1819790760":{"id":"n1819790760","loc":[-85.6133221,41.9712089]},"n1819790767":{"id":"n1819790767","loc":[-85.6116698,41.9699246]},"n1819790779":{"id":"n1819790779","loc":[-85.6130753,41.9710573]},"n1819790791":{"id":"n1819790791","loc":[-85.6137083,41.9692869]},"n1819790795":{"id":"n1819790795","loc":[-85.6141482,41.9679627]},"n1819790798":{"id":"n1819790798","loc":[-85.6137727,41.9694305]},"n1819790836":{"id":"n1819790836","loc":[-85.6143842,41.9676037]},"n1819790915":{"id":"n1819790915","loc":[-85.6148456,41.9702756]},"n1819790926":{"id":"n1819790926","loc":[-85.6138371,41.9713525]},"n1819790927":{"id":"n1819790927","loc":[-85.6141053,41.9713525]},"n1819790931":{"id":"n1819790931","loc":[-85.6162832,41.966814]},"n1821014625":{"id":"n1821014625","loc":[-85.5960611,41.9808498]},"n1821014627":{"id":"n1821014627","loc":[-85.5565843,42.010982]},"n1821014629":{"id":"n1821014629","loc":[-85.5971541,41.9805808]},"n1821014632":{"id":"n1821014632","loc":[-85.6061837,41.9725907]},"n1821014633":{"id":"n1821014633","loc":[-85.5247773,42.025766]},"n1821014635":{"id":"n1821014635","loc":[-85.5908938,41.9902384]},"n1821014636":{"id":"n1821014636","loc":[-85.5917682,41.9860637]},"n1821014637":{"id":"n1821014637","loc":[-85.5456556,42.0166797]},"n1821014638":{"id":"n1821014638","loc":[-85.5795749,42.0032352]},"n1821014639":{"id":"n1821014639","loc":[-85.6103988,41.9723456]},"n1821014642":{"id":"n1821014642","loc":[-85.5818816,42.0022466]},"n1821014643":{"id":"n1821014643","loc":[-85.5570604,42.0091586]},"n1821014644":{"id":"n1821014644","loc":[-85.5952886,41.9803792]},"n1821014645":{"id":"n1821014645","loc":[-85.5780366,42.0040343]},"n1821014646":{"id":"n1821014646","loc":[-85.6050505,41.9751971]},"n1821014647":{"id":"n1821014647","loc":[-85.5854435,41.9946162]},"n1821014648":{"id":"n1821014648","loc":[-85.5452278,42.0168768]},"n1821014649":{"id":"n1821014649","loc":[-85.6023254,41.9780166]},"n1821014651":{"id":"n1821014651","loc":[-85.5761899,42.0046783]},"n1821014653":{"id":"n1821014653","loc":[-85.5897351,41.9876707]},"n1821014657":{"id":"n1821014657","loc":[-85.5963601,41.9808998]},"n1821014658":{"id":"n1821014658","loc":[-85.5892952,41.9951983]},"n1821014660":{"id":"n1821014660","loc":[-85.5778328,42.0037194]},"n1821014661":{"id":"n1821014661","loc":[-85.5541475,42.0125705]},"n1821014663":{"id":"n1821014663","loc":[-85.5914047,41.9856469]},"n1821014664":{"id":"n1821014664","loc":[-85.6101681,41.9727723]},"n1821014665":{"id":"n1821014665","loc":[-85.5910172,41.9854696]},"n1821014666":{"id":"n1821014666","loc":[-85.5398688,42.0187699]},"n1821014667":{"id":"n1821014667","loc":[-85.5218752,42.0282884]},"n1821014668":{"id":"n1821014668","loc":[-85.5159582,42.0329384]},"n1821014669":{"id":"n1821014669","loc":[-85.5898102,41.9847319]},"n1821014670":{"id":"n1821014670","loc":[-85.5734809,42.0066235]},"n1821014671":{"id":"n1821014671","loc":[-85.5922939,41.980852]},"n1821014672":{"id":"n1821014672","loc":[-85.6023629,41.9781163]},"n1821014674":{"id":"n1821014674","loc":[-85.5409953,42.0191724]},"n1821014676":{"id":"n1821014676","loc":[-85.584435,41.9949909]},"n1821014677":{"id":"n1821014677","loc":[-85.5972399,41.9783835]},"n1821014678":{"id":"n1821014678","loc":[-85.5616738,42.0071337]},"n1821014681":{"id":"n1821014681","loc":[-85.5202994,42.0310755]},"n1821014682":{"id":"n1821014682","loc":[-85.5915912,41.9857767]},"n1821014684":{"id":"n1821014684","loc":[-85.6022288,41.977897]},"n1821014687":{"id":"n1821014687","loc":[-85.5933024,41.9846362]},"n1821014688":{"id":"n1821014688","loc":[-85.5846871,41.9956169]},"n1821014689":{"id":"n1821014689","loc":[-85.5898209,41.99037]},"n1821014691":{"id":"n1821014691","loc":[-85.5448939,42.0149261]},"n1821014692":{"id":"n1821014692","loc":[-85.5977763,41.9786348]},"n1821014694":{"id":"n1821014694","loc":[-85.5767706,42.0034523]},"n1821014695":{"id":"n1821014695","loc":[-85.6103559,41.9726766]},"n1821014697":{"id":"n1821014697","loc":[-85.5922134,41.9809876]},"n1821014698":{"id":"n1821014698","loc":[-85.5935277,41.9831728]},"n1821014700":{"id":"n1821014700","loc":[-85.5674674,42.0078273]},"n1821014703":{"id":"n1821014703","loc":[-85.6021,41.9778053]},"n1821014704":{"id":"n1821014704","loc":[-85.5756763,42.0053737]},"n1821014705":{"id":"n1821014705","loc":[-85.5887695,41.9895207]},"n1821014707":{"id":"n1821014707","loc":[-85.6061073,41.9746866]},"n1821014708":{"id":"n1821014708","loc":[-85.6033446,41.9751692]},"n1821014710":{"id":"n1821014710","loc":[-85.5180986,42.0322332]},"n1821014711":{"id":"n1821014711","loc":[-85.543365,42.0163569]},"n1821014712":{"id":"n1821014712","loc":[-85.6030656,41.9753646]},"n1821014713":{"id":"n1821014713","loc":[-85.6104417,41.9704792]},"n1821014714":{"id":"n1821014714","loc":[-85.5205716,42.030998]},"n1821014716":{"id":"n1821014716","loc":[-85.516382,42.032536]},"n1821014717":{"id":"n1821014717","loc":[-85.5932863,41.9820882]},"n1821014718":{"id":"n1821014718","loc":[-85.5361928,42.0194974]},"n1821014720":{"id":"n1821014720","loc":[-85.6011613,41.9773586]},"n1821014721":{"id":"n1821014721","loc":[-85.554287,42.0109124]},"n1821014722":{"id":"n1821014722","loc":[-85.5577524,42.0103425]},"n1821014725":{"id":"n1821014725","loc":[-85.5867256,41.9921004]},"n1821014726":{"id":"n1821014726","loc":[-85.5856045,41.9968807]},"n1821014727":{"id":"n1821014727","loc":[-85.5545445,42.0106454]},"n1821014728":{"id":"n1821014728","loc":[-85.5923797,41.9842534]},"n1821014729":{"id":"n1821014729","loc":[-85.5696346,42.0081462]},"n1821014730":{"id":"n1821014730","loc":[-85.5998322,41.9786884]},"n1821014735":{"id":"n1821014735","loc":[-85.5337426,42.0218266]},"n1821014736":{"id":"n1821014736","loc":[-85.5847944,41.994672]},"n1821014740":{"id":"n1821014740","loc":[-85.5315271,42.0238669]},"n1821014741":{"id":"n1821014741","loc":[-85.5248846,42.027085]},"n1821014742":{"id":"n1821014742","loc":[-85.5853376,41.997018]},"n1821014743":{"id":"n1821014743","loc":[-85.5894883,41.988811]},"n1821014745":{"id":"n1821014745","loc":[-85.6095311,41.9726226]},"n1821014746":{"id":"n1821014746","loc":[-85.5531511,42.0133416]},"n1821014747":{"id":"n1821014747","loc":[-85.5735882,42.007058]},"n1821014749":{"id":"n1821014749","loc":[-85.5428554,42.0164366]},"n1821014751":{"id":"n1821014751","loc":[-85.5395255,42.0186304]},"n1821014752":{"id":"n1821014752","loc":[-85.571378,42.0083176]},"n1821014754":{"id":"n1821014754","loc":[-85.5541918,42.0113925]},"n1821014755":{"id":"n1821014755","loc":[-85.5278029,42.0250806]},"n1821014756":{"id":"n1821014756","loc":[-85.5936725,41.9827102]},"n1821014757":{"id":"n1821014757","loc":[-85.5176266,42.0346677]},"n1821014758":{"id":"n1821014758","loc":[-85.6096692,41.9714245]},"n1821014759":{"id":"n1821014759","loc":[-85.5770321,42.0034266]},"n1821014761":{"id":"n1821014761","loc":[-85.5988921,41.9779369]},"n1821014762":{"id":"n1821014762","loc":[-85.5811788,42.0024499]},"n1821014763":{"id":"n1821014763","loc":[-85.5154003,42.0381101]},"n1821014764":{"id":"n1821014764","loc":[-85.5155827,42.0374089]},"n1821014765":{"id":"n1821014765","loc":[-85.5891249,41.9884978]},"n1821014766":{"id":"n1821014766","loc":[-85.5313863,42.0238293]},"n1821014768":{"id":"n1821014768","loc":[-85.593297,41.9833363]},"n1821014769":{"id":"n1821014769","loc":[-85.5849446,41.9957245]},"n1821014770":{"id":"n1821014770","loc":[-85.5537774,42.0130847]},"n1821014771":{"id":"n1821014771","loc":[-85.6111766,41.9706069]},"n1821014772":{"id":"n1821014772","loc":[-85.5585477,42.008989]},"n1821014774":{"id":"n1821014774","loc":[-85.5928142,41.9852623]},"n1821014777":{"id":"n1821014777","loc":[-85.5891933,41.9882608]},"n1821014778":{"id":"n1821014778","loc":[-85.5926909,41.9817532]},"n1821014779":{"id":"n1821014779","loc":[-85.5260272,42.0252201]},"n1821014781":{"id":"n1821014781","loc":[-85.5894615,41.9950468]},"n1821014782":{"id":"n1821014782","loc":[-85.5461063,42.0143242]},"n1821014783":{"id":"n1821014783","loc":[-85.5711527,42.0085886]},"n1821014784":{"id":"n1821014784","loc":[-85.5329379,42.0218624]},"n1821014786":{"id":"n1821014786","loc":[-85.583047,42.0020252]},"n1821014787":{"id":"n1821014787","loc":[-85.5758962,42.0054095]},"n1821014788":{"id":"n1821014788","loc":[-85.5626354,42.0077733]},"n1821014789":{"id":"n1821014789","loc":[-85.6029852,41.9755999]},"n1821014790":{"id":"n1821014790","loc":[-85.5892362,41.9886755]},"n1821014791":{"id":"n1821014791","loc":[-85.5157597,42.0372017]},"n1821014793":{"id":"n1821014793","loc":[-85.6054582,41.9751094]},"n1821014794":{"id":"n1821014794","loc":[-85.5986936,41.9778412]},"n1821014795":{"id":"n1821014795","loc":[-85.5880775,41.98976]},"n1821014796":{"id":"n1821014796","loc":[-85.5858727,41.9963624]},"n1821014798":{"id":"n1821014798","loc":[-85.5792543,42.0035958]},"n1821014799":{"id":"n1821014799","loc":[-85.5921665,41.9838326]},"n1821014801":{"id":"n1821014801","loc":[-85.599214,41.9782599]},"n1821014802":{"id":"n1821014802","loc":[-85.5571905,42.0090967]},"n1821014803":{"id":"n1821014803","loc":[-85.5426891,42.0173612]},"n1821014804":{"id":"n1821014804","loc":[-85.5889626,41.9896404]},"n1821014805":{"id":"n1821014805","loc":[-85.5491264,42.0141648]},"n1821014806":{"id":"n1821014806","loc":[-85.5618897,42.0072631]},"n1821014808":{"id":"n1821014808","loc":[-85.5573501,42.0109802]},"n1821014809":{"id":"n1821014809","loc":[-85.5983463,41.9778031]},"n1821014810":{"id":"n1821014810","loc":[-85.5885173,41.9895128]},"n1821014811":{"id":"n1821014811","loc":[-85.6084998,41.9721143]},"n1821014812":{"id":"n1821014812","loc":[-85.5737598,42.0056389]},"n1821014814":{"id":"n1821014814","loc":[-85.5542173,42.0118132]},"n1821014816":{"id":"n1821014816","loc":[-85.5277868,42.024451]},"n1821014817":{"id":"n1821014817","loc":[-85.5403999,42.0191724]},"n1821014819":{"id":"n1821014819","loc":[-85.5983879,41.9791452]},"n1821014820":{"id":"n1821014820","loc":[-85.5891302,41.9897578]},"n1821014822":{"id":"n1821014822","loc":[-85.5930731,41.9805108]},"n1821014824":{"id":"n1821014824","loc":[-85.515395,42.0378471]},"n1821014825":{"id":"n1821014825","loc":[-85.5352755,42.0205136]},"n1821014826":{"id":"n1821014826","loc":[-85.5502744,42.0133398]},"n1821014828":{"id":"n1821014828","loc":[-85.5701295,42.0088256]},"n1821014830":{"id":"n1821014830","loc":[-85.5888929,41.9953099]},"n1821014832":{"id":"n1821014832","loc":[-85.5880077,41.9901547]},"n1821014833":{"id":"n1821014833","loc":[-85.5451192,42.0157072]},"n1821014834":{"id":"n1821014834","loc":[-85.6096478,41.9711932]},"n1821014835":{"id":"n1821014835","loc":[-85.5806424,42.0026532]},"n1821014836":{"id":"n1821014836","loc":[-85.5911674,41.9868732]},"n1821014838":{"id":"n1821014838","loc":[-85.5930302,41.9836571]},"n1821014839":{"id":"n1821014839","loc":[-85.588925,41.9938148]},"n1821014840":{"id":"n1821014840","loc":[-85.6111874,41.9705311]},"n1821014841":{"id":"n1821014841","loc":[-85.5680843,42.0075842]},"n1821014842":{"id":"n1821014842","loc":[-85.6012793,41.9775062]},"n1821014843":{"id":"n1821014843","loc":[-85.5855562,41.9989777]},"n1821014844":{"id":"n1821014844","loc":[-85.5506137,42.0131662]},"n1821014845":{"id":"n1821014845","loc":[-85.5270049,42.025457]},"n1821014846":{"id":"n1821014846","loc":[-85.5257054,42.025244]},"n1821014847":{"id":"n1821014847","loc":[-85.6011184,41.9771832]},"n1821014848":{"id":"n1821014848","loc":[-85.515534,42.0389234]},"n1821014850":{"id":"n1821014850","loc":[-85.5847032,42.0010347]},"n1821014853":{"id":"n1821014853","loc":[-85.5361499,42.019063]},"n1821014854":{"id":"n1821014854","loc":[-85.5439176,42.0165721]},"n1821014855":{"id":"n1821014855","loc":[-85.5838825,42.0017284]},"n1821014857":{"id":"n1821014857","loc":[-85.5542173,42.0122317]},"n1821014859":{"id":"n1821014859","loc":[-85.5708201,42.0089195]},"n1821014860":{"id":"n1821014860","loc":[-85.5844833,41.9954415]},"n1821014862":{"id":"n1821014862","loc":[-85.5223204,42.0295396]},"n1821014863":{"id":"n1821014863","loc":[-85.5777898,42.0035918]},"n1821014864":{"id":"n1821014864","loc":[-85.591044,41.9898078]},"n1821014865":{"id":"n1821014865","loc":[-85.5973204,41.980182]},"n1821014866":{"id":"n1821014866","loc":[-85.5699578,42.0085825]},"n1821014867":{"id":"n1821014867","loc":[-85.5210598,42.0305278]},"n1821014868":{"id":"n1821014868","loc":[-85.5929108,41.9819008]},"n1821014869":{"id":"n1821014869","loc":[-85.5279799,42.0242995]},"n1821014870":{"id":"n1821014870","loc":[-85.5196114,42.0320539]},"n1821014871":{"id":"n1821014871","loc":[-85.5785449,42.0040883]},"n1821014872":{"id":"n1821014872","loc":[-85.588292,41.9895766]},"n1821014873":{"id":"n1821014873","loc":[-85.5160172,42.0331775]},"n1821014874":{"id":"n1821014874","loc":[-85.5688849,42.0077016]},"n1821014876":{"id":"n1821014876","loc":[-85.5857976,41.9996036]},"n1821014879":{"id":"n1821014879","loc":[-85.5990906,41.9780765]},"n1821014881":{"id":"n1821014881","loc":[-85.5483647,42.0144279]},"n1821014883":{"id":"n1821014883","loc":[-85.5691209,42.0077972]},"n1821014885":{"id":"n1821014885","loc":[-85.6076844,41.9721103]},"n1821014886":{"id":"n1821014886","loc":[-85.6015489,41.9766147]},"n1821014887":{"id":"n1821014887","loc":[-85.574822,42.0052802]},"n1821014888":{"id":"n1821014888","loc":[-85.5880024,41.9899593]},"n1821014890":{"id":"n1821014890","loc":[-85.5909421,41.9893772]},"n1821014892":{"id":"n1821014892","loc":[-85.5497326,42.0138141]},"n1821014893":{"id":"n1821014893","loc":[-85.5167106,42.0357811]},"n1821014895":{"id":"n1821014895","loc":[-85.5844404,41.9952501]},"n1821014896":{"id":"n1821014896","loc":[-85.5362465,42.0192662]},"n1821014898":{"id":"n1821014898","loc":[-85.5906095,41.9889147]},"n1821014899":{"id":"n1821014899","loc":[-85.5590667,42.0089354]},"n1821014900":{"id":"n1821014900","loc":[-85.5921598,41.9844209]},"n1821014902":{"id":"n1821014902","loc":[-85.5778971,42.0039266]},"n1821014903":{"id":"n1821014903","loc":[-85.603012,41.9761981]},"n1821014904":{"id":"n1821014904","loc":[-85.6108977,41.9706787]},"n1821014905":{"id":"n1821014905","loc":[-85.5685738,42.0076139]},"n1821014906":{"id":"n1821014906","loc":[-85.5392787,42.0186304]},"n1821014907":{"id":"n1821014907","loc":[-85.5227885,42.0274972]},"n1821014908":{"id":"n1821014908","loc":[-85.5857547,41.9961431]},"n1821014910":{"id":"n1821014910","loc":[-85.5610354,42.0072812]},"n1821014911":{"id":"n1821014911","loc":[-85.5209632,42.0308705]},"n1821014912":{"id":"n1821014912","loc":[-85.5709757,42.0087959]},"n1821014913":{"id":"n1821014913","loc":[-85.59231,41.9839344]},"n1821014914":{"id":"n1821014914","loc":[-85.5375245,42.0185865]},"n1821014916":{"id":"n1821014916","loc":[-85.5901548,41.9839841]},"n1821014917":{"id":"n1821014917","loc":[-85.5611213,42.0086405]},"n1821014918":{"id":"n1821014918","loc":[-85.5360426,42.0198122]},"n1821014919":{"id":"n1821014919","loc":[-85.5862817,41.9948691]},"n1821014921":{"id":"n1821014921","loc":[-85.5469807,42.0144438]},"n1821014922":{"id":"n1821014922","loc":[-85.5761309,42.0053838]},"n1821014924":{"id":"n1821014924","loc":[-85.516264,42.0332971]},"n1821014925":{"id":"n1821014925","loc":[-85.5277224,42.0246661]},"n1821014926":{"id":"n1821014926","loc":[-85.5980016,41.9798231]},"n1821014928":{"id":"n1821014928","loc":[-85.5924548,41.9806965]},"n1821014930":{"id":"n1821014930","loc":[-85.5899121,41.985023]},"n1821014931":{"id":"n1821014931","loc":[-85.5706015,42.0089492]},"n1821014932":{"id":"n1821014932","loc":[-85.515926,42.033046]},"n1821014933":{"id":"n1821014933","loc":[-85.5982377,41.9796796]},"n1821014936":{"id":"n1821014936","loc":[-85.5475721,42.0145253]},"n1821014938":{"id":"n1821014938","loc":[-85.5895701,41.9902323]},"n1821014939":{"id":"n1821014939","loc":[-85.6030495,41.9759947]},"n1821014942":{"id":"n1821014942","loc":[-85.6094721,41.9724989]},"n1821014944":{"id":"n1821014944","loc":[-85.5921973,41.9811112]},"n1821014945":{"id":"n1821014945","loc":[-85.5223526,42.0291332]},"n1821014946":{"id":"n1821014946","loc":[-85.5965103,41.9808998]},"n1821014948":{"id":"n1821014948","loc":[-85.517766,42.0349227]},"n1821014950":{"id":"n1821014950","loc":[-85.5889894,41.990996]},"n1821014951":{"id":"n1821014951","loc":[-85.5601932,42.0092902]},"n1821014954":{"id":"n1821014954","loc":[-85.6028135,41.9764055]},"n1821014955":{"id":"n1821014955","loc":[-85.5520621,42.0130666]},"n1821014956":{"id":"n1821014956","loc":[-85.593002,41.9839344]},"n1821014957":{"id":"n1821014957","loc":[-85.515926,42.0369666]},"n1821014960":{"id":"n1821014960","loc":[-85.5761255,42.003877]},"n1821014961":{"id":"n1821014961","loc":[-85.5716355,42.007911]},"n1821014962":{"id":"n1821014962","loc":[-85.5575378,42.0109045]},"n1821014963":{"id":"n1821014963","loc":[-85.5735667,42.0068188]},"n1821014964":{"id":"n1821014964","loc":[-85.5915214,41.9865861]},"n1821014965":{"id":"n1821014965","loc":[-85.5866344,41.9923157]},"n1821014967":{"id":"n1821014967","loc":[-85.5283138,42.0242256]},"n1821014968":{"id":"n1821014968","loc":[-85.5177875,42.0355801]},"n1821014969":{"id":"n1821014969","loc":[-85.548071,42.0144934]},"n1821014972":{"id":"n1821014972","loc":[-85.5611159,42.0088557]},"n1821014973":{"id":"n1821014973","loc":[-85.541686,42.0188757]},"n1821014974":{"id":"n1821014974","loc":[-85.5917628,41.9862631]},"n1821014975":{"id":"n1821014975","loc":[-85.5854864,41.9959478]},"n1821014977":{"id":"n1821014977","loc":[-85.609102,41.9722317]},"n1821014980":{"id":"n1821014980","loc":[-85.5761202,42.0042438]},"n1821014982":{"id":"n1821014982","loc":[-85.5465944,42.0143601]},"n1821014983":{"id":"n1821014983","loc":[-85.5173261,42.0342732]},"n1821014984":{"id":"n1821014984","loc":[-85.5897297,41.9888509]},"n1821014985":{"id":"n1821014985","loc":[-85.5856688,41.999181]},"n1821014986":{"id":"n1821014986","loc":[-85.5344011,42.0217251]},"n1821014987":{"id":"n1821014987","loc":[-85.601467,41.9768203]},"n1821014988":{"id":"n1821014988","loc":[-85.5457254,42.0165123]},"n1821014989":{"id":"n1821014989","loc":[-85.6023482,41.9784332]},"n1821014991":{"id":"n1821014991","loc":[-85.5361606,42.01823]},"n1821014992":{"id":"n1821014992","loc":[-85.5178465,42.0351139]},"n1821014995":{"id":"n1821014995","loc":[-85.5634293,42.0078092]},"n1821014996":{"id":"n1821014996","loc":[-85.573497,42.0072015]},"n1821014997":{"id":"n1821014997","loc":[-85.5976328,41.9799725]},"n1821014998":{"id":"n1821014998","loc":[-85.5210651,42.0303166]},"n1821015003":{"id":"n1821015003","loc":[-85.5222131,42.0288064]},"n1821015004":{"id":"n1821015004","loc":[-85.5897941,41.984405]},"n1821015005":{"id":"n1821015005","loc":[-85.5975725,41.9776099]},"n1821015006":{"id":"n1821015006","loc":[-85.5765708,42.0034903]},"n1821015007":{"id":"n1821015007","loc":[-85.5250187,42.026559]},"n1821015009":{"id":"n1821015009","loc":[-85.5426998,42.0166279]},"n1821015010":{"id":"n1821015010","loc":[-85.5957606,41.9806584]},"n1821015011":{"id":"n1821015011","loc":[-85.5262753,42.0252497]},"n1821015012":{"id":"n1821015012","loc":[-85.5266455,42.0253374]},"n1821015014":{"id":"n1821015014","loc":[-85.5515632,42.0130187]},"n1821015015":{"id":"n1821015015","loc":[-85.6024058,41.9765212]},"n1821015017":{"id":"n1821015017","loc":[-85.5175032,42.0357156]},"n1821015018":{"id":"n1821015018","loc":[-85.5302718,42.0236039]},"n1821015019":{"id":"n1821015019","loc":[-85.6024005,41.9782759]},"n1821015020":{"id":"n1821015020","loc":[-85.5907758,41.9890821]},"n1821015021":{"id":"n1821015021","loc":[-85.6019445,41.9777215]},"n1821015022":{"id":"n1821015022","loc":[-85.5942854,41.9800881]},"n1821015024":{"id":"n1821015024","loc":[-85.5325826,42.0222711]},"n1821015029":{"id":"n1821015029","loc":[-85.555093,42.0105316]},"n1821015033":{"id":"n1821015033","loc":[-85.5249704,42.0270372]},"n1821015034":{"id":"n1821015034","loc":[-85.5243965,42.0272205]},"n1821015038":{"id":"n1821015038","loc":[-85.5413426,42.0190749]},"n1821015039":{"id":"n1821015039","loc":[-85.5920431,41.9848175]},"n1821015041":{"id":"n1821015041","loc":[-85.5577685,42.0106015]},"n1821015042":{"id":"n1821015042","loc":[-85.5453606,42.0158866]},"n1821015045":{"id":"n1821015045","loc":[-85.5333228,42.0217889]},"n1821015046":{"id":"n1821015046","loc":[-85.5426891,42.0175924]},"n1821015048":{"id":"n1821015048","loc":[-85.5886836,41.9936474]},"n1821015050":{"id":"n1821015050","loc":[-85.6001152,41.9786467]},"n1821015051":{"id":"n1821015051","loc":[-85.6094064,41.9723655]},"n1821015053":{"id":"n1821015053","loc":[-85.605721,41.9749738]},"n1821015055":{"id":"n1821015055","loc":[-85.6106791,41.9705048]},"n1821015057":{"id":"n1821015057","loc":[-85.5210437,42.0307071]},"n1821015059":{"id":"n1821015059","loc":[-85.5995694,41.9786725]},"n1821015060":{"id":"n1821015060","loc":[-85.5371638,42.0182938]},"n1821015062":{"id":"n1821015062","loc":[-85.6111766,41.9704593]},"n1821015065":{"id":"n1821015065","loc":[-85.577704,42.0034921]},"n1821015067":{"id":"n1821015067","loc":[-85.5570067,42.0093699]},"n1821015068":{"id":"n1821015068","loc":[-85.5920364,41.9845525]},"n1821015069":{"id":"n1821015069","loc":[-85.5252065,42.0253954]},"n1821015072":{"id":"n1821015072","loc":[-85.5664159,42.0088517]},"n1821015073":{"id":"n1821015073","loc":[-85.5880399,41.991905]},"n1821015075":{"id":"n1821015075","loc":[-85.6099871,41.9727861]},"n1821015076":{"id":"n1821015076","loc":[-85.5319603,42.0231478]},"n1821015078":{"id":"n1821015078","loc":[-85.6036088,41.9751112]},"n1821015080":{"id":"n1821015080","loc":[-85.5983128,41.9789179]},"n1821015082":{"id":"n1821015082","loc":[-85.5614069,42.0071395]},"n1821015083":{"id":"n1821015083","loc":[-85.60968,41.9709738]},"n1821015086":{"id":"n1821015086","loc":[-85.5914195,41.9837351]},"n1821015087":{"id":"n1821015087","loc":[-85.5895473,41.9948036]},"n1821015090":{"id":"n1821015090","loc":[-85.5929913,41.9851905]},"n1821015093":{"id":"n1821015093","loc":[-85.5907396,41.9838485]},"n1821015095":{"id":"n1821015095","loc":[-85.5893864,41.9880176]},"n1821015096":{"id":"n1821015096","loc":[-85.5788024,42.0039807]},"n1821015097":{"id":"n1821015097","loc":[-85.5630592,42.0078411]},"n1821015098":{"id":"n1821015098","loc":[-85.5350609,42.0211274]},"n1821015099":{"id":"n1821015099","loc":[-85.5967195,41.9808679]},"n1821015100":{"id":"n1821015100","loc":[-85.5666734,42.0088119]},"n1821015101":{"id":"n1821015101","loc":[-85.564694,42.0077675]},"n1821015103":{"id":"n1821015103","loc":[-85.6066544,41.9726527]},"n1821015104":{"id":"n1821015104","loc":[-85.6011827,41.9769838]},"n1821015105":{"id":"n1821015105","loc":[-85.5972131,41.9776697]},"n1821015106":{"id":"n1821015106","loc":[-85.5880828,41.9903341]},"n1821015107":{"id":"n1821015107","loc":[-85.5510268,42.0130626]},"n1821015108":{"id":"n1821015108","loc":[-85.6102164,41.970543]},"n1821015109":{"id":"n1821015109","loc":[-85.5905344,41.9853899]},"n1821015111":{"id":"n1821015111","loc":[-85.5888821,41.9913429]},"n1821015112":{"id":"n1821015112","loc":[-85.606295,41.9741921]},"n1821015114":{"id":"n1821015114","loc":[-85.5969556,41.9807443]},"n1821015115":{"id":"n1821015115","loc":[-85.5882223,41.9934081]},"n1821015116":{"id":"n1821015116","loc":[-85.6104471,41.9724971]},"n1821015118":{"id":"n1821015118","loc":[-85.5406091,42.0192162]},"n1821015120":{"id":"n1821015120","loc":[-85.589955,41.9888429]},"n1821015121":{"id":"n1821015121","loc":[-85.5598821,42.0092304]},"n1821015122":{"id":"n1821015122","loc":[-85.545598,42.0144097]},"n1821015123":{"id":"n1821015123","loc":[-85.5649528,42.0079965]},"n1821015125":{"id":"n1821015125","loc":[-85.5883993,41.9917814]},"n1821015126":{"id":"n1821015126","loc":[-85.5295785,42.0239967]},"n1821015129":{"id":"n1821015129","loc":[-85.5648723,42.0078809]},"n1821015132":{"id":"n1821015132","loc":[-85.564989,42.0081103]},"n1821015133":{"id":"n1821015133","loc":[-85.5946127,41.9800841]},"n1821015134":{"id":"n1821015134","loc":[-85.583448,42.0019078]},"n1821015135":{"id":"n1821015135","loc":[-85.5905934,41.9871842]},"n1821015137":{"id":"n1821015137","loc":[-85.610608,41.9704752]},"n1821015138":{"id":"n1821015138","loc":[-85.5752257,42.0052939]},"n1821015139":{"id":"n1821015139","loc":[-85.5893864,41.9943491]},"n1821015140":{"id":"n1821015140","loc":[-85.5426247,42.0169866]},"n1821015141":{"id":"n1821015141","loc":[-85.562001,42.0074526]},"n1821015142":{"id":"n1821015142","loc":[-85.5212046,42.0301094]},"n1821015143":{"id":"n1821015143","loc":[-85.602214,41.9784531]},"n1821015144":{"id":"n1821015144","loc":[-85.5858687,41.9948293]},"n1821015145":{"id":"n1821015145","loc":[-85.5608477,42.0074805]},"n1821015146":{"id":"n1821015146","loc":[-85.5651607,42.0083614]},"n1821015147":{"id":"n1821015147","loc":[-85.5288288,42.0242495]},"n1821015149":{"id":"n1821015149","loc":[-85.5450334,42.0146989]},"n1821015151":{"id":"n1821015151","loc":[-85.5578275,42.0092304]},"n1821015154":{"id":"n1821015154","loc":[-85.6056634,41.9724511]},"n1821015155":{"id":"n1821015155","loc":[-85.5902179,41.9852742]},"n1821015156":{"id":"n1821015156","loc":[-85.5156256,42.0387157]},"n1821015157":{"id":"n1821015157","loc":[-85.5734433,42.0059459]},"n1821015158":{"id":"n1821015158","loc":[-85.6050773,41.9731273]},"n1821015160":{"id":"n1821015160","loc":[-85.5223419,42.0275233]},"n1821015163":{"id":"n1821015163","loc":[-85.6053562,41.972525]},"n1821015164":{"id":"n1821015164","loc":[-85.5850412,41.9946082]},"n1821015165":{"id":"n1821015165","loc":[-85.5359031,42.0186326]},"n1821015166":{"id":"n1821015166","loc":[-85.5608745,42.0077635]},"n1821015169":{"id":"n1821015169","loc":[-85.572876,42.0073189]},"n1821015171":{"id":"n1821015171","loc":[-85.5875424,41.9919188]},"n1821015172":{"id":"n1821015172","loc":[-85.5240116,42.0272581]},"n1821015173":{"id":"n1821015173","loc":[-85.5318369,42.0236818]},"n1821015174":{"id":"n1821015174","loc":[-85.566888,42.0086923]},"n1821015175":{"id":"n1821015175","loc":[-85.5931522,41.9850669]},"n1821015176":{"id":"n1821015176","loc":[-85.5604842,42.0093199]},"n1821015177":{"id":"n1821015177","loc":[-85.5868168,41.9927543]},"n1821015178":{"id":"n1821015178","loc":[-85.6052275,41.9732549]},"n1821015179":{"id":"n1821015179","loc":[-85.5910118,41.9900431]},"n1821015182":{"id":"n1821015182","loc":[-85.5610032,42.0082897]},"n1821015183":{"id":"n1821015183","loc":[-85.5425443,42.0179431]},"n1821015184":{"id":"n1821015184","loc":[-85.5843277,42.0014055]},"n1821015186":{"id":"n1821015186","loc":[-85.5733307,42.0063564]},"n1821015188":{"id":"n1821015188","loc":[-85.5277385,42.0248694]},"n1821015189":{"id":"n1821015189","loc":[-85.5558427,42.0108168]},"n1821015190":{"id":"n1821015190","loc":[-85.5650587,42.0082618]},"n1821015191":{"id":"n1821015191","loc":[-85.5660351,42.0088278]},"n1821015192":{"id":"n1821015192","loc":[-85.5849768,41.9980049]},"n1821015194":{"id":"n1821015194","loc":[-85.5359139,42.0188199]},"n1821015195":{"id":"n1821015195","loc":[-85.593238,41.9849194]},"n1821015197":{"id":"n1821015197","loc":[-85.5850841,41.9983239]},"n1821015199":{"id":"n1821015199","loc":[-85.5983396,41.9794283]},"n1821015204":{"id":"n1821015204","loc":[-85.5452801,42.0145355]},"n1821015205":{"id":"n1821015205","loc":[-85.5340685,42.0218407]},"n1821015207":{"id":"n1821015207","loc":[-85.5773272,42.0034186]},"n1821015209":{"id":"n1821015209","loc":[-85.5535212,42.0132419]},"n1821015211":{"id":"n1821015211","loc":[-85.6107703,41.9706045]},"n1821015212":{"id":"n1821015212","loc":[-85.6030066,41.9758193]},"n1821015213":{"id":"n1821015213","loc":[-85.5359943,42.0184213]},"n1821015214":{"id":"n1821015214","loc":[-85.5922993,41.9813305]},"n1821015215":{"id":"n1821015215","loc":[-85.5672689,42.0080465]},"n1821015217":{"id":"n1821015217","loc":[-85.5160494,42.0365682]},"n1821015218":{"id":"n1821015218","loc":[-85.5401142,42.0190351]},"n1821015219":{"id":"n1821015219","loc":[-85.5607632,42.0092282]},"n1821015220":{"id":"n1821015220","loc":[-85.5866197,41.9947894]},"n1821015221":{"id":"n1821015221","loc":[-85.6017889,41.9765132]},"n1821015222":{"id":"n1821015222","loc":[-85.5595978,42.009059]},"n1821015226":{"id":"n1821015226","loc":[-85.5871494,41.9929018]},"n1821015227":{"id":"n1821015227","loc":[-85.5857708,41.9998866]},"n1821015228":{"id":"n1821015228","loc":[-85.5317135,42.0238094]},"n1821015231":{"id":"n1821015231","loc":[-85.5733521,42.0061372]},"n1821015233":{"id":"n1821015233","loc":[-85.5855991,42.0001936]},"n1821015234":{"id":"n1821015234","loc":[-85.5213924,42.029962]},"n1821015235":{"id":"n1821015235","loc":[-85.6052221,41.9726567]},"n1821015236":{"id":"n1821015236","loc":[-85.5763723,42.0035422]},"n1821015237":{"id":"n1821015237","loc":[-85.5858512,41.9966215]},"n1821015238":{"id":"n1821015238","loc":[-85.567061,42.008439]},"n1821015239":{"id":"n1821015239","loc":[-85.5250563,42.0269057]},"n1821015240":{"id":"n1821015240","loc":[-85.5347551,42.0214263]},"n1821015241":{"id":"n1821015241","loc":[-85.6098463,41.9707066]},"n1821015242":{"id":"n1821015242","loc":[-85.5676927,42.0076519]},"n1821015243":{"id":"n1821015243","loc":[-85.516775,42.0322669]},"n1821015244":{"id":"n1821015244","loc":[-85.5762275,42.0036538]},"n1821015245":{"id":"n1821015245","loc":[-85.5583639,42.0090949]},"n1821015246":{"id":"n1821015246","loc":[-85.5554041,42.0106432]},"n1821015247":{"id":"n1821015247","loc":[-85.5973364,41.9776099]},"n1821015248":{"id":"n1821015248","loc":[-85.6098945,41.9717513]},"n1821015249":{"id":"n1821015249","loc":[-85.6045315,41.9751511]},"n1821015250":{"id":"n1821015250","loc":[-85.5579938,42.0092264]},"n1821015253":{"id":"n1821015253","loc":[-85.6058873,41.9724652]},"n1821015254":{"id":"n1821015254","loc":[-85.5869456,41.9947517]},"n1821015255":{"id":"n1821015255","loc":[-85.5936565,41.9823713]},"n1821015256":{"id":"n1821015256","loc":[-85.5218269,42.0278102]},"n1821015258":{"id":"n1821015258","loc":[-85.5887802,41.9905534]},"n1821015259":{"id":"n1821015259","loc":[-85.5901924,41.9904515]},"n1821015263":{"id":"n1821015263","loc":[-85.5249222,42.0255787]},"n1821015265":{"id":"n1821015265","loc":[-85.5175206,42.0321672]},"n1821015266":{"id":"n1821015266","loc":[-85.5275722,42.0254034]},"n1821015267":{"id":"n1821015267","loc":[-85.6016226,41.9765451]},"n1821015269":{"id":"n1821015269","loc":[-85.5569316,42.011032]},"n1821015271":{"id":"n1821015271","loc":[-85.6010714,41.9785209]},"n1821015272":{"id":"n1821015272","loc":[-85.6050666,41.9729917]},"n1821015273":{"id":"n1821015273","loc":[-85.5891235,41.99529]},"n1821015274":{"id":"n1821015274","loc":[-85.515454,42.0376439]},"n1821015276":{"id":"n1821015276","loc":[-85.5776021,42.0034443]},"n1821015277":{"id":"n1821015277","loc":[-85.6041707,41.9751453]},"n1821015278":{"id":"n1821015278","loc":[-85.5444701,42.0167435]},"n1821015280":{"id":"n1821015280","loc":[-85.5923274,41.9852202]},"n1821015283":{"id":"n1821015283","loc":[-85.5893649,41.9900271]},"n1821015284":{"id":"n1821015284","loc":[-85.5933453,41.9804412]},"n1821015285":{"id":"n1821015285","loc":[-85.5247237,42.026017]},"n1821015286":{"id":"n1821015286","loc":[-85.5286182,42.0242477]},"n1821015287":{"id":"n1821015287","loc":[-85.5904003,41.9888549]},"n1821015288":{"id":"n1821015288","loc":[-85.6062146,41.9739369]},"n1821015290":{"id":"n1821015290","loc":[-85.5762596,42.0052602]},"n1821015292":{"id":"n1821015292","loc":[-85.5849715,41.9975465]},"n1821015293":{"id":"n1821015293","loc":[-85.585229,42.0006241]},"n1821015294":{"id":"n1821015294","loc":[-85.5926922,41.9805946]},"n1821015295":{"id":"n1821015295","loc":[-85.5703387,42.0089133]},"n1821015299":{"id":"n1821015299","loc":[-85.5789955,42.0038611]},"n1821015301":{"id":"n1821015301","loc":[-85.6072888,41.9721918]},"n1821015302":{"id":"n1821015302","loc":[-85.5356349,42.0200992]},"n1821015304":{"id":"n1821015304","loc":[-85.5891772,41.994066]},"n1821015306":{"id":"n1821015306","loc":[-85.606295,41.9744952]},"n1821015307":{"id":"n1821015307","loc":[-85.538871,42.0186583]},"n1821015308":{"id":"n1821015308","loc":[-85.587997,41.994971]},"n1821015311":{"id":"n1821015311","loc":[-85.606869,41.9725809]},"n1821015312":{"id":"n1821015312","loc":[-85.5171974,42.0339943]},"n1821015314":{"id":"n1821015314","loc":[-85.5327435,42.0220479]},"n1821015315":{"id":"n1821015315","loc":[-85.5383439,42.0187282]},"n1821015316":{"id":"n1821015316","loc":[-85.5248095,42.0263119]},"n1821015318":{"id":"n1821015318","loc":[-85.5732502,42.0073051]},"n1821015319":{"id":"n1821015319","loc":[-85.5924226,41.9852663]},"n1821015321":{"id":"n1821015321","loc":[-85.5179001,42.0353052]},"n1821015322":{"id":"n1821015322","loc":[-85.5456771,42.0162413]},"n1821015323":{"id":"n1821015323","loc":[-85.5936618,41.9829096]},"n1821015325":{"id":"n1821015325","loc":[-85.5656931,42.0086582]},"n1821015326":{"id":"n1821015326","loc":[-85.5448456,42.0150975]},"n1821015327":{"id":"n1821015327","loc":[-85.5220039,42.027615]},"n1821015329":{"id":"n1821015329","loc":[-85.517884,42.0354885]},"n1821015330":{"id":"n1821015330","loc":[-85.5576666,42.0101671]},"n1821015332":{"id":"n1821015332","loc":[-85.5368754,42.0181402]},"n1821015333":{"id":"n1821015333","loc":[-85.5367078,42.0181145]},"n1821015334":{"id":"n1821015334","loc":[-85.5903909,41.9904316]},"n1821015335":{"id":"n1821015335","loc":[-85.5430767,42.0163587]},"n1821015336":{"id":"n1821015336","loc":[-85.5277492,42.0252878]},"n1821015337":{"id":"n1821015337","loc":[-85.5312146,42.0236898]},"n1821015338":{"id":"n1821015338","loc":[-85.5886568,41.991614]},"n1821015339":{"id":"n1821015339","loc":[-85.5782498,42.0040883]},"n1821015341":{"id":"n1821015341","loc":[-85.562233,42.0076457]},"n1821015342":{"id":"n1821015342","loc":[-85.588626,41.9952479]},"n1821015343":{"id":"n1821015343","loc":[-85.5762865,42.005033]},"n1821015344":{"id":"n1821015344","loc":[-85.5850841,41.9971478]},"n1821015346":{"id":"n1821015346","loc":[-85.5643144,42.0076936]},"n1821015347":{"id":"n1821015347","loc":[-85.5164893,42.0359467]},"n1821015348":{"id":"n1821015348","loc":[-85.5906846,41.9903541]},"n1821015349":{"id":"n1821015349","loc":[-85.557688,42.0107769]},"n1821015350":{"id":"n1821015350","loc":[-85.5363698,42.0181424]},"n1821015351":{"id":"n1821015351","loc":[-85.5939636,41.9801918]},"n1821015352":{"id":"n1821015352","loc":[-85.5524041,42.0131644]},"n1821015354":{"id":"n1821015354","loc":[-85.5308606,42.0236221]},"n1821015355":{"id":"n1821015355","loc":[-85.5877449,41.9932367]},"n1821015356":{"id":"n1821015356","loc":[-85.519885,42.0318586]},"n1821015357":{"id":"n1821015357","loc":[-85.5454035,42.0168431]},"n1821015358":{"id":"n1821015358","loc":[-85.5970629,41.9781881]},"n1821015359":{"id":"n1821015359","loc":[-85.5932541,41.9844767]},"n1821015360":{"id":"n1821015360","loc":[-85.5970736,41.9778252]},"n1821015361":{"id":"n1821015361","loc":[-85.537031,42.0181601]},"n1821015362":{"id":"n1821015362","loc":[-85.5548355,42.0105156]},"n1821015363":{"id":"n1821015363","loc":[-85.5168648,42.0336158]},"n1821015365":{"id":"n1821015365","loc":[-85.5870435,41.9919507]},"n1821015366":{"id":"n1821015366","loc":[-85.5719681,42.0075443]},"n1821015367":{"id":"n1821015367","loc":[-85.5969985,41.9780446]},"n1821015368":{"id":"n1821015368","loc":[-85.5926761,41.98528]},"n1821015369":{"id":"n1821015369","loc":[-85.5224009,42.0293444]},"n1821015371":{"id":"n1821015371","loc":[-85.518737,42.0322651]},"n1821015372":{"id":"n1821015372","loc":[-85.6064573,41.9726465]},"n1821015373":{"id":"n1821015373","loc":[-85.5201103,42.0313088]},"n1821015375":{"id":"n1821015375","loc":[-85.5378182,42.0186844]},"n1821015376":{"id":"n1821015376","loc":[-85.6109741,41.9706882]},"n1821015377":{"id":"n1821015377","loc":[-85.5993333,41.9785488]},"n1821015378":{"id":"n1821015378","loc":[-85.5889787,41.9907368]},"n1821015380":{"id":"n1821015380","loc":[-85.6060161,41.9737375]},"n1821015381":{"id":"n1821015381","loc":[-85.5743016,42.0053679]},"n1821015382":{"id":"n1821015382","loc":[-85.6014724,41.9776099]},"n1821015383":{"id":"n1821015383","loc":[-85.5574426,42.0091644]},"n1821015385":{"id":"n1821015385","loc":[-85.5208613,42.0309302]},"n1821015386":{"id":"n1821015386","loc":[-85.5919023,41.9837789]},"n1821015387":{"id":"n1821015387","loc":[-85.5455484,42.0160221]},"n1821015392":{"id":"n1821015392","loc":[-85.5801757,42.0028964]},"n1821015395":{"id":"n1821015395","loc":[-85.5493785,42.0139974]},"n1821015396":{"id":"n1821015396","loc":[-85.5449475,42.015488]},"n1821015398":{"id":"n1821015398","loc":[-85.611123,41.9706627]},"n1821015400":{"id":"n1821015400","loc":[-85.5935706,41.9822477]},"n1821015401":{"id":"n1821015401","loc":[-85.5724254,42.0073508]},"n1821015403":{"id":"n1821015403","loc":[-85.5486812,42.0143442]},"n1821015404":{"id":"n1821015404","loc":[-85.5161835,42.0327711]},"n1821015406":{"id":"n1821015406","loc":[-85.5921705,41.9851107]},"n1821015407":{"id":"n1821015407","loc":[-85.531912,42.0234069]},"n1821015410":{"id":"n1821015410","loc":[-85.5292566,42.024176]},"n1821015411":{"id":"n1821015411","loc":[-85.5845316,41.9948315]},"n1821015413":{"id":"n1821015413","loc":[-85.5217947,42.0280413]},"n1821015414":{"id":"n1821015414","loc":[-85.5527367,42.013272]},"n1821015415":{"id":"n1821015415","loc":[-85.5191179,42.0321973]},"n1821015416":{"id":"n1821015416","loc":[-85.5540241,42.0128655]},"n1821015418":{"id":"n1821015418","loc":[-85.5272892,42.0254849]},"n1821015419":{"id":"n1821015419","loc":[-85.5449744,42.016867]},"n1821015420":{"id":"n1821015420","loc":[-85.5852665,41.9986787]},"n1821015421":{"id":"n1821015421","loc":[-85.6102701,41.972186]},"n1821015423":{"id":"n1821015423","loc":[-85.6026365,41.9764972]},"n1821015427":{"id":"n1821015427","loc":[-85.5898692,41.9841498]},"n1821015429":{"id":"n1821015429","loc":[-85.5422546,42.0183855]},"n1821015430":{"id":"n1821015430","loc":[-85.5866505,41.9925549]},"n1821015431":{"id":"n1821015431","loc":[-85.5234376,42.0273577]},"n1821015432":{"id":"n1821015432","loc":[-85.6096746,41.9727284]},"n1821015433":{"id":"n1821015433","loc":[-85.5824891,42.0021567]},"n1821015434":{"id":"n1821015434","loc":[-85.5923905,41.9841139]},"n1821015435":{"id":"n1821015435","loc":[-85.5874565,41.9948014]},"n1821015437":{"id":"n1821015437","loc":[-85.6055279,41.9734423]},"n1821015438":{"id":"n1821015438","loc":[-85.5299379,42.0237376]},"n1821015439":{"id":"n1821015439","loc":[-85.5155022,42.0383651]},"n1821015442":{"id":"n1821015442","loc":[-85.527422,42.0254711]},"n1821015443":{"id":"n1821015443","loc":[-85.5920699,41.9849291]},"n1821015444":{"id":"n1821015444","loc":[-85.5639711,42.0077494]},"n1821015445":{"id":"n1821015445","loc":[-85.5162586,42.0361777]},"n1821015446":{"id":"n1821015446","loc":[-85.5220039,42.029695]},"n1821015448":{"id":"n1821015448","loc":[-85.5176641,42.0356956]},"n1821015449":{"id":"n1821015449","loc":[-85.5930556,41.9841577]},"n1821015451":{"id":"n1821015451","loc":[-85.5320783,42.0228848]},"n1821015452":{"id":"n1821015452","loc":[-85.5170096,42.0357235]},"n1821015453":{"id":"n1821015453","loc":[-85.5571355,42.009613]},"n1821015454":{"id":"n1821015454","loc":[-85.5609979,42.009059]},"n1821015455":{"id":"n1821015455","loc":[-85.6097336,41.9708342]},"n1821015456":{"id":"n1821015456","loc":[-85.5884476,41.9904218]},"w170843846":{"id":"w170843846","tags":{"waterway":"river"},"nodes":["n1819790555","n1819790762","n1819790547","n1819790618","n1819790898","n1819790796","n1819790534","n1819790543","n1819790541","n1819790687","n1819790877","n1819790811","n1819790670"]},"w209083541":{"id":"w209083541","tags":{"name":"Portage River","waterway":"river"},"nodes":["n1821014848","n1821015156","n1821015439","n1821014763","n1821014824","n1821015274","n1821014764","n1821014791","n1821014957","n1821015217","n1821015445","n1821015347","n1821014893","n1821015452","n1821015017","n1821015448","n1821014968","n1821015329","n1821015321","n1821014992","n1821014948","n1821014757","n1821014983","n1821015312","n1821015363","n1821014924","n1821014873","n1821014932","n1821014668","n1821015404","n1821014716","n1821015243","n1821015265","n1821014710","n1821015371","n1821015415","n1821014870","n1821015356","n1821015373","n1821014681","n1821014714","n1821015385","n1821014911","n1821015057","n1821014867","n1821014998","n1821015142","n1821015234","n1821015446","n1821014862","n1821015369","n1821014945","n1821015003","n1821014667","n1821015413","n1821015256","n1821015327","n1821015160","n1821014907","n1821015431","n1821015172","n1821015034","n1821014741","n1821015033","n1821015239","n1821015007","n1821015316","n1821015285","n1821014633","n1821015263","n1821015069","n1821014846","n1821014779","n1821015011","n1821015012","n1821014845","n1821015418","n1821015442","n1821015266","n1821015336","n1821014755","n1821015188","n1821014925","n1821014816","n1821014869","n1821014967","n1821015286","n1821015147","n1821015410","n1821015126","n1821015438","n1821015018","n1821015354","n1821015337","n1821014766","n1821014740","n1821015228","n1821015173","n1821015407","n1821015076","n1821015451","n1821015024","n1821015314","n1821014784","n1821015045","n1821014735","n1821015205","n1821014986","n1821015240","n1821015098","n1821014825","n1821015302","n1821014918","n1821014718","n1821014896","n1821014853","n1821015194","n1821015165","n1821015213","n1821014991","n1821015350","n1821015333","n1821015332","n1821015361","n1821015060","n1821014914","n1821015375","n1821015315","n1821015307","n1821014906","n1821014751","n1821014666","n1821015218","n1821014817","n1821015118","n1821014674","n1821015038","n1821014973","n1821015429","n1821015183","n1821015046","n1821014803","n1821015140","n1821015009","n1821014749","n1821015335","n1821014711","n1821014854","n1821015278","n1821015419","n1821014648","n1821015357","n1821014637","n1821014988","n1821015322","n1821015387","n1821015042","n1821014833","n1821015396","n1821015326","n1821014691","n1821015149","n1821015204","n1821015122","n1821014782","n1821014982","n1821014921","n1821014936","n1821014969","n1821014881","n1821015403","n1821014805","n1821015395","n1821014892","n1821014826","n1821014844","n1821015107","n1821015014","n1821014955","n1821015352","n1821015414","n1821014746","n1821015209","n1821014770","n1821015416","n1821014661","n1821014857","n1821014814","n1821014754","n1821014721","n1821014727","n1821015362","n1821015029","n1821015246","n1821015189","n1821014627","n1821015269","n1821014808","n1821014962","n1821015349","n1821015041","n1821014722","n1821015330","n1821015453","n1821015067","n1821014643","n1821014802","n1821015383","n1821015151","n1821015250","n1821015245","n1821014772","n1821014899","n1821015222","n1821015121","n1821014951","n1821015176","n1821015219","n1821015454","n1821014972","n1821014917","n1821015182","n1821015166","n1821015145","n1821014910","n1821015082","n1821014678","n1821014806","n1821015141","n1821015341","n1821014788","n1821015097","n1821014995","n1821015444","n1821015346","n1821015101","n1821015129","n1821015123","n1821015132","n1821015190","n1821015146","n1821015325","n1821015191","n1821015072","n1821015100","n1821015174","n1821015238","n1821015215","n1821014700","n1821015242","n1821014841","n1821014905","n1821014874","n1821014883","n1821014729","n1821014866","n1821014828","n1821015295","n1821014931","n1821014859","n1821014912","n1821014783","n1821014752","n1821014961","n1821015366","n1821015401","n1821015169","n1821015318","n1821014996","n1821014747","n1821014963","n1821014670","n1821015186","n1821015231","n1821015157","n1821014812","n1821015381","n1821014887","n1821015138","n1821014704","n1821014787","n1821014922","n1821015290","n1821015343","n1821014651","n1821014980","n1821014960","n1821015244","n1821015236","n1821015006","n1821014694","n1821014759","n1821015207","n1821015276","n1821015065","n1821014863","n1821014660","n1821014902","n1821014645","n1821015339","n1821014871","n1821015096","n1821015299","n1821014798","n1821014638","n1821015392","n1821014835","n1821014762","n1821014642","n1821015433","n1821014786","n1821015134","n1821014855","n1821015184","n1821014850","n1821015293","n1821015233","n1821015227","n1821014876","n1821014985","n1821014843","n1821015420","n1821015197","n1821015192","n1821015292","n1821015344","n1821014742","n1821014726","n1821015237","n1821014796","n1821014908","n1821014975","n1821014769","n1821014688","n1821014860","n1821014895","n1821014676","n1821015411","n1821014736","n1821015164","n1821014647","n1821015144","n1821014919","n1821015220","n1821015254","n1821015435","n1821015308","n1821015342","n1821014830","n1821015273","n1821014658","n1821014781","n1821015087","n1821015139","n1821015304","n1821014839","n1821015048","n1821015115","n1821015355","n1821015226","n1821015177","n1821015430","n1821014965","n1821014725","n1821015365","n1821015171","n1821015073","n1821015125","n1821015338","n1821015111","n1821014950","n1821015378","n1821015258","n1821015456","n1821015106","n1821014832","n1821014888","n1821014795","n1821014872","n1821014810","n1821014705","n1821014804","n1821014820","n1821015283","n1821014938","n1821014689","n1821015259","n1821015334","n1821015348","n1821014635","n1821015179","n1821014864","n1821014890","n1821015020","n1821014898","n1821015287","n1821015120","n1821014984","n1821014743","n1821014790","n1821014765","n1821014777","n1821015095","n1821014653","n1821015135","n1821014836","n1821014964","n1821014974","n1821014636","n1821014682","n1821014663","n1821014665","n1821015109","n1821015155","n1821014930","n1821014669","n1821015004","n1821015427","n1821014916","n1821015093","n1821015086","n1821015386","n1821014799","n1821014913","n1821015434","n1821014728","n1821014900","n1821015068","n1821015039","n1821015443","n1821015406","n1821015280","n1821015319","n1821015368","n1821014774","n1821015090","n1821015175","n1821015195","n1821014687","n1821015359","n1821015449","n1821014956","n1821014838","n1821014768","n1821014698","n1821015323","n1821014756","n1821015255","n1821015400","n1821014717","n1821014868","n1821014778","n1821015214","n1821014944","n1821014697","n1821014671","n1821014928","n1821015294","n1821014822","n1821015284","n1821015351","n1821015022","n1821015133","n1821014644","n1821015010","n1821014625","n1821014657","n1821014946","n1821015099","n1821015114","n1821014629","n1821014865","n1821014997","n1821014926","n1821014933","n1821015199","n1821014819","n1821015080","n1821014692","n1821014677","n1821015358","n1821015367","n1821015360","n1821015105","n1821015247","n1821015005","n1821014809","n1821014794","n1821014761","n1821014879","n1821014801","n1821015377","n1821015059","n1821014730","n1821015050","n1821015271","n1821015143","n1821014989","n1821015019","n1821014672","n1821014649","n1821014684","n1821014703","n1821015021","n1821015382","n1821014842","n1821014720","n1821014847","n1821015104","n1821014987","n1821014886","n1821015267","n1821015221","n1821015015","n1821015423","n1821014954","n1821014903","n1821014939","n1821015212","n1821014789","n1821014712","n1821014708","n1821015078","n1821015277","n1821015249","n1821014646","n1821014793","n1821015053","n1821014707","n1821015306","n1821015112","n1821015288","n1821015380","n1821015437","n1821015178","n1821015158","n1821015272","n1821015235","n1821015163","n1821015154","n1821015253","n1821014632","n1821015372","n1821015103","n1821015311","n1821015301","n1821014885","n1821014811","n1821014977","n1821015051","n1821014942","n1821014745","n1821015432","n1821015075","n1821014664","n1821014695","n1821015116","n1821014639","n1821015421","n1821015248","n1821014758","n1821014834","n1821015083","n1821015455","n1821015241","n1821015108","n1821014713","n1821015137","n1821015055","n1821015211","n1821014904","n1821015376","n1821015398","n1821014771","n1821014840","n1821015062","n1819790554","n1819790560","n1819790767","n1819790696","n1819790706","n1819790606","n1819790607","n1819790544","n1819790779","n1819790760","n1819790926","n1819790927","n1819790647","n1819790657","n1819790649","n1819790679","n1819790915","n1819790739","n1819790549","n1819790671","n1819790686","n1819790798","n1819790791","n1819790563","n1819790720","n1819790704","n1819790795","n1819790836","n1819790622","n1819790615","n1819790654","n1819790931","n1819790595","n1819790753","n1819790612","n1819790623","n1819790564","n1819790552","n1819790645","n1819790625","n1819790605","n1819790668","n1819790731","n1819790718","n1819790781","n1819790665","n1819790659","n1819790726","n1819790642","n1819790854","n1819790697","n1819790867","n1819790833","n1819790555","n1819790774","n1819790881","n1819790530","n1819790909","n1819790891","n1819790590","n1819790738","n1819790609","n1819790528","n1819790674","n1819790583","n1819790559","n1819790863","n1819790912","n1819790685","n1819790913"]},"n185955128":{"id":"n185955128","loc":[-85.6189367,41.9519432]},"n185948818":{"id":"n185948818","loc":[-85.616755,41.952231]},"n185978819":{"id":"n185978819","loc":[-85.616773,41.954737]},"n185978821":{"id":"n185978821","loc":[-85.616699,41.954742]},"n2138420714":{"id":"n2138420714","loc":[-85.6176304,41.9515154]},"n2138420715":{"id":"n2138420715","loc":[-85.6177355,41.9515717]},"n2138420716":{"id":"n2138420716","loc":[-85.6192901,41.951573]},"n2138420718":{"id":"n2138420718","loc":[-85.6171481,41.9513579]},"n2138420719":{"id":"n2138420719","loc":[-85.6165981,41.9519199]},"n2138420720":{"id":"n2138420720","loc":[-85.6165719,41.9519922]},"n2138420721":{"id":"n2138420721","loc":[-85.6165832,41.9520757]},"n2138420722":{"id":"n2138420722","loc":[-85.6166355,41.9521453]},"n2138420723":{"id":"n2138420723","loc":[-85.6169161,41.9522788]},"n2138420724":{"id":"n2138420724","loc":[-85.6170882,41.9522538]},"n2138420725":{"id":"n2138420725","loc":[-85.6189204,41.9514674]},"n2138420726":{"id":"n2138420726","loc":[-85.6180346,41.9514735]},"n2138420727":{"id":"n2138420727","loc":[-85.6180362,41.9515719]},"n2138420728":{"id":"n2138420728","loc":[-85.6189204,41.9515727]},"n2138420744":{"id":"n2138420744","loc":[-85.618919,41.9519571]},"n2138420745":{"id":"n2138420745","loc":[-85.6194575,41.9522374]},"n2138420746":{"id":"n2138420746","loc":[-85.6181777,41.9536179]},"n2138420747":{"id":"n2138420747","loc":[-85.6176582,41.9533658]},"n2138420748":{"id":"n2138420748","loc":[-85.6179871,41.9530242]},"n2138420749":{"id":"n2138420749","loc":[-85.618429,41.9532476]},"n2138420750":{"id":"n2138420750","loc":[-85.6185538,41.9531194]},"n2138420751":{"id":"n2138420751","loc":[-85.6180765,41.9528677]},"n2138420752":{"id":"n2138420752","loc":[-85.6180394,41.9528855]},"n2138420753":{"id":"n2138420753","loc":[-85.6193752,41.9521695]},"n2138420754":{"id":"n2138420754","loc":[-85.6181374,41.9535376]},"n2138420755":{"id":"n2138420755","loc":[-85.6179898,41.9535545]},"n2138420756":{"id":"n2138420756","loc":[-85.6177286,41.9534228]},"n2138420757":{"id":"n2138420757","loc":[-85.6181011,41.9530292]},"n2138420759":{"id":"n2138420759","loc":[-85.6185158,41.9531194]},"n2138420760":{"id":"n2138420760","loc":[-85.6191318,41.9520425]},"n2138420761":{"id":"n2138420761","loc":[-85.6182348,41.9529815]},"n2138420762":{"id":"n2138420762","loc":[-85.6184853,41.9524248]},"n2138420763":{"id":"n2138420763","loc":[-85.6186764,41.9525193]},"n2138420764":{"id":"n2138420764","loc":[-85.6189421,41.9526483]},"n2138420765":{"id":"n2138420765","loc":[-85.6182875,41.9531222]},"n2138420766":{"id":"n2138420766","loc":[-85.6179141,41.9535163]},"n2138420767":{"id":"n2138420767","loc":[-85.6178363,41.9535735]},"n185948824":{"id":"n185948824","loc":[-85.6165667,41.9529715]},"n2138420758":{"id":"n2138420758","loc":[-85.6184408,41.953201]},"n2138422349":{"id":"n2138422349","loc":[-85.6175136,41.9533346]},"n2138422350":{"id":"n2138422350","loc":[-85.6171867,41.9531679]},"n2138422351":{"id":"n2138422351","loc":[-85.61722,41.9531305]},"n2138422352":{"id":"n2138422352","loc":[-85.6171889,41.9531158]},"n2138422353":{"id":"n2138422353","loc":[-85.6171733,41.9531284]},"n2138422354":{"id":"n2138422354","loc":[-85.616765,41.9529207]},"n2138422355":{"id":"n2138422355","loc":[-85.6167565,41.9529355]},"n2138422356":{"id":"n2138422356","loc":[-85.6164772,41.9527911]},"n2138422357":{"id":"n2138422357","loc":[-85.6168227,41.9524261]},"n2138422358":{"id":"n2138422358","loc":[-85.6171913,41.9526158]},"n2138422359":{"id":"n2138422359","loc":[-85.6172403,41.9525589]},"n2138422360":{"id":"n2138422360","loc":[-85.6172097,41.952542]},"n2138422361":{"id":"n2138422361","loc":[-85.6173948,41.9523512]},"n2138422362":{"id":"n2138422362","loc":[-85.6174256,41.9523678]},"n2138422363":{"id":"n2138422363","loc":[-85.6174831,41.9523086]},"n2138422364":{"id":"n2138422364","loc":[-85.6173316,41.9522289]},"n2138422365":{"id":"n2138422365","loc":[-85.6174507,41.9521024]},"n2138422366":{"id":"n2138422366","loc":[-85.6174773,41.9521155]},"n2138422367":{"id":"n2138422367","loc":[-85.6176577,41.9519232]},"n2138422368":{"id":"n2138422368","loc":[-85.6176336,41.9519105]},"n2138422369":{"id":"n2138422369","loc":[-85.617747,41.9517861]},"n2138422370":{"id":"n2138422370","loc":[-85.6182675,41.9520559]},"n2138422371":{"id":"n2138422371","loc":[-85.6182105,41.9521219]},"n2138422372":{"id":"n2138422372","loc":[-85.6183863,41.9522203]},"n2138422373":{"id":"n2138422373","loc":[-85.6180984,41.9525266]},"n2138422374":{"id":"n2138422374","loc":[-85.6179159,41.9524295]},"n2138422375":{"id":"n2138422375","loc":[-85.617854,41.9524979]},"n2138422376":{"id":"n2138422376","loc":[-85.6177686,41.9524531]},"n2138422377":{"id":"n2138422377","loc":[-85.6174716,41.9527765]},"n2138422378":{"id":"n2138422378","loc":[-85.6178545,41.9529756]},"n2138425424":{"id":"n2138425424","loc":[-85.6171736,41.9536385]},"n2138425425":{"id":"n2138425425","loc":[-85.6180159,41.9535782]},"n2138425426":{"id":"n2138425426","loc":[-85.6181068,41.9536282]},"n2138425427":{"id":"n2138425427","loc":[-85.6180673,41.9542678]},"n2138425428":{"id":"n2138425428","loc":[-85.6178636,41.9542634]},"n2138425429":{"id":"n2138425429","loc":[-85.6176204,41.9542046]},"n2138425430":{"id":"n2138425430","loc":[-85.6174366,41.9541031]},"n2138425431":{"id":"n2138425431","loc":[-85.6172942,41.9539781]},"n2138425432":{"id":"n2138425432","loc":[-85.6172171,41.9538399]},"n2138425433":{"id":"n2138425433","loc":[-85.6168138,41.9543266]},"n2138425434":{"id":"n2138425434","loc":[-85.6167779,41.9538098]},"n2138425435":{"id":"n2138425435","loc":[-85.6165849,41.9537073]},"n2138425441":{"id":"n2138425441","loc":[-85.616458,41.9543184]},"n2138425442":{"id":"n2138425442","loc":[-85.6166428,41.954345]},"n2138425445":{"id":"n2138425445","loc":[-85.6181332,41.9514117]},"n2138425446":{"id":"n2138425446","loc":[-85.6183263,41.9514111]},"n2138425447":{"id":"n2138425447","loc":[-85.6185033,41.9514102]},"n2138425449":{"id":"n2138425449","loc":[-85.6186809,41.9514093]},"n2138425451":{"id":"n2138425451","loc":[-85.6188681,41.9514082]},"n2138436008":{"id":"n2138436008","loc":[-85.6170474,41.9513604]},"n2138436009":{"id":"n2138436009","loc":[-85.6164937,41.9519586]},"n2138436010":{"id":"n2138436010","loc":[-85.616497,41.9520725]},"n2138436011":{"id":"n2138436011","loc":[-85.6165654,41.9521645]},"n2138436012":{"id":"n2138436012","loc":[-85.6166631,41.9522178]},"n2138436013":{"id":"n2138436013","loc":[-85.6167327,41.9522554]},"n2138436014":{"id":"n2138436014","loc":[-85.6172383,41.9525125]},"n2138439319":{"id":"n2138439319","loc":[-85.6170432,41.9524057]},"n2138439320":{"id":"n2138439320","loc":[-85.617691,41.9517107]},"n2138439321":{"id":"n2138439321","loc":[-85.6177727,41.9516794]},"n2138439322":{"id":"n2138439322","loc":[-85.619085,41.9516811]},"n2138439323":{"id":"n2138439323","loc":[-85.6179432,41.952895]},"n2138439324":{"id":"n2138439324","loc":[-85.6180389,41.9529384]},"n2138439325":{"id":"n2138439325","loc":[-85.6176303,41.9533604]},"n2138439326":{"id":"n2138439326","loc":[-85.6175538,41.9534396]},"n2138439327":{"id":"n2138439327","loc":[-85.6173806,41.9523658]},"n2138439328":{"id":"n2138439328","loc":[-85.6171841,41.9522542]},"n2138439329":{"id":"n2138439329","loc":[-85.6172077,41.9524958]},"n2138439330":{"id":"n2138439330","loc":[-85.6171235,41.9525809]},"n2138439331":{"id":"n2138439331","loc":[-85.6180938,41.9527349]},"n2138439332":{"id":"n2138439332","loc":[-85.6177023,41.9525253]},"n2138439333":{"id":"n2138439333","loc":[-85.6175543,41.9526865]},"n2138439334":{"id":"n2138439334","loc":[-85.6179589,41.9528783]},"n185948820":{"id":"n185948820","loc":[-85.6163249,41.952701]},"n185948822":{"id":"n185948822","loc":[-85.6163757,41.952855]},"n185955123":{"id":"n185955123","loc":[-85.6198103,41.9510408]},"n185958839":{"id":"n185958839","loc":[-85.611651,41.954761]},"n185965033":{"id":"n185965033","loc":[-85.614195,41.954754]},"n185976502":{"id":"n185976502","loc":[-85.617375,41.947559]},"n185976504":{"id":"n185976504","loc":[-85.6174164,41.9510804]},"n185978828":{"id":"n185978828","loc":[-85.613542,41.954756]},"n185978830":{"id":"n185978830","loc":[-85.610373,41.954774]},"n2138420713":{"id":"n2138420713","loc":[-85.6174641,41.9506942]},"n2138420717":{"id":"n2138420717","loc":[-85.6173027,41.9512895]},"n2138420768":{"id":"n2138420768","loc":[-85.61745,41.9501974]},"n2138420773":{"id":"n2138420773","loc":[-85.6174135,41.9489136]},"n2138425436":{"id":"n2138425436","loc":[-85.6159148,41.9538036]},"n2138425437":{"id":"n2138425437","loc":[-85.6159534,41.9539677]},"n2138425438":{"id":"n2138425438","loc":[-85.6160306,41.9540846]},"n2138425439":{"id":"n2138425439","loc":[-85.6161354,41.954181]},"n2138425440":{"id":"n2138425440","loc":[-85.6162733,41.954263]},"n2138425443":{"id":"n2138425443","loc":[-85.6183273,41.9510826]},"n2138425444":{"id":"n2138425444","loc":[-85.6181354,41.9510835]},"n2138425448":{"id":"n2138425448","loc":[-85.6185033,41.9510816]},"n2138425450":{"id":"n2138425450","loc":[-85.6186816,41.9510808]},"n2138425452":{"id":"n2138425452","loc":[-85.6188641,41.9510818]},"n2138435984":{"id":"n2138435984","loc":[-85.6167607,41.9501009]},"n2138436000":{"id":"n2138436000","loc":[-85.6173169,41.947558]},"n2138436001":{"id":"n2138436001","loc":[-85.6173362,41.948883]},"n2138436002":{"id":"n2138436002","loc":[-85.6167791,41.9492952]},"n2138436003":{"id":"n2138436003","loc":[-85.6167543,41.949349]},"n2138436004":{"id":"n2138436004","loc":[-85.6167648,41.9509125]},"n2138436005":{"id":"n2138436005","loc":[-85.6168832,41.9510412]},"n2138436006":{"id":"n2138436006","loc":[-85.6170045,41.9511417]},"n2138436007":{"id":"n2138436007","loc":[-85.6170624,41.9512483]},"n2138436017":{"id":"n2138436017","loc":[-85.6168094,41.9492729]},"n2138436021":{"id":"n2138436021","loc":[-85.6167553,41.9494886]},"n2138436023":{"id":"n2138436023","loc":[-85.6167585,41.9499707]},"n2138436025":{"id":"n2138436025","loc":[-85.6167567,41.9497018]},"w203838284":{"id":"w203838284","tags":{"area":"yes","leisure":"pitch","sport":"baseball"},"nodes":["n2138425424","n2138425425","n2138425426","n2138425427","n2138425428","n2138425429","n2138425430","n2138425431","n2138425432","n2138425424"]},"w203837928":{"id":"w203837928","tags":{"highway":"service"},"nodes":["n2138420717","n2138420718","n2138420719","n2138420720","n2138420721","n2138420722","n185948818","n2138420723","n2138420724","n2138420715"]},"w203839364":{"id":"w203839364","tags":{"highway":"footway"},"nodes":["n2138439331","n2138439332"]},"w203837932":{"id":"w203837932","tags":{"amenity":"parking","area":"yes"},"nodes":["n2138420744","n2138420745","n2138420746","n2138420747","n2138420748","n2138420749","n2138420750","n2138420751","n2138420744"]},"w203839362":{"id":"w203839362","tags":{"highway":"footway"},"nodes":["n2138439327","n2138439328"]},"w203839363":{"id":"w203839363","tags":{"highway":"footway"},"nodes":["n2138439329","n2138439330"]},"w203837933":{"id":"w203837933","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n185955128","n2138420760","n2138420753","n2138420764","n2138420759","n2138420758","n2138420754","n2138420755","n2138420766","n2138420756"]},"w203837936":{"id":"w203837936","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420765","n2138420766"]},"w17966364":{"id":"w17966364","tags":{"access":"private","highway":"service","name":"Collins Dr"},"nodes":["n185961362","n185976502","n2138420773","n2138420768","n2138420713","n185976504","n2138420717","n2138420714","n2138420715","n2138420727","n2138420728","n2138420716"]},"w203838040":{"id":"w203838040","tags":{"amenity":"school","area":"yes","building":"yes","name":"Three Rivers Middle School"},"nodes":["n2138422349","n2138422350","n2138422351","n2138422352","n2138422353","n2138422354","n2138422355","n2138422356","n2138422357","n2138439330","n2138422358","n2138422359","n2138422360","n2138436014","n2138439327","n2138422361","n2138422362","n2138422363","n2138422364","n2138422365","n2138422366","n2138422367","n2138422368","n2138422369","n2138422370","n2138422371","n2138422372","n2138422373","n2138422374","n2138422375","n2138422376","n2138439332","n2138439333","n2138422377","n2138422378","n2138422349"]},"w17964049":{"id":"w17964049","tags":{"highway":"service"},"nodes":["n185955120","n185955123","n2138420716","n185955128","n2138420762","n2138420752","n2138420761","n2138420759"]},"w41074899":{"id":"w41074899","tags":{"highway":"secondary","name":"E Hoffman St","ref":"M 60"},"nodes":["n185978817","n185978819","n185978821","n185965033","n185978828","n185958839","n185978830"]},"w203839365":{"id":"w203839365","tags":{"highway":"footway"},"nodes":["n2138439333","n2138439334"]},"w203837935":{"id":"w203837935","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420762","n2138420763","n2138420764"]},"w203838287":{"id":"w203838287","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425446","n2138425447","n2138425448","n2138425443","n2138425446"]},"w203837934":{"id":"w203837934","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420760","n2138420763","n2138420761"]},"w203838289":{"id":"w203838289","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425449","n2138425451","n2138425452","n2138425450","n2138425449"]},"w17963047":{"id":"w17963047","tags":{"highway":"service"},"nodes":["n185948818","n2138436013","n185948820","n185948822","n185948824","n2138439326","n2138420767","n2138420766"]},"w203839091":{"id":"w203839091","tags":{"highway":"footway"},"nodes":["n185976502","n2138436000","n2138436001","n2138436017","n2138436002","n2138436003","n2138436021","n2138436025","n2138436023","n2138435984","n2138436004","n2138436005","n2138436006","n2138436007","n2138436008","n2138436009","n2138436010","n2138436011","n2138436012","n2138436013","n2138439319","n2138439329","n2138436014"]},"w204830797":{"id":"w204830797","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420756","n2138420757","n2138420765","n2138420758"]},"w203838288":{"id":"w203838288","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425447","n2138425449","n2138425450","n2138425448","n2138425447"]},"w203838285":{"id":"w203838285","tags":{"area":"yes","leisure":"pitch","sport":"baseball"},"nodes":["n2138425433","n2138425434","n2138425435","n2138425436","n2138425437","n2138425438","n2138425439","n2138425440","n2138425441","n2138425442","n2138425433"]},"w203838286":{"id":"w203838286","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425443","n2138425444","n2138425445","n2138425446","n2138425443"]},"w203837929":{"id":"w203837929","tags":{"amenity":"parking","area":"yes"},"nodes":["n2138420725","n2138420726","n2138420727","n2138420728","n2138420725"]},"w203839361":{"id":"w203839361","tags":{"highway":"footway"},"nodes":["n2138439319","n2138439328","n2138439320","n2138439321","n2138439322","n2138439331","n2138439334","n2138439323","n2138439324","n2138439325","n2138439326"]},"n394381698":{"id":"n394381698","loc":[-85.614471,41.954755]},"n394381699":{"id":"n394381699","loc":[-85.6152,41.954744]},"n394381700":{"id":"n394381700","loc":[-85.615201,41.954081]},"n394381701":{"id":"n394381701","loc":[-85.614426,41.954042]},"n394381702":{"id":"n394381702","loc":[-85.616319,41.954749]},"n394381704":{"id":"n394381704","loc":[-85.616152,41.954752]},"n394381706":{"id":"n394381706","loc":[-85.615201,41.95483]},"n394490775":{"id":"n394490775","loc":[-85.613971,41.954839]},"n394490782":{"id":"n394490782","loc":[-85.614372,41.954841]},"n185958835":{"id":"n185958835","loc":[-85.611615,41.953704]},"n185958837":{"id":"n185958837","loc":[-85.611636,41.953938]},"n185958842":{"id":"n185958842","loc":[-85.611187,41.951686]},"n185958844":{"id":"n185958844","loc":[-85.611087,41.951741]},"n185958845":{"id":"n185958845","loc":[-85.611034,41.951852]},"n185958847":{"id":"n185958847","loc":[-85.611016,41.95196]},"n185958849":{"id":"n185958849","loc":[-85.610989,41.95328]},"n185958851":{"id":"n185958851","loc":[-85.611021,41.953484]},"n185958852":{"id":"n185958852","loc":[-85.611091,41.953603]},"n185958853":{"id":"n185958853","loc":[-85.6112,41.953661]},"n185958855":{"id":"n185958855","loc":[-85.611364,41.953686]},"n185965031":{"id":"n185965031","loc":[-85.614204,41.953696]},"n185965032":{"id":"n185965032","loc":[-85.6142,41.953978]},"n185965062":{"id":"n185965062","loc":[-85.614617,41.951639]},"n185965064":{"id":"n185965064","loc":[-85.61463,41.951852]},"n185965066":{"id":"n185965066","loc":[-85.614642,41.953436]},"n185965068":{"id":"n185965068","loc":[-85.6146,41.953551]},"n185965071":{"id":"n185965071","loc":[-85.614487,41.95363]},"n185965073":{"id":"n185965073","loc":[-85.614354,41.953672]},"n185966288":{"id":"n185966288","loc":[-85.61179,41.953695]},"n185966290":{"id":"n185966290","loc":[-85.612232,41.953685]},"n185966293":{"id":"n185966293","loc":[-85.613438,41.953677]},"n185966349":{"id":"n185966349","loc":[-85.611323,41.951653]},"n185966351":{"id":"n185966351","loc":[-85.611892,41.951642]},"n185966352":{"id":"n185966352","loc":[-85.612216,41.951641]},"n185966353":{"id":"n185966353","loc":[-85.613111,41.951639]},"n185966354":{"id":"n185966354","loc":[-85.613396,41.95164]},"n185966355":{"id":"n185966355","loc":[-85.614221,41.95164]},"n185973839":{"id":"n185973839","loc":[-85.61341,41.951919]},"n185973840":{"id":"n185973840","loc":[-85.613438,41.953308]},"n185980222":{"id":"n185980222","loc":[-85.613781,41.955164]},"n185980223":{"id":"n185980223","loc":[-85.613815,41.955237]},"n185980225":{"id":"n185980225","loc":[-85.613837,41.955316]},"n185990345":{"id":"n185990345","loc":[-85.612211,41.951977]},"n185955743":{"id":"n185955743","loc":[-85.613873,41.95635]},"n185980227":{"id":"n185980227","loc":[-85.613851,41.955415]},"n185980229":{"id":"n185980229","loc":[-85.613918,41.957134]},"n394381703":{"id":"n394381703","loc":[-85.616287,41.955674]},"n394381705":{"id":"n394381705","loc":[-85.615164,41.955676]},"n394490777":{"id":"n394490777","loc":[-85.613973,41.955979]},"n394490780":{"id":"n394490780","loc":[-85.614364,41.955987]},"w17965307":{"id":"w17965307","tags":{"highway":"residential","name":"Bates Ave"},"nodes":["n185958842","n185966349","n185966351","n185966352","n185966353","n185966354","n185966355","n185965062"]},"w17967957":{"id":"w17967957","tags":{"highway":"residential","name":"Krum Ave"},"nodes":["n185966352","n185990345","n185966290"]},"w17964508":{"id":"w17964508","tags":{"highway":"residential","name":"Blossom Dr"},"nodes":["n185958842","n185958844","n185958845","n185958847","n185958849","n185958851","n185958852","n185958853","n185958855","n185958835"]},"w17964507":{"id":"w17964507","tags":{"highway":"residential","name":"Blossom Dr"},"nodes":["n185958835","n185958837","n185958839"]},"w34367080":{"id":"w34367080","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394381699","n394381706","n394381705","n394381703","n394381702","n394381704","n394381699"]},"w17965302":{"id":"w17965302","tags":{"highway":"residential","name":"Clausen Ave"},"nodes":["n185958835","n185966288","n185966290","n185966293","n185965031"]},"w17965156":{"id":"w17965156","tags":{"highway":"residential","name":"Orchard Dr"},"nodes":["n185965062","n185965064","n185965066","n185965068","n185965071","n185965073","n185965031"]},"w34369812":{"id":"w34369812","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490775","n394490777","n394490780","n394490782","n394490775"]},"w17965151":{"id":"w17965151","tags":{"highway":"residential","name":"Orchard Dr"},"nodes":["n185965031","n185965032","n185965033"]},"w17966756":{"id":"w17966756","tags":{"access":"private","highway":"service","name":"Lockport Dr"},"nodes":["n185978828","n185980222","n185980223","n185980225","n185980227","n185955743","n185980229"]},"w17966056":{"id":"w17966056","tags":{"highway":"residential","name":"Angell Ave"},"nodes":["n185966354","n185973839","n185973840","n185966293"]},"w34367079":{"id":"w34367079","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394381700","n394381701","n394381698","n394381699","n394381700"]},"n185955744":{"id":"n185955744","loc":[-85.611753,41.956208]},"n185988932":{"id":"n185988932","loc":[-85.6159,41.956336]},"n185988934":{"id":"n185988934","loc":[-85.6159158,41.9590646]},"n185988935":{"id":"n185988935","loc":[-85.6157358,41.959364],"tags":{"highway":"turning_circle"}},"n2138447007":{"id":"n2138447007","loc":[-85.6130784,41.9590689]},"n2138447008":{"id":"n2138447008","loc":[-85.6133328,41.9593805]},"n2138447003":{"id":"n2138447003","loc":[-85.610238,41.9547745]},"n2138447004":{"id":"n2138447004","loc":[-85.6102652,41.9566041]},"n2138447005":{"id":"n2138447005","loc":[-85.610325,41.9568823]},"n2138447006":{"id":"n2138447006","loc":[-85.6105644,41.9571383]},"n2138447009":{"id":"n2138447009","loc":[-85.6135946,41.959948]},"n2138447010":{"id":"n2138447010","loc":[-85.6136071,41.9629372]},"n2138447011":{"id":"n2138447011","loc":[-85.6134392,41.9633182]},"n2138447012":{"id":"n2138447012","loc":[-85.6130151,41.9636073]},"n2138447013":{"id":"n2138447013","loc":[-85.6122729,41.9637125]},"n2138447014":{"id":"n2138447014","loc":[-85.6056682,41.963752]},"w17964174":{"id":"w17964174","tags":{"access":"private","highway":"service"},"nodes":["n185955743","n185955744"]},"w17967743":{"id":"w17967743","tags":{"access":"private","highway":"service","name":"Manistee River Rd"},"nodes":["n185971574","n185988932","n185971407","n185981301","n185967987","n185988934","n185988935"]},"w203839666":{"id":"w203839666","tags":{"highway":"residential","name":"Hov Aire Drive"},"nodes":["n2138447003","n2138447004","n2138447005","n2138447006","n2138447007","n2138447008","n2138447009","n2138447010","n2138447011","n2138447012","n2138447013","n2138447014"]}}';iD.data = {"deprecated":[{"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"}}],"discarded":["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"],"wikipedia":[["Abkhazian","Аҧсшәа","ab"],["Achinese","Acèh","ace"],["Adyghe","адыгабзэ","ady"],["Afrikaans","Afrikaans","af"],["Akan","Akan","ak"],["Alemannisch","Alemannisch","als"],["Amharic","አማርኛ","am"],["Aragonese","aragonés","an"],["Old English","Ænglisc","ang"],["Arabic","العربية","ar"],["Aramaic","ܐܪܡܝܐ","arc"],["Egyptian Arabic","مصرى","arz"],["Assamese","অসমীয়া","as"],["Asturian","asturianu","ast"],["Avaric","авар","av"],["Aymara","Aymar aru","ay"],["Azerbaijani","azərbaycanca","az"],["تۆرکجه","تۆرکجه","azb"],["Bashkir","башҡортса","ba"],["Bavarian","Boarisch","bar"],["Samogitian","žemaitėška","bat-smg"],["Bikol Central","Bikol Central","bcl"],["Belarusian","беларуская","be"],["беларуская (тарашкевіца)","беларуская (тарашкевіца)","be-x-old"],["Bulgarian","български","bg"],["भोजपुरी","भोजपुरी","bh"],["Bislama","Bislama","bi"],["Banjar","Bahasa Banjar","bjn"],["Bambara","bamanankan","bm"],["Bengali","বাংলা","bn"],["Tibetan","བོད་ཡིག","bo"],["Bishnupriya","বিষ্ণুপ্রিয়া মণিপুরী","bpy"],["Breton","brezhoneg","br"],["Bosnian","bosanski","bs"],["Buginese","ᨅᨔ ᨕᨘᨁᨗ","bug"],["буряад","буряад","bxr"],["Catalan","català","ca"],["Chavacano de Zamboanga","Chavacano de Zamboanga","cbk-zam"],["Min Dong Chinese","Mìng-dĕ̤ng-ngṳ̄","cdo"],["Chechen","нохчийн","ce"],["Cebuano","Cebuano","ceb"],["Chamorro","Chamoru","ch"],["Cherokee","ᏣᎳᎩ","chr"],["Cheyenne","Tsetsêhestâhese","chy"],["Central Kurdish","کوردیی ناوەندی","ckb"],["Corsican","corsu","co"],["Cree","Nēhiyawēwin / ᓀᐦᐃᔭᐍᐏᐣ","cr"],["Crimean Turkish","qırımtatarca","crh"],["Czech","čeština","cs"],["Kashubian","kaszëbsczi","csb"],["Church Slavic","словѣньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ","cu"],["Chuvash","Чӑвашла","cv"],["Welsh","Cymraeg","cy"],["Danish","dansk","da"],["German","Deutsch","de"],["Zazaki","Zazaki","diq"],["Lower Sorbian","dolnoserbski","dsb"],["Divehi","ދިވެހިބަސް","dv"],["Dzongkha","ཇོང་ཁ","dz"],["Ewe","eʋegbe","ee"],["Greek","Ελληνικά","el"],["Emiliano-Romagnolo","emiliàn e rumagnòl","eml"],["English","English","en"],["Esperanto","Esperanto","eo"],["Spanish","español","es"],["Estonian","eesti","et"],["Basque","euskara","eu"],["Extremaduran","estremeñu","ext"],["Persian","فارسی","fa"],["Fulah","Fulfulde","ff"],["Finnish","suomi","fi"],["Võro","Võro","fiu-vro"],["Fijian","Na Vosa Vakaviti","fj"],["Faroese","føroyskt","fo"],["French","français","fr"],["Arpitan","arpetan","frp"],["Northern Frisian","Nordfriisk","frr"],["Friulian","furlan","fur"],["Western Frisian","Frysk","fy"],["Irish","Gaeilge","ga"],["Gagauz","Gagauz","gag"],["Gan Chinese","贛語","gan"],["Scottish Gaelic","Gàidhlig","gd"],["Galician","galego","gl"],["Gilaki","گیلکی","glk"],["Guarani","Avañe'ẽ","gn"],["Goan Konkani","गोंयची कोंकणी / Gõychi Konknni","gom"],["Gothic","𐌲𐌿𐍄𐌹𐍃𐌺","got"],["Gujarati","ગુજરાતી","gu"],["Manx","Gaelg","gv"],["Hausa","Hausa","ha"],["Hakka Chinese","客家語/Hak-kâ-ngî","hak"],["Hawaiian","Hawaiʻi","haw"],["Hebrew","עברית","he"],["Hindi","हिन्दी","hi"],["Fiji Hindi","Fiji Hindi","hif"],["Croatian","hrvatski","hr"],["Upper Sorbian","hornjoserbsce","hsb"],["Haitian Creole","Kreyòl ayisyen","ht"],["Hungarian","magyar","hu"],["Armenian","Հայերեն","hy"],["Interlingua","interlingua","ia"],["Indonesian","Bahasa Indonesia","id"],["Interlingue","Interlingue","ie"],["Igbo","Igbo","ig"],["Inupiaq","Iñupiak","ik"],["Iloko","Ilokano","ilo"],["Ido","Ido","io"],["Icelandic","íslenska","is"],["Italian","italiano","it"],["Inuktitut","ᐃᓄᒃᑎᑐᑦ/inuktitut","iu"],["Japanese","日本語","ja"],["Jamaican Creole English","Patois","jam"],["Lojban","la .lojban.","jbo"],["Javanese","Basa Jawa","jv"],["Georgian","ქართული","ka"],["Kara-Kalpak","Qaraqalpaqsha","kaa"],["Kabyle","Taqbaylit","kab"],["Kabardian","Адыгэбзэ","kbd"],["Kongo","Kongo","kg"],["Kikuyu","Gĩkũyũ","ki"],["Kazakh","қазақша","kk"],["Kalaallisut","kalaallisut","kl"],["Khmer","ភាសាខ្មែរ","km"],["Kannada","ಕನ್ನಡ","kn"],["Korean","한국어","ko"],["Komi-Permyak","Перем Коми","koi"],["Karachay-Balkar","къарачай-малкъар","krc"],["Kashmiri","कॉशुर / کٲشُر","ks"],["Colognian","Ripoarisch","ksh"],["Kurdish","Kurdî","ku"],["Komi","коми","kv"],["Cornish","kernowek","kw"],["Kyrgyz","Кыргызча","ky"],["Latin","Latina","la"],["Ladino","Ladino","lad"],["Luxembourgish","Lëtzebuergesch","lb"],["лакку","лакку","lbe"],["Lezghian","лезги","lez"],["Ganda","Luganda","lg"],["Limburgish","Limburgs","li"],["Ligurian","Ligure","lij"],["Lombard","lumbaart","lmo"],["Lingala","lingála","ln"],["Lao","ລາວ","lo"],["Northern Luri","لۊری شومالی","lrc"],["Lithuanian","lietuvių","lt"],["Latgalian","latgaļu","ltg"],["Latvian","latviešu","lv"],["Maithili","मैथिली","mai"],["Basa Banyumasan","Basa Banyumasan","map-bms"],["Moksha","мокшень","mdf"],["Malagasy","Malagasy","mg"],["Eastern Mari","олык марий","mhr"],["Maori","Māori","mi"],["Minangkabau","Baso Minangkabau","min"],["Macedonian","македонски","mk"],["Malayalam","മലയാളം","ml"],["Mongolian","монгол","mn"],["Marathi","मराठी","mr"],["Western Mari","кырык мары","mrj"],["Malay","Bahasa Melayu","ms"],["Maltese","Malti","mt"],["Mirandese","Mirandés","mwl"],["Burmese","မြန်မာဘာသာ","my"],["Erzya","эрзянь","myv"],["Mazanderani","مازِرونی","mzn"],["Nauru","Dorerin Naoero","na"],["Nāhuatl","Nāhuatl","nah"],["Neapolitan","Napulitano","nap"],["Low German","Plattdüütsch","nds"],["Low Saxon","Nedersaksies","nds-nl"],["Nepali","नेपाली","ne"],["Newari","नेपाल भाषा","new"],["Dutch","Nederlands","nl"],["Norwegian Nynorsk","norsk nynorsk","nn"],["Norwegian","norsk bokmål","no"],["Novial","Novial","nov"],["Nouormand","Nouormand","nrm"],["Northern Sotho","Sesotho sa Leboa","nso"],["Navajo","Diné bizaad","nv"],["Nyanja","Chi-Chewa","ny"],["Occitan","occitan","oc"],["Oromo","Oromoo","om"],["Oriya","ଓଡ଼ିଆ","or"],["Ossetic","Ирон","os"],["Punjabi","ਪੰਜਾਬੀ","pa"],["Pangasinan","Pangasinan","pag"],["Pampanga","Kapampangan","pam"],["Papiamento","Papiamentu","pap"],["Picard","Picard","pcd"],["Pennsylvania German","Deitsch","pdc"],["Palatine German","Pälzisch","pfl"],["Pali","पालि","pi"],["Norfuk / Pitkern","Norfuk / Pitkern","pih"],["Polish","polski","pl"],["Piedmontese","Piemontèis","pms"],["Western Punjabi","پنجابی","pnb"],["Pontic","Ποντιακά","pnt"],["Pashto","پښتو","ps"],["Portuguese","português","pt"],["Quechua","Runa Simi","qu"],["Romansh","rumantsch","rm"],["Romani","Romani","rmy"],["Rundi","Kirundi","rn"],["Romanian","română","ro"],["Aromanian","armãneashti","roa-rup"],["tarandíne","tarandíne","roa-tara"],["Russian","русский","ru"],["Rusyn","русиньскый","rue"],["Kinyarwanda","Kinyarwanda","rw"],["Sanskrit","संस्कृतम्","sa"],["Sakha","саха тыла","sah"],["Sardinian","sardu","sc"],["Sicilian","sicilianu","scn"],["Scots","Scots","sco"],["Sindhi","سنڌي","sd"],["Northern Sami","sámegiella","se"],["Sango","Sängö","sg"],["Serbo-Croatian","srpskohrvatski / српскохрватски","sh"],["Sinhala","සිංහල","si"],["Simple English","Simple English","simple"],["Slovak","slovenčina","sk"],["Slovenian","slovenščina","sl"],["Samoan","Gagana Samoa","sm"],["Shona","chiShona","sn"],["Somali","Soomaaliga","so"],["Albanian","shqip","sq"],["Serbian","српски / srpski","sr"],["Sranan Tongo","Sranantongo","srn"],["Swati","SiSwati","ss"],["Southern Sotho","Sesotho","st"],["Saterland Frisian","Seeltersk","stq"],["Sundanese","Basa Sunda","su"],["Swedish","svenska","sv"],["Swahili","Kiswahili","sw"],["Silesian","ślůnski","szl"],["Tamil","தமிழ்","ta"],["Telugu","తెలుగు","te"],["Tetum","tetun","tet"],["Tajik","тоҷикӣ","tg"],["Thai","ไทย","th"],["Tigrinya","ትግርኛ","ti"],["Turkmen","Türkmençe","tk"],["Tagalog","Tagalog","tl"],["Tswana","Setswana","tn"],["Tongan","lea faka-Tonga","to"],["Tok Pisin","Tok Pisin","tpi"],["Turkish","Türkçe","tr"],["Tsonga","Xitsonga","ts"],["Tatar","татарча/tatarça","tt"],["Tumbuka","chiTumbuka","tum"],["Twi","Twi","tw"],["Tahitian","reo tahiti","ty"],["Tuvinian","тыва дыл","tyv"],["Udmurt","удмурт","udm"],["Uyghur","ئۇيغۇرچە / Uyghurche","ug"],["Ukrainian","українська","uk"],["Urdu","اردو","ur"],["Uzbek","oʻzbekcha/ўзбекча","uz"],["Venda","Tshivenda","ve"],["Venetian","vèneto","vec"],["Veps","vepsän kel’","vep"],["Vietnamese","Tiếng Việt","vi"],["West Flemish","West-Vlams","vls"],["Volapük","Volapük","vo"],["Walloon","walon","wa"],["Waray","Winaray","war"],["Wolof","Wolof","wo"],["Wu Chinese","吴语","wuu"],["Kalmyk","хальмг","xal"],["Xhosa","isiXhosa","xh"],["Mingrelian","მარგალური","xmf"],["Yiddish","ייִדיש","yi"],["Yoruba","Yorùbá","yo"],["Zhuang","Vahcuengh","za"],["Zeelandic","Zeêuws","zea"],["Chinese","中文","zh"],["Classical Chinese","文言","zh-classical"],["Chinese (Min Nan)","Bân-lâm-gú","zh-min-nan"],["Cantonese","粵語","zh-yue"],["Zulu","isiZulu","zu"]],"imperial":{"type":"FeatureCollection","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]]]}}]},"featureIcons":{"circle-stroked-24":{"x":0,"y":0,"width":24,"height":24},"circle-stroked-18":{"x":24,"y":0,"width":18,"height":18},"circle-stroked-12":{"x":42,"y":0,"width":12,"height":12},"circle-24":{"x":54,"y":0,"width":24,"height":24},"circle-18":{"x":78,"y":0,"width":18,"height":18},"circle-12":{"x":96,"y":0,"width":12,"height":12},"square-stroked-24":{"x":108,"y":0,"width":24,"height":24},"square-stroked-18":{"x":132,"y":0,"width":18,"height":18},"square-stroked-12":{"x":150,"y":0,"width":12,"height":12},"square-24":{"x":162,"y":0,"width":24,"height":24},"square-18":{"x":186,"y":0,"width":18,"height":18},"square-12":{"x":204,"y":0,"width":12,"height":12},"triangle-stroked-24":{"x":216,"y":0,"width":24,"height":24},"triangle-stroked-18":{"x":240,"y":0,"width":18,"height":18},"triangle-stroked-12":{"x":258,"y":0,"width":12,"height":12},"triangle-24":{"x":0,"y":24,"width":24,"height":24},"triangle-18":{"x":24,"y":24,"width":18,"height":18},"triangle-12":{"x":42,"y":24,"width":12,"height":12},"star-stroked-24":{"x":54,"y":24,"width":24,"height":24},"star-stroked-18":{"x":78,"y":24,"width":18,"height":18},"star-stroked-12":{"x":96,"y":24,"width":12,"height":12},"star-24":{"x":108,"y":24,"width":24,"height":24},"star-18":{"x":132,"y":24,"width":18,"height":18},"star-12":{"x":150,"y":24,"width":12,"height":12},"cross-24":{"x":162,"y":24,"width":24,"height":24},"cross-18":{"x":186,"y":24,"width":18,"height":18},"cross-12":{"x":204,"y":24,"width":12,"height":12},"marker-stroked-24":{"x":216,"y":24,"width":24,"height":24},"marker-stroked-18":{"x":240,"y":24,"width":18,"height":18},"marker-stroked-12":{"x":258,"y":24,"width":12,"height":12},"marker-24":{"x":0,"y":48,"width":24,"height":24},"marker-18":{"x":24,"y":48,"width":18,"height":18},"marker-12":{"x":42,"y":48,"width":12,"height":12},"religious-jewish-24":{"x":54,"y":48,"width":24,"height":24},"religious-jewish-18":{"x":78,"y":48,"width":18,"height":18},"religious-jewish-12":{"x":96,"y":48,"width":12,"height":12},"religious-christian-24":{"x":108,"y":48,"width":24,"height":24},"religious-christian-18":{"x":132,"y":48,"width":18,"height":18},"religious-christian-12":{"x":150,"y":48,"width":12,"height":12},"religious-muslim-24":{"x":162,"y":48,"width":24,"height":24},"religious-muslim-18":{"x":186,"y":48,"width":18,"height":18},"religious-muslim-12":{"x":204,"y":48,"width":12,"height":12},"cemetery-24":{"x":216,"y":48,"width":24,"height":24},"cemetery-18":{"x":240,"y":48,"width":18,"height":18},"cemetery-12":{"x":258,"y":48,"width":12,"height":12},"rocket-24":{"x":0,"y":72,"width":24,"height":24},"rocket-18":{"x":24,"y":72,"width":18,"height":18},"rocket-12":{"x":42,"y":72,"width":12,"height":12},"airport-24":{"x":54,"y":72,"width":24,"height":24},"airport-18":{"x":78,"y":72,"width":18,"height":18},"airport-12":{"x":96,"y":72,"width":12,"height":12},"heliport-24":{"x":108,"y":72,"width":24,"height":24},"heliport-18":{"x":132,"y":72,"width":18,"height":18},"heliport-12":{"x":150,"y":72,"width":12,"height":12},"rail-24":{"x":162,"y":72,"width":24,"height":24},"rail-18":{"x":186,"y":72,"width":18,"height":18},"rail-12":{"x":204,"y":72,"width":12,"height":12},"rail-metro-24":{"x":216,"y":72,"width":24,"height":24},"rail-metro-18":{"x":240,"y":72,"width":18,"height":18},"rail-metro-12":{"x":258,"y":72,"width":12,"height":12},"rail-light-24":{"x":0,"y":96,"width":24,"height":24},"rail-light-18":{"x":24,"y":96,"width":18,"height":18},"rail-light-12":{"x":42,"y":96,"width":12,"height":12},"bus-24":{"x":54,"y":96,"width":24,"height":24},"bus-18":{"x":78,"y":96,"width":18,"height":18},"bus-12":{"x":96,"y":96,"width":12,"height":12},"fuel-24":{"x":108,"y":96,"width":24,"height":24},"fuel-18":{"x":132,"y":96,"width":18,"height":18},"fuel-12":{"x":150,"y":96,"width":12,"height":12},"parking-24":{"x":162,"y":96,"width":24,"height":24},"parking-18":{"x":186,"y":96,"width":18,"height":18},"parking-12":{"x":204,"y":96,"width":12,"height":12},"parking-garage-24":{"x":216,"y":96,"width":24,"height":24},"parking-garage-18":{"x":240,"y":96,"width":18,"height":18},"parking-garage-12":{"x":258,"y":96,"width":12,"height":12},"airfield-24":{"x":0,"y":120,"width":24,"height":24},"airfield-18":{"x":24,"y":120,"width":18,"height":18},"airfield-12":{"x":42,"y":120,"width":12,"height":12},"roadblock-24":{"x":54,"y":120,"width":24,"height":24},"roadblock-18":{"x":78,"y":120,"width":18,"height":18},"roadblock-12":{"x":96,"y":120,"width":12,"height":12},"ferry-24":{"x":108,"y":120,"width":24,"height":24},"ferry-18":{"x":132,"y":120,"width":18,"height":18},"ferry-12":{"x":150,"y":120,"width":12,"height":12},"harbor-24":{"x":162,"y":120,"width":24,"height":24},"harbor-18":{"x":186,"y":120,"width":18,"height":18},"harbor-12":{"x":204,"y":120,"width":12,"height":12},"bicycle-24":{"x":216,"y":120,"width":24,"height":24},"bicycle-18":{"x":240,"y":120,"width":18,"height":18},"bicycle-12":{"x":258,"y":120,"width":12,"height":12},"park-24":{"x":0,"y":144,"width":24,"height":24},"park-18":{"x":24,"y":144,"width":18,"height":18},"park-12":{"x":42,"y":144,"width":12,"height":12},"park2-24":{"x":54,"y":144,"width":24,"height":24},"park2-18":{"x":78,"y":144,"width":18,"height":18},"park2-12":{"x":96,"y":144,"width":12,"height":12},"museum-24":{"x":108,"y":144,"width":24,"height":24},"museum-18":{"x":132,"y":144,"width":18,"height":18},"museum-12":{"x":150,"y":144,"width":12,"height":12},"lodging-24":{"x":162,"y":144,"width":24,"height":24},"lodging-18":{"x":186,"y":144,"width":18,"height":18},"lodging-12":{"x":204,"y":144,"width":12,"height":12},"monument-24":{"x":216,"y":144,"width":24,"height":24},"monument-18":{"x":240,"y":144,"width":18,"height":18},"monument-12":{"x":258,"y":144,"width":12,"height":12},"zoo-24":{"x":0,"y":168,"width":24,"height":24},"zoo-18":{"x":24,"y":168,"width":18,"height":18},"zoo-12":{"x":42,"y":168,"width":12,"height":12},"garden-24":{"x":54,"y":168,"width":24,"height":24},"garden-18":{"x":78,"y":168,"width":18,"height":18},"garden-12":{"x":96,"y":168,"width":12,"height":12},"campsite-24":{"x":108,"y":168,"width":24,"height":24},"campsite-18":{"x":132,"y":168,"width":18,"height":18},"campsite-12":{"x":150,"y":168,"width":12,"height":12},"theatre-24":{"x":162,"y":168,"width":24,"height":24},"theatre-18":{"x":186,"y":168,"width":18,"height":18},"theatre-12":{"x":204,"y":168,"width":12,"height":12},"art-gallery-24":{"x":216,"y":168,"width":24,"height":24},"art-gallery-18":{"x":240,"y":168,"width":18,"height":18},"art-gallery-12":{"x":258,"y":168,"width":12,"height":12},"pitch-24":{"x":0,"y":192,"width":24,"height":24},"pitch-18":{"x":24,"y":192,"width":18,"height":18},"pitch-12":{"x":42,"y":192,"width":12,"height":12},"soccer-24":{"x":54,"y":192,"width":24,"height":24},"soccer-18":{"x":78,"y":192,"width":18,"height":18},"soccer-12":{"x":96,"y":192,"width":12,"height":12},"america-football-24":{"x":108,"y":192,"width":24,"height":24},"america-football-18":{"x":132,"y":192,"width":18,"height":18},"america-football-12":{"x":150,"y":192,"width":12,"height":12},"tennis-24":{"x":162,"y":192,"width":24,"height":24},"tennis-18":{"x":186,"y":192,"width":18,"height":18},"tennis-12":{"x":204,"y":192,"width":12,"height":12},"basketball-24":{"x":216,"y":192,"width":24,"height":24},"basketball-18":{"x":240,"y":192,"width":18,"height":18},"basketball-12":{"x":258,"y":192,"width":12,"height":12},"baseball-24":{"x":0,"y":216,"width":24,"height":24},"baseball-18":{"x":24,"y":216,"width":18,"height":18},"baseball-12":{"x":42,"y":216,"width":12,"height":12},"golf-24":{"x":54,"y":216,"width":24,"height":24},"golf-18":{"x":78,"y":216,"width":18,"height":18},"golf-12":{"x":96,"y":216,"width":12,"height":12},"swimming-24":{"x":108,"y":216,"width":24,"height":24},"swimming-18":{"x":132,"y":216,"width":18,"height":18},"swimming-12":{"x":150,"y":216,"width":12,"height":12},"cricket-24":{"x":162,"y":216,"width":24,"height":24},"cricket-18":{"x":186,"y":216,"width":18,"height":18},"cricket-12":{"x":204,"y":216,"width":12,"height":12},"skiing-24":{"x":216,"y":216,"width":24,"height":24},"skiing-18":{"x":240,"y":216,"width":18,"height":18},"skiing-12":{"x":258,"y":216,"width":12,"height":12},"school-24":{"x":0,"y":240,"width":24,"height":24},"school-18":{"x":24,"y":240,"width":18,"height":18},"school-12":{"x":42,"y":240,"width":12,"height":12},"college-24":{"x":54,"y":240,"width":24,"height":24},"college-18":{"x":78,"y":240,"width":18,"height":18},"college-12":{"x":96,"y":240,"width":12,"height":12},"library-24":{"x":108,"y":240,"width":24,"height":24},"library-18":{"x":132,"y":240,"width":18,"height":18},"library-12":{"x":150,"y":240,"width":12,"height":12},"post-24":{"x":162,"y":240,"width":24,"height":24},"post-18":{"x":186,"y":240,"width":18,"height":18},"post-12":{"x":204,"y":240,"width":12,"height":12},"fire-station-24":{"x":216,"y":240,"width":24,"height":24},"fire-station-18":{"x":240,"y":240,"width":18,"height":18},"fire-station-12":{"x":258,"y":240,"width":12,"height":12},"town-hall-24":{"x":0,"y":264,"width":24,"height":24},"town-hall-18":{"x":24,"y":264,"width":18,"height":18},"town-hall-12":{"x":42,"y":264,"width":12,"height":12},"police-24":{"x":54,"y":264,"width":24,"height":24},"police-18":{"x":78,"y":264,"width":18,"height":18},"police-12":{"x":96,"y":264,"width":12,"height":12},"prison-24":{"x":108,"y":264,"width":24,"height":24},"prison-18":{"x":132,"y":264,"width":18,"height":18},"prison-12":{"x":150,"y":264,"width":12,"height":12},"embassy-24":{"x":162,"y":264,"width":24,"height":24},"embassy-18":{"x":186,"y":264,"width":18,"height":18},"embassy-12":{"x":204,"y":264,"width":12,"height":12},"beer-24":{"x":216,"y":264,"width":24,"height":24},"beer-18":{"x":240,"y":264,"width":18,"height":18},"beer-12":{"x":258,"y":264,"width":12,"height":12},"restaurant-24":{"x":0,"y":288,"width":24,"height":24},"restaurant-18":{"x":24,"y":288,"width":18,"height":18},"restaurant-12":{"x":42,"y":288,"width":12,"height":12},"cafe-24":{"x":54,"y":288,"width":24,"height":24},"cafe-18":{"x":78,"y":288,"width":18,"height":18},"cafe-12":{"x":96,"y":288,"width":12,"height":12},"shop-24":{"x":108,"y":288,"width":24,"height":24},"shop-18":{"x":132,"y":288,"width":18,"height":18},"shop-12":{"x":150,"y":288,"width":12,"height":12},"fast-food-24":{"x":162,"y":288,"width":24,"height":24},"fast-food-18":{"x":186,"y":288,"width":18,"height":18},"fast-food-12":{"x":204,"y":288,"width":12,"height":12},"bar-24":{"x":216,"y":288,"width":24,"height":24},"bar-18":{"x":240,"y":288,"width":18,"height":18},"bar-12":{"x":258,"y":288,"width":12,"height":12},"bank-24":{"x":0,"y":312,"width":24,"height":24},"bank-18":{"x":24,"y":312,"width":18,"height":18},"bank-12":{"x":42,"y":312,"width":12,"height":12},"grocery-24":{"x":54,"y":312,"width":24,"height":24},"grocery-18":{"x":78,"y":312,"width":18,"height":18},"grocery-12":{"x":96,"y":312,"width":12,"height":12},"cinema-24":{"x":108,"y":312,"width":24,"height":24},"cinema-18":{"x":132,"y":312,"width":18,"height":18},"cinema-12":{"x":150,"y":312,"width":12,"height":12},"pharmacy-24":{"x":162,"y":312,"width":24,"height":24},"pharmacy-18":{"x":186,"y":312,"width":18,"height":18},"pharmacy-12":{"x":204,"y":312,"width":12,"height":12},"hospital-24":{"x":216,"y":312,"width":24,"height":24},"hospital-18":{"x":240,"y":312,"width":18,"height":18},"hospital-12":{"x":258,"y":312,"width":12,"height":12},"danger-24":{"x":0,"y":336,"width":24,"height":24},"danger-18":{"x":24,"y":336,"width":18,"height":18},"danger-12":{"x":42,"y":336,"width":12,"height":12},"industrial-24":{"x":54,"y":336,"width":24,"height":24},"industrial-18":{"x":78,"y":336,"width":18,"height":18},"industrial-12":{"x":96,"y":336,"width":12,"height":12},"warehouse-24":{"x":108,"y":336,"width":24,"height":24},"warehouse-18":{"x":132,"y":336,"width":18,"height":18},"warehouse-12":{"x":150,"y":336,"width":12,"height":12},"commercial-24":{"x":162,"y":336,"width":24,"height":24},"commercial-18":{"x":186,"y":336,"width":18,"height":18},"commercial-12":{"x":204,"y":336,"width":12,"height":12},"building-24":{"x":216,"y":336,"width":24,"height":24},"building-18":{"x":240,"y":336,"width":18,"height":18},"building-12":{"x":258,"y":336,"width":12,"height":12},"place-of-worship-24":{"x":0,"y":360,"width":24,"height":24},"place-of-worship-18":{"x":24,"y":360,"width":18,"height":18},"place-of-worship-12":{"x":42,"y":360,"width":12,"height":12},"alcohol-shop-24":{"x":54,"y":360,"width":24,"height":24},"alcohol-shop-18":{"x":78,"y":360,"width":18,"height":18},"alcohol-shop-12":{"x":96,"y":360,"width":12,"height":12},"logging-24":{"x":108,"y":360,"width":24,"height":24},"logging-18":{"x":132,"y":360,"width":18,"height":18},"logging-12":{"x":150,"y":360,"width":12,"height":12},"oil-well-24":{"x":162,"y":360,"width":24,"height":24},"oil-well-18":{"x":186,"y":360,"width":18,"height":18},"oil-well-12":{"x":204,"y":360,"width":12,"height":12},"slaughterhouse-24":{"x":216,"y":360,"width":24,"height":24},"slaughterhouse-18":{"x":240,"y":360,"width":18,"height":18},"slaughterhouse-12":{"x":258,"y":360,"width":12,"height":12},"dam-24":{"x":0,"y":384,"width":24,"height":24},"dam-18":{"x":24,"y":384,"width":18,"height":18},"dam-12":{"x":42,"y":384,"width":12,"height":12},"water-24":{"x":54,"y":384,"width":24,"height":24},"water-18":{"x":78,"y":384,"width":18,"height":18},"water-12":{"x":96,"y":384,"width":12,"height":12},"wetland-24":{"x":108,"y":384,"width":24,"height":24},"wetland-18":{"x":132,"y":384,"width":18,"height":18},"wetland-12":{"x":150,"y":384,"width":12,"height":12},"disability-24":{"x":162,"y":384,"width":24,"height":24},"disability-18":{"x":186,"y":384,"width":18,"height":18},"disability-12":{"x":204,"y":384,"width":12,"height":12},"telephone-24":{"x":216,"y":384,"width":24,"height":24},"telephone-18":{"x":240,"y":384,"width":18,"height":18},"telephone-12":{"x":258,"y":384,"width":12,"height":12},"emergency-telephone-24":{"x":0,"y":408,"width":24,"height":24},"emergency-telephone-18":{"x":24,"y":408,"width":18,"height":18},"emergency-telephone-12":{"x":42,"y":408,"width":12,"height":12},"toilets-24":{"x":54,"y":408,"width":24,"height":24},"toilets-18":{"x":78,"y":408,"width":18,"height":18},"toilets-12":{"x":96,"y":408,"width":12,"height":12},"waste-basket-24":{"x":108,"y":408,"width":24,"height":24},"waste-basket-18":{"x":132,"y":408,"width":18,"height":18},"waste-basket-12":{"x":150,"y":408,"width":12,"height":12},"music-24":{"x":162,"y":408,"width":24,"height":24},"music-18":{"x":186,"y":408,"width":18,"height":18},"music-12":{"x":204,"y":408,"width":12,"height":12},"land-use-24":{"x":216,"y":408,"width":24,"height":24},"land-use-18":{"x":240,"y":408,"width":18,"height":18},"land-use-12":{"x":258,"y":408,"width":12,"height":12},"city-24":{"x":0,"y":432,"width":24,"height":24},"city-18":{"x":24,"y":432,"width":18,"height":18},"city-12":{"x":42,"y":432,"width":12,"height":12},"town-24":{"x":54,"y":432,"width":24,"height":24},"town-18":{"x":78,"y":432,"width":18,"height":18},"town-12":{"x":96,"y":432,"width":12,"height":12},"village-24":{"x":108,"y":432,"width":24,"height":24},"village-18":{"x":132,"y":432,"width":18,"height":18},"village-12":{"x":150,"y":432,"width":12,"height":12},"farm-24":{"x":162,"y":432,"width":24,"height":24},"farm-18":{"x":186,"y":432,"width":18,"height":18},"farm-12":{"x":204,"y":432,"width":12,"height":12},"bakery-24":{"x":216,"y":432,"width":24,"height":24},"bakery-18":{"x":240,"y":432,"width":18,"height":18},"bakery-12":{"x":258,"y":432,"width":12,"height":12},"dog-park-24":{"x":0,"y":456,"width":24,"height":24},"dog-park-18":{"x":24,"y":456,"width":18,"height":18},"dog-park-12":{"x":42,"y":456,"width":12,"height":12},"lighthouse-24":{"x":54,"y":456,"width":24,"height":24},"lighthouse-18":{"x":78,"y":456,"width":18,"height":18},"lighthouse-12":{"x":96,"y":456,"width":12,"height":12},"clothing-store-24":{"x":108,"y":456,"width":24,"height":24},"clothing-store-18":{"x":132,"y":456,"width":18,"height":18},"clothing-store-12":{"x":150,"y":456,"width":12,"height":12},"polling-place-24":{"x":162,"y":456,"width":24,"height":24},"polling-place-18":{"x":186,"y":456,"width":18,"height":18},"polling-place-12":{"x":204,"y":456,"width":12,"height":12},"playground-24":{"x":216,"y":456,"width":24,"height":24},"playground-18":{"x":240,"y":456,"width":18,"height":18},"playground-12":{"x":258,"y":456,"width":12,"height":12},"entrance-24":{"x":0,"y":480,"width":24,"height":24},"entrance-18":{"x":24,"y":480,"width":18,"height":18},"entrance-12":{"x":42,"y":480,"width":12,"height":12},"heart-24":{"x":54,"y":480,"width":24,"height":24},"heart-18":{"x":78,"y":480,"width":18,"height":18},"heart-12":{"x":96,"y":480,"width":12,"height":12},"london-underground-24":{"x":108,"y":480,"width":24,"height":24},"london-underground-18":{"x":132,"y":480,"width":18,"height":18},"london-underground-12":{"x":150,"y":480,"width":12,"height":12},"minefield-24":{"x":162,"y":480,"width":24,"height":24},"minefield-18":{"x":186,"y":480,"width":18,"height":18},"minefield-12":{"x":204,"y":480,"width":12,"height":12},"rail-underground-24":{"x":216,"y":480,"width":24,"height":24},"rail-underground-18":{"x":240,"y":480,"width":18,"height":18},"rail-underground-12":{"x":258,"y":480,"width":12,"height":12},"rail-above-24":{"x":0,"y":504,"width":24,"height":24},"rail-above-18":{"x":24,"y":504,"width":18,"height":18},"rail-above-12":{"x":42,"y":504,"width":12,"height":12},"camera-24":{"x":54,"y":504,"width":24,"height":24},"camera-18":{"x":78,"y":504,"width":18,"height":18},"camera-12":{"x":96,"y":504,"width":12,"height":12},"laundry-24":{"x":108,"y":504,"width":24,"height":24},"laundry-18":{"x":132,"y":504,"width":18,"height":18},"laundry-12":{"x":150,"y":504,"width":12,"height":12},"car-24":{"x":162,"y":504,"width":24,"height":24},"car-18":{"x":186,"y":504,"width":18,"height":18},"car-12":{"x":204,"y":504,"width":12,"height":12},"suitcase-24":{"x":216,"y":504,"width":24,"height":24},"suitcase-18":{"x":240,"y":504,"width":18,"height":18},"suitcase-12":{"x":258,"y":504,"width":12,"height":12},"hairdresser-24":{"x":0,"y":528,"width":24,"height":24},"hairdresser-18":{"x":24,"y":528,"width":18,"height":18},"hairdresser-12":{"x":42,"y":528,"width":12,"height":12},"chemist-24":{"x":54,"y":528,"width":24,"height":24},"chemist-18":{"x":78,"y":528,"width":18,"height":18},"chemist-12":{"x":96,"y":528,"width":12,"height":12},"mobilephone-24":{"x":108,"y":528,"width":24,"height":24},"mobilephone-18":{"x":132,"y":528,"width":18,"height":18},"mobilephone-12":{"x":150,"y":528,"width":12,"height":12},"scooter-24":{"x":162,"y":528,"width":24,"height":24},"scooter-18":{"x":186,"y":528,"width":18,"height":18},"scooter-12":{"x":204,"y":528,"width":12,"height":12},"gift-24":{"x":216,"y":528,"width":24,"height":24},"gift-18":{"x":240,"y":528,"width":18,"height":18},"gift-12":{"x":258,"y":528,"width":12,"height":12},"ice-cream-24":{"x":0,"y":552,"width":24,"height":24},"ice-cream-18":{"x":24,"y":552,"width":18,"height":18},"ice-cream-12":{"x":42,"y":552,"width":12,"height":12}},"locales":["af","sq","ar","ar-AA","hy","ast","bn","bs","bg-BG","ca","zh","zh-CN","zh-HK","zh-TW","yue","hr","cs","da","nl","en-GB","eo","et","fi","fr","gl","de","el","gu","hi","hu","is","id","it","ja","kn","ko","lv","lij","lt","ml","no","fa","pl","pt","pt-BR","ro","ru","sc","sr","si","sk","sl","es","sv","tl","ta","te","th","tr","uk","vi"],"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":"Delete object 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} objects."},"incomplete_relation":"This feature can't be deleted because it hasn't been fully downloaded.","part_of_relation":"This feature can't be deleted because it's part of a larger relation. You must remove it from the relation first.","connected_to_hidden":"This can't be deleted because it is connected to a hidden feature."},"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 they 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":"Move this 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 objects."},"incomplete_relation":"This feature can't be moved because it hasn't been fully downloaded.","too_large":"This can't be moved because not enough of it is currently visible.","connected_to_hidden":"This can't be moved because it is connected to a hidden feature."},"rotate":{"title":"Rotate","description":"Rotate this object around its center point.","key":"R","annotation":{"line":"Rotated a line.","area":"Rotated an area."},"too_large":"This can't be rotated because not enough of it is currently visible.","connected_to_hidden":"This can't be rotated because it is connected to a hidden feature."},"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","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."},"commit":{"title":"Save Changes","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":"Save","cancel":"Cancel","changes":"{count} Changes","warnings":"Warnings","modified":"Modified","deleted":"Deleted","created":"Created","about_changeset_comments":"About changeset comments","about_changeset_comments_link":"//wiki.openstreetmap.org/wiki/Good_changeset_comments","google_warning":"You mentioned Google in this comment: remember that copying from Google Maps is strictly forbidden.","google_warning_link":"http://www.openstreetmap.org/copyright"},"contributors":{"list":"Edits by {users}","truncated_list":"Edits by {users} and {count} others"},"infobox":{"selected":"{n} selected","geometry":"Geometry","closed":"closed","center":"Center","perimeter":"Perimeter","length":"Length","area":"Area","centroid":"Centroid","location":"Location","metric":"Metric","imperial":"Imperial"},"geometry":{"point":"point","vertex":"vertex","line":"line","area":"area","relation":"relation"},"geocoder":{"search":"Search worldwide...","no_results_visible":"No results in visible map area","no_results_worldwide":"No results found"},"geolocate":{"title":"Show My Location","locating":"Locating, please wait..."},"inspector":{"no_documentation_combination":"There is no documentation available for this tag combination","no_documentation_key":"There is no documentation available for this key","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 items","unknown":"Unknown","incomplete":"<not downloaded>","feature_list":"Search features","edit":"Edit feature","check":{"yes":"Yes","no":"No"},"add":"Add","none":"None","node":"Node","way":"Way","relation":"Relation","location":"Location","add_fields":"Add field:"},"background":{"title":"Background","description":"Background settings","percent_brightness":"{opacity}% brightness","none":"None","best_imagery":"Best known imagery source for this location","switch":"Switch back to this background","custom":"Custom","custom_button":"Edit custom background","custom_prompt":"Enter a tile URL template. Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.","fix_misalignment":"Adjust imagery offset","imagery_source_faq":"Where does this imagery come from?","reset":"reset","offset":"Drag anywhere in the gray area below to adjust the imagery offset, or enter the offset values in meters.","minimap":{"description":"Minimap","tooltip":"Show a zoomed out map to help locate the area currently displayed."}},"map_data":{"title":"Map Data","description":"Map Data","data_layers":"Data Layers","fill_area":"Fill Areas","map_features":"Map Features","autohidden":"These features have been automatically hidden because too many would be shown on the screen. You can zoom in to edit them."},"feature":{"points":{"description":"Points","tooltip":"Points of Interest"},"traffic_roads":{"description":"Traffic Roads","tooltip":"Highways, Streets, etc."},"service_roads":{"description":"Service Roads","tooltip":"Service Roads, Parking Aisles, Tracks, etc."},"paths":{"description":"Paths","tooltip":"Sidewalks, Foot Paths, Cycle Paths, etc."},"buildings":{"description":"Buildings","tooltip":"Buildings, Shelters, Garages, etc."},"landuse":{"description":"Landuse Features","tooltip":"Forests, Farmland, Parks, Residential, Commercial, etc."},"boundaries":{"description":"Boundaries","tooltip":"Administrative Boundaries"},"water":{"description":"Water Features","tooltip":"Rivers, Lakes, Ponds, Basins, etc."},"rail":{"description":"Rail Features","tooltip":"Railways"},"power":{"description":"Power Features","tooltip":"Power Lines, Power Plants, Substations, etc."},"past_future":{"description":"Past/Future","tooltip":"Proposed, Construction, Abandoned, Demolished, etc."},"others":{"description":"Others","tooltip":"Everything Else"}},"area_fill":{"wireframe":{"description":"No Fill (Wireframe)","tooltip":"Enabling wireframe mode makes it easy to see the background imagery."},"partial":{"description":"Partial Fill","tooltip":"Areas are drawn with fill only around their inner edges. (Recommended for beginner mappers)"},"full":{"description":"Full Fill","tooltip":"Areas are drawn fully filled."}},"restore":{"heading":"You have unsaved changes","description":"Do you wish to restore unsaved changes from a previous editing session?","restore":"Restore","reset":"Reset"},"save":{"title":"Save","help":"Save changes 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 item 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 object has been deleted by {user}.","location":"This object 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":"Okay","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"},"tag_reference":{"description":"Description","on_wiki":"{tag} on wiki.osm.org","used_with":"used with {type}"},"validations":{"untagged_point":"Untagged point","untagged_line":"Untagged line","untagged_area":"Untagged area","many_deletions":"You're deleting {n} objects. 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","untagged_point_tooltip":"Select a feature type that describes what this point is.","untagged_line_tooltip":"Select a feature type that describes what this line is.","untagged_area_tooltip":"Select a feature type that describes what this area is.","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 GPX file","drag_drop":"Drag and drop a .gpx file on the page, or click the button to the right to browse","zoom":"Zoom to GPX track","browse":"Browse for a .gpx file"},"mapillary_images":{"tooltip":"Street-level photos from Mapillary","title":"Photo Overlay (Mapillary)"},"mapillary_signs":{"tooltip":"Traffic signs from Mapillary (must enable Photo Overlay)","title":"Traffic Sign Overlay (Mapillary)"},"mapillary":{"view_on_mapillary":"View this image on Mapillary"},"help":{"title":"Help","help":"# Help\n\nThis is an editor for [OpenStreetMap](http://www.openstreetmap.org/), the\nfree and editable map of the world. You can use it to add and update\ndata in your area, making an open-source and open-data map of the world\nbetter for everyone.\n\nEdits that you make on this map will be visible to everyone who uses\nOpenStreetMap. In order to make an edit, you'll need to\n[log in](https://www.openstreetmap.org/login).\n\nThe [iD editor](http://ideditor.com/) is a collaborative project with [source\ncode available on GitHub](https://github.com/openstreetmap/iD).\n","editing_saving":"# Editing & Saving\n\nThis editor is designed to work primarily online, and you're accessing\nit through a website right now.\n\n### Selecting Features\n\nTo select a map feature, like a road or point of interest, click\non it on the map. This will highlight the selected feature, open a panel with\ndetails about it, and show a menu of things you can do with the feature.\n\nTo select multiple features, hold down the 'Shift' key. Then either click\non the features you want to select, or drag on the map to draw a rectangle.\nThis will draw a box and select all the points within it.\n\n### Saving Edits\n\nWhen you make changes like editing roads, buildings, and places, these are\nstored locally until you save them to the server. Don't worry if you make\na mistake - you can undo changes by clicking the undo button, and redo\nchanges by clicking the redo button.\n\nClick 'Save' to finish a group of edits - for instance, if you've completed\nan area of town and would like to start on a new area. You'll have a chance\nto review what you've done, and the editor supplies helpful suggestions\nand warnings if something doesn't seem right about the changes.\n\nIf everything looks good, you can enter a short comment explaining the change\nyou made, and click 'Save' again to post the changes\nto [OpenStreetMap.org](http://www.openstreetmap.org/), where they are visible\nto all other users and available for others to build and improve upon.\n\nIf you can't finish your edits in one sitting, you can leave the editor\nwindow and come back (on the same browser and computer), and the\neditor application will offer to restore your work.\n\n### Using the editor\n\nA list of available keyboard shortcuts can be found [here](http://wiki.openstreetmap.org/wiki/ID/Shortcuts).\n","roads":"# Roads\n\nYou can create, fix, and delete roads with this editor. Roads can be all\nkinds: paths, highways, trails, cycleways, and more - any often-crossed\nsegment should be mappable.\n\n### Selecting\n\nClick on a road to select it. An outline should become visible, along\nwith a small tools menu on the map and a sidebar showing more information\nabout the road.\n\n### Modifying\n\nOften you'll see roads that aren't aligned to the imagery behind them\nor to a GPS track. You can adjust these roads so they are in the correct\nplace.\n\nFirst click on the road you want to change. This will highlight it and show\ncontrol points along it that you can drag to better locations. If\nyou want to add new control points for more detail, double-click a part\nof the road without a node, and one will be added.\n\nIf the road connects to another road, but doesn't properly connect on\nthe map, you can drag one of its control points onto the other road in\norder to join them. Having roads connect is important for the map\nand essential for providing driving directions.\n\nYou can also click the 'Move' tool or press the `M` shortcut key to move the entire road at\none time, and then click again to save that movement.\n\n### Deleting\n\nIf a road is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the road could simply be newly built.\n\nYou can delete a road by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n\n### Creating\n\nFound somewhere there should be a road but there isn't? Click the 'Line'\nicon in the top-left of the editor or press the shortcut key `2` to start drawing\na line.\n\nClick on the start of the road on the map to start drawing. If the road\nbranches off from an existing road, start by clicking on the place where they connect.\n\nThen click on points along the road so that it follows the right path, according\nto satellite imagery or GPS. If the road you are drawing crosses another road, connect\nit by clicking on the intersection point. When you're done drawing, double-click\nor press 'Return' or 'Enter' on your keyboard.\n","gps":"# GPS\n\nCollected GPS traces are one valuable source of data for OpenStreetMap. This editor\nsupports local traces - `.gpx` files on your local computer. You can collect\nthis kind of GPS trace with a number of smartphone applications as well as\npersonal GPS hardware.\n\nFor information on how to perform a GPS survey, read\n[Mapping with a smartphone, GPS, or paper](http://learnosm.org/en/mobile-mapping/).\n\nTo use a GPX track for mapping, drag and drop the GPX file onto the map\neditor. If it's recognized, it will be added to the map as a bright purple\nline. Click on the 'Map Data' menu on the right side to enable,\ndisable, or zoom to this new GPX-powered layer.\n\nThe GPX track isn't directly uploaded to OpenStreetMap - the best way to\nuse it is to draw on the map, using it as a guide for the new features that\nyou add, and also to [upload it to OpenStreetMap](http://www.openstreetmap.org/trace/create)\nfor other users to use.\n","imagery":"# Imagery\n\nAerial imagery is an important resource for mapping. A combination of\nairplane flyovers, satellite views, and freely-compiled sources are available\nin the editor under the 'Background Settings' menu on the right.\n\nBy default a [Bing Maps](http://www.bing.com/maps/) satellite layer is\npresented in the editor, but as you pan and zoom the map to new geographical\nareas, new sources will become available. Some countries, like the United\nStates, France, and Denmark have very high-quality imagery available for some areas.\n\nImagery is sometimes offset from the map data because of a mistake on the\nimagery provider's side. If you see a lot of roads shifted from the background,\ndon't immediately move them all to match the background. Instead you can adjust\nthe imagery so that it matches the existing data by clicking 'Fix alignment' at\nthe bottom of the Background Settings UI.\n","addresses":"# Addresses\n\nAddresses are some of the most useful information for the map.\n\nAlthough addresses are often represented as parts of streets, in OpenStreetMap\nthey're recorded as attributes of buildings and places along streets.\n\nYou can add address information to places mapped as building outlines\nas well as those mapped as single points. The optimal source of address\ndata is from an on-the-ground survey or personal knowledge - as with any\nother feature, copying from commercial sources like Google Maps is strictly\nforbidden.\n","inspector":"# Using the Inspector\n\nThe inspector is the section on the left side of the page that allows you to\nedit the details of the selected feature.\n\n### Selecting a Feature Type\n\nAfter you add a point, line, or area, you can choose what type of feature it\nis, like whether it's a highway or residential road, supermarket or cafe.\nThe inspector will display buttons for common feature types, and you can\nfind others by typing what you're looking for in the search box.\n\nClick the 'i' in the bottom-right-hand corner of a feature type button to\nlearn more about it. Click a button to choose that type.\n\n### Using Forms and Editing Tags\n\nAfter you choose a feature type, or when you select a feature that already\nhas a type assigned, the inspector will display fields with details about\nthe feature like its name and address.\n\nBelow the fields you see, you can click the 'Add field' dropdown to add\nother details, like a Wikipedia link, wheelchair access, and more.\n\nAt the bottom of the inspector, click 'Additional tags' to add arbitrary\nother tags to the element. [Taginfo](http://taginfo.openstreetmap.org/) is a\ngreat resource for learn more about popular tag combinations.\n\nChanges you make in the inspector are automatically applied to the map.\nYou can undo them at any time by clicking the 'Undo' button.\n","buildings":"# Buildings\n\nOpenStreetMap is the world's largest database of buildings. You can create\nand improve this database.\n\n### Selecting\n\nYou can select a building by clicking on its border. This will highlight the\nbuilding and open a small tools menu and a sidebar showing more information\nabout the building.\n\n### Modifying\n\nSometimes buildings are incorrectly placed or have incorrect tags.\n\nTo move an entire building, select it, then click the 'Move' tool. Move your\nmouse to shift the building, and click when it's correctly placed.\n\nTo fix the specific shape of a building, click and drag the nodes that form\nits border into better places.\n\n### Creating\n\nOne of the main questions around adding buildings to the map is that\nOpenStreetMap records buildings both as shapes and points. The rule of thumb\nis to _map a building as a shape whenever possible_, and map companies, homes,\namenities, and other things that operate out of buildings as points placed\nwithin the building shape.\n\nStart drawing a building as a shape by clicking the 'Area' button in the top\nleft of the interface, and end it either by pressing 'Return' on your keyboard\nor clicking on the first node drawn to close the shape.\n\n### Deleting\n\nIf a building is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the building could simply be newly built.\n\nYou can delete a building by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n","relations":"# Relations\n\nA relation is a special type of feature in OpenStreetMap that groups together\nother features. For example, two common types of relations are *route relations*,\nwhich group together sections of road that belong to a specific freeway or\nhighway, and *multipolygons*, which group together several lines that define\na complex area (one with several pieces or holes in it like a donut).\n\nThe group of features in a relation are called *members*. In the sidebar, you can\nsee which relations a feature is a member of, and click on a relation there\nto select the it. When the relation is selected, you can see all of its\nmembers listed in the sidebar and highlighted on the map.\n\nFor the most part, iD will take care of maintaining relations automatically\nwhile you edit. The main thing you should be aware of is that if you delete a\nsection of road to redraw it more accurately, you should make sure that the\nnew section is a member of the same relations as the original.\n\n## Editing Relations\n\nIf you want to edit relations, here are the basics.\n\nTo add a feature to a relation, select the feature, click the \"+\" button in the\n\"All relations\" section of the sidebar, and select or type the name of the relation.\n\nTo create a new relation, select the first feature that should be a member,\nclick the \"+\" button in the \"All relations\" section, and select \"New relation...\".\n\nTo remove a feature from a relation, select the feature and click the trash\nbutton next to the relation you want to remove it from.\n\nYou can create multipolygons with holes using the \"Merge\" tool. Draw two areas (inner\nand outer), hold the Shift key and click on each of them to select them both, and then\nclick the \"Merge\" (+) button.\n"},"intro":{"graph":{"city_hall":"Three Rivers City Hall","fire_department":"Three Rivers Fire Department","memory_isle_park":"Memory Isle Park","riverwalk_trail":"Riverwalk Trail","w_michigan_ave":"West Michigan Avenue","e_michigan_ave":"East Michigan Avenue","spring_st":"Spring Street","scidmore_park":"Scidmore Park","petting_zoo":"Scidmore Park Petting Zoo","n_andrews_st":"North Andrews Street","s_andrews_st":"South Andrews Street","n_constantine_st":"North Constantine Street","s_constantine_st":"South Constantine Street","rocky_river":"Rocky River","railroad_dr":"Railroad Drive","conrail_rr":"Conrail Railroad","st_joseph_river":"Saint Joseph River","n_main_st":"North Main Street","s_main_st":"South Main Street","water_st":"Water Street","foster_st":"Foster Street","portage_river":"Portage River","flower_st":"Flower Street","elm_st":"Elm Street","walnut_st":"Walnut Street","morris_ave":"Morris Avenue","east_st":"East Street","portage_ave":"Portage Avenue"},"navigation":{"title":"Navigation","drag":"The main map area shows OpenStreetMap data on top of a background. You can navigate by dragging and scrolling, just like any web map. **Drag the map!**","select":"Map features are represented three ways: using points, lines or areas. All features can be selected by clicking on them. **Click on the point to select it.**","pane":"When a feature is selected, the feature editor is displayed. The header shows us the feature type and the main pane shows the feature's attributes, such as its name and address. **Close the feature editor by pressing the {button} button in the top right.**","search":"You can also search for features in the current view, or worldwide. **Search for '{name}'**","choose":"**Choose {name} from the list to select it.**","chosen":"Great! {name} is now selected. **Close the feature editor by pressing the {button} button.**"},"points":{"title":"Points","add":"Points can be used to represent features such as shops, restaurants, and monuments. They mark a specific location, and describe what's there. **Click the {button} Point button to add a new point.**","place":"The point can be placed by clicking on the map. **Click the map to place the new point on top of the building.**","search":"There are many different features that can be represented by points. The point you just added is a Cafe. **Search for '{name}'**","choose":"**Choose Cafe from the list.**","describe":"The point is now marked as a cafe. Using the feature editor, we can add more information about the feature. **Add a name**","close":"The feature editor will remember all of your changes automatically. When you change a feature, the close button will change to a checkmark. **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 point you just created.**","fixname":"**Change the name, then click the {button} button to close the feature editor.**","reselect_delete":"All features on the map can be deleted. **Click to select the point you created.**","delete":"The menu around the point contains operations that can be performed on it, including delete. **Click on the {button} button to delete the point.**"},"areas":{"title":"Areas","add":"Areas are used to show the boundaries of features like lakes, buildings, and residential areas. 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.**","corner":"Areas are drawn by placing nodes that mark the boundary of the area. **Click to place a starting node on one of the corners of the playground.**","place":"Draw the area by placing more nodes. Finish the area by clicking on the starting node. **Draw an area for the playground.**","search":"**Search for '{name}'.**","choose":"**Choose Playground from the list.**","describe":"**Add a name, then click the {button} button to close the feature editor**"},"lines":{"title":"Lines","add":"Lines are used to represent features such as roads, railroads, and rivers. **Click the {button} Line button to add a new line.**","start":"**Start the line by clicking on the end of the road.**","intersect":"Click to add more nodes to the line. You can drag the map while drawing if necessary. 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.**","finish":"Lines can be finished by clicking on the last node again. **Finish drawing the road.**","road":"**Select Road from the list**","residential":"There are different types of roads, the most common of which is Residential. **Choose the Residential road type**","describe":"**Name the road, then click the {button} button to close the feature editor.**","restart":"The road needs to intersect {name}.","wrong_preset":"You didn't select the Residential road type. **Click here to choose again**"},"startediting":{"title":"Start Editing","help":"You can replay this walkthrough or view more documentation by clicking the {button} Help button.","save":"Don't forget to regularly save your changes!","start":"Start mapping!"}},"presets":{"categories":{"category-barrier":{"name":"Barrier Features"},"category-building":{"name":"Building Features"},"category-golf":{"name":"Golf Features"},"category-landuse":{"name":"Land Use Features"},"category-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":{"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"}}},"access_simple":{"label":"Allowed Access","placeholder":"yes"},"access_toilets":{"label":"Access"},"address":{"label":"Address","placeholders":{"housename":"Housename","housenumber":"123","conscriptionnumber":"123","street":"Street","city":"City","postcode":"Postcode","place":"Place","hamlet":"Hamlet","suburb":"Suburb","subdistrict":"Subdistrict","district":"District","province":"Province","state":"State","country":"Country"}},"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"},"area/highway":{"label":"Type"},"artist":{"label":"Artist"},"artwork_type":{"label":"Type"},"atm":{"label":"ATM"},"backrest":{"label":"Backrest"},"barrier":{"label":"Type"},"bench":{"label":"Bench"},"bicycle_parking":{"label":"Type"},"bin":{"label":"Waste Bin"},"boundary":{"label":"Type"},"brand":{"label":"Brand"},"building":{"label":"Building"},"building_area":{"label":"Building"},"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"}},"clock_direction":{"label":"Direction","options":{"clockwise":"Clockwise","anticlockwise":"Counterclockwise"}},"collection_times":{"label":"Collection Times"},"construction":{"label":"Type"},"content":{"label":"Contents"},"country":{"label":"Country"},"covered":{"label":"Covered"},"craft":{"label":"Type"},"crop":{"label":"Crop"},"crossing":{"label":"Type"},"cuisine":{"label":"Cuisine"},"currency_multi":{"label":"Currency Types"},"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"}}},"delivery":{"label":"Delivery"},"denomination":{"label":"Denomination"},"denotation":{"label":"Denotation"},"description":{"label":"Description"},"diaper":{"label":"Diaper Changing Available"},"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"},"emergency":{"label":"Emergency"},"entrance":{"label":"Type"},"except":{"label":"Exceptions"},"fax":{"label":"Fax","placeholder":"+31 42 123 4567"},"fee":{"label":"Fee"},"fire_hydrant/type":{"label":"Type","options":{"pillar":"Pillar/Aboveground","underground":"Underground","wall":"Wall","pond":"Pond"}},"fixme":{"label":"Fix Me"},"fuel":{"label":"Fuel"},"fuel_multi":{"label":"Fuel Types"},"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)"},"handicap":{"label":"Handicap","placeholder":"1-18"},"handrail":{"label":"Handrail"},"highway":{"label":"Type"},"historic":{"label":"Type"},"hoops":{"label":"Hoops","placeholder":"1, 2, 4..."},"iata":{"label":"IATA"},"icao":{"label":"ICAO"},"incline":{"label":"Incline"},"incline_steps":{"label":"Incline","options":{"up":"Up","down":"Down"}},"information":{"label":"Type"},"internet_access":{"label":"Internet Access","options":{"yes":"Yes","no":"No","wlan":"Wifi","wired":"Wired","terminal":"Terminal"}},"internet_access/fee":{"label":"Internet Access Fee"},"kerb":{"label":"Curb Ramp"},"lamp_type":{"label":"Type"},"landuse":{"label":"Type"},"lanes":{"label":"Lanes","placeholder":"1, 2, 3..."},"layer":{"label":"Layer"},"leaf_cycle":{"label":"Leaf Cycle","options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous","mixed":"Mixed"}},"leaf_cycle_singular":{"label":"Leaf Cycle","options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous"}},"leaf_type":{"label":"Leaf Type","options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","mixed":"Mixed","leafless":"Leafless"}},"leaf_type_singular":{"label":"Leaf Type","options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","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"},"maxspeed":{"label":"Speed Limit","placeholder":"40, 50, 60..."},"maxstay":{"label":"Max Stay"},"mtb/scale":{"label":"Mountain Biking Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Solid gravel/packed earth, no obstacles, wide curves","1":"1: Some loose surface, small obstacles, wide curves","2":"2: Much loose surface, large obstacles, easy hairpins","3":"3: Slippery surface, large obstacles, tight hairpins","4":"4: Loose surface or boulders, dangerous hairpins","5":"5: Maximum difficulty, boulder fields, landslides","6":"6: Not rideable except by the very best mountain bikers"}},"mtb/scale/imba":{"label":"IMBA Trail Difficulty","placeholder":"Easy, Medium, Difficult...","options":{"0":"Easiest (white circle)","1":"Easy (green circle)","2":"Medium (blue square)","3":"Difficult (black diamond)","4":"Extremely Difficult (double black diamond)"}},"mtb/scale/uphill":{"label":"Mountain Biking Uphill Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Avg. incline <10%, gravel/packed earth, no obstacles","1":"1: Avg. incline <15%, gravel/packed earth, few small objects","2":"2: Avg. incline <20%, stable surface, fistsize rocks/roots","3":"3: Avg. incline <25%, variable surface, fistsize rocks/branches","4":"4: Avg. incline <30%, poor condition, big rocks/branches","5":"5: Very steep, bike generally needs to be pushed or carried"}},"name":{"label":"Name","placeholder":"Common name (if any)"},"natural":{"label":"Natural"},"network":{"label":"Network"},"note":{"label":"Note"},"office":{"label":"Type"},"oneway":{"label":"One Way","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"oneway_yes":{"label":"One Way","options":{"undefined":"Assumed to be Yes","yes":"Yes","no":"No"}},"opening_hours":{"label":"Hours"},"operator":{"label":"Operator"},"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"},"population":{"label":"Population"},"power":{"label":"Type"},"power_supply":{"label":"Power Supply"},"railway":{"label":"Type"},"recycling_accepts":{"label":"Accepts"},"ref":{"label":"Reference"},"relation":{"label":"Type"},"religion":{"label":"Religion"},"restriction":{"label":"Type"},"restrictions":{"label":"Turn Restrictions"},"rooms":{"label":"Rooms"},"route":{"label":"Type"},"route_master":{"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"},"service":{"label":"Type"},"service/bicycle/chain_tool":{"label":"Chain Tool","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"service/bicycle/pump":{"label":"Air Pump","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"service_rail":{"label":"Service Type","options":{"spur":"Spur","yard":"Yard","siding":"Siding","crossover":"Crossover"}},"shelter":{"label":"Shelter"},"shelter_type":{"label":"Type"},"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","placeholder":"Homeless, Disabled, Child, etc"},"source":{"label":"Source"},"sport":{"label":"Sport"},"sport_ice":{"label":"Sport"},"sport_racing":{"label":"Sport"},"stars":{"label":"Stars"},"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"},"surface":{"label":"Surface"},"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"}},"tourism":{"label":"Type"},"towertype":{"label":"Tower 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_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"},"water":{"label":"Type"},"water_point":{"label":"Water Point"},"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":{"address":{"name":"Address","terms":""},"aerialway":{"name":"Aerialway","terms":"ski lift,funifor,funitel"},"aerialway/cable_car":{"name":"Cable Car","terms":"tramway,ropeway"},"aerialway/chair_lift":{"name":"Chair Lift","terms":""},"aerialway/gondola":{"name":"Gondola","terms":""},"aerialway/magic_carpet":{"name":"Magic Carpet 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":{"name":"Aeroway","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":{"name":"Amenity","terms":""},"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/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/embassy":{"name":"Embassy","terms":""},"amenity/fast_food":{"name":"Fast Food","terms":"restaurant"},"amenity/ferry_terminal":{"name":"Ferry Terminal","terms":""},"amenity/fire_station":{"name":"Fire Station","terms":""},"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 service,hospice,infirmary,institution,nursing home,sanatorium,sanitarium,sick,surgery,ward"},"amenity/hunting_stand":{"name":"Hunting Stand","terms":""},"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":{"name":"Car Parking","terms":""},"amenity/parking_entrance":{"name":"Parking Garage Entrance/Exit","terms":""},"amenity/parking_space":{"name":"Parking Space","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/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":"dive,beer,bier,booze"},"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":{"name":"Recycling","terms":"can,bottle,garbage,scrap,trash"},"amenity/register_office":{"name":"Register Office","terms":""},"amenity/restaurant":{"name":"Restaurant","terms":"bar,breakfast,cafe,café,canteen,coffee,dine,dining,dinner,drive-in,eat,grill,lunch,table"},"amenity/sanitary_dump_station":{"name":"RV Toilet Disposal","terms":"Motor Home,Camper,Sanitary,Dump Station,Elsan,CDP,CTDP,Chemical Toilet"},"amenity/school":{"name":"School Grounds","terms":"academy,elementary school,middle school,high school"},"amenity/shelter":{"name":"Shelter","terms":"lean-to,gazebo,picnic"},"amenity/social_facility":{"name":"Social Facility","terms":""},"amenity/social_facility/food_bank":{"name":"Food Bank","terms":""},"amenity/social_facility/group_home":{"name":"Elderly Group Home","terms":"old,senior,living"},"amenity/social_facility/homeless_shelter":{"name":"Homeless Shelter","terms":"houseless,unhoused,displaced"},"amenity/studio":{"name":"Studio","terms":"recording,radio,television"},"amenity/swimming_pool":{"name":"Swimming Pool","terms":""},"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/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/news_papers":{"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/vending_machine/vending_machine":{"name":"Vending Machine","terms":""},"amenity/veterinary":{"name":"Veterinary","terms":"pet clinic,veterinarian,animal hospital,pet doctor"},"amenity/waste_basket":{"name":"Waste Basket","terms":"bin,rubbish,litter,trash,garbage"},"amenity/waste_disposal":{"name":"Garbage Dumpster","terms":"rubbish,litter,trash"},"amenity/water_point":{"name":"RV Drinking Water","terms":""},"area":{"name":"Area","terms":""},"area/highway":{"name":"Road Surface","terms":""},"barrier":{"name":"Barrier","terms":""},"barrier/block":{"name":"Block","terms":""},"barrier/bollard":{"name":"Bollard","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/entrance":{"name":"Entrance","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/apartments":{"name":"Apartments","terms":""},"building/barn":{"name":"Barn","terms":""},"building/bunker":{"name":"Bunker","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/entrance":{"name":"Entrance/Exit","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/train_station":{"name":"Train Station","terms":""},"building/university":{"name":"University Building","terms":"college"},"building/warehouse":{"name":"Warehouse","terms":""},"craft":{"name":"Craft","terms":""},"craft/basket_maker":{"name":"Basket Maker","terms":""},"craft/beekeeper":{"name":"Beekeeper","terms":""},"craft/blacksmith":{"name":"Blacksmith","terms":""},"craft/boatbuilder":{"name":"Boat Builder","terms":""},"craft/bookbinder":{"name":"Bookbinder","terms":"book repair"},"craft/brewery":{"name":"Brewery","terms":"beer,bier"},"craft/carpenter":{"name":"Carpenter","terms":"woodworker"},"craft/carpet_layer":{"name":"Carpet Layer","terms":""},"craft/caterer":{"name":"Caterer","terms":""},"craft/clockmaker":{"name":"Clockmaker","terms":""},"craft/confectionery":{"name":"Confectionery","terms":"sweets,candy"},"craft/dressmaker":{"name":"Dressmaker","terms":"seamstress"},"craft/electrician":{"name":"Electrician","terms":"power,wire"},"craft/gardener":{"name":"Gardener","terms":"landscaper,grounds keeper"},"craft/glaziery":{"name":"Glaziery","terms":"glass,stained-glass,window"},"craft/handicraft":{"name":"Handicraft","terms":""},"craft/hvac":{"name":"HVAC","terms":"heat*,vent*,air conditioning"},"craft/insulator":{"name":"Insulator","terms":""},"craft/jeweler":{"name":"Jeweler","terms":""},"craft/key_cutter":{"name":"Key Cutter","terms":""},"craft/locksmith":{"name":"Locksmith","terms":""},"craft/metal_construction":{"name":"Metal Construction","terms":""},"craft/optician":{"name":"Optician","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/tailor":{"name":"Tailor","terms":"clothes,suit"},"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/ambulance_station":{"name":"Ambulance Station","terms":"EMS,EMT,rescue"},"emergency/defibrillator":{"name":"Defibrillator","terms":""},"emergency/fire_hydrant":{"name":"Fire Hydrant","terms":""},"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":{"name":"Lateral Water Hazard","terms":""},"golf/rough":{"name":"Rough","terms":""},"golf/tee":{"name":"Tee Box","terms":"teeing ground"},"golf/water_hazard":{"name":"Water Hazard","terms":""},"highway":{"name":"Highway","terms":""},"highway/bridleway":{"name":"Bridle Path","terms":"bridleway,equestrian,horse"},"highway/bus_stop":{"name":"Bus Stop","terms":""},"highway/corridor":{"name":"Indoor Corridor","terms":"gallery,hall,hallway,indoor,passage,passageway"},"highway/crossing":{"name":"Street Crossing","terms":""},"highway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"highway/cycleway":{"name":"Cycle Path","terms":"bike"},"highway/footway":{"name":"Foot Path","terms":"hike,hiking,trackway,trail,walk"},"highway/give_way":{"name":"Yield Sign","terms":"give way,yield,sign"},"highway/living_street":{"name":"Living Street","terms":""},"highway/mini_roundabout":{"name":"Mini-Roundabout","terms":""},"highway/motorway":{"name":"Motorway","terms":""},"highway/motorway_junction":{"name":"Motorway Junction / Exit","terms":""},"highway/motorway_link":{"name":"Motorway Link","terms":"ramp,on ramp,off ramp"},"highway/path":{"name":"Path","terms":"hike,hiking,trackway,trail,walk"},"highway/pedestrian":{"name":"Pedestrian Street","terms":""},"highway/primary":{"name":"Primary Road","terms":""},"highway/primary_link":{"name":"Primary Link","terms":"ramp,on ramp,off ramp"},"highway/raceway":{"name":"Motor Raceway","terms":"auto*,race*,nascar"},"highway/residential":{"name":"Residential Road","terms":""},"highway/rest_area":{"name":"Rest Area","terms":"rest stop"},"highway/road":{"name":"Unknown Road","terms":""},"highway/secondary":{"name":"Secondary Road","terms":""},"highway/secondary_link":{"name":"Secondary Link","terms":"ramp,on ramp,off ramp"},"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/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":{"name":"Tertiary Road","terms":""},"highway/tertiary_link":{"name":"Tertiary Link","terms":"ramp,on ramp,off ramp"},"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_signals":{"name":"Traffic Signals","terms":"light,stoplight,traffic light"},"highway/trunk":{"name":"Trunk Road","terms":""},"highway/trunk_link":{"name":"Trunk Link","terms":"ramp,on ramp,off ramp"},"highway/turning_circle":{"name":"Turning Circle","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/wayside_cross":{"name":"Wayside Cross","terms":""},"historic/wayside_shrine":{"name":"Wayside Shrine","terms":""},"junction":{"name":"Junction","terms":""},"landuse":{"name":"Land Use","terms":""},"landuse/allotments":{"name":"Community Garden","terms":"allotment,garden"},"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/farm":{"name":"Farmland","terms":""},"landuse/farmland":{"name":"Farmland","terms":""},"landuse/farmyard":{"name":"Farmyard","terms":""},"landuse/forest":{"name":"Forest","terms":"tree"},"landuse/garages":{"name":"Garages","terms":""},"landuse/grass":{"name":"Grass","terms":""},"landuse/industrial":{"name":"Industrial Area","terms":""},"landuse/landfill":{"name":"Landfill","terms":"dump"},"landuse/meadow":{"name":"Meadow","terms":""},"landuse/military":{"name":"Military Area","terms":""},"landuse/orchard":{"name":"Orchard","terms":""},"landuse/plant_nursery":{"name":"Plant Nursery","terms":"vivero"},"landuse/quarry":{"name":"Quarry","terms":""},"landuse/residential":{"name":"Residential Area","terms":""},"landuse/retail":{"name":"Retail Area","terms":""},"landuse/vineyard":{"name":"Vineyard","terms":""},"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/dog_park":{"name":"Dog Park","terms":""},"leisure/firepit":{"name":"Firepit","terms":"fireplace,campfire"},"leisure/garden":{"name":"Garden","terms":""},"leisure/golf_course":{"name":"Golf Course","terms":"links"},"leisure/ice_rink":{"name":"Ice Rink","terms":"hockey,skating,curling"},"leisure/marina":{"name":"Marina","terms":"boat"},"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/rugby_league":{"name":"Rugby League Field","terms":""},"leisure/pitch/rugby_union":{"name":"Rugby Union Field","terms":""},"leisure/pitch/skateboard":{"name":"Skate Park","terms":""},"leisure/pitch/soccer":{"name":"Soccer Field","terms":""},"leisure/pitch/tennis":{"name":"Tennis Court","terms":""},"leisure/pitch/volleyball":{"name":"Volleyball Court","terms":""},"leisure/playground":{"name":"Playground","terms":"jungle gym,play area"},"leisure/running_track":{"name":"Running Track","terms":""},"leisure/slipway":{"name":"Slipway","terms":"boat launch,boat ramp"},"leisure/sports_centre":{"name":"Sports Center / Gym","terms":"gym"},"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":""},"leisure/water_park":{"name":"Water Park","terms":"swim,pool,dive"},"line":{"name":"Line","terms":""},"man_made":{"name":"Man Made","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/embankment":{"name":"Embankment","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":"Radio Mast","terms":"broadcast tower,cell phone tower,cell tower,guyed tower,mobile phone tower,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/silo":{"name":"Silo","terms":"grain,corn,wheat"},"man_made/storage_tank":{"name":"Storage Tank","terms":"water,oil,gas,petrol"},"man_made/surveillance":{"name":"Surveillance","terms":""},"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":"Works","terms":"car assembly plant,aluminium processing plant,brewery,furniture manufacture factory,oil refinery,plastic recycling"},"military/airfield":{"name":"Airfield","terms":""},"military/barracks":{"name":"Barracks","terms":""},"military/bunker":{"name":"Bunker","terms":""},"military/checkpoint":{"name":"Checkpoint","terms":""},"military/danger_area":{"name":"Danger Area","terms":""},"military/naval_base":{"name":"Naval Base","terms":""},"military/obstacle_course":{"name":"Obstacle Course","terms":""},"military/range":{"name":"Military Range","terms":""},"military/training_area":{"name":"Training area","terms":""},"natural":{"name":"Natural","terms":""},"natural/bay":{"name":"Bay","terms":""},"natural/beach":{"name":"Beach","terms":""},"natural/cave_entrance":{"name":"Cave Entrance","terms":"cavern,hollow,grotto,shelter,cavity"},"natural/cliff":{"name":"Cliff","terms":""},"natural/coastline":{"name":"Coastline","terms":"shore"},"natural/fell":{"name":"Fell","terms":""},"natural/glacier":{"name":"Glacier","terms":""},"natural/grassland":{"name":"Grassland","terms":""},"natural/heath":{"name":"Heath","terms":""},"natural/peak":{"name":"Peak","terms":"acme,aiguille,alp,climax,crest,crown,hill,mount,mountain,pinnacle,summit,tip,top"},"natural/saddle":{"name":"Saddle","terms":"pass,mountain pass,top"},"natural/scree":{"name":"Scree","terms":"loose rocks"},"natural/scrub":{"name":"Scrub","terms":"bush,shrubs"},"natural/spring":{"name":"Spring","terms":""},"natural/tree":{"name":"Tree","terms":""},"natural/tree_row":{"name":"Tree row","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"},"office":{"name":"Office","terms":""},"office/accountant":{"name":"Accountant","terms":""},"office/administrative":{"name":"Administrative Office","terms":""},"office/architect":{"name":"Architect","terms":""},"office/company":{"name":"Company Office","terms":""},"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/insurance":{"name":"Insurance Office","terms":""},"office/it":{"name":"IT Office","terms":""},"office/lawyer":{"name":"Law Office","terms":""},"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":""},"office/travel_agent":{"name":"Travel Agency","terms":""},"piste":{"name":"Piste/Ski Trail","terms":"ski,sled,sleigh,snowboard,nordic,downhill,snowmobile"},"place":{"name":"Place","terms":""},"place/city":{"name":"City","terms":""},"place/farm":{"name":"Farm","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/suburb":{"name":"Borough","terms":"Boro,Quarter"},"place/town":{"name":"Town","terms":""},"place/village":{"name":"Village","terms":""},"point":{"name":"Point","terms":""},"power":{"name":"Power","terms":""},"power/generator":{"name":"Power Generator","terms":""},"power/line":{"name":"Power Line","terms":""},"power/minor_line":{"name":"Minor Power Line","terms":""},"power/pole":{"name":"Power Pole","terms":""},"power/sub_station":{"name":"Substation","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":{"name":"Railway","terms":""},"railway/abandoned":{"name":"Abandoned Railway","terms":""},"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","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":{"name":"Subway","terms":""},"railway/subway_entrance":{"name":"Subway Entrance","terms":""},"railway/tram":{"name":"Tram","terms":"streetcar"},"relation":{"name":"Relation","terms":""},"roundabout":{"name":"Roundabout","terms":""},"route/ferry":{"name":"Ferry Route","terms":""},"shop":{"name":"Shop","terms":""},"shop/alcohol":{"name":"Liquor Store","terms":"alcohol,beer,booze,wine"},"shop/anime":{"name":"Anime Shop","terms":""},"shop/antiques":{"name":"Antiques Shop","terms":""},"shop/art":{"name":"Art Store","terms":"art*,exhibit*,gallery"},"shop/baby_goods":{"name":"Baby Goods Store","terms":""},"shop/bag":{"name":"Bag/Luggage Store","terms":"handbag,purse"},"shop/bakery":{"name":"Bakery","terms":""},"shop/bathroom_furnishing":{"name":"Bathroom Furnishing Store","terms":""},"shop/beauty":{"name":"Beauty Shop","terms":"nail spa,spa,salon,tanning"},"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":""},"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":{"name":"Car Dealership","terms":"auto"},"shop/car_parts":{"name":"Car Parts Store","terms":"auto"},"shop/car_repair":{"name":"Car Repair Shop","terms":"auto"},"shop/carpet":{"name":"Carpet Store","terms":"rug"},"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/electronics":{"name":"Electronics Store","terms":"appliance,audio,computer,tv"},"shop/erotic":{"name":"Erotic Store","terms":"sex,porn"},"shop/fabric":{"name":"Fabric Store","terms":"sew"},"shop/farm":{"name":"Produce Stand","terms":"farm shop,farm stand"},"shop/fashion":{"name":"Fashion Store","terms":""},"shop/fishmonger":{"name":"Fishmonger","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/gift":{"name":"Gift Shop","terms":""},"shop/greengrocer":{"name":"Greengrocer","terms":"fruit,vegetable"},"shop/hairdresser":{"name":"Hairdresser","terms":""},"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":""},"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":""},"shop/music":{"name":"Music Store","terms":"CD,vinyl"},"shop/musical_instrument":{"name":"Musical Instrument Store","terms":""},"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/pawnbroker":{"name":"Pawn Shop","terms":""},"shop/pet":{"name":"Pet Store","terms":"cat,dog,fish"},"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/vacant":{"name":"Vacant Shop","terms":""},"shop/vacuum_cleaner":{"name":"Vacuum Cleaner Store","terms":""},"shop/variety_store":{"name":"Variety Store","terms":""},"shop/video":{"name":"Video Store","terms":"DVD"},"shop/video_games":{"name":"Video Game Store","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/artwork":{"name":"Artwork","terms":"mural,sculpture,statue"},"tourism/attraction":{"name":"Tourist Attraction","terms":""},"tourism/camp_site":{"name":"Camp Site","terms":"Tent"},"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/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":""},"traffic_calming/bump":{"name":"Speed Bump","terms":"speed hump"},"traffic_calming/hump":{"name":"Speed Hump","terms":"speed bump"},"traffic_calming/rumble_strip":{"name":"Rumble Strip","terms":"sleeper lines,audible lines,growlers"},"traffic_calming/table":{"name":"Raised Pedestrian Crossing","terms":"speed table,flat top hump"},"type/boundary":{"name":"Boundary","terms":""},"type/boundary/administrative":{"name":"Administrative Boundary","terms":""},"type/multipolygon":{"name":"Multipolygon","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":{"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/route_master":{"name":"Route Master","terms":""},"type/site":{"name":"Site","terms":""},"vertex":{"name":"Other","terms":""},"waterway":{"name":"Waterway","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/weir":{"name":"Weir","terms":""}}}},"suggestions":{"amenity":{"pub":{"The Green Man":{"count":54},"Kings Arms":{"count":77},"The White Horse":{"count":223},"The White Hart":{"count":238},"Royal Oak":{"count":175},"The Red Lion":{"count":253},"The Kings Arms":{"count":60},"The Star":{"count":74},"The Cross Keys":{"count":58},"The Wheatsheaf":{"count":121},"The Kings Head":{"count":63},"The Castle":{"count":63},"The Railway":{"count":105},"The Bell":{"count":129},"The Bull":{"count":75},"The Plough":{"count":187},"The George":{"count":115},"The Royal Oak":{"count":216},"The Fox":{"count":78},"Prince of Wales":{"count":86},"The Rising Sun":{"count":78},"The Chequers":{"count":72},"The Crown":{"count":253},"The Swan":{"count":149},"The Crown Inn":{"count":76},"The Ship":{"count":90},"The Victoria":{"count":69},"New Inn":{"count":104},"The Anchor":{"count":67},"Royal Hotel":{"count":62},"Red Lion":{"count":207},"Cross Keys":{"count":63},"The Bell Inn":{"count":57},"The White Lion":{"count":73},"The Black Horse":{"count":97},"Rose and Crown":{"count":85},"Commercial Hotel":{"count":54},"The White Swan":{"count":53},"The Greyhound":{"count":98},"The New Inn":{"count":119},"Kings Head":{"count":62},"The Angel":{"count":57},"The Queens Head":{"count":55},"Black Bull":{"count":54},"Black Horse":{"count":52},"The Swan Inn":{"count":54},"Rose & Crown":{"count":58},"The Albion":{"count":54},"The Cricketers":{"count":55},"The Ship Inn":{"count":94},"The Star Inn":{"count":51},"Queens Head":{"count":56},"Irish Pub":{"count":99},"魚民":{"count":84}},"fuel":{"76":{"count":498},"Neste":{"count":177},"Shell":{"count":10789},"Agip":{"count":2524},"Migrol":{"count":78},"Avia":{"count":1014},"Texaco":{"count":1057},"Total":{"count":3182},"Statoil":{"count":668},"BP":{"count":3517},"Topaz":{"count":98},"Esso":{"count":4179},"Jet":{"count":461},"OMV":{"count":929},"Aral":{"count":1383},"Tesco":{"count":214},"JET":{"count":212},"Morrisons":{"count":122},"United":{"count":155},"Sainsbury's":{"count":72},"Canadian Tire":{"count":90},"Mobil":{"count":1150},"Q8":{"count":1325},"Caltex":{"count":1304},"Petro-Canada":{"count":736},"ABC":{"count":84},"ARAL":{"count":385},"CEPSA":{"count":972},"BFT":{"count":102},"Petron":{"count":1283},"Intermarché":{"count":591},"Total Access":{"count":173},"Auchan":{"count":71},"Super U":{"count":147},"Carrefour":{"count":291},"Station Service E. Leclerc":{"count":516},"Elan":{"count":174},"Shell Express":{"count":171},"Hess":{"count":213},"F24":{"count":56},"Gulf":{"count":330},"PTT":{"count":241},"Teboil":{"count":111},"St1":{"count":126},"HEM":{"count":241},"GALP":{"count":762},"پمپ بنزین":{"count":266},"Avanti":{"count":110},"Cepsa":{"count":208},"OK":{"count":205},"Tinq":{"count":215},"Repsol":{"count":775},"Westfalen":{"count":94},"Esso Express":{"count":150},"Slovnaft":{"count":261},"Raiffeisenbank":{"count":129},"Tamoil":{"count":913},"bft":{"count":185},"Afriquia":{"count":117},"Engen":{"count":307},"Sasol":{"count":74},"Jetti":{"count":59},"LPG":{"count":309},"Coop":{"count":67},"Orlen":{"count":1074},"Kobil":{"count":81},"Oilibya":{"count":87},"Tango":{"count":143},"Star":{"count":352},"Петрол":{"count":111},"EKO":{"count":110},"Turmöl":{"count":74},"OIL!":{"count":111},"Flying V":{"count":146},"Ultramar":{"count":246},"CARREFOUR":{"count":73},"Eni":{"count":469},"Irving":{"count":149},"Lukoil":{"count":832},"Coles Express":{"count":262},"Pioneer":{"count":93},"Speedway":{"count":381},"Uno-X":{"count":57},"7-Eleven":{"count":892},"Agrola":{"count":90},"Husky":{"count":188},"Sunoco":{"count":684},"Sheetz":{"count":248},"Turkey Hill":{"count":56},"MOL":{"count":380},"OKQ8":{"count":209},"Petronas":{"count":254},"Mol":{"count":60},"Benzina":{"count":148},"Газпромнефть":{"count":1093},"Роснефть":{"count":805},"Opet":{"count":105},"Marathon":{"count":513},"Vito":{"count":63},"Valero":{"count":656},"Neste A24":{"count":56},"REPSOL":{"count":1502},"Lotos":{"count":260},"Api":{"count":253},"Chevron":{"count":1505},"ARCO":{"count":128},"Pemex":{"count":1340},"ТНК":{"count":594},"Petrol Ofisi":{"count":115},"eni":{"count":84},"Petrom":{"count":330},"PETRONOR":{"count":196},"Rompetrol":{"count":193},"Copec":{"count":541},"Petrobras":{"count":341},"АЗС":{"count":1060},"Pilot":{"count":57},"LUKOIL":{"count":64},"SB Tank":{"count":56},"Arco":{"count":391},"Лукойл":{"count":2285},"ОМВ":{"count":58},"Liberty":{"count":79},"Bliska":{"count":162},"Moya":{"count":52},"Erg":{"count":510},"Eneos":{"count":121},"P T T":{"count":55},"Citgo":{"count":547},"IP":{"count":967},"Metano":{"count":248},"Сургутнефтегаз":{"count":75},"ENI":{"count":79},"Eko":{"count":75},"Indipend.":{"count":144},"TotalErg":{"count":188},"IES":{"count":63},"Star Oil":{"count":77},"ERG":{"count":78},"Cenex":{"count":194},"ПТК":{"count":97},"Белоруснефть":{"count":64},"HP":{"count":127},"Phillips 66":{"count":332},"Q1":{"count":53},"ป.ต.ท.":{"count":449},"Circle K":{"count":313},"Woolworths Petrol":{"count":151},"PSO":{"count":80},"Татнефть":{"count":311},"Ceypetco":{"count":63},"Seaoil":{"count":55},"Sea Oil":{"count":65},"Phoenix":{"count":182},"Cosmo":{"count":61},"Gazprom":{"count":69},"Kwik Trip":{"count":169},"КазМунайГаз":{"count":163},"Wawa":{"count":143},"Pertamina":{"count":274},"เอสโซ่":{"count":85},"Terpel":{"count":337},"Z":{"count":93},"Socar":{"count":71},"Bharat Petroleum":{"count":166},"Indian Oil":{"count":327},"АГЗС":{"count":897},"JOMO":{"count":56},"Holiday":{"count":140},"ОККО":{"count":294},"Exxon":{"count":883},"コスモ石油":{"count":325},"出光":{"count":478,"tags":{"name:en":"IDEMITSU"}},"ENEOS":{"count":1292},"WOG":{"count":323},"CAMPSA":{"count":507},"Casey's General Store":{"count":307},"Башнефть":{"count":137},"Kangaroo":{"count":113},"Puma":{"count":315},"Hindustan Petroleum":{"count":58},"Lotos Optima":{"count":64},"MEROIL":{"count":74},"TEXACO":{"count":54},"ゼネラル":{"count":58},"Helios":{"count":61},"Татнефтепродукт":{"count":69},"昭和シェル":{"count":215},"BEBECO":{"count":77},"НК Альянс":{"count":97},"คาลเท็กซ์":{"count":72},"JA-SS":{"count":52},"Sinclair":{"count":163},"Costco":{"count":73},"Conoco":{"count":327},"SPBU":{"count":205},"Макпетрол":{"count":109},"Sam's Club":{"count":51},"Ipiranga":{"count":159},"1-2-3":{"count":68},"Posto Ipiranga":{"count":168},"Drummed Fuel":{"count":156},"Rubis":{"count":107},"БРСМ-Нафта":{"count":58},"АГНКС":{"count":54},"QuikTrip":{"count":209},"เชลล์":{"count":94},"Stewart's":{"count":66},"Cumberland Farms":{"count":80},"Posto BR":{"count":191},"台灣中油":{"count":147},"บางจาก":{"count":195},"محطه وقود":{"count":59},"ANP":{"count":163},"Kum & Go":{"count":113},"Primax":{"count":147},"Mobile":{"count":56},"Укрнафта":{"count":201},"Пропан":{"count":57},"Petrolimex":{"count":143},"Tela":{"count":171},"Авіас":{"count":97},"Sokimex":{"count":82},"Safeway":{"count":53},"Delta":{"count":144},"H-E-B Gas":{"count":161},"Kroger Fuel":{"count":53},"Sinopec Fuel":{"count":112},"Posto Shell":{"count":94},"RaceTrac":{"count":71},"BR":{"count":149},"Costco Gas":{"count":58},"Murphy USA":{"count":135},"پمپ گاز":{"count":62},"Royal Farms":{"count":64},"Нефтьмагистраль":{"count":64},"PT":{"count":138},"Uno":{"count":134},"Independent Fuel Station":{"count":56},"エネオス":{"count":68},"P T":{"count":62},"Pecsa":{"count":54},"Bangchak":{"count":68},"CNG":{"count":315},"Posto":{"count":64},"NP":{"count":67},"Posto Atem":{"count":58},"GNV":{"count":79},"Minipump":{"count":116},"Petroperu":{"count":84},"Petrochina":{"count":103}},"place_of_worship":{"Saint Mary":{"count":99},"All Saints":{"count":410},"St Andrew's":{"count":60},"Catholic Church":{"count":173},"Christ Church":{"count":366},"Saint Mary's":{"count":101},"Holy Trinity":{"count":221},"St Mary's Church":{"count":183},"Saint Marks Church":{"count":196},"St Mary":{"count":138},"Trinity Baptist Church":{"count":202},"Sacred Heart Church":{"count":213},"St Peter":{"count":93},"All Saints Church":{"count":217},"Northside Baptist Church":{"count":69},"Saint John the Baptist":{"count":58},"Zion Baptist Church":{"count":71},"Trinity Methodist Church":{"count":93},"Central Baptist Church":{"count":206},"Sacred Heart Catholic Church":{"count":232},"Kingdom Hall":{"count":340},"The Church of Jesus Christ of Latter-day Saints":{"count":3095},"Salvation Army":{"count":150},"Baptist Church":{"count":166},"St John the Baptist":{"count":138},"Saint Mary the Virgin":{"count":70},"Marienkapelle":{"count":338},"Neuapostolische Kirche":{"count":771},"St Mary the Virgin":{"count":164},"Seventh Day Adventist":{"count":65},"St. Mary's Church":{"count":105},"Friedhofskapelle":{"count":810},"Faith Baptist Church":{"count":241},"Grace Lutheran Church":{"count":253},"Church of God":{"count":786},"Kingdom Hall of Jehovah's Witnesses":{"count":1029},"United Reformed Church":{"count":73},"St. Mary's":{"count":72},"St Peter's":{"count":103},"St Andrew's Church":{"count":70},"Kapelle":{"count":1666},"St. Josef":{"count":224},"St. Laurentius":{"count":259},"Church of the Good Shepherd":{"count":99},"Friedenskirche":{"count":264},"Hubertuskapelle":{"count":157},"St Mary's":{"count":218},"Kingdom Hall of Jehovahs Witnesses":{"count":601},"Saint Mary's Church":{"count":111},"Pauluskirche":{"count":110},"Martinskirche":{"count":139},"St Nicholas":{"count":107},"Erlöserkirche":{"count":137},"Saint Pauls Church":{"count":517},"Saint Josephs Church":{"count":131},"Mariä Himmelfahrt":{"count":225},"Heilig-Geist-Kirche":{"count":90},"St. Peter und Paul":{"count":314},"Königreichssaal":{"count":88},"Auferstehungskirche":{"count":159},"St. Johannes Baptist":{"count":68},"Herz Jesu":{"count":95},"Kirche":{"count":302},"Grace Chapel":{"count":54},"Katholische Kirche":{"count":172},"Sankt Michael":{"count":123},"Christuskirche":{"count":423},"St. Michael":{"count":430},"Lutherkirche":{"count":118},"Church":{"count":406},"Evangelische Kirche":{"count":671},"Johanniskirche":{"count":54},"St. Georg":{"count":319},"Sankt Laurentius":{"count":65},"St. Stephanus":{"count":98},"Chiesa di Sant'Antonio":{"count":86},"Église":{"count":1017},"Saint Joseph Church":{"count":136},"Bible Baptist Church":{"count":166},"Church of Christ":{"count":1545},"Saint Peter":{"count":63},"Kreuzkirche":{"count":172},"Seventh Day Adventist Church":{"count":560},"St. Sebastian":{"count":107},"Saint Peters Church":{"count":231},"Methodist Church":{"count":236},"Heilig-Kreuz-Kirche":{"count":66},"Herz-Jesu-Kirche":{"count":111},"Maria Hilf":{"count":55},"Shady Grove Church":{"count":323},"St. Johannes der Täufer":{"count":129},"Thomaskirche":{"count":57},"Stadtkirche":{"count":108},"Heilige Familie":{"count":56},"Jehovas Zeugen":{"count":72},"Versöhnungskirche":{"count":83},"St Mary Magdalene":{"count":57},"Sankt Marien":{"count":87},"Sankt Martin":{"count":145},"St James":{"count":102},"St Michael and All Angels":{"count":59},"Waldkapelle":{"count":72},"Sankt Nikolaus":{"count":102},"St. Joseph":{"count":111},"Friends Meeting House":{"count":60},"St. Katharina":{"count":76},"Stupa":{"count":85},"Jézus Szíve-templom":{"count":80},"Concord Church":{"count":185},"Congregational Church":{"count":58},"Chapelle":{"count":480},"Церковь":{"count":265},"Kreuzkapelle":{"count":69},"Heilig Kreuz":{"count":117},"St. Jakob":{"count":56},"St. Leonhard":{"count":108},"St John the Evangelist":{"count":82},"Anglican Church":{"count":92},"Heilig Geist":{"count":54},"St Peter's Church":{"count":95},"St. Ulrich":{"count":95},"Emmanuel Church":{"count":183},"Johanneskirche":{"count":191},"Martin-Luther-Kirche":{"count":128},"Foursquare Gospel Church":{"count":57},"St. Marien":{"count":216},"Liebfrauenkirche":{"count":73},"Seventh-Day Adventist Church":{"count":52},"Biserica":{"count":2164},"Evangelisch-Freikirchliche Gemeinde":{"count":99},"Marienkirche":{"count":192},"Iglesia de San Juan":{"count":56},"St. Antonius":{"count":121},"St Paul's":{"count":53},"St John's Church":{"count":55},"St. Jakobus":{"count":106},"St Peters":{"count":54},"Masjid":{"count":1950},"Holy Trinity Church":{"count":202},"Redeemer Lutheran Church":{"count":112},"St Andrew":{"count":68},"Sankt Georg":{"count":97},"St. Andreas":{"count":139},"St Andrews":{"count":54},"Αγία Παρασκευή":{"count":73},"San Francesco":{"count":92},"St. Martin":{"count":411},"St. Nikolaus":{"count":340},"Maria Himmelfahrt":{"count":115},"Synagogue":{"count":83},"St. Johann Baptist":{"count":58},"The Salvation Army":{"count":86},"Iglesia de San Andrés":{"count":58},"Surau":{"count":159},"Trinity Church":{"count":456},"Mariengrotte":{"count":90},"Saint Andrews Church":{"count":121},"熊野神社":{"count":99},"Chiesa di San Martino":{"count":133},"Iglesia":{"count":962},"Mosque":{"count":590},"Προφήτης Ηλίας":{"count":90},"Calvary Church":{"count":447},"St. Peter":{"count":161},"St. Bartholomäus":{"count":139},"Sankt Andreas":{"count":55},"Церковь Преображения Господня":{"count":100},"Saint Peter's Church":{"count":53},"Chapelle Sainte-Anne":{"count":92},"First Baptist Church":{"count":2346},"Igreja Matriz":{"count":213},"Saint Josephs Catholic Church":{"count":124},"Église Saint-Michel":{"count":229},"St. Johannes":{"count":160},"Sankt Josef":{"count":74},"Chiesa di San Giuseppe":{"count":137},"St. Bonifatius":{"count":108},"Chiesa di San Giorgio":{"count":134},"Chiesa di San Giovanni Battista":{"count":180},"St. Barbara":{"count":85},"New Life Church":{"count":84},"Iglesia ni Cristo":{"count":237},"Iglesia Ni Cristo":{"count":299},"Calvary Baptist Church":{"count":547},"United Methodist Church":{"count":638},"Bethany Baptist Church":{"count":105},"Saint Francis Church":{"count":54},"Holy Family Church":{"count":74},"Wesleyan Church":{"count":101},"United Pentecostal Church":{"count":158},"Trinity Lutheran Church":{"count":458},"Antoniuskapelle":{"count":94},"Emmanuel Baptist Church":{"count":149},"Chapel":{"count":230},"San Pietro":{"count":85},"St. Ägidius":{"count":57},"Iglesia de San Martín":{"count":66},"Ermita de San Roque":{"count":125},"Igreja Batista":{"count":59},"St. Elisabeth":{"count":102},"St. Anna":{"count":124},"Dorfkirche":{"count":226},"Assembleia de Deus":{"count":64},"St. Martinus":{"count":65},"Hope Church":{"count":65},"Biserică":{"count":709},"St. Pankratius":{"count":79},"Temple":{"count":504},"Biserica Ortodoxă":{"count":62},"Holy Family Catholic Church":{"count":94},"諏訪神社":{"count":86},"Chiesa di San Rocco":{"count":265},"Chiesa":{"count":203},"八坂神社":{"count":66},"Klosterkirche":{"count":76},"Église Saint-Pierre":{"count":997},"Sankt Peter und Paul":{"count":67},"St. Maria":{"count":82},"New Jerusalem Church":{"count":51},"San Martino":{"count":79},"Église Saint-Antoine":{"count":80},"St Michael's":{"count":61},"St. Vitus":{"count":106},"Santo Stefano":{"count":52},"San Giovanni Battista":{"count":78},"Markuskirche":{"count":65},"Calvary Chapel":{"count":57},"Dreifaltigkeitskirche":{"count":93},"Kapel":{"count":97},"Église Saint-Martin":{"count":1353},"Ermita de San Miguel":{"count":65},"Церковь Троицы Живоначальной":{"count":227},"Bethlehem Lutheran Church":{"count":88},"St. Johannis":{"count":60},"Maria Königin":{"count":56},"Chiesa di Sant'Andrea":{"count":57},"Mariä Heimsuchung":{"count":65},"Zion Lutheran Church":{"count":226},"Pfarrkirche":{"count":106},"Église Saint-Hilaire":{"count":109},"Holy Cross Church":{"count":86},"St. Margaretha":{"count":52},"Chiesa di Santa Lucia":{"count":70},"Ermita":{"count":109},"Saint Mary's Catholic Church":{"count":65},"Église Saint-Christophe":{"count":84},"Königreichssaal Jehovas Zeugen":{"count":59},"Trauerhalle":{"count":123},"Iglesia Parroquial":{"count":62},"Church of God of Prophecy":{"count":232},"Mount Olive Baptist Church":{"count":159},"Chiesa di San Giovanni":{"count":53},"Michaelskirche":{"count":59},"Άγιος Γεώργιος":{"count":97},"Reformierte Kirche":{"count":97},"Aussegnungshalle":{"count":106},"Wesley Church":{"count":72},"First United Methodist Church":{"count":880},"稲荷神社":{"count":85},"San Michele Arcangelo":{"count":57},"St. Mauritius":{"count":55},"svatý Václav":{"count":68},"San Lorenzo":{"count":79},"Iglesia de San Juan Bautista":{"count":90},"Evangelical Free Church":{"count":81},"Providence Church":{"count":252},"Église Saint-Vincent":{"count":105},"Chapelle Saint-Roch":{"count":106},"San Giuseppe":{"count":80},"First Presbyterian Church":{"count":1196},"Église Saint-Denis":{"count":138},"church":{"count":64},"Pentecostal Church":{"count":78},"Fellowship Baptist Church":{"count":105},"First Church of the Nazarene":{"count":306},"Iglesia Evangelica":{"count":74},"Iglesia de Nuestra Señora de la Asunción":{"count":66},"Mariä Geburt":{"count":52},"Grace Baptist Church":{"count":272},"Hope Lutheran Church":{"count":88},"San Giorgio":{"count":57},"St. Stephan":{"count":89},"Église Saint-Éloi":{"count":52},"Église Notre-Dame":{"count":548},"Chapelle Saint-Jean":{"count":53},"Église Sainte-Anne":{"count":71},"Chiesa di San Lorenzo":{"count":132},"Église Saint-Aubin":{"count":75},"Chapelle Saint-Pierre":{"count":51},"Saint Michaels Church":{"count":71},"Messiah Lutheran Church":{"count":75},"Madonna della Neve":{"count":58},"Saint Pauls Lutheran Church":{"count":141},"Church of God in Christ":{"count":141},"Immaculate Conception Catholic Church":{"count":86},"First Church of Christ Scientist":{"count":450},"Chiesa di Santa Maria Assunta":{"count":138},"New Apostolic Church":{"count":92},"Free Methodist Church":{"count":143},"Iglesia de Dios":{"count":66},"Apostolic Church":{"count":75},"Chiesa di San Francesco":{"count":108},"Ermita de San Antonio":{"count":53},"Église Saint-Joseph":{"count":114},"Church of the Nazarene":{"count":509},"Community of Christ":{"count":180},"Parroquia":{"count":92},"Santa Maria":{"count":202},"Мечеть":{"count":313},"Königreichsaal":{"count":54},"Ev. Kirche":{"count":122},"Iglesia de San Miguel":{"count":105},"Saint Paul Church":{"count":250},"Antioch Church":{"count":545},"Assembly of God Church":{"count":273},"Bethany Church":{"count":329},"Bethel Church":{"count":1055},"Bethel Lutheran Church":{"count":53},"Bethesda Church":{"count":94},"Bethlehem Church":{"count":499},"Beulah Church":{"count":179},"Christian Church":{"count":83},"Church of the Brethren":{"count":51},"Church of Jesus Christ":{"count":53},"Community Church":{"count":171},"County Line Church":{"count":91},"Ebenezer Church":{"count":349},"Evergreen Church":{"count":88},"Faith Lutheran Church":{"count":190},"Faith Church":{"count":203},"Fairview Church":{"count":388},"Fellowship Church":{"count":127},"Grace Church":{"count":312},"First Congregational Church":{"count":391},"Friendship Church":{"count":484},"Full Gospel Church":{"count":81},"Friends Church":{"count":51},"Harmony Church":{"count":162},"Immanuel Church":{"count":141},"Maple Grove Church":{"count":73},"Liberty Church":{"count":322},"Little Zion Church":{"count":71},"Midway Church":{"count":196},"Mount Bethel Church":{"count":57},"Mount Hope Church":{"count":98},"Mount Zion Church":{"count":1084},"Mount Pleasant Church":{"count":508},"Mount Olive Church":{"count":594},"Nazarene Church":{"count":60},"New Hope Church":{"count":701},"Oak Grove Church":{"count":592},"Pleasant Hill Church":{"count":482},"Pilgrim Church":{"count":73},"Pine Grove Church":{"count":292},"Pleasant View Church":{"count":137},"Pleasant Valley Church":{"count":203},"Pleasant Ridge Church":{"count":127},"Riverside Church":{"count":84},"Saint John Church":{"count":148},"Saint James Church":{"count":318},"Saint Lukes Church":{"count":193},"Saint Johns Church":{"count":664},"Saint Luke Church":{"count":87},"Saint Mark Church":{"count":51},"Saint Marys Church":{"count":311},"Saint Mary Church":{"count":64},"Tabernacle Church":{"count":97},"Saint Thomas Church":{"count":76},"Saint Stephens Church":{"count":74},"Salem Church":{"count":475},"Smith Chapel":{"count":80},"Springfield Church":{"count":74},"Union Church":{"count":519},"Union Chapel":{"count":182},"United Church":{"count":90},"Victory Church":{"count":90},"Zion Church":{"count":493},"Macedonia Church":{"count":423},"Saint Joseph Catholic Church":{"count":116},"Saint Pauls Episcopal Church":{"count":140},"Unity Church":{"count":86},"Central Church":{"count":111},"Shiloh Church":{"count":420},"All Saints Episcopal Church":{"count":98},"Saint Johns Catholic Church":{"count":71},"Locust Grove Church":{"count":67},"Greenwood Church":{"count":51},"Jehovah's Witnesses":{"count":69},"Bethel Baptist Church":{"count":255},"Calvary Lutheran Church":{"count":64},"Grace United Methodist Church":{"count":165},"Wesley United Methodist Church":{"count":111},"First Assembly of God Church":{"count":389},"Saint John's Episcopal Church":{"count":61},"Bethany Lutheran Church":{"count":86},"Saint Paul's Lutheran Church":{"count":62},"First Lutheran Church":{"count":195},"Saint John's Lutheran Church":{"count":69},"Bethel African Methodist Episcopal Church":{"count":122},"Church of the Living God":{"count":96},"Chapel Hill Church":{"count":77},"Mount Calvary Church":{"count":158},"First Church of God":{"count":235},"Saint Paul Lutheran Church":{"count":151},"Holy Trinity Lutheran Church":{"count":70},"Immaculate Conception Church":{"count":120},"Immanuel Baptist Church":{"count":127},"Prince of Peace Lutheran Church":{"count":70},"Shiloh Baptist Church":{"count":170},"Christ United Methodist Church":{"count":86},"Community Bible Church":{"count":58},"Trinity United Methodist Church":{"count":230},"Holy Trinity Episcopal Church":{"count":51},"Grace Bible Church":{"count":65},"Grace Episcopal Church":{"count":128},"Good Shepherd Lutheran Church":{"count":131},"First Church of Christ":{"count":81},"Presbyterian Church":{"count":160},"Saint James Episcopal Church":{"count":115},"Community Baptist Church":{"count":110},"Central United Methodist Church":{"count":56},"Trinity Episcopal Church":{"count":221},"First Missionary Baptist Church":{"count":59},"First Reformed Church":{"count":63},"Holy Cross Lutheran Church":{"count":63},"Peace Lutheran Church":{"count":108},"Saint John Lutheran Church":{"count":79},"First Free Will Baptist Church":{"count":51},"Immanuel Lutheran Church":{"count":190},"Faith United Methodist Church":{"count":70},"Berean Baptist Church":{"count":51},"First Methodist Church":{"count":191},"Bethlehem Baptist Church":{"count":97},"Second Baptist Church":{"count":211},"First Christian Church":{"count":663},"Saint Johns Lutheran Church":{"count":150},"Friendship Baptist Church":{"count":176},"Our Savior Lutheran Church":{"count":74},"Saint Marks Episcopal Church":{"count":76},"First United Presbyterian Church":{"count":84},"Christ Episcopal Church":{"count":160},"Saint Johns Episcopal Church":{"count":151},"Grace Community Church":{"count":64},"Liberty Baptist Church":{"count":124},"Pentecostal Church of God":{"count":98},"Saint Matthews Church":{"count":139},"Christ Lutheran Church":{"count":155},"Saint Paul United Methodist Church":{"count":70},"Victory Baptist Church":{"count":97},"Saint James Catholic Church":{"count":54},"Christ Community Church":{"count":56},"Saint Andrews Episcopal Church":{"count":91},"New Hope Baptist Church":{"count":230},"Westminster Presbyterian Church":{"count":150},"Trinity Evangelical Lutheran Church":{"count":57},"New Bethel Baptist Church":{"count":52},"Hopewell Baptist Church":{"count":60},"Pleasant Grove Church":{"count":487},"Mount Zion Baptist Church":{"count":221},"Mount Calvary Baptist Church":{"count":91},"Saint Paul Baptist Church":{"count":77},"Cornerstone Baptist Church":{"count":51},"First Pentecostal Church":{"count":76},"Cornerstone Church":{"count":53},"United Church of Christ":{"count":95},"Crossroads Church":{"count":110},"Covenant Presbyterian Church":{"count":63},"Asbury Church":{"count":64},"Asbury United Methodist Church":{"count":80},"Beech Grove Church":{"count":76},"Berea Church":{"count":59},"Cedar Grove Church":{"count":213},"Center Church":{"count":79},"Corinth Church":{"count":176},"Galilee Church":{"count":91},"Hebron Church":{"count":114},"Hickory Grove Church":{"count":115},"Hopewell Church":{"count":288},"Jerusalem Church":{"count":139},"Lebanon Church":{"count":111},"Macedonia Baptist Church":{"count":138},"New Bethel Church":{"count":216},"New Liberty Church":{"count":57},"New Prospect Church":{"count":88},"New Home Church":{"count":96},"New Salem Church":{"count":132},"New Zion Church":{"count":164},"Mount Zion United Methodist Church":{"count":51},"Mount Gilead Church":{"count":81},"Mount Hebron Church":{"count":56},"Mount Pisgah Church":{"count":139},"Mount Moriah Church":{"count":196},"Mount Nebo Church":{"count":108},"Oak Grove Baptist Church":{"count":90},"Oak Hill Church":{"count":95},"Oakland Church":{"count":60},"Mount Carmel Church":{"count":284},"Mount Olivet Church":{"count":101},"Mount Vernon Church":{"count":152},"Mount Tabor Church":{"count":106},"Rose Hill Church":{"count":75},"Palestine Church":{"count":63},"Rock Springs Church":{"count":51},"Pisgah Church":{"count":72},"Sharon Church":{"count":90},"Union Grove Church":{"count":173},"Saint Patricks Church":{"count":91},"Walnut Grove Church":{"count":102},"Wesley Chapel":{"count":174},"White Oak Church":{"count":82},"Memorial Baptist Church":{"count":57},"Bethel United Methodist Church":{"count":78},"Central Christian Church":{"count":84},"Saint Thomas Episcopal Church":{"count":54},"Saint Marys Catholic Church":{"count":180},"Zion Hill Church":{"count":146},"Saint Patricks Catholic Church":{"count":79},"Mount Pleasant Baptist Church":{"count":76},"Philadelphia Church":{"count":82},"Good Hope Church":{"count":125},"Mount Carmel Baptist Church":{"count":72},"Central Church of Christ":{"count":68},"First Southern Baptist Church":{"count":95},"Union Baptist Church":{"count":131},"Holy Cross Catholic Church":{"count":54},"Central Presbyterian Church":{"count":51},"Trinity Presbyterian Church":{"count":70},"Saint Marys Roman Catholic Church":{"count":54},"Temple Baptist Church":{"count":119},"Saint Peters Episcopal Church":{"count":54},"Antioch Baptist Church":{"count":173},"Sacred Heart Roman Catholic Church":{"count":59},"First United Pentecostal Church":{"count":85},"Holy Trinity Catholic Church":{"count":54},"Calvary United Methodist Church":{"count":65},"Providence Baptist Church":{"count":77},"Mount Sinai Church":{"count":107},"Morning Star Church":{"count":126},"Saint James Baptist Church":{"count":59},"Pleasant Grove Baptist Church":{"count":89},"Pleasant Hill Baptist Church":{"count":68},"Tabernacle Baptist Church":{"count":108},"Morning Star Baptist Church":{"count":72},"Saint Paul African Methodist Episcopal Church":{"count":58},"Saint Peter Church":{"count":62},"Salem Baptist Church":{"count":79},"Highland Church":{"count":61},"Smyrna Church":{"count":69},"Saint Pauls United Methodist Church":{"count":52},"Saint Mary's Roman Catholic Church":{"count":55},"Fairview Baptist Church":{"count":54},"Saint Lukes Episcopal Church":{"count":69},"Église Saint-Jean-Baptiste":{"count":435},"Церковь Рождества Христова":{"count":117},"Pilgrim Rest Church":{"count":80},"Chestnut Grove Church":{"count":64},"Ebenezer Baptist Church":{"count":100},"Enon Church":{"count":68},"Faith Tabernacle":{"count":55},"Holiness Church":{"count":94},"Mill Creek Church":{"count":61},"Mountain View Church":{"count":106},"Oak Ridge Church":{"count":65},"Sardis Church":{"count":86},"Sweet Home Church":{"count":59},"Union Hill Church":{"count":119},"Mount Zion Church (historical)":{"count":68},"Pentecostal Holiness Church":{"count":69},"Liberty Hill Church":{"count":77},"New Hope Church (historical)":{"count":55},"Bethel Church (historical)":{"count":84},"Saint John Baptist Church":{"count":56},"Saint Marys Episcopal Church":{"count":51},"Southside Baptist Church":{"count":94},"Holly Grove Church":{"count":57},"Jones Chapel":{"count":73},"Mount Pilgrim Church":{"count":52},"Pilgrims Rest Church":{"count":68},"Pine Hill Church":{"count":57},"Piney Grove Church":{"count":170},"Poplar Springs Church":{"count":57},"Prospect Church":{"count":98},"Red Hill Church":{"count":72},"Rock Hill Church":{"count":74},"Spring Hill Church":{"count":178},"Beulah Baptist Church":{"count":51},"Magnolia Church":{"count":57},"Westside Baptist Church":{"count":55},"First Assembly of God":{"count":61},"First Church of Christ, Scientist":{"count":64},"Église Saint-André":{"count":176},"Kaplica":{"count":269},"Ganesh Temple":{"count":56},"Ganesha Temple":{"count":53},"Iglesia de San Francisco":{"count":55},"Igreja Universal do Reino de Deus":{"count":114},"Calvaire":{"count":53},"Kaplička":{"count":56},"Santa Lucia":{"count":69},"temple":{"count":68},"Hanuman Temple":{"count":172},"Église Saint-Étienne":{"count":281},"Часовня":{"count":319},"Szent Mihály-templom":{"count":60},"Chiesa di Sant'Anna":{"count":81},"Chiesa di San Sebastiano":{"count":69},"八幡神社":{"count":139},"Église Saint-Léger":{"count":155},"Chiesa di Santa Maria":{"count":65},"Церковь Михаила Архангела":{"count":142},"Церковь Покрова Пресвятой Богородицы":{"count":288},"San Michele":{"count":83},"Église Saint-Didier":{"count":51},"biserica":{"count":192},"San Rocco":{"count":157},"Jakobuskirche":{"count":53},"Церковь Рождества Пресвятой Богородицы":{"count":173},"مسجد":{"count":485},"Capilla":{"count":173},"Église Sainte-Marie-Madeleine":{"count":72},"Άγιος Νικόλαος":{"count":99},"Église Saint-Nicolas":{"count":283},"Assembléia de Deus":{"count":177},"Salão do Reino das Testemunhas de Jeová":{"count":64},"Chiesa di San Michele":{"count":85},"Salón del Reino de los Testigos de Jehová":{"count":90},"Église Saint-Julien":{"count":104},"Chiesa di San Pietro":{"count":114},"Церковь Николая Чудотворца":{"count":366},"Református templom":{"count":357},"Saint-Pierre":{"count":55},"Церковь Петра и Павла":{"count":71},"San Bartolomeo":{"count":57},"Chapelle Notre-Dame":{"count":62},"Hanuman Mandir":{"count":54},"Mosquée":{"count":587},"Церковь Иконы Божией Матери Казанская":{"count":88},"Iglesia de Santa María":{"count":106},"Saint-Martin":{"count":70},"Nanebevzetí Panny Marie":{"count":128},"Église Saint-Sébastien":{"count":67},"Церковь Вознесения Господня":{"count":95},"Shiva Temple":{"count":76},"Wat":{"count":124},"Chapelle Saint-Joseph":{"count":54},"Sant'Anna":{"count":56},"Церковь Успения Пресвятой Богородицы":{"count":176},"Chiesa di San Bartolomeo":{"count":99},"Iglesia de San Pedro":{"count":114},"Kaplica cmentarna":{"count":558},"kaplica cmentarna":{"count":95},"mosque":{"count":63},"The Church of Jesus Christ of Latter Day Saints":{"count":64},"Chiesa della Santissima Trinità":{"count":59},"masjid":{"count":224},"神明社":{"count":67},"Igreja Católica":{"count":87},"Церковь Богоявления Господня":{"count":72},"Chiesa di San Giacomo":{"count":61},"Église Saint-Jacques":{"count":115},"Evangélikus templom":{"count":113},"Église Saint-Maurice":{"count":197},"Église Saint-Georges":{"count":171},"Église Saint-Barthélémy":{"count":54},"mosquée":{"count":67},"Chiesa del Carmine":{"count":52},"Chiesa dei Santi Pietro e Paolo":{"count":73},"Ermita de San Pedro":{"count":54},"Igreja":{"count":89},"Masjid Al Ikhlas":{"count":54},"Masjid Nurul Iman":{"count":80},"Masjid Nurul Huda":{"count":79},"Kościół pw. Najświętszego Serca Pana Jezusa":{"count":98},"Gereja":{"count":100},"Chiesa di Sant'Antonio Abate":{"count":71},"Sant'Antonio":{"count":81},"Santa Maria Assunta":{"count":109},"Église Saint-Vaast":{"count":83},"Camii":{"count":95},"Église Saint-Jean":{"count":79},"Sala Królestwa Świadków Jehowy":{"count":82},"Église Saint-Laurent":{"count":236},"Iglesia Catolica":{"count":80},"土地公廟":{"count":56},"Церква":{"count":63},"Capela":{"count":81},"Церковь Георгия Победоносца":{"count":83},"Церковь Воскресения Христова":{"count":78},"Eglise":{"count":79},"Kościół pw. Wniebowzięcia Najświętszej Maryi Panny":{"count":68},"Церковь Илии Пророка":{"count":59},"مسجد جامع":{"count":65},"Церковь Спаса Преображения":{"count":51},"Iglesia de Jesucristo de los Santos de los Últimos Días":{"count":60},"წმინდა გიორგი (St. Giorgi)":{"count":62},"Iglesia Cristiana Evangélica":{"count":53},"Église de l'Assomption":{"count":114},"Église Notre-Dame de l'Assomption":{"count":114},"Église Saint-Louis":{"count":64},"Église Saint-Sauveur":{"count":55},"Chiesa di San Michele Arcangelo":{"count":90},"Mesjid":{"count":330},"Mushalla":{"count":215},"Iglesia Católica":{"count":56},"Igreja Assembléia de Deus":{"count":57},"Άγιος Δημήτριος":{"count":57},"Iglesia de San Esteban":{"count":56},"Narození Panny Marie":{"count":54},"Église Saint-Sulpice":{"count":89},"La Iglesia de Jesucristo de los Santos de los Últimos Días":{"count":53},"Chiesa di San Biagio":{"count":56},"Église Saint-Saturnin":{"count":56},"monastery":{"count":254},"Церковь Казанской иконы Божией Матери":{"count":83},"pilone votivo":{"count":64},"mesjid":{"count":173},"Église Sainte-Madeleine":{"count":91},"Église Saint-Pierre et Saint-Paul":{"count":120},"Chiesa di Santo Stefano":{"count":80},"Sant Miquel":{"count":71},"福德祠":{"count":62},"Musholla":{"count":164},"Église Notre-Dame-de-l'Assomption":{"count":187},"Църква":{"count":52},"福德宮":{"count":63},"Chiesa di San Domenico":{"count":54},"Magyarok Nagyasszonya-templom":{"count":64},"Mushola":{"count":172},"Nagyboldogasszony-templom":{"count":98},"Église Saint-Germain":{"count":138},"Église Saint-Roch":{"count":53},"Nejsvětější Trojice":{"count":85},"MASJID":{"count":66},"Église Saint-Médard":{"count":114},"Mushollah":{"count":51},"Sant Pere":{"count":54},"pagoda":{"count":306},"Église Saint-Symphorien":{"count":64},"Kościół pw. Miłosierdzia Bożego":{"count":56},"Unknown Mosque":{"count":55},"Église Saint-Pierre-ès-Liens":{"count":65},"Kovil":{"count":161},"Église Saint-Blaise":{"count":71},"Église Saint-Barthélemy":{"count":77},"Kościół pw. Podwyższenia Krzyża Świętego":{"count":63},"Szent István király templom":{"count":66},"Ref. templom":{"count":191},"Église Saint-Rémy":{"count":77},"IGLESIA CATOLICA":{"count":56},"Szent István király-templom":{"count":111},"Église Saint-Paul":{"count":92},"Église Saint-Rémi":{"count":67},"Kisboldogasszony-templom":{"count":70},"Szent Anna-templom":{"count":64},"Église Saint-Quentin":{"count":66},"svätého Michala":{"count":68},"Église du Sacré-Cœur":{"count":55},"Szentháromság-templom":{"count":104},"Nagyboldogasszony templom":{"count":52},"Szent Kereszt felmagasztalása-templom":{"count":61}},"fast_food":{"Quick":{"count":489},"McDonald's":{"count":16493,"tags":{"cuisine":"burger"}},"Subway":{"count":9310,"tags":{"cuisine":"sandwich"}},"Burger King":{"count":5558,"tags":{"cuisine":"burger"}},"Pizza Hut":{"count":1320,"tags":{"cuisine":"pizza"}},"Ali Baba":{"count":90},"Hungry Jacks":{"count":239,"tags":{"cuisine":"burger"}},"Red Rooster":{"count":179},"KFC":{"count":4912,"tags":{"cuisine":"chicken"}},"Chowking":{"count":213},"Jollibee":{"count":637},"Five Guys":{"count":310},"肯德基":{"count":174},"Domino's Pizza":{"count":1811,"tags":{"cuisine":"pizza"}},"Hesburger":{"count":156},"Wendy's":{"count":2624,"tags":{"cuisine":"burger"}},"Steers":{"count":168},"Arby's":{"count":1231},"A&W":{"count":497},"Tim Hortons":{"count":406},"Dairy Queen":{"count":1243},"Fish & Chips":{"count":159},"麦当劳":{"count":97},"Harvey's":{"count":138},"麥當勞":{"count":168},"Pizza Pizza":{"count":361},"Istanbul Kebab":{"count":53},"Kotipizza":{"count":77},"Jack in the Box":{"count":815,"tags":{"cuisine":"burger"}},"KFC/Taco Bell":{"count":59},"Istanbul":{"count":86},"Kochlöffel":{"count":76},"Pita Pit":{"count":110},"Telepizza":{"count":267},"Hallo Pizza":{"count":93},"Qdoba":{"count":71},"Carl's Jr.":{"count":482,"tags":{"cuisine":"burger"}},"Quiznos":{"count":336,"tags":{"cuisine":"sandwich"}},"Wimpy":{"count":156},"Sonic":{"count":1004,"tags":{"cuisine":"burger"}},"Rally's":{"count":61},"Taco Bell":{"count":2528,"tags":{"cuisine":"mexican"}},"Pizza Nova":{"count":83},"Papa John's":{"count":626,"tags":{"cuisine":"pizza"}},"Max":{"count":52},"Nordsee":{"count":188},"Mr. Sub":{"count":140},"Panera Bread":{"count":103},"Krispy Kreme":{"count":60},"Chipotle":{"count":542,"tags":{"cuisine":"mexican"}},"Макдоналдс":{"count":394,"tags":{"name:en":"McDonald's"}},"マクドナルド":{"count":1078,"tags":{"name:en":"McDonald's","cuisine":"burger"}},"ケンタッキーフライドチキン":{"count":302,"tags":{"name:en":"KFC","cuisine":"chicken"}},"Food Court":{"count":58},"Dunkin' Donuts":{"count":645,"tags":{"cuisine":"donut"}},"Asia Wok":{"count":52},"In-N-Out Burger":{"count":115},"松屋":{"count":542,"tags":{"name:en":"Matsuya"}},"Jimmy John's":{"count":379,"tags":{"cuisine":"sandwich"}},"Hardee's":{"count":511,"tags":{"cuisine":"burger"}},"Waffle House":{"count":67},"Bistro":{"count":64},"Quiznos Sub":{"count":56},"Jamba Juice":{"count":120},"Робин Сдобин":{"count":115},"Baskin-Robbins":{"count":200,"tags":{"amenity":"ice_cream"}},"くら寿司":{"count":97},"吉野家":{"count":403},"Taco Time":{"count":135},"モスバーガー":{"count":449,"tags":{"name:en":"MOS BURGER"}},"すき家":{"count":493,"tags":{"name:en":"SUKIYA"}},"CoCo壱番屋":{"count":203},"スシロー":{"count":94},"Sibylla":{"count":70},"The Pizza Company":{"count":58},"Firehouse Subs":{"count":115},"Little Caesar's":{"count":62},"Papa Murphy's":{"count":70},"Little Caesars":{"count":393,"tags":{"cuisine":"pizza"}},"El Pollo Loco":{"count":112},"Del Taco":{"count":214},"White Castle":{"count":126},"Boston Market":{"count":100},"Chick-fil-A":{"count":720,"tags":{"cuisine":"chicken"}},"Panda Express":{"count":477,"tags":{"cuisine":"chinese"}},"Checkers":{"count":83},"Wienerschnitzel":{"count":53},"ミスタードーナツ":{"count":172},"Whataburger":{"count":760},"Cold Stone Creamery":{"count":71},"Greenwich":{"count":69},"Habib's":{"count":72},"Culver's":{"count":497},"Bob's":{"count":69},"ロッテリア":{"count":83},"Church's Chicken":{"count":207},"Popeye's":{"count":374,"tags":{"cuisine":"chicken"}},"Five Guys Burgers and Fries":{"count":54},"Jersey Mike's Subs":{"count":64},"Long John Silver's":{"count":176},"Kiosk":{"count":56},"Booster Juice":{"count":58},"Burger Machine":{"count":52},"Lotteria":{"count":56},"Schlotzsky's Deli":{"count":274},"Pizza Hut Delivery":{"count":59},"Pollo Campero":{"count":115},"Шаурма":{"count":151},"Taco John's":{"count":119},"SubWay":{"count":52},"Bojangles":{"count":70},"Taco Cabana":{"count":53},"New York Pizza":{"count":53},"Русский Аппетит":{"count":120},"Теремок":{"count":117},"かっぱ寿司":{"count":76},"Zaxby's":{"count":139},"Kebabai":{"count":56},"オリジン弁当":{"count":89},"なか卯":{"count":156},"DQ":{"count":52},"Бургер Кинг":{"count":85},"Бистро":{"count":51},"サブウェイ":{"count":73},"Шаверма":{"count":66},"ほっともっと":{"count":133},"幸楽苑":{"count":67},"摩斯漢堡":{"count":61},"СтарДогс":{"count":72},"Pollo Granjero":{"count":62},"Pinulito":{"count":57}},"restaurant":{"Pizza Hut":{"count":2161,"tags":{"cuisine":"pizza"}},"Pizzeria Italia":{"count":53},"Hirsch":{"count":84},"Shakey's":{"count":53},"Little Chef":{"count":66},"Zur Krone":{"count":93},"Deutsches Haus":{"count":89},"Krone":{"count":178},"Akropolis":{"count":197},"Schützenhaus":{"count":147},"Wagamama":{"count":94},"Kreuz":{"count":85},"Waldschänke":{"count":53},"Pizza Express":{"count":380},"Jägerhof":{"count":55},"La Piazza":{"count":111},"Adler":{"count":158},"La Boucherie":{"count":72},"Lamm":{"count":68},"Zur Sonne":{"count":72},"Zur Linde":{"count":219},"La Pergola":{"count":72},"Panorama":{"count":89},"Shanghai":{"count":89},"Red Lobster":{"count":371},"Zum Löwen":{"count":82},"Swiss Chalet":{"count":148},"Frankie & Benny's":{"count":137},"Hooters":{"count":168},"Sternen":{"count":86},"Hirschen":{"count":88},"Ali Baba":{"count":51},"Denny's":{"count":737},"Sonne":{"count":116},"Ratskeller":{"count":162},"La Cantina":{"count":90},"El Greco":{"count":98},"Gasthof zur Post":{"count":96},"Löwen":{"count":134},"Lotus":{"count":77},"La Pataterie":{"count":96},"Syrtaki":{"count":61},"Bella Napoli":{"count":75},"Oasis":{"count":62},"Mandarin":{"count":82},"Nando's":{"count":338},"Zizzi":{"count":87},"Rhodos":{"count":88},"Bären":{"count":72},"Gasthaus Adler":{"count":66},"Pomodoro":{"count":52},"Lindenhof":{"count":90},"Milano":{"count":66},"Dolce Vita":{"count":108},"Kirchenwirt":{"count":92},"Kreta":{"count":67},"Kantine":{"count":99},"Hong Kong":{"count":109},"Ochsen":{"count":94},"Spur":{"count":64},"Applebee's":{"count":845},"Europa":{"count":61},"Flunch":{"count":175},"Zur Post":{"count":125},"China Town":{"count":99},"La Dolce Vita":{"count":118},"Waffle House":{"count":421},"Gasthaus Krone":{"count":89},"Linde":{"count":115},"Outback Steakhouse":{"count":348},"Dionysos":{"count":80},"Frohsinn":{"count":51},"Kelsey's":{"count":65},"Boston Pizza":{"count":239},"Mykonos":{"count":79},"Bella Italia":{"count":183},"Olympia":{"count":83},"Zum Hirschen":{"count":51},"China House":{"count":61},"Sizzler":{"count":80},"Grüner Baum":{"count":118},"Taj Mahal":{"count":154},"Delphi":{"count":102},"Casablanca":{"count":54},"Rössli":{"count":85},"Wimpy":{"count":57},"Traube":{"count":68},"La Taverna":{"count":52},"Adria":{"count":59},"Pancake House":{"count":67},"Red Robin":{"count":273},"Golden Dragon":{"count":54},"L'Osteria":{"count":64},"Bahnhof":{"count":53},"Harvester":{"count":67},"Belvedere":{"count":52},"Roma":{"count":75},"Hellas":{"count":63},"Mamma Mia":{"count":104},"La Perla":{"count":82},"Vips":{"count":87},"Tim Hortons":{"count":60},"Santorini":{"count":52},"Poseidon":{"count":131},"Gusto":{"count":59},"Тануки":{"count":55},"Da Vinci":{"count":79},"Toscana":{"count":64},"Hippopotamus":{"count":107},"La Terrazza":{"count":54},"Courtepaille":{"count":145},"Dorfkrug":{"count":54},"Hard Rock Cafe":{"count":94},"Marco Polo":{"count":58},"La Piazzetta":{"count":62},"Zorbas":{"count":53},"Athen":{"count":70},"La Fontana":{"count":53},"Pinocchio":{"count":63},"San Marco":{"count":82},"Portofino":{"count":61},"デニーズ":{"count":178},"La Gondola":{"count":56},"Sphinx":{"count":53},"Sportheim":{"count":103},"ジョリーパスタ":{"count":64},"TGI Friday's":{"count":320},"Gasthaus zur Linde":{"count":54},"餃子の王将":{"count":176},"Engel":{"count":52},"Alte Post":{"count":64},"Carpe Diem":{"count":57},"Pizzeria Roma":{"count":77},"La Casa":{"count":56},"China Garden":{"count":106},"Vapiano":{"count":123},"Bistro":{"count":59},"La Scala":{"count":59},"Telepizza":{"count":66},"Trattoria":{"count":64},"Casa Mia":{"count":63},"Taverna":{"count":52},"IHOP":{"count":643},"Chili's":{"count":556},"Asia":{"count":66},"Athos":{"count":58},"Ruby Tuesday":{"count":270},"Olive Garden":{"count":460},"Ocean Basket":{"count":57},"Mellow Mushroom":{"count":63},"Cracker Barrel":{"count":294},"La Strada":{"count":65},"Panera Bread":{"count":466},"Friendly's":{"count":108},"Buffalo Grill":{"count":255},"Taste of India":{"count":57},"Texas Roadhouse":{"count":199},"ガスト":{"count":431,"tags":{"name:en":"Gusto"}},"牛角":{"count":75},"Schwarzer Adler":{"count":59},"丸亀製麺":{"count":63},"ココス":{"count":119},"ロイヤルホスト":{"count":95},"Sushi Bar":{"count":58},"La Tasca":{"count":51},"Venezia":{"count":57},"ジョナサン":{"count":122},"Léon de Bruxelles":{"count":57},"夢庵":{"count":53},"Mensa":{"count":146},"大戸屋":{"count":51},"El Paso":{"count":54},"Five Guys":{"count":70},"びっくりドンキー":{"count":91},"サイゼリヤ":{"count":233},"MK Restaurants":{"count":51},"Village Inn":{"count":135},"Peking":{"count":69},"Sakura":{"count":109},"Tony Roma's":{"count":55},"restaurant":{"count":60},"El Rancho":{"count":71},"Prezzo":{"count":117},"La Bodega":{"count":51},"バーミヤン":{"count":115},"Mimi's Cafe":{"count":53},"Little Italy":{"count":71},"Boston Market":{"count":80},"La Trattoria":{"count":72},"Bonefish Grill":{"count":66},"Wasabi":{"count":62},"China Wok":{"count":76},"Joe's Crab Shack":{"count":66},"Round Table Pizza":{"count":78},"Buffalo Wild Wings":{"count":365},"Perkins":{"count":140},"La Terrasse":{"count":69},"L'Escale":{"count":54},"Shari's":{"count":70},"Bob Evans":{"count":237},"바다횟집 (Bada Fish Restaurant)":{"count":56},"Mang Inasal":{"count":115},"California Pizza Kitchen":{"count":98},"Da Grasso":{"count":53},"Якитория":{"count":80},"Pizza Ranch":{"count":64},"Golden Corral":{"count":191},"Old Chicago":{"count":51},"Евразия":{"count":95},"Carrabba's Italian Grill":{"count":52},"Noodles & Company":{"count":80},"Canteen":{"count":60},"Kudu":{"count":172},"Cold Stone Creamery":{"count":59},"O'Charley's":{"count":59},"Qdoba":{"count":70},"Campanile":{"count":52},"Jason's Deli":{"count":63},"安楽亭":{"count":53},"LongHorn Steakhouse":{"count":151},"Logan's Roadhouse":{"count":81},"Moe's Southwest Grill":{"count":62},"Sushi":{"count":53},"Sonic":{"count":64,"tags":{"cuisine":"burger"}},"Famous Dave's":{"count":56},"Jimmy John's":{"count":119,"tags":{"cuisine":"sandwich"}},"Hardee's":{"count":51,"tags":{"cuisine":"burger"}},"天下一品":{"count":61},"Little Caesars":{"count":66,"tags":{"cuisine":"pizza"}},"Firehouse Subs":{"count":65},"Steak 'n Shake":{"count":68,"tags":{"cuisine":"burger"}},"ジョイフル":{"count":53},"Dunkin' Donuts":{"count":76,"tags":{"cuisine":"donut"}},"やよい軒":{"count":52},"Ristorante Del Arte":{"count":143},"八方雲集":{"count":94}},"parking":{"Coop":{"count":55},"Wanderparkplatz":{"count":796},"Tesco":{"count":86},"Carpool":{"count":55},"Friedhof":{"count":485},"Park and Ride":{"count":88},"Rathaus":{"count":111},"P1":{"count":357},"P2":{"count":351},"Markt":{"count":77},"Public Parking":{"count":173},"Rewe":{"count":201},"ALDI":{"count":324},"P7":{"count":96},"P8":{"count":62},"Parkplatz":{"count":278},"Car Park":{"count":232},"P9":{"count":56},"Lot D":{"count":91},"Park & Ride":{"count":139},"Marktplatz":{"count":166},"P3":{"count":282},"Parkhaus":{"count":139},"Visitor Parking":{"count":246},"Parking de la Mairie":{"count":105},"Edeka":{"count":142},"Besucherparkplatz":{"count":182},"Friedhofsparkplatz":{"count":165},"Estacionamiento":{"count":214},"Festplatz":{"count":109},"Behindertenparkplatz":{"count":176},"Place de l'Église":{"count":311},"Volksbank":{"count":59},"Sportplatz":{"count":143},"P&R":{"count":59},"Kaufland":{"count":117},"Waldparkplatz":{"count":143},"Bahnhof":{"count":98},"P+R":{"count":150},"Parcare":{"count":300},"Sparkasse":{"count":129},"NETTO":{"count":268},"Tesco Car Park":{"count":59},"Bus":{"count":61},"Norma":{"count":68},"Kirche":{"count":52},"P6":{"count":132},"Kundenparkplatz":{"count":280},"School":{"count":241},"Parkplatz Friedhof":{"count":124},"Place de la Mairie":{"count":229},"Krankenhaus":{"count":55},"parking":{"count":252},"Schulparkplatz":{"count":76},"Place de la République":{"count":137},"Lehrerparkplatz":{"count":189},"Lidl":{"count":544},"P10":{"count":55},"P4":{"count":214},"停車場":{"count":92},"Dorfplatz":{"count":53},"P":{"count":73},"Staff Car Park":{"count":71},"Парковка":{"count":164},"Busparkplatz":{"count":122},"PKW":{"count":59},"LKW":{"count":81},"Parking de la Gare":{"count":125},"Carrefour":{"count":77},"Spar":{"count":69},"Mitarbeiterparkplatz":{"count":110},"Parkplatz Lidl":{"count":60},"Penny":{"count":123},"McDonald's":{"count":166,"tags":{"cuisine":"burger"}},"Disabled Parking":{"count":58},"Anwohnerparkplatz":{"count":68},"Bus Parking":{"count":117},"Pendlerparkplatz":{"count":68},"Gravel Parking Lot, Mille Lacs WMA":{"count":82},"Privatparkplatz":{"count":71},"Parking de la Poste":{"count":52},"Lidl Parkplatz":{"count":78},"Place du 19 Mars 1962":{"count":88},"Place de la Liberté":{"count":55},"P5":{"count":193},"Parcheggio":{"count":198},"counter":{"count":110},"Park":{"count":325},"Car Parking":{"count":159},"Parking du Cimetière":{"count":62},"タイムズ":{"count":870},"Visitor":{"count":60},"Private":{"count":188},"Netto Parkplatz":{"count":51},"Place du Champ de Foire":{"count":63},"Kunden":{"count":65},"Parqueadero":{"count":103},"TIR":{"count":93},"Student Parking":{"count":98},"Faculty Parking":{"count":62},"Parking":{"count":1047},"Esselunga":{"count":66},"Автостоянка":{"count":171},"Place du 8 Mai 1945":{"count":86},"Place du Général de Gaulle":{"count":83},"Billa":{"count":51},"Parking Garage":{"count":81},"Freibad":{"count":57},"Staff Parking":{"count":215},"Паркинг":{"count":88},"Place du Marché":{"count":105},"Parqueo":{"count":122},"PMR":{"count":130},"Besucher":{"count":101},"Estacionamento":{"count":122},"<different> Boat Ramp":{"count":113},"Lot B":{"count":107},"Parking leśny":{"count":63},"Стоянка":{"count":147},"Lot C":{"count":95},"Truck Parking":{"count":144},"Parking Lot":{"count":127},"三井のリパーク":{"count":595},"Lot 6":{"count":72},"Lot 2":{"count":81},"Lot 1":{"count":96},"Lot 5":{"count":84},"Lot 3":{"count":90},"Lot 4":{"count":76},"Place de la Libération":{"count":55},"LKW-Parkplatz":{"count":55},"Aldi Süd":{"count":82},"Aparcamiento":{"count":110},"Parkplatz Netto":{"count":56},"Mieterparkplatz":{"count":180},"P11":{"count":51},"Гаражи":{"count":96},"Church":{"count":90},"Private Parking":{"count":55},"H":{"count":51},"Parking strzeżony":{"count":52},"Parkoló":{"count":82},"Privat":{"count":69},"Mitarbeiter":{"count":51},"Handicapped":{"count":203},"Park Cimitero":{"count":126},"駐車場":{"count":178},"Place de la Gare":{"count":72},"car parking":{"count":96},"Parcheggio disabili":{"count":266},"Employee Parking":{"count":104},"Motorcycle Parking":{"count":62},"miejsce postoju":{"count":66},"Overflow Parking":{"count":69},"پارکینگ":{"count":74},"Disabled":{"count":210},"名鉄協商パーキング":{"count":182},"月極駐車場":{"count":67},"Lot A":{"count":110},"Parcheggio Disabili":{"count":238},"Garaje":{"count":83},"Life Time Fitness Parking":{"count":55},"truck parking":{"count":84},"Lot F":{"count":57},"Lot 7":{"count":61},"truck":{"count":271},"car":{"count":460},"Lot H":{"count":54},"Lot E":{"count":67},"Lot G":{"count":55},"Förhyrda":{"count":58}},"bank":{"Chase":{"count":1355},"Commonwealth Bank":{"count":338},"Citibank":{"count":421},"Barclays":{"count":1203},"Westpac":{"count":297},"NAB":{"count":186},"HSBC":{"count":1571},"ANZ":{"count":331},"Bank of China":{"count":65},"TSB":{"count":198},"BBBank":{"count":55},"Sparkasse":{"count":4663},"UCPB":{"count":108},"PNB":{"count":293},"Metrobank":{"count":309},"BDO":{"count":473},"Volksbank":{"count":2690},"China Bank":{"count":132},"BPI":{"count":529},"Postbank":{"count":575},"NatWest":{"count":773},"بانک ملت":{"count":151},"Raiffeisenbank":{"count":2581},"Nordea":{"count":336},"Landbank":{"count":76},"Yorkshire Bank":{"count":89},"ABSA":{"count":96},"Standard Bank":{"count":137},"FNB":{"count":117},"بانک کشاورزی":{"count":100},"بانک مسکن":{"count":96},"Deutsche Bank":{"count":995},"Santander":{"count":2861},"Commerzbank":{"count":867},"Targobank":{"count":201},"ABN AMRO":{"count":144},"SEB":{"count":131},"Handelsbanken":{"count":239},"Kreissparkasse":{"count":615},"UniCredit Bank":{"count":501},"Monte dei Paschi di Siena":{"count":225},"Banca Popolare di Milano":{"count":76},"Caja Rural":{"count":186},"Sparda-Bank":{"count":284},"VÚB":{"count":103},"Slovenská sporiteľňa":{"count":157},"Банка ДСК":{"count":59},"Bank of Montreal":{"count":137},"Comerica Bank":{"count":55},"KBC":{"count":265},"US Bank":{"count":492},"HypoVereinsbank":{"count":449},"Bank Austria":{"count":151},"Lloyds Bank":{"count":620},"ING":{"count":596},"Erste Bank":{"count":206},"CIBC":{"count":422},"BCA":{"count":65},"Scotiabank":{"count":918},"Caisse d'Épargne":{"count":1426},"Clydesdale Bank":{"count":54},"Bank of Scotland":{"count":115},"Royal Bank of Scotland":{"count":126},"TD Canada Trust":{"count":613},"BMO":{"count":288},"Danske Bank":{"count":152},"Crédit Mutuel de Bretagne":{"count":330},"中国农业银行":{"count":148},"Crédit Agricole":{"count":2267},"LCL":{"count":846},"VR-Bank":{"count":500},"ČSOB":{"count":203},"Česká spořitelna":{"count":233},"BNP Paribas":{"count":1062},"National Bank":{"count":100},"RBC Royal Bank":{"count":104},"Nationwide":{"count":286},"中国建设银行":{"count":105},"Halifax":{"count":316},"BAWAG PSK":{"count":98},"CIBC Banking Centre":{"count":55},"Royal Bank":{"count":83},"Nedbank":{"count":92},"First National Bank":{"count":150},"Rabobank":{"count":557},"Sparkasse KölnBonn":{"count":78},"Swedbank":{"count":241},"Tatra banka":{"count":74},"IberCaja":{"count":201},"Volksbank Raiffeisenbank":{"count":60},"İş Bankası":{"count":89},"Berliner Sparkasse":{"count":67},"Berliner Volksbank":{"count":78},"Wells Fargo":{"count":1643},"Société Générale":{"count":1022},"RBC":{"count":363},"Osuuspankki":{"count":85},"Sparkasse Aachen":{"count":56},"Hamburger Sparkasse":{"count":159},"Cassa di Risparmio del Veneto":{"count":99},"Ziraat Bankası":{"count":106},"Akbank":{"count":85},"Banque Populaire":{"count":715},"BNP Paribas Fortis":{"count":282},"Banco Popular":{"count":543},"Bankia":{"count":529},"La Caixa":{"count":1120},"Credit Suisse":{"count":87},"BRD":{"count":251},"BCR":{"count":193},"BW-Bank":{"count":101},"Komerční banka":{"count":171},"Banco Pastor":{"count":77},"OTP":{"count":345},"Sberbank":{"count":130},"CIC":{"count":645},"Banca Transilvania":{"count":139},"Bancpost":{"count":70},"Maybank":{"count":155},"BBVA":{"count":1146},"Postbank Finanzcenter":{"count":55},"中国银行":{"count":209},"Unicredit Banca":{"count":462},"Crédit Mutuel":{"count":1034},"mBank":{"count":58},"Intesa San Paolo":{"count":135},"ATB Financial":{"count":58},"Belfius":{"count":280},"Piraeus Bank":{"count":59},"Bank of America":{"count":1595},"Standard Chartered":{"count":64},"Intesa Sanpaolo":{"count":66},"Сбербанк":{"count":6219},"Россельхозбанк":{"count":304},"Banc Sabadell":{"count":163},"MetroBank":{"count":82},"Crédit du Nord":{"count":138},"Popular":{"count":68},"Banco Sabadell":{"count":176},"Santander Consumer Bank":{"count":101},"BancoEstado":{"count":106},"Millennium Bank":{"count":397},"State Bank of India":{"count":317},"Banca Popolare di Novara":{"count":66},"Беларусбанк":{"count":510},"ING Bank Śląski":{"count":117},"Targo Bank":{"count":60},"Белинвестбанк":{"count":71},"Kreissparkasse Köln":{"count":68},"Banco BCI":{"count":63},"Banco de Chile":{"count":133},"Приорбанк":{"count":70},"ВТБ24":{"count":454},"UBS":{"count":169},"BPH":{"count":61},"PKO BP":{"count":453},"Казкоммерцбанк":{"count":66},"PSBank":{"count":99},"UnionBank":{"count":100},"RCBC Savings Bank":{"count":79},"EastWest Bank":{"count":66},"Commercial Bank of Ceylon PLC":{"count":97},"Caja España":{"count":63},"Unicaja Banco":{"count":180},"BBK":{"count":100},"RBS":{"count":178},"Bank of Ireland":{"count":142},"BNL":{"count":129},"Stadtsparkasse":{"count":72},"Banco Itaú":{"count":288},"AIB":{"count":86},"Райффайзенбанк":{"count":63},"BZ WBK":{"count":146},"Banco do Brasil":{"count":1063},"Caixa Econômica Federal":{"count":451},"Banca Românească":{"count":52},"Fifth Third Bank":{"count":202},"Banca Popolare di Vicenza":{"count":112},"Wachovia":{"count":53},"K&H Bank":{"count":70},"CIB Bank":{"count":61},"Budapest Bank":{"count":53},"みずほ銀行":{"count":244},"BES":{"count":54},"ICICI Bank":{"count":160},"Credem":{"count":55},"HDFC Bank":{"count":163},"La Banque Postale":{"count":109},"Bangkok Bank":{"count":69},"Bank BPH":{"count":58},"工商银行":{"count":140},"Oberbank":{"count":99},"Oldenburgische Landesbank":{"count":68},"Banco di Sardegna":{"count":72},"BRED":{"count":60},"First Bank":{"count":74},"Banca Popolare di Verona":{"count":56},"OLB":{"count":53},"Banca Popolare di Sondrio":{"count":82},"Cariparma":{"count":60},"Bendigo Bank":{"count":127},"BBVA Bancomer":{"count":97},"Argenta":{"count":114},"AXA":{"count":96},"Axis Bank":{"count":125},"Getin Bank":{"count":97},"CaixaBank":{"count":111},"Pekao SA":{"count":120},"Banca March":{"count":60},"БПС-Сбербанк":{"count":51},"Альфа-Банк":{"count":262},"GE Money Bank":{"count":86},"Белагропромбанк":{"count":157},"Banco Galicia":{"count":78},"Eurobank":{"count":215},"Bankinter":{"count":108},"横浜銀行":{"count":79},"Τράπεζα Πειραιώς":{"count":108},"Bank of New Zealand":{"count":58},"Banca Intesa":{"count":93},"Canara Bank":{"count":168},"Cajamar":{"count":149},"Banamex":{"count":288},"CEC Bank":{"count":95},"Davivienda":{"count":152},"Alpha Bank":{"count":287},"招商银行":{"count":63},"Banque Nationale":{"count":88},"第一銀行":{"count":53},"SBI":{"count":70},"Veneto Banca":{"count":65},"Bank of the West":{"count":140},"Liberbank":{"count":101},"Εθνική Τράπεζα":{"count":88},"Key Bank":{"count":226},"Western Union":{"count":327},"Citizens Bank":{"count":190},"УкрСиббанк":{"count":218},"ProCredit Bank":{"count":51},"ПриватБанк":{"count":919},"RCBC":{"count":125},"Security Bank":{"count":136},"Millenium":{"count":59},"HNB":{"count":60},"三菱東京UFJ銀行":{"count":217},"CajaSur":{"count":72},"ВТБ":{"count":70},"Indian Bank":{"count":60},"Andhra Bank":{"count":55},"Banque populaire":{"count":52},"Ulster Bank":{"count":96},"Bancolombia":{"count":122},"TD Bank":{"count":341},"Caixa":{"count":163},"SunTrust Bank":{"count":129},"Авангард":{"count":58},"Union Bank":{"count":173},"Philippine National Bank":{"count":64},"Bradesco":{"count":553},"Itaú":{"count":525},"Punjab National Bank":{"count":73},"PBZ":{"count":64},"Alior Bank":{"count":154},"中国工商银行":{"count":130},"Novo Banco":{"count":69},"Santander Río":{"count":157},"Райффайзен Банк Аваль":{"count":111},"Yorkshire Building Society":{"count":59},"De Venezuela":{"count":89},"ธนาคารไทยพาณิชย์":{"count":57},"Bancomer":{"count":192},"Banorte":{"count":186},"BOC":{"count":94},"Republic Bank":{"count":65},"Raiffeisen Polbank":{"count":60},"Банк Москвы":{"count":172},"Banco Nacional":{"count":120},"Banco Pichincha":{"count":69},"Syndicate Bank":{"count":69},"Bank Zachodni WBK":{"count":80},"Caja Duero":{"count":80},"Regions Bank":{"count":158},"KeyBank":{"count":80},"Bank of Commerce":{"count":64},"Росбанк":{"count":207},"Открытие":{"count":64},"Бинбанк":{"count":77},"People's Bank":{"count":68},"ПУМБ":{"count":63},"Banco di Napoli":{"count":67},"Bank Spółdzielczy":{"count":333},"Public Bank":{"count":56},"SunTrust":{"count":150},"PNC Bank":{"count":493},"신한은행":{"count":221,"tags":{"name:en":"Sinhan Bank"}},"우리은행":{"count":291,"tags":{"name:en":"Uri Bank"}},"국민은행":{"count":168,"tags":{"name:en":"Gungmin Bank"}},"Газпромбанк":{"count":129},"M&T Bank":{"count":138},"Indian Overseas Bank":{"count":62},"Santander Totta":{"count":186},"Banco de Bogotá":{"count":51},"Ощадбанк":{"count":684},"State Bank of Mysore":{"count":58},"Banco Estado":{"count":110},"Ecobank":{"count":138},"Takarékszövetkezet":{"count":120},"East West Bank":{"count":53},"بانک صادرات":{"count":178},"Banco Azteca":{"count":79},"TCF Bank":{"count":68},"Banco Nación":{"count":123},"Galicia":{"count":58},"Macro":{"count":57},"Πειραιώς":{"count":109},"Промсвязьбанк":{"count":120},"بانک سپه":{"count":119},"بانک ملی":{"count":186},"Уралсиб":{"count":118},"صادرات":{"count":61},"三井住友銀行":{"count":179},"りそな銀行":{"count":122},"Commercial Bank":{"count":53},"BCI":{"count":91},"Banco de Costa Rica":{"count":113},"Hrvatska poštanska banka":{"count":55},"Caixa Geral de Depósitos":{"count":210},"Banco Provincia":{"count":98},"Bank of India":{"count":59},"Umpqua Bank":{"count":70},"BCP":{"count":86},"BB&T":{"count":344},"Capital One":{"count":114},"ABANCA":{"count":79},"Возрождение":{"count":67},"Banco Macro":{"count":79},"МДМ Банк":{"count":59},"Capital One Bank":{"count":68},"BBVA Compass":{"count":60},"Caja Círculo":{"count":69},"CatalunyaCaixa":{"count":110},"One Network Bank":{"count":89},"Occidental de Descuento":{"count":67},"Народный банк":{"count":56},"Bank Mandiri":{"count":130},"Banco de la Nación Argentina":{"count":73},"Mercantil":{"count":116},"PKO Bank Polski":{"count":75},"Русский стандарт":{"count":52},"First Citizens Bank":{"count":69},"Corporation Bank":{"count":61},"Bank of Baroda":{"count":68},"Banco G&T Continental":{"count":86},"U.S. Bank":{"count":69},"Banco de Occidente":{"count":55},"Kasa Stefczyka":{"count":57},"Мособлбанк":{"count":52},"CGD":{"count":56},"Huntington Bank":{"count":74},"Sampath Bank":{"count":72},"Peoples Bank":{"count":151},"建设银行":{"count":78},"Interbank":{"count":68},"Banrisul":{"count":76},"بانک تجارت":{"count":122},"Cбербанк":{"count":79},"BBVA Francés":{"count":75},"ธนาคารกรุงเทพ":{"count":77},"ธนาคารกสิกรไทย":{"count":66},"Millenium BCP":{"count":54},"Montepio":{"count":105},"Provincial":{"count":78},"Bicentenario":{"count":127},"Banesco":{"count":172},"ธนาคารกรุงไทย":{"count":60},"Garanti Bankası":{"count":59},"Совкомбанк":{"count":102},"BNA":{"count":67},"BAC":{"count":74},"Banrural":{"count":58},"BRI":{"count":62},"Banco Industrial":{"count":74},"京都銀行":{"count":67},"Cajero Automatico Bancared":{"count":122},"Banco de Desarrollo Banrural":{"count":84},"Banco Patagonia":{"count":51},"ICBC":{"count":107},"Banco de Venezuela":{"count":53},"Banco de la Nación":{"count":117},"Banco Bradesco":{"count":190},"Bank of Africa":{"count":52},"Sicredi":{"count":64},"ლიბერთი ბანკი":{"count":54,"tags":{"name:en":"Liberty Bank"}},"ملی":{"count":52},"Crédito Agrícola":{"count":79},"Caja Rural de Jaén":{"count":54},"ASB Bank":{"count":51},"농협":{"count":51},"РНКБ":{"count":78},"农业银行":{"count":64},"Bank BRI":{"count":140},"Генбанк":{"count":67},"하나은행":{"count":81},"CityCommerce Bank":{"count":54}},"bureau_de_change":{"Western Union":{"count":119},"Kantor":{"count":106}},"car_rental":{"Europcar":{"count":468},"Budget":{"count":161},"Sixt":{"count":250},"Hertz":{"count":511},"Avis":{"count":481},"Enterprise":{"count":443},"Thrifty":{"count":58},"U-Haul":{"count":74},"ニッポンレンタカー":{"count":87}},"pharmacy":{"Lloyds Pharmacy":{"count":436},"Rowlands Pharmacy":{"count":102},"Boots":{"count":1096},"Marien-Apotheke":{"count":371},"Park-Apotheke":{"count":55},"Mercury Drug":{"count":507},"Löwen-Apotheke":{"count":398},"Superdrug":{"count":157},"Sonnen-Apotheke":{"count":374},"Engel-Apotheke":{"count":143},"Hirsch-Apotheke":{"count":114},"Apoteket":{"count":53},"Stadt-Apotheke":{"count":387},"Markt-Apotheke":{"count":203},"Аптека":{"count":2787},"Brunnen-Apotheke":{"count":77},"Hubertus Apotheke":{"count":124},"Bahnhof Apotheke":{"count":51},"Shoppers Drug Mart":{"count":642},"Pharmacie Centrale":{"count":178},"Alte Apotheke":{"count":99},"Neue Apotheke":{"count":122},"Rathaus-Apotheke":{"count":178},"Gintarinė vaistinė":{"count":116},"Rats-Apotheke":{"count":127},"Rosen-Apotheke":{"count":203},"Eczane":{"count":55},"Pharmasave":{"count":116},"Adler Apotheke":{"count":378},"Bären-Apotheke":{"count":109},"Hirsch Apotheke":{"count":69},"Walgreens":{"count":2896},"Rite Aid":{"count":1293},"Linden-Apotheke":{"count":220},"Bahnhof-Apotheke":{"count":88},"Burg-Apotheke":{"count":77},"Apotheke am Markt":{"count":82},"Schloss-Apotheke":{"count":62},"Jean Coutu":{"count":93},"Pharmaprix":{"count":79},"Pharmacie du Centre":{"count":123},"Farmacias Ahumada":{"count":130},"Stern-Apotheke":{"count":83},"Guardian":{"count":59},"Farmacia Comunale":{"count":167},"Dr.Max":{"count":102},"Cruz Verde":{"count":132},"ГорЗдрав":{"count":65},"Watsons":{"count":67},"Farmacias Cruz Verde":{"count":132},"CVS":{"count":2678},"Sensiblu":{"count":96},"Норма":{"count":89},"Farmacias SalcoBrand":{"count":142},"Фармация":{"count":163},"Pharmacie du Marché":{"count":89},"Pharmacie de la Mairie":{"count":57},"Farmacia Guadalajara":{"count":101},"Apteka":{"count":579},"Pharmacie Principale":{"count":54},"Clicks":{"count":116},"セイジョー":{"count":62},"Аптека №1":{"count":80},"マツモトキヨシ":{"count":171},"Dr. Max":{"count":169},"Вита":{"count":119},"Catena":{"count":88},"Здоровье":{"count":64},"Аптека 36,6":{"count":238},"Радуга":{"count":109},"サンドラッグ":{"count":98},"Pharmacie de la Gare":{"count":100},"Apollo Pharmacy":{"count":58},"Chemist Warehouse":{"count":74},"Rexall":{"count":88},"Первая помощь":{"count":114},"Gyógyszertár":{"count":51},"Ригла":{"count":187},"Droga Raia":{"count":104},"Аптека низьких цін":{"count":60},"Rose Pharmacy":{"count":83},"Dbam o Zdrowie":{"count":51},"Kinney Drugs":{"count":71},"Классика":{"count":91},"Ljekarna":{"count":66},"Фармакор":{"count":103},"Farmàcia":{"count":56},"スギ薬局":{"count":101},"Pague Menos":{"count":55},"Горздрав":{"count":139},"Mēness aptieka":{"count":60},"South Star Drug":{"count":57},"Панацея":{"count":58},"Арніка":{"count":123},"Drogaria São Paulo":{"count":52},"Аптечный пункт":{"count":254},"Невис":{"count":106},"Panvel":{"count":52},"Айболит":{"count":71},"SalcoBrand":{"count":90},"Живика":{"count":58},"Walmart Pharmacy":{"count":84},"Walgreens Pharmacy":{"count":59},"Farmacity":{"count":135},"аптека":{"count":126},"The Generics Pharmacy":{"count":171},"Farmacias del Ahorro":{"count":110},"Farmacias Similares":{"count":84},"Farmatodo":{"count":137},"ツルハドラッグ":{"count":116},"Duane Reade":{"count":78},"Фармленд":{"count":93},"H-E-B Pharmacy":{"count":219},"Планета здоровья":{"count":101},"pharmacie":{"count":62},"А5":{"count":94},"Имплозия":{"count":97},"Eurovaistinė":{"count":83},"Бережная аптека":{"count":58},"36.6":{"count":51},"Benavides":{"count":65},"ドラッグてらしま (Drug Terashima)":{"count":77},"Farmacias Guadalajara":{"count":66},"Drogasil":{"count":93},"Фармакопейка":{"count":53},"Аптека от склада":{"count":52},"クリエイト":{"count":51},"ავერსი (Aversi)":{"count":58},"Inkafarma":{"count":56},"Farmahorro":{"count":51},"ウエルシア":{"count":61},"داروخانه":{"count":58},"丁丁藥局":{"count":72}},"library":{"Stadtbibliothek":{"count":233},"Central Library":{"count":56},"Stadtbücherei":{"count":282},"Médiathèque":{"count":251},"Public Library":{"count":74},"Biblioteca Municipal":{"count":388},"Gemeindebücherei":{"count":138},"Bibliothek":{"count":81},"Biblioteca Comunale":{"count":193},"Library":{"count":536},"Bibliothèque municipale":{"count":203},"Bibliothèque Municipale":{"count":266},"Bibliothèque":{"count":252},"Bücherei":{"count":108},"Biblioteca Pública Municipal":{"count":55},"Bibliotheek":{"count":71},"Библиотека":{"count":369},"Детская библиотека":{"count":208},"Центральная городская библиотека":{"count":52},"Biblioteca":{"count":188},"Miejska Biblioteka Publiczna":{"count":59},"Městská knihovna":{"count":54},"Biblioteka":{"count":71},"Biblioteca comunale":{"count":175},"Biblioteka Publiczna":{"count":68},"Gminna Biblioteka Publiczna":{"count":52},"Центральная библиотека":{"count":69},"Biblioteca Pública":{"count":52},"Бібліотека":{"count":71},"Городская библиотека":{"count":54},"图书馆":{"count":51}},"kindergarten":{"Kindergarten":{"count":980},"Arche Noah":{"count":65},"Waldkindergarten":{"count":101},"Städtischer Kindergarten":{"count":98},"Детский сад №19":{"count":56},"Детский сад №11":{"count":71},"Детский сад №8":{"count":73},"Детский сад №2":{"count":139},"Детский сад №7":{"count":89},"Детский сад №15":{"count":65},"Evangelischer Kindergarten":{"count":214},"Katholischer Kindergarten":{"count":99},"Villa Kunterbunt":{"count":86},"Waldorfkindergarten":{"count":69},"Ev. Kindergarten":{"count":106},"Kindergarten St. Josef":{"count":52},"Kindertagesstätte":{"count":130},"Pusteblume":{"count":55},"École maternelle":{"count":335},"Materská škola":{"count":133},"MŠ":{"count":100},"Детский сад №1":{"count":134},"Детский сад №18":{"count":72},"École Maternelle":{"count":66},"Crèche":{"count":99},"Kindergarten Regenbogen":{"count":61},"Przedszkole":{"count":140},"Mateřská škola":{"count":164},"Детский сад":{"count":812},"детский сад":{"count":77},"Óvoda":{"count":63},"Jardin Infantil":{"count":77},"Детский сад №4":{"count":77},"Nursery School":{"count":110},"Детский сад №3":{"count":112},"Детский сад №14":{"count":69},"Детский сад №5":{"count":95},"Детский сад №10":{"count":69},"Детский сад №29":{"count":51},"Детский сад №22":{"count":55},"Scuola Materna":{"count":60},"Детский сад №25":{"count":53},"Детский сад №6":{"count":85},"Солнышко":{"count":87},"საბავშვო ბაღი (Kindergarten)":{"count":149},"Детский сад №9":{"count":71},"PAUD":{"count":83},"Детский сад №12":{"count":51},"中央保育所":{"count":56},"Детский сад \"Солнышко\"":{"count":54},"Maria Montessori":{"count":91},"Rosaura Zapata":{"count":70},"Federico Froebel":{"count":88},"Детский сад №17":{"count":59},"Gabriela Mistral":{"count":129},"Anganwadi":{"count":85},"Jean Piaget":{"count":82},"Amado Nervo":{"count":64},"Benito Juarez":{"count":89},"Cuauhtemoc":{"count":55},"Educacion Inicial de CONAFE No Escolarizado":{"count":184},"Emiliano Zapata":{"count":60},"Estefania Casta�eda":{"count":53},"Jose Vasconcelos":{"count":71},"Juan Escutia":{"count":83},"Miguel Hidalgo Y Costilla":{"count":57},"Preescolar Comunitario":{"count":409},"CONAFE Preescolar":{"count":91},"Ni�os Heroes":{"count":68},"Sor Juana Ines De La Cruz":{"count":76},"Cursos Comunitarios":{"count":74}},"cafe":{"Starbucks":{"count":6881,"tags":{"cuisine":"coffee_shop"}},"Cafeteria":{"count":436},"Costa":{"count":1104},"Caffè Nero":{"count":247},"Кафе":{"count":364},"Café Central":{"count":100},"Tim Hortons":{"count":1662},"Second Cup":{"count":227},"Country Style":{"count":60},"Bar Centrale":{"count":67},"Dunkin' Donuts":{"count":1300,"tags":{"cuisine":"donut"}},"Espresso House":{"count":95},"Coffee Time":{"count":134},"Eiscafe Dolomiti":{"count":52},"Cafe Coffee Day":{"count":197},"Eiscafe Venezia":{"count":226},"スターバックス":{"count":503,"tags":{"name:en":"Starbucks"}},"タリーズコーヒー":{"count":230},"Coffee House":{"count":62},"Segafredo":{"count":101},"Dolce Vita":{"count":55},"Pret A Manger":{"count":155},"Barista":{"count":53},"Venezia":{"count":52},"Шоколадница":{"count":223},"Peet's Coffee & Tea":{"count":64},"Jamba Juice":{"count":68},"Сказка":{"count":56},"ドトールコーヒーショップ":{"count":488},"Café des Sports":{"count":63},"Internet Cafe":{"count":53},"Coffee Shop":{"count":53},"Bistro":{"count":56},"Столовая":{"count":903},"Tchibo":{"count":172},"Бистро":{"count":65},"The Coffee Club":{"count":62},"Теремок":{"count":56},"Кофе Хауз":{"count":121},"Wayne's Coffee":{"count":51},"星巴克":{"count":93},"The Coffee Bean & Tea Leaf":{"count":69},"Закусочная":{"count":74},"Caribou Coffee":{"count":147},"Уют":{"count":81},"ארומה":{"count":53},"カフェ・ベローチェ":{"count":106},"Кофейня":{"count":56},"Шашлычная":{"count":109},"Кафетерий":{"count":55},"Встреча":{"count":70},"Coffee Fellows":{"count":68},"Havanna":{"count":52},"コメダ珈琲店":{"count":147},"คาเฟ่ อเมซอน":{"count":61},"Traveler's Coffee":{"count":64},"85度C":{"count":80},"Café Amazon":{"count":231},"エクセルシオール カフェ":{"count":56},"カフェ・ド・クリエ":{"count":76,"tags":{"name:en":"Cafe de CRIE"}},"サンマルクカフェ":{"count":150},"Bar Kafe":{"count":154}},"school":{"Школа №17":{"count":105},"Kindergarten":{"count":120},"Základná škola":{"count":96},"Astrid-Lindgren-Schule":{"count":78},"École primaire":{"count":2788},"Albert-Schweitzer-Schule":{"count":84},"Grundschule":{"count":653},"Realschule":{"count":75},"school":{"count":51},"Volkshochschule":{"count":100},"Sunnyside School":{"count":61},"Primary School":{"count":1171},"École primaire Jules Ferry":{"count":78},"Základní škola":{"count":159},"Musikschule":{"count":156},"École Primaire":{"count":184},"École Saint-Joseph":{"count":85},"École maternelle":{"count":880},"Erich-Kästner-Schule":{"count":53},"Hauptschule":{"count":156},"Escola Primária":{"count":66},"ZŠ":{"count":111},"Holy Trinity School":{"count":60},"Школа №21":{"count":69},"Школа №27":{"count":55},"Школа №7":{"count":198},"Школа №11":{"count":132},"Школа №16":{"count":89},"Школа №24":{"count":71},"Школа №22":{"count":76},"Saint Joseph School":{"count":149},"Scuola Materna":{"count":63},"Center School":{"count":118},"Jackson School":{"count":60},"Lincoln School":{"count":288},"Roosevelt School":{"count":118},"Pleasant Valley School":{"count":86},"Garfield Elementary School":{"count":66},"Riverside School":{"count":76},"Gimnazjum nr 1":{"count":57},"École Communale":{"count":98},"Volksschule":{"count":372},"Pestalozzischule":{"count":84},"Scuola Elementare":{"count":201},"Scuole Elementari":{"count":61},"Colegio San José":{"count":64},"Schule":{"count":56},"Средняя школа":{"count":161},"Школа №1":{"count":534},"Trinity School":{"count":86},"Secondary School":{"count":222},"Szkoła":{"count":59},"Saint Johns School":{"count":176},"Schillerschule":{"count":59},"Музыкальная школа":{"count":257},"École élémentaire":{"count":845},"École maternelle publique":{"count":78},"École primaire publique":{"count":144},"Гимназия №1":{"count":93},"École primaire privée Saint-Joseph":{"count":130},"Collège Jean Moulin":{"count":65},"Primarschule":{"count":68},"Emiliano Zapata":{"count":286},"Школа №18":{"count":108},"Школа №2":{"count":481},"Школа №3":{"count":380},"Школа №5":{"count":266},"Гимназия":{"count":80},"Школа №26":{"count":60},"École communale":{"count":56},"Scuola Media":{"count":95},"Escuela":{"count":313},"Miguel Hidalgo":{"count":85},"Turnhalle":{"count":60},"École":{"count":452},"Longfellow Elementary School":{"count":54},"Oak Grove School":{"count":149},"Scuola elementare":{"count":94},"Central High School":{"count":140},"Central Elementary School":{"count":176},"Central School":{"count":222},"Fairview School":{"count":166},"Fairview Elementary School":{"count":61},"Garfield School":{"count":61},"Franklin School":{"count":134},"Franklin Elementary School":{"count":100},"Highland School":{"count":72},"Holy Cross School":{"count":70},"Holy Family School":{"count":75},"Hillcrest Elementary School":{"count":60},"Jefferson Elementary School":{"count":177},"Jackson Elementary School":{"count":52},"Jefferson School":{"count":116},"Immaculate Conception School":{"count":86},"Lincoln Elementary School":{"count":264},"Liberty School":{"count":87},"Longfellow School":{"count":60},"McKinley School":{"count":65},"Maple Grove School":{"count":51},"Pine Grove School":{"count":63},"Pleasant View School":{"count":62},"Pleasant Hill School":{"count":110},"Roosevelt Elementary School":{"count":116},"Saint Josephs School":{"count":166},"Saint James School":{"count":89},"Sacred Heart School":{"count":210},"Saint Pauls School":{"count":76},"Saint Peters School":{"count":83},"Saint Marys School":{"count":272},"Saint Patricks School":{"count":87},"Saint Paul School":{"count":53},"Smith School":{"count":61},"Union School":{"count":131},"Trinity Lutheran School":{"count":51},"Wilson School":{"count":85},"Wilson Elementary School":{"count":63},"Washington School":{"count":225},"Washington Elementary School":{"count":191},"White School":{"count":52},"West Elementary School":{"count":58},"Saint Francis School":{"count":58},"Saint Mary School":{"count":53},"North Elementary School":{"count":56},"McKinley Elementary School":{"count":61},"Brown School":{"count":57},"Miller School":{"count":67},"Mount Pleasant School":{"count":63},"School Number 1":{"count":250},"School Number 4":{"count":137},"School Number 3":{"count":192},"School Number 2":{"count":217},"Highland Elementary School":{"count":52},"Liberty Elementary School":{"count":52},"Bethel School (historical)":{"count":97},"Cedar Grove School (historical)":{"count":71},"Center School (historical)":{"count":87},"Central School (historical)":{"count":70},"Fairview School (historical)":{"count":219},"Friendship School (historical)":{"count":63},"Hickory Grove School (historical)":{"count":59},"Hopewell School (historical)":{"count":63},"Liberty School (historical)":{"count":111},"Mount Olive School (historical)":{"count":55},"Mount Pleasant School (historical)":{"count":77},"Mount Zion School (historical)":{"count":96},"New Hope School (historical)":{"count":95},"Oak Hill School (historical)":{"count":53},"Pine Grove School (historical)":{"count":103},"Pleasant Grove School (historical)":{"count":92},"Pleasant Hill School (historical)":{"count":134},"Salem School (historical)":{"count":72},"Union School (historical)":{"count":157},"Walnut Grove School (historical)":{"count":70},"Oak Grove School (historical)":{"count":261},"Maple Grove School (historical)":{"count":54},"Pleasant Valley School (historical)":{"count":95},"Shady Grove School (historical)":{"count":80},"Shiloh School (historical)":{"count":75},"School Number 3 (historical)":{"count":276},"School Number 4 (historical)":{"count":304},"Antioch School (historical)":{"count":70},"School Number 1 (historical)":{"count":276},"School Number 12 (historical)":{"count":128},"School Number 5 (historical)":{"count":272},"School Number 7 (historical)":{"count":255},"School Number 8 (historical)":{"count":209},"School Number 10 (historical)":{"count":160},"Mount Zion School":{"count":53},"Midway School (historical)":{"count":55},"School Number 15 (historical)":{"count":56},"School Number 2 (historical)":{"count":290},"School Number 9 (historical)":{"count":185},"High School":{"count":62},"School Number 6 (historical)":{"count":263},"School Number 11 (historical)":{"count":130},"School Number 14 (historical)":{"count":71},"School Number 13 (historical)":{"count":91},"Gimnazjum":{"count":96},"Zespół Szkół":{"count":83},"Szkoła Podstawowa":{"count":291},"Школа искусств":{"count":75},"School":{"count":1293},"École Élémentaire":{"count":65},"École Maternelle":{"count":62},"Школа №10":{"count":164},"Школа №19":{"count":92},"Escuela Primaria":{"count":79},"École élémentaire publique":{"count":104},"Ecole":{"count":248},"Школа":{"count":665},"Школа №12":{"count":130},"Elementary School":{"count":64},"Scuola Primaria":{"count":71},"Escola Municipal":{"count":161},"Детская школа искусств":{"count":101},"Groupe Scolaire":{"count":55},"CEM":{"count":183},"Школа №8":{"count":187},"École primaire Jean Jaurès":{"count":61},"Szkoła Podstawowa nr 3":{"count":57},"Школа №14":{"count":116},"Школа №13":{"count":128},"Школа № 1":{"count":126},"Szkoła Podstawowa nr 2":{"count":73},"Colegio":{"count":66},"Szkoła Podstawowa nr 1":{"count":75},"Школа №25":{"count":59},"Школа № 2":{"count":105},"Școala":{"count":51},"École primaire privée Notre-Dame":{"count":63},"Школа №4":{"count":275},"Школа №6":{"count":205},"Школа №15":{"count":113},"EPP":{"count":68},"Школа № 4":{"count":78},"Lycée":{"count":120},"Школа № 6":{"count":52},"Ecole primaire":{"count":107},"Szkoła podstawowa":{"count":77},"Школа № 3":{"count":78},"Sekolah":{"count":184},"Escola Estadual":{"count":57},"Collège privé Saint-Joseph":{"count":56},"Школа №9":{"count":178},"Начальная школа":{"count":77},"Школа №23":{"count":76},"Primaire":{"count":59},"Школа-интернат":{"count":109},"Школа №20":{"count":94},"Школа №31":{"count":51},"市立南小学校":{"count":58},"Ecole Primaire":{"count":57},"Средняя школа №2":{"count":70},"UNIDAD EDUCATIVA":{"count":105},"Средняя школа №1":{"count":59},"Nursery School":{"count":66},"Benito Juarez":{"count":295},"SDN":{"count":287},"市立南中学校":{"count":57},"市立東中学校":{"count":62},"市立西中学校":{"count":52},"SD":{"count":54},"Leona Vicario":{"count":64},"École primaire privée Sainte-Marie":{"count":57},"школа":{"count":72},"ESCUELA":{"count":224},"Escola":{"count":70},"École primaire privée":{"count":64},"Általános iskola":{"count":106},"Adolfo Lopez Mateos":{"count":139},"Amado Nervo":{"count":85},"Cuauhtemoc":{"count":152},"Gregorio Torres Quintero":{"count":54},"Guadalupe Victoria":{"count":58},"Ignacio Zaragoza":{"count":98},"Justo Sierra":{"count":118},"Nicolas Bravo":{"count":58},"Vicente Guerrero":{"count":159},"مدرسه":{"count":97},"ESCOLA":{"count":75},"sekolah":{"count":75},"École Primaire Publique":{"count":53},"Juan Escutia":{"count":122},"Josefa Ortiz De Dominguez":{"count":78},"Curso Comunitario":{"count":58},"Francisco I. Madero":{"count":52},"Francisco Villa":{"count":116},"Ignacio Allende":{"count":51},"Jose Clemente Orozco":{"count":59},"Lazaro Cardenas":{"count":69},"Miguel Hidalgo Y Costilla":{"count":213},"Ni�os Heroes":{"count":158},"Ricardo Flores Magon":{"count":91},"Valentin Gomez Farias":{"count":72},"Venustiano Carranza":{"count":64},"Jose Vasconcelos":{"count":75},"Lazaro Cardenas Del Rio":{"count":153},"Agustin Ya�ez":{"count":57},"Manuel Lopez Cotilla":{"count":111},"Nombre En Tramite":{"count":130},"Sor Juana Ines De La Cruz":{"count":56},"Francisco I Madero":{"count":87},"Jose Ma Morelos Y Pavon":{"count":120},"Pedro Moreno":{"count":69},"Ramon Corona":{"count":54},"Cursos Comunitarios":{"count":116},"Primaria Comunitaria":{"count":58},"Saint Kizito Primary School":{"count":61}},"cinema":{"Odeon":{"count":77},"Cineworld":{"count":58},"Cinemark":{"count":68}},"doctors":{"Ärztehaus":{"count":243},"Centro de Salud":{"count":89},"Поликлиника":{"count":152},"Cabinet Médical":{"count":77},"Orvosi rendelő":{"count":64},"Cabinet médical":{"count":84},"Инвитро":{"count":74},"Женская консультация":{"count":66},"Детская поликлиника":{"count":89},"Амбулатория":{"count":53},"Фельдшерско-акушерский пункт":{"count":58},"Ośrodek Zdrowia":{"count":58},"Медпункт":{"count":65},"ФАП":{"count":87},"Consultorio Médico":{"count":102},"Centre de Santé":{"count":54}},"hospital":{"Детская поликлиника":{"count":181},"Centro de Saúde":{"count":86},"Женская консультация":{"count":55},"Centro de Salud":{"count":280},"Cruz Roja":{"count":79},"IMSS":{"count":62},"Government Hospital":{"count":77},"ЦРБ":{"count":114},"Больница":{"count":276},"Поликлиника":{"count":325},"Центральная районная больница":{"count":133},"Роддом":{"count":106},"Городская больница":{"count":60},"Hospital":{"count":157},"Кожно-венерологический диспансер":{"count":51},"Hospital Municipal":{"count":102},"Hôpital":{"count":51},"경희한의원 (Gyeonghui Oriental Medicine Clinic)":{"count":52},"Амбулатория":{"count":81},"Скорая помощь":{"count":66},"Районная больница":{"count":74},"Медпункт":{"count":54},"Детская больница":{"count":87},"ФАП":{"count":86},"Родильный дом":{"count":66},"Инфекционное отделение":{"count":71},"Consultorio Médico":{"count":64},"โรงพยาบาลส่งเสริมสุขภาพตำบล":{"count":59}},"biergarten":{"Biergarten":{"count":86}},"theatre":{"Teatro Municipal":{"count":75},"Freilichtbühne":{"count":67},"Дом культуры":{"count":51},"Amphitheatre":{"count":77},"Anfiteatro":{"count":74},"Amphitheater":{"count":85},"Amfiteatr":{"count":79}},"bar":{"Bar Sport":{"count":81},"Bar Centrale":{"count":115},"Бар":{"count":53},"Beach Bar":{"count":55}},"car_wash":{"Spălătorie Auto":{"count":61},"Автомойка":{"count":1105},"Shell":{"count":150},"Statoil":{"count":58},"Мойка":{"count":106},"Car Wash":{"count":400},"Waschanlage":{"count":66},"Aral":{"count":86},"BP":{"count":61},"автомойка":{"count":60},"Intermarché":{"count":57},"Car wash":{"count":60},"Myjnia samochodowa":{"count":52},"Myjnia bezdotykowa":{"count":62},"H-E-B Car Wash":{"count":65}},"clinic":{"Детская поликлиника":{"count":130},"Centro de Salud":{"count":127},"Polyclinique":{"count":90},"Поликлиника":{"count":147},"Posto de Saúde":{"count":64},"Clinic":{"count":83},"Health Sub Center":{"count":71},"ФАП":{"count":138},"Aid Post":{"count":69}},"bicycle_rental":{"metropolradruhr":{"count":82},"Bicing":{"count":99}},"veterinary":{"Clinique vétérinaire":{"count":75},"Ветлечебница":{"count":55},"Vétérinaire":{"count":68},"Clinique Vétérinaire":{"count":106},"Ветеринарная клиника":{"count":60}},"dentist":{"Стоматология":{"count":437},"Zahnarzt":{"count":68},"Dentiste":{"count":61},"Clínica Dental":{"count":56},"Dental Clinic":{"count":55},"Dentist":{"count":85},"Aspen Dental":{"count":51},"Стоматологическая поликлиника":{"count":87},"Clinica Dental":{"count":212}},"casino":{"Casino":{"count":59}},"arts_centre":{"Дом культуры":{"count":159},"Клуб":{"count":55},"Świetlica wiejska":{"count":52}},"ice_cream":{"Grido":{"count":98}},"sauna":{"Баня":{"count":102}},"driving_school":{"Автошкола":{"count":92}},"social_facility":{"Социальный участковый":{"count":208},"Safe Haven":{"count":92}}},"shop":{"mobile_phone":{"Vodafone":{"count":827},"T-Punkt":{"count":53},"Билайн":{"count":318},"ソフトバンクショップ":{"count":463},"O2":{"count":433},"Carphone Warehouse":{"count":260},"Orange":{"count":565},"3 Store":{"count":64},"T-Mobile":{"count":477},"Sprint":{"count":269},"AT&T":{"count":380},"Verizon Wireless":{"count":453},"Verizon":{"count":94},"mobilcom debitel":{"count":56},"Евросеть":{"count":821},"Movistar":{"count":257},"Telekom Shop":{"count":80},"EE":{"count":143},"Telekom":{"count":111},"ドコモショップ":{"count":370},"Telus":{"count":51},"Claro":{"count":326},"Cricket":{"count":77},"The Phone House":{"count":120},"vodafone":{"count":59},"Bell":{"count":123},"SFR":{"count":133},"МТС":{"count":731},"Metro PCS":{"count":55},"Digicel":{"count":127},"Связной":{"count":695},"Мегафон":{"count":457},"Теле2":{"count":58},"Wind":{"count":115},"Boost Mobile":{"count":91},"Алло":{"count":52},"МегаФон":{"count":76},"MetroPCS":{"count":65},"Play":{"count":103},"Telenor":{"count":79},"au":{"count":107},"Plus":{"count":73},"Tele2":{"count":90},"auショップ":{"count":318},"Bitė":{"count":68}},"supermarket":{"Eurospar":{"count":329},"Merkur":{"count":117},"Sainsbury's":{"count":580},"Lidl":{"count":8439},"Edeka":{"count":2195},"Coles":{"count":525},"Iceland":{"count":468},"Woolworths":{"count":754},"denn's Biomarkt":{"count":119},"Billa":{"count":1507},"ALDI":{"count":5976},"The Co-operative Food":{"count":1146},"Checkers":{"count":134},"Penny":{"count":1836},"Norma":{"count":1128},"NETTO":{"count":4439},"Morrisons":{"count":447},"Kaufland":{"count":1119},"Tesco Metro":{"count":148},"Intermarché Contact":{"count":97},"Nahkauf":{"count":198},"Rewe":{"count":2766},"Aldi Süd":{"count":720},"Real":{"count":195},"Tesco Express":{"count":504},"King Soopers":{"count":96},"Kiwi":{"count":219},"Asda":{"count":234},"Pick n Pay":{"count":258},"Coop":{"count":2227},"Tengelmann":{"count":189},"Carrefour":{"count":2267},"Waitrose":{"count":288},"Spar":{"count":2996},"Hofer":{"count":461},"Tesco":{"count":1371},"M-Preis":{"count":80},"tegut":{"count":213},"Sainsbury's Local":{"count":200},"E-Center":{"count":66},"Aldi Nord":{"count":260},"Meijer":{"count":112},"Safeway":{"count":553},"No Frills":{"count":163},"Budgens":{"count":81},"Albert":{"count":245},"Jumbo":{"count":421},"Interspar":{"count":112},"Shoprite":{"count":294},"MPreis":{"count":70},"Penny Market":{"count":543},"Tesco Extra":{"count":186},"Albert Heijn":{"count":697},"IGA":{"count":488},"Super U":{"count":577},"Metro":{"count":333},"Migros":{"count":586},"Marktkauf":{"count":118},"Combi":{"count":121},"ICA":{"count":176},"PLUS":{"count":100},"Hoogvliet":{"count":60},"EMTÉ":{"count":66},"coop":{"count":80},"Dirk van den Broek":{"count":52},"Food Basics":{"count":108},"Casino":{"count":332},"Penny Markt":{"count":482},"Giant":{"count":243},"COOP Jednota":{"count":136},"ADEG":{"count":77},"ALDI SÜD":{"count":130},"Simply Market":{"count":483},"Konzum":{"count":321},"Carrefour Express":{"count":634},"Foodland":{"count":170},"Famila":{"count":152},"Hemköp":{"count":83},"Markant":{"count":91},"Volg":{"count":200},"Netto Marken-Discount":{"count":525},"Leader Price":{"count":417},"Treff 3000":{"count":120},"Kaiser's":{"count":231},"K+K":{"count":108},"Unimarkt":{"count":97},"Meny":{"count":79},"U Express":{"count":88},"Carrefour City":{"count":268},"Bim":{"count":468},"real,-":{"count":78},"Countdown":{"count":130},"Sobeys":{"count":158},"Cargills Food City":{"count":71},"S-Market":{"count":110},"Denner":{"count":376},"Zielpunkt":{"count":76},"NP":{"count":178},"Franprix":{"count":371},"Monoprix":{"count":271},"Landi":{"count":51},"Diska":{"count":66},"PENNY":{"count":86},"Giant Eagle":{"count":118},"NORMA":{"count":133},"NP-Markt":{"count":77},"Coop Extra":{"count":72},"AD Delhaize":{"count":75},"Grocery Outlet":{"count":79},"Auchan":{"count":215},"Mercadona":{"count":1050},"Consum":{"count":169},"Pam":{"count":73},"sky":{"count":118},"Şok":{"count":114},"Despar":{"count":194},"Eroski":{"count":269},"Costcutter":{"count":88},"SuperValu":{"count":73},"Dia":{"count":1198},"Rema 1000":{"count":437},"Bunnpris":{"count":69},"Konsum":{"count":140},"Profi":{"count":176},"Colruyt":{"count":203},"The Co-operative":{"count":67},"Rimi":{"count":112},"Delhaize":{"count":224},"CBA":{"count":241},"Real Canadian Superstore":{"count":59},"Mercator":{"count":155},"Smith's":{"count":53},"Walmart":{"count":999},"Kroger":{"count":550},"Intermarché":{"count":1559},"Albertsons":{"count":304},"Trader Joe's":{"count":324},"Feneberg":{"count":64},"Kvickly":{"count":54},"Makro":{"count":188},"Лента":{"count":104},"Nah & Frisch":{"count":100},"ALDI Nord":{"count":83},"Maxi":{"count":154},"Ашан":{"count":65},"CRAI":{"count":56},"ICA Supermarket":{"count":83},"Fakta":{"count":274},"Ekom":{"count":61},"Магнит":{"count":3327},"nahkauf":{"count":103},"Caprabo":{"count":129},"Famiglia Cooperativa":{"count":84},"Народная 7Я семьЯ":{"count":194},"Carrefour Contact":{"count":185},"Авоська":{"count":55},"Maxima XX":{"count":60},"Petit Casino":{"count":142},"Wasgau":{"count":55},"Match":{"count":133},"Pingo Doce":{"count":281},"Lider":{"count":69},"Unimarc":{"count":217},"Santa Isabel":{"count":155},"Седьмой континент":{"count":87},"Carrefour express":{"count":70},"HIT":{"count":60},"Пятёрочка":{"count":2392},"Conad":{"count":449},"Фуршет":{"count":82},"Willys":{"count":89},"Farmfoods":{"count":114},"Фора":{"count":126},"Dunnes Stores":{"count":74},"Сільпо":{"count":196},"マルエツ":{"count":87},"Alnatura":{"count":77},"Piggly Wiggly":{"count":87},"Prix":{"count":51},"Crai":{"count":99},"Biocoop":{"count":105},"REWE City":{"count":60},"El Árbol":{"count":103},"E. Leclerc":{"count":55},"Super Brugsen":{"count":69},"Дикси":{"count":1323},"Whole Foods Market":{"count":328,"tags":{"shop":"supermarket"}},"G20":{"count":65},"Eroski Center":{"count":63},"Publix":{"count":568},"Conad City":{"count":70},"Перекресток":{"count":409},"Føtex":{"count":67},"イトーヨーカドー":{"count":64},"Sprouts Farmers Market":{"count":55},"Ralphs":{"count":75},"Mila":{"count":73},"Biedronka":{"count":2155},"Proxi":{"count":55},"Eurospin":{"count":273},"Семья":{"count":76},"Виват":{"count":60},"Froiz":{"count":72},"Gadis":{"count":107},"Евроопт":{"count":168},"Квартал":{"count":74},"Esselunga":{"count":105},"SuperBrugsen":{"count":72},"Reliance Fresh":{"count":80},"Winn-Dixie":{"count":67},"Coop Jednota":{"count":97},"Irma":{"count":70},"Londis":{"count":54},"Mega Image":{"count":88},"Centre Commercial E. Leclerc":{"count":486},"西友":{"count":124},"A101":{"count":193},"Game":{"count":55},"Coop Konsum":{"count":97},"Alimerka":{"count":94},"Piotr i Paweł":{"count":98},"A&O":{"count":61},"Coviran":{"count":87},"Żabka":{"count":61},"Maxima":{"count":106},"ΑΒ Βασιλόπουλος":{"count":62},"Stokrotka":{"count":197},"Карусель":{"count":66},"Utile":{"count":52},"CONAD":{"count":64},"Winn Dixie":{"count":76},"Vival":{"count":67},"Μασούτης":{"count":64},"Mini Market":{"count":115},"イオン":{"count":84},"Chedraui":{"count":60},"Family Dollar":{"count":59},"Walmart Neighborhood Market":{"count":112},"Delikatesy Centrum":{"count":158},"Géant Casino":{"count":63},"Ekono":{"count":59},"ASDA":{"count":220},"Intermarche":{"count":117},"Stop & Shop":{"count":118},"Maxima X":{"count":147},"Tottus":{"count":58},"Food Lion":{"count":388},"Społem":{"count":99},"Harris Teeter":{"count":140},"Sam's Club":{"count":259},"Continente":{"count":96},"Foodworks":{"count":78},"Centra":{"count":60},"Maxi Dia":{"count":52},"H-E-B":{"count":271},"Price Chopper":{"count":123},"Soriana":{"count":148},"Атак":{"count":80},"Puregold":{"count":58},"Полушка":{"count":198},"Jewel-Osco":{"count":53},"Condis":{"count":103},"Big C":{"count":53},"Sigma":{"count":95},"Верный":{"count":160},"いなげや":{"count":57},"АТБ":{"count":499},"Bodega Aurrera":{"count":167},"Fresh Market":{"count":75},"Виктория":{"count":64},"Азбука Вкуса":{"count":52},"QFC":{"count":55},"Vea":{"count":62},"Minipreço":{"count":204},"Lewiatan":{"count":208},"Sisa":{"count":51},"Монетка":{"count":291},"Магнолия":{"count":111},"POLOmarket":{"count":186},"Palí":{"count":64},"Costco":{"count":264},"Tesco Lotus":{"count":90},"Lupa":{"count":69},"Hy-Vee":{"count":110},"Копейка":{"count":54},"Disco":{"count":68},"Pão de Açúcar":{"count":59},"Save-A-Lot":{"count":79,"tags":{"shop":"supermarket"}},"Walmart Supercenter":{"count":511},"Comercial Mexicana":{"count":53},"Plodine":{"count":61},"Grand Frais":{"count":52},"Hannaford":{"count":87},"Fred Meyer":{"count":76},"Мария-Ра":{"count":118},"マックスバリュ":{"count":109},"Wegmans":{"count":88},"Dia %":{"count":136},"Dollar General":{"count":92},"Cub Foods":{"count":51},"Универсам":{"count":84},"Extra":{"count":126},"Магазин":{"count":130},"ライフ":{"count":117},"Picard":{"count":93},"Гроздь":{"count":52},"Супермаркет":{"count":52},"Atacadão":{"count":63},"New World":{"count":86},"Ahorramás":{"count":56},"Eko":{"count":64},"Oxxo":{"count":112},"業務スーパー":{"count":129},"Despensa Familiar":{"count":68},"Красный Яр":{"count":60},"全聯福利中心":{"count":157},"Plaza Vea":{"count":53},"Командор":{"count":66},"Таврія-В":{"count":56},"まいばすけっと":{"count":108},"Norfa XL":{"count":63},"Indomaret":{"count":123},"Радеж":{"count":58},"Mercado de Abastos":{"count":52},"Dino":{"count":182},"Покупочка":{"count":51},"Хүнсний дэлгүүр":{"count":64},"E. Leclerc Drive":{"count":55},"Leclerc Drive":{"count":127},"Alfamart":{"count":76},"全聯":{"count":62}},"sports":{"Sports Direct":{"count":160},"Decathlon":{"count":388},"Intersport":{"count":614},"Спорттовары":{"count":60},"Nike":{"count":57},"Sports Authority":{"count":147},"Спортмастер":{"count":165},"Hervis":{"count":55},"Sport 2000":{"count":147},"Big 5 Sporting Goods":{"count":68},"Adidas":{"count":90},"Dick's Sporting Goods":{"count":170}},"department_store":{"Big W":{"count":114},"Canadian Tire":{"count":150},"Karstadt":{"count":64},"Walmart":{"count":802},"Kmart":{"count":359},"El Corte Inglés":{"count":60},"Target":{"count":947},"Big Lots":{"count":86},"The Warehouse":{"count":56},"Galeria Kaufhof":{"count":61},"Dollar General":{"count":53},"Debenhams":{"count":110},"Marks & Spencer":{"count":115},"Argos":{"count":71},"Woolworth":{"count":112},"Универмаг":{"count":139},"Sears":{"count":384},"Walmart Supercenter":{"count":195},"BHS":{"count":81},"Kohl's":{"count":302},"Bed Bath & Beyond":{"count":58},"Dillard's":{"count":60},"Macy's":{"count":243},"JCPenney":{"count":214},"Dollar Tree":{"count":59},"HEMA":{"count":157},"Family Dollar":{"count":65},"Sam's Club":{"count":95},"Магнит":{"count":87}},"convenience":{"Shell":{"count":412},"Statoil":{"count":78},"Spar":{"count":1340},"Tesco Express":{"count":605},"Sainsbury's Local":{"count":192},"Aral":{"count":84},"One Stop":{"count":233},"The Co-operative Food":{"count":318},"Londis":{"count":453},"7-Eleven":{"count":8603},"Coop":{"count":1110},"Sale":{"count":86},"Sheetz":{"count":111},"Costcutter":{"count":379},"Konzum":{"count":219},"Siwa":{"count":222},"Esso":{"count":120},"COOP Jednota":{"count":324},"Mac's":{"count":254},"Alepa":{"count":68},"Hasty Market":{"count":84},"K-Market":{"count":64},"On the Run":{"count":106},"CBA":{"count":291},"Valintatalo":{"count":55},"Alimentación":{"count":88},"Casino":{"count":89},"Franprix":{"count":85},"Circle K":{"count":603},"セブンイレブン":{"count":6433,"tags":{"name:en":"7-Eleven"}},"ローソン":{"count":3335,"tags":{"name:en":"LAWSON"}},"BP":{"count":238},"Tesco":{"count":59},"OK":{"count":72},"Migrolino":{"count":66},"Petit Casino":{"count":285},"Volg":{"count":147},"Total":{"count":51},"Coop Pronto":{"count":53},"Mace":{"count":142},"Mini Market":{"count":874},"Kiosk":{"count":455},"Nisa Local":{"count":114},"Продукты":{"count":7552},"Mini Stop":{"count":362},"LAWSON":{"count":265},"デイリーヤマザキ":{"count":314},"Biedronka":{"count":96},"Надежда":{"count":94},"Mobil":{"count":78},"Nisa":{"count":67},"Premier":{"count":224},"ABC":{"count":655},"КазМунайГаз":{"count":120},"McColl's":{"count":159},"Carrefour Express":{"count":178},"ミニストップ":{"count":631,"tags":{"name:en":"MINISTOP"}},"サンクス":{"count":893,"tags":{"name:en":"sunkus"}},"スリーエフ":{"count":221},"8 à Huit":{"count":76},"Żabka":{"count":1199},"Almacen":{"count":375},"Mercator":{"count":109},"Proxi":{"count":199},"萊爾富":{"count":298},"全家便利商店":{"count":524},"Vival":{"count":309},"FamilyMart":{"count":742},"ファミリーマート":{"count":3307,"tags":{"name:en":"FamilyMart"}},"Магазин":{"count":1407},"Carrefour City":{"count":88},"Casey's General Store":{"count":174},"セブンイレブン(Seven-Eleven)":{"count":246},"Jednota":{"count":67},"Гастроном":{"count":321},"Centra":{"count":130},"Евроопт":{"count":104},"Couche-Tard":{"count":71},"サークルK":{"count":976,"tags":{"name:en":"Circle K"}},"7 eleven":{"count":71},"Mlin i pekare":{"count":59},"Sunkus":{"count":54},"Wawa":{"count":228},"Lifestyle Express":{"count":75},"Chevron":{"count":89},"ampm":{"count":132},"General Store":{"count":75},"Tchibo":{"count":65},"Lewiatan":{"count":397},"Coles Express":{"count":170},"Večerka":{"count":110},"Potraviny":{"count":393},"Rite Aid":{"count":59},"Select":{"count":111},"Ассорти":{"count":85},"Копейка":{"count":55},"Универсам":{"count":118},"Берёзка":{"count":170},"Русь":{"count":52},"Społem":{"count":161},"Shop":{"count":473},"Cumberland Farms":{"count":96},"Fresh Market":{"count":75},"Мария-Ра":{"count":189},"Пятёрочка":{"count":671},"Woolworths Petrol":{"count":73},"Aibė":{"count":71},"Coop Jednota":{"count":120},"Магнит":{"count":1196},"Tesco Lotus Express":{"count":89},"Смак":{"count":104},"Виктория":{"count":122},"Plaid Pantry":{"count":60},"M&S Simply Food":{"count":56},"Sklep spożywczy":{"count":223},"Groszek":{"count":187},"Продукти":{"count":595},"Martin's":{"count":51},"Bodega":{"count":55},"Татьяна":{"count":55},"24 часа":{"count":76},"Минимаркет":{"count":279},"Oxxo":{"count":1566},"abc":{"count":237},"Family Dollar":{"count":60},"Stewart's":{"count":253},"Любимый":{"count":67},"Shop & Go":{"count":72},"Hruška":{"count":76},"ローソンストア100":{"count":252},"CU":{"count":57},"Гурман":{"count":57},"Sunoco":{"count":54},"Радуга":{"count":131},"Delikatesy Centrum":{"count":142},"Фортуна":{"count":80},"Магнолия":{"count":79},"Magazin Mixt":{"count":98},"Kum & Go":{"count":102},"Magazin Alimentar":{"count":60},"Маяк":{"count":58},"Prehrana":{"count":87},"Picard":{"count":95},"Epicerie":{"count":398},"Эконом":{"count":60},"Four Square":{"count":84},"Визит":{"count":84},"Nasz Sklep":{"count":64},"Апельсин":{"count":53},"Авоська":{"count":92},"Dollar General":{"count":397},"Studenac":{"count":107},"Magazin":{"count":61},"Central Convenience Store":{"count":66},"セイコーマート":{"count":258},"Mini Mart":{"count":62},"Mini ABC":{"count":66},"Holiday":{"count":65},"Тройка":{"count":56},"продукты":{"count":139},"Теремок":{"count":91},"Alimentari":{"count":72},"Кулинария":{"count":105},"Агрокомплекс":{"count":51},"Speedway":{"count":85},"全家":{"count":414},"Citgo":{"count":73},"GS25":{"count":89},"Extra":{"count":63},"Kwik Trip":{"count":116},"Мечта":{"count":81},"Кировский":{"count":78},"United Dairy Farmers":{"count":52},"Freshmarket":{"count":87},"Mini market":{"count":66},"Перекресток":{"count":118},"Delikatesy":{"count":127},"Odido":{"count":74},"Corner Store":{"count":74},"Монетка":{"count":118},"Ромашка":{"count":63},"Alimentation Générale":{"count":73},"ポプラ":{"count":95},"BP Shop":{"count":57},"Верный":{"count":52},"Дикси":{"count":246},"Продуктовый":{"count":227},"Almacén":{"count":73},"Весна":{"count":78},"Центральный":{"count":58},"Мираж":{"count":51},"Mini Market Non-Stop":{"count":124},"ココストア":{"count":53},"Светлана":{"count":72},"Копеечка":{"count":83},"QuikTrip":{"count":133},"Меркурий":{"count":63},"Food Mart":{"count":384},"Royal Farms":{"count":75},"Vegyesbolt":{"count":326},"Елена":{"count":51},"Продукты 24":{"count":61},"Kisbolt":{"count":98},"Parduotuvė":{"count":67},"Reál":{"count":52},"AMPM":{"count":114},"ヤマザキショップ":{"count":86},"Продуктовый магазин":{"count":611},"Alfamart":{"count":228},"odido":{"count":53},"Indomaret":{"count":275},"магазин":{"count":258},"Alfa Mart":{"count":55},"Fresh":{"count":57},"Boutique":{"count":163},"მარკეტი (Market)":{"count":140},"Magazin alimentar":{"count":52},"OK便利商店":{"count":65},"Magazin Non-Stop":{"count":64},"Sari-sari Store":{"count":65},"Stores":{"count":66},"Małpka Express":{"count":56},"Baqala":{"count":61}},"chemist":{"Budnikowsky":{"count":102},"dm":{"count":1667},"Müller":{"count":321},"Schlecker":{"count":97},"Etos":{"count":480},"Bipa":{"count":398},"Rossmann":{"count":2241},"Teta":{"count":82},"Kruidvat":{"count":338},"Walgreens":{"count":57},"Рубль Бум":{"count":64},"Watsons":{"count":87},"Улыбка радуги":{"count":96},"7 Дней":{"count":52},"Бытовая химия":{"count":67},"丁丁藥局":{"count":72},"Магнит Косметик":{"count":53},"屈臣氏":{"count":56}},"car_repair":{"Peugeot":{"count":133},"Kwik Fit":{"count":215},"A.T.U":{"count":460},"Midas":{"count":387},"Feu Vert":{"count":152},"Norauto":{"count":220},"Шиномонтаж":{"count":2787},"Speedy":{"count":175},"Автозапчасти":{"count":209},"Renault":{"count":257},"Pit Stop":{"count":72},"Garage Renault":{"count":57},"Jiffy Lube":{"count":363},"СТО":{"count":820},"Автосервис":{"count":668},"O'Reilly Auto Parts":{"count":194},"Pep Boys":{"count":68},"Carglass":{"count":181},"ÖAMTC":{"count":53},"шиномонтаж":{"count":136},"Citroen":{"count":93},"Euromaster":{"count":133},"NAPA Auto Parts":{"count":83},"Mr. Lube":{"count":52},"Valvoline Instant Oil Change":{"count":74},"Wulkanizacja":{"count":64},"Firestone":{"count":176},"Goodyear":{"count":75},"Roady":{"count":75},"Mekonomen":{"count":51},"Автомастерская":{"count":74},"Advance Auto Parts":{"count":238},"Замена масла":{"count":74},"Gomeria":{"count":110},"Firestone Complete Auto Care":{"count":52},"Автосервис+шиномонтаж":{"count":55},"Gomería":{"count":65}},"bakery":{"Red Ribbon":{"count":53},"Kamps":{"count":263},"Lila Bäcker":{"count":83},"Bäckerei Schmidt":{"count":95},"Anker":{"count":83},"Schäfer":{"count":59},"Schäfer's":{"count":80},"Sternenbäck":{"count":74},"Hofpfisterei":{"count":125},"Bakers Delight":{"count":62},"Greggs":{"count":481},"Panaderia":{"count":367},"Ströck":{"count":62},"Oebel":{"count":65},"Sehne":{"count":76},"Boulangerie":{"count":454},"Stadtbäckerei":{"count":60},"Banette":{"count":89},"Steinecke":{"count":234},"Goldilocks":{"count":106},"Backwerk":{"count":130},"Dat Backhus":{"count":77},"K&U":{"count":98},"Ihle":{"count":100},"Der Beck":{"count":102},"Ditsch":{"count":60},"Bäckerei Fuchs":{"count":59},"Bakker Bart":{"count":80},"Bäckerei Müller":{"count":66},"Backshop":{"count":51},"Wiener Feinbäcker":{"count":58},"Bäckerei Grimminger":{"count":52},"Goeken backen":{"count":53},"von Allwörden":{"count":52},"Paul":{"count":150},"Musmanni":{"count":73},"Хлеб":{"count":136},"Fornetti":{"count":110},"Le Fournil":{"count":51},"Булочная":{"count":56},"boulangerie":{"count":65},"Пекарня":{"count":187},"Mlinar":{"count":71},"Свежий хлеб":{"count":59},"Marie Blachère":{"count":53},"Cooplands":{"count":57},"Кулиничи":{"count":101}},"furniture":{"IKEA":{"count":215},"Dänisches Bettenlager":{"count":424},"Jysk":{"count":209},"Roller":{"count":89},"Conforama":{"count":141},"The Brick":{"count":51},"Мебель":{"count":327},"Casa":{"count":57},"JYSK":{"count":97},"But":{"count":115},"Pier 1 Imports":{"count":81},"ニトリ":{"count":68},"Black Red White":{"count":61}},"doityourself":{"Hornbach":{"count":129},"B&Q":{"count":235},"Hubo":{"count":93},"Mr Bricolage":{"count":133},"Gamma":{"count":122},"OBI":{"count":498},"Lowe's":{"count":1228},"Wickes":{"count":148},"Hagebau":{"count":53},"Castorama":{"count":161},"Rona":{"count":69},"Toom Baumarkt":{"count":95},"Homebase":{"count":209},"Lagerhaus":{"count":108},"Bauhaus":{"count":210},"Leroy Merlin":{"count":255},"Hellweg":{"count":65},"Brico":{"count":125},"Bricomarché":{"count":381},"Hagebaumarkt":{"count":128},"Biltema":{"count":52},"BayWa":{"count":53},"Home Depot":{"count":1250},"Menards":{"count":103},"Weldom":{"count":101},"Toom":{"count":63},"Praktiker":{"count":62},"Canadian Tire":{"count":125},"Easy":{"count":51},"Sonderpreis Baumarkt":{"count":52},"Ace Hardware":{"count":246},"Screwfix":{"count":62},"Karwei":{"count":59},"Mr. Bricolage":{"count":56},"Строитель":{"count":57},"Home Hardware":{"count":144},"Мастер":{"count":53},"Хозтовары":{"count":128},"コメリ":{"count":108},"Bunnings Warehouse":{"count":167},"Bricorama":{"count":103},"Стройматериалы":{"count":401},"コーナン":{"count":67},"Point P":{"count":102}},"stationery":{"Staples":{"count":580},"McPaper":{"count":136},"Ryman":{"count":74},"Pagro":{"count":64},"Officeworks":{"count":59},"Office Depot":{"count":295},"Libro":{"count":64},"Office Max":{"count":138},"Канцтовары":{"count":110}},"car":{"Skoda":{"count":122},"BMW":{"count":189},"KIA":{"count":74},"Citroen":{"count":395},"Renault":{"count":560},"Mercedes-Benz":{"count":335},"Volvo":{"count":146},"Ford":{"count":382},"Kia Motors":{"count":97},"Mazda":{"count":164},"Mitsubishi":{"count":120},"Fiat":{"count":130},"Автозапчасти":{"count":243},"Opel":{"count":206},"Volkswagen":{"count":318},"Toyota":{"count":467},"Nissan":{"count":330},"Seat":{"count":84},"Porsche":{"count":72},"Suzuki":{"count":127},"Honda":{"count":271},"Peugeot":{"count":461},"Lexus":{"count":66},"KIA Motors":{"count":54},"Hyundai":{"count":330},"Kia":{"count":108},"Audi":{"count":158},"Автомагазин":{"count":92},"Subaru":{"count":92},"Chevrolet":{"count":178}},"kiosk":{"Shell":{"count":119},"R-kioski":{"count":147},"Aral":{"count":73},"Kiosk":{"count":774},"R-Kioski":{"count":198},"Narvesen":{"count":177},"Tabak Trafik":{"count":65},"Trafik":{"count":235},"Pressbyrån":{"count":104},"Trinkhalle":{"count":96},"Relay":{"count":54},"Kiosco":{"count":164},"Edicola":{"count":68},"Пресса":{"count":130},"Trafika":{"count":64},"Роспечать":{"count":218},"Ruch":{"count":146},"Продукты":{"count":216},"Tisak":{"count":218},"Киоск":{"count":137},"Kolporter":{"count":70},"Мороженое":{"count":55},"Kiosko":{"count":63},"Kios":{"count":191},"Lietuvos spauda":{"count":59},"Союзпечать":{"count":87},"Pulpería":{"count":59},"მარკეტი (Market)":{"count":138},"KIOS":{"count":84},"Warung":{"count":68}},"electronics":{"Maplin":{"count":102},"Media Markt":{"count":378},"Saturn":{"count":147},"Currys":{"count":116},"Euronics":{"count":203},"Rogers":{"count":59},"Radio Shack":{"count":461},"Apple Store":{"count":56},"Best Buy":{"count":609},"Elgiganten":{"count":52},"Expert":{"count":173},"Эльдорадо":{"count":265},"DNS":{"count":74},"Hartlauer":{"count":52},"Darty":{"count":130},"Interdiscount":{"count":52},"М.Видео":{"count":106},"Bell":{"count":76},"Samsung":{"count":99},"Фокстрот":{"count":70},"ケーズデンキ":{"count":111},"The Source":{"count":67},"Boulanger":{"count":65},"Batteries Plus Bulbs":{"count":67},"Эксперт":{"count":61},"Media Expert":{"count":119},"ヤマダ電機":{"count":129},"エディオン":{"count":62},"Neonet":{"count":73},"La Curacao":{"count":63}},"variety_store":{"Tedi":{"count":575},"Action":{"count":85},"Dollar Tree":{"count":487},"Dollarama":{"count":295},"ダイソー":{"count":152},"Fix Price":{"count":92},"Family Dollar":{"count":405},"GiFi":{"count":92},"Dollar General":{"count":233},"Big Lots":{"count":54},"Poundland":{"count":132},"Variety Store":{"count":143}},"alcohol":{"Alko":{"count":169},"Beer Store":{"count":54},"LCBO":{"count":371},"The Beer Store":{"count":213},"Systembolaget":{"count":259},"Норман":{"count":120},"Ароматный мир":{"count":130},"Bargain Booze":{"count":108},"BWS":{"count":124},"Vinmonopolet":{"count":60},"Botilleria":{"count":87},"SAQ":{"count":118},"Gall & Gall":{"count":505},"Liquorland":{"count":86},"Mitra":{"count":60},"Nicolas":{"count":180},"Живое пиво":{"count":158},"Dan Murphy's":{"count":54},"Красное и белое":{"count":88},"BC Liquor Store":{"count":52},"Красное & Белое":{"count":168},"Liquor Store":{"count":54},"Бристоль":{"count":152},"Красное и Белое":{"count":57},"Разливное пиво":{"count":96},"Красное&Белое":{"count":78},"Пиво":{"count":53}},"bicycle":{"Halfords":{"count":156},"サイクルベースあさひ":{"count":64},"Веломарка":{"count":52}},"clothes":{"KiK":{"count":1684},"H&M":{"count":1182},"C&A":{"count":764},"Second Hand":{"count":129},"Urban Outfitters":{"count":107},"Vögele":{"count":182},"Zeeman":{"count":272},"Takko":{"count":761},"Adler":{"count":75},"Charles Vögele":{"count":114},"Nike":{"count":80},"Peek & Cloppenburg":{"count":68},"OVS":{"count":59},"Zara":{"count":413},"Vero Moda":{"count":187},"Ernsting's family":{"count":631},"Winners":{"count":93},"NKD":{"count":690},"GAP":{"count":63},"River Island":{"count":105},"Next":{"count":262},"Monsoon":{"count":72},"Gap":{"count":147},"Adidas":{"count":176},"Gerry Weber":{"count":183},"Woolworths":{"count":119},"Ulla Popken":{"count":105},"Mr Price":{"count":93},"Jet":{"count":65},"Pep":{"count":134},"Edgars":{"count":113},"Ackermans":{"count":93},"House":{"count":53},"Truworths":{"count":66},"Reserved":{"count":99},"Ross":{"count":215},"Hugo Boss":{"count":82},"Burton":{"count":78},"Dorothy Perkins":{"count":77},"s.Oliver":{"count":89},"Cecil":{"count":103},"Lane Bryant":{"count":66},"Dress Barn":{"count":97},"Old Navy":{"count":303},"Dressmann":{"count":56},"Jack & Jones":{"count":142},"Hunkemöller":{"count":129},"Pimkie":{"count":141},"Esprit":{"count":359},"Primark":{"count":150},"Bonita":{"count":277},"Mexx":{"count":76},"Matalan":{"count":127},"Tally Weijl":{"count":118},"Mango":{"count":277},"TK Maxx":{"count":157},"Springfield":{"count":69},"Sisley":{"count":68},"Benetton":{"count":164},"AWG":{"count":83},"Tommy Hilfiger":{"count":149},"Wibra":{"count":59},"Fat Face":{"count":72},"Reitmans":{"count":51},"Lindex":{"count":99},"New Look":{"count":230},"KappAhl":{"count":64},"New Yorker":{"count":301},"Etam":{"count":91},"Kiabi":{"count":234},"Palmers":{"count":68},"Jack Wolfskin":{"count":69},"American Apparel":{"count":86},"Desigual":{"count":135},"Cubus":{"count":54},"Gant":{"count":65},"Tom Tailor":{"count":101},"Topshop":{"count":58},"Bershka":{"count":117},"Burlington Coat Factory":{"count":76},"Jules":{"count":95},"Guess":{"count":100},"Jennyfer":{"count":60},"Pepco":{"count":88},"Orsay":{"count":139},"Tezenis":{"count":64},"Forever 21":{"count":84},"Mark's":{"count":55},"Triumph":{"count":100},"Timberland":{"count":66},"Superdry":{"count":62},"AOKI":{"count":89},"Calzedonia":{"count":186},"Intimissimi":{"count":119},"Orchestra":{"count":79},"United Colors of Benetton":{"count":159},"Goodwill":{"count":56},"洋服の青山":{"count":199},"Levi's":{"count":152},"Petit Bateau":{"count":55},"Diesel":{"count":66},"American Eagle Outfitters":{"count":62},"Celio":{"count":140},"Camaïeu":{"count":98},"Puma":{"count":55},"Lacoste":{"count":156},"WE":{"count":62},"Men's Wearhouse":{"count":112},"Sergent Major":{"count":63},"Jeans Fritz":{"count":92},"Ross Dress for Less":{"count":52},"Promod":{"count":159},"Street One":{"count":129},"TJ Maxx":{"count":171},"ユニクロ":{"count":168},"Engbers":{"count":62},"Only":{"count":62},"Marc O'Polo":{"count":61},"Banana Republic":{"count":102},"Одежда":{"count":124},"Marshalls":{"count":161},"La Halle":{"count":113},"Peacocks":{"count":144},"Camaieu":{"count":68},"Justice":{"count":59},"Massimo Dutti":{"count":76},"Cache Cache":{"count":53},"Женская одежда":{"count":51},"Victoria's Secret":{"count":90},"Спецодежда":{"count":65},"西松屋":{"count":84},"Calvin Klein":{"count":56},"Stradivarius":{"count":66},"Stefanel":{"count":51},"Gina Laura":{"count":57},"Chico's":{"count":74},"Caroll":{"count":61},"しまむら":{"count":161},"Gémo":{"count":71},"ワークマン":{"count":51},"Mim":{"count":52},"Cropp":{"count":52},"Toko Pakaian":{"count":72}},"bookmaker":{"Paddy Power":{"count":102},"Ladbrokes":{"count":497},"Betfred":{"count":229},"William Hill":{"count":518},"Coral":{"count":352}},"video_games":{"GameStop":{"count":372},"Game Stop":{"count":80},"EB Games":{"count":86},"Micromania":{"count":67},"Gamestop":{"count":56},"Game":{"count":53}},"beverages":{"REWE Getränkemarkt":{"count":131},"Getränke Hoffmann":{"count":164},"Orterer Getränkemarkt":{"count":65},"Rewe Getränkemarkt":{"count":110},"Getränkemarkt":{"count":104},"Fristo":{"count":85},"Trinkgut":{"count":58},"Dursty":{"count":71},"Getränkeland":{"count":71},"Edeka Getränkemarkt":{"count":62},"trinkgut":{"count":52}},"pet":{"Fressnapf":{"count":555},"PetSmart":{"count":398},"Pet Valu":{"count":84},"Das Futterhaus":{"count":128},"Pets at Home":{"count":133},"Petco":{"count":281},"Зоотовары":{"count":63}},"butcher":{"Boucherie":{"count":103},"Carniceria":{"count":69},"Мясо":{"count":131},"Великолукский мясокомбинат":{"count":160},"Мясная лавка":{"count":165},"Macelleria":{"count":68},"Ариант":{"count":69},"Свежее мясо":{"count":82}},"tobacco":{"Estanco":{"count":76},"Tabacchi":{"count":53},"Табак":{"count":58},"Nemzeti Dohánybolt":{"count":386},"Nemzeti dohánybolt":{"count":134}},"laundry":{"Laundrette":{"count":52},"Coin Laundry":{"count":71},"Laverie":{"count":96},"Laundromat":{"count":122},"Lavanderia":{"count":76},"Laundry":{"count":84}},"optician":{"Boots Opticians":{"count":68},"Fielmann":{"count":375},"Pearle":{"count":120},"Apollo":{"count":377},"Hakim Optical":{"count":62},"メガネスーパー":{"count":51},"Vision Express":{"count":146},"Générale d'Optique":{"count":66},"Optic 2000":{"count":225},"Alain Afflelou":{"count":153},"Specsavers":{"count":287},"Krys":{"count":144},"Optical Center":{"count":90},"Atol":{"count":101},"Les Opticiens Mutualistes":{"count":76},"Hans Anders":{"count":63},"Optika":{"count":51},"眼鏡市場":{"count":176},"แว่นท็อปเจริญ":{"count":57}},"hardware":{"Lowe's":{"count":81},"1000 мелочей":{"count":87},"Стройматериалы":{"count":87},"Home Hardware":{"count":67},"Хозтовары":{"count":336},"Ferretería":{"count":78},"Hardware":{"count":63},"Quincaillerie":{"count":66},"Сантехника":{"count":52},"Ferreteria":{"count":95}},"shoes":{"Deichmann":{"count":1083},"Reno":{"count":231},"Payless ShoeSource":{"count":91},"Ecco":{"count":131},"Clarks":{"count":221},"La Halle aux Chaussures":{"count":120},"東京靴流通センター":{"count":56},"Brantano":{"count":130},"Tamaris":{"count":73},"Geox":{"count":113},"Salamander":{"count":88},"Payless Shoe Source":{"count":255},"Famous Footwear":{"count":132},"Quick Schuh":{"count":109},"Foot Locker":{"count":192},"Shoe Zone":{"count":135},"Siemes Schuhcenter":{"count":62},"Юничел":{"count":54},"Ремонт обуви":{"count":51},"Rieker":{"count":55},"Aldo":{"count":59},"Bata":{"count":200},"Eram":{"count":73},"CCC":{"count":169},"Scapino":{"count":55},"ЦентрОбувь":{"count":73},"Chaussea":{"count":74}},"toys":{"La Grande Récré":{"count":82},"Toys R Us":{"count":358,"tags":{"shop":"toys"}},"Intertoys":{"count":108},"Bart Smit":{"count":80},"Детский мир":{"count":151},"Maxi Toys":{"count":51},"Игрушки":{"count":76},"King Jouet":{"count":78},"Dráčik":{"count":51}},"travel_agency":{"Flight Centre":{"count":130},"Thomson":{"count":106},"Thomas Cook":{"count":236},"First Reisebüro":{"count":52},"TUI":{"count":187},"The Co-operative Travel":{"count":51}},"jewelry":{"585":{"count":77},"Bijou Brigitte":{"count":143},"Christ":{"count":98},"Claire's":{"count":69},"Swarovski":{"count":174},"Pandora":{"count":177},"Адамас":{"count":54},"Kay Jewelers":{"count":59}},"carpet":{"Carpet Right":{"count":90}},"energy":{"Punto Enel":{"count":1007}},"beauty":{"Yves Rocher":{"count":708},"Nails":{"count":60},"Sally Beauty Supply":{"count":101}},"car_parts":{"Halfords":{"count":84},"Автозапчасти":{"count":576},"Автомагазин":{"count":75},"AutoZone":{"count":481},"O'Reilly Auto Parts":{"count":222},"NAPA Auto Parts":{"count":185},"Advance Auto Parts":{"count":210},"タイヤ館":{"count":76},"Repco":{"count":58},"オートバックス":{"count":65},"イエローハット":{"count":57},"Tokić":{"count":61},"repuestos automotrices":{"count":61}},"video":{"World of Video":{"count":59},"Family Video":{"count":72},"Blockbuster":{"count":90},"TSUTAYA":{"count":94},"ゲオ":{"count":58}},"charity":{"British Heart Foundation":{"count":137},"Cancer Research UK":{"count":101},"Oxfam":{"count":169},"Scope":{"count":55},"Age UK":{"count":91},"Goodwill":{"count":77},"Sue Ryder":{"count":57}},"florist":{"Monceau Fleurs":{"count":62},"Blumenladen":{"count":69},"Interflora":{"count":66},"Blume 2000":{"count":86},"Цветы":{"count":1002},"Blumen":{"count":74},"Blumen Risse":{"count":64},"상록식물원 (Sangnok Florist)":{"count":57},"Florărie":{"count":53},"Kwiaciarnia":{"count":177},"Virágbolt":{"count":56}},"tailor":{"Änderungsschneiderei":{"count":171},"Ателье":{"count":70}},"hearing_aids":{"Kind Hörgeräte":{"count":61},"Amplifon":{"count":84}},"hairdresser":{"Klier":{"count":218},"Klipp":{"count":64},"Toni & Guy":{"count":63},"Haarscharf":{"count":56},"Supercuts":{"count":276},"Hairkiller":{"count":73},"Great Clips":{"count":426},"Парикмахерская":{"count":719},"Haarmonie":{"count":74},"Top Hair":{"count":64},"Figaro":{"count":60},"Перукарня":{"count":81},"Tchip":{"count":53},"Jean Louis David":{"count":76},"The Barber Shop":{"count":81},"Стиль":{"count":74},"Sport Clips":{"count":88},"Franck Provost":{"count":120},"Hair Cuttery":{"count":92},"Cost Cutters":{"count":56},"Coiffure":{"count":61},"Шарм":{"count":60},"Салон красоты":{"count":80},"Peluquería":{"count":58}},"bed":{"Matratzen Concord":{"count":324},"Dänisches Bettenlager":{"count":129},"Mattress Firm":{"count":102}},"copyshop":{"FedEx Office Print and Ship Center":{"count":166}},"erotic":{"Orion":{"count":76}},"money_lender":{"Money Mart":{"count":79}},"cosmetics":{"The Body Shop":{"count":59},"Yves Rocher":{"count":73},"Sephora":{"count":59},"Л'Этуаль":{"count":66}},"confectionery":{"Thorntons":{"count":57},"Hussel":{"count":71},"Leonidas":{"count":75},"Fagyizó":{"count":59}},"music":{"HMV":{"count":79}},"motorcycle":{"Harley Davidson":{"count":58},"Yamaha":{"count":171},"Honda":{"count":174},"Suzuki":{"count":80}},"newsagent":{"Relay":{"count":212},"WH Smith":{"count":53},"Maison de la Presse":{"count":103},"WHSmith":{"count":72},"Печать":{"count":92},"Tabac Presse":{"count":58},"Роспечать":{"count":306},"Союзпечать":{"count":120},"Edicola":{"count":94},"Витебскоблсоюзпечать":{"count":52},"Пресса":{"count":73}},"lottery":{"Lotto":{"count":113},"ONCE":{"count":68},"Lottózó":{"count":60}},"coffee":{"Tchibo":{"count":155},"Starbucks":{"count":164,"tags":{"cuisine":"coffee_shop"}},"Café Amazon":{"count":219}},"garden_centre":{"Dehner":{"count":56},"Jardiland":{"count":114},"Gamm Vert":{"count":164},"Point Vert":{"count":55}},"tyres":{"Шиномонтаж":{"count":349},"Discount Tire":{"count":67},"Euromaster":{"count":60},"Borracharia":{"count":55},"Вулканизация":{"count":67}},"baby_goods":{"Babies R Us":{"count":67}},"craft":{"Michael's":{"count":74},"Michaels":{"count":79},"Hobby Lobby":{"count":57}},"outdoor":{"REI":{"count":66},"Mountain Warehouse":{"count":59},"Рыболов":{"count":62}},"houseware":{"Blokker":{"count":212},"Xenos":{"count":67},"Marskramer":{"count":58}},"computer":{"PC World":{"count":63},"ДНС":{"count":51},"DNS":{"count":201},"Apple Store":{"count":70}},"interior_decoration":{"Depot":{"count":66}},"second_hand":{"Goodwill":{"count":171}},"pawnbroker":{"Cash Converters":{"count":64},"Ломбард":{"count":177}},"hifi":{},"farm":{"Hofladen":{"count":51}},"dry_cleaning":{"Химчистка":{"count":55},"Диана":{"count":68},"Cleaners":{"count":80},"ホワイト急便":{"count":81}},"paint":{"Sherwin-Williams":{"count":107},"Comex":{"count":51},"Sherwin Williams":{"count":111}},"funeral_directors":{"Ритуальные услуги":{"count":114},"The Co-operative Funeralcare":{"count":53}},"gift":{"Hallmark":{"count":119},"Сувениры":{"count":60},"Card Factory":{"count":70},"Gift Shop":{"count":53}},"ticket":{"Проездные билеты":{"count":54},"Boutique Grandes Lignes":{"count":63},"Guichet Transilien":{"count":245}},"greengrocer":{"Овощи-фрукты":{"count":98},"Zöldséges":{"count":52}},"ice_cream":{"Мороженое":{"count":67}},"fabric":{"Ткани":{"count":105}},"frame":{"rumah penduduk":{"count":175}},"kitchen":{"Home Utensils":{"count":65}}},"tourism":{"hotel":{"Holiday Inn":{"count":429},"Hotel Ibis":{"count":67},"Novotel":{"count":172},"Crowne Plaza":{"count":86},"Premier Inn":{"count":362},"Holiday Inn Express":{"count":472},"Park Hotel":{"count":75},"Krone":{"count":66},"Ibis":{"count":203},"Ibis Budget":{"count":178},"Travelodge":{"count":280},"City Hotel":{"count":69},"Hotel Royal":{"count":54},"Campanile":{"count":137},"Comfort Inn":{"count":273},"Quality Inn & Suites":{"count":57},"Courtyard by Marriott":{"count":74},"Mercure":{"count":112},"Hotel Europa":{"count":74},"Formule 1":{"count":70},"Grand Hotel":{"count":83},"Hilton":{"count":56},"Courtyard Marriott":{"count":69},"Hotel Krone":{"count":56},"Ramada":{"count":103},"Best Western":{"count":231},"Quality Inn":{"count":166},"Days Inn":{"count":246},"Royal Hotel":{"count":81},"Marriott":{"count":66},"Première Classe":{"count":53},"Hotel Central":{"count":78},"Hotel Victoria":{"count":52},"東横イン":{"count":53},"Kyriad":{"count":60},"Parkhotel":{"count":65},"Extended Stay America":{"count":90},"Hotel zur Post":{"count":57},"Fairfield Inn":{"count":60},"Hotel Post":{"count":56},"Staybridge Suites":{"count":51},"Hotel Panorama":{"count":51},"Hampton Inn & Suites":{"count":84},"Hotel":{"count":270},"Sheraton":{"count":65},"Hôtel Ibis":{"count":63},"Sleep Inn":{"count":59},"Country Inn & Suites":{"count":82},"Comfort Suites":{"count":143},"Super 8":{"count":223},"Гостиница":{"count":120},"Residence Inn":{"count":83},"Homewood Suites":{"count":57},"Hilton Garden Inn":{"count":178},"Hôtel de France":{"count":53},"Hampton Inn":{"count":380},"Embassy Suites":{"count":65},"Econo Lodge":{"count":66},"Comfort Inn & Suites":{"count":59},"Motel 6":{"count":85},"La Quinta":{"count":57},"Holiday Inn Express & Suites":{"count":56},"Fairfield Inn & Suites":{"count":63}},"motel":{"Travelodge":{"count":68},"Motel":{"count":72},"Econo Lodge":{"count":81},"Super 8":{"count":162},"Days Inn":{"count":100},"Motel 6":{"count":190},"Rodeway Inn":{"count":77},"Comfort Inn":{"count":128},"Best Western":{"count":57},"Quality Inn":{"count":91},"Holiday Inn Express":{"count":52},"Budget Inn":{"count":60}},"museum":{"Heimatmuseum":{"count":336},"Stadtmuseum":{"count":84},"Краеведческий музей":{"count":210},"Музей":{"count":83},"Tájház":{"count":89}},"attraction":{"Kursächsische Postmeilensäule":{"count":54},"Lavoir":{"count":78},"Sommerrodelbahn":{"count":60},"Часовня":{"count":66},"Колесо обозрения":{"count":54},"дольмен":{"count":112},"Усадьба":{"count":52},"Кладбище еврейское":{"count":91},"Приусадебный парк":{"count":69},"Хозяйственный двор":{"count":72},"OWŚ":{"count":106}},"camp_site":{"Camping":{"count":173},"Camping Municipal":{"count":184},"Camping municipal":{"count":77},"Campsite":{"count":59}},"chalet":{"Ferienwohnung":{"count":55}},"hostel":{"Общежитие":{"count":58}},"alpine_hut":{"КОШ":{"count":77}},"caravan_site":{"мк с Освещением ":{"count":97},"жб с Освещением ":{"count":65}}},"leisure":{"playground":{"Playground":{"count":569},"Abenteuerspielplatz":{"count":149},"Kinderspielplatz":{"count":268},"Waldspielplatz":{"count":170},"Spielplatz":{"count":264},"Bolzplatz":{"count":127},"Wasserspielplatz":{"count":148},"Játszótér":{"count":114},"Parque Infantil":{"count":385},"Parque":{"count":59},"Parque infantil":{"count":79},"Aire de Jeux":{"count":78},"Plac zabaw":{"count":255},"Dětské hřiště":{"count":77},"Детская площадка":{"count":200},"playground":{"count":118},"Tot Lot":{"count":121},"Jeux Enfants":{"count":51},"Parco giochi":{"count":58},"Zona Infantil":{"count":57}},"sports_centre":{"Kieser Training":{"count":95},"Turnhalle":{"count":612},"Virgin Active":{"count":69},"Planet Fitness":{"count":104},"Sporthalle":{"count":1056},"Schulsporthalle":{"count":85},"Palestra":{"count":74},"Sportplatz":{"count":100},"Schützenhaus":{"count":77},"Fitness First":{"count":67},"LA Fitness":{"count":106},"Reithalle":{"count":104},"McFit":{"count":59},"Спортзал":{"count":94},"Mrs. Sporty":{"count":75},"Tennishalle":{"count":164},"YMCA":{"count":166},"Hallenbad":{"count":79},"Palazzetto dello Sport":{"count":114},"24 Hour Fitness":{"count":52},"Mehrzweckhalle":{"count":152},"Gold's Gym":{"count":79},"Polideportivo":{"count":200},"Curves":{"count":88},"Tennis":{"count":109},"ДЮСШ":{"count":72},"Gymnase":{"count":360},"Salle Polyvalente":{"count":59},"ФОК":{"count":81},"Anytime Fitness":{"count":126},"Piscina Municipal":{"count":54},"Gym":{"count":80},"Hala sportowa":{"count":61},"Orlik":{"count":70},"Спорткомплекс":{"count":52},"Palestra Comunale":{"count":65},"Gymnasium":{"count":55},"Gimnasio":{"count":144},"Gimnasio Municipal":{"count":75},"Polideportivo Municipal":{"count":185},"Life Time Fitness":{"count":78},"Pabellón de Deportes":{"count":82},"Pabellón Municipal de Deportes":{"count":85}},"swimming_pool":{"Piscina municipal":{"count":77},"Piscine municipale":{"count":102},"Pool":{"count":170},"Piscine":{"count":97},"Piscina Comunale":{"count":59},"Swimming Pool":{"count":88},"Бассейн":{"count":62},"Piscina Municipal":{"count":178},"Piscina":{"count":145},"Nichtschwimmerbecken":{"count":57},"Sportbecken":{"count":54},"Kinderbecken":{"count":94},"piscina":{"count":62}}},"man_made":{"windmill":{"De Hoop":{"count":57}}}},"addressFormats":[{"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"]]}],"phoneFormats":{"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","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 207 123456","gg":"+44 207 123456","im":"+44 207 123456","je":"+44 207 123456","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 12345678"},"driveLeft":{"type":"FeatureCollection","features":[{"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]]]}}]}};