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"});
2003 function mousedowned() {
2005 target = d3.event.target,
2006 dispatch = event.of(that, arguments),
2008 subject = d3.select(d3_window(that)).on(mousemove, moved).on(mouseup, ended),
2009 location0 = location(d3.mouse(that)),
2010 dragRestore = d3_event_dragSuppress(that);
2012 d3_selection_interrupt.call(that);
2013 zoomstarted(dispatch);
2017 translateTo(d3.mouse(that), location0);
2022 subject.on(mousemove, null).on(mouseup, null);
2023 dragRestore(dragged && d3.event.target === target);
2024 zoomended(dispatch);
2028 // These closures persist for as long as at least one touch is active.
2029 function touchstarted() {
2031 dispatch = event.of(that, arguments),
2032 locations0 = {}, // touchstart locations
2033 distance0 = 0, // distance² between initial touches
2034 scale0, // scale when we started touching
2035 zoomName = ".zoom-" + d3.event.changedTouches[0].identifier,
2036 touchmove = "touchmove" + zoomName,
2037 touchend = "touchend" + zoomName,
2039 subject = d3.select(that),
2040 dragRestore = d3_event_dragSuppress(that);
2043 zoomstarted(dispatch);
2045 // Workaround for Chrome issue 412723: the touchstart listener must be set
2046 // after the touchmove listener.
2047 subject.on(mousedown, null).on(touchstart, started); // prevent duplicate events
2049 // Updates locations of any touches in locations0.
2050 function relocate() {
2051 var touches = d3.touches(that);
2053 touches.forEach(function(t) {
2054 if (t.identifier in locations0) locations0[t.identifier] = location(t);
2059 // Temporarily override touchstart while gesture is active.
2060 function started() {
2062 // Listen for touchmove and touchend on the target of touchstart.
2063 var target = d3.event.target;
2064 d3.select(target).on(touchmove, moved).on(touchend, ended);
2065 targets.push(target);
2067 // Only track touches started on the same subject element.
2068 var changed = d3.event.changedTouches;
2069 for (var i = 0, n = changed.length; i < n; ++i) {
2070 locations0[changed[i].identifier] = null;
2073 var touches = relocate(),
2076 if (touches.length === 1) {
2077 if (now - touchtime < 500) { // dbltap
2079 zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1);
2080 d3_eventPreventDefault();
2083 } else if (touches.length > 1) {
2084 var p = touches[0], q = touches[1],
2085 dx = p[0] - q[0], dy = p[1] - q[1];
2086 distance0 = dx * dx + dy * dy;
2091 var touches = d3.touches(that),
2095 d3_selection_interrupt.call(that);
2097 for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
2099 if (l1 = locations0[p1.identifier]) {
2106 var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1,
2107 scale1 = distance0 && Math.sqrt(distance1 / distance0);
2108 p0 = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
2109 l0 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
2110 scaleTo(scale1 * scale0);
2114 translateTo(p0, l0);
2119 // If there are any globally-active touches remaining, remove the ended
2120 // touches from locations0.
2121 if (d3.event.touches.length) {
2122 var changed = d3.event.changedTouches;
2123 for (var i = 0, n = changed.length; i < n; ++i) {
2124 delete locations0[changed[i].identifier];
2126 // If locations0 is not empty, then relocate and continue listening for
2127 // touchmove and touchend.
2128 for (var identifier in locations0) {
2129 return void relocate(); // locations may have detached due to rotation
2132 // Otherwise, remove touchmove and touchend listeners.
2133 d3.selectAll(targets).on(zoomName, null);
2134 subject.on(mousedown, mousedowned).on(touchstart, touchstarted);
2136 zoomended(dispatch);
2140 function mousewheeled() {
2141 var dispatch = event.of(this, arguments);
2142 if (mousewheelTimer) clearTimeout(mousewheelTimer);
2143 else translate0 = location(center0 = center || d3.mouse(this)), d3_selection_interrupt.call(this), zoomstarted(dispatch);
2144 mousewheelTimer = setTimeout(function() { mousewheelTimer = null; zoomended(dispatch); }, 50);
2145 d3_eventPreventDefault();
2146 scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
2147 translateTo(center0, translate0);
2151 function dblclicked() {
2152 var p = d3.mouse(this),
2153 k = Math.log(view.k) / Math.LN2;
2155 zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1);
2158 return d3.rebind(zoom, event, "on");
2161 var d3_behavior_zoomInfinity = [0, Infinity], // default scale extent
2162 d3_behavior_zoomDelta, // initialized lazily
2163 d3_behavior_zoomWheel;
2164 function d3_functor(v) {
2165 return typeof v === "function" ? v : function() { return v; };
2168 d3.functor = d3_functor;
2170 d3.touch = function(container, touches, identifier) {
2171 if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches;
2172 if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) {
2173 if ((touch = touches[i]).identifier === identifier) {
2174 return d3_mousePoint(container, touch);
2179 var d3_timer_queueHead,
2181 d3_timer_interval, // is an interval (or frame) active?
2182 d3_timer_timeout, // is a timeout active?
2183 d3_timer_active, // active timer object
2184 d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) { setTimeout(callback, 17); };
2186 // The timer will continue to fire until callback returns true.
2187 d3.timer = function(callback, delay, then) {
2188 var n = arguments.length;
2189 if (n < 2) delay = 0;
2190 if (n < 3) then = Date.now();
2192 // Add the callback to the tail of the queue.
2193 var time = then + delay, timer = {c: callback, t: time, f: false, n: null};
2194 if (d3_timer_queueTail) d3_timer_queueTail.n = timer;
2195 else d3_timer_queueHead = timer;
2196 d3_timer_queueTail = timer;
2199 if (!d3_timer_interval) {
2200 d3_timer_timeout = clearTimeout(d3_timer_timeout);
2201 d3_timer_interval = 1;
2202 d3_timer_frame(d3_timer_step);
2206 function d3_timer_step() {
2207 var now = d3_timer_mark(),
2208 delay = d3_timer_sweep() - now;
2210 if (isFinite(delay)) {
2211 clearTimeout(d3_timer_timeout);
2212 d3_timer_timeout = setTimeout(d3_timer_step, delay);
2214 d3_timer_interval = 0;
2216 d3_timer_interval = 1;
2217 d3_timer_frame(d3_timer_step);
2221 d3.timer.flush = function() {
2226 function d3_timer_mark() {
2227 var now = Date.now();
2228 d3_timer_active = d3_timer_queueHead;
2229 while (d3_timer_active) {
2230 if (now >= d3_timer_active.t) d3_timer_active.f = d3_timer_active.c(now - d3_timer_active.t);
2231 d3_timer_active = d3_timer_active.n;
2236 // Flush after callbacks to avoid concurrent queue modification.
2237 // Returns the time of the earliest active timer, post-sweep.
2238 function d3_timer_sweep() {
2240 t1 = d3_timer_queueHead,
2244 t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n;
2246 if (t1.t < time) time = t1.t;
2250 d3_timer_queueTail = t0;
2255 d3.geo.stream = function(object, listener) {
2256 if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) {
2257 d3_geo_streamObjectType[object.type](object, listener);
2259 d3_geo_streamGeometry(object, listener);
2263 function d3_geo_streamGeometry(geometry, listener) {
2264 if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) {
2265 d3_geo_streamGeometryType[geometry.type](geometry, listener);
2269 var d3_geo_streamObjectType = {
2270 Feature: function(feature, listener) {
2271 d3_geo_streamGeometry(feature.geometry, listener);
2273 FeatureCollection: function(object, listener) {
2274 var features = object.features, i = -1, n = features.length;
2275 while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener);
2279 var d3_geo_streamGeometryType = {
2280 Sphere: function(object, listener) {
2283 Point: function(object, listener) {
2284 object = object.coordinates;
2285 listener.point(object[0], object[1], object[2]);
2287 MultiPoint: function(object, listener) {
2288 var coordinates = object.coordinates, i = -1, n = coordinates.length;
2289 while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]);
2291 LineString: function(object, listener) {
2292 d3_geo_streamLine(object.coordinates, listener, 0);
2294 MultiLineString: function(object, listener) {
2295 var coordinates = object.coordinates, i = -1, n = coordinates.length;
2296 while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0);
2298 Polygon: function(object, listener) {
2299 d3_geo_streamPolygon(object.coordinates, listener);
2301 MultiPolygon: function(object, listener) {
2302 var coordinates = object.coordinates, i = -1, n = coordinates.length;
2303 while (++i < n) d3_geo_streamPolygon(coordinates[i], listener);
2305 GeometryCollection: function(object, listener) {
2306 var geometries = object.geometries, i = -1, n = geometries.length;
2307 while (++i < n) d3_geo_streamGeometry(geometries[i], listener);
2311 function d3_geo_streamLine(coordinates, listener, closed) {
2312 var i = -1, n = coordinates.length - closed, coordinate;
2313 listener.lineStart();
2314 while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]);
2318 function d3_geo_streamPolygon(coordinates, listener) {
2319 var i = -1, n = coordinates.length;
2320 listener.polygonStart();
2321 while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1);
2322 listener.polygonEnd();
2325 d3.geo.length = function(object) {
2326 d3_geo_lengthSum = 0;
2327 d3.geo.stream(object, d3_geo_length);
2328 return d3_geo_lengthSum;
2331 var d3_geo_lengthSum;
2333 var d3_geo_length = {
2336 lineStart: d3_geo_lengthLineStart,
2338 polygonStart: d3_noop,
2342 function d3_geo_lengthLineStart() {
2343 var λ0, sinφ0, cosφ0;
2345 d3_geo_length.point = function(λ, φ) {
2346 λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ);
2347 d3_geo_length.point = nextPoint;
2350 d3_geo_length.lineEnd = function() {
2351 d3_geo_length.point = d3_geo_length.lineEnd = d3_noop;
2354 function nextPoint(λ, φ) {
2355 var sinφ = Math.sin(φ *= d3_radians),
2357 t = abs((λ *= d3_radians) - λ0),
2358 cosΔλ = Math.cos(t);
2359 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Δλ);
2360 λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ;
2363 function d3_identity(d) {
2366 function d3_true() {
2370 function d3_geo_spherical(cartesian) {
2372 Math.atan2(cartesian[1], cartesian[0]),
2373 d3_asin(cartesian[2])
2377 function d3_geo_sphericalEqual(a, b) {
2378 return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε;
2381 // General spherical polygon clipping algorithm: takes a polygon, cuts it into
2382 // visible line segments and rejoins the segments by interpolating along the
2384 function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) {
2388 segments.forEach(function(segment) {
2389 if ((n = segment.length - 1) <= 0) return;
2390 var n, p0 = segment[0], p1 = segment[n];
2392 // If the first and last points of a segment are coincident, then treat as
2394 // TODO if all rings are closed, then the winding order of the exterior
2395 // ring should be checked.
2396 if (d3_geo_sphericalEqual(p0, p1)) {
2397 listener.lineStart();
2398 for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]);
2403 var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true),
2404 b = new d3_geo_clipPolygonIntersection(p0, null, a, false);
2408 a = new d3_geo_clipPolygonIntersection(p1, segment, null, false);
2409 b = new d3_geo_clipPolygonIntersection(p1, null, a, true);
2415 d3_geo_clipPolygonLinkCircular(subject);
2416 d3_geo_clipPolygonLinkCircular(clip);
2417 if (!subject.length) return;
2419 for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) {
2420 clip[i].e = entry = !entry;
2423 var start = subject[0],
2427 // Find first unvisited intersection.
2428 var current = start,
2430 while (current.v) if ((current = current.n) === start) return;
2432 listener.lineStart();
2434 current.v = current.o.v = true;
2437 for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]);
2439 interpolate(current.x, current.n.x, 1, listener);
2441 current = current.n;
2444 points = current.p.z;
2445 for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]);
2447 interpolate(current.x, current.p.x, -1, listener);
2449 current = current.p;
2451 current = current.o;
2453 isSubject = !isSubject;
2454 } while (!current.v);
2459 function d3_geo_clipPolygonLinkCircular(array) {
2460 if (!(n = array.length)) return;
2474 function d3_geo_clipPolygonIntersection(point, points, other, entry) {
2477 this.o = other; // another intersection
2478 this.e = entry; // is an entry?
2479 this.v = false; // visited
2480 this.n = this.p = null; // next & previous
2483 function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
2484 return function(rotate, listener) {
2485 var line = clipLine(listener),
2486 rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]);
2490 lineStart: lineStart,
2492 polygonStart: function() {
2493 clip.point = pointRing;
2494 clip.lineStart = ringStart;
2495 clip.lineEnd = ringEnd;
2499 polygonEnd: function() {
2501 clip.lineStart = lineStart;
2502 clip.lineEnd = lineEnd;
2504 segments = d3.merge(segments);
2505 var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
2506 if (segments.length) {
2507 if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
2508 d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);
2509 } else if (clipStartInside) {
2510 if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
2511 listener.lineStart();
2512 interpolate(null, null, 1, listener);
2515 if (polygonStarted) listener.polygonEnd(), polygonStarted = false;
2516 segments = polygon = null;
2518 sphere: function() {
2519 listener.polygonStart();
2520 listener.lineStart();
2521 interpolate(null, null, 1, listener);
2523 listener.polygonEnd();
2527 function point(λ, φ) {
2528 var point = rotate(λ, φ);
2529 if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ);
2531 function pointLine(λ, φ) {
2532 var point = rotate(λ, φ);
2533 line.point(point[0], point[1]);
2535 function lineStart() { clip.point = pointLine; line.lineStart(); }
2536 function lineEnd() { clip.point = point; line.lineEnd(); }
2540 var buffer = d3_geo_clipBufferListener(),
2541 ringListener = clipLine(buffer),
2542 polygonStarted = false,
2546 function pointRing(λ, φ) {
2548 var point = rotate(λ, φ);
2549 ringListener.point(point[0], point[1]);
2552 function ringStart() {
2553 ringListener.lineStart();
2557 function ringEnd() {
2558 pointRing(ring[0][0], ring[0][1]);
2559 ringListener.lineEnd();
2561 var clean = ringListener.clean(),
2562 ringSegments = buffer.buffer(),
2564 n = ringSegments.length;
2572 // No intersections.
2574 segment = ringSegments[0];
2575 var n = segment.length - 1,
2579 if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
2580 listener.lineStart();
2581 while (++i < n) listener.point((point = segment[i])[0], point[1]);
2587 // Rejoin connected segments.
2588 // TODO reuse bufferListener.rejoin()?
2589 if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
2591 segments.push(ringSegments.filter(d3_geo_clipSegmentLength1));
2598 function d3_geo_clipSegmentLength1(segment) {
2599 return segment.length > 1;
2602 function d3_geo_clipBufferListener() {
2606 lineStart: function() { lines.push(line = []); },
2607 point: function(λ, φ) { line.push([λ, φ]); },
2609 buffer: function() {
2615 rejoin: function() {
2616 if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
2621 // Intersection points are sorted along the clip edge. For both antimeridian
2622 // cutting and circle clipping, the same comparison is used.
2623 function d3_geo_clipSort(a, b) {
2624 return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1])
2625 - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]);
2628 var d3_geo_clipAntimeridian = d3_geo_clip(
2630 d3_geo_clipAntimeridianLine,
2631 d3_geo_clipAntimeridianInterpolate,
2634 // Takes a line and cuts into visible segments. Return values:
2635 // 0: there were intersections or the line was empty.
2636 // 1: no intersections.
2637 // 2: there were intersections, and the first and last segments should be
2639 function d3_geo_clipAntimeridianLine(listener) {
2643 clean; // no intersections
2646 lineStart: function() {
2647 listener.lineStart();
2650 point: function(λ1, φ1) {
2651 var sλ1 = λ1 > 0 ? π : -π,
2653 if (abs(dλ - π) < ε) { // line crosses a pole
2654 listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ);
2655 listener.point(sλ0, φ0);
2657 listener.lineStart();
2658 listener.point(sλ1, φ0);
2659 listener.point(λ1, φ0);
2661 } else if (sλ0 !== sλ1 && dλ >= π) { // line crosses antimeridian
2662 // handle degeneracies
2663 if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε;
2664 if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε;
2665 φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1);
2666 listener.point(sλ0, φ0);
2668 listener.lineStart();
2669 listener.point(sλ1, φ0);
2672 listener.point(λ0 = λ1, φ0 = φ1);
2675 lineEnd: function() {
2679 // if there are intersections, we always rejoin the first and last segments.
2680 clean: function() { return 2 - clean; }
2684 function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) {
2687 sinλ0_λ1 = Math.sin(λ0 - λ1);
2688 return abs(sinλ0_λ1) > ε
2689 ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1)
2690 - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0))
2691 / (cosφ0 * cosφ1 * sinλ0_λ1))
2695 function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) {
2698 φ = direction * halfπ;
2699 listener.point(-π, φ);
2700 listener.point( 0, φ);
2701 listener.point( π, φ);
2702 listener.point( π, 0);
2703 listener.point( π, -φ);
2704 listener.point( 0, -φ);
2705 listener.point(-π, -φ);
2706 listener.point(-π, 0);
2707 listener.point(-π, φ);
2708 } else if (abs(from[0] - to[0]) > ε) {
2709 var s = from[0] < to[0] ? π : -π;
2710 φ = direction * s / 2;
2711 listener.point(-s, φ);
2712 listener.point( 0, φ);
2713 listener.point( s, φ);
2715 listener.point(to[0], to[1]);
2719 // cross and scale return new vectors,
2720 // whereas add and normalize operate in-place
2722 function d3_geo_cartesian(spherical) {
2723 var λ = spherical[0],
2733 function d3_geo_cartesianDot(a, b) {
2734 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
2737 function d3_geo_cartesianCross(a, b) {
2739 a[1] * b[2] - a[2] * b[1],
2740 a[2] * b[0] - a[0] * b[2],
2741 a[0] * b[1] - a[1] * b[0]
2745 function d3_geo_cartesianAdd(a, b) {
2751 function d3_geo_cartesianScale(vector, k) {
2759 function d3_geo_cartesianNormalize(d) {
2760 var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
2765 function d3_geo_compose(a, b) {
2767 function compose(x, y) {
2768 return x = a(x, y), b(x[0], x[1]);
2771 if (a.invert && b.invert) compose.invert = function(x, y) {
2772 return x = b.invert(x, y), x && a.invert(x[0], x[1]);
2778 function d3_geo_equirectangular(λ, φ) {
2782 (d3.geo.equirectangular = function() {
2783 return d3_geo_projection(d3_geo_equirectangular);
2784 }).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular;
2786 d3.geo.rotation = function(rotate) {
2787 rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0);
2789 function forward(coordinates) {
2790 coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
2791 return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
2794 forward.invert = function(coordinates) {
2795 coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians);
2796 return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates;
2802 function d3_geo_identityRotation(λ, φ) {
2803 return [λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ];
2806 d3_geo_identityRotation.invert = d3_geo_equirectangular;
2808 // Note: |δλ| must be < 2π
2809 function d3_geo_rotation(δλ, δφ, δγ) {
2810 return δλ ? (δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ))
2811 : d3_geo_rotationλ(δλ))
2812 : (δφ || δγ ? d3_geo_rotationφγ(δφ, δγ)
2813 : d3_geo_identityRotation);
2816 function d3_geo_forwardRotationλ(δλ) {
2817 return function(λ, φ) {
2818 return λ += δλ, [λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ];
2822 function d3_geo_rotationλ(δλ) {
2823 var rotation = d3_geo_forwardRotationλ(δλ);
2824 rotation.invert = d3_geo_forwardRotationλ(-δλ);
2828 function d3_geo_rotationφγ(δφ, δγ) {
2829 var cosδφ = Math.cos(δφ),
2830 sinδφ = Math.sin(δφ),
2831 cosδγ = Math.cos(δγ),
2832 sinδγ = Math.sin(δγ);
2834 function rotation(λ, φ) {
2835 var cosφ = Math.cos(φ),
2836 x = Math.cos(λ) * cosφ,
2837 y = Math.sin(λ) * cosφ,
2839 k = z * cosδφ + x * sinδφ;
2841 Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ),
2842 d3_asin(k * cosδγ + y * sinδγ)
2846 rotation.invert = function(λ, φ) {
2847 var cosφ = Math.cos(φ),
2848 x = Math.cos(λ) * cosφ,
2849 y = Math.sin(λ) * cosφ,
2851 k = z * cosδγ - y * sinδγ;
2853 Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ),
2854 d3_asin(k * cosδφ - x * sinδφ)
2861 d3.geo.circle = function() {
2862 var origin = [0, 0],
2868 var center = typeof origin === "function" ? origin.apply(this, arguments) : origin,
2869 rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert,
2872 interpolate(null, null, 1, {
2873 point: function(x, y) {
2874 ring.push(x = rotate(x, y));
2875 x[0] *= d3_degrees, x[1] *= d3_degrees;
2879 return {type: "Polygon", coordinates: [ring]};
2882 circle.origin = function(x) {
2883 if (!arguments.length) return origin;
2888 circle.angle = function(x) {
2889 if (!arguments.length) return angle;
2890 interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians);
2894 circle.precision = function(_) {
2895 if (!arguments.length) return precision;
2896 interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians);
2900 return circle.angle(90);
2903 // Interpolates along a circle centered at [0°, 0°], with a given radius and
2905 function d3_geo_circleInterpolate(radius, precision) {
2906 var cr = Math.cos(radius),
2907 sr = Math.sin(radius);
2908 return function(from, to, direction, listener) {
2909 var step = direction * precision;
2911 from = d3_geo_circleAngle(cr, from);
2912 to = d3_geo_circleAngle(cr, to);
2913 if (direction > 0 ? from < to: from > to) from += direction * τ;
2915 from = radius + direction * τ;
2916 to = radius - .5 * step;
2918 for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) {
2919 listener.point((point = d3_geo_spherical([
2928 // Signed angle of a cartesian point relative to [cr, 0, 0].
2929 function d3_geo_circleAngle(cr, point) {
2930 var a = d3_geo_cartesian(point);
2932 d3_geo_cartesianNormalize(a);
2933 var angle = d3_acos(-a[1]);
2934 return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI);
2936 // Adds floating point numbers with twice the normal precision.
2937 // Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
2938 // Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
2940 // Code adapted from GeographicLib by Charles F. F. Karney,
2941 // http://geographiclib.sourceforge.net/
2942 // See lib/geographiclib/LICENSE for details.
2944 function d3_adder() {}
2946 d3_adder.prototype = {
2947 s: 0, // rounded value
2948 t: 0, // exact error
2950 d3_adderSum(y, this.t, d3_adderTemp);
2951 d3_adderSum(d3_adderTemp.s, this.s, this);
2952 if (this.s) this.t += d3_adderTemp.t;
2953 else this.s = d3_adderTemp.t;
2956 this.s = this.t = 0;
2958 valueOf: function() {
2963 var d3_adderTemp = new d3_adder;
2965 function d3_adderSum(a, b, o) {
2966 var x = o.s = a + b, // a + b
2967 bv = x - a, av = x - bv; // b_virtual & a_virtual
2968 o.t = (a - av) + (b - bv); // a_roundoff + b_roundoff
2971 d3.geo.area = function(object) {
2973 d3.geo.stream(object, d3_geo_area);
2974 return d3_geo_areaSum;
2978 d3_geo_areaRingSum = new d3_adder;
2981 sphere: function() { d3_geo_areaSum += 4 * π; },
2986 // Only count area for polygon rings.
2987 polygonStart: function() {
2988 d3_geo_areaRingSum.reset();
2989 d3_geo_area.lineStart = d3_geo_areaRingStart;
2991 polygonEnd: function() {
2992 var area = 2 * d3_geo_areaRingSum;
2993 d3_geo_areaSum += area < 0 ? 4 * π + area : area;
2994 d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop;
2998 function d3_geo_areaRingStart() {
2999 var λ00, φ00, λ0, cosφ0, sinφ0; // start point and previous point
3001 // For the first point, …
3002 d3_geo_area.point = function(λ, φ) {
3003 d3_geo_area.point = nextPoint;
3004 λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), sinφ0 = Math.sin(φ);
3007 // For subsequent points, …
3008 function nextPoint(λ, φ) {
3010 φ = φ * d3_radians / 2 + π / 4; // half the angular distance from south pole
3012 // Spherical excess E for a spherical triangle with vertices: south pole,
3013 // previous point, current point. Uses a formula derived from Cagnoli’s
3014 // theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
3016 sdλ = dλ >= 0 ? 1 : -1,
3021 u = cosφ0 * cosφ + k * Math.cos(adλ),
3022 v = k * sdλ * Math.sin(adλ);
3023 d3_geo_areaRingSum.add(Math.atan2(v, u));
3025 // Advance the previous points.
3026 λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ;
3029 // For the last point, return to the start.
3030 d3_geo_area.lineEnd = function() {
3031 nextPoint(λ00, φ00);
3035 function d3_geo_pointInPolygon(point, polygon) {
3036 var meridian = point[0],
3037 parallel = point[1],
3038 meridianNormal = [Math.sin(meridian), -Math.cos(meridian), 0],
3041 d3_geo_areaRingSum.reset();
3043 for (var i = 0, n = polygon.length; i < n; ++i) {
3044 var ring = polygon[i],
3047 var point0 = ring[0],
3049 φ0 = point0[1] / 2 + π / 4,
3050 sinφ0 = Math.sin(φ0),
3051 cosφ0 = Math.cos(φ0),
3058 φ = point[1] / 2 + π / 4,
3062 sdλ = dλ >= 0 ? 1 : -1,
3064 antimeridian = adλ > π,
3066 d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ)));
3068 polarAngle += antimeridian ? dλ + sdλ * τ : dλ;
3070 // Are the longitudes either side of the point's meridian, and are the
3071 // latitudes smaller than the parallel?
3072 if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) {
3073 var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point));
3074 d3_geo_cartesianNormalize(arc);
3075 var intersection = d3_geo_cartesianCross(meridianNormal, arc);
3076 d3_geo_cartesianNormalize(intersection);
3077 var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]);
3078 if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) {
3079 winding += antimeridian ^ dλ >= 0 ? 1 : -1;
3083 λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point;
3087 // First, determine whether the South pole is inside or outside:
3090 // * the polygon winds around it in a clockwise direction.
3091 // * the polygon does not (cumulatively) wind around it, but has a negative
3092 // (counter-clockwise) area.
3094 // Second, count the (signed) number of times a segment crosses a meridian
3095 // from the point to the South pole. If it is zero, then the point is the
3096 // same side as the South pole.
3098 return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < 0) ^ (winding & 1);
3101 // Clip features against a small circle centered at [0°, 0°].
3102 function d3_geo_clipCircle(radius) {
3103 var cr = Math.cos(radius),
3104 smallRadius = cr > 0,
3105 notHemisphere = abs(cr) > ε, // TODO optimise for this common case
3106 interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians);
3108 return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-π, radius - π]);
3110 function visible(λ, φ) {
3111 return Math.cos(λ) * Math.cos(φ) > cr;
3114 // Takes a line and cuts into visible segments. Return values used for
3115 // polygon clipping:
3116 // 0: there were intersections or the line was empty.
3117 // 1: no intersections.
3118 // 2: there were intersections, and the first and last segments should be
3120 function clipLine(listener) {
3121 var point0, // previous point
3122 c0, // code for previous point
3123 v0, // visibility of previous point
3124 v00, // visibility of first point
3125 clean; // no intersections
3127 lineStart: function() {
3131 point: function(λ, φ) {
3132 var point1 = [λ, φ],
3136 ? v ? 0 : code(λ, φ)
3137 : v ? code(λ + (λ < 0 ? π : -π), φ) : 0;
3138 if (!point0 && (v00 = v0 = v)) listener.lineStart();
3139 // Handle degeneracies.
3140 // TODO ignore if not clipping polygons.
3142 point2 = intersect(point0, point1);
3143 if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) {
3146 v = visible(point1[0], point1[1]);
3153 listener.lineStart();
3154 point2 = intersect(point1, point0);
3155 listener.point(point2[0], point2[1]);
3158 point2 = intersect(point0, point1);
3159 listener.point(point2[0], point2[1]);
3163 } else if (notHemisphere && point0 && smallRadius ^ v) {
3165 // If the codes for two points are different, or are both zero,
3166 // and there this segment intersects with the small circle.
3167 if (!(c & c0) && (t = intersect(point1, point0, true))) {
3170 listener.lineStart();
3171 listener.point(t[0][0], t[0][1]);
3172 listener.point(t[1][0], t[1][1]);
3175 listener.point(t[1][0], t[1][1]);
3177 listener.lineStart();
3178 listener.point(t[0][0], t[0][1]);
3182 if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) {
3183 listener.point(point1[0], point1[1]);
3185 point0 = point1, v0 = v, c0 = c;
3187 lineEnd: function() {
3188 if (v0) listener.lineEnd();
3191 // Rejoin first and last segments if there were intersections and the first
3192 // and last points were visible.
3193 clean: function() { return clean | ((v00 && v0) << 1); }
3197 // Intersects the great circle between a and b with the clip circle.
3198 function intersect(a, b, two) {
3199 var pa = d3_geo_cartesian(a),
3200 pb = d3_geo_cartesian(b);
3202 // We have two planes, n1.p = d1 and n2.p = d2.
3203 // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
3204 var n1 = [1, 0, 0], // normal
3205 n2 = d3_geo_cartesianCross(pa, pb),
3206 n2n2 = d3_geo_cartesianDot(n2, n2),
3207 n1n2 = n2[0], // d3_geo_cartesianDot(n1, n2),
3208 determinant = n2n2 - n1n2 * n1n2;
3210 // Two polar points.
3211 if (!determinant) return !two && a;
3213 var c1 = cr * n2n2 / determinant,
3214 c2 = -cr * n1n2 / determinant,
3215 n1xn2 = d3_geo_cartesianCross(n1, n2),
3216 A = d3_geo_cartesianScale(n1, c1),
3217 B = d3_geo_cartesianScale(n2, c2);
3218 d3_geo_cartesianAdd(A, B);
3220 // Solve |p(t)|^2 = 1.
3222 w = d3_geo_cartesianDot(A, u),
3223 uu = d3_geo_cartesianDot(u, u),
3224 t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1);
3228 var t = Math.sqrt(t2),
3229 q = d3_geo_cartesianScale(u, (-w - t) / uu);
3230 d3_geo_cartesianAdd(q, A);
3231 q = d3_geo_spherical(q);
3234 // Two intersection points.
3240 if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z;
3242 polar = abs(δλ - π) < ε,
3243 meridian = polar || δλ < ε;
3245 if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z;
3247 // Check that the first point is between a and b.
3250 ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1)
3251 : φ0 <= q[1] && q[1] <= φ1
3252 : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) {
3253 var q1 = d3_geo_cartesianScale(u, (-w + t) / uu);
3254 d3_geo_cartesianAdd(q1, A);
3255 return [q, d3_geo_spherical(q1)];
3259 // Generates a 4-bit vector representing the location of a point relative to
3260 // the small circle's bounding box.
3261 function code(λ, φ) {
3262 var r = smallRadius ? radius : π - radius,
3264 if (λ < -r) code |= 1; // left
3265 else if (λ > r) code |= 2; // right
3266 if (φ < -r) code |= 4; // below
3267 else if (φ > r) code |= 8; // above
3272 // Liang–Barsky line clipping.
3273 function d3_geom_clipLine(x0, y0, x1, y1) {
3274 return function(line) {
3288 if (!dx && r > 0) return;
3293 } else if (dx > 0) {
3299 if (!dx && r < 0) return;
3304 } else if (dx > 0) {
3310 if (!dy && r > 0) return;
3315 } else if (dy > 0) {
3321 if (!dy && r < 0) return;
3326 } else if (dy > 0) {
3331 if (t0 > 0) line.a = {x: ax + t0 * dx, y: ay + t0 * dy};
3332 if (t1 < 1) line.b = {x: ax + t1 * dx, y: ay + t1 * dy};
3337 var d3_geo_clipExtentMAX = 1e9;
3339 d3.geo.clipExtent = function() {
3344 stream: function(output) {
3345 if (stream) stream.valid = false;
3346 stream = clip(output);
3347 stream.valid = true; // allow caching by d3.geo.path
3350 extent: function(_) {
3351 if (!arguments.length) return [[x0, y0], [x1, y1]];
3352 clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]);
3353 if (stream) stream.valid = false, stream = null;
3357 return clipExtent.extent([[0, 0], [960, 500]]);
3360 function d3_geo_clipExtent(x0, y0, x1, y1) {
3361 return function(listener) {
3362 var listener_ = listener,
3363 bufferListener = d3_geo_clipBufferListener(),
3364 clipLine = d3_geom_clipLine(x0, y0, x1, y1),
3371 lineStart: lineStart,
3373 polygonStart: function() {
3374 listener = bufferListener;
3379 polygonEnd: function() {
3380 listener = listener_;
3381 segments = d3.merge(segments);
3382 var clipStartInside = insidePolygon([x0, y1]),
3383 inside = clean && clipStartInside,
3384 visible = segments.length;
3385 if (inside || visible) {
3386 listener.polygonStart();
3388 listener.lineStart();
3389 interpolate(null, null, 1, listener);
3393 d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener);
3395 listener.polygonEnd();
3397 segments = polygon = ring = null;
3401 function insidePolygon(p) {
3402 var wn = 0, // the winding number counter
3406 for (var i = 0; i < n; ++i) {
3407 for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) {
3410 if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn;
3412 if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn;
3420 function interpolate(from, to, direction, listener) {
3423 (a = corner(from, direction)) !== (a1 = corner(to, direction)) ||
3424 comparePoints(from, to) < 0 ^ direction > 0) {
3426 listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
3427 } while ((a = (a + direction + 4) % 4) !== a1);
3429 listener.point(to[0], to[1]);
3433 function pointVisible(x, y) {
3434 return x0 <= x && x <= x1 && y0 <= y && y <= y1;
3437 function point(x, y) {
3438 if (pointVisible(x, y)) listener.point(x, y);
3441 var x__, y__, v__, // first point
3442 x_, y_, v_, // previous point
3446 function lineStart() {
3447 clip.point = linePoint;
3448 if (polygon) polygon.push(ring = []);
3454 function lineEnd() {
3455 // TODO rather than special-case polygons, simply handle them separately.
3456 // Ideally, coincident intersection points should be jittered to avoid
3459 linePoint(x__, y__);
3460 if (v__ && v_) bufferListener.rejoin();
3461 segments.push(bufferListener.buffer());
3464 if (v_) listener.lineEnd();
3467 function linePoint(x, y) {
3468 x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x));
3469 y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y));
3470 var v = pointVisible(x, y);
3471 if (polygon) ring.push([x, y]);
3473 x__ = x, y__ = y, v__ = v;
3476 listener.lineStart();
3477 listener.point(x, y);
3480 if (v && v_) listener.point(x, y);
3482 var l = {a: {x: x_, y: y_}, b: {x: x, y: y}};
3485 listener.lineStart();
3486 listener.point(l.a.x, l.a.y);
3488 listener.point(l.b.x, l.b.y);
3489 if (!v) listener.lineEnd();
3492 listener.lineStart();
3493 listener.point(x, y);
3498 x_ = x, y_ = y, v_ = v;
3504 function corner(p, direction) {
3505 return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3
3506 : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1
3507 : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0
3508 : direction > 0 ? 3 : 2; // abs(p[1] - y1) < ε
3511 function compare(a, b) {
3512 return comparePoints(a.x, b.x);
3515 function comparePoints(a, b) {
3516 var ca = corner(a, 1),
3518 return ca !== cb ? ca - cb
3519 : ca === 0 ? b[1] - a[1]
3520 : ca === 1 ? a[0] - b[0]
3521 : ca === 2 ? a[1] - b[1]
3526 function d3_geo_conic(projectAt) {
3529 m = d3_geo_projectionMutator(projectAt),
3532 p.parallels = function(_) {
3533 if (!arguments.length) return [φ0 / π * 180, φ1 / π * 180];
3534 return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180);
3540 function d3_geo_conicEqualArea(φ0, φ1) {
3541 var sinφ0 = Math.sin(φ0),
3542 n = (sinφ0 + Math.sin(φ1)) / 2,
3543 C = 1 + sinφ0 * (2 * n - sinφ0),
3544 ρ0 = Math.sqrt(C) / n;
3546 function forward(λ, φ) {
3547 var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n;
3549 ρ * Math.sin(λ *= n),
3550 ρ0 - ρ * Math.cos(λ)
3554 forward.invert = function(x, y) {
3557 Math.atan2(x, ρ0_y) / n,
3558 d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n))
3565 (d3.geo.conicEqualArea = function() {
3566 return d3_geo_conic(d3_geo_conicEqualArea);
3567 }).raw = d3_geo_conicEqualArea;
3570 d3.geo.albers = function() {
3571 return d3.geo.conicEqualArea()
3573 .center([-.6, 38.7])
3574 .parallels([29.5, 45.5])
3578 // A composite projection for the United States, configured by default for
3579 // 960×500. Also works quite well at 960×600 with scale 1285. The set of
3580 // standard parallels for each region comes from USGS, which is published here:
3581 // http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
3582 d3.geo.albersUsa = function() {
3583 var lower48 = d3.geo.albers();
3586 var alaska = d3.geo.conicEqualArea()
3589 .parallels([55, 65]);
3592 var hawaii = d3.geo.conicEqualArea()
3595 .parallels([8, 18]);
3598 pointStream = {point: function(x, y) { point = [x, y]; }},
3603 function albersUsa(coordinates) {
3604 var x = coordinates[0], y = coordinates[1];
3606 (lower48Point(x, y), point)
3607 || (alaskaPoint(x, y), point)
3608 || hawaiiPoint(x, y);
3612 albersUsa.invert = function(coordinates) {
3613 var k = lower48.scale(),
3614 t = lower48.translate(),
3615 x = (coordinates[0] - t[0]) / k,
3616 y = (coordinates[1] - t[1]) / k;
3617 return (y >= .120 && y < .234 && x >= -.425 && x < -.214 ? alaska
3618 : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii
3619 : lower48).invert(coordinates);
3622 // A naïve multi-projection stream.
3623 // The projections must have mutually exclusive clip regions on the sphere,
3624 // as this will avoid emitting interleaving lines and polygons.
3625 albersUsa.stream = function(stream) {
3626 var lower48Stream = lower48.stream(stream),
3627 alaskaStream = alaska.stream(stream),
3628 hawaiiStream = hawaii.stream(stream);
3630 point: function(x, y) {
3631 lower48Stream.point(x, y);
3632 alaskaStream.point(x, y);
3633 hawaiiStream.point(x, y);
3635 sphere: function() {
3636 lower48Stream.sphere();
3637 alaskaStream.sphere();
3638 hawaiiStream.sphere();
3640 lineStart: function() {
3641 lower48Stream.lineStart();
3642 alaskaStream.lineStart();
3643 hawaiiStream.lineStart();
3645 lineEnd: function() {
3646 lower48Stream.lineEnd();
3647 alaskaStream.lineEnd();
3648 hawaiiStream.lineEnd();
3650 polygonStart: function() {
3651 lower48Stream.polygonStart();
3652 alaskaStream.polygonStart();
3653 hawaiiStream.polygonStart();
3655 polygonEnd: function() {
3656 lower48Stream.polygonEnd();
3657 alaskaStream.polygonEnd();
3658 hawaiiStream.polygonEnd();
3663 albersUsa.precision = function(_) {
3664 if (!arguments.length) return lower48.precision();
3665 lower48.precision(_);
3666 alaska.precision(_);
3667 hawaii.precision(_);
3671 albersUsa.scale = function(_) {
3672 if (!arguments.length) return lower48.scale();
3674 alaska.scale(_ * .35);
3676 return albersUsa.translate(lower48.translate());
3679 albersUsa.translate = function(_) {
3680 if (!arguments.length) return lower48.translate();
3681 var k = lower48.scale(), x = +_[0], y = +_[1];
3683 lower48Point = lower48
3685 .clipExtent([[x - .455 * k, y - .238 * k], [x + .455 * k, y + .238 * k]])
3686 .stream(pointStream).point;
3688 alaskaPoint = alaska
3689 .translate([x - .307 * k, y + .201 * k])
3690 .clipExtent([[x - .425 * k + ε, y + .120 * k + ε], [x - .214 * k - ε, y + .234 * k - ε]])
3691 .stream(pointStream).point;
3693 hawaiiPoint = hawaii
3694 .translate([x - .205 * k, y + .212 * k])
3695 .clipExtent([[x - .214 * k + ε, y + .166 * k + ε], [x - .115 * k - ε, y + .234 * k - ε]])
3696 .stream(pointStream).point;
3701 return albersUsa.scale(1070);
3704 d3.geo.bounds = (function() {
3705 var λ0, φ0, λ1, φ1, // bounds
3706 λ_, // previous λ-coordinate
3707 λ__, φ__, // first point
3708 p0, // previous 3D point
3715 lineStart: lineStart,
3718 polygonStart: function() {
3719 bound.point = ringPoint;
3720 bound.lineStart = ringStart;
3721 bound.lineEnd = ringEnd;
3723 d3_geo_area.polygonStart();
3725 polygonEnd: function() {
3726 d3_geo_area.polygonEnd();
3727 bound.point = point;
3728 bound.lineStart = lineStart;
3729 bound.lineEnd = lineEnd;
3730 if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90);
3731 else if (dλSum > ε) φ1 = 90;
3732 else if (dλSum < -ε) φ0 = -90;
3733 range[0] = λ0, range[1] = λ1;
3737 function point(λ, φ) {
3738 ranges.push(range = [λ0 = λ, λ1 = λ]);
3743 function linePoint(λ, φ) {
3744 var p = d3_geo_cartesian([λ * d3_radians, φ * d3_radians]);
3746 var normal = d3_geo_cartesianCross(p0, p),
3747 equatorial = [normal[1], -normal[0], 0],
3748 inflection = d3_geo_cartesianCross(equatorial, normal);
3749 d3_geo_cartesianNormalize(inflection);
3750 inflection = d3_geo_spherical(inflection);
3752 s = dλ > 0 ? 1 : -1,
3753 λi = inflection[0] * d3_degrees * s,
3754 antimeridian = abs(dλ) > 180;
3755 if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
3756 var φi = inflection[1] * d3_degrees;
3757 if (φi > φ1) φ1 = φi;
3758 } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) {
3759 var φi = -inflection[1] * d3_degrees;
3760 if (φi < φ0) φ0 = φi;
3767 if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
3769 if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
3777 if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ;
3779 if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ;
3789 function lineStart() { bound.point = linePoint; }
3790 function lineEnd() {
3791 range[0] = λ0, range[1] = λ1;
3792 bound.point = point;
3796 function ringPoint(λ, φ) {
3799 dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ;
3800 } else λ__ = λ, φ__ = φ;
3801 d3_geo_area.point(λ, φ);
3805 function ringStart() {
3806 d3_geo_area.lineStart();
3809 function ringEnd() {
3810 ringPoint(λ__, φ__);
3811 d3_geo_area.lineEnd();
3812 if (abs(dλSum) > ε) λ0 = -(λ1 = 180);
3813 range[0] = λ0, range[1] = λ1;
3817 // Finds the left-right distance between two longitudes.
3818 // This is almost the same as (λ1 - λ0 + 360°) % 360°, except that we want
3819 // the distance between ±180° to be 360°.
3820 function angle(λ0, λ1) { return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; }
3822 function compareRanges(a, b) { return a[0] - b[0]; }
3824 function withinRange(x, range) {
3825 return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
3828 return function(feature) {
3829 φ1 = λ1 = -(λ0 = φ0 = Infinity);
3832 d3.geo.stream(feature, bound);
3834 var n = ranges.length;
3836 // First, sort ranges by their minimum longitudes.
3837 ranges.sort(compareRanges);
3839 // Then, merge any ranges that overlap.
3840 for (var i = 1, a = ranges[0], b, merged = [a]; i < n; ++i) {
3842 if (withinRange(b[0], a) || withinRange(b[1], a)) {
3843 if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
3844 if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
3850 // Finally, find the largest gap between the merged ranges.
3851 // The final bounding box will be the inverse of this gap.
3852 var best = -Infinity, dλ;
3853 for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) {
3855 if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1];
3858 ranges = range = null;
3860 return λ0 === Infinity || φ0 === Infinity
3861 ? [[NaN, NaN], [NaN, NaN]]
3862 : [[λ0, φ0], [λ1, φ1]];
3866 d3.geo.centroid = function(object) {
3867 d3_geo_centroidW0 = d3_geo_centroidW1 =
3868 d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 =
3869 d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 =
3870 d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
3871 d3.geo.stream(object, d3_geo_centroid);
3873 var x = d3_geo_centroidX2,
3874 y = d3_geo_centroidY2,
3875 z = d3_geo_centroidZ2,
3876 m = x * x + y * y + z * z;
3878 // If the area-weighted centroid is undefined, fall back to length-weighted centroid.
3880 x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1;
3881 // If the feature has zero length, fall back to arithmetic mean of point vectors.
3882 if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0;
3883 m = x * x + y * y + z * z;
3884 // If the feature still has an undefined centroid, then return.
3885 if (m < ε2) return [NaN, NaN];
3888 return [Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees];
3891 var d3_geo_centroidW0,
3903 var d3_geo_centroid = {
3905 point: d3_geo_centroidPoint,
3906 lineStart: d3_geo_centroidLineStart,
3907 lineEnd: d3_geo_centroidLineEnd,
3908 polygonStart: function() {
3909 d3_geo_centroid.lineStart = d3_geo_centroidRingStart;
3911 polygonEnd: function() {
3912 d3_geo_centroid.lineStart = d3_geo_centroidLineStart;
3916 // Arithmetic mean of Cartesian vectors.
3917 function d3_geo_centroidPoint(λ, φ) {
3919 var cosφ = Math.cos(φ *= d3_radians);
3920 d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ));
3923 function d3_geo_centroidPointXYZ(x, y, z) {
3924 ++d3_geo_centroidW0;
3925 d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0;
3926 d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0;
3927 d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0;
3930 function d3_geo_centroidLineStart() {
3931 var x0, y0, z0; // previous point
3933 d3_geo_centroid.point = function(λ, φ) {
3935 var cosφ = Math.cos(φ *= d3_radians);
3936 x0 = cosφ * Math.cos(λ);
3937 y0 = cosφ * Math.sin(λ);
3939 d3_geo_centroid.point = nextPoint;
3940 d3_geo_centroidPointXYZ(x0, y0, z0);
3943 function nextPoint(λ, φ) {
3945 var cosφ = Math.cos(φ *= d3_radians),
3946 x = cosφ * Math.cos(λ),
3947 y = cosφ * Math.sin(λ),
3950 Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w),
3951 x0 * x + y0 * y + z0 * z);
3952 d3_geo_centroidW1 += w;
3953 d3_geo_centroidX1 += w * (x0 + (x0 = x));
3954 d3_geo_centroidY1 += w * (y0 + (y0 = y));
3955 d3_geo_centroidZ1 += w * (z0 + (z0 = z));
3956 d3_geo_centroidPointXYZ(x0, y0, z0);
3960 function d3_geo_centroidLineEnd() {
3961 d3_geo_centroid.point = d3_geo_centroidPoint;
3964 // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
3965 // J. Applied Mechanics 42, 239 (1975).
3966 function d3_geo_centroidRingStart() {
3967 var λ00, φ00, // first point
3968 x0, y0, z0; // previous point
3970 d3_geo_centroid.point = function(λ, φ) {
3972 d3_geo_centroid.point = nextPoint;
3974 var cosφ = Math.cos(φ *= d3_radians);
3975 x0 = cosφ * Math.cos(λ);
3976 y0 = cosφ * Math.sin(λ);
3978 d3_geo_centroidPointXYZ(x0, y0, z0);
3981 d3_geo_centroid.lineEnd = function() {
3982 nextPoint(λ00, φ00);
3983 d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd;
3984 d3_geo_centroid.point = d3_geo_centroidPoint;
3987 function nextPoint(λ, φ) {
3989 var cosφ = Math.cos(φ *= d3_radians),
3990 x = cosφ * Math.cos(λ),
3991 y = cosφ * Math.sin(λ),
3993 cx = y0 * z - z0 * y,
3994 cy = z0 * x - x0 * z,
3995 cz = x0 * y - y0 * x,
3996 m = Math.sqrt(cx * cx + cy * cy + cz * cz),
3997 u = x0 * x + y0 * y + z0 * z,
3998 v = m && -d3_acos(u) / m, // area weight
3999 w = Math.atan2(m, u); // line weight
4000 d3_geo_centroidX2 += v * cx;
4001 d3_geo_centroidY2 += v * cy;
4002 d3_geo_centroidZ2 += v * cz;
4003 d3_geo_centroidW1 += w;
4004 d3_geo_centroidX1 += w * (x0 + (x0 = x));
4005 d3_geo_centroidY1 += w * (y0 + (y0 = y));
4006 d3_geo_centroidZ1 += w * (z0 + (z0 = z));
4007 d3_geo_centroidPointXYZ(x0, y0, z0);
4011 // TODO Unify this code with d3.geom.polygon area?
4013 var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = {
4018 // Only count area for polygon rings.
4019 polygonStart: function() {
4020 d3_geo_pathAreaPolygon = 0;
4021 d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart;
4023 polygonEnd: function() {
4024 d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop;
4025 d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2);
4029 function d3_geo_pathAreaRingStart() {
4030 var x00, y00, x0, y0;
4032 // For the first point, …
4033 d3_geo_pathArea.point = function(x, y) {
4034 d3_geo_pathArea.point = nextPoint;
4035 x00 = x0 = x, y00 = y0 = y;
4038 // For subsequent points, …
4039 function nextPoint(x, y) {
4040 d3_geo_pathAreaPolygon += y0 * x - x0 * y;
4044 // For the last point, return to the start.
4045 d3_geo_pathArea.lineEnd = function() {
4046 nextPoint(x00, y00);
4050 var d3_geo_pathBoundsX0,
4051 d3_geo_pathBoundsY0,
4052 d3_geo_pathBoundsX1,
4053 d3_geo_pathBoundsY1;
4055 var d3_geo_pathBounds = {
4056 point: d3_geo_pathBoundsPoint,
4059 polygonStart: d3_noop,
4063 function d3_geo_pathBoundsPoint(x, y) {
4064 if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x;
4065 if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x;
4066 if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y;
4067 if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y;
4069 function d3_geo_pathBuffer() {
4070 var pointCircle = d3_geo_pathBufferCircle(4.5),
4076 // While inside a line, override point to moveTo then lineTo.
4077 lineStart: function() { stream.point = pointLineStart; },
4080 // While inside a polygon, override lineEnd to closePath.
4081 polygonStart: function() { stream.lineEnd = lineEndPolygon; },
4082 polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; },
4084 pointRadius: function(_) {
4085 pointCircle = d3_geo_pathBufferCircle(_);
4089 result: function() {
4090 if (buffer.length) {
4091 var result = buffer.join("");
4098 function point(x, y) {
4099 buffer.push("M", x, ",", y, pointCircle);
4102 function pointLineStart(x, y) {
4103 buffer.push("M", x, ",", y);
4104 stream.point = pointLine;
4107 function pointLine(x, y) {
4108 buffer.push("L", x, ",", y);
4111 function lineEnd() {
4112 stream.point = point;
4115 function lineEndPolygon() {
4122 function d3_geo_pathBufferCircle(radius) {
4123 return "m0," + radius
4124 + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
4125 + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
4129 // TODO Unify this code with d3.geom.polygon centroid?
4130 // TODO Enforce positive area for exterior, negative area for interior?
4132 var d3_geo_pathCentroid = {
4133 point: d3_geo_pathCentroidPoint,
4135 // For lines, weight by length.
4136 lineStart: d3_geo_pathCentroidLineStart,
4137 lineEnd: d3_geo_pathCentroidLineEnd,
4139 // For polygons, weight by area.
4140 polygonStart: function() {
4141 d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart;
4143 polygonEnd: function() {
4144 d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
4145 d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart;
4146 d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd;
4150 function d3_geo_pathCentroidPoint(x, y) {
4151 d3_geo_centroidX0 += x;
4152 d3_geo_centroidY0 += y;
4153 ++d3_geo_centroidZ0;
4156 function d3_geo_pathCentroidLineStart() {
4159 d3_geo_pathCentroid.point = function(x, y) {
4160 d3_geo_pathCentroid.point = nextPoint;
4161 d3_geo_pathCentroidPoint(x0 = x, y0 = y);
4164 function nextPoint(x, y) {
4165 var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
4166 d3_geo_centroidX1 += z * (x0 + x) / 2;
4167 d3_geo_centroidY1 += z * (y0 + y) / 2;
4168 d3_geo_centroidZ1 += z;
4169 d3_geo_pathCentroidPoint(x0 = x, y0 = y);
4173 function d3_geo_pathCentroidLineEnd() {
4174 d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint;
4177 function d3_geo_pathCentroidRingStart() {
4178 var x00, y00, x0, y0;
4180 // For the first point, …
4181 d3_geo_pathCentroid.point = function(x, y) {
4182 d3_geo_pathCentroid.point = nextPoint;
4183 d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y);
4186 // For subsequent points, …
4187 function nextPoint(x, y) {
4188 var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy);
4189 d3_geo_centroidX1 += z * (x0 + x) / 2;
4190 d3_geo_centroidY1 += z * (y0 + y) / 2;
4191 d3_geo_centroidZ1 += z;
4193 z = y0 * x - x0 * y;
4194 d3_geo_centroidX2 += z * (x0 + x);
4195 d3_geo_centroidY2 += z * (y0 + y);
4196 d3_geo_centroidZ2 += z * 3;
4197 d3_geo_pathCentroidPoint(x0 = x, y0 = y);
4200 // For the last point, return to the start.
4201 d3_geo_pathCentroid.lineEnd = function() {
4202 nextPoint(x00, y00);
4206 function d3_geo_pathContext(context) {
4207 var pointRadius = 4.5;
4212 // While inside a line, override point to moveTo then lineTo.
4213 lineStart: function() { stream.point = pointLineStart; },
4216 // While inside a polygon, override lineEnd to closePath.
4217 polygonStart: function() { stream.lineEnd = lineEndPolygon; },
4218 polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; },
4220 pointRadius: function(_) {
4228 function point(x, y) {
4229 context.moveTo(x + pointRadius, y);
4230 context.arc(x, y, pointRadius, 0, τ);
4233 function pointLineStart(x, y) {
4234 context.moveTo(x, y);
4235 stream.point = pointLine;
4238 function pointLine(x, y) {
4239 context.lineTo(x, y);
4242 function lineEnd() {
4243 stream.point = point;
4246 function lineEndPolygon() {
4247 context.closePath();
4253 function d3_geo_resample(project) {
4254 var δ2 = .5, // precision, px²
4255 cosMinDistance = Math.cos(30 * d3_radians), // cos(minimum angular distance)
4258 function resample(stream) {
4259 return (maxDepth ? resampleRecursive : resampleNone)(stream);
4262 function resampleNone(stream) {
4263 return d3_geo_transformPoint(stream, function(x, y) {
4265 stream.point(x[0], x[1]);
4269 function resampleRecursive(stream) {
4270 var λ00, φ00, x00, y00, a00, b00, c00, // first point
4271 λ0, x0, y0, a0, b0, c0; // previous point
4275 lineStart: lineStart,
4277 polygonStart: function() { stream.polygonStart(); resample.lineStart = ringStart; },
4278 polygonEnd: function() { stream.polygonEnd(); resample.lineStart = lineStart; }
4281 function point(x, y) {
4283 stream.point(x[0], x[1]);
4286 function lineStart() {
4288 resample.point = linePoint;
4292 function linePoint(λ, φ) {
4293 var c = d3_geo_cartesian([λ, φ]), p = project(λ, φ);
4294 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);
4295 stream.point(x0, y0);
4298 function lineEnd() {
4299 resample.point = point;
4303 function ringStart() {
4305 resample.point = ringPoint;
4306 resample.lineEnd = ringEnd;
4309 function ringPoint(λ, φ) {
4310 linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
4311 resample.point = linePoint;
4314 function ringEnd() {
4315 resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream);
4316 resample.lineEnd = lineEnd;
4323 function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) {
4326 d2 = dx * dx + dy * dy;
4327 if (d2 > 4 * δ2 && depth--) {
4331 m = Math.sqrt(a * a + b * b + c * c),
4332 φ2 = Math.asin(c /= m),
4333 λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a),
4334 p = project(λ2, φ2),
4339 dz = dy * dx2 - dx * dy2;
4340 if (dz * dz / d2 > δ2 // perpendicular projected distance
4341 || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 // midpoint close to an end
4342 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
4343 resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream);
4344 stream.point(x2, y2);
4345 resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream);
4350 resample.precision = function(_) {
4351 if (!arguments.length) return Math.sqrt(δ2);
4352 maxDepth = (δ2 = _ * _) > 0 && 16;
4359 d3.geo.path = function() {
4360 var pointRadius = 4.5,
4367 function path(object) {
4369 if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
4370 if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream);
4371 d3.geo.stream(object, cacheStream);
4373 return contextStream.result();
4376 path.area = function(object) {
4377 d3_geo_pathAreaSum = 0;
4378 d3.geo.stream(object, projectStream(d3_geo_pathArea));
4379 return d3_geo_pathAreaSum;
4382 path.centroid = function(object) {
4383 d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 =
4384 d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 =
4385 d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0;
4386 d3.geo.stream(object, projectStream(d3_geo_pathCentroid));
4387 return d3_geo_centroidZ2 ? [d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2]
4388 : d3_geo_centroidZ1 ? [d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1]
4389 : d3_geo_centroidZ0 ? [d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0]
4393 path.bounds = function(object) {
4394 d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity);
4395 d3.geo.stream(object, projectStream(d3_geo_pathBounds));
4396 return [[d3_geo_pathBoundsX0, d3_geo_pathBoundsY0], [d3_geo_pathBoundsX1, d3_geo_pathBoundsY1]];
4399 path.projection = function(_) {
4400 if (!arguments.length) return projection;
4401 projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity;
4405 path.context = function(_) {
4406 if (!arguments.length) return context;
4407 contextStream = (context = _) == null ? new d3_geo_pathBuffer : new d3_geo_pathContext(_);
4408 if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
4412 path.pointRadius = function(_) {
4413 if (!arguments.length) return pointRadius;
4414 pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
4423 return path.projection(d3.geo.albersUsa()).context(null);
4426 function d3_geo_pathProjectStream(project) {
4427 var resample = d3_geo_resample(function(x, y) { return project([x * d3_degrees, y * d3_degrees]); });
4428 return function(stream) { return d3_geo_projectionRadians(resample(stream)); };
4431 d3.geo.transform = function(methods) {
4433 stream: function(stream) {
4434 var transform = new d3_geo_transform(stream);
4435 for (var k in methods) transform[k] = methods[k];
4441 function d3_geo_transform(stream) {
4442 this.stream = stream;
4445 d3_geo_transform.prototype = {
4446 point: function(x, y) { this.stream.point(x, y); },
4447 sphere: function() { this.stream.sphere(); },
4448 lineStart: function() { this.stream.lineStart(); },
4449 lineEnd: function() { this.stream.lineEnd(); },
4450 polygonStart: function() { this.stream.polygonStart(); },
4451 polygonEnd: function() { this.stream.polygonEnd(); }
4454 function d3_geo_transformPoint(stream, point) {
4457 sphere: function() { stream.sphere(); },
4458 lineStart: function() { stream.lineStart(); },
4459 lineEnd: function() { stream.lineEnd(); },
4460 polygonStart: function() { stream.polygonStart(); },
4461 polygonEnd: function() { stream.polygonEnd(); },
4465 d3.geo.projection = d3_geo_projection;
4466 d3.geo.projectionMutator = d3_geo_projectionMutator;
4468 function d3_geo_projection(project) {
4469 return d3_geo_projectionMutator(function() { return project; })();
4472 function d3_geo_projectionMutator(projectAt) {
4476 projectResample = d3_geo_resample(function(x, y) { x = project(x, y); return [x[0] * k + δx, δy - x[1] * k]; }),
4478 x = 480, y = 250, // translate
4479 λ = 0, φ = 0, // center
4480 δλ = 0, δφ = 0, δγ = 0, // rotate
4482 preclip = d3_geo_clipAntimeridian,
4483 postclip = d3_identity,
4488 function projection(point) {
4489 point = projectRotate(point[0] * d3_radians, point[1] * d3_radians);
4490 return [point[0] * k + δx, δy - point[1] * k];
4493 function invert(point) {
4494 point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k);
4495 return point && [point[0] * d3_degrees, point[1] * d3_degrees];
4498 projection.stream = function(output) {
4499 if (stream) stream.valid = false;
4500 stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output))));
4501 stream.valid = true; // allow caching by d3.geo.path
4505 projection.clipAngle = function(_) {
4506 if (!arguments.length) return clipAngle;
4507 preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians);
4508 return invalidate();
4511 projection.clipExtent = function(_) {
4512 if (!arguments.length) return clipExtent;
4514 postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity;
4515 return invalidate();
4518 projection.scale = function(_) {
4519 if (!arguments.length) return k;
4524 projection.translate = function(_) {
4525 if (!arguments.length) return [x, y];
4531 projection.center = function(_) {
4532 if (!arguments.length) return [λ * d3_degrees, φ * d3_degrees];
4533 λ = _[0] % 360 * d3_radians;
4534 φ = _[1] % 360 * d3_radians;
4538 projection.rotate = function(_) {
4539 if (!arguments.length) return [δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees];
4540 δλ = _[0] % 360 * d3_radians;
4541 δφ = _[1] % 360 * d3_radians;
4542 δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0;
4546 d3.rebind(projection, projectResample, "precision");
4549 projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project);
4550 var center = project(λ, φ);
4551 δx = x - center[0] * k;
4552 δy = y + center[1] * k;
4553 return invalidate();
4556 function invalidate() {
4557 if (stream) stream.valid = false, stream = null;
4562 project = projectAt.apply(this, arguments);
4563 projection.invert = project.invert && invert;
4568 function d3_geo_projectionRadians(stream) {
4569 return d3_geo_transformPoint(stream, function(x, y) {
4570 stream.point(x * d3_radians, y * d3_radians);
4574 function d3_geo_mercator(λ, φ) {
4575 return [λ, Math.log(Math.tan(π / 4 + φ / 2))];
4578 d3_geo_mercator.invert = function(x, y) {
4579 return [x, 2 * Math.atan(Math.exp(y)) - halfπ];
4582 function d3_geo_mercatorProjection(project) {
4583 var m = d3_geo_projection(project),
4585 translate = m.translate,
4586 clipExtent = m.clipExtent,
4589 m.scale = function() {
4590 var v = scale.apply(m, arguments);
4591 return v === m ? (clipAuto ? m.clipExtent(null) : m) : v;
4594 m.translate = function() {
4595 var v = translate.apply(m, arguments);
4596 return v === m ? (clipAuto ? m.clipExtent(null) : m) : v;
4599 m.clipExtent = function(_) {
4600 var v = clipExtent.apply(m, arguments);
4602 if (clipAuto = _ == null) {
4603 var k = π * scale(), t = translate();
4604 clipExtent([[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]]);
4606 } else if (clipAuto) {
4612 return m.clipExtent(null);
4615 (d3.geo.mercator = function() {
4616 return d3_geo_mercatorProjection(d3_geo_mercator);
4617 }).raw = d3_geo_mercator;
4620 d3.geom.polygon = function(coordinates) {
4621 d3_subclass(coordinates, d3_geom_polygonPrototype);
4625 var d3_geom_polygonPrototype = d3.geom.polygon.prototype = [];
4627 d3_geom_polygonPrototype.area = function() {
4637 area += a[1] * b[0] - a[0] * b[1];
4643 d3_geom_polygonPrototype.centroid = function(k) {
4652 if (!arguments.length) k = -1 / (6 * this.area());
4657 c = a[0] * b[1] - b[0] * a[1];
4658 x += (a[0] + b[0]) * c;
4659 y += (a[1] + b[1]) * c;
4662 return [x * k, y * k];
4665 // The Sutherland-Hodgman clipping algorithm.
4666 // Note: requires the clip polygon to be counterclockwise and convex.
4667 d3_geom_polygonPrototype.clip = function(subject) {
4669 closed = d3_geom_polygonClosed(subject),
4671 n = this.length - d3_geom_polygonClosed(this),
4680 input = subject.slice();
4683 c = input[(m = input.length - closed) - 1];
4687 if (d3_geom_polygonInside(d, a, b)) {
4688 if (!d3_geom_polygonInside(c, a, b)) {
4689 subject.push(d3_geom_polygonIntersect(c, d, a, b));
4692 } else if (d3_geom_polygonInside(c, a, b)) {
4693 subject.push(d3_geom_polygonIntersect(c, d, a, b));
4697 if (closed) subject.push(subject[0]);
4704 function d3_geom_polygonInside(p, a, b) {
4705 return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]);
4708 // Intersect two infinite lines cd and ab.
4709 function d3_geom_polygonIntersect(c, d, a, b) {
4710 var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3,
4711 y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3,
4712 ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21);
4713 return [x1 + ua * x21, y1 + ua * y21];
4716 // Returns true if the polygon is closed.
4717 function d3_geom_polygonClosed(coordinates) {
4718 var a = coordinates[0],
4719 b = coordinates[coordinates.length - 1];
4720 return !(a[0] - b[0] || a[1] - b[1]);
4722 function d3_geom_pointX(d) {
4726 function d3_geom_pointY(d) {
4731 * Computes the 2D convex hull of a set of points using the monotone chain
4733 * http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain)
4735 * The runtime of this algorithm is O(n log n), where n is the number of input
4736 * points. However in practice it outperforms other O(n log n) hulls.
4738 * @param vertices [[x1, y1], [x2, y2], ...]
4739 * @returns polygon [[x1, y1], [x2, y2], ...]
4741 d3.geom.hull = function(vertices) {
4742 var x = d3_geom_pointX,
4745 if (arguments.length) return hull(vertices);
4747 function hull(data) {
4748 // Hull of < 3 points is not well-defined
4749 if (data.length < 3) return [];
4751 var fx = d3_functor(x),
4755 points = [], // of the form [[x0, y0, 0], ..., [xn, yn, n]]
4758 for (i = 0 ; i < n; i++) {
4759 points.push([+fx.call(this, data[i], i), +fy.call(this, data[i], i), i]);
4762 // sort ascending by x-coord first, y-coord second
4763 points.sort(d3_geom_hullOrder);
4765 // we flip bottommost points across y axis so we can use the upper hull routine on both
4766 for (i = 0; i < n; i++) flippedPoints.push([points[i][0], -points[i][1]]);
4768 var upper = d3_geom_hullUpper(points),
4769 lower = d3_geom_hullUpper(flippedPoints);
4771 // construct the polygon, removing possible duplicate endpoints
4772 var skipLeft = lower[0] === upper[0],
4773 skipRight = lower[lower.length - 1] === upper[upper.length - 1],
4776 // add upper hull in r->l order
4777 // then add lower hull in l->r order
4778 for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]);
4779 for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]);
4784 hull.x = function(_) {
4785 return arguments.length ? (x = _, hull) : x;
4788 hull.y = function(_) {
4789 return arguments.length ? (y = _, hull) : y;
4795 // finds the 'upper convex hull' (see wiki link above)
4796 // assumes points arg has >=3 elements, is sorted by x, unique in y
4797 // returns array of indices into points in left to right order
4798 function d3_geom_hullUpper(points) {
4799 var n = points.length,
4801 hs = 2; // hull size
4803 for (var i = 2; i < n; i++) {
4804 while (hs > 1 && d3_cross2d(points[hull[hs-2]], points[hull[hs-1]], points[i]) <= 0) --hs;
4808 // we slice to make sure that the points we 'popped' from hull don't stay behind
4809 return hull.slice(0, hs);
4812 // comparator for ascending sort by x-coord first, y-coord second
4813 function d3_geom_hullOrder(a, b) {
4814 return a[0] - b[0] || a[1] - b[1];
4816 // import "../transition/transition";
4818 d3_selectionPrototype.transition = function(name) {
4819 var id = d3_transitionInheritId || ++d3_transitionId,
4820 ns = d3_transitionNamespace(name),
4824 transition = d3_transitionInherit || {time: Date.now(), ease: d3_ease_cubicInOut, delay: 0, duration: 250};
4826 for (var j = -1, m = this.length; ++j < m;) {
4827 subgroups.push(subgroup = []);
4828 for (var group = this[j], i = -1, n = group.length; ++i < n;) {
4829 if (node = group[i]) d3_transitionNode(node, i, ns, id, transition);
4830 subgroup.push(node);
4834 return d3_transition(subgroups, ns, id);
4836 // import "../transition/transition";
4838 // TODO Interrupt transitions for all namespaces?
4839 d3_selectionPrototype.interrupt = function(name) {
4840 return this.each(name == null
4841 ? d3_selection_interrupt
4842 : d3_selection_interruptNS(d3_transitionNamespace(name)));
4845 var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace());
4847 function d3_selection_interruptNS(ns) {
4850 if ((lock = this[ns]) && (active = lock[lock.active])) {
4851 if (--lock.count) delete lock[lock.active];
4852 else delete this[ns];
4854 active.event && active.event.interrupt.call(this, this.__data__, active.index);
4859 function d3_transition(groups, ns, id) {
4860 d3_subclass(groups, d3_transitionPrototype);
4863 groups.namespace = ns;
4869 var d3_transitionPrototype = [],
4870 d3_transitionId = 0,
4871 d3_transitionInheritId,
4872 d3_transitionInherit;
4874 d3_transitionPrototype.call = d3_selectionPrototype.call;
4875 d3_transitionPrototype.empty = d3_selectionPrototype.empty;
4876 d3_transitionPrototype.node = d3_selectionPrototype.node;
4877 d3_transitionPrototype.size = d3_selectionPrototype.size;
4879 d3.transition = function(selection, name) {
4880 return selection && selection.transition
4881 ? (d3_transitionInheritId ? selection.transition(name) : selection)
4882 : d3.selection().transition(selection);
4885 d3.transition.prototype = d3_transitionPrototype;
4888 d3_transitionPrototype.select = function(selector) {
4890 ns = this.namespace,
4896 selector = d3_selection_selector(selector);
4898 for (var j = -1, m = this.length; ++j < m;) {
4899 subgroups.push(subgroup = []);
4900 for (var group = this[j], i = -1, n = group.length; ++i < n;) {
4901 if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) {
4902 if ("__data__" in node) subnode.__data__ = node.__data__;
4903 d3_transitionNode(subnode, i, ns, id, node[ns][id]);
4904 subgroup.push(subnode);
4906 subgroup.push(null);
4911 return d3_transition(subgroups, ns, id);
4914 d3_transitionPrototype.selectAll = function(selector) {
4916 ns = this.namespace,
4924 selector = d3_selection_selectorAll(selector);
4926 for (var j = -1, m = this.length; ++j < m;) {
4927 for (var group = this[j], i = -1, n = group.length; ++i < n;) {
4928 if (node = group[i]) {
4929 transition = node[ns][id];
4930 subnodes = selector.call(node, node.__data__, i, j);
4931 subgroups.push(subgroup = []);
4932 for (var k = -1, o = subnodes.length; ++k < o;) {
4933 if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition);
4934 subgroup.push(subnode);
4940 return d3_transition(subgroups, ns, id);
4943 d3_transitionPrototype.filter = function(filter) {
4949 if (typeof filter !== "function") filter = d3_selection_filter(filter);
4951 for (var j = 0, m = this.length; j < m; j++) {
4952 subgroups.push(subgroup = []);
4953 for (var group = this[j], i = 0, n = group.length; i < n; i++) {
4954 if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
4955 subgroup.push(node);
4960 return d3_transition(subgroups, this.namespace, this.id);
4962 d3.color = d3_color;
4964 function d3_color() {}
4966 d3_color.prototype.toString = function() {
4967 return this.rgb() + "";
4972 function d3_hsl(h, s, l) {
4973 return this instanceof d3_hsl ? void (this.h = +h, this.s = +s, this.l = +l)
4974 : arguments.length < 2 ? (h instanceof d3_hsl ? new d3_hsl(h.h, h.s, h.l)
4975 : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl))
4976 : new d3_hsl(h, s, l);
4979 var d3_hslPrototype = d3_hsl.prototype = new d3_color;
4981 d3_hslPrototype.brighter = function(k) {
4982 k = Math.pow(0.7, arguments.length ? k : 1);
4983 return new d3_hsl(this.h, this.s, this.l / k);
4986 d3_hslPrototype.darker = function(k) {
4987 k = Math.pow(0.7, arguments.length ? k : 1);
4988 return new d3_hsl(this.h, this.s, k * this.l);
4991 d3_hslPrototype.rgb = function() {
4992 return d3_hsl_rgb(this.h, this.s, this.l);
4995 function d3_hsl_rgb(h, s, l) {
4999 /* Some simple corrections for h, s and l. */
5000 h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h;
5001 s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s;
5002 l = l < 0 ? 0 : l > 1 ? 1 : l;
5004 /* From FvD 13.37, CSS Color Module Level 3 */
5005 m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
5009 if (h > 360) h -= 360;
5010 else if (h < 0) h += 360;
5011 if (h < 60) return m1 + (m2 - m1) * h / 60;
5012 if (h < 180) return m2;
5013 if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
5018 return Math.round(v(h) * 255);
5021 return new d3_rgb(vv(h + 120), vv(h), vv(h - 120));
5026 function d3_hcl(h, c, l) {
5027 return this instanceof d3_hcl ? void (this.h = +h, this.c = +c, this.l = +l)
5028 : arguments.length < 2 ? (h instanceof d3_hcl ? new d3_hcl(h.h, h.c, h.l)
5029 : (h instanceof d3_lab ? d3_lab_hcl(h.l, h.a, h.b)
5030 : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b)))
5031 : new d3_hcl(h, c, l);
5034 var d3_hclPrototype = d3_hcl.prototype = new d3_color;
5036 d3_hclPrototype.brighter = function(k) {
5037 return new d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)));
5040 d3_hclPrototype.darker = function(k) {
5041 return new d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)));
5044 d3_hclPrototype.rgb = function() {
5045 return d3_hcl_lab(this.h, this.c, this.l).rgb();
5048 function d3_hcl_lab(h, c, l) {
5049 if (isNaN(h)) h = 0;
5050 if (isNaN(c)) c = 0;
5051 return new d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c);
5056 function d3_lab(l, a, b) {
5057 return this instanceof d3_lab ? void (this.l = +l, this.a = +a, this.b = +b)
5058 : arguments.length < 2 ? (l instanceof d3_lab ? new d3_lab(l.l, l.a, l.b)
5059 : (l instanceof d3_hcl ? d3_hcl_lab(l.h, l.c, l.l)
5060 : d3_rgb_lab((l = d3_rgb(l)).r, l.g, l.b)))
5061 : new d3_lab(l, a, b);
5064 // Corresponds roughly to RGB brighter/darker
5067 // D65 standard referent
5068 var d3_lab_X = 0.950470,
5070 d3_lab_Z = 1.088830;
5072 var d3_labPrototype = d3_lab.prototype = new d3_color;
5074 d3_labPrototype.brighter = function(k) {
5075 return new d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
5078 d3_labPrototype.darker = function(k) {
5079 return new d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b);
5082 d3_labPrototype.rgb = function() {
5083 return d3_lab_rgb(this.l, this.a, this.b);
5086 function d3_lab_rgb(l, a, b) {
5087 var y = (l + 16) / 116,
5090 x = d3_lab_xyz(x) * d3_lab_X;
5091 y = d3_lab_xyz(y) * d3_lab_Y;
5092 z = d3_lab_xyz(z) * d3_lab_Z;
5094 d3_xyz_rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z),
5095 d3_xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
5096 d3_xyz_rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z)
5100 function d3_lab_hcl(l, a, b) {
5102 ? new d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l)
5103 : new d3_hcl(NaN, NaN, l);
5106 function d3_lab_xyz(x) {
5107 return x > 0.206893034 ? x * x * x : (x - 4 / 29) / 7.787037;
5109 function d3_xyz_lab(x) {
5110 return x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29;
5113 function d3_xyz_rgb(r) {
5114 return Math.round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - 0.055));
5119 function d3_rgb(r, g, b) {
5120 return this instanceof d3_rgb ? void (this.r = ~~r, this.g = ~~g, this.b = ~~b)
5121 : arguments.length < 2 ? (r instanceof d3_rgb ? new d3_rgb(r.r, r.g, r.b)
5122 : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb))
5123 : new d3_rgb(r, g, b);
5126 function d3_rgbNumber(value) {
5127 return new d3_rgb(value >> 16, value >> 8 & 0xff, value & 0xff);
5130 function d3_rgbString(value) {
5131 return d3_rgbNumber(value) + "";
5134 var d3_rgbPrototype = d3_rgb.prototype = new d3_color;
5136 d3_rgbPrototype.brighter = function(k) {
5137 k = Math.pow(0.7, arguments.length ? k : 1);
5142 if (!r && !g && !b) return new d3_rgb(i, i, i);
5143 if (r && r < i) r = i;
5144 if (g && g < i) g = i;
5145 if (b && b < i) b = i;
5146 return new d3_rgb(Math.min(255, r / k), Math.min(255, g / k), Math.min(255, b / k));
5149 d3_rgbPrototype.darker = function(k) {
5150 k = Math.pow(0.7, arguments.length ? k : 1);
5151 return new d3_rgb(k * this.r, k * this.g, k * this.b);
5154 d3_rgbPrototype.hsl = function() {
5155 return d3_rgb_hsl(this.r, this.g, this.b);
5158 d3_rgbPrototype.toString = function() {
5159 return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
5162 function d3_rgb_hex(v) {
5164 ? "0" + Math.max(0, v).toString(16)
5165 : Math.min(255, v).toString(16);
5168 function d3_rgb_parse(format, rgb, hsl) {
5169 var r = 0, // red channel; int in [0, 255]
5170 g = 0, // green channel; int in [0, 255]
5171 b = 0, // blue channel; int in [0, 255]
5172 m1, // CSS color specification match
5173 m2, // CSS color specification type (e.g., rgb)
5176 /* Handle hsl, rgb. */
5177 m1 = /([a-z]+)\((.*)\)/i.exec(format);
5179 m2 = m1[2].split(",");
5183 parseFloat(m2[0]), // degrees
5184 parseFloat(m2[1]) / 100, // percentage
5185 parseFloat(m2[2]) / 100 // percentage
5190 d3_rgb_parseNumber(m2[0]),
5191 d3_rgb_parseNumber(m2[1]),
5192 d3_rgb_parseNumber(m2[2])
5199 if (color = d3_rgb_names.get(format.toLowerCase())) {
5200 return rgb(color.r, color.g, color.b);
5203 /* Hexadecimal colors: #rgb and #rrggbb. */
5204 if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.slice(1), 16))) {
5205 if (format.length === 4) {
5206 r = (color & 0xf00) >> 4; r = (r >> 4) | r;
5207 g = (color & 0xf0); g = (g >> 4) | g;
5208 b = (color & 0xf); b = (b << 4) | b;
5209 } else if (format.length === 7) {
5210 r = (color & 0xff0000) >> 16;
5211 g = (color & 0xff00) >> 8;
5216 return rgb(r, g, b);
5219 function d3_rgb_hsl(r, g, b) {
5220 var min = Math.min(r /= 255, g /= 255, b /= 255),
5221 max = Math.max(r, g, b),
5225 l = (max + min) / 2;
5227 s = l < .5 ? d / (max + min) : d / (2 - max - min);
5228 if (r == max) h = (g - b) / d + (g < b ? 6 : 0);
5229 else if (g == max) h = (b - r) / d + 2;
5230 else h = (r - g) / d + 4;
5234 s = l > 0 && l < 1 ? 0 : h;
5236 return new d3_hsl(h, s, l);
5239 function d3_rgb_lab(r, g, b) {
5243 var x = d3_xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / d3_lab_X),
5244 y = d3_xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / d3_lab_Y),
5245 z = d3_xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / d3_lab_Z);
5246 return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z));
5249 function d3_rgb_xyz(r) {
5250 return (r /= 255) <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
5253 function d3_rgb_parseNumber(c) { // either integer or percentage
5254 var f = parseFloat(c);
5255 return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
5258 var d3_rgb_names = d3.map({
5259 aliceblue: 0xf0f8ff,
5260 antiquewhite: 0xfaebd7,
5262 aquamarine: 0x7fffd4,
5267 blanchedalmond: 0xffebcd,
5269 blueviolet: 0x8a2be2,
5271 burlywood: 0xdeb887,
5272 cadetblue: 0x5f9ea0,
5273 chartreuse: 0x7fff00,
5274 chocolate: 0xd2691e,
5276 cornflowerblue: 0x6495ed,
5282 darkgoldenrod: 0xb8860b,
5284 darkgreen: 0x006400,
5286 darkkhaki: 0xbdb76b,
5287 darkmagenta: 0x8b008b,
5288 darkolivegreen: 0x556b2f,
5289 darkorange: 0xff8c00,
5290 darkorchid: 0x9932cc,
5292 darksalmon: 0xe9967a,
5293 darkseagreen: 0x8fbc8f,
5294 darkslateblue: 0x483d8b,
5295 darkslategray: 0x2f4f4f,
5296 darkslategrey: 0x2f4f4f,
5297 darkturquoise: 0x00ced1,
5298 darkviolet: 0x9400d3,
5300 deepskyblue: 0x00bfff,
5303 dodgerblue: 0x1e90ff,
5304 firebrick: 0xb22222,
5305 floralwhite: 0xfffaf0,
5306 forestgreen: 0x228b22,
5308 gainsboro: 0xdcdcdc,
5309 ghostwhite: 0xf8f8ff,
5311 goldenrod: 0xdaa520,
5314 greenyellow: 0xadff2f,
5318 indianred: 0xcd5c5c,
5323 lavenderblush: 0xfff0f5,
5324 lawngreen: 0x7cfc00,
5325 lemonchiffon: 0xfffacd,
5326 lightblue: 0xadd8e6,
5327 lightcoral: 0xf08080,
5328 lightcyan: 0xe0ffff,
5329 lightgoldenrodyellow: 0xfafad2,
5330 lightgray: 0xd3d3d3,
5331 lightgreen: 0x90ee90,
5332 lightgrey: 0xd3d3d3,
5333 lightpink: 0xffb6c1,
5334 lightsalmon: 0xffa07a,
5335 lightseagreen: 0x20b2aa,
5336 lightskyblue: 0x87cefa,
5337 lightslategray: 0x778899,
5338 lightslategrey: 0x778899,
5339 lightsteelblue: 0xb0c4de,
5340 lightyellow: 0xffffe0,
5342 limegreen: 0x32cd32,
5346 mediumaquamarine: 0x66cdaa,
5347 mediumblue: 0x0000cd,
5348 mediumorchid: 0xba55d3,
5349 mediumpurple: 0x9370db,
5350 mediumseagreen: 0x3cb371,
5351 mediumslateblue: 0x7b68ee,
5352 mediumspringgreen: 0x00fa9a,
5353 mediumturquoise: 0x48d1cc,
5354 mediumvioletred: 0xc71585,
5355 midnightblue: 0x191970,
5356 mintcream: 0xf5fffa,
5357 mistyrose: 0xffe4e1,
5359 navajowhite: 0xffdead,
5363 olivedrab: 0x6b8e23,
5365 orangered: 0xff4500,
5367 palegoldenrod: 0xeee8aa,
5368 palegreen: 0x98fb98,
5369 paleturquoise: 0xafeeee,
5370 palevioletred: 0xdb7093,
5371 papayawhip: 0xffefd5,
5372 peachpuff: 0xffdab9,
5376 powderblue: 0xb0e0e6,
5378 rebeccapurple: 0x663399,
5380 rosybrown: 0xbc8f8f,
5381 royalblue: 0x4169e1,
5382 saddlebrown: 0x8b4513,
5384 sandybrown: 0xf4a460,
5390 slateblue: 0x6a5acd,
5391 slategray: 0x708090,
5392 slategrey: 0x708090,
5394 springgreen: 0x00ff7f,
5395 steelblue: 0x4682b4,
5400 turquoise: 0x40e0d0,
5404 whitesmoke: 0xf5f5f5,
5406 yellowgreen: 0x9acd32
5409 d3_rgb_names.forEach(function(key, value) {
5410 d3_rgb_names.set(key, d3_rgbNumber(value));
5413 d3.interpolateRgb = d3_interpolateRgb;
5415 function d3_interpolateRgb(a, b) {
5424 return function(t) {
5426 + d3_rgb_hex(Math.round(ar + br * t))
5427 + d3_rgb_hex(Math.round(ag + bg * t))
5428 + d3_rgb_hex(Math.round(ab + bb * t));
5432 d3.interpolateObject = d3_interpolateObject;
5434 function d3_interpolateObject(a, b) {
5440 i[k] = d3_interpolate(a[k], b[k]);
5450 return function(t) {
5451 for (k in i) c[k] = i[k](t);
5456 d3.interpolateArray = d3_interpolateArray;
5458 function d3_interpolateArray(a, b) {
5463 n0 = Math.min(a.length, b.length),
5465 for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i]));
5466 for (; i < na; ++i) c[i] = a[i];
5467 for (; i < nb; ++i) c[i] = b[i];
5468 return function(t) {
5469 for (i = 0; i < n0; ++i) c[i] = x[i](t);
5473 d3.interpolateNumber = d3_interpolateNumber;
5475 function d3_interpolateNumber(a, b) {
5477 return function(t) { return a * (1 - t) + b * t; };
5480 d3.interpolateString = d3_interpolateString;
5482 function d3_interpolateString(a, b) {
5483 var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, // scan index for next number in b
5484 am, // current match in a
5485 bm, // current match in b
5486 bs, // string preceding current number in b, if any
5487 i = -1, // index in s
5488 s = [], // string constants and placeholders
5489 q = []; // number interpolators
5491 // Coerce inputs to strings.
5492 a = a + "", b = b + "";
5494 // Interpolate pairs of numbers in a & b.
5495 while ((am = d3_interpolate_numberA.exec(a))
5496 && (bm = d3_interpolate_numberB.exec(b))) {
5497 if ((bs = bm.index) > bi) { // a string precedes the next number in b
5498 bs = b.slice(bi, bs);
5499 if (s[i]) s[i] += bs; // coalesce with previous string
5502 if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
5503 if (s[i]) s[i] += bm; // coalesce with previous string
5505 } else { // interpolate non-matching numbers
5507 q.push({i: i, x: d3_interpolateNumber(am, bm)});
5509 bi = d3_interpolate_numberB.lastIndex;
5512 // Add remains of b.
5513 if (bi < b.length) {
5515 if (s[i]) s[i] += bs; // coalesce with previous string
5519 // Special optimization for only a single match.
5520 // Otherwise, interpolate each of the numbers and rejoin the string.
5522 ? (q[0] ? (b = q[0].x, function(t) { return b(t) + ""; })
5523 : function() { return b; })
5524 : (b = q.length, function(t) {
5525 for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
5530 var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
5531 d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g");
5533 d3.interpolate = d3_interpolate;
5535 function d3_interpolate(a, b) {
5536 var i = d3.interpolators.length, f;
5537 while (--i >= 0 && !(f = d3.interpolators[i](a, b)));
5541 d3.interpolators = [
5544 return (t === "string" ? (d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString)
5545 : b instanceof d3_color ? d3_interpolateRgb
5546 : Array.isArray(b) ? d3_interpolateArray
5547 : t === "object" && isNaN(b) ? d3_interpolateObject
5548 : d3_interpolateNumber)(a, b);
5552 d3.transform = function(string) {
5553 var g = d3_document.createElementNS(d3.ns.prefix.svg, "g");
5554 return (d3.transform = function(string) {
5555 if (string != null) {
5556 g.setAttribute("transform", string);
5557 var t = g.transform.baseVal.consolidate();
5559 return new d3_transform(t ? t.matrix : d3_transformIdentity);
5563 // Compute x-scale and normalize the first row.
5564 // Compute shear and make second row orthogonal to first.
5565 // Compute y-scale and normalize the second row.
5566 // Finally, compute the rotation.
5567 function d3_transform(m) {
5568 var r0 = [m.a, m.b],
5570 kx = d3_transformNormalize(r0),
5571 kz = d3_transformDot(r0, r1),
5572 ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0;
5573 if (r0[0] * r1[1] < r1[0] * r0[1]) {
5579 this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees;
5580 this.translate = [m.e, m.f];
5581 this.scale = [kx, ky];
5582 this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0;
5585 d3_transform.prototype.toString = function() {
5586 return "translate(" + this.translate
5587 + ")rotate(" + this.rotate
5588 + ")skewX(" + this.skew
5589 + ")scale(" + this.scale
5593 function d3_transformDot(a, b) {
5594 return a[0] * b[0] + a[1] * b[1];
5597 function d3_transformNormalize(a) {
5598 var k = Math.sqrt(d3_transformDot(a, a));
5606 function d3_transformCombine(a, b, k) {
5612 var d3_transformIdentity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0};
5614 d3.interpolateTransform = d3_interpolateTransform;
5616 function d3_interpolateTransform(a, b) {
5617 var s = [], // string constants and placeholders
5618 q = [], // number interpolators
5620 A = d3.transform(a),
5621 B = d3.transform(b),
5631 if (ta[0] != tb[0] || ta[1] != tb[1]) {
5632 s.push("translate(", null, ",", null, ")");
5633 q.push({i: 1, x: d3_interpolateNumber(ta[0], tb[0])}, {i: 3, x: d3_interpolateNumber(ta[1], tb[1])});
5634 } else if (tb[0] || tb[1]) {
5635 s.push("translate(" + tb + ")");
5641 if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; // shortest path
5642 q.push({i: s.push(s.pop() + "rotate(", null, ")") - 2, x: d3_interpolateNumber(ra, rb)});
5644 s.push(s.pop() + "rotate(" + rb + ")");
5648 q.push({i: s.push(s.pop() + "skewX(", null, ")") - 2, x: d3_interpolateNumber(wa, wb)});
5650 s.push(s.pop() + "skewX(" + wb + ")");
5653 if (ka[0] != kb[0] || ka[1] != kb[1]) {
5654 n = s.push(s.pop() + "scale(", null, ",", null, ")");
5655 q.push({i: n - 4, x: d3_interpolateNumber(ka[0], kb[0])}, {i: n - 2, x: d3_interpolateNumber(ka[1], kb[1])});
5656 } else if (kb[0] != 1 || kb[1] != 1) {
5657 s.push(s.pop() + "scale(" + kb + ")");
5661 return function(t) {
5663 while (++i < n) s[(o = q[i]).i] = o.x(t);
5668 d3_transitionPrototype.tween = function(name, tween) {
5669 var id = this.id, ns = this.namespace;
5670 if (arguments.length < 2) return this.node()[ns][id].tween.get(name);
5671 return d3_selection_each(this, tween == null
5672 ? function(node) { node[ns][id].tween.remove(name); }
5673 : function(node) { node[ns][id].tween.set(name, tween); });
5676 function d3_transition_tween(groups, name, value, tween) {
5677 var id = groups.id, ns = groups.namespace;
5678 return d3_selection_each(groups, typeof value === "function"
5679 ? function(node, i, j) { node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j))); }
5680 : (value = tween(value), function(node) { node[ns][id].tween.set(name, value); }));
5683 d3_transitionPrototype.attr = function(nameNS, value) {
5684 if (arguments.length < 2) {
5686 // For attr(object), the object specifies the names and values of the
5687 // attributes to transition. The values may be functions that are
5688 // evaluated for each element.
5689 for (value in nameNS) this.attr(value, nameNS[value]);
5693 var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate,
5694 name = d3.ns.qualify(nameNS);
5696 // For attr(string, null), remove the attribute with the specified name.
5697 function attrNull() {
5698 this.removeAttribute(name);
5700 function attrNullNS() {
5701 this.removeAttributeNS(name.space, name.local);
5704 // For attr(string, string), set the attribute with the specified name.
5705 function attrTween(b) {
5706 return b == null ? attrNull : (b += "", function() {
5707 var a = this.getAttribute(name), i;
5708 return a !== b && (i = interpolate(a, b), function(t) { this.setAttribute(name, i(t)); });
5711 function attrTweenNS(b) {
5712 return b == null ? attrNullNS : (b += "", function() {
5713 var a = this.getAttributeNS(name.space, name.local), i;
5714 return a !== b && (i = interpolate(a, b), function(t) { this.setAttributeNS(name.space, name.local, i(t)); });
5718 return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween);
5721 d3_transitionPrototype.attrTween = function(nameNS, tween) {
5722 var name = d3.ns.qualify(nameNS);
5724 function attrTween(d, i) {
5725 var f = tween.call(this, d, i, this.getAttribute(name));
5726 return f && function(t) { this.setAttribute(name, f(t)); };
5728 function attrTweenNS(d, i) {
5729 var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
5730 return f && function(t) { this.setAttributeNS(name.space, name.local, f(t)); };
5733 return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
5736 d3_transitionPrototype.style = function(name, value, priority) {
5737 var n = arguments.length;
5740 // For style(object) or style(object, string), the object specifies the
5741 // names and values of the attributes to set or remove. The values may be
5742 // functions that are evaluated for each element. The optional string
5743 // specifies the priority.
5744 if (typeof name !== "string") {
5745 if (n < 2) value = "";
5746 for (priority in name) this.style(priority, name[priority], value);
5750 // For style(string, string) or style(string, function), use the default
5751 // priority. The priority is ignored for style(string, null).
5755 // For style(name, null) or style(name, null, priority), remove the style
5756 // property with the specified name. The priority is ignored.
5757 function styleNull() {
5758 this.style.removeProperty(name);
5761 // For style(name, string) or style(name, string, priority), set the style
5762 // property with the specified name, using the specified priority.
5763 // Otherwise, a name, value and priority are specified, and handled as below.
5764 function styleString(b) {
5765 return b == null ? styleNull : (b += "", function() {
5766 var a = d3_window(this).getComputedStyle(this, null).getPropertyValue(name), i;
5767 return a !== b && (i = d3_interpolate(a, b), function(t) { this.style.setProperty(name, i(t), priority); });
5771 return d3_transition_tween(this, "style." + name, value, styleString);
5774 d3_transitionPrototype.styleTween = function(name, tween, priority) {
5775 if (arguments.length < 3) priority = "";
5777 function styleTween(d, i) {
5778 var f = tween.call(this, d, i, d3_window(this).getComputedStyle(this, null).getPropertyValue(name));
5779 return f && function(t) { this.style.setProperty(name, f(t), priority); };
5782 return this.tween("style." + name, styleTween);
5785 d3_transitionPrototype.text = function(value) {
5786 return d3_transition_tween(this, "text", value, d3_transition_text);
5789 function d3_transition_text(b) {
5790 if (b == null) b = "";
5791 return function() { this.textContent = b; };
5794 d3_transitionPrototype.remove = function() {
5795 var ns = this.namespace;
5796 return this.each("end.transition", function() {
5798 if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this);
5802 var d3_ease_default = function() { return d3_identity; };
5804 var d3_ease = d3.map({
5805 linear: d3_ease_default,
5807 quad: function() { return d3_ease_quad; },
5808 cubic: function() { return d3_ease_cubic; },
5809 sin: function() { return d3_ease_sin; },
5810 exp: function() { return d3_ease_exp; },
5811 circle: function() { return d3_ease_circle; },
5812 elastic: d3_ease_elastic,
5814 bounce: function() { return d3_ease_bounce; }
5817 var d3_ease_mode = d3.map({
5819 "out": d3_ease_reverse,
5820 "in-out": d3_ease_reflect,
5821 "out-in": function(f) { return d3_ease_reflect(d3_ease_reverse(f)); }
5824 d3.ease = function(name) {
5825 var i = name.indexOf("-"),
5826 t = i >= 0 ? name.slice(0, i) : name,
5827 m = i >= 0 ? name.slice(i + 1) : "in";
5828 t = d3_ease.get(t) || d3_ease_default;
5829 m = d3_ease_mode.get(m) || d3_identity;
5830 return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1))));
5833 function d3_ease_clamp(f) {
5834 return function(t) {
5835 return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
5839 function d3_ease_reverse(f) {
5840 return function(t) {
5841 return 1 - f(1 - t);
5845 function d3_ease_reflect(f) {
5846 return function(t) {
5847 return .5 * (t < .5 ? f(2 * t) : (2 - f(2 - 2 * t)));
5851 function d3_ease_quad(t) {
5855 function d3_ease_cubic(t) {
5859 // Optimized clamp(reflect(poly(3))).
5860 function d3_ease_cubicInOut(t) {
5861 if (t <= 0) return 0;
5862 if (t >= 1) return 1;
5863 var t2 = t * t, t3 = t2 * t;
5864 return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75);
5867 function d3_ease_poly(e) {
5868 return function(t) {
5869 return Math.pow(t, e);
5873 function d3_ease_sin(t) {
5874 return 1 - Math.cos(t * halfπ);
5877 function d3_ease_exp(t) {
5878 return Math.pow(2, 10 * (t - 1));
5881 function d3_ease_circle(t) {
5882 return 1 - Math.sqrt(1 - t * t);
5885 function d3_ease_elastic(a, p) {
5887 if (arguments.length < 2) p = 0.45;
5888 if (arguments.length) s = p / τ * Math.asin(1 / a);
5889 else a = 1, s = p / 4;
5890 return function(t) {
5891 return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p);
5895 function d3_ease_back(s) {
5896 if (!s) s = 1.70158;
5897 return function(t) {
5898 return t * t * ((s + 1) * t - s);
5902 function d3_ease_bounce(t) {
5903 return t < 1 / 2.75 ? 7.5625 * t * t
5904 : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75
5905 : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375
5906 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
5909 d3_transitionPrototype.ease = function(value) {
5910 var id = this.id, ns = this.namespace;
5911 if (arguments.length < 1) return this.node()[ns][id].ease;
5912 if (typeof value !== "function") value = d3.ease.apply(d3, arguments);
5913 return d3_selection_each(this, function(node) { node[ns][id].ease = value; });
5916 d3_transitionPrototype.delay = function(value) {
5917 var id = this.id, ns = this.namespace;
5918 if (arguments.length < 1) return this.node()[ns][id].delay;
5919 return d3_selection_each(this, typeof value === "function"
5920 ? function(node, i, j) { node[ns][id].delay = +value.call(node, node.__data__, i, j); }
5921 : (value = +value, function(node) { node[ns][id].delay = value; }));
5924 d3_transitionPrototype.duration = function(value) {
5925 var id = this.id, ns = this.namespace;
5926 if (arguments.length < 1) return this.node()[ns][id].duration;
5927 return d3_selection_each(this, typeof value === "function"
5928 ? function(node, i, j) { node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j)); }
5929 : (value = Math.max(1, value), function(node) { node[ns][id].duration = value; }));
5932 d3_transitionPrototype.each = function(type, listener) {
5933 var id = this.id, ns = this.namespace;
5934 if (arguments.length < 2) {
5935 var inherit = d3_transitionInherit,
5936 inheritId = d3_transitionInheritId;
5938 d3_transitionInheritId = id;
5939 d3_selection_each(this, function(node, i, j) {
5940 d3_transitionInherit = node[ns][id];
5941 type.call(node, node.__data__, i, j);
5944 d3_transitionInherit = inherit;
5945 d3_transitionInheritId = inheritId;
5948 d3_selection_each(this, function(node) {
5949 var transition = node[ns][id];
5950 (transition.event || (transition.event = d3.dispatch("start", "end", "interrupt"))).on(type, listener);
5956 d3_transitionPrototype.transition = function() {
5958 id1 = ++d3_transitionId,
5959 ns = this.namespace,
5966 for (var j = 0, m = this.length; j < m; j++) {
5967 subgroups.push(subgroup = []);
5968 for (var group = this[j], i = 0, n = group.length; i < n; i++) {
5969 if (node = group[i]) {
5970 transition = node[ns][id0];
5971 d3_transitionNode(node, i, ns, id1, {time: transition.time, ease: transition.ease, delay: transition.delay + transition.duration, duration: transition.duration});
5973 subgroup.push(node);
5977 return d3_transition(subgroups, ns, id1);
5980 function d3_transitionNamespace(name) {
5981 return name == null ? "__transition__" : "__transition_" + name + "__";
5984 function d3_transitionNode(node, i, ns, id, inherit) {
5985 var lock = node[ns] || (node[ns] = {active: 0, count: 0}),
5986 transition = lock[id];
5989 var time = inherit.time;
5991 transition = lock[id] = {
5994 delay: inherit.delay,
5995 duration: inherit.duration,
6000 inherit = null; // allow gc
6004 d3.timer(function(elapsed) {
6005 var delay = transition.delay,
6008 timer = d3_timer_active,
6011 timer.t = delay + time;
6012 if (delay <= elapsed) return start(elapsed - delay);
6015 function start(elapsed) {
6016 if (lock.active > id) return stop();
6018 var active = lock[lock.active];
6021 delete lock[lock.active];
6022 active.event && active.event.interrupt.call(node, node.__data__, active.index);
6027 transition.event && transition.event.start.call(node, node.__data__, i);
6029 transition.tween.forEach(function(key, value) {
6030 if (value = value.call(node, node.__data__, i)) {
6031 tweened.push(value);
6035 // Deferred capture to allow tweens to initialize ease & duration.
6036 ease = transition.ease;
6037 duration = transition.duration;
6039 d3.timer(function() { // defer to end of current frame
6040 timer.c = tick(elapsed || 1) ? d3_true : tick;
6045 function tick(elapsed) {
6046 if (lock.active !== id) return 1;
6048 var t = elapsed / duration,
6053 tweened[--n].call(node, e);
6057 transition.event && transition.event.end.call(node, node.__data__, i);
6063 if (--lock.count) delete lock[id];
6064 else delete node[ns];
6071 d3.xhr = d3_xhrType(d3_identity);
6073 function d3_xhrType(response) {
6074 return function(url, mimeType, callback) {
6075 if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, mimeType = null;
6076 return d3_xhr(url, mimeType, response, callback);
6080 function d3_xhr(url, mimeType, response, callback) {
6082 dispatch = d3.dispatch("beforesend", "progress", "load", "error"),
6084 request = new XMLHttpRequest,
6085 responseType = null;
6087 // If IE does not support CORS, use XDomainRequest.
6088 if (this.XDomainRequest
6089 && !("withCredentials" in request)
6090 && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest;
6093 ? request.onload = request.onerror = respond
6094 : request.onreadystatechange = function() { request.readyState > 3 && respond(); };
6096 function respond() {
6097 var status = request.status, result;
6098 if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) {
6100 result = response.call(xhr, request);
6102 dispatch.error.call(xhr, e);
6105 dispatch.load.call(xhr, result);
6107 dispatch.error.call(xhr, request);
6111 request.onprogress = function(event) {
6114 try { dispatch.progress.call(xhr, request); }
6115 finally { d3.event = o; }
6118 xhr.header = function(name, value) {
6119 name = (name + "").toLowerCase();
6120 if (arguments.length < 2) return headers[name];
6121 if (value == null) delete headers[name];
6122 else headers[name] = value + "";
6126 // If mimeType is non-null and no Accept header is set, a default is used.
6127 xhr.mimeType = function(value) {
6128 if (!arguments.length) return mimeType;
6129 mimeType = value == null ? null : value + "";
6133 // Specifies what type the response value should take;
6134 // for instance, arraybuffer, blob, document, or text.
6135 xhr.responseType = function(value) {
6136 if (!arguments.length) return responseType;
6137 responseType = value;
6141 // Specify how to convert the response content to a specific type;
6142 // changes the callback value on "load" events.
6143 xhr.response = function(value) {
6148 // Convenience methods.
6149 ["get", "post"].forEach(function(method) {
6150 xhr[method] = function() {
6151 return xhr.send.apply(xhr, [method].concat(d3_array(arguments)));
6155 // If callback is non-null, it will be used for error and load events.
6156 xhr.send = function(method, data, callback) {
6157 if (arguments.length === 2 && typeof data === "function") callback = data, data = null;
6158 request.open(method, url, true);
6159 if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*";
6160 if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]);
6161 if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType);
6162 if (responseType != null) request.responseType = responseType;
6163 if (callback != null) xhr.on("error", callback).on("load", function(request) { callback(null, request); });
6164 dispatch.beforesend.call(xhr, request);
6165 request.send(data == null ? null : data);
6169 xhr.abort = function() {
6174 d3.rebind(xhr, dispatch, "on");
6176 return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback));
6179 function d3_xhr_fixCallback(callback) {
6180 return callback.length === 1
6181 ? function(error, request) { callback(error == null ? request : null); }
6185 function d3_xhrHasResponse(request) {
6186 var type = request.responseType;
6187 return type && type !== "text"
6188 ? request.response // null on error
6189 : request.responseText; // "" on error
6192 d3.text = d3_xhrType(function(request) {
6193 return request.responseText;
6196 d3.json = function(url, callback) {
6197 return d3_xhr(url, "application/json", d3_json, callback);
6200 function d3_json(request) {
6201 return JSON.parse(request.responseText);
6204 d3.html = function(url, callback) {
6205 return d3_xhr(url, "text/html", d3_html, callback);
6208 function d3_html(request) {
6209 var range = d3_document.createRange();
6210 range.selectNode(d3_document.body);
6211 return range.createContextualFragment(request.responseText);
6214 d3.xml = d3_xhrType(function(request) {
6215 return request.responseXML;
6217 if (typeof define === "function" && define.amd) define(d3);
6218 else if (typeof module === "object" && module.exports) module.exports = d3;
6221 d3.combobox = function() {
6222 var event = d3.dispatch('accept'),
6226 caseSensitive = false;
6228 var fetcher = function(val, cb) {
6229 cb(data.filter(function(d) {
6233 .indexOf(val.toLowerCase()) !== -1;
6237 var combobox = function(input) {
6239 container = d3.select(document.body)
6240 .selectAll('div.combobox')
6241 .filter(function(d) { return d === input.node(); }),
6242 shown = !container.empty();
6245 .classed('combobox-input', true)
6246 .on('focus.typeahead', focus)
6247 .on('blur.typeahead', blur)
6248 .on('keydown.typeahead', keydown)
6249 .on('keyup.typeahead', keyup)
6250 .on('input.typeahead', change)
6252 var parent = this.parentNode,
6253 sibling = this.nextSibling;
6255 var caret = d3.select(parent).selectAll('.combobox-caret')
6256 .filter(function(d) { return d === input.node(); })
6257 .data([input.node()]);
6259 caret.enter().insert('div', function() { return sibling; })
6260 .attr('class', 'combobox-caret');
6263 .on('mousedown', function () {
6264 // prevent the form element from blurring. it blurs
6266 d3.event.stopPropagation();
6267 d3.event.preventDefault();
6269 input.node().focus();
6278 fetch(value(), render);
6282 window.setTimeout(hide, 150);
6287 container = d3.select(document.body)
6288 .insert('div', ':first-child')
6289 .datum(input.node())
6290 .attr('class', 'combobox')
6292 position: 'absolute',
6296 .on('mousedown', function () {
6297 // prevent moving focus out of the text field
6298 d3.event.preventDefault();
6301 d3.select(document.body)
6302 .on('scroll.combobox', render, true);
6313 d3.select(document.body)
6314 .on('scroll.combobox', null);
6320 function keydown() {
6321 switch (d3.event.keyCode) {
6322 // backspace, delete
6325 input.on('input.typeahead', function() {
6328 var start = input.property('selectionStart');
6329 input.node().setSelectionRange(start, start);
6330 input.on('input.typeahead', change);
6335 container.selectAll('a.selected').each(event.accept);
6339 d3.event.preventDefault();
6344 d3.event.preventDefault();
6349 d3.event.preventDefault();
6352 d3.event.stopPropagation();
6356 switch (d3.event.keyCode) {
6363 container.selectAll('a.selected').each(event.accept);
6370 fetch(value(), function() {
6377 idx = Math.max(Math.min(idx + dir, suggestions.length - 1), 0);
6378 input.property('value', suggestions[idx].value);
6384 var value = input.property('value'),
6385 start = input.property('selectionStart'),
6386 end = input.property('selectionEnd');
6389 value = value.substring(0, start);
6395 function fetch(v, cb) {
6396 fetcher.call(input, v, function(_) {
6402 function autocomplete() {
6403 var v = caseSensitive ? value() : value().toLowerCase();
6407 for (var i = 0; i < suggestions.length; i++) {
6408 var suggestion = suggestions[i].value,
6409 compare = caseSensitive ? suggestion : suggestion.toLowerCase();
6411 if (compare.indexOf(v) === 0) {
6413 input.property('value', suggestion);
6414 input.node().setSelectionRange(v.length, suggestion.length);
6421 if (suggestions.length >= minItems && document.activeElement === input.node()) {
6428 var options = container
6429 .selectAll('a.combobox-option')
6430 .data(suggestions, function(d) { return d.value; });
6432 options.enter().append('a')
6433 .attr('class', 'combobox-option')
6434 .text(function(d) { return d.value; });
6437 .attr('title', function(d) { return d.title; })
6438 .classed('selected', function(d, i) { return i == idx; })
6439 .on('mouseover', select)
6440 .on('click', accept)
6446 var rect = input.node().getBoundingClientRect();
6449 'left': rect.left + 'px',
6450 'width': rect.width + 'px',
6451 'top': rect.height + rect.top + 'px'
6455 function select(d, i) {
6460 function ensureVisible() {
6461 var node = container.selectAll('a.selected').node();
6462 if (node) node.scrollIntoView();
6465 function accept(d) {
6468 .property('value', d.value)
6475 combobox.fetcher = function(_) {
6476 if (!arguments.length) return fetcher;
6481 combobox.data = function(_) {
6482 if (!arguments.length) return data;
6487 combobox.minItems = function(_) {
6488 if (!arguments.length) return minItems;
6493 combobox.caseSensitive = function(_) {
6494 if (!arguments.length) return caseSensitive;
6499 return d3.rebind(combobox, event, 'on');
6502 d3.combobox.off = function(input) {
6507 .on('focus.typeahead', null)
6508 .on('blur.typeahead', null)
6509 .on('keydown.typeahead', null)
6510 .on('keyup.typeahead', null)
6511 .on('input.typeahead', null)
6513 d3.select(this.parentNode).selectAll('.combobox-caret')
6514 .filter(function(d) { return d === input.node(); })
6515 .on('mousedown', null);
6518 d3.select(document.body)
6519 .on('scroll.combobox', null);
6521 d3.geo.tile = function() {
6522 var size = [960, 500],
6524 scaleExtent = [0, 20],
6525 translate = [size[0] / 2, size[1] / 2],
6529 return Math.min(scaleExtent[1], Math.max(scaleExtent[0], _));
6533 var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
6534 z0 = bound(Math.round(z + zoomDelta)),
6535 k = Math.pow(2, z - z0 + 8),
6536 origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
6538 cols = d3.range(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
6539 rows = d3.range(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
6541 rows.forEach(function(y) {
6542 cols.forEach(function(x) {
6543 tiles.push([x, y, z0]);
6547 tiles.translate = origin;
6553 tile.scaleExtent = function(_) {
6554 if (!arguments.length) return scaleExtent;
6559 tile.size = function(_) {
6560 if (!arguments.length) return size;
6565 tile.scale = function(_) {
6566 if (!arguments.length) return scale;
6571 tile.translate = function(_) {
6572 if (!arguments.length) return translate;
6577 tile.zoomDelta = function(_) {
6578 if (!arguments.length) return zoomDelta;
6585 d3.jsonp = function (url, callback) {
6587 var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
6589 while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
6593 function create(url) {
6594 var e = url.match(/callback=d3.jsonp.(\w+)/),
6595 c = e ? e[1] : rand();
6596 d3.jsonp[c] = function(data) {
6601 return 'd3.jsonp.' + c;
6604 var cb = create(url),
6605 script = d3.select('head')
6607 .attr('type', 'text/javascript')
6608 .attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
6611 * This code is licensed under the MIT license.
6613 * Copyright © 2013, iD authors.
6615 * Portions copyright © 2011, Keith Cirkel
6616 * See https://github.com/keithamus/jwerty
6619 d3.keybinding = function(namespace) {
6622 function matches(binding, event) {
6623 for (var p in binding.event) {
6624 if (event[p] != binding.event[p])
6628 return (!binding.capture) === (event.eventPhase !== Event.CAPTURING_PHASE);
6631 function capture() {
6632 for (var i = 0; i < bindings.length; i++) {
6633 var binding = bindings[i];
6634 if (matches(binding, d3.event)) {
6641 var tagName = d3.select(d3.event.target).node().tagName;
6642 if (tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA') {
6648 function keybinding(selection) {
6649 selection = selection || d3.select(document);
6650 selection.on('keydown.capture' + namespace, capture, true);
6651 selection.on('keydown.bubble' + namespace, bubble, false);
6655 keybinding.off = function(selection) {
6656 selection = selection || d3.select(document);
6657 selection.on('keydown.capture' + namespace, null);
6658 selection.on('keydown.bubble' + namespace, null);
6662 keybinding.on = function(code, callback, capture) {
6675 code = code.toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
6677 for (var i = 0; i < code.length; i++) {
6678 // Normalise matching errors
6679 if (code[i] === '++') code[i] = '+';
6681 if (code[i] in d3.keybinding.modifierCodes) {
6682 binding.event[d3.keybinding.modifierProperties[d3.keybinding.modifierCodes[code[i]]]] = true;
6683 } else if (code[i] in d3.keybinding.keyCodes) {
6684 binding.event.keyCode = d3.keybinding.keyCodes[code[i]];
6688 bindings.push(binding);
6697 d3.keybinding.modifierCodes = {
6700 // CTRL key, on Mac: ⌃
6702 // ALT key, on Mac: ⌥ (Alt)
6703 '⌥': 18, alt: 18, option: 18,
6704 // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
6705 '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
6708 d3.keybinding.modifierProperties = {
6715 d3.keybinding.keyCodes = {
6716 // Backspace key, on Mac: ⌫ (Backspace)
6717 '⌫': 8, backspace: 8,
6718 // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
6719 '⇥': 9, '⇆': 9, tab: 9,
6721 '↩': 13, 'return': 13, enter: 13, '⌅': 13,
6723 'pause': 19, 'pause-break': 19,
6725 '⇪': 20, caps: 20, 'caps-lock': 20,
6726 // Escape key, on Mac: ⎋, on Windows: Esc
6727 '⎋': 27, escape: 27, esc: 27,
6730 // Page-Up key, or pgup, on Mac: ↖
6731 '↖': 33, pgup: 33, 'page-up': 33,
6732 // Page-Down key, or pgdown, on Mac: ↘
6733 '↘': 34, pgdown: 34, 'page-down': 34,
6734 // END key, on Mac: ⇟
6736 // HOME key, on Mac: ⇞
6738 // Insert key, or ins
6739 ins: 45, insert: 45,
6740 // Delete key, on Mac: ⌦ (Delete)
6741 '⌦': 46, del: 46, 'delete': 46,
6742 // Left Arrow Key, or ←
6743 '←': 37, left: 37, 'arrow-left': 37,
6744 // Up Arrow Key, or ↑
6745 '↑': 38, up: 38, 'arrow-up': 38,
6746 // Right Arrow Key, or →
6747 '→': 39, right: 39, 'arrow-right': 39,
6748 // Up Arrow Key, or ↓
6749 '↓': 40, down: 40, 'arrow-down': 40,
6750 // odities, printing characters that come out wrong:
6753 // Num-Multiply, or *
6754 '*': 106, star: 106, asterisk: 106, multiply: 106,
6756 '+': 107, 'plus': 107,
6757 // Num-Subtract, or -
6758 '-': 109, subtract: 109,
6764 ';': 186, semicolon: 186,
6766 '=': 187, 'equals': 187,
6768 ',': 188, comma: 188,
6770 // Period, or ., or full-stop
6771 '.': 190, period: 190, 'full-stop': 190,
6772 // Slash, or /, or forward-slash
6773 '/': 191, slash: 191, 'forward-slash': 191,
6774 // Tick, or `, or back-quote
6775 '`': 192, tick: 192, 'back-quote': 192,
6776 // Open bracket, or [
6777 '[': 219, 'open-bracket': 219,
6779 '\\': 220, 'back-slash': 220,
6780 // Close backet, or ]
6781 ']': 221, 'close-bracket': 221,
6782 // Apostrophe, or Quote, or '
6783 '\'': 222, quote: 222, apostrophe: 222
6789 d3.keybinding.keyCodes['num-' + n] = i;
6796 d3.keybinding.keyCodes[n] = i;
6803 d3.keybinding.keyCodes['f' + n] = i;
6810 d3.keybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i;
6813 d3.selection.prototype.one = function (type, listener, capture) {
6814 var target = this, typeOnce = type + ".once";
6816 target.on(typeOnce, null);
6817 listener.apply(this, arguments);
6819 target.on(typeOnce, one, capture);
6822 d3.selection.prototype.dimensions = function (dimensions) {
6823 var refresh = (function(node) {
6824 var cr = node.getBoundingClientRect();
6825 prop = [cr.width, cr.height];
6826 this.property('__dimensions__', prop);
6830 var node = this.node();
6832 if (!arguments.length) {
6833 if (!node) return [0,0];
6834 return this.property('__dimensions__') || refresh(node);
6836 if (dimensions === null) {
6837 if (!node) return [0,0];
6838 return refresh(node);
6842 .property('__dimensions__', [dimensions[0], dimensions[1]])
6843 .attr({width: dimensions[0], height: dimensions[1]});
6845 d3.selection.prototype.trigger = function (type) {
6846 this.each(function() {
6847 var evt = document.createEvent('HTMLEvents');
6848 evt.initEvent(type, true, true);
6849 this.dispatchEvent(evt);
6852 // Tooltips and svg mask used to highlight certain features
6853 d3.curtain = function() {
6855 var event = d3.dispatch(),
6860 function curtain(selection) {
6862 surface = selection.append('svg')
6863 .attr('id', 'curtain')
6866 'pointer-events': 'none',
6867 'position': 'absolute',
6872 darkness = surface.append('path')
6876 'class': 'curtain-darkness'
6879 d3.select(window).on('resize.curtain', resize);
6881 tooltip = selection.append('div')
6882 .attr('class', 'tooltip')
6883 .style('z-index', 1002);
6885 tooltip.append('div').attr('class', 'tooltip-arrow');
6886 tooltip.append('div').attr('class', 'tooltip-inner');
6892 width: window.innerWidth,
6893 height: window.innerHeight
6895 curtain.cut(darkness.datum());
6899 curtain.reveal = function(box, text, tooltipclass, duration) {
6900 if (typeof box === 'string') box = d3.select(box).node();
6901 if (box.getBoundingClientRect) box = box.getBoundingClientRect();
6903 curtain.cut(box, duration);
6906 // pseudo markdown bold text hack
6907 var parts = text.split('**');
6908 var html = parts[0] ? '<span>' + parts[0] + '</span>' : '';
6909 if (parts[1]) html += '<span class="bold">' + parts[1] + '</span>';
6911 var dimensions = tooltip.classed('in', true)
6912 .select('.tooltip-inner')
6918 var w = window.innerWidth,
6919 h = window.innerHeight;
6921 if (box.top + box.height < Math.min(100, box.width + box.left)) {
6923 pos = [box.left + box.width / 2 - dimensions[0]/ 2, box.top + box.height];
6925 } else if (box.left + box.width + 300 < window.innerWidth) {
6927 pos = [box.left + box.width, box.top + box.height / 2 - dimensions[1] / 2];
6929 } else if (box.left > 300) {
6931 pos = [box.left - 200, box.top + box.height / 2 - dimensions[1] / 2];
6934 pos = [box.left, box.top + box.height];
6938 Math.min(Math.max(10, pos[0]), w - dimensions[0] - 10),
6939 Math.min(Math.max(10, pos[1]), h - dimensions[1] - 10)
6943 if (duration !== 0 || !tooltip.classed(side)) tooltip.call(iD.ui.Toggle(true));
6946 .style('top', pos[1] + 'px')
6947 .style('left', pos[0] + 'px')
6948 .attr('class', 'curtain-tooltip tooltip in ' + side + ' ' + tooltipclass)
6949 .select('.tooltip-inner')
6953 tooltip.call(iD.ui.Toggle(false));
6957 curtain.cut = function(datum, duration) {
6958 darkness.datum(datum);
6960 (duration === 0 ? darkness : darkness.transition().duration(duration || 600))
6961 .attr('d', function(d) {
6962 var string = "M 0,0 L 0," + window.innerHeight + " L " +
6963 window.innerWidth + "," + window.innerHeight + "L" +
6964 window.innerWidth + ",0 Z";
6966 if (!d) return string;
6967 return string + 'M' +
6968 d.left + ',' + d.top + 'L' +
6969 d.left + ',' + (d.top + d.height) + 'L' +
6970 (d.left + d.width) + ',' + (d.top + d.height) + 'L' +
6971 (d.left + d.width) + ',' + (d.top) + 'Z';
6976 curtain.remove = function() {
6981 return d3.rebind(curtain, event, 'on');
6983 // Like selection.property('value', ...), but avoids no-op value sets,
6984 // which can result in layout/repaint thrashing in some situations.
6985 d3.selection.prototype.value = function(value) {
6986 function d3_selection_value(value) {
6987 function valueNull() {
6991 function valueConstant() {
6992 if (this.value !== value) this.value = value;
6995 function valueFunction() {
6996 var x = value.apply(this, arguments);
6997 if (x == null) delete this.value;
6998 else if (this.value !== x) this.value = x;
7001 return value == null
7002 ? valueNull : (typeof value === "function"
7003 ? valueFunction : valueConstant);
7006 if (!arguments.length) return this.property('value');
7007 return this.each(d3_selection_value(value));
7009 // Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
7010 // Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
7012 // Permission is hereby granted, free of charge, to any person
7013 // obtaining a copy of this software and associated documentation files
7014 // (the "Software"), to deal in the Software without restriction,
7015 // including without limitation the rights to use, copy, modify, merge,
7016 // publish, distribute, sublicense, and/or sell copies of the Software,
7017 // and to permit persons to whom the Software is furnished to do so,
7018 // subject to the following conditions:
7020 // The above copyright notice and this permission notice shall be
7021 // included in all copies or substantial portions of the Software.
7023 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
7024 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
7025 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
7026 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
7027 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
7028 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
7029 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
7032 // source: https://bitbucket.org/lshift/synchrotron/src
7034 Diff3 = (function() {
7038 longest_common_subsequence: function(file1, file2) {
7039 /* Text diff algorithm following Hunt and McIlroy 1976.
7040 * J. W. Hunt and M. D. McIlroy, An algorithm for differential file
7041 * comparison, Bell Telephone Laboratories CSTR #41 (1976)
7042 * http://www.cs.dartmouth.edu/~doug/
7044 * Expects two arrays of strings.
7046 var equivalenceClasses;
7051 var c, i, j, jX, r, s;
7053 equivalenceClasses = {};
7054 for (j = 0; j < file2.length; j++) {
7056 if (equivalenceClasses[line]) {
7057 equivalenceClasses[line].push(j);
7059 equivalenceClasses[line] = [j];
7063 candidates = [{file1index: -1,
7067 for (i = 0; i < file1.length; i++) {
7069 file2indices = equivalenceClasses[line] || [];
7074 for (jX = 0; jX < file2indices.length; jX++) {
7075 j = file2indices[jX];
7077 for (s = 0; s < candidates.length; s++) {
7078 if ((candidates[s].file2index < j) &&
7079 ((s == candidates.length - 1) ||
7080 (candidates[s + 1].file2index > j)))
7084 if (s < candidates.length) {
7085 newCandidate = {file1index: i,
7087 chain: candidates[s]};
7088 if (r == candidates.length) {
7095 if (r == candidates.length) {
7096 break; // no point in examining further (j)s
7104 // At this point, we know the LCS: it's in the reverse of the
7105 // linked-list through .chain of
7106 // candidates[candidates.length - 1].
7108 return candidates[candidates.length - 1];
7111 diff_comm: function(file1, file2) {
7112 // We apply the LCS to build a "comm"-style picture of the
7113 // differences between file1 and file2.
7116 var tail1 = file1.length;
7117 var tail2 = file2.length;
7118 var common = {common: []};
7120 function processCommon() {
7121 if (common.common.length) {
7122 common.common.reverse();
7123 result.push(common);
7124 common = {common: []};
7128 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7130 candidate = candidate.chain)
7132 var different = {file1: [], file2: []};
7134 while (--tail1 > candidate.file1index) {
7135 different.file1.push(file1[tail1]);
7138 while (--tail2 > candidate.file2index) {
7139 different.file2.push(file2[tail2]);
7142 if (different.file1.length || different.file2.length) {
7144 different.file1.reverse();
7145 different.file2.reverse();
7146 result.push(different);
7150 common.common.push(file1[tail1]);
7160 diff_patch: function(file1, file2) {
7161 // We apply the LCD to build a JSON representation of a
7162 // diff(1)-style patch.
7165 var tail1 = file1.length;
7166 var tail2 = file2.length;
7168 function chunkDescription(file, offset, length) {
7170 for (var i = 0; i < length; i++) {
7171 chunk.push(file[offset + i]);
7173 return {offset: offset,
7178 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7180 candidate = candidate.chain)
7182 var mismatchLength1 = tail1 - candidate.file1index - 1;
7183 var mismatchLength2 = tail2 - candidate.file2index - 1;
7184 tail1 = candidate.file1index;
7185 tail2 = candidate.file2index;
7187 if (mismatchLength1 || mismatchLength2) {
7188 result.push({file1: chunkDescription(file1,
7189 candidate.file1index + 1,
7191 file2: chunkDescription(file2,
7192 candidate.file2index + 1,
7201 strip_patch: function(patch) {
7202 // Takes the output of Diff3.diff_patch(), and removes
7203 // information from it. It can still be used by patch(),
7204 // below, but can no longer be inverted.
7206 for (var i = 0; i < patch.length; i++) {
7207 var chunk = patch[i];
7208 newpatch.push({file1: {offset: chunk.file1.offset,
7209 length: chunk.file1.length},
7210 file2: {chunk: chunk.file2.chunk}});
7215 invert_patch: function(patch) {
7216 // Takes the output of Diff3.diff_patch(), and inverts the
7217 // sense of it, so that it can be applied to file2 to give
7218 // file1 rather than the other way around.
7220 for (var i = 0; i < patch.length; i++) {
7221 var chunk = patch[i];
7222 var tmp = chunk.file1;
7223 chunk.file1 = chunk.file2;
7228 patch: function (file, patch) {
7229 // Applies a patch to a file.
7231 // Given file1 and file2, Diff3.patch(file1,
7232 // Diff3.diff_patch(file1, file2)) should give file2.
7235 var commonOffset = 0;
7237 function copyCommon(targetOffset) {
7238 while (commonOffset < targetOffset) {
7239 result.push(file[commonOffset]);
7244 for (var chunkIndex = 0; chunkIndex < patch.length; chunkIndex++) {
7245 var chunk = patch[chunkIndex];
7246 copyCommon(chunk.file1.offset);
7247 for (var lineIndex = 0; lineIndex < chunk.file2.chunk.length; lineIndex++) {
7248 result.push(chunk.file2.chunk[lineIndex]);
7250 commonOffset += chunk.file1.length;
7253 copyCommon(file.length);
7257 diff_indices: function(file1, file2) {
7258 // We apply the LCS to give a simple representation of the
7259 // offsets and lengths of mismatched chunks in the input
7260 // files. This is used by diff3_merge_indices below.
7263 var tail1 = file1.length;
7264 var tail2 = file2.length;
7266 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7268 candidate = candidate.chain)
7270 var mismatchLength1 = tail1 - candidate.file1index - 1;
7271 var mismatchLength2 = tail2 - candidate.file2index - 1;
7272 tail1 = candidate.file1index;
7273 tail2 = candidate.file2index;
7275 if (mismatchLength1 || mismatchLength2) {
7276 result.push({file1: [tail1 + 1, mismatchLength1],
7277 file2: [tail2 + 1, mismatchLength2]});
7285 diff3_merge_indices: function (a, o, b) {
7286 // Given three files, A, O, and B, where both A and B are
7287 // independently derived from O, returns a fairly complicated
7288 // internal representation of merge decisions it's taken. The
7289 // interested reader may wish to consult
7291 // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
7292 // Formal Investigation of Diff3." In Arvind and Prasad,
7293 // editors, Foundations of Software Technology and Theoretical
7294 // Computer Science (FSTTCS), December 2007.
7296 // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
7299 var m1 = Diff3.diff_indices(o, a);
7300 var m2 = Diff3.diff_indices(o, b);
7303 function addHunk(h, side) {
7304 hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]);
7306 for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); }
7307 for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); }
7311 var commonOffset = 0;
7312 function copyCommon(targetOffset) {
7313 if (targetOffset > commonOffset) {
7314 result.push([1, commonOffset, targetOffset - commonOffset]);
7315 commonOffset = targetOffset;
7319 for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {
7320 var firstHunkIndex = hunkIndex;
7321 var hunk = hunks[hunkIndex];
7322 var regionLhs = hunk[0];
7323 var regionRhs = regionLhs + hunk[2];
7324 while (hunkIndex < hunks.length - 1) {
7325 var maybeOverlapping = hunks[hunkIndex + 1];
7326 var maybeLhs = maybeOverlapping[0];
7327 if (maybeLhs > regionRhs) break;
7328 regionRhs = maybeLhs + maybeOverlapping[2];
7332 copyCommon(regionLhs);
7333 if (firstHunkIndex == hunkIndex) {
7334 // The "overlap" was only one hunk long, meaning that
7335 // there's no conflict here. Either a and o were the
7336 // same, or b and o were the same.
7338 result.push([hunk[1], hunk[3], hunk[4]]);
7341 // A proper conflict. Determine the extents of the
7342 // regions involved from a, o and b. Effectively merge
7343 // all the hunks on the left into one giant hunk, and
7344 // do the same for the right; then, correct for skew
7345 // in the regions of o that each side changed, and
7346 // report appropriate spans for the three sides.
7348 0: [a.length, -1, o.length, -1],
7349 2: [b.length, -1, o.length, -1]
7351 for (i = firstHunkIndex; i <= hunkIndex; i++) {
7354 var r = regions[side];
7356 var oRhs = oLhs + hunk[2];
7357 var abLhs = hunk[3];
7358 var abRhs = abLhs + hunk[4];
7359 r[0] = Math.min(abLhs, r[0]);
7360 r[1] = Math.max(abRhs, r[1]);
7361 r[2] = Math.min(oLhs, r[2]);
7362 r[3] = Math.max(oRhs, r[3]);
7364 var aLhs = regions[0][0] + (regionLhs - regions[0][2]);
7365 var aRhs = regions[0][1] + (regionRhs - regions[0][3]);
7366 var bLhs = regions[2][0] + (regionLhs - regions[2][2]);
7367 var bRhs = regions[2][1] + (regionRhs - regions[2][3]);
7370 regionLhs, regionRhs - regionLhs,
7371 bLhs, bRhs - bLhs]);
7373 commonOffset = regionRhs;
7376 copyCommon(o.length);
7380 diff3_merge: function (a, o, b, excludeFalseConflicts) {
7381 // Applies the output of Diff3.diff3_merge_indices to actually
7382 // construct the merged file; the returned result alternates
7383 // between "ok" and "conflict" blocks.
7386 var files = [a, o, b];
7387 var indices = Diff3.diff3_merge_indices(a, o, b);
7390 function flushOk() {
7391 if (okLines.length) {
7392 result.push({ok: okLines});
7396 function pushOk(xs) {
7397 for (var j = 0; j < xs.length; j++) {
7398 okLines.push(xs[j]);
7402 function isTrueConflict(rec) {
7403 if (rec[2] != rec[6]) return true;
7406 for (var j = 0; j < rec[2]; j++) {
7407 if (a[j + aoff] != b[j + boff]) return true;
7412 for (var i = 0; i < indices.length; i++) {
7416 if (excludeFalseConflicts && !isTrueConflict(x)) {
7417 pushOk(files[0].slice(x[1], x[1] + x[2]));
7420 result.push({conflict: {a: a.slice(x[1], x[1] + x[2]),
7422 o: o.slice(x[3], x[3] + x[4]),
7424 b: b.slice(x[5], x[5] + x[6]),
7428 pushOk(files[side].slice(x[1], x[1] + x[2]));
7439 if (typeof module !== 'undefined') module.exports = Diff3;
7440 var JXON = new (function () {
7442 sValueProp = "keyValue", sAttributesProp = "keyAttributes", sAttrPref = "@", /* you can customize these values */
7443 aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
7445 function parseText (sValue) {
7446 if (rIsNull.test(sValue)) { return null; }
7447 if (rIsBool.test(sValue)) { return sValue.toLowerCase() === "true"; }
7448 if (isFinite(sValue)) { return parseFloat(sValue); }
7449 if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
7453 function EmptyTree () { }
7454 EmptyTree.prototype.toString = function () { return "null"; };
7455 EmptyTree.prototype.valueOf = function () { return null; };
7457 function objectify (vValue) {
7458 return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
7461 function createObjTree (oParentNode, nVerb, bFreeze, bNesteAttr) {
7463 nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(),
7464 bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
7467 sProp, vContent, nLength = 0, sCollectedTxt = "",
7468 vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
7471 for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
7472 oNode = oParentNode.childNodes.item(nItem);
7473 if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is "CDATASection" (4) */
7474 else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is "Text" (3) */
7475 else if (oNode.nodeType === 1 && !oNode.prefix) { aCache.push(oNode); } /* nodeType is "Element" (1) */
7479 var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
7481 if (!bHighVerb && (bChildren || bAttributes)) { vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; }
7483 for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
7484 sProp = aCache[nElId].nodeName.toLowerCase();
7485 vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
7486 if (vResult.hasOwnProperty(sProp)) {
7487 if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; }
7488 vResult[sProp].push(vContent);
7490 vResult[sProp] = vContent;
7497 nAttrLen = oParentNode.attributes.length,
7498 sAPrefix = bNesteAttr ? "" : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
7500 for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
7501 oAttrib = oParentNode.attributes.item(nAttrib);
7502 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
7506 if (bFreeze) { Object.freeze(oAttrParent); }
7507 vResult[sAttributesProp] = oAttrParent;
7508 nLength -= nAttrLen - 1;
7512 if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
7513 vResult[sValueProp] = vBuiltVal;
7514 } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
7515 vResult = vBuiltVal;
7518 if (bFreeze && (bHighVerb || nLength > 0)) { Object.freeze(vResult); }
7520 aCache.length = nLevelStart;
7525 function loadObjTree (oXMLDoc, oParentEl, oParentObj) {
7528 if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
7529 oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
7530 } else if (oParentObj.constructor === Date) {
7531 oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
7534 for (var sName in oParentObj) {
7535 vValue = oParentObj[sName];
7536 if (isFinite(sName) || vValue instanceof Function) { continue; } /* verbosity level is 0 */
7537 if (sName === sValueProp) {
7538 if (vValue !== null && vValue !== true) { oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); }
7539 } else if (sName === sAttributesProp) { /* verbosity level is 3 */
7540 for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); }
7541 } else if (sName.charAt(0) === sAttrPref) {
7542 oParentEl.setAttribute(sName.slice(1), vValue);
7543 } else if (vValue.constructor === Array) {
7544 for (var nItem = 0; nItem < vValue.length; nItem++) {
7545 oChild = oXMLDoc.createElement(sName);
7546 loadObjTree(oXMLDoc, oChild, vValue[nItem]);
7547 oParentEl.appendChild(oChild);
7550 oChild = oXMLDoc.createElement(sName);
7551 if (vValue instanceof Object) {
7552 loadObjTree(oXMLDoc, oChild, vValue);
7553 } else if (vValue !== null && vValue !== true) {
7554 oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
7556 oParentEl.appendChild(oChild);
7561 this.build = function (oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
7562 var _nVerb = arguments.length > 1 && typeof nVerbosity === "number" ? nVerbosity & 3 : /* put here the default verbosity level: */ 1;
7563 return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
7566 this.unbuild = function (oObjTree) {
7567 var oNewDoc = document.implementation.createDocument("", "", null);
7568 loadObjTree(oNewDoc, oNewDoc, oObjTree);
7572 this.stringify = function (oObjTree) {
7573 return (new XMLSerializer()).serializeToString(JXON.unbuild(oObjTree));
7576 // var myObject = JXON.build(doc);
7577 // we got our javascript object! try: alert(JSON.stringify(myObject));
7579 // var newDoc = JXON.unbuild(myObject);
7580 // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
7583 * lodash 3.9.3 (Custom Build) <https://lodash.com/>
7584 * Build: `lodash --development --output js/lib/lodash.js include="any,assign,bind,chunk,clone,compact,contains,debounce,difference,each,every,extend,filter,find,first,forEach,forOwn,groupBy,indexOf,intersection,isEmpty,isEqual,isFunction,keys,last,map,omit,pairs,pluck,reject,some,throttle,union,uniq,unique,values,without,flatten,value,chain,cloneDeep,merge,pick,reduce" exports="global,node"`
7585 * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
7586 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
7587 * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
7588 * Available under MIT license <https://lodash.com/license>
7592 /** Used as a safe reference for `undefined` in pre-ES5 environments. */
7595 /** Used as the semantic version number. */
7596 var VERSION = '3.9.3';
7598 /** Used to compose bitmasks for wrapper metadata. */
7601 CURRY_BOUND_FLAG = 4,
7603 CURRY_RIGHT_FLAG = 16,
7605 PARTIAL_RIGHT_FLAG = 64,
7609 /** Used to detect when a function becomes hot. */
7610 var HOT_COUNT = 150,
7613 /** Used to indicate the type of lazy iteratees. */
7614 var LAZY_DROP_WHILE_FLAG = 0,
7615 LAZY_FILTER_FLAG = 1,
7618 /** Used as the `TypeError` message for "Functions" methods. */
7619 var FUNC_ERROR_TEXT = 'Expected a function';
7621 /** Used as the internal argument placeholder. */
7622 var PLACEHOLDER = '__lodash_placeholder__';
7624 /** `Object#toString` result references. */
7625 var argsTag = '[object Arguments]',
7626 arrayTag = '[object Array]',
7627 boolTag = '[object Boolean]',
7628 dateTag = '[object Date]',
7629 errorTag = '[object Error]',
7630 funcTag = '[object Function]',
7631 mapTag = '[object Map]',
7632 numberTag = '[object Number]',
7633 objectTag = '[object Object]',
7634 regexpTag = '[object RegExp]',
7635 setTag = '[object Set]',
7636 stringTag = '[object String]',
7637 weakMapTag = '[object WeakMap]';
7639 var arrayBufferTag = '[object ArrayBuffer]',
7640 float32Tag = '[object Float32Array]',
7641 float64Tag = '[object Float64Array]',
7642 int8Tag = '[object Int8Array]',
7643 int16Tag = '[object Int16Array]',
7644 int32Tag = '[object Int32Array]',
7645 uint8Tag = '[object Uint8Array]',
7646 uint8ClampedTag = '[object Uint8ClampedArray]',
7647 uint16Tag = '[object Uint16Array]',
7648 uint32Tag = '[object Uint32Array]';
7650 /** Used to match property names within property paths. */
7651 var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,
7652 reIsPlainProp = /^\w*$/,
7653 rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g;
7656 * Used to match `RegExp` [special characters](http://www.regular-expressions.info/characters.html#special).
7657 * In addition to special characters the forward slash is escaped to allow for
7658 * easier `eval` use and `Function` compilation.
7660 var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g,
7661 reHasRegExpChars = RegExp(reRegExpChars.source);
7663 /** Used to match backslashes in property paths. */
7664 var reEscapeChar = /\\(\\)?/g;
7666 /** Used to match `RegExp` flags from their coerced string values. */
7667 var reFlags = /\w*$/;
7669 /** Used to detect host constructors (Safari > 5). */
7670 var reIsHostCtor = /^\[object .+?Constructor\]$/;
7672 /** Used to detect unsigned integer values. */
7673 var reIsUint = /^\d+$/;
7675 /** Used to fix the JScript `[[DontEnum]]` bug. */
7677 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
7678 'toLocaleString', 'toString', 'valueOf'
7681 /** Used to identify `toStringTag` values of typed arrays. */
7682 var typedArrayTags = {};
7683 typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
7684 typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
7685 typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
7686 typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
7687 typedArrayTags[uint32Tag] = true;
7688 typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
7689 typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
7690 typedArrayTags[dateTag] = typedArrayTags[errorTag] =
7691 typedArrayTags[funcTag] = typedArrayTags[mapTag] =
7692 typedArrayTags[numberTag] = typedArrayTags[objectTag] =
7693 typedArrayTags[regexpTag] = typedArrayTags[setTag] =
7694 typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
7696 /** Used to identify `toStringTag` values supported by `_.clone`. */
7697 var cloneableTags = {};
7698 cloneableTags[argsTag] = cloneableTags[arrayTag] =
7699 cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
7700 cloneableTags[dateTag] = cloneableTags[float32Tag] =
7701 cloneableTags[float64Tag] = cloneableTags[int8Tag] =
7702 cloneableTags[int16Tag] = cloneableTags[int32Tag] =
7703 cloneableTags[numberTag] = cloneableTags[objectTag] =
7704 cloneableTags[regexpTag] = cloneableTags[stringTag] =
7705 cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
7706 cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
7707 cloneableTags[errorTag] = cloneableTags[funcTag] =
7708 cloneableTags[mapTag] = cloneableTags[setTag] =
7709 cloneableTags[weakMapTag] = false;
7711 /** Used as an internal `_.debounce` options object by `_.throttle`. */
7712 var debounceOptions = {
7718 /** Used to determine if values are of the language type `Object`. */
7724 /** Detect free variable `exports`. */
7725 var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
7727 /** Detect free variable `module`. */
7728 var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
7730 /** Detect free variable `global` from Node.js. */
7731 var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global;
7733 /** Detect free variable `self`. */
7734 var freeSelf = objectTypes[typeof self] && self && self.Object && self;
7736 /** Detect free variable `window`. */
7737 var freeWindow = objectTypes[typeof window] && window && window.Object && window;
7739 /** Detect the popular CommonJS extension `module.exports`. */
7740 var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
7743 * Used as a reference to the global object.
7745 * The `this` value is used if it's the global object to avoid Greasemonkey's
7746 * restricted `window` object, otherwise the `window` object is used.
7748 var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this;
7750 /*--------------------------------------------------------------------------*/
7753 * The base implementation of `_.findIndex` and `_.findLastIndex` without
7754 * support for callback shorthands and `this` binding.
7757 * @param {Array} array The array to search.
7758 * @param {Function} predicate The function invoked per iteration.
7759 * @param {boolean} [fromRight] Specify iterating from right to left.
7760 * @returns {number} Returns the index of the matched value, else `-1`.
7762 function baseFindIndex(array, predicate, fromRight) {
7763 var length = array.length,
7764 index = fromRight ? length : -1;
7766 while ((fromRight ? index-- : ++index < length)) {
7767 if (predicate(array[index], index, array)) {
7775 * The base implementation of `_.indexOf` without support for binary searches.
7778 * @param {Array} array The array to search.
7779 * @param {*} value The value to search for.
7780 * @param {number} fromIndex The index to search from.
7781 * @returns {number} Returns the index of the matched value, else `-1`.
7783 function baseIndexOf(array, value, fromIndex) {
7784 if (value !== value) {
7785 return indexOfNaN(array, fromIndex);
7787 var index = fromIndex - 1,
7788 length = array.length;
7790 while (++index < length) {
7791 if (array[index] === value) {
7799 * The base implementation of `_.isFunction` without support for environments
7800 * with incorrect `typeof` results.
7803 * @param {*} value The value to check.
7804 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
7806 function baseIsFunction(value) {
7807 // Avoid a Chakra JIT bug in compatibility modes of IE 11.
7808 // See https://github.com/jashkenas/underscore/issues/1621 for more details.
7809 return typeof value == 'function' || false;
7813 * Converts `value` to a string if it's not one. An empty string is returned
7814 * for `null` or `undefined` values.
7817 * @param {*} value The value to process.
7818 * @returns {string} Returns the string.
7820 function baseToString(value) {
7821 if (typeof value == 'string') {
7824 return value == null ? '' : (value + '');
7828 * Gets the index at which the first occurrence of `NaN` is found in `array`.
7831 * @param {Array} array The array to search.
7832 * @param {number} fromIndex The index to search from.
7833 * @param {boolean} [fromRight] Specify iterating from right to left.
7834 * @returns {number} Returns the index of the matched `NaN`, else `-1`.
7836 function indexOfNaN(array, fromIndex, fromRight) {
7837 var length = array.length,
7838 index = fromIndex + (fromRight ? 0 : -1);
7840 while ((fromRight ? index-- : ++index < length)) {
7841 var other = array[index];
7842 if (other !== other) {
7850 * Checks if `value` is a host object in IE < 9.
7853 * @param {*} value The value to check.
7854 * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
7856 var isHostObject = (function() {
7858 Object({ 'toString': 0 } + '');
7860 return function() { return false; };
7862 return function(value) {
7863 // IE < 9 presents many host objects as `Object` objects that can coerce
7864 // to strings despite having improperly defined `toString` methods.
7865 return typeof value.toString != 'function' && typeof (value + '') == 'string';
7870 * Checks if `value` is object-like.
7873 * @param {*} value The value to check.
7874 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
7876 function isObjectLike(value) {
7877 return !!value && typeof value == 'object';
7881 * Replaces all `placeholder` elements in `array` with an internal placeholder
7882 * and returns an array of their indexes.
7885 * @param {Array} array The array to modify.
7886 * @param {*} placeholder The placeholder to replace.
7887 * @returns {Array} Returns the new array of placeholder indexes.
7889 function replaceHolders(array, placeholder) {
7891 length = array.length,
7895 while (++index < length) {
7896 if (array[index] === placeholder) {
7897 array[index] = PLACEHOLDER;
7898 result[++resIndex] = index;
7905 * An implementation of `_.uniq` optimized for sorted arrays without support
7906 * for callback shorthands and `this` binding.
7909 * @param {Array} array The array to inspect.
7910 * @param {Function} [iteratee] The function invoked per iteration.
7911 * @returns {Array} Returns the new duplicate-value-free array.
7913 function sortedUniq(array, iteratee) {
7916 length = array.length,
7920 while (++index < length) {
7921 var value = array[index],
7922 computed = iteratee ? iteratee(value, index, array) : value;
7924 if (!index || seen !== computed) {
7926 result[++resIndex] = value;
7932 /*--------------------------------------------------------------------------*/
7934 /** Used for native method references. */
7935 var arrayProto = Array.prototype,
7936 errorProto = Error.prototype,
7937 objectProto = Object.prototype,
7938 stringProto = String.prototype;
7940 /** Used to resolve the decompiled source of functions. */
7941 var fnToString = Function.prototype.toString;
7943 /** Used to check objects for own properties. */
7944 var hasOwnProperty = objectProto.hasOwnProperty;
7947 * Used to resolve the [`toStringTag`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring)
7950 var objToString = objectProto.toString;
7952 /** Used to detect if a method is native. */
7953 var reIsNative = RegExp('^' +
7954 escapeRegExp(fnToString.call(hasOwnProperty))
7955 .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
7958 /** Native method references. */
7959 var ArrayBuffer = getNative(root, 'ArrayBuffer'),
7960 bufferSlice = getNative(ArrayBuffer && new ArrayBuffer(0), 'slice'),
7963 getPrototypeOf = getNative(Object, 'getPrototypeOf'),
7964 push = arrayProto.push,
7965 propertyIsEnumerable = objectProto.propertyIsEnumerable,
7966 Set = getNative(root, 'Set'),
7967 splice = arrayProto.splice,
7968 Uint8Array = getNative(root, 'Uint8Array'),
7969 WeakMap = getNative(root, 'WeakMap');
7971 /** Used to clone array buffers. */
7972 var Float64Array = (function() {
7973 // Safari 5 errors when using an array buffer to initialize a typed array
7974 // where the array buffer's `byteLength` is not a multiple of the typed
7975 // array's `BYTES_PER_ELEMENT`.
7977 var func = getNative(root, 'Float64Array'),
7978 result = new func(new ArrayBuffer(10), 0, 1) && func;
7980 return result || null;
7983 /* Native method references for those with the same name as other `lodash` methods. */
7984 var nativeCreate = getNative(Object, 'create'),
7985 nativeIsArray = getNative(Array, 'isArray'),
7986 nativeKeys = getNative(Object, 'keys'),
7987 nativeMax = Math.max,
7988 nativeMin = Math.min,
7989 nativeNow = getNative(Date, 'now');
7991 /** Used as references for `-Infinity` and `Infinity`. */
7992 var POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
7994 /** Used as references for the maximum length and index of an array. */
7995 var MAX_ARRAY_LENGTH = 4294967295,
7996 MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
7997 HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
7999 /** Used as the size, in bytes, of each `Float64Array` element. */
8000 var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0;
8003 * Used as the [maximum length](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer)
8004 * of an array-like value.
8006 var MAX_SAFE_INTEGER = 9007199254740991;
8008 /** Used to store function metadata. */
8009 var metaMap = WeakMap && new WeakMap;
8011 /** Used to lookup unminified function names. */
8014 /** Used to lookup a type array constructors by `toStringTag`. */
8016 ctorByTag[float32Tag] = root.Float32Array;
8017 ctorByTag[float64Tag] = root.Float64Array;
8018 ctorByTag[int8Tag] = root.Int8Array;
8019 ctorByTag[int16Tag] = root.Int16Array;
8020 ctorByTag[int32Tag] = root.Int32Array;
8021 ctorByTag[uint8Tag] = root.Uint8Array;
8022 ctorByTag[uint8ClampedTag] = root.Uint8ClampedArray;
8023 ctorByTag[uint16Tag] = root.Uint16Array;
8024 ctorByTag[uint32Tag] = root.Uint32Array;
8026 /** Used to avoid iterating over non-enumerable properties in IE < 9. */
8027 var nonEnumProps = {};
8028 nonEnumProps[arrayTag] = nonEnumProps[dateTag] = nonEnumProps[numberTag] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true };
8029 nonEnumProps[boolTag] = nonEnumProps[stringTag] = { 'constructor': true, 'toString': true, 'valueOf': true };
8030 nonEnumProps[errorTag] = nonEnumProps[funcTag] = nonEnumProps[regexpTag] = { 'constructor': true, 'toString': true };
8031 nonEnumProps[objectTag] = { 'constructor': true };
8033 arrayEach(shadowProps, function(key) {
8034 for (var tag in nonEnumProps) {
8035 if (hasOwnProperty.call(nonEnumProps, tag)) {
8036 var props = nonEnumProps[tag];
8037 props[key] = hasOwnProperty.call(props, key);
8042 /*------------------------------------------------------------------------*/
8045 * Creates a `lodash` object which wraps `value` to enable implicit chaining.
8046 * Methods that operate on and return arrays, collections, and functions can
8047 * be chained together. Methods that return a boolean or single value will
8048 * automatically end the chain returning the unwrapped value. Explicit chaining
8049 * may be enabled using `_.chain`. The execution of chained methods is lazy,
8050 * that is, execution is deferred until `_#value` is implicitly or explicitly
8053 * Lazy evaluation allows several methods to support shortcut fusion. Shortcut
8054 * fusion is an optimization that merges iteratees to avoid creating intermediate
8055 * arrays and reduce the number of iteratee executions.
8057 * Chaining is supported in custom builds as long as the `_#value` method is
8058 * directly or indirectly included in the build.
8060 * In addition to lodash methods, wrappers have `Array` and `String` methods.
8062 * The wrapper `Array` methods are:
8063 * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`,
8064 * `splice`, and `unshift`
8066 * The wrapper `String` methods are:
8067 * `replace` and `split`
8069 * The wrapper methods that support shortcut fusion are:
8070 * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`,
8071 * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`,
8072 * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`,
8075 * The chainable wrapper methods are:
8076 * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
8077 * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`,
8078 * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defer`, `delay`,
8079 * `difference`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `fill`,
8080 * `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`, `forEach`,
8081 * `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`,
8082 * `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`,
8083 * `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
8084 * `memoize`, `merge`, `method`, `methodOf`, `mixin`, `negate`, `omit`, `once`,
8085 * `pairs`, `partial`, `partialRight`, `partition`, `pick`, `plant`, `pluck`,
8086 * `property`, `propertyOf`, `pull`, `pullAt`, `push`, `range`, `rearg`,
8087 * `reject`, `remove`, `rest`, `restParam`, `reverse`, `set`, `shuffle`,
8088 * `slice`, `sort`, `sortBy`, `sortByAll`, `sortByOrder`, `splice`, `spread`,
8089 * `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `tap`, `throttle`,
8090 * `thru`, `times`, `toArray`, `toPlainObject`, `transform`, `union`, `uniq`,
8091 * `unshift`, `unzip`, `unzipWith`, `values`, `valuesIn`, `where`, `without`,
8092 * `wrap`, `xor`, `zip`, `zipObject`, `zipWith`
8094 * The wrapper methods that are **not** chainable by default are:
8095 * `add`, `attempt`, `camelCase`, `capitalize`, `clone`, `cloneDeep`, `deburr`,
8096 * `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`,
8097 * `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`, `get`,
8098 * `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`, `inRange`, `isArguments`,
8099 * `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isError`,
8100 * `isFinite` `isFunction`, `isMatch`, `isNative`, `isNaN`, `isNull`, `isNumber`,
8101 * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`,
8102 * `isTypedArray`, `join`, `kebabCase`, `last`, `lastIndexOf`, `lt`, `lte`,
8103 * `max`, `min`, `noConflict`, `noop`, `now`, `pad`, `padLeft`, `padRight`,
8104 * `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`,
8105 * `runInContext`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`,
8106 * `sortedLastIndex`, `startCase`, `startsWith`, `sum`, `template`, `trim`,
8107 * `trimLeft`, `trimRight`, `trunc`, `unescape`, `uniqueId`, `value`, and `words`
8109 * The wrapper method `sample` will return a wrapped value when `n` is provided,
8110 * otherwise an unwrapped value is returned.
8115 * @param {*} value The value to wrap in a `lodash` instance.
8116 * @returns {Object} Returns the new `lodash` wrapper instance.
8119 * var wrapped = _([1, 2, 3]);
8121 * // returns an unwrapped value
8122 * wrapped.reduce(function(total, n) {
8127 * // returns a wrapped value
8128 * var squares = wrapped.map(function(n) {
8132 * _.isArray(squares);
8135 * _.isArray(squares.value());
8138 function lodash(value) {
8139 if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
8140 if (value instanceof LodashWrapper) {
8143 if (hasOwnProperty.call(value, '__chain__') && hasOwnProperty.call(value, '__wrapped__')) {
8144 return wrapperClone(value);
8147 return new LodashWrapper(value);
8151 * The function whose prototype all chaining wrappers inherit from.
8155 function baseLodash() {
8156 // No operation performed.
8160 * The base constructor for creating `lodash` wrapper objects.
8163 * @param {*} value The value to wrap.
8164 * @param {boolean} [chainAll] Enable chaining for all wrapper methods.
8165 * @param {Array} [actions=[]] Actions to peform to resolve the unwrapped value.
8167 function LodashWrapper(value, chainAll, actions) {
8168 this.__wrapped__ = value;
8169 this.__actions__ = actions || [];
8170 this.__chain__ = !!chainAll;
8174 * An object environment feature flags.
8180 var support = lodash.support = {};
8183 var Ctor = function() { this.x = x; },
8184 object = { '0': x, 'length': x },
8187 Ctor.prototype = { 'valueOf': x, 'y': x };
8188 for (var key in new Ctor) { props.push(key); }
8191 * Detect if the `toStringTag` of `arguments` objects is resolvable
8192 * (all but Firefox < 4, IE < 9).
8194 * @memberOf _.support
8197 support.argsTag = objToString.call(arguments) == argsTag;
8200 * Detect if `name` or `message` properties of `Error.prototype` are
8201 * enumerable by default (IE < 9, Safari < 5.1).
8203 * @memberOf _.support
8206 support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') ||
8207 propertyIsEnumerable.call(errorProto, 'name');
8210 * Detect if `prototype` properties are enumerable by default.
8212 * Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
8213 * (if the prototype or a property on the prototype has been set)
8214 * incorrectly set the `[[Enumerable]]` value of a function's `prototype`
8215 * property to `true`.
8217 * @memberOf _.support
8220 support.enumPrototypes = propertyIsEnumerable.call(Ctor, 'prototype');
8223 * Detect if properties shadowing those on `Object.prototype` are non-enumerable.
8225 * In IE < 9 an object's own properties, shadowing non-enumerable ones,
8226 * are made non-enumerable as well (a.k.a the JScript `[[DontEnum]]` bug).
8228 * @memberOf _.support
8231 support.nonEnumShadows = !/valueOf/.test(props);
8234 * Detect if own properties are iterated after inherited properties (IE < 9).
8236 * @memberOf _.support
8239 support.ownLast = props[0] != 'x';
8242 * Detect if `Array#shift` and `Array#splice` augment array-like objects
8245 * Firefox < 10, compatibility modes of IE 8, and IE < 9 have buggy Array
8246 * `shift()` and `splice()` functions that fail to remove the last element,
8247 * `value[0]`, of array-like objects even though the "length" property is
8248 * set to `0`. The `shift()` method is buggy in compatibility modes of IE 8,
8249 * while `splice()` is buggy regardless of mode in IE < 9.
8251 * @memberOf _.support
8254 support.spliceObjects = (splice.call(object, 0, 1), !object[0]);
8257 * Detect lack of support for accessing string characters by index.
8259 * IE < 8 can't access characters by index. IE 8 can only access characters
8260 * by index on string literals, not string objects.
8262 * @memberOf _.support
8265 support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx';
8268 /*------------------------------------------------------------------------*/
8271 * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
8274 * @param {*} value The value to wrap.
8276 function LazyWrapper(value) {
8277 this.__wrapped__ = value;
8278 this.__actions__ = null;
8280 this.__dropCount__ = 0;
8281 this.__filtered__ = false;
8282 this.__iteratees__ = null;
8283 this.__takeCount__ = POSITIVE_INFINITY;
8284 this.__views__ = null;
8288 * Creates a clone of the lazy wrapper object.
8292 * @memberOf LazyWrapper
8293 * @returns {Object} Returns the cloned `LazyWrapper` object.
8295 function lazyClone() {
8296 var actions = this.__actions__,
8297 iteratees = this.__iteratees__,
8298 views = this.__views__,
8299 result = new LazyWrapper(this.__wrapped__);
8301 result.__actions__ = actions ? arrayCopy(actions) : null;
8302 result.__dir__ = this.__dir__;
8303 result.__filtered__ = this.__filtered__;
8304 result.__iteratees__ = iteratees ? arrayCopy(iteratees) : null;
8305 result.__takeCount__ = this.__takeCount__;
8306 result.__views__ = views ? arrayCopy(views) : null;
8311 * Reverses the direction of lazy iteration.
8315 * @memberOf LazyWrapper
8316 * @returns {Object} Returns the new reversed `LazyWrapper` object.
8318 function lazyReverse() {
8319 if (this.__filtered__) {
8320 var result = new LazyWrapper(this);
8321 result.__dir__ = -1;
8322 result.__filtered__ = true;
8324 result = this.clone();
8325 result.__dir__ *= -1;
8331 * Extracts the unwrapped value from its lazy wrapper.
8335 * @memberOf LazyWrapper
8336 * @returns {*} Returns the unwrapped value.
8338 function lazyValue() {
8339 var array = this.__wrapped__.value();
8340 if (!isArray(array)) {
8341 return baseWrapperValue(array, this.__actions__);
8343 var dir = this.__dir__,
8345 view = getView(0, array.length, this.__views__),
8348 length = end - start,
8349 index = isRight ? end : (start - 1),
8350 takeCount = nativeMin(length, this.__takeCount__),
8351 iteratees = this.__iteratees__,
8352 iterLength = iteratees ? iteratees.length : 0,
8357 while (length-- && resIndex < takeCount) {
8361 value = array[index];
8363 while (++iterIndex < iterLength) {
8364 var data = iteratees[iterIndex],
8365 iteratee = data.iteratee,
8368 if (type == LAZY_DROP_WHILE_FLAG) {
8369 if (data.done && (isRight ? (index > data.index) : (index < data.index))) {
8375 var limit = data.limit;
8376 if (!(data.done = limit > -1 ? (data.count++ >= limit) : !iteratee(value))) {
8381 var computed = iteratee(value);
8382 if (type == LAZY_MAP_FLAG) {
8384 } else if (!computed) {
8385 if (type == LAZY_FILTER_FLAG) {
8393 result[resIndex++] = value;
8398 /*------------------------------------------------------------------------*/
8402 * Creates a cache object to store unique values.
8405 * @param {Array} [values] The values to cache.
8407 function SetCache(values) {
8408 var length = values ? values.length : 0;
8410 this.data = { 'hash': nativeCreate(null), 'set': new Set };
8412 this.push(values[length]);
8417 * Checks if `value` is in `cache` mimicking the return signature of
8418 * `_.indexOf` by returning `0` if the value is found, else `-1`.
8421 * @param {Object} cache The cache to search.
8422 * @param {*} value The value to search for.
8423 * @returns {number} Returns `0` if `value` is found, else `-1`.
8425 function cacheIndexOf(cache, value) {
8426 var data = cache.data,
8427 result = (typeof value == 'string' || isObject(value)) ? data.set.has(value) : data.hash[value];
8429 return result ? 0 : -1;
8433 * Adds `value` to the cache.
8437 * @memberOf SetCache
8438 * @param {*} value The value to cache.
8440 function cachePush(value) {
8441 var data = this.data;
8442 if (typeof value == 'string' || isObject(value)) {
8443 data.set.add(value);
8445 data.hash[value] = true;
8449 /*------------------------------------------------------------------------*/
8452 * Copies the values of `source` to `array`.
8455 * @param {Array} source The array to copy values from.
8456 * @param {Array} [array=[]] The array to copy values to.
8457 * @returns {Array} Returns `array`.
8459 function arrayCopy(source, array) {
8461 length = source.length;
8463 array || (array = Array(length));
8464 while (++index < length) {
8465 array[index] = source[index];
8471 * A specialized version of `_.forEach` for arrays without support for callback
8472 * shorthands and `this` binding.
8475 * @param {Array} array The array to iterate over.
8476 * @param {Function} iteratee The function invoked per iteration.
8477 * @returns {Array} Returns `array`.
8479 function arrayEach(array, iteratee) {
8481 length = array.length;
8483 while (++index < length) {
8484 if (iteratee(array[index], index, array) === false) {
8492 * A specialized version of `_.every` for arrays without support for callback
8493 * shorthands and `this` binding.
8496 * @param {Array} array The array to iterate over.
8497 * @param {Function} predicate The function invoked per iteration.
8498 * @returns {boolean} Returns `true` if all elements pass the predicate check,
8501 function arrayEvery(array, predicate) {
8503 length = array.length;
8505 while (++index < length) {
8506 if (!predicate(array[index], index, array)) {
8514 * A specialized version of `_.filter` for arrays without support for callback
8515 * shorthands and `this` binding.
8518 * @param {Array} array The array to iterate over.
8519 * @param {Function} predicate The function invoked per iteration.
8520 * @returns {Array} Returns the new filtered array.
8522 function arrayFilter(array, predicate) {
8524 length = array.length,
8528 while (++index < length) {
8529 var value = array[index];
8530 if (predicate(value, index, array)) {
8531 result[++resIndex] = value;
8538 * A specialized version of `_.map` for arrays without support for callback
8539 * shorthands and `this` binding.
8542 * @param {Array} array The array to iterate over.
8543 * @param {Function} iteratee The function invoked per iteration.
8544 * @returns {Array} Returns the new mapped array.
8546 function arrayMap(array, iteratee) {
8548 length = array.length,
8549 result = Array(length);
8551 while (++index < length) {
8552 result[index] = iteratee(array[index], index, array);
8558 * A specialized version of `_.reduce` for arrays without support for callback
8559 * shorthands and `this` binding.
8562 * @param {Array} array The array to iterate over.
8563 * @param {Function} iteratee The function invoked per iteration.
8564 * @param {*} [accumulator] The initial value.
8565 * @param {boolean} [initFromArray] Specify using the first element of `array`
8566 * as the initial value.
8567 * @returns {*} Returns the accumulated value.
8569 function arrayReduce(array, iteratee, accumulator, initFromArray) {
8571 length = array.length;
8573 if (initFromArray && length) {
8574 accumulator = array[++index];
8576 while (++index < length) {
8577 accumulator = iteratee(accumulator, array[index], index, array);
8583 * A specialized version of `_.some` for arrays without support for callback
8584 * shorthands and `this` binding.
8587 * @param {Array} array The array to iterate over.
8588 * @param {Function} predicate The function invoked per iteration.
8589 * @returns {boolean} Returns `true` if any element passes the predicate check,
8592 function arraySome(array, predicate) {
8594 length = array.length;
8596 while (++index < length) {
8597 if (predicate(array[index], index, array)) {
8605 * A specialized version of `_.assign` for customizing assigned values without
8606 * support for argument juggling, multiple sources, and `this` binding `customizer`
8610 * @param {Object} object The destination object.
8611 * @param {Object} source The source object.
8612 * @param {Function} customizer The function to customize assigned values.
8613 * @returns {Object} Returns `object`.
8615 function assignWith(object, source, customizer) {
8617 props = keys(source),
8618 length = props.length;
8620 while (++index < length) {
8621 var key = props[index],
8622 value = object[key],
8623 result = customizer(value, source[key], key, object, source);
8625 if ((result === result ? (result !== value) : (value === value)) ||
8626 (value === undefined && !(key in object))) {
8627 object[key] = result;
8634 * The base implementation of `_.assign` without support for argument juggling,
8635 * multiple sources, and `customizer` functions.
8638 * @param {Object} object The destination object.
8639 * @param {Object} source The source object.
8640 * @returns {Object} Returns `object`.
8642 function baseAssign(object, source) {
8643 return source == null
8645 : baseCopy(source, keys(source), object);
8649 * Copies properties of `source` to `object`.
8652 * @param {Object} source The object to copy properties from.
8653 * @param {Array} props The property names to copy.
8654 * @param {Object} [object={}] The object to copy properties to.
8655 * @returns {Object} Returns `object`.
8657 function baseCopy(source, props, object) {
8658 object || (object = {});
8661 length = props.length;
8663 while (++index < length) {
8664 var key = props[index];
8665 object[key] = source[key];
8671 * The base implementation of `_.callback` which supports specifying the
8672 * number of arguments to provide to `func`.
8675 * @param {*} [func=_.identity] The value to convert to a callback.
8676 * @param {*} [thisArg] The `this` binding of `func`.
8677 * @param {number} [argCount] The number of arguments to provide to `func`.
8678 * @returns {Function} Returns the callback.
8680 function baseCallback(func, thisArg, argCount) {
8681 var type = typeof func;
8682 if (type == 'function') {
8683 return thisArg === undefined
8685 : bindCallback(func, thisArg, argCount);
8690 if (type == 'object') {
8691 return baseMatches(func);
8693 return thisArg === undefined
8695 : baseMatchesProperty(func, thisArg);
8699 * The base implementation of `_.clone` without support for argument juggling
8700 * and `this` binding `customizer` functions.
8703 * @param {*} value The value to clone.
8704 * @param {boolean} [isDeep] Specify a deep clone.
8705 * @param {Function} [customizer] The function to customize cloning values.
8706 * @param {string} [key] The key of `value`.
8707 * @param {Object} [object] The object `value` belongs to.
8708 * @param {Array} [stackA=[]] Tracks traversed source objects.
8709 * @param {Array} [stackB=[]] Associates clones with source counterparts.
8710 * @returns {*} Returns the cloned value.
8712 function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
8715 result = object ? customizer(value, key, object) : customizer(value);
8717 if (result !== undefined) {
8720 if (!isObject(value)) {
8723 var isArr = isArray(value);
8725 result = initCloneArray(value);
8727 return arrayCopy(value, result);
8730 var tag = objToString.call(value),
8731 isFunc = tag == funcTag;
8733 if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
8734 if (isHostObject(value)) {
8735 return object ? value : {};
8737 result = initCloneObject(isFunc ? {} : value);
8739 return baseAssign(result, value);
8742 return cloneableTags[tag]
8743 ? initCloneByTag(value, tag, isDeep)
8744 : (object ? value : {});
8747 // Check for circular references and return corresponding clone.
8748 stackA || (stackA = []);
8749 stackB || (stackB = []);
8751 var length = stackA.length;
8753 if (stackA[length] == value) {
8754 return stackB[length];
8757 // Add the source value to the stack of traversed objects and associate it with its clone.
8759 stackB.push(result);
8761 // Recursively populate clone (susceptible to call stack limits).
8762 (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
8763 result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
8769 * The base implementation of `_.create` without support for assigning
8770 * properties to the created object.
8773 * @param {Object} prototype The object to inherit from.
8774 * @returns {Object} Returns the new object.
8776 var baseCreate = (function() {
8777 function object() {}
8778 return function(prototype) {
8779 if (isObject(prototype)) {
8780 object.prototype = prototype;
8781 var result = new object;
8782 object.prototype = null;
8784 return result || {};
8789 * The base implementation of `_.difference` which accepts a single array
8790 * of values to exclude.
8793 * @param {Array} array The array to inspect.
8794 * @param {Array} values The values to exclude.
8795 * @returns {Array} Returns the new array of filtered values.
8797 function baseDifference(array, values) {
8798 var length = array ? array.length : 0,
8805 indexOf = getIndexOf(),
8806 isCommon = indexOf == baseIndexOf,
8807 cache = (isCommon && values.length >= 200) ? createCache(values) : null,
8808 valuesLength = values.length;
8811 indexOf = cacheIndexOf;
8816 while (++index < length) {
8817 var value = array[index];
8819 if (isCommon && value === value) {
8820 var valuesIndex = valuesLength;
8821 while (valuesIndex--) {
8822 if (values[valuesIndex] === value) {
8828 else if (indexOf(values, value, 0) < 0) {
8836 * The base implementation of `_.forEach` without support for callback
8837 * shorthands and `this` binding.
8840 * @param {Array|Object|string} collection The collection to iterate over.
8841 * @param {Function} iteratee The function invoked per iteration.
8842 * @returns {Array|Object|string} Returns `collection`.
8844 var baseEach = createBaseEach(baseForOwn);
8847 * The base implementation of `_.every` without support for callback
8848 * shorthands and `this` binding.
8851 * @param {Array|Object|string} collection The collection to iterate over.
8852 * @param {Function} predicate The function invoked per iteration.
8853 * @returns {boolean} Returns `true` if all elements pass the predicate check,
8856 function baseEvery(collection, predicate) {
8858 baseEach(collection, function(value, index, collection) {
8859 result = !!predicate(value, index, collection);
8866 * The base implementation of `_.filter` without support for callback
8867 * shorthands and `this` binding.
8870 * @param {Array|Object|string} collection The collection to iterate over.
8871 * @param {Function} predicate The function invoked per iteration.
8872 * @returns {Array} Returns the new filtered array.
8874 function baseFilter(collection, predicate) {
8876 baseEach(collection, function(value, index, collection) {
8877 if (predicate(value, index, collection)) {
8885 * The base implementation of `_.find`, `_.findLast`, `_.findKey`, and `_.findLastKey`,
8886 * without support for callback shorthands and `this` binding, which iterates
8887 * over `collection` using the provided `eachFunc`.
8890 * @param {Array|Object|string} collection The collection to search.
8891 * @param {Function} predicate The function invoked per iteration.
8892 * @param {Function} eachFunc The function to iterate over `collection`.
8893 * @param {boolean} [retKey] Specify returning the key of the found element
8894 * instead of the element itself.
8895 * @returns {*} Returns the found element or its key, else `undefined`.
8897 function baseFind(collection, predicate, eachFunc, retKey) {
8899 eachFunc(collection, function(value, key, collection) {
8900 if (predicate(value, key, collection)) {
8901 result = retKey ? key : value;
8909 * The base implementation of `_.flatten` with added support for restricting
8910 * flattening and specifying the start index.
8913 * @param {Array} array The array to flatten.
8914 * @param {boolean} [isDeep] Specify a deep flatten.
8915 * @param {boolean} [isStrict] Restrict flattening to arrays-like objects.
8916 * @returns {Array} Returns the new flattened array.
8918 function baseFlatten(array, isDeep, isStrict) {
8920 length = array.length,
8924 while (++index < length) {
8925 var value = array[index];
8926 if (isObjectLike(value) && isArrayLike(value) &&
8927 (isStrict || isArray(value) || isArguments(value))) {
8929 // Recursively flatten arrays (susceptible to call stack limits).
8930 value = baseFlatten(value, isDeep, isStrict);
8933 valLength = value.length;
8935 while (++valIndex < valLength) {
8936 result[++resIndex] = value[valIndex];
8938 } else if (!isStrict) {
8939 result[++resIndex] = value;
8946 * The base implementation of `baseForIn` and `baseForOwn` which iterates
8947 * over `object` properties returned by `keysFunc` invoking `iteratee` for
8948 * each property. Iteratee functions may exit iteration early by explicitly
8949 * returning `false`.
8952 * @param {Object} object The object to iterate over.
8953 * @param {Function} iteratee The function invoked per iteration.
8954 * @param {Function} keysFunc The function to get the keys of `object`.
8955 * @returns {Object} Returns `object`.
8957 var baseFor = createBaseFor();
8960 * The base implementation of `_.forIn` without support for callback
8961 * shorthands and `this` binding.
8964 * @param {Object} object The object to iterate over.
8965 * @param {Function} iteratee The function invoked per iteration.
8966 * @returns {Object} Returns `object`.
8968 function baseForIn(object, iteratee) {
8969 return baseFor(object, iteratee, keysIn);
8973 * The base implementation of `_.forOwn` without support for callback
8974 * shorthands and `this` binding.
8977 * @param {Object} object The object to iterate over.
8978 * @param {Function} iteratee The function invoked per iteration.
8979 * @returns {Object} Returns `object`.
8981 function baseForOwn(object, iteratee) {
8982 return baseFor(object, iteratee, keys);
8986 * The base implementation of `_.functions` which creates an array of
8987 * `object` function property names filtered from those provided.
8990 * @param {Object} object The object to inspect.
8991 * @param {Array} props The property names to filter.
8992 * @returns {Array} Returns the new array of filtered property names.
8994 function baseFunctions(object, props) {
8996 length = props.length,
9000 while (++index < length) {
9001 var key = props[index];
9002 if (isFunction(object[key])) {
9003 result[++resIndex] = key;
9010 * The base implementation of `get` without support for string paths
9011 * and default values.
9014 * @param {Object} object The object to query.
9015 * @param {Array} path The path of the property to get.
9016 * @param {string} [pathKey] The key representation of path.
9017 * @returns {*} Returns the resolved value.
9019 function baseGet(object, path, pathKey) {
9020 if (object == null) {
9023 object = toObject(object);
9024 if (pathKey !== undefined && pathKey in object) {
9028 length = path.length;
9030 while (object != null && index < length) {
9031 object = toObject(object)[path[index++]];
9033 return (index && index == length) ? object : undefined;
9037 * The base implementation of `_.isEqual` without support for `this` binding
9038 * `customizer` functions.
9041 * @param {*} value The value to compare.
9042 * @param {*} other The other value to compare.
9043 * @param {Function} [customizer] The function to customize comparing values.
9044 * @param {boolean} [isLoose] Specify performing partial comparisons.
9045 * @param {Array} [stackA] Tracks traversed `value` objects.
9046 * @param {Array} [stackB] Tracks traversed `other` objects.
9047 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
9049 function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) {
9050 if (value === other) {
9053 if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
9054 return value !== value && other !== other;
9056 return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB);
9060 * A specialized version of `baseIsEqual` for arrays and objects which performs
9061 * deep comparisons and tracks traversed objects enabling objects with circular
9062 * references to be compared.
9065 * @param {Object} object The object to compare.
9066 * @param {Object} other The other object to compare.
9067 * @param {Function} equalFunc The function to determine equivalents of values.
9068 * @param {Function} [customizer] The function to customize comparing objects.
9069 * @param {boolean} [isLoose] Specify performing partial comparisons.
9070 * @param {Array} [stackA=[]] Tracks traversed `value` objects.
9071 * @param {Array} [stackB=[]] Tracks traversed `other` objects.
9072 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
9074 function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
9075 var objIsArr = isArray(object),
9076 othIsArr = isArray(other),
9081 objTag = objToString.call(object);
9082 if (objTag == argsTag) {
9084 } else if (objTag != objectTag) {
9085 objIsArr = isTypedArray(object);
9089 othTag = objToString.call(other);
9090 if (othTag == argsTag) {
9092 } else if (othTag != objectTag) {
9093 othIsArr = isTypedArray(other);
9096 var objIsObj = objTag == objectTag && !isHostObject(object),
9097 othIsObj = othTag == objectTag && !isHostObject(other),
9098 isSameTag = objTag == othTag;
9100 if (isSameTag && !(objIsArr || objIsObj)) {
9101 return equalByTag(object, other, objTag);
9104 var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
9105 othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
9107 if (objIsWrapped || othIsWrapped) {
9108 return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB);
9114 // Assume cyclic values are equal.
9115 // For more information on detecting circular references see https://es5.github.io/#JO.
9116 stackA || (stackA = []);
9117 stackB || (stackB = []);
9119 var length = stackA.length;
9121 if (stackA[length] == object) {
9122 return stackB[length] == other;
9125 // Add `object` and `other` to the stack of traversed objects.
9126 stackA.push(object);
9129 var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB);
9138 * The base implementation of `_.isMatch` without support for callback
9139 * shorthands and `this` binding.
9142 * @param {Object} object The object to inspect.
9143 * @param {Array} matchData The propery names, values, and compare flags to match.
9144 * @param {Function} [customizer] The function to customize comparing objects.
9145 * @returns {boolean} Returns `true` if `object` is a match, else `false`.
9147 function baseIsMatch(object, matchData, customizer) {
9148 var index = matchData.length,
9150 noCustomizer = !customizer;
9152 if (object == null) {
9155 object = toObject(object);
9157 var data = matchData[index];
9158 if ((noCustomizer && data[2])
9159 ? data[1] !== object[data[0]]
9160 : !(data[0] in object)
9165 while (++index < length) {
9166 data = matchData[index];
9168 objValue = object[key],
9171 if (noCustomizer && data[2]) {
9172 if (objValue === undefined && !(key in object)) {
9176 var result = customizer ? customizer(objValue, srcValue, key) : undefined;
9177 if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, true) : result)) {
9186 * The base implementation of `_.map` without support for callback shorthands
9187 * and `this` binding.
9190 * @param {Array|Object|string} collection The collection to iterate over.
9191 * @param {Function} iteratee The function invoked per iteration.
9192 * @returns {Array} Returns the new mapped array.
9194 function baseMap(collection, iteratee) {
9196 result = isArrayLike(collection) ? Array(collection.length) : [];
9198 baseEach(collection, function(value, key, collection) {
9199 result[++index] = iteratee(value, key, collection);
9205 * The base implementation of `_.matches` which does not clone `source`.
9208 * @param {Object} source The object of property values to match.
9209 * @returns {Function} Returns the new function.
9211 function baseMatches(source) {
9212 var matchData = getMatchData(source);
9213 if (matchData.length == 1 && matchData[0][2]) {
9214 var key = matchData[0][0],
9215 value = matchData[0][1];
9217 return function(object) {
9218 if (object == null) {
9221 object = toObject(object);
9222 return object[key] === value && (value !== undefined || (key in object));
9225 return function(object) {
9226 return baseIsMatch(object, matchData);
9231 * The base implementation of `_.matchesProperty` which does not clone `srcValue`.
9234 * @param {string} path The path of the property to get.
9235 * @param {*} srcValue The value to compare.
9236 * @returns {Function} Returns the new function.
9238 function baseMatchesProperty(path, srcValue) {
9239 var isArr = isArray(path),
9240 isCommon = isKey(path) && isStrictComparable(srcValue),
9241 pathKey = (path + '');
9243 path = toPath(path);
9244 return function(object) {
9245 if (object == null) {
9249 object = toObject(object);
9250 if ((isArr || !isCommon) && !(key in object)) {
9251 object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
9252 if (object == null) {
9256 object = toObject(object);
9258 return object[key] === srcValue
9259 ? (srcValue !== undefined || (key in object))
9260 : baseIsEqual(srcValue, object[key], undefined, true);
9265 * The base implementation of `_.merge` without support for argument juggling,
9266 * multiple sources, and `this` binding `customizer` functions.
9269 * @param {Object} object The destination object.
9270 * @param {Object} source The source object.
9271 * @param {Function} [customizer] The function to customize merging properties.
9272 * @param {Array} [stackA=[]] Tracks traversed source objects.
9273 * @param {Array} [stackB=[]] Associates values with source counterparts.
9274 * @returns {Object} Returns `object`.
9276 function baseMerge(object, source, customizer, stackA, stackB) {
9277 if (!isObject(object)) {
9280 var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)),
9281 props = isSrcArr ? null : keys(source);
9283 arrayEach(props || source, function(srcValue, key) {
9286 srcValue = source[key];
9288 if (isObjectLike(srcValue)) {
9289 stackA || (stackA = []);
9290 stackB || (stackB = []);
9291 baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
9294 var value = object[key],
9295 result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
9296 isCommon = result === undefined;
9301 if ((result !== undefined || (isSrcArr && !(key in object))) &&
9302 (isCommon || (result === result ? (result !== value) : (value === value)))) {
9303 object[key] = result;
9311 * A specialized version of `baseMerge` for arrays and objects which performs
9312 * deep merges and tracks traversed objects enabling objects with circular
9313 * references to be merged.
9316 * @param {Object} object The destination object.
9317 * @param {Object} source The source object.
9318 * @param {string} key The key of the value to merge.
9319 * @param {Function} mergeFunc The function to merge values.
9320 * @param {Function} [customizer] The function to customize merging properties.
9321 * @param {Array} [stackA=[]] Tracks traversed source objects.
9322 * @param {Array} [stackB=[]] Associates values with source counterparts.
9323 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
9325 function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
9326 var length = stackA.length,
9327 srcValue = source[key];
9330 if (stackA[length] == srcValue) {
9331 object[key] = stackB[length];
9335 var value = object[key],
9336 result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
9337 isCommon = result === undefined;
9341 if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) {
9342 result = isArray(value)
9344 : (isArrayLike(value) ? arrayCopy(value) : []);
9346 else if (isPlainObject(srcValue) || isArguments(srcValue)) {
9347 result = isArguments(value)
9348 ? toPlainObject(value)
9349 : (isPlainObject(value) ? value : {});
9355 // Add the source value to the stack of traversed objects and associate
9356 // it with its merged value.
9357 stackA.push(srcValue);
9358 stackB.push(result);
9361 // Recursively merge objects and arrays (susceptible to call stack limits).
9362 object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
9363 } else if (result === result ? (result !== value) : (value === value)) {
9364 object[key] = result;
9369 * The base implementation of `_.property` without support for deep paths.
9372 * @param {string} key The key of the property to get.
9373 * @returns {Function} Returns the new function.
9375 function baseProperty(key) {
9376 return function(object) {
9377 return object == null ? undefined : toObject(object)[key];
9382 * A specialized version of `baseProperty` which supports deep paths.
9385 * @param {Array|string} path The path of the property to get.
9386 * @returns {Function} Returns the new function.
9388 function basePropertyDeep(path) {
9389 var pathKey = (path + '');
9390 path = toPath(path);
9391 return function(object) {
9392 return baseGet(object, path, pathKey);
9397 * The base implementation of `_.reduce` and `_.reduceRight` without support
9398 * for callback shorthands and `this` binding, which iterates over `collection`
9399 * using the provided `eachFunc`.
9402 * @param {Array|Object|string} collection The collection to iterate over.
9403 * @param {Function} iteratee The function invoked per iteration.
9404 * @param {*} accumulator The initial value.
9405 * @param {boolean} initFromCollection Specify using the first or last element
9406 * of `collection` as the initial value.
9407 * @param {Function} eachFunc The function to iterate over `collection`.
9408 * @returns {*} Returns the accumulated value.
9410 function baseReduce(collection, iteratee, accumulator, initFromCollection, eachFunc) {
9411 eachFunc(collection, function(value, index, collection) {
9412 accumulator = initFromCollection
9413 ? (initFromCollection = false, value)
9414 : iteratee(accumulator, value, index, collection);
9420 * The base implementation of `setData` without support for hot loop detection.
9423 * @param {Function} func The function to associate metadata with.
9424 * @param {*} data The metadata.
9425 * @returns {Function} Returns `func`.
9427 var baseSetData = !metaMap ? identity : function(func, data) {
9428 metaMap.set(func, data);
9433 * The base implementation of `_.slice` without an iteratee call guard.
9436 * @param {Array} array The array to slice.
9437 * @param {number} [start=0] The start position.
9438 * @param {number} [end=array.length] The end position.
9439 * @returns {Array} Returns the slice of `array`.
9441 function baseSlice(array, start, end) {
9443 length = array.length;
9445 start = start == null ? 0 : (+start || 0);
9447 start = -start > length ? 0 : (length + start);
9449 end = (end === undefined || end > length) ? length : (+end || 0);
9453 length = start > end ? 0 : ((end - start) >>> 0);
9456 var result = Array(length);
9457 while (++index < length) {
9458 result[index] = array[index + start];
9464 * The base implementation of `_.some` without support for callback shorthands
9465 * and `this` binding.
9468 * @param {Array|Object|string} collection The collection to iterate over.
9469 * @param {Function} predicate The function invoked per iteration.
9470 * @returns {boolean} Returns `true` if any element passes the predicate check,
9473 function baseSome(collection, predicate) {
9476 baseEach(collection, function(value, index, collection) {
9477 result = predicate(value, index, collection);
9484 * The base implementation of `_.uniq` without support for callback shorthands
9485 * and `this` binding.
9488 * @param {Array} array The array to inspect.
9489 * @param {Function} [iteratee] The function invoked per iteration.
9490 * @returns {Array} Returns the new duplicate-value-free array.
9492 function baseUniq(array, iteratee) {
9494 indexOf = getIndexOf(),
9495 length = array.length,
9496 isCommon = indexOf == baseIndexOf,
9497 isLarge = isCommon && length >= 200,
9498 seen = isLarge ? createCache() : null,
9502 indexOf = cacheIndexOf;
9506 seen = iteratee ? [] : result;
9509 while (++index < length) {
9510 var value = array[index],
9511 computed = iteratee ? iteratee(value, index, array) : value;
9513 if (isCommon && value === value) {
9514 var seenIndex = seen.length;
9515 while (seenIndex--) {
9516 if (seen[seenIndex] === computed) {
9521 seen.push(computed);
9525 else if (indexOf(seen, computed, 0) < 0) {
9526 if (iteratee || isLarge) {
9527 seen.push(computed);
9536 * The base implementation of `_.values` and `_.valuesIn` which creates an
9537 * array of `object` property values corresponding to the property names
9541 * @param {Object} object The object to query.
9542 * @param {Array} props The property names to get values for.
9543 * @returns {Object} Returns the array of property values.
9545 function baseValues(object, props) {
9547 length = props.length,
9548 result = Array(length);
9550 while (++index < length) {
9551 result[index] = object[props[index]];
9557 * The base implementation of `wrapperValue` which returns the result of
9558 * performing a sequence of actions on the unwrapped `value`, where each
9559 * successive action is supplied the return value of the previous.
9562 * @param {*} value The unwrapped value.
9563 * @param {Array} actions Actions to peform to resolve the unwrapped value.
9564 * @returns {*} Returns the resolved value.
9566 function baseWrapperValue(value, actions) {
9568 if (result instanceof LazyWrapper) {
9569 result = result.value();
9572 length = actions.length;
9574 while (++index < length) {
9575 var args = [result],
9576 action = actions[index];
9578 push.apply(args, action.args);
9579 result = action.func.apply(action.thisArg, args);
9585 * Performs a binary search of `array` to determine the index at which `value`
9586 * should be inserted into `array` in order to maintain its sort order.
9589 * @param {Array} array The sorted array to inspect.
9590 * @param {*} value The value to evaluate.
9591 * @param {boolean} [retHighest] Specify returning the highest qualified index.
9592 * @returns {number} Returns the index at which `value` should be inserted
9595 function binaryIndex(array, value, retHighest) {
9597 high = array ? array.length : low;
9599 if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
9600 while (low < high) {
9601 var mid = (low + high) >>> 1,
9602 computed = array[mid];
9604 if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) {
9612 return binaryIndexBy(array, value, identity, retHighest);
9616 * This function is like `binaryIndex` except that it invokes `iteratee` for
9617 * `value` and each element of `array` to compute their sort ranking. The
9618 * iteratee is invoked with one argument; (value).
9621 * @param {Array} array The sorted array to inspect.
9622 * @param {*} value The value to evaluate.
9623 * @param {Function} iteratee The function invoked per iteration.
9624 * @param {boolean} [retHighest] Specify returning the highest qualified index.
9625 * @returns {number} Returns the index at which `value` should be inserted
9628 function binaryIndexBy(array, value, iteratee, retHighest) {
9629 value = iteratee(value);
9632 high = array ? array.length : 0,
9633 valIsNaN = value !== value,
9634 valIsNull = value === null,
9635 valIsUndef = value === undefined;
9637 while (low < high) {
9638 var mid = floor((low + high) / 2),
9639 computed = iteratee(array[mid]),
9640 isDef = computed !== undefined,
9641 isReflexive = computed === computed;
9644 var setLow = isReflexive || retHighest;
9645 } else if (valIsNull) {
9646 setLow = isReflexive && isDef && (retHighest || computed != null);
9647 } else if (valIsUndef) {
9648 setLow = isReflexive && (retHighest || isDef);
9649 } else if (computed == null) {
9652 setLow = retHighest ? (computed <= value) : (computed < value);
9660 return nativeMin(high, MAX_ARRAY_INDEX);
9664 * A specialized version of `baseCallback` which only supports `this` binding
9665 * and specifying the number of arguments to provide to `func`.
9668 * @param {Function} func The function to bind.
9669 * @param {*} thisArg The `this` binding of `func`.
9670 * @param {number} [argCount] The number of arguments to provide to `func`.
9671 * @returns {Function} Returns the callback.
9673 function bindCallback(func, thisArg, argCount) {
9674 if (typeof func != 'function') {
9677 if (thisArg === undefined) {
9681 case 1: return function(value) {
9682 return func.call(thisArg, value);
9684 case 3: return function(value, index, collection) {
9685 return func.call(thisArg, value, index, collection);
9687 case 4: return function(accumulator, value, index, collection) {
9688 return func.call(thisArg, accumulator, value, index, collection);
9690 case 5: return function(value, other, key, object, source) {
9691 return func.call(thisArg, value, other, key, object, source);
9695 return func.apply(thisArg, arguments);
9700 * Creates a clone of the given array buffer.
9703 * @param {ArrayBuffer} buffer The array buffer to clone.
9704 * @returns {ArrayBuffer} Returns the cloned array buffer.
9706 function bufferClone(buffer) {
9707 return bufferSlice.call(buffer, 0);
9710 // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`.
9711 bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) {
9712 var byteLength = buffer.byteLength,
9713 floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0,
9714 offset = floatLength * FLOAT64_BYTES_PER_ELEMENT,
9715 result = new ArrayBuffer(byteLength);
9718 var view = new Float64Array(result, 0, floatLength);
9719 view.set(new Float64Array(buffer, 0, floatLength));
9721 if (byteLength != offset) {
9722 view = new Uint8Array(result, offset);
9723 view.set(new Uint8Array(buffer, offset));
9730 * Creates an array that is the composition of partially applied arguments,
9731 * placeholders, and provided arguments into a single array of arguments.
9734 * @param {Array|Object} args The provided arguments.
9735 * @param {Array} partials The arguments to prepend to those provided.
9736 * @param {Array} holders The `partials` placeholder indexes.
9737 * @returns {Array} Returns the new array of composed arguments.
9739 function composeArgs(args, partials, holders) {
9740 var holdersLength = holders.length,
9742 argsLength = nativeMax(args.length - holdersLength, 0),
9744 leftLength = partials.length,
9745 result = Array(argsLength + leftLength);
9747 while (++leftIndex < leftLength) {
9748 result[leftIndex] = partials[leftIndex];
9750 while (++argsIndex < holdersLength) {
9751 result[holders[argsIndex]] = args[argsIndex];
9753 while (argsLength--) {
9754 result[leftIndex++] = args[argsIndex++];
9760 * This function is like `composeArgs` except that the arguments composition
9761 * is tailored for `_.partialRight`.
9764 * @param {Array|Object} args The provided arguments.
9765 * @param {Array} partials The arguments to append to those provided.
9766 * @param {Array} holders The `partials` placeholder indexes.
9767 * @returns {Array} Returns the new array of composed arguments.
9769 function composeArgsRight(args, partials, holders) {
9770 var holdersIndex = -1,
9771 holdersLength = holders.length,
9773 argsLength = nativeMax(args.length - holdersLength, 0),
9775 rightLength = partials.length,
9776 result = Array(argsLength + rightLength);
9778 while (++argsIndex < argsLength) {
9779 result[argsIndex] = args[argsIndex];
9781 var offset = argsIndex;
9782 while (++rightIndex < rightLength) {
9783 result[offset + rightIndex] = partials[rightIndex];
9785 while (++holdersIndex < holdersLength) {
9786 result[offset + holders[holdersIndex]] = args[argsIndex++];
9792 * Creates a function that aggregates a collection, creating an accumulator
9793 * object composed from the results of running each element in the collection
9794 * through an iteratee.
9796 * **Note:** This function is used to create `_.countBy`, `_.groupBy`, `_.indexBy`,
9797 * and `_.partition`.
9800 * @param {Function} setter The function to set keys and values of the accumulator object.
9801 * @param {Function} [initializer] The function to initialize the accumulator object.
9802 * @returns {Function} Returns the new aggregator function.
9804 function createAggregator(setter, initializer) {
9805 return function(collection, iteratee, thisArg) {
9806 var result = initializer ? initializer() : {};
9807 iteratee = getCallback(iteratee, thisArg, 3);
9809 if (isArray(collection)) {
9811 length = collection.length;
9813 while (++index < length) {
9814 var value = collection[index];
9815 setter(result, value, iteratee(value, index, collection), collection);
9818 baseEach(collection, function(value, key, collection) {
9819 setter(result, value, iteratee(value, key, collection), collection);
9827 * Creates a function that assigns properties of source object(s) to a given
9828 * destination object.
9830 * **Note:** This function is used to create `_.assign`, `_.defaults`, and `_.merge`.
9833 * @param {Function} assigner The function to assign values.
9834 * @returns {Function} Returns the new assigner function.
9836 function createAssigner(assigner) {
9837 return restParam(function(object, sources) {
9839 length = object == null ? 0 : sources.length,
9840 customizer = length > 2 ? sources[length - 2] : undefined,
9841 guard = length > 2 ? sources[2] : undefined,
9842 thisArg = length > 1 ? sources[length - 1] : undefined;
9844 if (typeof customizer == 'function') {
9845 customizer = bindCallback(customizer, thisArg, 5);
9848 customizer = typeof thisArg == 'function' ? thisArg : undefined;
9849 length -= (customizer ? 1 : 0);
9851 if (guard && isIterateeCall(sources[0], sources[1], guard)) {
9852 customizer = length < 3 ? undefined : customizer;
9855 while (++index < length) {
9856 var source = sources[index];
9858 assigner(object, source, customizer);
9866 * Creates a `baseEach` or `baseEachRight` function.
9869 * @param {Function} eachFunc The function to iterate over a collection.
9870 * @param {boolean} [fromRight] Specify iterating from right to left.
9871 * @returns {Function} Returns the new base function.
9873 function createBaseEach(eachFunc, fromRight) {
9874 return function(collection, iteratee) {
9875 var length = collection ? getLength(collection) : 0;
9876 if (!isLength(length)) {
9877 return eachFunc(collection, iteratee);
9879 var index = fromRight ? length : -1,
9880 iterable = toObject(collection);
9882 while ((fromRight ? index-- : ++index < length)) {
9883 if (iteratee(iterable[index], index, iterable) === false) {
9892 * Creates a base function for `_.forIn` or `_.forInRight`.
9895 * @param {boolean} [fromRight] Specify iterating from right to left.
9896 * @returns {Function} Returns the new base function.
9898 function createBaseFor(fromRight) {
9899 return function(object, iteratee, keysFunc) {
9900 var iterable = toObject(object),
9901 props = keysFunc(object),
9902 length = props.length,
9903 index = fromRight ? length : -1;
9905 while ((fromRight ? index-- : ++index < length)) {
9906 var key = props[index];
9907 if (iteratee(iterable[key], key, iterable) === false) {
9916 * Creates a function that wraps `func` and invokes it with the `this`
9917 * binding of `thisArg`.
9920 * @param {Function} func The function to bind.
9921 * @param {*} [thisArg] The `this` binding of `func`.
9922 * @returns {Function} Returns the new bound function.
9924 function createBindWrapper(func, thisArg) {
9925 var Ctor = createCtorWrapper(func);
9927 function wrapper() {
9928 var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
9929 return fn.apply(thisArg, arguments);
9935 * Creates a `Set` cache object to optimize linear searches of large arrays.
9938 * @param {Array} [values] The values to cache.
9939 * @returns {null|Object} Returns the new cache object if `Set` is supported, else `null`.
9941 var createCache = !(nativeCreate && Set) ? constant(null) : function(values) {
9942 return new SetCache(values);
9946 * Creates a function that produces an instance of `Ctor` regardless of
9947 * whether it was invoked as part of a `new` expression or by `call` or `apply`.
9950 * @param {Function} Ctor The constructor to wrap.
9951 * @returns {Function} Returns the new wrapped function.
9953 function createCtorWrapper(Ctor) {
9955 // Use a `switch` statement to work with class constructors.
9956 // See https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-function-objects-call-thisargument-argumentslist
9957 // for more details.
9958 var args = arguments;
9959 switch (args.length) {
9960 case 0: return new Ctor;
9961 case 1: return new Ctor(args[0]);
9962 case 2: return new Ctor(args[0], args[1]);
9963 case 3: return new Ctor(args[0], args[1], args[2]);
9964 case 4: return new Ctor(args[0], args[1], args[2], args[3]);
9965 case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
9967 var thisBinding = baseCreate(Ctor.prototype),
9968 result = Ctor.apply(thisBinding, args);
9970 // Mimic the constructor's `return` behavior.
9971 // See https://es5.github.io/#x13.2.2 for more details.
9972 return isObject(result) ? result : thisBinding;
9977 * Creates a `_.find` or `_.findLast` function.
9980 * @param {Function} eachFunc The function to iterate over a collection.
9981 * @param {boolean} [fromRight] Specify iterating from right to left.
9982 * @returns {Function} Returns the new find function.
9984 function createFind(eachFunc, fromRight) {
9985 return function(collection, predicate, thisArg) {
9986 predicate = getCallback(predicate, thisArg, 3);
9987 if (isArray(collection)) {
9988 var index = baseFindIndex(collection, predicate, fromRight);
9989 return index > -1 ? collection[index] : undefined;
9991 return baseFind(collection, predicate, eachFunc);
9996 * Creates a function for `_.forEach` or `_.forEachRight`.
9999 * @param {Function} arrayFunc The function to iterate over an array.
10000 * @param {Function} eachFunc The function to iterate over a collection.
10001 * @returns {Function} Returns the new each function.
10003 function createForEach(arrayFunc, eachFunc) {
10004 return function(collection, iteratee, thisArg) {
10005 return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))
10006 ? arrayFunc(collection, iteratee)
10007 : eachFunc(collection, bindCallback(iteratee, thisArg, 3));
10012 * Creates a function for `_.forOwn` or `_.forOwnRight`.
10015 * @param {Function} objectFunc The function to iterate over an object.
10016 * @returns {Function} Returns the new each function.
10018 function createForOwn(objectFunc) {
10019 return function(object, iteratee, thisArg) {
10020 if (typeof iteratee != 'function' || thisArg !== undefined) {
10021 iteratee = bindCallback(iteratee, thisArg, 3);
10023 return objectFunc(object, iteratee);
10028 * Creates a function for `_.reduce` or `_.reduceRight`.
10031 * @param {Function} arrayFunc The function to iterate over an array.
10032 * @param {Function} eachFunc The function to iterate over a collection.
10033 * @returns {Function} Returns the new each function.
10035 function createReduce(arrayFunc, eachFunc) {
10036 return function(collection, iteratee, accumulator, thisArg) {
10037 var initFromArray = arguments.length < 3;
10038 return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))
10039 ? arrayFunc(collection, iteratee, accumulator, initFromArray)
10040 : baseReduce(collection, getCallback(iteratee, thisArg, 4), accumulator, initFromArray, eachFunc);
10045 * Creates a function that wraps `func` and invokes it with optional `this`
10046 * binding of, partial application, and currying.
10049 * @param {Function|string} func The function or method name to reference.
10050 * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
10051 * @param {*} [thisArg] The `this` binding of `func`.
10052 * @param {Array} [partials] The arguments to prepend to those provided to the new function.
10053 * @param {Array} [holders] The `partials` placeholder indexes.
10054 * @param {Array} [partialsRight] The arguments to append to those provided to the new function.
10055 * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
10056 * @param {Array} [argPos] The argument positions of the new function.
10057 * @param {number} [ary] The arity cap of `func`.
10058 * @param {number} [arity] The arity of `func`.
10059 * @returns {Function} Returns the new wrapped function.
10061 function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
10062 var isAry = bitmask & ARY_FLAG,
10063 isBind = bitmask & BIND_FLAG,
10064 isBindKey = bitmask & BIND_KEY_FLAG,
10065 isCurry = bitmask & CURRY_FLAG,
10066 isCurryBound = bitmask & CURRY_BOUND_FLAG,
10067 isCurryRight = bitmask & CURRY_RIGHT_FLAG,
10068 Ctor = isBindKey ? null : createCtorWrapper(func);
10070 function wrapper() {
10071 // Avoid `arguments` object use disqualifying optimizations by
10072 // converting it to an array before providing it to other functions.
10073 var length = arguments.length,
10075 args = Array(length);
10078 args[index] = arguments[index];
10081 args = composeArgs(args, partials, holders);
10083 if (partialsRight) {
10084 args = composeArgsRight(args, partialsRight, holdersRight);
10086 if (isCurry || isCurryRight) {
10087 var placeholder = wrapper.placeholder,
10088 argsHolders = replaceHolders(args, placeholder);
10090 length -= argsHolders.length;
10091 if (length < arity) {
10092 var newArgPos = argPos ? arrayCopy(argPos) : null,
10093 newArity = nativeMax(arity - length, 0),
10094 newsHolders = isCurry ? argsHolders : null,
10095 newHoldersRight = isCurry ? null : argsHolders,
10096 newPartials = isCurry ? args : null,
10097 newPartialsRight = isCurry ? null : args;
10099 bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
10100 bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
10102 if (!isCurryBound) {
10103 bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
10105 var newData = [func, bitmask, thisArg, newPartials, newsHolders, newPartialsRight, newHoldersRight, newArgPos, ary, newArity],
10106 result = createHybridWrapper.apply(undefined, newData);
10108 if (isLaziable(func)) {
10109 setData(result, newData);
10111 result.placeholder = placeholder;
10115 var thisBinding = isBind ? thisArg : this,
10116 fn = isBindKey ? thisBinding[func] : func;
10119 args = reorder(args, argPos);
10121 if (isAry && ary < args.length) {
10124 if (this && this !== root && this instanceof wrapper) {
10125 fn = Ctor || createCtorWrapper(func);
10127 return fn.apply(thisBinding, args);
10133 * Creates a function that wraps `func` and invokes it with the optional `this`
10134 * binding of `thisArg` and the `partials` prepended to those provided to
10138 * @param {Function} func The function to partially apply arguments to.
10139 * @param {number} bitmask The bitmask of flags. See `createWrapper` for more details.
10140 * @param {*} thisArg The `this` binding of `func`.
10141 * @param {Array} partials The arguments to prepend to those provided to the new function.
10142 * @returns {Function} Returns the new bound function.
10144 function createPartialWrapper(func, bitmask, thisArg, partials) {
10145 var isBind = bitmask & BIND_FLAG,
10146 Ctor = createCtorWrapper(func);
10148 function wrapper() {
10149 // Avoid `arguments` object use disqualifying optimizations by
10150 // converting it to an array before providing it `func`.
10151 var argsIndex = -1,
10152 argsLength = arguments.length,
10154 leftLength = partials.length,
10155 args = Array(argsLength + leftLength);
10157 while (++leftIndex < leftLength) {
10158 args[leftIndex] = partials[leftIndex];
10160 while (argsLength--) {
10161 args[leftIndex++] = arguments[++argsIndex];
10163 var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
10164 return fn.apply(isBind ? thisArg : this, args);
10170 * Creates a function that either curries or invokes `func` with optional
10171 * `this` binding and partially applied arguments.
10174 * @param {Function|string} func The function or method name to reference.
10175 * @param {number} bitmask The bitmask of flags.
10176 * The bitmask may be composed of the following flags:
10179 * 4 - `_.curry` or `_.curryRight` of a bound function
10181 * 16 - `_.curryRight`
10183 * 64 - `_.partialRight`
10186 * @param {*} [thisArg] The `this` binding of `func`.
10187 * @param {Array} [partials] The arguments to be partially applied.
10188 * @param {Array} [holders] The `partials` placeholder indexes.
10189 * @param {Array} [argPos] The argument positions of the new function.
10190 * @param {number} [ary] The arity cap of `func`.
10191 * @param {number} [arity] The arity of `func`.
10192 * @returns {Function} Returns the new wrapped function.
10194 function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
10195 var isBindKey = bitmask & BIND_KEY_FLAG;
10196 if (!isBindKey && typeof func != 'function') {
10197 throw new TypeError(FUNC_ERROR_TEXT);
10199 var length = partials ? partials.length : 0;
10201 bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
10202 partials = holders = null;
10204 length -= (holders ? holders.length : 0);
10205 if (bitmask & PARTIAL_RIGHT_FLAG) {
10206 var partialsRight = partials,
10207 holdersRight = holders;
10209 partials = holders = null;
10211 var data = isBindKey ? null : getData(func),
10212 newData = [func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity];
10215 mergeData(newData, data);
10216 bitmask = newData[1];
10217 arity = newData[9];
10219 newData[9] = arity == null
10220 ? (isBindKey ? 0 : func.length)
10221 : (nativeMax(arity - length, 0) || 0);
10223 if (bitmask == BIND_FLAG) {
10224 var result = createBindWrapper(newData[0], newData[2]);
10225 } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !newData[4].length) {
10226 result = createPartialWrapper.apply(undefined, newData);
10228 result = createHybridWrapper.apply(undefined, newData);
10230 var setter = data ? baseSetData : setData;
10231 return setter(result, newData);
10235 * A specialized version of `baseIsEqualDeep` for arrays with support for
10236 * partial deep comparisons.
10239 * @param {Array} array The array to compare.
10240 * @param {Array} other The other array to compare.
10241 * @param {Function} equalFunc The function to determine equivalents of values.
10242 * @param {Function} [customizer] The function to customize comparing arrays.
10243 * @param {boolean} [isLoose] Specify performing partial comparisons.
10244 * @param {Array} [stackA] Tracks traversed `value` objects.
10245 * @param {Array} [stackB] Tracks traversed `other` objects.
10246 * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
10248 function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) {
10250 arrLength = array.length,
10251 othLength = other.length;
10253 if (arrLength != othLength && !(isLoose && othLength > arrLength)) {
10256 // Ignore non-index properties.
10257 while (++index < arrLength) {
10258 var arrValue = array[index],
10259 othValue = other[index],
10260 result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined;
10262 if (result !== undefined) {
10268 // Recursively compare arrays (susceptible to call stack limits).
10270 if (!arraySome(other, function(othValue) {
10271 return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB);
10275 } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) {
10283 * A specialized version of `baseIsEqualDeep` for comparing objects of
10284 * the same `toStringTag`.
10286 * **Note:** This function only supports comparing values with tags of
10287 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
10290 * @param {Object} value The object to compare.
10291 * @param {Object} other The other object to compare.
10292 * @param {string} tag The `toStringTag` of the objects to compare.
10293 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
10295 function equalByTag(object, other, tag) {
10299 // Coerce dates and booleans to numbers, dates to milliseconds and booleans
10300 // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
10301 return +object == +other;
10304 return object.name == other.name && object.message == other.message;
10307 // Treat `NaN` vs. `NaN` as equal.
10308 return (object != +object)
10310 : object == +other;
10314 // Coerce regexes to strings and treat strings primitives and string
10315 // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details.
10316 return object == (other + '');
10322 * A specialized version of `baseIsEqualDeep` for objects with support for
10323 * partial deep comparisons.
10326 * @param {Object} object The object to compare.
10327 * @param {Object} other The other object to compare.
10328 * @param {Function} equalFunc The function to determine equivalents of values.
10329 * @param {Function} [customizer] The function to customize comparing values.
10330 * @param {boolean} [isLoose] Specify performing partial comparisons.
10331 * @param {Array} [stackA] Tracks traversed `value` objects.
10332 * @param {Array} [stackB] Tracks traversed `other` objects.
10333 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
10335 function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
10336 var objProps = keys(object),
10337 objLength = objProps.length,
10338 othProps = keys(other),
10339 othLength = othProps.length;
10341 if (objLength != othLength && !isLoose) {
10344 var index = objLength;
10346 var key = objProps[index];
10347 if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) {
10351 var skipCtor = isLoose;
10352 while (++index < objLength) {
10353 key = objProps[index];
10354 var objValue = object[key],
10355 othValue = other[key],
10356 result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined;
10358 // Recursively compare objects (susceptible to call stack limits).
10359 if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) {
10362 skipCtor || (skipCtor = key == 'constructor');
10365 var objCtor = object.constructor,
10366 othCtor = other.constructor;
10368 // Non `Object` object instances with different constructors are not equal.
10369 if (objCtor != othCtor &&
10370 ('constructor' in object && 'constructor' in other) &&
10371 !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
10372 typeof othCtor == 'function' && othCtor instanceof othCtor)) {
10380 * Gets the appropriate "callback" function. If the `_.callback` method is
10381 * customized this function returns the custom method, otherwise it returns
10382 * the `baseCallback` function. If arguments are provided the chosen function
10383 * is invoked with them and its result is returned.
10386 * @returns {Function} Returns the chosen function or its result.
10388 function getCallback(func, thisArg, argCount) {
10389 var result = lodash.callback || callback;
10390 result = result === callback ? baseCallback : result;
10391 return argCount ? result(func, thisArg, argCount) : result;
10395 * Gets metadata for `func`.
10398 * @param {Function} func The function to query.
10399 * @returns {*} Returns the metadata for `func`.
10401 var getData = !metaMap ? noop : function(func) {
10402 return metaMap.get(func);
10406 * Gets the name of `func`.
10409 * @param {Function} func The function to query.
10410 * @returns {string} Returns the function name.
10412 function getFuncName(func) {
10413 var result = func.name,
10414 array = realNames[result],
10415 length = array ? array.length : 0;
10418 var data = array[length],
10419 otherFunc = data.func;
10420 if (otherFunc == null || otherFunc == func) {
10428 * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
10429 * customized this function returns the custom method, otherwise it returns
10430 * the `baseIndexOf` function. If arguments are provided the chosen function
10431 * is invoked with them and its result is returned.
10434 * @returns {Function|number} Returns the chosen function or its result.
10436 function getIndexOf(collection, target, fromIndex) {
10437 var result = lodash.indexOf || indexOf;
10438 result = result === indexOf ? baseIndexOf : result;
10439 return collection ? result(collection, target, fromIndex) : result;
10443 * Gets the "length" property value of `object`.
10445 * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
10446 * that affects Safari on at least iOS 8.1-8.3 ARM64.
10449 * @param {Object} object The object to query.
10450 * @returns {*} Returns the "length" value.
10452 var getLength = baseProperty('length');
10455 * Gets the propery names, values, and compare flags of `object`.
10458 * @param {Object} object The object to query.
10459 * @returns {Array} Returns the match data of `object`.
10461 function getMatchData(object) {
10462 var result = pairs(object),
10463 length = result.length;
10466 result[length][2] = isStrictComparable(result[length][1]);
10472 * Gets the native function at `key` of `object`.
10475 * @param {Object} object The object to query.
10476 * @param {string} key The key of the method to get.
10477 * @returns {*} Returns the function if it's native, else `undefined`.
10479 function getNative(object, key) {
10480 var value = object == null ? undefined : object[key];
10481 return isNative(value) ? value : undefined;
10485 * Gets the view, applying any `transforms` to the `start` and `end` positions.
10488 * @param {number} start The start of the view.
10489 * @param {number} end The end of the view.
10490 * @param {Array} [transforms] The transformations to apply to the view.
10491 * @returns {Object} Returns an object containing the `start` and `end`
10492 * positions of the view.
10494 function getView(start, end, transforms) {
10496 length = transforms ? transforms.length : 0;
10498 while (++index < length) {
10499 var data = transforms[index],
10502 switch (data.type) {
10503 case 'drop': start += size; break;
10504 case 'dropRight': end -= size; break;
10505 case 'take': end = nativeMin(end, start + size); break;
10506 case 'takeRight': start = nativeMax(start, end - size); break;
10509 return { 'start': start, 'end': end };
10513 * Initializes an array clone.
10516 * @param {Array} array The array to clone.
10517 * @returns {Array} Returns the initialized clone.
10519 function initCloneArray(array) {
10520 var length = array.length,
10521 result = new array.constructor(length);
10523 // Add array properties assigned by `RegExp#exec`.
10524 if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
10525 result.index = array.index;
10526 result.input = array.input;
10532 * Initializes an object clone.
10535 * @param {Object} object The object to clone.
10536 * @returns {Object} Returns the initialized clone.
10538 function initCloneObject(object) {
10539 var Ctor = object.constructor;
10540 if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
10547 * Initializes an object clone based on its `toStringTag`.
10549 * **Note:** This function only supports cloning values with tags of
10550 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
10553 * @param {Object} object The object to clone.
10554 * @param {string} tag The `toStringTag` of the object to clone.
10555 * @param {boolean} [isDeep] Specify a deep clone.
10556 * @returns {Object} Returns the initialized clone.
10558 function initCloneByTag(object, tag, isDeep) {
10559 var Ctor = object.constructor;
10561 case arrayBufferTag:
10562 return bufferClone(object);
10566 return new Ctor(+object);
10568 case float32Tag: case float64Tag:
10569 case int8Tag: case int16Tag: case int32Tag:
10570 case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
10571 // Safari 5 mobile incorrectly has `Object` as the constructor of typed arrays.
10572 if (Ctor instanceof Ctor) {
10573 Ctor = ctorByTag[tag];
10575 var buffer = object.buffer;
10576 return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
10580 return new Ctor(object);
10583 var result = new Ctor(object.source, reFlags.exec(object));
10584 result.lastIndex = object.lastIndex;
10590 * Checks if `value` is array-like.
10593 * @param {*} value The value to check.
10594 * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
10596 function isArrayLike(value) {
10597 return value != null && isLength(getLength(value));
10601 * Checks if `value` is a valid array-like index.
10604 * @param {*} value The value to check.
10605 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
10606 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
10608 function isIndex(value, length) {
10609 value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
10610 length = length == null ? MAX_SAFE_INTEGER : length;
10611 return value > -1 && value % 1 == 0 && value < length;
10615 * Checks if the provided arguments are from an iteratee call.
10618 * @param {*} value The potential iteratee value argument.
10619 * @param {*} index The potential iteratee index or key argument.
10620 * @param {*} object The potential iteratee object argument.
10621 * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
10623 function isIterateeCall(value, index, object) {
10624 if (!isObject(object)) {
10627 var type = typeof index;
10628 if (type == 'number'
10629 ? (isArrayLike(object) && isIndex(index, object.length))
10630 : (type == 'string' && index in object)) {
10631 var other = object[index];
10632 return value === value ? (value === other) : (other !== other);
10638 * Checks if `value` is a property name and not a property path.
10641 * @param {*} value The value to check.
10642 * @param {Object} [object] The object to query keys on.
10643 * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
10645 function isKey(value, object) {
10646 var type = typeof value;
10647 if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') {
10650 if (isArray(value)) {
10653 var result = !reIsDeepProp.test(value);
10654 return result || (object != null && value in toObject(object));
10658 * Checks if `func` has a lazy counterpart.
10661 * @param {Function} func The function to check.
10662 * @returns {boolean} Returns `true` if `func` has a lazy counterpart, else `false`.
10664 function isLaziable(func) {
10665 var funcName = getFuncName(func);
10666 if (!(funcName in LazyWrapper.prototype)) {
10669 var other = lodash[funcName];
10670 if (func === other) {
10673 var data = getData(other);
10674 return !!data && func === data[0];
10678 * Checks if `value` is a valid array-like length.
10680 * **Note:** This function is based on [`ToLength`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength).
10683 * @param {*} value The value to check.
10684 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
10686 function isLength(value) {
10687 return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
10691 * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
10694 * @param {*} value The value to check.
10695 * @returns {boolean} Returns `true` if `value` if suitable for strict
10696 * equality comparisons, else `false`.
10698 function isStrictComparable(value) {
10699 return value === value && !isObject(value);
10703 * Merges the function metadata of `source` into `data`.
10705 * Merging metadata reduces the number of wrappers required to invoke a function.
10706 * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
10707 * may be applied regardless of execution order. Methods like `_.ary` and `_.rearg`
10708 * augment function arguments, making the order in which they are executed important,
10709 * preventing the merging of metadata. However, we make an exception for a safe
10710 * common case where curried functions have `_.ary` and or `_.rearg` applied.
10713 * @param {Array} data The destination metadata.
10714 * @param {Array} source The source metadata.
10715 * @returns {Array} Returns `data`.
10717 function mergeData(data, source) {
10718 var bitmask = data[1],
10719 srcBitmask = source[1],
10720 newBitmask = bitmask | srcBitmask,
10721 isCommon = newBitmask < ARY_FLAG;
10724 (srcBitmask == ARY_FLAG && bitmask == CURRY_FLAG) ||
10725 (srcBitmask == ARY_FLAG && bitmask == REARG_FLAG && data[7].length <= source[8]) ||
10726 (srcBitmask == (ARY_FLAG | REARG_FLAG) && bitmask == CURRY_FLAG);
10728 // Exit early if metadata can't be merged.
10729 if (!(isCommon || isCombo)) {
10732 // Use source `thisArg` if available.
10733 if (srcBitmask & BIND_FLAG) {
10734 data[2] = source[2];
10735 // Set when currying a bound function.
10736 newBitmask |= (bitmask & BIND_FLAG) ? 0 : CURRY_BOUND_FLAG;
10738 // Compose partial arguments.
10739 var value = source[3];
10741 var partials = data[3];
10742 data[3] = partials ? composeArgs(partials, value, source[4]) : arrayCopy(value);
10743 data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : arrayCopy(source[4]);
10745 // Compose partial right arguments.
10748 partials = data[5];
10749 data[5] = partials ? composeArgsRight(partials, value, source[6]) : arrayCopy(value);
10750 data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : arrayCopy(source[6]);
10752 // Use source `argPos` if available.
10755 data[7] = arrayCopy(value);
10757 // Use source `ary` if it's smaller.
10758 if (srcBitmask & ARY_FLAG) {
10759 data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
10761 // Use source `arity` if one is not provided.
10762 if (data[9] == null) {
10763 data[9] = source[9];
10765 // Use source `func` and merge bitmasks.
10766 data[0] = source[0];
10767 data[1] = newBitmask;
10773 * A specialized version of `_.pick` which picks `object` properties specified
10777 * @param {Object} object The source object.
10778 * @param {string[]} props The property names to pick.
10779 * @returns {Object} Returns the new object.
10781 function pickByArray(object, props) {
10782 object = toObject(object);
10785 length = props.length,
10788 while (++index < length) {
10789 var key = props[index];
10790 if (key in object) {
10791 result[key] = object[key];
10798 * A specialized version of `_.pick` which picks `object` properties `predicate`
10799 * returns truthy for.
10802 * @param {Object} object The source object.
10803 * @param {Function} predicate The function invoked per iteration.
10804 * @returns {Object} Returns the new object.
10806 function pickByCallback(object, predicate) {
10808 baseForIn(object, function(value, key, object) {
10809 if (predicate(value, key, object)) {
10810 result[key] = value;
10817 * Reorder `array` according to the specified indexes where the element at
10818 * the first index is assigned as the first element, the element at
10819 * the second index is assigned as the second element, and so on.
10822 * @param {Array} array The array to reorder.
10823 * @param {Array} indexes The arranged array indexes.
10824 * @returns {Array} Returns `array`.
10826 function reorder(array, indexes) {
10827 var arrLength = array.length,
10828 length = nativeMin(indexes.length, arrLength),
10829 oldArray = arrayCopy(array);
10832 var index = indexes[length];
10833 array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
10839 * Sets metadata for `func`.
10841 * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
10842 * period of time, it will trip its breaker and transition to an identity function
10843 * to avoid garbage collection pauses in V8. See [V8 issue 2070](https://code.google.com/p/v8/issues/detail?id=2070)
10844 * for more details.
10847 * @param {Function} func The function to associate metadata with.
10848 * @param {*} data The metadata.
10849 * @returns {Function} Returns `func`.
10851 var setData = (function() {
10855 return function(key, value) {
10857 remaining = HOT_SPAN - (stamp - lastCalled);
10859 lastCalled = stamp;
10860 if (remaining > 0) {
10861 if (++count >= HOT_COUNT) {
10867 return baseSetData(key, value);
10872 * A fallback implementation of `_.isPlainObject` which checks if `value`
10873 * is an object created by the `Object` constructor or has a `[[Prototype]]`
10877 * @param {*} value The value to check.
10878 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
10880 function shimIsPlainObject(value) {
10882 support = lodash.support;
10884 // Exit early for non `Object` objects.
10885 if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isHostObject(value)) ||
10886 (!hasOwnProperty.call(value, 'constructor') &&
10887 (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor))) ||
10888 (!support.argsTag && isArguments(value))) {
10891 // IE < 9 iterates inherited properties before own properties. If the first
10892 // iterated property is an object's own property then there are no inherited
10893 // enumerable properties.
10895 if (support.ownLast) {
10896 baseForIn(value, function(subValue, key, object) {
10897 result = hasOwnProperty.call(object, key);
10900 return result !== false;
10902 // In most environments an object's own properties are iterated before
10903 // its inherited properties. If the last iterated property is an object's
10904 // own property then there are no inherited enumerable properties.
10905 baseForIn(value, function(subValue, key) {
10908 return result === undefined || hasOwnProperty.call(value, result);
10912 * A fallback implementation of `Object.keys` which creates an array of the
10913 * own enumerable property names of `object`.
10916 * @param {Object} object The object to query.
10917 * @returns {Array} Returns the array of property names.
10919 function shimKeys(object) {
10920 var props = keysIn(object),
10921 propsLength = props.length,
10922 length = propsLength && object.length;
10924 var allowIndexes = !!length && isLength(length) &&
10925 (isArray(object) || isArguments(object) || isString(object));
10930 while (++index < propsLength) {
10931 var key = props[index];
10932 if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
10940 * Converts `value` to an object if it's not one.
10943 * @param {*} value The value to process.
10944 * @returns {Object} Returns the object.
10946 function toObject(value) {
10947 if (lodash.support.unindexedChars && isString(value)) {
10949 length = value.length,
10950 result = Object(value);
10952 while (++index < length) {
10953 result[index] = value.charAt(index);
10957 return isObject(value) ? value : Object(value);
10961 * Converts `value` to property path array if it's not one.
10964 * @param {*} value The value to process.
10965 * @returns {Array} Returns the property path array.
10967 function toPath(value) {
10968 if (isArray(value)) {
10972 baseToString(value).replace(rePropName, function(match, number, quote, string) {
10973 result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
10979 * Creates a clone of `wrapper`.
10982 * @param {Object} wrapper The wrapper to clone.
10983 * @returns {Object} Returns the cloned wrapper.
10985 function wrapperClone(wrapper) {
10986 return wrapper instanceof LazyWrapper
10988 : new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__, arrayCopy(wrapper.__actions__));
10991 /*------------------------------------------------------------------------*/
10994 * Creates an array of elements split into groups the length of `size`.
10995 * If `collection` can't be split evenly, the final chunk will be the remaining
11001 * @param {Array} array The array to process.
11002 * @param {number} [size=1] The length of each chunk.
11003 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
11004 * @returns {Array} Returns the new array containing chunks.
11007 * _.chunk(['a', 'b', 'c', 'd'], 2);
11008 * // => [['a', 'b'], ['c', 'd']]
11010 * _.chunk(['a', 'b', 'c', 'd'], 3);
11011 * // => [['a', 'b', 'c'], ['d']]
11013 function chunk(array, size, guard) {
11014 if (guard ? isIterateeCall(array, size, guard) : size == null) {
11017 size = nativeMax(+size || 1, 1);
11020 length = array ? array.length : 0,
11022 result = Array(ceil(length / size));
11024 while (index < length) {
11025 result[++resIndex] = baseSlice(array, index, (index += size));
11031 * Creates an array with all falsey values removed. The values `false`, `null`,
11032 * `0`, `""`, `undefined`, and `NaN` are falsey.
11037 * @param {Array} array The array to compact.
11038 * @returns {Array} Returns the new array of filtered values.
11041 * _.compact([0, 1, false, 2, '', 3]);
11044 function compact(array) {
11046 length = array ? array.length : 0,
11050 while (++index < length) {
11051 var value = array[index];
11053 result[++resIndex] = value;
11060 * Creates an array of unique `array` values not included in the other
11061 * provided arrays using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11062 * for equality comparisons.
11067 * @param {Array} array The array to inspect.
11068 * @param {...Array} [values] The arrays of values to exclude.
11069 * @returns {Array} Returns the new array of filtered values.
11072 * _.difference([1, 2, 3], [4, 2]);
11075 var difference = restParam(function(array, values) {
11076 return isArrayLike(array)
11077 ? baseDifference(array, baseFlatten(values, false, true))
11082 * Gets the first element of `array`.
11088 * @param {Array} array The array to query.
11089 * @returns {*} Returns the first element of `array`.
11092 * _.first([1, 2, 3]);
11098 function first(array) {
11099 return array ? array[0] : undefined;
11103 * Flattens a nested array. If `isDeep` is `true` the array is recursively
11104 * flattened, otherwise it is only flattened a single level.
11109 * @param {Array} array The array to flatten.
11110 * @param {boolean} [isDeep] Specify a deep flatten.
11111 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
11112 * @returns {Array} Returns the new flattened array.
11115 * _.flatten([1, [2, 3, [4]]]);
11116 * // => [1, 2, 3, [4]]
11118 * // using `isDeep`
11119 * _.flatten([1, [2, 3, [4]]], true);
11120 * // => [1, 2, 3, 4]
11122 function flatten(array, isDeep, guard) {
11123 var length = array ? array.length : 0;
11124 if (guard && isIterateeCall(array, isDeep, guard)) {
11127 return length ? baseFlatten(array, isDeep) : [];
11131 * Gets the index at which the first occurrence of `value` is found in `array`
11132 * using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11133 * for equality comparisons. If `fromIndex` is negative, it is used as the offset
11134 * from the end of `array`. If `array` is sorted providing `true` for `fromIndex`
11135 * performs a faster binary search.
11140 * @param {Array} array The array to search.
11141 * @param {*} value The value to search for.
11142 * @param {boolean|number} [fromIndex=0] The index to search from or `true`
11143 * to perform a binary search on a sorted array.
11144 * @returns {number} Returns the index of the matched value, else `-1`.
11147 * _.indexOf([1, 2, 1, 2], 2);
11150 * // using `fromIndex`
11151 * _.indexOf([1, 2, 1, 2], 2, 2);
11154 * // performing a binary search
11155 * _.indexOf([1, 1, 2, 2], 2, true);
11158 function indexOf(array, value, fromIndex) {
11159 var length = array ? array.length : 0;
11163 if (typeof fromIndex == 'number') {
11164 fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex;
11165 } else if (fromIndex) {
11166 var index = binaryIndex(array, value),
11167 other = array[index];
11169 if (value === value ? (value === other) : (other !== other)) {
11174 return baseIndexOf(array, value, fromIndex || 0);
11178 * Creates an array of unique values that are included in all of the provided
11179 * arrays using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11180 * for equality comparisons.
11185 * @param {...Array} [arrays] The arrays to inspect.
11186 * @returns {Array} Returns the new array of shared values.
11188 * _.intersection([1, 2], [4, 2], [2, 1]);
11191 var intersection = restParam(function(arrays) {
11192 var othLength = arrays.length,
11193 othIndex = othLength,
11194 caches = Array(length),
11195 indexOf = getIndexOf(),
11196 isCommon = indexOf == baseIndexOf,
11199 while (othIndex--) {
11200 var value = arrays[othIndex] = isArrayLike(value = arrays[othIndex]) ? value : [];
11201 caches[othIndex] = (isCommon && value.length >= 120) ? createCache(othIndex && value) : null;
11203 var array = arrays[0],
11205 length = array ? array.length : 0,
11209 while (++index < length) {
11210 value = array[index];
11211 if ((seen ? cacheIndexOf(seen, value) : indexOf(result, value, 0)) < 0) {
11212 var othIndex = othLength;
11213 while (--othIndex) {
11214 var cache = caches[othIndex];
11215 if ((cache ? cacheIndexOf(cache, value) : indexOf(arrays[othIndex], value, 0)) < 0) {
11222 result.push(value);
11229 * Gets the last element of `array`.
11234 * @param {Array} array The array to query.
11235 * @returns {*} Returns the last element of `array`.
11238 * _.last([1, 2, 3]);
11241 function last(array) {
11242 var length = array ? array.length : 0;
11243 return length ? array[length - 1] : undefined;
11247 * Creates an array of unique values, in order, from all of the provided arrays
11248 * using [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11249 * for equality comparisons.
11254 * @param {...Array} [arrays] The arrays to inspect.
11255 * @returns {Array} Returns the new array of combined values.
11258 * _.union([1, 2], [4, 2], [2, 1]);
11261 var union = restParam(function(arrays) {
11262 return baseUniq(baseFlatten(arrays, false, true));
11266 * Creates a duplicate-free version of an array, using
11267 * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11268 * for equality comparisons, in which only the first occurence of each element
11269 * is kept. Providing `true` for `isSorted` performs a faster search algorithm
11270 * for sorted arrays. If an iteratee function is provided it is invoked for
11271 * each element in the array to generate the criterion by which uniqueness
11272 * is computed. The `iteratee` is bound to `thisArg` and invoked with three
11273 * arguments: (value, index, array).
11275 * If a property name is provided for `iteratee` the created `_.property`
11276 * style callback returns the property value of the given element.
11278 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11279 * style callback returns `true` for elements that have a matching property
11280 * value, else `false`.
11282 * If an object is provided for `iteratee` the created `_.matches` style
11283 * callback returns `true` for elements that have the properties of the given
11284 * object, else `false`.
11290 * @param {Array} array The array to inspect.
11291 * @param {boolean} [isSorted] Specify the array is sorted.
11292 * @param {Function|Object|string} [iteratee] The function invoked per iteration.
11293 * @param {*} [thisArg] The `this` binding of `iteratee`.
11294 * @returns {Array} Returns the new duplicate-value-free array.
11297 * _.uniq([2, 1, 2]);
11300 * // using `isSorted`
11301 * _.uniq([1, 1, 2], true);
11304 * // using an iteratee function
11305 * _.uniq([1, 2.5, 1.5, 2], function(n) {
11306 * return this.floor(n);
11310 * // using the `_.property` callback shorthand
11311 * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
11312 * // => [{ 'x': 1 }, { 'x': 2 }]
11314 function uniq(array, isSorted, iteratee, thisArg) {
11315 var length = array ? array.length : 0;
11319 if (isSorted != null && typeof isSorted != 'boolean') {
11320 thisArg = iteratee;
11321 iteratee = isIterateeCall(array, isSorted, thisArg) ? null : isSorted;
11324 var callback = getCallback();
11325 if (!(iteratee == null && callback === baseCallback)) {
11326 iteratee = callback(iteratee, thisArg, 3);
11328 return (isSorted && getIndexOf() == baseIndexOf)
11329 ? sortedUniq(array, iteratee)
11330 : baseUniq(array, iteratee);
11334 * Creates an array excluding all provided values using
11335 * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11336 * for equality comparisons.
11341 * @param {Array} array The array to filter.
11342 * @param {...*} [values] The values to exclude.
11343 * @returns {Array} Returns the new array of filtered values.
11346 * _.without([1, 2, 1, 3], 1, 2);
11349 var without = restParam(function(array, values) {
11350 return isArrayLike(array)
11351 ? baseDifference(array, values)
11355 /*------------------------------------------------------------------------*/
11358 * Creates a `lodash` object that wraps `value` with explicit method
11359 * chaining enabled.
11364 * @param {*} value The value to wrap.
11365 * @returns {Object} Returns the new `lodash` wrapper instance.
11369 * { 'user': 'barney', 'age': 36 },
11370 * { 'user': 'fred', 'age': 40 },
11371 * { 'user': 'pebbles', 'age': 1 }
11374 * var youngest = _.chain(users)
11376 * .map(function(chr) {
11377 * return chr.user + ' is ' + chr.age;
11381 * // => 'pebbles is 1'
11383 function chain(value) {
11384 var result = lodash(value);
11385 result.__chain__ = true;
11390 * This method invokes `interceptor` and returns `value`. The interceptor is
11391 * bound to `thisArg` and invoked with one argument; (value). The purpose of
11392 * this method is to "tap into" a method chain in order to perform operations
11393 * on intermediate results within the chain.
11398 * @param {*} value The value to provide to `interceptor`.
11399 * @param {Function} interceptor The function to invoke.
11400 * @param {*} [thisArg] The `this` binding of `interceptor`.
11401 * @returns {*} Returns `value`.
11405 * .tap(function(array) {
11412 function tap(value, interceptor, thisArg) {
11413 interceptor.call(thisArg, value);
11418 * This method is like `_.tap` except that it returns the result of `interceptor`.
11423 * @param {*} value The value to provide to `interceptor`.
11424 * @param {Function} interceptor The function to invoke.
11425 * @param {*} [thisArg] The `this` binding of `interceptor`.
11426 * @returns {*} Returns the result of `interceptor`.
11432 * .thru(function(value) {
11438 function thru(value, interceptor, thisArg) {
11439 return interceptor.call(thisArg, value);
11443 * Enables explicit method chaining on the wrapper object.
11448 * @returns {Object} Returns the new `lodash` wrapper instance.
11452 * { 'user': 'barney', 'age': 36 },
11453 * { 'user': 'fred', 'age': 40 }
11456 * // without explicit chaining
11457 * _(users).first();
11458 * // => { 'user': 'barney', 'age': 36 }
11460 * // with explicit chaining
11465 * // => { 'user': 'barney' }
11467 function wrapperChain() {
11468 return chain(this);
11472 * Executes the chained sequence and returns the wrapped result.
11477 * @returns {Object} Returns the new `lodash` wrapper instance.
11480 * var array = [1, 2];
11481 * var wrapper = _(array).push(3);
11483 * console.log(array);
11486 * wrapper = wrapper.commit();
11487 * console.log(array);
11493 * console.log(array);
11496 function wrapperCommit() {
11497 return new LodashWrapper(this.value(), this.__chain__);
11501 * Creates a clone of the chained sequence planting `value` as the wrapped value.
11506 * @returns {Object} Returns the new `lodash` wrapper instance.
11509 * var array = [1, 2];
11510 * var wrapper = _(array).map(function(value) {
11511 * return Math.pow(value, 2);
11514 * var other = [3, 4];
11515 * var otherWrapper = wrapper.plant(other);
11517 * otherWrapper.value();
11523 function wrapperPlant(value) {
11527 while (parent instanceof baseLodash) {
11528 var clone = wrapperClone(parent);
11530 previous.__wrapped__ = clone;
11534 var previous = clone;
11535 parent = parent.__wrapped__;
11537 previous.__wrapped__ = value;
11542 * Reverses the wrapped array so the first element becomes the last, the
11543 * second element becomes the second to last, and so on.
11545 * **Note:** This method mutates the wrapped array.
11550 * @returns {Object} Returns the new reversed `lodash` wrapper instance.
11553 * var array = [1, 2, 3];
11555 * _(array).reverse().value()
11558 * console.log(array);
11561 function wrapperReverse() {
11562 var value = this.__wrapped__;
11563 if (value instanceof LazyWrapper) {
11564 if (this.__actions__.length) {
11565 value = new LazyWrapper(this);
11567 return new LodashWrapper(value.reverse(), this.__chain__);
11569 return this.thru(function(value) {
11570 return value.reverse();
11575 * Produces the result of coercing the unwrapped value to a string.
11580 * @returns {string} Returns the coerced string value.
11583 * _([1, 2, 3]).toString();
11586 function wrapperToString() {
11587 return (this.value() + '');
11591 * Executes the chained sequence to extract the unwrapped value.
11595 * @alias run, toJSON, valueOf
11597 * @returns {*} Returns the resolved unwrapped value.
11600 * _([1, 2, 3]).value();
11603 function wrapperValue() {
11604 return baseWrapperValue(this.__wrapped__, this.__actions__);
11607 /*------------------------------------------------------------------------*/
11610 * Checks if `predicate` returns truthy for **all** elements of `collection`.
11611 * The predicate is bound to `thisArg` and invoked with three arguments:
11612 * (value, index|key, collection).
11614 * If a property name is provided for `predicate` the created `_.property`
11615 * style callback returns the property value of the given element.
11617 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11618 * style callback returns `true` for elements that have a matching property
11619 * value, else `false`.
11621 * If an object is provided for `predicate` the created `_.matches` style
11622 * callback returns `true` for elements that have the properties of the given
11623 * object, else `false`.
11628 * @category Collection
11629 * @param {Array|Object|string} collection The collection to iterate over.
11630 * @param {Function|Object|string} [predicate=_.identity] The function invoked
11632 * @param {*} [thisArg] The `this` binding of `predicate`.
11633 * @returns {boolean} Returns `true` if all elements pass the predicate check,
11637 * _.every([true, 1, null, 'yes'], Boolean);
11641 * { 'user': 'barney', 'active': false },
11642 * { 'user': 'fred', 'active': false }
11645 * // using the `_.matches` callback shorthand
11646 * _.every(users, { 'user': 'barney', 'active': false });
11649 * // using the `_.matchesProperty` callback shorthand
11650 * _.every(users, 'active', false);
11653 * // using the `_.property` callback shorthand
11654 * _.every(users, 'active');
11657 function every(collection, predicate, thisArg) {
11658 var func = isArray(collection) ? arrayEvery : baseEvery;
11659 if (thisArg && isIterateeCall(collection, predicate, thisArg)) {
11662 if (typeof predicate != 'function' || thisArg !== undefined) {
11663 predicate = getCallback(predicate, thisArg, 3);
11665 return func(collection, predicate);
11669 * Iterates over elements of `collection`, returning an array of all elements
11670 * `predicate` returns truthy for. The predicate is bound to `thisArg` and
11671 * invoked with three arguments: (value, index|key, collection).
11673 * If a property name is provided for `predicate` the created `_.property`
11674 * style callback returns the property value of the given element.
11676 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11677 * style callback returns `true` for elements that have a matching property
11678 * value, else `false`.
11680 * If an object is provided for `predicate` the created `_.matches` style
11681 * callback returns `true` for elements that have the properties of the given
11682 * object, else `false`.
11687 * @category Collection
11688 * @param {Array|Object|string} collection The collection to iterate over.
11689 * @param {Function|Object|string} [predicate=_.identity] The function invoked
11691 * @param {*} [thisArg] The `this` binding of `predicate`.
11692 * @returns {Array} Returns the new filtered array.
11695 * _.filter([4, 5, 6], function(n) {
11696 * return n % 2 == 0;
11701 * { 'user': 'barney', 'age': 36, 'active': true },
11702 * { 'user': 'fred', 'age': 40, 'active': false }
11705 * // using the `_.matches` callback shorthand
11706 * _.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user');
11709 * // using the `_.matchesProperty` callback shorthand
11710 * _.pluck(_.filter(users, 'active', false), 'user');
11713 * // using the `_.property` callback shorthand
11714 * _.pluck(_.filter(users, 'active'), 'user');
11717 function filter(collection, predicate, thisArg) {
11718 var func = isArray(collection) ? arrayFilter : baseFilter;
11719 predicate = getCallback(predicate, thisArg, 3);
11720 return func(collection, predicate);
11724 * Iterates over elements of `collection`, returning the first element
11725 * `predicate` returns truthy for. The predicate is bound to `thisArg` and
11726 * invoked with three arguments: (value, index|key, collection).
11728 * If a property name is provided for `predicate` the created `_.property`
11729 * style callback returns the property value of the given element.
11731 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11732 * style callback returns `true` for elements that have a matching property
11733 * value, else `false`.
11735 * If an object is provided for `predicate` the created `_.matches` style
11736 * callback returns `true` for elements that have the properties of the given
11737 * object, else `false`.
11742 * @category Collection
11743 * @param {Array|Object|string} collection The collection to search.
11744 * @param {Function|Object|string} [predicate=_.identity] The function invoked
11746 * @param {*} [thisArg] The `this` binding of `predicate`.
11747 * @returns {*} Returns the matched element, else `undefined`.
11751 * { 'user': 'barney', 'age': 36, 'active': true },
11752 * { 'user': 'fred', 'age': 40, 'active': false },
11753 * { 'user': 'pebbles', 'age': 1, 'active': true }
11756 * _.result(_.find(users, function(chr) {
11757 * return chr.age < 40;
11761 * // using the `_.matches` callback shorthand
11762 * _.result(_.find(users, { 'age': 1, 'active': true }), 'user');
11765 * // using the `_.matchesProperty` callback shorthand
11766 * _.result(_.find(users, 'active', false), 'user');
11769 * // using the `_.property` callback shorthand
11770 * _.result(_.find(users, 'active'), 'user');
11773 var find = createFind(baseEach);
11776 * Iterates over elements of `collection` invoking `iteratee` for each element.
11777 * The `iteratee` is bound to `thisArg` and invoked with three arguments:
11778 * (value, index|key, collection). Iteratee functions may exit iteration early
11779 * by explicitly returning `false`.
11781 * **Note:** As with other "Collections" methods, objects with a "length" property
11782 * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
11783 * may be used for object iteration.
11788 * @category Collection
11789 * @param {Array|Object|string} collection The collection to iterate over.
11790 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
11791 * @param {*} [thisArg] The `this` binding of `iteratee`.
11792 * @returns {Array|Object|string} Returns `collection`.
11795 * _([1, 2]).forEach(function(n) {
11798 * // => logs each value from left to right and returns the array
11800 * _.forEach({ 'a': 1, 'b': 2 }, function(n, key) {
11801 * console.log(n, key);
11803 * // => logs each value-key pair and returns the object (iteration order is not guaranteed)
11805 var forEach = createForEach(arrayEach, baseEach);
11808 * Creates an object composed of keys generated from the results of running
11809 * each element of `collection` through `iteratee`. The corresponding value
11810 * of each key is an array of the elements responsible for generating the key.
11811 * The `iteratee` is bound to `thisArg` and invoked with three arguments:
11812 * (value, index|key, collection).
11814 * If a property name is provided for `iteratee` the created `_.property`
11815 * style callback returns the property value of the given element.
11817 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11818 * style callback returns `true` for elements that have a matching property
11819 * value, else `false`.
11821 * If an object is provided for `iteratee` the created `_.matches` style
11822 * callback returns `true` for elements that have the properties of the given
11823 * object, else `false`.
11827 * @category Collection
11828 * @param {Array|Object|string} collection The collection to iterate over.
11829 * @param {Function|Object|string} [iteratee=_.identity] The function invoked
11831 * @param {*} [thisArg] The `this` binding of `iteratee`.
11832 * @returns {Object} Returns the composed aggregate object.
11835 * _.groupBy([4.2, 6.1, 6.4], function(n) {
11836 * return Math.floor(n);
11838 * // => { '4': [4.2], '6': [6.1, 6.4] }
11840 * _.groupBy([4.2, 6.1, 6.4], function(n) {
11841 * return this.floor(n);
11843 * // => { '4': [4.2], '6': [6.1, 6.4] }
11845 * // using the `_.property` callback shorthand
11846 * _.groupBy(['one', 'two', 'three'], 'length');
11847 * // => { '3': ['one', 'two'], '5': ['three'] }
11849 var groupBy = createAggregator(function(result, value, key) {
11850 if (hasOwnProperty.call(result, key)) {
11851 result[key].push(value);
11853 result[key] = [value];
11858 * Checks if `value` is in `collection` using
11859 * [`SameValueZero`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-samevaluezero)
11860 * for equality comparisons. If `fromIndex` is negative, it is used as the offset
11861 * from the end of `collection`.
11865 * @alias contains, include
11866 * @category Collection
11867 * @param {Array|Object|string} collection The collection to search.
11868 * @param {*} target The value to search for.
11869 * @param {number} [fromIndex=0] The index to search from.
11870 * @param- {Object} [guard] Enables use as a callback for functions like `_.reduce`.
11871 * @returns {boolean} Returns `true` if a matching element is found, else `false`.
11874 * _.includes([1, 2, 3], 1);
11877 * _.includes([1, 2, 3], 1, 2);
11880 * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
11883 * _.includes('pebbles', 'eb');
11886 function includes(collection, target, fromIndex, guard) {
11887 var length = collection ? getLength(collection) : 0;
11888 if (!isLength(length)) {
11889 collection = values(collection);
11890 length = collection.length;
11895 if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) {
11898 fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
11900 return (typeof collection == 'string' || !isArray(collection) && isString(collection))
11901 ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1)
11902 : (getIndexOf(collection, target, fromIndex) > -1);
11906 * Creates an array of values by running each element in `collection` through
11907 * `iteratee`. The `iteratee` is bound to `thisArg` and invoked with three
11908 * arguments: (value, index|key, collection).
11910 * If a property name is provided for `iteratee` the created `_.property`
11911 * style callback returns the property value of the given element.
11913 * If a value is also provided for `thisArg` the created `_.matchesProperty`
11914 * style callback returns `true` for elements that have a matching property
11915 * value, else `false`.
11917 * If an object is provided for `iteratee` the created `_.matches` style
11918 * callback returns `true` for elements that have the properties of the given
11919 * object, else `false`.
11921 * Many lodash methods are guarded to work as iteratees for methods like
11922 * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
11924 * The guarded methods are:
11925 * `ary`, `callback`, `chunk`, `clone`, `create`, `curry`, `curryRight`,
11926 * `drop`, `dropRight`, `every`, `fill`, `flatten`, `invert`, `max`, `min`,
11927 * `parseInt`, `slice`, `sortBy`, `take`, `takeRight`, `template`, `trim`,
11928 * `trimLeft`, `trimRight`, `trunc`, `random`, `range`, `sample`, `some`,
11929 * `sum`, `uniq`, and `words`
11934 * @category Collection
11935 * @param {Array|Object|string} collection The collection to iterate over.
11936 * @param {Function|Object|string} [iteratee=_.identity] The function invoked
11938 * @param {*} [thisArg] The `this` binding of `iteratee`.
11939 * @returns {Array} Returns the new mapped array.
11942 * function timesThree(n) {
11946 * _.map([1, 2], timesThree);
11949 * _.map({ 'a': 1, 'b': 2 }, timesThree);
11950 * // => [3, 6] (iteration order is not guaranteed)
11953 * { 'user': 'barney' },
11954 * { 'user': 'fred' }
11957 * // using the `_.property` callback shorthand
11958 * _.map(users, 'user');
11959 * // => ['barney', 'fred']
11961 function map(collection, iteratee, thisArg) {
11962 var func = isArray(collection) ? arrayMap : baseMap;
11963 iteratee = getCallback(iteratee, thisArg, 3);
11964 return func(collection, iteratee);
11968 * Gets the property value of `path` from all elements in `collection`.
11972 * @category Collection
11973 * @param {Array|Object|string} collection The collection to iterate over.
11974 * @param {Array|string} path The path of the property to pluck.
11975 * @returns {Array} Returns the property values.
11979 * { 'user': 'barney', 'age': 36 },
11980 * { 'user': 'fred', 'age': 40 }
11983 * _.pluck(users, 'user');
11984 * // => ['barney', 'fred']
11986 * var userIndex = _.indexBy(users, 'user');
11987 * _.pluck(userIndex, 'age');
11988 * // => [36, 40] (iteration order is not guaranteed)
11990 function pluck(collection, path) {
11991 return map(collection, property(path));
11995 * Reduces `collection` to a value which is the accumulated result of running
11996 * each element in `collection` through `iteratee`, where each successive
11997 * invocation is supplied the return value of the previous. If `accumulator`
11998 * is not provided the first element of `collection` is used as the initial
11999 * value. The `iteratee` is bound to `thisArg` and invoked with four arguments:
12000 * (accumulator, value, index|key, collection).
12002 * Many lodash methods are guarded to work as iteratees for methods like
12003 * `_.reduce`, `_.reduceRight`, and `_.transform`.
12005 * The guarded methods are:
12006 * `assign`, `defaults`, `includes`, `merge`, `sortByAll`, and `sortByOrder`
12010 * @alias foldl, inject
12011 * @category Collection
12012 * @param {Array|Object|string} collection The collection to iterate over.
12013 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12014 * @param {*} [accumulator] The initial value.
12015 * @param {*} [thisArg] The `this` binding of `iteratee`.
12016 * @returns {*} Returns the accumulated value.
12019 * _.reduce([1, 2], function(total, n) {
12020 * return total + n;
12024 * _.reduce({ 'a': 1, 'b': 2 }, function(result, n, key) {
12025 * result[key] = n * 3;
12028 * // => { 'a': 3, 'b': 6 } (iteration order is not guaranteed)
12030 var reduce = createReduce(arrayReduce, baseEach);
12033 * The opposite of `_.filter`; this method returns the elements of `collection`
12034 * that `predicate` does **not** return truthy for.
12038 * @category Collection
12039 * @param {Array|Object|string} collection The collection to iterate over.
12040 * @param {Function|Object|string} [predicate=_.identity] The function invoked
12042 * @param {*} [thisArg] The `this` binding of `predicate`.
12043 * @returns {Array} Returns the new filtered array.
12046 * _.reject([1, 2, 3, 4], function(n) {
12047 * return n % 2 == 0;
12052 * { 'user': 'barney', 'age': 36, 'active': false },
12053 * { 'user': 'fred', 'age': 40, 'active': true }
12056 * // using the `_.matches` callback shorthand
12057 * _.pluck(_.reject(users, { 'age': 40, 'active': true }), 'user');
12060 * // using the `_.matchesProperty` callback shorthand
12061 * _.pluck(_.reject(users, 'active', false), 'user');
12064 * // using the `_.property` callback shorthand
12065 * _.pluck(_.reject(users, 'active'), 'user');
12068 function reject(collection, predicate, thisArg) {
12069 var func = isArray(collection) ? arrayFilter : baseFilter;
12070 predicate = getCallback(predicate, thisArg, 3);
12071 return func(collection, function(value, index, collection) {
12072 return !predicate(value, index, collection);
12077 * Checks if `predicate` returns truthy for **any** element of `collection`.
12078 * The function returns as soon as it finds a passing value and does not iterate
12079 * over the entire collection. The predicate is bound to `thisArg` and invoked
12080 * with three arguments: (value, index|key, collection).
12082 * If a property name is provided for `predicate` the created `_.property`
12083 * style callback returns the property value of the given element.
12085 * If a value is also provided for `thisArg` the created `_.matchesProperty`
12086 * style callback returns `true` for elements that have a matching property
12087 * value, else `false`.
12089 * If an object is provided for `predicate` the created `_.matches` style
12090 * callback returns `true` for elements that have the properties of the given
12091 * object, else `false`.
12096 * @category Collection
12097 * @param {Array|Object|string} collection The collection to iterate over.
12098 * @param {Function|Object|string} [predicate=_.identity] The function invoked
12100 * @param {*} [thisArg] The `this` binding of `predicate`.
12101 * @returns {boolean} Returns `true` if any element passes the predicate check,
12105 * _.some([null, 0, 'yes', false], Boolean);
12109 * { 'user': 'barney', 'active': true },
12110 * { 'user': 'fred', 'active': false }
12113 * // using the `_.matches` callback shorthand
12114 * _.some(users, { 'user': 'barney', 'active': false });
12117 * // using the `_.matchesProperty` callback shorthand
12118 * _.some(users, 'active', false);
12121 * // using the `_.property` callback shorthand
12122 * _.some(users, 'active');
12125 function some(collection, predicate, thisArg) {
12126 var func = isArray(collection) ? arraySome : baseSome;
12127 if (thisArg && isIterateeCall(collection, predicate, thisArg)) {
12130 if (typeof predicate != 'function' || thisArg !== undefined) {
12131 predicate = getCallback(predicate, thisArg, 3);
12133 return func(collection, predicate);
12136 /*------------------------------------------------------------------------*/
12139 * Gets the number of milliseconds that have elapsed since the Unix epoch
12140 * (1 January 1970 00:00:00 UTC).
12147 * _.defer(function(stamp) {
12148 * console.log(_.now() - stamp);
12150 * // => logs the number of milliseconds it took for the deferred function to be invoked
12152 var now = nativeNow || function() {
12153 return new Date().getTime();
12156 /*------------------------------------------------------------------------*/
12159 * Creates a function that invokes `func` with the `this` binding of `thisArg`
12160 * and prepends any additional `_.bind` arguments to those provided to the
12163 * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
12164 * may be used as a placeholder for partially applied arguments.
12166 * **Note:** Unlike native `Function#bind` this method does not set the "length"
12167 * property of bound functions.
12171 * @category Function
12172 * @param {Function} func The function to bind.
12173 * @param {*} thisArg The `this` binding of `func`.
12174 * @param {...*} [partials] The arguments to be partially applied.
12175 * @returns {Function} Returns the new bound function.
12178 * var greet = function(greeting, punctuation) {
12179 * return greeting + ' ' + this.user + punctuation;
12182 * var object = { 'user': 'fred' };
12184 * var bound = _.bind(greet, object, 'hi');
12188 * // using placeholders
12189 * var bound = _.bind(greet, object, _, '!');
12193 var bind = restParam(function(func, thisArg, partials) {
12194 var bitmask = BIND_FLAG;
12195 if (partials.length) {
12196 var holders = replaceHolders(partials, bind.placeholder);
12197 bitmask |= PARTIAL_FLAG;
12199 return createWrapper(func, bitmask, thisArg, partials, holders);
12203 * Creates a debounced function that delays invoking `func` until after `wait`
12204 * milliseconds have elapsed since the last time the debounced function was
12205 * invoked. The debounced function comes with a `cancel` method to cancel
12206 * delayed invocations. Provide an options object to indicate that `func`
12207 * should be invoked on the leading and/or trailing edge of the `wait` timeout.
12208 * Subsequent calls to the debounced function return the result of the last
12209 * `func` invocation.
12211 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
12212 * on the trailing edge of the timeout only if the the debounced function is
12213 * invoked more than once during the `wait` timeout.
12215 * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
12216 * for details over the differences between `_.debounce` and `_.throttle`.
12220 * @category Function
12221 * @param {Function} func The function to debounce.
12222 * @param {number} [wait=0] The number of milliseconds to delay.
12223 * @param {Object} [options] The options object.
12224 * @param {boolean} [options.leading=false] Specify invoking on the leading
12225 * edge of the timeout.
12226 * @param {number} [options.maxWait] The maximum time `func` is allowed to be
12227 * delayed before it is invoked.
12228 * @param {boolean} [options.trailing=true] Specify invoking on the trailing
12229 * edge of the timeout.
12230 * @returns {Function} Returns the new debounced function.
12233 * // avoid costly calculations while the window size is in flux
12234 * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
12236 * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
12237 * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
12239 * 'trailing': false
12242 * // ensure `batchLog` is invoked once after 1 second of debounced calls
12243 * var source = new EventSource('/stream');
12244 * jQuery(source).on('message', _.debounce(batchLog, 250, {
12248 * // cancel a debounced call
12249 * var todoChanges = _.debounce(batchLog, 1000);
12250 * Object.observe(models.todo, todoChanges);
12252 * Object.observe(models, function(changes) {
12253 * if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
12254 * todoChanges.cancel();
12258 * // ...at some point `models.todo` is changed
12259 * models.todo.completed = true;
12261 * // ...before 1 second has passed `models.todo` is deleted
12262 * // which cancels the debounced `todoChanges` call
12263 * delete models.todo;
12265 function debounce(func, wait, options) {
12277 if (typeof func != 'function') {
12278 throw new TypeError(FUNC_ERROR_TEXT);
12280 wait = wait < 0 ? 0 : (+wait || 0);
12281 if (options === true) {
12282 var leading = true;
12284 } else if (isObject(options)) {
12285 leading = options.leading;
12286 maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);
12287 trailing = 'trailing' in options ? options.trailing : trailing;
12290 function cancel() {
12292 clearTimeout(timeoutId);
12294 if (maxTimeoutId) {
12295 clearTimeout(maxTimeoutId);
12297 maxTimeoutId = timeoutId = trailingCall = undefined;
12300 function delayed() {
12301 var remaining = wait - (now() - stamp);
12302 if (remaining <= 0 || remaining > wait) {
12303 if (maxTimeoutId) {
12304 clearTimeout(maxTimeoutId);
12306 var isCalled = trailingCall;
12307 maxTimeoutId = timeoutId = trailingCall = undefined;
12309 lastCalled = now();
12310 result = func.apply(thisArg, args);
12311 if (!timeoutId && !maxTimeoutId) {
12312 args = thisArg = null;
12316 timeoutId = setTimeout(delayed, remaining);
12320 function maxDelayed() {
12322 clearTimeout(timeoutId);
12324 maxTimeoutId = timeoutId = trailingCall = undefined;
12325 if (trailing || (maxWait !== wait)) {
12326 lastCalled = now();
12327 result = func.apply(thisArg, args);
12328 if (!timeoutId && !maxTimeoutId) {
12329 args = thisArg = null;
12334 function debounced() {
12338 trailingCall = trailing && (timeoutId || !leading);
12340 if (maxWait === false) {
12341 var leadingCall = leading && !timeoutId;
12343 if (!maxTimeoutId && !leading) {
12344 lastCalled = stamp;
12346 var remaining = maxWait - (stamp - lastCalled),
12347 isCalled = remaining <= 0 || remaining > maxWait;
12350 if (maxTimeoutId) {
12351 maxTimeoutId = clearTimeout(maxTimeoutId);
12353 lastCalled = stamp;
12354 result = func.apply(thisArg, args);
12356 else if (!maxTimeoutId) {
12357 maxTimeoutId = setTimeout(maxDelayed, remaining);
12360 if (isCalled && timeoutId) {
12361 timeoutId = clearTimeout(timeoutId);
12363 else if (!timeoutId && wait !== maxWait) {
12364 timeoutId = setTimeout(delayed, wait);
12368 result = func.apply(thisArg, args);
12370 if (isCalled && !timeoutId && !maxTimeoutId) {
12371 args = thisArg = null;
12375 debounced.cancel = cancel;
12380 * Creates a function that invokes `func` with the `this` binding of the
12381 * created function and arguments from `start` and beyond provided as an array.
12383 * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters).
12387 * @category Function
12388 * @param {Function} func The function to apply a rest parameter to.
12389 * @param {number} [start=func.length-1] The start position of the rest parameter.
12390 * @returns {Function} Returns the new function.
12393 * var say = _.restParam(function(what, names) {
12394 * return what + ' ' + _.initial(names).join(', ') +
12395 * (_.size(names) > 1 ? ', & ' : '') + _.last(names);
12398 * say('hello', 'fred', 'barney', 'pebbles');
12399 * // => 'hello fred, barney, & pebbles'
12401 function restParam(func, start) {
12402 if (typeof func != 'function') {
12403 throw new TypeError(FUNC_ERROR_TEXT);
12405 start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);
12406 return function() {
12407 var args = arguments,
12409 length = nativeMax(args.length - start, 0),
12410 rest = Array(length);
12412 while (++index < length) {
12413 rest[index] = args[start + index];
12416 case 0: return func.call(this, rest);
12417 case 1: return func.call(this, args[0], rest);
12418 case 2: return func.call(this, args[0], args[1], rest);
12420 var otherArgs = Array(start + 1);
12422 while (++index < start) {
12423 otherArgs[index] = args[index];
12425 otherArgs[start] = rest;
12426 return func.apply(this, otherArgs);
12431 * Creates a throttled function that only invokes `func` at most once per
12432 * every `wait` milliseconds. The throttled function comes with a `cancel`
12433 * method to cancel delayed invocations. Provide an options object to indicate
12434 * that `func` should be invoked on the leading and/or trailing edge of the
12435 * `wait` timeout. Subsequent calls to the throttled function return the
12436 * result of the last `func` call.
12438 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
12439 * on the trailing edge of the timeout only if the the throttled function is
12440 * invoked more than once during the `wait` timeout.
12442 * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
12443 * for details over the differences between `_.throttle` and `_.debounce`.
12447 * @category Function
12448 * @param {Function} func The function to throttle.
12449 * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
12450 * @param {Object} [options] The options object.
12451 * @param {boolean} [options.leading=true] Specify invoking on the leading
12452 * edge of the timeout.
12453 * @param {boolean} [options.trailing=true] Specify invoking on the trailing
12454 * edge of the timeout.
12455 * @returns {Function} Returns the new throttled function.
12458 * // avoid excessively updating the position while scrolling
12459 * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
12461 * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes
12462 * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
12463 * 'trailing': false
12466 * // cancel a trailing throttled call
12467 * jQuery(window).on('popstate', throttled.cancel);
12469 function throttle(func, wait, options) {
12470 var leading = true,
12473 if (typeof func != 'function') {
12474 throw new TypeError(FUNC_ERROR_TEXT);
12476 if (options === false) {
12478 } else if (isObject(options)) {
12479 leading = 'leading' in options ? !!options.leading : leading;
12480 trailing = 'trailing' in options ? !!options.trailing : trailing;
12482 debounceOptions.leading = leading;
12483 debounceOptions.maxWait = +wait;
12484 debounceOptions.trailing = trailing;
12485 return debounce(func, wait, debounceOptions);
12488 /*------------------------------------------------------------------------*/
12491 * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
12492 * otherwise they are assigned by reference. If `customizer` is provided it is
12493 * invoked to produce the cloned values. If `customizer` returns `undefined`
12494 * cloning is handled by the method instead. The `customizer` is bound to
12495 * `thisArg` and invoked with two argument; (value [, index|key, object]).
12497 * **Note:** This method is loosely based on the
12498 * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm).
12499 * The enumerable properties of `arguments` objects and objects created by
12500 * constructors other than `Object` are cloned to plain `Object` objects. An
12501 * empty object is returned for uncloneable values such as functions, DOM nodes,
12502 * Maps, Sets, and WeakMaps.
12507 * @param {*} value The value to clone.
12508 * @param {boolean} [isDeep] Specify a deep clone.
12509 * @param {Function} [customizer] The function to customize cloning values.
12510 * @param {*} [thisArg] The `this` binding of `customizer`.
12511 * @returns {*} Returns the cloned value.
12515 * { 'user': 'barney' },
12516 * { 'user': 'fred' }
12519 * var shallow = _.clone(users);
12520 * shallow[0] === users[0];
12523 * var deep = _.clone(users, true);
12524 * deep[0] === users[0];
12527 * // using a customizer callback
12528 * var el = _.clone(document.body, function(value) {
12529 * if (_.isElement(value)) {
12530 * return value.cloneNode(false);
12534 * el === document.body
12538 * el.childNodes.length;
12541 function clone(value, isDeep, customizer, thisArg) {
12542 if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) {
12545 else if (typeof isDeep == 'function') {
12546 thisArg = customizer;
12547 customizer = isDeep;
12550 return typeof customizer == 'function'
12551 ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 1))
12552 : baseClone(value, isDeep);
12556 * Creates a deep clone of `value`. If `customizer` is provided it is invoked
12557 * to produce the cloned values. If `customizer` returns `undefined` cloning
12558 * is handled by the method instead. The `customizer` is bound to `thisArg`
12559 * and invoked with two argument; (value [, index|key, object]).
12561 * **Note:** This method is loosely based on the
12562 * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm).
12563 * The enumerable properties of `arguments` objects and objects created by
12564 * constructors other than `Object` are cloned to plain `Object` objects. An
12565 * empty object is returned for uncloneable values such as functions, DOM nodes,
12566 * Maps, Sets, and WeakMaps.
12571 * @param {*} value The value to deep clone.
12572 * @param {Function} [customizer] The function to customize cloning values.
12573 * @param {*} [thisArg] The `this` binding of `customizer`.
12574 * @returns {*} Returns the deep cloned value.
12578 * { 'user': 'barney' },
12579 * { 'user': 'fred' }
12582 * var deep = _.cloneDeep(users);
12583 * deep[0] === users[0];
12586 * // using a customizer callback
12587 * var el = _.cloneDeep(document.body, function(value) {
12588 * if (_.isElement(value)) {
12589 * return value.cloneNode(true);
12593 * el === document.body
12597 * el.childNodes.length;
12600 function cloneDeep(value, customizer, thisArg) {
12601 return typeof customizer == 'function'
12602 ? baseClone(value, true, bindCallback(customizer, thisArg, 1))
12603 : baseClone(value, true);
12607 * Checks if `value` is classified as an `arguments` object.
12612 * @param {*} value The value to check.
12613 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
12616 * _.isArguments(function() { return arguments; }());
12619 * _.isArguments([1, 2, 3]);
12622 function isArguments(value) {
12623 return isObjectLike(value) && isArrayLike(value) && objToString.call(value) == argsTag;
12625 // Fallback for environments without a `toStringTag` for `arguments` objects.
12626 if (!support.argsTag) {
12627 isArguments = function(value) {
12628 return isObjectLike(value) && isArrayLike(value) &&
12629 hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee');
12634 * Checks if `value` is classified as an `Array` object.
12639 * @param {*} value The value to check.
12640 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
12643 * _.isArray([1, 2, 3]);
12646 * _.isArray(function() { return arguments; }());
12649 var isArray = nativeIsArray || function(value) {
12650 return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
12654 * Checks if `value` is empty. A value is considered empty unless it is an
12655 * `arguments` object, array, string, or jQuery-like collection with a length
12656 * greater than `0` or an object with own enumerable properties.
12661 * @param {Array|Object|string} value The value to inspect.
12662 * @returns {boolean} Returns `true` if `value` is empty, else `false`.
12674 * _.isEmpty([1, 2, 3]);
12677 * _.isEmpty({ 'a': 1 });
12680 function isEmpty(value) {
12681 if (value == null) {
12684 if (isArrayLike(value) && (isArray(value) || isString(value) || isArguments(value) ||
12685 (isObjectLike(value) && isFunction(value.splice)))) {
12686 return !value.length;
12688 return !keys(value).length;
12692 * Performs a deep comparison between two values to determine if they are
12693 * equivalent. If `customizer` is provided it is invoked to compare values.
12694 * If `customizer` returns `undefined` comparisons are handled by the method
12695 * instead. The `customizer` is bound to `thisArg` and invoked with three
12696 * arguments: (value, other [, index|key]).
12698 * **Note:** This method supports comparing arrays, booleans, `Date` objects,
12699 * numbers, `Object` objects, regexes, and strings. Objects are compared by
12700 * their own, not inherited, enumerable properties. Functions and DOM nodes
12701 * are **not** supported. Provide a customizer function to extend support
12702 * for comparing other values.
12708 * @param {*} value The value to compare.
12709 * @param {*} other The other value to compare.
12710 * @param {Function} [customizer] The function to customize value comparisons.
12711 * @param {*} [thisArg] The `this` binding of `customizer`.
12712 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
12715 * var object = { 'user': 'fred' };
12716 * var other = { 'user': 'fred' };
12721 * _.isEqual(object, other);
12724 * // using a customizer callback
12725 * var array = ['hello', 'goodbye'];
12726 * var other = ['hi', 'goodbye'];
12728 * _.isEqual(array, other, function(value, other) {
12729 * if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) {
12735 function isEqual(value, other, customizer, thisArg) {
12736 customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined;
12737 var result = customizer ? customizer(value, other) : undefined;
12738 return result === undefined ? baseIsEqual(value, other, customizer) : !!result;
12742 * Checks if `value` is classified as a `Function` object.
12747 * @param {*} value The value to check.
12748 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
12754 * _.isFunction(/abc/);
12757 var isFunction = !(baseIsFunction(/x/) || (Uint8Array && !baseIsFunction(Uint8Array))) ? baseIsFunction : function(value) {
12758 // The use of `Object#toString` avoids issues with the `typeof` operator
12759 // in older versions of Chrome and Safari which return 'function' for regexes
12760 // and Safari 8 equivalents which return 'object' for typed array constructors.
12761 return objToString.call(value) == funcTag;
12765 * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
12766 * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
12771 * @param {*} value The value to check.
12772 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
12778 * _.isObject([1, 2, 3]);
12784 function isObject(value) {
12785 // Avoid a V8 JIT bug in Chrome 19-20.
12786 // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
12787 var type = typeof value;
12788 return !!value && (type == 'object' || type == 'function');
12792 * Checks if `value` is a native function.
12797 * @param {*} value The value to check.
12798 * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
12801 * _.isNative(Array.prototype.push);
12807 function isNative(value) {
12808 if (value == null) {
12811 if (objToString.call(value) == funcTag) {
12812 return reIsNative.test(fnToString.call(value));
12814 return isObjectLike(value) && (isHostObject(value) ? reIsNative : reIsHostCtor).test(value);
12818 * Checks if `value` is a plain object, that is, an object created by the
12819 * `Object` constructor or one with a `[[Prototype]]` of `null`.
12821 * **Note:** This method assumes objects created by the `Object` constructor
12822 * have no inherited enumerable properties.
12827 * @param {*} value The value to check.
12828 * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
12835 * _.isPlainObject(new Foo);
12838 * _.isPlainObject([1, 2, 3]);
12841 * _.isPlainObject({ 'x': 0, 'y': 0 });
12844 * _.isPlainObject(Object.create(null));
12847 var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
12848 if (!(value && objToString.call(value) == objectTag) || (!lodash.support.argsTag && isArguments(value))) {
12851 var valueOf = getNative(value, 'valueOf'),
12852 objProto = valueOf && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
12855 ? (value == objProto || getPrototypeOf(value) == objProto)
12856 : shimIsPlainObject(value);
12860 * Checks if `value` is classified as a `String` primitive or object.
12865 * @param {*} value The value to check.
12866 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
12869 * _.isString('abc');
12875 function isString(value) {
12876 return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag);
12880 * Checks if `value` is classified as a typed array.
12885 * @param {*} value The value to check.
12886 * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
12889 * _.isTypedArray(new Uint8Array);
12892 * _.isTypedArray([]);
12895 function isTypedArray(value) {
12896 return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)];
12900 * Converts `value` to a plain object flattening inherited enumerable
12901 * properties of `value` to own properties of the plain object.
12906 * @param {*} value The value to convert.
12907 * @returns {Object} Returns the converted plain object.
12914 * Foo.prototype.c = 3;
12916 * _.assign({ 'a': 1 }, new Foo);
12917 * // => { 'a': 1, 'b': 2 }
12919 * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
12920 * // => { 'a': 1, 'b': 2, 'c': 3 }
12922 function toPlainObject(value) {
12923 return baseCopy(value, keysIn(value));
12926 /*------------------------------------------------------------------------*/
12929 * Assigns own enumerable properties of source object(s) to the destination
12930 * object. Subsequent sources overwrite property assignments of previous sources.
12931 * If `customizer` is provided it is invoked to produce the assigned values.
12932 * The `customizer` is bound to `thisArg` and invoked with five arguments:
12933 * (objectValue, sourceValue, key, object, source).
12935 * **Note:** This method mutates `object` and is based on
12936 * [`Object.assign`](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign).
12942 * @param {Object} object The destination object.
12943 * @param {...Object} [sources] The source objects.
12944 * @param {Function} [customizer] The function to customize assigned values.
12945 * @param {*} [thisArg] The `this` binding of `customizer`.
12946 * @returns {Object} Returns `object`.
12949 * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
12950 * // => { 'user': 'fred', 'age': 40 }
12952 * // using a customizer callback
12953 * var defaults = _.partialRight(_.assign, function(value, other) {
12954 * return _.isUndefined(value) ? other : value;
12957 * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
12958 * // => { 'user': 'barney', 'age': 36 }
12960 var assign = createAssigner(function(object, source, customizer) {
12962 ? assignWith(object, source, customizer)
12963 : baseAssign(object, source);
12967 * Iterates over own enumerable properties of an object invoking `iteratee`
12968 * for each property. The `iteratee` is bound to `thisArg` and invoked with
12969 * three arguments: (value, key, object). Iteratee functions may exit iteration
12970 * early by explicitly returning `false`.
12975 * @param {Object} object The object to iterate over.
12976 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12977 * @param {*} [thisArg] The `this` binding of `iteratee`.
12978 * @returns {Object} Returns `object`.
12986 * Foo.prototype.c = 3;
12988 * _.forOwn(new Foo, function(value, key) {
12989 * console.log(key);
12991 * // => logs 'a' and 'b' (iteration order is not guaranteed)
12993 var forOwn = createForOwn(baseForOwn);
12996 * Creates an array of the own enumerable property names of `object`.
12998 * **Note:** Non-object values are coerced to objects. See the
12999 * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys)
13000 * for more details.
13005 * @param {Object} object The object to query.
13006 * @returns {Array} Returns the array of property names.
13014 * Foo.prototype.c = 3;
13017 * // => ['a', 'b'] (iteration order is not guaranteed)
13022 var keys = !nativeKeys ? shimKeys : function(object) {
13023 var Ctor = object == null ? null : object.constructor;
13024 if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
13025 (typeof object == 'function' ? lodash.support.enumPrototypes : isArrayLike(object))) {
13026 return shimKeys(object);
13028 return isObject(object) ? nativeKeys(object) : [];
13032 * Creates an array of the own and inherited enumerable property names of `object`.
13034 * **Note:** Non-object values are coerced to objects.
13039 * @param {Object} object The object to query.
13040 * @returns {Array} Returns the array of property names.
13048 * Foo.prototype.c = 3;
13050 * _.keysIn(new Foo);
13051 * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
13053 function keysIn(object) {
13054 if (object == null) {
13057 if (!isObject(object)) {
13058 object = Object(object);
13060 var length = object.length,
13061 support = lodash.support;
13063 length = (length && isLength(length) &&
13064 (isArray(object) || isArguments(object) || isString(object)) && length) || 0;
13066 var Ctor = object.constructor,
13068 proto = (isFunction(Ctor) && Ctor.prototype) || objectProto,
13069 isProto = proto === object,
13070 result = Array(length),
13071 skipIndexes = length > 0,
13072 skipErrorProps = support.enumErrorProps && (object === errorProto || object instanceof Error),
13073 skipProto = support.enumPrototypes && isFunction(object);
13075 while (++index < length) {
13076 result[index] = (index + '');
13078 // lodash skips the `constructor` property when it infers it is iterating
13079 // over a `prototype` object because IE < 9 can't set the `[[Enumerable]]`
13080 // attribute of an existing property and the `constructor` property of a
13081 // prototype defaults to non-enumerable.
13082 for (var key in object) {
13083 if (!(skipProto && key == 'prototype') &&
13084 !(skipErrorProps && (key == 'message' || key == 'name')) &&
13085 !(skipIndexes && isIndex(key, length)) &&
13086 !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
13090 if (support.nonEnumShadows && object !== objectProto) {
13091 var tag = object === stringProto ? stringTag : (object === errorProto ? errorTag : objToString.call(object)),
13092 nonEnums = nonEnumProps[tag] || nonEnumProps[objectTag];
13094 if (tag == objectTag) {
13095 proto = objectProto;
13097 length = shadowProps.length;
13099 key = shadowProps[length];
13100 var nonEnum = nonEnums[key];
13101 if (!(isProto && nonEnum) &&
13102 (nonEnum ? hasOwnProperty.call(object, key) : object[key] !== proto[key])) {
13111 * Recursively merges own enumerable properties of the source object(s), that
13112 * don't resolve to `undefined` into the destination object. Subsequent sources
13113 * overwrite property assignments of previous sources. If `customizer` is
13114 * provided it is invoked to produce the merged values of the destination and
13115 * source properties. If `customizer` returns `undefined` merging is handled
13116 * by the method instead. The `customizer` is bound to `thisArg` and invoked
13117 * with five arguments: (objectValue, sourceValue, key, object, source).
13122 * @param {Object} object The destination object.
13123 * @param {...Object} [sources] The source objects.
13124 * @param {Function} [customizer] The function to customize assigned values.
13125 * @param {*} [thisArg] The `this` binding of `customizer`.
13126 * @returns {Object} Returns `object`.
13130 * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
13134 * 'data': [{ 'age': 36 }, { 'age': 40 }]
13137 * _.merge(users, ages);
13138 * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
13140 * // using a customizer callback
13142 * 'fruits': ['apple'],
13143 * 'vegetables': ['beet']
13147 * 'fruits': ['banana'],
13148 * 'vegetables': ['carrot']
13151 * _.merge(object, other, function(a, b) {
13152 * if (_.isArray(a)) {
13153 * return a.concat(b);
13156 * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
13158 var merge = createAssigner(baseMerge);
13161 * The opposite of `_.pick`; this method creates an object composed of the
13162 * own and inherited enumerable properties of `object` that are not omitted.
13167 * @param {Object} object The source object.
13168 * @param {Function|...(string|string[])} [predicate] The function invoked per
13169 * iteration or property names to omit, specified as individual property
13170 * names or arrays of property names.
13171 * @param {*} [thisArg] The `this` binding of `predicate`.
13172 * @returns {Object} Returns the new object.
13175 * var object = { 'user': 'fred', 'age': 40 };
13177 * _.omit(object, 'age');
13178 * // => { 'user': 'fred' }
13180 * _.omit(object, _.isNumber);
13181 * // => { 'user': 'fred' }
13183 var omit = restParam(function(object, props) {
13184 if (object == null) {
13187 if (typeof props[0] != 'function') {
13188 var props = arrayMap(baseFlatten(props), String);
13189 return pickByArray(object, baseDifference(keysIn(object), props));
13191 var predicate = bindCallback(props[0], props[1], 3);
13192 return pickByCallback(object, function(value, key, object) {
13193 return !predicate(value, key, object);
13198 * Creates a two dimensional array of the key-value pairs for `object`,
13199 * e.g. `[[key1, value1], [key2, value2]]`.
13204 * @param {Object} object The object to query.
13205 * @returns {Array} Returns the new array of key-value pairs.
13208 * _.pairs({ 'barney': 36, 'fred': 40 });
13209 * // => [['barney', 36], ['fred', 40]] (iteration order is not guaranteed)
13211 function pairs(object) {
13212 object = toObject(object);
13215 props = keys(object),
13216 length = props.length,
13217 result = Array(length);
13219 while (++index < length) {
13220 var key = props[index];
13221 result[index] = [key, object[key]];
13227 * Creates an object composed of the picked `object` properties. Property
13228 * names may be specified as individual arguments or as arrays of property
13229 * names. If `predicate` is provided it is invoked for each property of `object`
13230 * picking the properties `predicate` returns truthy for. The predicate is
13231 * bound to `thisArg` and invoked with three arguments: (value, key, object).
13236 * @param {Object} object The source object.
13237 * @param {Function|...(string|string[])} [predicate] The function invoked per
13238 * iteration or property names to pick, specified as individual property
13239 * names or arrays of property names.
13240 * @param {*} [thisArg] The `this` binding of `predicate`.
13241 * @returns {Object} Returns the new object.
13244 * var object = { 'user': 'fred', 'age': 40 };
13246 * _.pick(object, 'user');
13247 * // => { 'user': 'fred' }
13249 * _.pick(object, _.isString);
13250 * // => { 'user': 'fred' }
13252 var pick = restParam(function(object, props) {
13253 if (object == null) {
13256 return typeof props[0] == 'function'
13257 ? pickByCallback(object, bindCallback(props[0], props[1], 3))
13258 : pickByArray(object, baseFlatten(props));
13262 * Creates an array of the own enumerable property values of `object`.
13264 * **Note:** Non-object values are coerced to objects.
13269 * @param {Object} object The object to query.
13270 * @returns {Array} Returns the array of property values.
13278 * Foo.prototype.c = 3;
13280 * _.values(new Foo);
13281 * // => [1, 2] (iteration order is not guaranteed)
13286 function values(object) {
13287 return baseValues(object, keys(object));
13290 /*------------------------------------------------------------------------*/
13293 * Escapes the `RegExp` special characters "\", "/", "^", "$", ".", "|", "?",
13294 * "*", "+", "(", ")", "[", "]", "{" and "}" in `string`.
13299 * @param {string} [string=''] The string to escape.
13300 * @returns {string} Returns the escaped string.
13303 * _.escapeRegExp('[lodash](https://lodash.com/)');
13304 * // => '\[lodash\]\(https:\/\/lodash\.com\/\)'
13306 function escapeRegExp(string) {
13307 string = baseToString(string);
13308 return (string && reHasRegExpChars.test(string))
13309 ? string.replace(reRegExpChars, '\\$&')
13313 /*------------------------------------------------------------------------*/
13316 * Creates a function that invokes `func` with the `this` binding of `thisArg`
13317 * and arguments of the created function. If `func` is a property name the
13318 * created callback returns the property value for a given element. If `func`
13319 * is an object the created callback returns `true` for elements that contain
13320 * the equivalent object properties, otherwise it returns `false`.
13325 * @category Utility
13326 * @param {*} [func=_.identity] The value to convert to a callback.
13327 * @param {*} [thisArg] The `this` binding of `func`.
13328 * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
13329 * @returns {Function} Returns the callback.
13333 * { 'user': 'barney', 'age': 36 },
13334 * { 'user': 'fred', 'age': 40 }
13337 * // wrap to create custom callback shorthands
13338 * _.callback = _.wrap(_.callback, function(callback, func, thisArg) {
13339 * var match = /^(.+?)__([gl]t)(.+)$/.exec(func);
13341 * return callback(func, thisArg);
13343 * return function(object) {
13344 * return match[2] == 'gt'
13345 * ? object[match[1]] > match[3]
13346 * : object[match[1]] < match[3];
13350 * _.filter(users, 'age__gt36');
13351 * // => [{ 'user': 'fred', 'age': 40 }]
13353 function callback(func, thisArg, guard) {
13354 if (guard && isIterateeCall(func, thisArg, guard)) {
13357 return isObjectLike(func)
13359 : baseCallback(func, thisArg);
13363 * Creates a function that returns `value`.
13367 * @category Utility
13368 * @param {*} value The value to return from the new function.
13369 * @returns {Function} Returns the new function.
13372 * var object = { 'user': 'fred' };
13373 * var getter = _.constant(object);
13375 * getter() === object;
13378 function constant(value) {
13379 return function() {
13385 * This method returns the first argument provided to it.
13389 * @category Utility
13390 * @param {*} value Any value.
13391 * @returns {*} Returns `value`.
13394 * var object = { 'user': 'fred' };
13396 * _.identity(object) === object;
13399 function identity(value) {
13404 * Creates a function that performs a deep comparison between a given object
13405 * and `source`, returning `true` if the given object has equivalent property
13406 * values, else `false`.
13408 * **Note:** This method supports comparing arrays, booleans, `Date` objects,
13409 * numbers, `Object` objects, regexes, and strings. Objects are compared by
13410 * their own, not inherited, enumerable properties. For comparing a single
13411 * own or inherited property value see `_.matchesProperty`.
13415 * @category Utility
13416 * @param {Object} source The object of property values to match.
13417 * @returns {Function} Returns the new function.
13421 * { 'user': 'barney', 'age': 36, 'active': true },
13422 * { 'user': 'fred', 'age': 40, 'active': false }
13425 * _.filter(users, _.matches({ 'age': 40, 'active': false }));
13426 * // => [{ 'user': 'fred', 'age': 40, 'active': false }]
13428 function matches(source) {
13429 return baseMatches(baseClone(source, true));
13433 * Adds all own enumerable function properties of a source object to the
13434 * destination object. If `object` is a function then methods are added to
13435 * its prototype as well.
13437 * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
13438 * avoid conflicts caused by modifying the original.
13442 * @category Utility
13443 * @param {Function|Object} [object=lodash] The destination object.
13444 * @param {Object} source The object of functions to add.
13445 * @param {Object} [options] The options object.
13446 * @param {boolean} [options.chain=true] Specify whether the functions added
13448 * @returns {Function|Object} Returns `object`.
13451 * function vowels(string) {
13452 * return _.filter(string, function(v) {
13453 * return /[aeiou]/i.test(v);
13457 * _.mixin({ 'vowels': vowels });
13458 * _.vowels('fred');
13461 * _('fred').vowels().value();
13464 * _.mixin({ 'vowels': vowels }, { 'chain': false });
13465 * _('fred').vowels();
13468 function mixin(object, source, options) {
13469 if (options == null) {
13470 var isObj = isObject(source),
13471 props = isObj ? keys(source) : null,
13472 methodNames = (props && props.length) ? baseFunctions(source, props) : null;
13474 if (!(methodNames ? methodNames.length : isObj)) {
13475 methodNames = false;
13481 if (!methodNames) {
13482 methodNames = baseFunctions(source, keys(source));
13486 isFunc = isFunction(object),
13487 length = methodNames.length;
13489 if (options === false) {
13491 } else if (isObject(options) && 'chain' in options) {
13492 chain = options.chain;
13494 while (++index < length) {
13495 var methodName = methodNames[index],
13496 func = source[methodName];
13498 object[methodName] = func;
13500 object.prototype[methodName] = (function(func) {
13501 return function() {
13502 var chainAll = this.__chain__;
13503 if (chain || chainAll) {
13504 var result = object(this.__wrapped__),
13505 actions = result.__actions__ = arrayCopy(this.__actions__);
13507 actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
13508 result.__chain__ = chainAll;
13511 var args = [this.value()];
13512 push.apply(args, arguments);
13513 return func.apply(object, args);
13522 * A no-operation function that returns `undefined` regardless of the
13523 * arguments it receives.
13527 * @category Utility
13530 * var object = { 'user': 'fred' };
13532 * _.noop(object) === undefined;
13536 // No operation performed.
13540 * Creates a function that returns the property value at `path` on a
13545 * @category Utility
13546 * @param {Array|string} path The path of the property to get.
13547 * @returns {Function} Returns the new function.
13551 * { 'a': { 'b': { 'c': 2 } } },
13552 * { 'a': { 'b': { 'c': 1 } } }
13555 * _.map(objects, _.property('a.b.c'));
13558 * _.pluck(_.sortBy(objects, _.property(['a', 'b', 'c'])), 'a.b.c');
13561 function property(path) {
13562 return isKey(path) ? baseProperty(path) : basePropertyDeep(path);
13565 /*------------------------------------------------------------------------*/
13567 // Ensure wrappers are instances of `baseLodash`.
13568 lodash.prototype = baseLodash.prototype;
13570 LodashWrapper.prototype = baseCreate(baseLodash.prototype);
13571 LodashWrapper.prototype.constructor = LodashWrapper;
13573 LazyWrapper.prototype = baseCreate(baseLodash.prototype);
13574 LazyWrapper.prototype.constructor = LazyWrapper;
13576 // Add functions to the `Set` cache.
13577 SetCache.prototype.push = cachePush;
13579 // Add functions that return wrapped values when chaining.
13580 lodash.assign = assign;
13581 lodash.bind = bind;
13582 lodash.callback = callback;
13583 lodash.chain = chain;
13584 lodash.chunk = chunk;
13585 lodash.compact = compact;
13586 lodash.constant = constant;
13587 lodash.debounce = debounce;
13588 lodash.difference = difference;
13589 lodash.filter = filter;
13590 lodash.flatten = flatten;
13591 lodash.forEach = forEach;
13592 lodash.forOwn = forOwn;
13593 lodash.groupBy = groupBy;
13594 lodash.intersection = intersection;
13595 lodash.keys = keys;
13596 lodash.keysIn = keysIn;
13598 lodash.matches = matches;
13599 lodash.merge = merge;
13600 lodash.mixin = mixin;
13601 lodash.omit = omit;
13602 lodash.pairs = pairs;
13603 lodash.pick = pick;
13604 lodash.pluck = pluck;
13605 lodash.property = property;
13606 lodash.reject = reject;
13607 lodash.restParam = restParam;
13609 lodash.throttle = throttle;
13610 lodash.thru = thru;
13611 lodash.toPlainObject = toPlainObject;
13612 lodash.union = union;
13613 lodash.uniq = uniq;
13614 lodash.values = values;
13615 lodash.without = without;
13618 lodash.collect = map;
13619 lodash.each = forEach;
13620 lodash.extend = assign;
13621 lodash.iteratee = callback;
13622 lodash.select = filter;
13623 lodash.unique = uniq;
13625 // Add functions to `lodash.prototype`.
13626 mixin(lodash, lodash);
13628 /*------------------------------------------------------------------------*/
13630 // Add functions that return unwrapped values when chaining.
13631 lodash.clone = clone;
13632 lodash.cloneDeep = cloneDeep;
13633 lodash.escapeRegExp = escapeRegExp;
13634 lodash.every = every;
13635 lodash.find = find;
13636 lodash.first = first;
13637 lodash.identity = identity;
13638 lodash.includes = includes;
13639 lodash.indexOf = indexOf;
13640 lodash.isArguments = isArguments;
13641 lodash.isArray = isArray;
13642 lodash.isEmpty = isEmpty;
13643 lodash.isEqual = isEqual;
13644 lodash.isFunction = isFunction;
13645 lodash.isNative = isNative;
13646 lodash.isObject = isObject;
13647 lodash.isPlainObject = isPlainObject;
13648 lodash.isString = isString;
13649 lodash.isTypedArray = isTypedArray;
13650 lodash.last = last;
13651 lodash.noop = noop;
13653 lodash.reduce = reduce;
13654 lodash.some = some;
13657 lodash.all = every;
13659 lodash.contains = includes;
13660 lodash.eq = isEqual;
13661 lodash.detect = find;
13662 lodash.foldl = reduce;
13663 lodash.head = first;
13664 lodash.include = includes;
13665 lodash.inject = reduce;
13667 mixin(lodash, (function() {
13669 baseForOwn(lodash, function(func, methodName) {
13670 if (!lodash.prototype[methodName]) {
13671 source[methodName] = func;
13677 /*------------------------------------------------------------------------*/
13679 lodash.prototype.sample = function(n) {
13680 if (!this.__chain__ && n == null) {
13681 return sample(this.value());
13683 return this.thru(function(value) {
13684 return sample(value, n);
13688 /*------------------------------------------------------------------------*/
13691 * The semantic version number.
13697 lodash.VERSION = VERSION;
13699 // Assign default placeholders.
13700 bind.placeholder = lodash;
13702 // Add `LazyWrapper` methods that accept an `iteratee` value.
13703 arrayEach(['dropWhile', 'filter', 'map', 'takeWhile'], function(methodName, type) {
13704 var isFilter = type != LAZY_MAP_FLAG,
13705 isDropWhile = type == LAZY_DROP_WHILE_FLAG;
13707 LazyWrapper.prototype[methodName] = function(iteratee, thisArg) {
13708 var filtered = this.__filtered__,
13709 result = (filtered && isDropWhile) ? new LazyWrapper(this) : this.clone(),
13710 iteratees = result.__iteratees__ || (result.__iteratees__ = []);
13716 'iteratee': getCallback(iteratee, thisArg, 1),
13721 result.__filtered__ = filtered || isFilter;
13726 // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
13727 arrayEach(['drop', 'take'], function(methodName, index) {
13728 var whileName = methodName + 'While';
13730 LazyWrapper.prototype[methodName] = function(n) {
13731 var filtered = this.__filtered__,
13732 result = (filtered && !index) ? this.dropWhile() : this.clone();
13734 n = n == null ? 1 : nativeMax(floor(n) || 0, 0);
13737 result.__takeCount__ = nativeMin(result.__takeCount__, n);
13739 last(result.__iteratees__).limit = n;
13742 var views = result.__views__ || (result.__views__ = []);
13743 views.push({ 'size': n, 'type': methodName + (result.__dir__ < 0 ? 'Right' : '') });
13748 LazyWrapper.prototype[methodName + 'Right'] = function(n) {
13749 return this.reverse()[methodName](n).reverse();
13752 LazyWrapper.prototype[methodName + 'RightWhile'] = function(predicate, thisArg) {
13753 return this.reverse()[whileName](predicate, thisArg).reverse();
13757 // Add `LazyWrapper` methods for `_.first` and `_.last`.
13758 arrayEach(['first', 'last'], function(methodName, index) {
13759 var takeName = 'take' + (index ? 'Right' : '');
13761 LazyWrapper.prototype[methodName] = function() {
13762 return this[takeName](1).value()[0];
13766 // Add `LazyWrapper` methods for `_.initial` and `_.rest`.
13767 arrayEach(['initial', 'rest'], function(methodName, index) {
13768 var dropName = 'drop' + (index ? '' : 'Right');
13770 LazyWrapper.prototype[methodName] = function() {
13771 return this[dropName](1);
13775 // Add `LazyWrapper` methods for `_.pluck` and `_.where`.
13776 arrayEach(['pluck', 'where'], function(methodName, index) {
13777 var operationName = index ? 'filter' : 'map',
13778 createCallback = index ? baseMatches : property;
13780 LazyWrapper.prototype[methodName] = function(value) {
13781 return this[operationName](createCallback(value));
13785 LazyWrapper.prototype.compact = function() {
13786 return this.filter(identity);
13789 LazyWrapper.prototype.reject = function(predicate, thisArg) {
13790 predicate = getCallback(predicate, thisArg, 1);
13791 return this.filter(function(value) {
13792 return !predicate(value);
13796 LazyWrapper.prototype.slice = function(start, end) {
13797 start = start == null ? 0 : (+start || 0);
13801 result = this.takeRight(-start);
13802 } else if (start) {
13803 result = this.drop(start);
13805 if (end !== undefined) {
13807 result = end < 0 ? result.dropRight(-end) : result.take(end - start);
13812 LazyWrapper.prototype.toArray = function() {
13813 return this.drop(0);
13816 // Add `LazyWrapper` methods to `lodash.prototype`.
13817 baseForOwn(LazyWrapper.prototype, function(func, methodName) {
13818 var lodashFunc = lodash[methodName];
13822 var checkIteratee = /^(?:filter|map|reject)|While$/.test(methodName),
13823 retUnwrapped = /^(?:first|last)$/.test(methodName);
13825 lodash.prototype[methodName] = function() {
13826 var args = arguments,
13827 chainAll = this.__chain__,
13828 value = this.__wrapped__,
13829 isHybrid = !!this.__actions__.length,
13830 isLazy = value instanceof LazyWrapper,
13831 iteratee = args[0],
13832 useLazy = isLazy || isArray(value);
13834 if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
13835 // avoid lazy use if the iteratee has a "length" value other than `1`
13836 isLazy = useLazy = false;
13838 var onlyLazy = isLazy && !isHybrid;
13839 if (retUnwrapped && !chainAll) {
13842 : lodashFunc.call(lodash, this.value());
13844 var interceptor = function(value) {
13845 var otherArgs = [value];
13846 push.apply(otherArgs, args);
13847 return lodashFunc.apply(lodash, otherArgs);
13850 var wrapper = onlyLazy ? value : new LazyWrapper(this),
13851 result = func.apply(wrapper, args);
13853 if (!retUnwrapped && (isHybrid || result.__actions__)) {
13854 var actions = result.__actions__ || (result.__actions__ = []);
13855 actions.push({ 'func': thru, 'args': [interceptor], 'thisArg': lodash });
13857 return new LodashWrapper(result, chainAll);
13859 return this.thru(interceptor);
13863 // Add `Array` and `String` methods to `lodash.prototype`.
13864 arrayEach(['concat', 'join', 'pop', 'push', 'replace', 'shift', 'sort', 'splice', 'split', 'unshift'], function(methodName) {
13865 var protoFunc = (/^(?:replace|split)$/.test(methodName) ? stringProto : arrayProto)[methodName],
13866 chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
13867 fixObjects = !support.spliceObjects && /^(?:pop|shift|splice)$/.test(methodName),
13868 retUnwrapped = /^(?:join|pop|replace|shift)$/.test(methodName);
13870 // Avoid array-like object bugs with `Array#shift` and `Array#splice` in
13871 // IE < 9, Firefox < 10, and RingoJS.
13872 var func = !fixObjects ? protoFunc : function() {
13873 var result = protoFunc.apply(this, arguments);
13874 if (this.length === 0) {
13880 lodash.prototype[methodName] = function() {
13881 var args = arguments;
13882 if (retUnwrapped && !this.__chain__) {
13883 return func.apply(this.value(), args);
13885 return this[chainName](function(value) {
13886 return func.apply(value, args);
13891 // Map minified function names to their real names.
13892 baseForOwn(LazyWrapper.prototype, function(func, methodName) {
13893 var lodashFunc = lodash[methodName];
13895 var key = lodashFunc.name,
13896 names = realNames[key] || (realNames[key] = []);
13898 names.push({ 'name': methodName, 'func': lodashFunc });
13902 realNames[createHybridWrapper(null, BIND_KEY_FLAG).name] = [{ 'name': 'wrapper', 'func': null }];
13904 // Add functions to the lazy wrapper.
13905 LazyWrapper.prototype.clone = lazyClone;
13906 LazyWrapper.prototype.reverse = lazyReverse;
13907 LazyWrapper.prototype.value = lazyValue;
13909 // Add chaining functions to the `lodash` wrapper.
13910 lodash.prototype.chain = wrapperChain;
13911 lodash.prototype.commit = wrapperCommit;
13912 lodash.prototype.plant = wrapperPlant;
13913 lodash.prototype.reverse = wrapperReverse;
13914 lodash.prototype.toString = wrapperToString;
13915 lodash.prototype.run = lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
13917 // Add function aliases to the `lodash` wrapper.
13918 lodash.prototype.collect = lodash.prototype.map;
13919 lodash.prototype.head = lodash.prototype.first;
13920 lodash.prototype.select = lodash.prototype.filter;
13921 lodash.prototype.tail = lodash.prototype.rest;
13923 /*--------------------------------------------------------------------------*/
13925 if (freeExports && freeModule) {
13926 // Export for Node.js or RingoJS.
13927 if (moduleExports) {
13928 (freeModule.exports = lodash)._ = lodash;
13932 // Export for a browser or Rhino.
13936 (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;
13937 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){
13940 var ohauth = require('ohauth'),
13941 xtend = require('xtend'),
13942 store = require('store');
13946 // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
13947 // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
13948 // does not support custom headers, which this uses everywhere.
13949 module.exports = function(o) {
13953 // authenticated users will also have a request token secret, but it's
13954 // not used in transactions with the server
13955 oauth.authenticated = function() {
13956 return !!(token('oauth_token') && token('oauth_token_secret'));
13959 oauth.logout = function() {
13960 token('oauth_token', '');
13961 token('oauth_token_secret', '');
13962 token('oauth_request_token_secret', '');
13966 // TODO: detect lack of click event
13967 oauth.authenticate = function(callback) {
13968 if (oauth.authenticated()) return callback();
13972 // ## Getting a request token
13973 var params = timenonce(getAuth(o)),
13974 url = o.url + '/oauth/request_token',
13977 params.oauth_signature = ohauth.signature(
13978 o.oauth_secret, '',
13979 ohauth.baseString('POST', url, params));
13981 if (!o.singlepage) {
13982 // Create a 600x550 popup window in the center of the screen
13983 var w = 600, h = 550,
13985 ['width', w], ['height', h],
13986 ['left', screen.width / 2 - w / 2],
13987 ['top', screen.height / 2 - h / 2]].map(function(x) {
13988 return x.join('=');
13990 popup = window.open('about:blank', 'oauth_window', settings);
13993 timer = setInterval(function() {
13994 if (popup.closed) {
13996 clearInterval(timer);
13997 callback('not authenticated', null);
14002 // Request a request token. When this is complete, the popup
14003 // window is redirected to OSM's authorization page.
14004 ohauth.xhr('POST', url, params, null, {}, reqTokenDone);
14007 function reqTokenDone(err, xhr) {
14010 if (timer) clearInterval(timer);
14011 return callback(err);
14013 var resp = ohauth.stringQs(xhr.response);
14014 token('oauth_request_token_secret', resp.oauth_token_secret);
14015 var authorize_url = o.url + '/oauth/authorize?' + ohauth.qsString({
14016 oauth_token: resp.oauth_token,
14017 oauth_callback: location.href.replace('index.html', '')
14018 .replace(/#.*/, '') + o.landing
14021 if (o.singlepage) {
14022 location.href = authorize_url;
14024 popup.location = authorize_url;
14028 // Called by a function in a landing page, in the popup window. The
14029 // window closes itself.
14030 window.authComplete = function(token) {
14031 if (timer) clearInterval(timer);
14032 var oauth_token = ohauth.stringQs(token.split('?')[1]);
14033 get_access_token(oauth_token.oauth_token);
14034 delete window.authComplete;
14037 // ## Getting an request token
14039 // At this point we have an `oauth_token`, brought in from a function
14040 // call on a landing page popup.
14041 function get_access_token(oauth_token) {
14042 var url = o.url + '/oauth/access_token',
14043 params = timenonce(getAuth(o)),
14044 request_token_secret = token('oauth_request_token_secret');
14045 params.oauth_token = oauth_token;
14046 params.oauth_signature = ohauth.signature(
14048 request_token_secret,
14049 ohauth.baseString('POST', url, params));
14051 // ## Getting an access token
14053 // The final token required for authentication. At this point
14054 // we have a `request token secret`
14055 ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
14059 function accessTokenDone(err, xhr) {
14061 if (timer) clearInterval(timer);
14062 if (err) return callback(err);
14063 var access_token = ohauth.stringQs(xhr.response);
14064 token('oauth_token', access_token.oauth_token);
14065 token('oauth_token_secret', access_token.oauth_token_secret);
14066 callback(null, oauth);
14070 oauth.bootstrapToken = function(oauth_token, callback) {
14071 // ## Getting an request token
14072 // At this point we have an `oauth_token`, brought in from a function
14073 // call on a landing page popup.
14074 function get_access_token(oauth_token) {
14075 var url = o.url + '/oauth/access_token',
14076 params = timenonce(getAuth(o)),
14077 request_token_secret = token('oauth_request_token_secret');
14078 params.oauth_token = oauth_token;
14079 params.oauth_signature = ohauth.signature(
14081 request_token_secret,
14082 ohauth.baseString('POST', url, params));
14084 // ## Getting an access token
14085 // The final token required for authentication. At this point
14086 // we have a `request token secret`
14087 ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
14091 function accessTokenDone(err, xhr) {
14093 if (err) return callback(err);
14094 var access_token = ohauth.stringQs(xhr.response);
14095 token('oauth_token', access_token.oauth_token);
14096 token('oauth_token_secret', access_token.oauth_token_secret);
14097 callback(null, oauth);
14100 get_access_token(oauth_token);
14105 // A single XMLHttpRequest wrapper that does authenticated calls if the
14106 // user has logged in.
14107 oauth.xhr = function(options, callback) {
14108 if (!oauth.authenticated()) {
14109 if (o.auto) return oauth.authenticate(run);
14110 else return callback('not authenticated', null);
14111 } else return run();
14114 var params = timenonce(getAuth(o)),
14115 url = o.url + options.path,
14116 oauth_token_secret = token('oauth_token_secret');
14118 // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
14119 if ((!options.options || !options.options.header ||
14120 options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') &&
14122 params = xtend(params, ohauth.stringQs(options.content));
14125 params.oauth_token = token('oauth_token');
14126 params.oauth_signature = ohauth.signature(
14128 oauth_token_secret,
14129 ohauth.baseString(options.method, url, params));
14131 ohauth.xhr(options.method,
14132 url, params, options.content, options.options, done);
14135 function done(err, xhr) {
14136 if (err) return callback(err);
14137 else if (xhr.responseXML) return callback(err, xhr.responseXML);
14138 else return callback(err, xhr.response);
14142 // pre-authorize this object, if we can just get a token and token_secret
14144 oauth.preauth = function(c) {
14146 if (c.oauth_token) token('oauth_token', c.oauth_token);
14147 if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
14151 oauth.options = function(_) {
14152 if (!arguments.length) return o;
14156 o.url = o.url || 'http://www.openstreetmap.org';
14157 o.landing = o.landing || 'land.html';
14159 o.singlepage = o.singlepage || false;
14161 // Optional loading and loading-done functions for nice UI feedback.
14162 // by default, no-ops
14163 o.loading = o.loading || function() {};
14164 o.done = o.done || function() {};
14166 return oauth.preauth(o);
14169 // 'stamp' an authentication object from `getAuth()`
14170 // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
14172 function timenonce(o) {
14173 o.oauth_timestamp = ohauth.timestamp();
14174 o.oauth_nonce = ohauth.nonce();
14178 // get/set tokens. These are prefixed with the base URL so that `osm-auth`
14179 // can be used with multiple APIs and the keys in `localStorage`
14183 if (store.enabled) {
14184 token = function (x, y) {
14185 if (arguments.length === 1) return store.get(o.url + x);
14186 else if (arguments.length === 2) return store.set(o.url + x, y);
14190 token = function (x, y) {
14191 if (arguments.length === 1) return storage[o.url + x];
14192 else if (arguments.length === 2) return storage[o.url + x] = y;
14196 // Get an authentication object. If you just add and remove properties
14197 // from a single object, you'll need to use `delete` to make sure that
14198 // it doesn't contain undesired properties for authentication
14199 function getAuth(o) {
14201 oauth_consumer_key: o.oauth_consumer_key,
14202 oauth_signature_method: "HMAC-SHA1"
14206 // potentially pre-authorize
14212 },{"ohauth":2,"store":3,"xtend":4}],3:[function(require,module,exports){
14213 (function(global){;(function(win){
14215 doc = win.document,
14216 localStorageName = 'localStorage',
14219 store.disabled = false
14220 store.set = function(key, value) {}
14221 store.get = function(key) {}
14222 store.remove = function(key) {}
14223 store.clear = function() {}
14224 store.transact = function(key, defaultVal, transactionFn) {
14225 var val = store.get(key)
14226 if (transactionFn == null) {
14227 transactionFn = defaultVal
14230 if (typeof val == 'undefined') { val = defaultVal || {} }
14232 store.set(key, val)
14234 store.getAll = function() {}
14235 store.forEach = function() {}
14237 store.serialize = function(value) {
14238 return JSON.stringify(value)
14240 store.deserialize = function(value) {
14241 if (typeof value != 'string') { return undefined }
14242 try { return JSON.parse(value) }
14243 catch(e) { return value || undefined }
14246 // Functions to encapsulate questionable FireFox 3.6.13 behavior
14247 // when about.config::dom.storage.enabled === false
14248 // See https://github.com/marcuswestin/store.js/issues#issue/13
14249 function isLocalStorageNameSupported() {
14250 try { return (localStorageName in win && win[localStorageName]) }
14251 catch(err) { return false }
14254 if (isLocalStorageNameSupported()) {
14255 storage = win[localStorageName]
14256 store.set = function(key, val) {
14257 if (val === undefined) { return store.remove(key) }
14258 storage.setItem(key, store.serialize(val))
14261 store.get = function(key) { return store.deserialize(storage.getItem(key)) }
14262 store.remove = function(key) { storage.removeItem(key) }
14263 store.clear = function() { storage.clear() }
14264 store.getAll = function() {
14266 store.forEach(function(key, val) {
14271 store.forEach = function(callback) {
14272 for (var i=0; i<storage.length; i++) {
14273 var key = storage.key(i)
14274 callback(key, store.get(key))
14277 } else if (doc.documentElement.addBehavior) {
14280 // Since #userData storage applies only to specific paths, we need to
14281 // somehow link our data to a specific path. We choose /favicon.ico
14282 // as a pretty safe option, since all browsers already make a request to
14283 // this URL anyway and being a 404 will not hurt us here. We wrap an
14284 // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
14285 // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
14286 // since the iframe access rules appear to allow direct access and
14287 // manipulation of the document element, even for a 404 page. This
14288 // document can be used instead of the current document (which would
14289 // have been limited to the current path) to perform #userData storage.
14291 storageContainer = new ActiveXObject('htmlfile')
14292 storageContainer.open()
14293 storageContainer.write('<s' + 'cript>document.w=window</s' + 'cript><iframe src="/favicon.ico"></iframe>')
14294 storageContainer.close()
14295 storageOwner = storageContainer.w.frames[0].document
14296 storage = storageOwner.createElement('div')
14298 // somehow ActiveXObject instantiation failed (perhaps some special
14299 // security settings or otherwse), fall back to per-path storage
14300 storage = doc.createElement('div')
14301 storageOwner = doc.body
14303 function withIEStorage(storeFunction) {
14304 return function() {
14305 var args = Array.prototype.slice.call(arguments, 0)
14306 args.unshift(storage)
14307 // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
14308 // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
14309 storageOwner.appendChild(storage)
14310 storage.addBehavior('#default#userData')
14311 storage.load(localStorageName)
14312 var result = storeFunction.apply(store, args)
14313 storageOwner.removeChild(storage)
14318 // In IE7, keys may not contain special chars. See all of https://github.com/marcuswestin/store.js/issues/40
14319 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g")
14320 function ieKeyFix(key) {
14321 return key.replace(forbiddenCharsRegex, '___')
14323 store.set = withIEStorage(function(storage, key, val) {
14324 key = ieKeyFix(key)
14325 if (val === undefined) { return store.remove(key) }
14326 storage.setAttribute(key, store.serialize(val))
14327 storage.save(localStorageName)
14330 store.get = withIEStorage(function(storage, key) {
14331 key = ieKeyFix(key)
14332 return store.deserialize(storage.getAttribute(key))
14334 store.remove = withIEStorage(function(storage, key) {
14335 key = ieKeyFix(key)
14336 storage.removeAttribute(key)
14337 storage.save(localStorageName)
14339 store.clear = withIEStorage(function(storage) {
14340 var attributes = storage.XMLDocument.documentElement.attributes
14341 storage.load(localStorageName)
14342 for (var i=0, attr; attr=attributes[i]; i++) {
14343 storage.removeAttribute(attr.name)
14345 storage.save(localStorageName)
14347 store.getAll = function(storage) {
14349 store.forEach(function(key, val) {
14354 store.forEach = withIEStorage(function(storage, callback) {
14355 var attributes = storage.XMLDocument.documentElement.attributes
14356 for (var i=0, attr; attr=attributes[i]; ++i) {
14357 callback(attr.name, store.deserialize(storage.getAttribute(attr.name)))
14363 var testKey = '__storejs__'
14364 store.set(testKey, testKey)
14365 if (store.get(testKey) != testKey) { store.disabled = true }
14366 store.remove(testKey)
14368 store.disabled = true
14370 store.enabled = !store.disabled
14372 if (typeof module != 'undefined' && module.exports) { module.exports = store }
14373 else if (typeof define === 'function' && define.amd) { define(store) }
14374 else { win.store = store }
14376 })(this.window || global);
14379 },{}],5:[function(require,module,exports){
14380 module.exports = hasKeys
14382 function hasKeys(source) {
14383 return source !== null &&
14384 (typeof source === "object" ||
14385 typeof source === "function")
14388 },{}],4:[function(require,module,exports){
14389 var Keys = require("object-keys")
14390 var hasKeys = require("./has-keys")
14392 module.exports = extend
14394 function extend() {
14397 for (var i = 0; i < arguments.length; i++) {
14398 var source = arguments[i]
14400 if (!hasKeys(source)) {
14404 var keys = Keys(source)
14406 for (var j = 0; j < keys.length; j++) {
14408 target[name] = source[name]
14415 },{"./has-keys":5,"object-keys":6}],7:[function(require,module,exports){
14416 (function(global){/**
14417 * jsHashes - A fast and independent hashing library pure JavaScript implemented (ES3 compliant) for both server and client side
14420 * @author Tomas Aparicio <tomas@rijndael-project.com>
14421 * @license New BSD (see LICENSE file)
14424 * Algorithms specification:
14426 * MD5 <http://www.ietf.org/rfc/rfc1321.txt>
14427 * RIPEMD-160 <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
14428 * SHA1 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
14429 * SHA256 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
14430 * SHA512 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
14431 * HMAC <http://www.ietf.org/rfc/rfc2104.txt>
14437 // private helper methods
14438 function utf8Encode(str) {
14439 var x, y, output = '', i = -1, l;
14441 if (str && str.length) {
14443 while ((i+=1) < l) {
14444 /* Decode utf-16 surrogate pairs */
14445 x = str.charCodeAt(i);
14446 y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
14447 if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
14448 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
14451 /* Encode output as utf-8 */
14453 output += String.fromCharCode(x);
14454 } else if (x <= 0x7FF) {
14455 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
14456 0x80 | ( x & 0x3F));
14457 } else if (x <= 0xFFFF) {
14458 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
14459 0x80 | ((x >>> 6 ) & 0x3F),
14460 0x80 | ( x & 0x3F));
14461 } else if (x <= 0x1FFFFF) {
14462 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
14463 0x80 | ((x >>> 12) & 0x3F),
14464 0x80 | ((x >>> 6 ) & 0x3F),
14465 0x80 | ( x & 0x3F));
14472 function utf8Decode(str) {
14473 var i, ac, c1, c2, c3, arr = [], l;
14474 i = ac = c1 = c2 = c3 = 0;
14476 if (str && str.length) {
14481 c1 = str.charCodeAt(i);
14484 arr[ac] = String.fromCharCode(c1);
14486 } else if (c1 > 191 && c1 < 224) {
14487 c2 = str.charCodeAt(i + 1);
14488 arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
14491 c2 = str.charCodeAt(i + 1);
14492 c3 = str.charCodeAt(i + 2);
14493 arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
14498 return arr.join('');
14502 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
14503 * to work around bugs in some JS interpreters.
14505 function safe_add(x, y) {
14506 var lsw = (x & 0xFFFF) + (y & 0xFFFF),
14507 msw = (x >> 16) + (y >> 16) + (lsw >> 16);
14508 return (msw << 16) | (lsw & 0xFFFF);
14512 * Bitwise rotate a 32-bit number to the left.
14514 function bit_rol(num, cnt) {
14515 return (num << cnt) | (num >>> (32 - cnt));
14519 * Convert a raw string to a hex string
14521 function rstr2hex(input, hexcase) {
14522 var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
14523 output = '', x, i = 0, l = input.length;
14524 for (; i < l; i+=1) {
14525 x = input.charCodeAt(i);
14526 output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F);
14532 * Encode a string as utf-16
14534 function str2rstr_utf16le(input) {
14535 var i, l = input.length, output = '';
14536 for (i = 0; i < l; i+=1) {
14537 output += String.fromCharCode( input.charCodeAt(i) & 0xFF, (input.charCodeAt(i) >>> 8) & 0xFF);
14542 function str2rstr_utf16be(input) {
14543 var i, l = input.length, output = '';
14544 for (i = 0; i < l; i+=1) {
14545 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, input.charCodeAt(i) & 0xFF);
14551 * Convert an array of big-endian words to a string
14553 function binb2rstr(input) {
14554 var i, l = input.length * 32, output = '';
14555 for (i = 0; i < l; i += 8) {
14556 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
14562 * Convert an array of little-endian words to a string
14564 function binl2rstr(input) {
14565 var i, l = input.length * 32, output = '';
14566 for (i = 0;i < l; i += 8) {
14567 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
14573 * Convert a raw string to an array of little-endian words
14574 * Characters >255 have their high-byte silently ignored.
14576 function rstr2binl(input) {
14577 var i, l = input.length * 8, output = Array(input.length >> 2), lo = output.length;
14578 for (i = 0; i < lo; i+=1) {
14581 for (i = 0; i < l; i += 8) {
14582 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
14588 * Convert a raw string to an array of big-endian words
14589 * Characters >255 have their high-byte silently ignored.
14591 function rstr2binb(input) {
14592 var i, l = input.length * 8, output = Array(input.length >> 2), lo = output.length;
14593 for (i = 0; i < lo; i+=1) {
14596 for (i = 0; i < l; i += 8) {
14597 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
14603 * Convert a raw string to an arbitrary string encoding
14605 function rstr2any(input, encoding) {
14606 var divisor = encoding.length,
14607 remainders = Array(),
14608 i, q, x, ld, quotient, dividend, output, full_length;
14610 /* Convert to an array of 16-bit big-endian values, forming the dividend */
14611 dividend = Array(Math.ceil(input.length / 2));
14612 ld = dividend.length;
14613 for (i = 0; i < ld; i+=1) {
14614 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
14618 * Repeatedly perform a long division. The binary array forms the dividend,
14619 * the length of the encoding is the divisor. Once computed, the quotient
14620 * forms the dividend for the next step. We stop when the dividend is zerHashes.
14621 * All remainders are stored for later use.
14623 while(dividend.length > 0) {
14624 quotient = Array();
14626 for (i = 0; i < dividend.length; i+=1) {
14627 x = (x << 16) + dividend[i];
14628 q = Math.floor(x / divisor);
14630 if (quotient.length > 0 || q > 0) {
14631 quotient[quotient.length] = q;
14634 remainders[remainders.length] = x;
14635 dividend = quotient;
14638 /* Convert the remainders to the output string */
14640 for (i = remainders.length - 1; i >= 0; i--) {
14641 output += encoding.charAt(remainders[i]);
14644 /* Append leading zero equivalents */
14645 full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
14646 for (i = output.length; i < full_length; i+=1) {
14647 output = encoding[0] + output;
14653 * Convert a raw string to a base-64 string
14655 function rstr2b64(input, b64pad) {
14656 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
14658 len = input.length, i, j, triplet;
14659 b64pad= b64pad || '=';
14660 for (i = 0; i < len; i += 3) {
14661 triplet = (input.charCodeAt(i) << 16)
14662 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
14663 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
14664 for (j = 0; j < 4; j+=1) {
14665 if (i * 8 + j * 6 > input.length * 8) {
14668 output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
14677 * @property {String} version
14686 Base64 : function () {
14687 // private properties
14688 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
14689 pad = '=', // default pad according with the RFC standard
14690 url = false, // URL encoding support @todo
14691 utf8 = true; // by default enable UTF-8 support encoding
14693 // public method for encoding
14694 this.encode = function (input) {
14697 len = input.length;
14700 input = (utf8) ? utf8Encode(input) : input;
14702 for (i = 0; i < len; i += 3) {
14703 triplet = (input.charCodeAt(i) << 16)
14704 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
14705 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
14706 for (j = 0; j < 4; j+=1) {
14707 if (i * 8 + j * 6 > len * 8) {
14710 output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
14717 // public method for decoding
14718 this.decode = function (input) {
14719 // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
14720 var i, o1, o2, o3, h1, h2, h3, h4, bits, ac,
14723 if (!input) { return input; }
14726 input = input.replace(new RegExp('\\'+pad,'gi'),''); // use '='
14729 do { // unpack four hexets into three octets using index points in b64
14730 h1 = tab.indexOf(input.charAt(i+=1));
14731 h2 = tab.indexOf(input.charAt(i+=1));
14732 h3 = tab.indexOf(input.charAt(i+=1));
14733 h4 = tab.indexOf(input.charAt(i+=1));
14735 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
14737 o1 = bits >> 16 & 0xff;
14738 o2 = bits >> 8 & 0xff;
14743 arr[ac] = String.fromCharCode(o1);
14744 } else if (h4 === 64) {
14745 arr[ac] = String.fromCharCode(o1, o2);
14747 arr[ac] = String.fromCharCode(o1, o2, o3);
14749 } while (i < input.length);
14751 dec = arr.join('');
14752 dec = (utf8) ? utf8Decode(dec) : dec;
14757 // set custom pad string
14758 this.setPad = function (str) {
14762 // set custom tab string characters
14763 this.setTab = function (str) {
14767 this.setUTF8 = function (bool) {
14768 if (typeof bool === 'boolean') {
14776 * CRC-32 calculation
14780 * @param {String} str Input String
14783 CRC32 : function (str) {
14784 var crc = 0, x = 0, y = 0, table, i, iTop;
14785 str = utf8Encode(str);
14788 '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ',
14789 '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ',
14790 '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ',
14791 '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ',
14792 'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ',
14793 '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ',
14794 'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ',
14795 '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ',
14796 'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ',
14797 '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ',
14798 'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ',
14799 '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ',
14800 'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ',
14801 '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ',
14802 '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ',
14803 '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ',
14804 '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ',
14805 'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ',
14806 '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ',
14807 'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ',
14808 '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ',
14809 'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ',
14810 '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ',
14811 'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ',
14812 '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ',
14813 'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'
14817 for (i = 0, iTop = str.length; i < iTop; i+=1 ) {
14818 y = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
14819 x = '0x' + table.substr( y * 9, 8 );
14820 crc = ( crc >>> 8 ) ^ x;
14822 // always return a positive number (that's what >>> 0 does)
14823 return (crc ^ (-1)) >>> 0;
14829 * @param {Object} [config]
14831 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
14832 * Digest Algorithm, as defined in RFC 1321.
14833 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
14834 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
14835 * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
14837 MD5 : function (options) {
14839 * Private config properties. You may need to tweak these to be compatible with
14840 * the server-side, but the defaults work in most cases.
14841 * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
14843 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
14844 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
14845 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
14847 // privileged (public) methods
14848 this.hex = function (s) {
14849 return rstr2hex(rstr(s, utf8), hexcase);
14851 this.b64 = function (s) {
14852 return rstr2b64(rstr(s), b64pad);
14854 this.any = function(s, e) {
14855 return rstr2any(rstr(s, utf8), e);
14857 this.hex_hmac = function (k, d) {
14858 return rstr2hex(rstr_hmac(k, d), hexcase);
14860 this.b64_hmac = function (k, d) {
14861 return rstr2b64(rstr_hmac(k,d), b64pad);
14863 this.any_hmac = function (k, d, e) {
14864 return rstr2any(rstr_hmac(k, d), e);
14867 * Perform a simple self-test to see if the VM is working
14868 * @return {String} Hexadecimal hash sample
14870 this.vm_test = function () {
14871 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
14874 * Enable/disable uppercase hexadecimal returned string
14876 * @return {Object} this
14878 this.setUpperCase = function (a) {
14879 if (typeof a === 'boolean' ) {
14885 * Defines a base64 pad string
14886 * @param {String} Pad
14887 * @return {Object} this
14889 this.setPad = function (a) {
14890 b64pad = a || b64pad;
14894 * Defines a base64 pad string
14896 * @return {Object} [this]
14898 this.setUTF8 = function (a) {
14899 if (typeof a === 'boolean') {
14908 * Calculate the MD5 of a raw string
14911 s = (utf8) ? utf8Encode(s): s;
14912 return binl2rstr(binl(rstr2binl(s), s.length * 8));
14916 * Calculate the HMAC-MD5, of a key and some data (raw strings)
14918 function rstr_hmac(key, data) {
14919 var bkey, ipad, opad, hash, i;
14921 key = (utf8) ? utf8Encode(key) : key;
14922 data = (utf8) ? utf8Encode(data) : data;
14923 bkey = rstr2binl(key);
14924 if (bkey.length > 16) {
14925 bkey = binl(bkey, key.length * 8);
14928 ipad = Array(16), opad = Array(16);
14929 for (i = 0; i < 16; i+=1) {
14930 ipad[i] = bkey[i] ^ 0x36363636;
14931 opad[i] = bkey[i] ^ 0x5C5C5C5C;
14933 hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
14934 return binl2rstr(binl(opad.concat(hash), 512 + 128));
14938 * Calculate the MD5 of an array of little-endian words, and a bit length.
14940 function binl(x, len) {
14941 var i, olda, oldb, oldc, oldd,
14947 /* append padding */
14948 x[len >> 5] |= 0x80 << ((len) % 32);
14949 x[(((len + 64) >>> 9) << 4) + 14] = len;
14951 for (i = 0; i < x.length; i += 16) {
14957 a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
14958 d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
14959 c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
14960 b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
14961 a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
14962 d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
14963 c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
14964 b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
14965 a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
14966 d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
14967 c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
14968 b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
14969 a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
14970 d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
14971 c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
14972 b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
14974 a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
14975 d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
14976 c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
14977 b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
14978 a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
14979 d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
14980 c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
14981 b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
14982 a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
14983 d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
14984 c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
14985 b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
14986 a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
14987 d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
14988 c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
14989 b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
14991 a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
14992 d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
14993 c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
14994 b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
14995 a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
14996 d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
14997 c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
14998 b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
14999 a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
15000 d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
15001 c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
15002 b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
15003 a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
15004 d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
15005 c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
15006 b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
15008 a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
15009 d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
15010 c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
15011 b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
15012 a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
15013 d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
15014 c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
15015 b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
15016 a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
15017 d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
15018 c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
15019 b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
15020 a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
15021 d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
15022 c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
15023 b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
15025 a = safe_add(a, olda);
15026 b = safe_add(b, oldb);
15027 c = safe_add(c, oldc);
15028 d = safe_add(d, oldd);
15030 return Array(a, b, c, d);
15034 * These functions implement the four basic operations the algorithm uses.
15036 function md5_cmn(q, a, b, x, s, t) {
15037 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
15039 function md5_ff(a, b, c, d, x, s, t) {
15040 return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
15042 function md5_gg(a, b, c, d, x, s, t) {
15043 return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
15045 function md5_hh(a, b, c, d, x, s, t) {
15046 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
15048 function md5_ii(a, b, c, d, x, s, t) {
15049 return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
15054 * @class Hashes.SHA1
15055 * @param {Object} [config]
15058 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
15059 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
15060 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
15061 * See http://pajhome.org.uk/crypt/md5 for details.
15063 SHA1 : function (options) {
15065 * Private config properties. You may need to tweak these to be compatible with
15066 * the server-side, but the defaults work in most cases.
15067 * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
15069 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
15070 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
15071 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
15074 this.hex = function (s) {
15075 return rstr2hex(rstr(s, utf8), hexcase);
15077 this.b64 = function (s) {
15078 return rstr2b64(rstr(s, utf8), b64pad);
15080 this.any = function (s, e) {
15081 return rstr2any(rstr(s, utf8), e);
15083 this.hex_hmac = function (k, d) {
15084 return rstr2hex(rstr_hmac(k, d));
15086 this.b64_hmac = function (k, d) {
15087 return rstr2b64(rstr_hmac(k, d), b64pad);
15089 this.any_hmac = function (k, d, e) {
15090 return rstr2any(rstr_hmac(k, d), e);
15093 * Perform a simple self-test to see if the VM is working
15094 * @return {String} Hexadecimal hash sample
15097 this.vm_test = function () {
15098 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
15101 * @description Enable/disable uppercase hexadecimal returned string
15103 * @return {Object} this
15106 this.setUpperCase = function (a) {
15107 if (typeof a === 'boolean') {
15113 * @description Defines a base64 pad string
15114 * @param {string} Pad
15115 * @return {Object} this
15118 this.setPad = function (a) {
15119 b64pad = a || b64pad;
15123 * @description Defines a base64 pad string
15125 * @return {Object} this
15128 this.setUTF8 = function (a) {
15129 if (typeof a === 'boolean') {
15138 * Calculate the SHA-512 of a raw string
15141 s = (utf8) ? utf8Encode(s) : s;
15142 return binb2rstr(binb(rstr2binb(s), s.length * 8));
15146 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
15148 function rstr_hmac(key, data) {
15149 var bkey, ipad, opad, i, hash;
15150 key = (utf8) ? utf8Encode(key) : key;
15151 data = (utf8) ? utf8Encode(data) : data;
15152 bkey = rstr2binb(key);
15154 if (bkey.length > 16) {
15155 bkey = binb(bkey, key.length * 8);
15157 ipad = Array(16), opad = Array(16);
15158 for (i = 0; i < 16; i+=1) {
15159 ipad[i] = bkey[i] ^ 0x36363636;
15160 opad[i] = bkey[i] ^ 0x5C5C5C5C;
15162 hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
15163 return binb2rstr(binb(opad.concat(hash), 512 + 160));
15167 * Calculate the SHA-1 of an array of big-endian words, and a bit length
15169 function binb(x, len) {
15170 var i, j, t, olda, oldb, oldc, oldd, olde,
15178 /* append padding */
15179 x[len >> 5] |= 0x80 << (24 - len % 32);
15180 x[((len + 64 >> 9) << 4) + 15] = len;
15182 for (i = 0; i < x.length; i += 16) {
15189 for (j = 0; j < 80; j+=1) {
15193 w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
15195 t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
15196 safe_add(safe_add(e, w[j]), sha1_kt(j)));
15199 c = bit_rol(b, 30);
15204 a = safe_add(a, olda);
15205 b = safe_add(b, oldb);
15206 c = safe_add(c, oldc);
15207 d = safe_add(d, oldd);
15208 e = safe_add(e, olde);
15210 return Array(a, b, c, d, e);
15214 * Perform the appropriate triplet combination function for the current
15217 function sha1_ft(t, b, c, d) {
15218 if (t < 20) { return (b & c) | ((~b) & d); }
15219 if (t < 40) { return b ^ c ^ d; }
15220 if (t < 60) { return (b & c) | (b & d) | (c & d); }
15225 * Determine the appropriate additive constant for the current iteration
15227 function sha1_kt(t) {
15228 return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
15229 (t < 60) ? -1894007588 : -899497514;
15233 * @class Hashes.SHA256
15236 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
15237 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
15238 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
15239 * See http://pajhome.org.uk/crypt/md5 for details.
15240 * Also http://anmar.eu.org/projects/jssha2/
15242 SHA256 : function (options) {
15244 * Private properties configuration variables. You may need to tweak these to be compatible with
15245 * the server-side, but the defaults work in most cases.
15246 * @see this.setUpperCase() method
15247 * @see this.setPad() method
15249 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase */
15250 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
15251 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
15254 /* privileged (public) methods */
15255 this.hex = function (s) {
15256 return rstr2hex(rstr(s, utf8));
15258 this.b64 = function (s) {
15259 return rstr2b64(rstr(s, utf8), b64pad);
15261 this.any = function (s, e) {
15262 return rstr2any(rstr(s, utf8), e);
15264 this.hex_hmac = function (k, d) {
15265 return rstr2hex(rstr_hmac(k, d));
15267 this.b64_hmac = function (k, d) {
15268 return rstr2b64(rstr_hmac(k, d), b64pad);
15270 this.any_hmac = function (k, d, e) {
15271 return rstr2any(rstr_hmac(k, d), e);
15274 * Perform a simple self-test to see if the VM is working
15275 * @return {String} Hexadecimal hash sample
15278 this.vm_test = function () {
15279 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
15282 * Enable/disable uppercase hexadecimal returned string
15284 * @return {Object} this
15287 this.setUpperCase = function (a) {
15288 if (typeof a === 'boolean') {
15294 * @description Defines a base64 pad string
15295 * @param {string} Pad
15296 * @return {Object} this
15299 this.setPad = function (a) {
15300 b64pad = a || b64pad;
15304 * Defines a base64 pad string
15306 * @return {Object} this
15309 this.setUTF8 = function (a) {
15310 if (typeof a === 'boolean') {
15319 * Calculate the SHA-512 of a raw string
15321 function rstr(s, utf8) {
15322 s = (utf8) ? utf8Encode(s) : s;
15323 return binb2rstr(binb(rstr2binb(s), s.length * 8));
15327 * Calculate the HMAC-sha256 of a key and some data (raw strings)
15329 function rstr_hmac(key, data) {
15330 key = (utf8) ? utf8Encode(key) : key;
15331 data = (utf8) ? utf8Encode(data) : data;
15333 bkey = rstr2binb(key),
15337 if (bkey.length > 16) { bkey = binb(bkey, key.length * 8); }
15339 for (; i < 16; i+=1) {
15340 ipad[i] = bkey[i] ^ 0x36363636;
15341 opad[i] = bkey[i] ^ 0x5C5C5C5C;
15344 hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
15345 return binb2rstr(binb(opad.concat(hash), 512 + 256));
15349 * Main sha256 function, with its support functions
15351 function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
15352 function sha256_R (X, n) {return ( X >>> n );}
15353 function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
15354 function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
15355 function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
15356 function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
15357 function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
15358 function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
15359 function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
15360 function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
15361 function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
15362 function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
15365 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
15366 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
15367 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
15368 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
15369 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
15370 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
15371 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
15372 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
15373 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
15374 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
15375 -1866530822, -1538233109, -1090935817, -965641998
15378 function binb(m, l) {
15379 var HASH = [1779033703, -1150833019, 1013904242, -1521486534,
15380 1359893119, -1694144372, 528734635, 1541459225];
15381 var W = new Array(64);
15382 var a, b, c, d, e, f, g, h;
15385 /* append padding */
15386 m[l >> 5] |= 0x80 << (24 - l % 32);
15387 m[((l + 64 >> 9) << 4) + 15] = l;
15389 for (i = 0; i < m.length; i += 16)
15400 for (j = 0; j < 64; j+=1)
15405 W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
15406 sha256_Gamma0256(W[j - 15])), W[j - 16]);
15409 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
15410 sha256_K[j]), W[j]);
15411 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
15415 e = safe_add(d, T1);
15419 a = safe_add(T1, T2);
15422 HASH[0] = safe_add(a, HASH[0]);
15423 HASH[1] = safe_add(b, HASH[1]);
15424 HASH[2] = safe_add(c, HASH[2]);
15425 HASH[3] = safe_add(d, HASH[3]);
15426 HASH[4] = safe_add(e, HASH[4]);
15427 HASH[5] = safe_add(f, HASH[5]);
15428 HASH[6] = safe_add(g, HASH[6]);
15429 HASH[7] = safe_add(h, HASH[7]);
15437 * @class Hashes.SHA512
15440 * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
15441 * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
15442 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
15443 * See http://pajhome.org.uk/crypt/md5 for details.
15445 SHA512 : function (options) {
15447 * Private properties configuration variables. You may need to tweak these to be compatible with
15448 * the server-side, but the defaults work in most cases.
15449 * @see this.setUpperCase() method
15450 * @see this.setPad() method
15452 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false , /* hexadecimal output case format. false - lowercase; true - uppercase */
15453 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
15454 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
15457 /* privileged (public) methods */
15458 this.hex = function (s) {
15459 return rstr2hex(rstr(s));
15461 this.b64 = function (s) {
15462 return rstr2b64(rstr(s), b64pad);
15464 this.any = function (s, e) {
15465 return rstr2any(rstr(s), e);
15467 this.hex_hmac = function (k, d) {
15468 return rstr2hex(rstr_hmac(k, d));
15470 this.b64_hmac = function (k, d) {
15471 return rstr2b64(rstr_hmac(k, d), b64pad);
15473 this.any_hmac = function (k, d, e) {
15474 return rstr2any(rstr_hmac(k, d), e);
15477 * Perform a simple self-test to see if the VM is working
15478 * @return {String} Hexadecimal hash sample
15481 this.vm_test = function () {
15482 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
15485 * @description Enable/disable uppercase hexadecimal returned string
15487 * @return {Object} this
15490 this.setUpperCase = function (a) {
15491 if (typeof a === 'boolean') {
15497 * @description Defines a base64 pad string
15498 * @param {string} Pad
15499 * @return {Object} this
15502 this.setPad = function (a) {
15503 b64pad = a || b64pad;
15507 * @description Defines a base64 pad string
15509 * @return {Object} this
15512 this.setUTF8 = function (a) {
15513 if (typeof a === 'boolean') {
15519 /* private methods */
15522 * Calculate the SHA-512 of a raw string
15525 s = (utf8) ? utf8Encode(s) : s;
15526 return binb2rstr(binb(rstr2binb(s), s.length * 8));
15529 * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
15531 function rstr_hmac(key, data) {
15532 key = (utf8) ? utf8Encode(key) : key;
15533 data = (utf8) ? utf8Encode(data) : data;
15536 bkey = rstr2binb(key),
15537 ipad = Array(32), opad = Array(32);
15539 if (bkey.length > 32) { bkey = binb(bkey, key.length * 8); }
15541 for (; i < 32; i+=1) {
15542 ipad[i] = bkey[i] ^ 0x36363636;
15543 opad[i] = bkey[i] ^ 0x5C5C5C5C;
15546 hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
15547 return binb2rstr(binb(opad.concat(hash), 1024 + 512));
15551 * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
15553 function binb(x, len) {
15556 hash = new Array(16),
15557 //Initial hash values
15559 new int64(0x6a09e667, -205731576),
15560 new int64(-1150833019, -2067093701),
15561 new int64(0x3c6ef372, -23791573),
15562 new int64(-1521486534, 0x5f1d36f1),
15563 new int64(0x510e527f, -1377402159),
15564 new int64(-1694144372, 0x2b3e6c1f),
15565 new int64(0x1f83d9ab, -79577749),
15566 new int64(0x5be0cd19, 0x137e2179)
15568 T1 = new int64(0, 0),
15569 T2 = new int64(0, 0),
15570 a = new int64(0,0),
15571 b = new int64(0,0),
15572 c = new int64(0,0),
15573 d = new int64(0,0),
15574 e = new int64(0,0),
15575 f = new int64(0,0),
15576 g = new int64(0,0),
15577 h = new int64(0,0),
15578 //Temporary variables not specified by the document
15579 s0 = new int64(0, 0),
15580 s1 = new int64(0, 0),
15581 Ch = new int64(0, 0),
15582 Maj = new int64(0, 0),
15583 r1 = new int64(0, 0),
15584 r2 = new int64(0, 0),
15585 r3 = new int64(0, 0);
15587 if (sha512_k === undefined) {
15590 new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
15591 new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
15592 new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
15593 new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
15594 new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
15595 new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
15596 new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
15597 new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
15598 new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
15599 new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
15600 new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
15601 new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
15602 new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
15603 new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
15604 new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
15605 new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
15606 new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
15607 new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
15608 new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
15609 new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
15610 new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
15611 new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
15612 new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
15613 new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
15614 new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
15615 new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
15616 new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
15617 new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
15618 new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
15619 new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
15620 new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
15621 new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
15622 new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
15623 new int64(-354779690, -840897762), new int64(-176337025, -294727304),
15624 new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
15625 new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
15626 new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
15627 new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
15628 new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
15629 new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)
15633 for (i=0; i<80; i+=1) {
15634 W[i] = new int64(0, 0);
15637 // append padding to the source string. The format is described in the FIPS.
15638 x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
15639 x[((len + 128 >> 10)<< 5) + 31] = len;
15641 for (i = 0; i<l; i+=32) { //32 dwords is the block size
15642 int64copy(a, H[0]);
15643 int64copy(b, H[1]);
15644 int64copy(c, H[2]);
15645 int64copy(d, H[3]);
15646 int64copy(e, H[4]);
15647 int64copy(f, H[5]);
15648 int64copy(g, H[6]);
15649 int64copy(h, H[7]);
15651 for (j=0; j<16; j+=1) {
15652 W[j].h = x[i + 2*j];
15653 W[j].l = x[i + 2*j + 1];
15656 for (j=16; j<80; j+=1) {
15658 int64rrot(r1, W[j-2], 19);
15659 int64revrrot(r2, W[j-2], 29);
15660 int64shr(r3, W[j-2], 6);
15661 s1.l = r1.l ^ r2.l ^ r3.l;
15662 s1.h = r1.h ^ r2.h ^ r3.h;
15664 int64rrot(r1, W[j-15], 1);
15665 int64rrot(r2, W[j-15], 8);
15666 int64shr(r3, W[j-15], 7);
15667 s0.l = r1.l ^ r2.l ^ r3.l;
15668 s0.h = r1.h ^ r2.h ^ r3.h;
15670 int64add4(W[j], s1, W[j-7], s0, W[j-16]);
15673 for (j = 0; j < 80; j+=1) {
15675 Ch.l = (e.l & f.l) ^ (~e.l & g.l);
15676 Ch.h = (e.h & f.h) ^ (~e.h & g.h);
15679 int64rrot(r1, e, 14);
15680 int64rrot(r2, e, 18);
15681 int64revrrot(r3, e, 9);
15682 s1.l = r1.l ^ r2.l ^ r3.l;
15683 s1.h = r1.h ^ r2.h ^ r3.h;
15686 int64rrot(r1, a, 28);
15687 int64revrrot(r2, a, 2);
15688 int64revrrot(r3, a, 7);
15689 s0.l = r1.l ^ r2.l ^ r3.l;
15690 s0.h = r1.h ^ r2.h ^ r3.h;
15693 Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
15694 Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
15696 int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
15697 int64add(T2, s0, Maj);
15702 int64add(e, d, T1);
15706 int64add(a, T1, T2);
15708 int64add(H[0], H[0], a);
15709 int64add(H[1], H[1], b);
15710 int64add(H[2], H[2], c);
15711 int64add(H[3], H[3], d);
15712 int64add(H[4], H[4], e);
15713 int64add(H[5], H[5], f);
15714 int64add(H[6], H[6], g);
15715 int64add(H[7], H[7], h);
15718 //represent the hash as an array of 32-bit dwords
15719 for (i=0; i<8; i+=1) {
15720 hash[2*i] = H[i].h;
15721 hash[2*i + 1] = H[i].l;
15726 //A constructor for 64-bit numbers
15727 function int64(h, l) {
15730 //this.toString = int64toString;
15733 //Copies src into dst, assuming both are 64-bit numbers
15734 function int64copy(dst, src) {
15739 //Right-rotates a 64-bit number by shift
15740 //Won't handle cases of shift>=32
15741 //The function revrrot() is for that
15742 function int64rrot(dst, x, shift) {
15743 dst.l = (x.l >>> shift) | (x.h << (32-shift));
15744 dst.h = (x.h >>> shift) | (x.l << (32-shift));
15747 //Reverses the dwords of the source and then rotates right by shift.
15748 //This is equivalent to rotation by 32+shift
15749 function int64revrrot(dst, x, shift) {
15750 dst.l = (x.h >>> shift) | (x.l << (32-shift));
15751 dst.h = (x.l >>> shift) | (x.h << (32-shift));
15754 //Bitwise-shifts right a 64-bit number by shift
15755 //Won't handle shift>=32, but it's never needed in SHA512
15756 function int64shr(dst, x, shift) {
15757 dst.l = (x.l >>> shift) | (x.h << (32-shift));
15758 dst.h = (x.h >>> shift);
15761 //Adds two 64-bit numbers
15762 //Like the original implementation, does not rely on 32-bit operations
15763 function int64add(dst, x, y) {
15764 var w0 = (x.l & 0xffff) + (y.l & 0xffff);
15765 var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
15766 var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
15767 var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
15768 dst.l = (w0 & 0xffff) | (w1 << 16);
15769 dst.h = (w2 & 0xffff) | (w3 << 16);
15772 //Same, except with 4 addends. Works faster than adding them one by one.
15773 function int64add4(dst, a, b, c, d) {
15774 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
15775 var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
15776 var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
15777 var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
15778 dst.l = (w0 & 0xffff) | (w1 << 16);
15779 dst.h = (w2 & 0xffff) | (w3 << 16);
15782 //Same, except with 5 addends
15783 function int64add5(dst, a, b, c, d, e) {
15784 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
15785 w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
15786 w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
15787 w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
15788 dst.l = (w0 & 0xffff) | (w1 << 16);
15789 dst.h = (w2 & 0xffff) | (w3 << 16);
15793 * @class Hashes.RMD160
15795 * @param {Object} [config]
15797 * A JavaScript implementation of the RIPEMD-160 Algorithm
15798 * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
15799 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
15800 * See http://pajhome.org.uk/crypt/md5 for details.
15801 * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
15803 RMD160 : function (options) {
15805 * Private properties configuration variables. You may need to tweak these to be compatible with
15806 * the server-side, but the defaults work in most cases.
15807 * @see this.setUpperCase() method
15808 * @see this.setPad() method
15810 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, /* hexadecimal output case format. false - lowercase; true - uppercase */
15811 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
15812 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
15814 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
15815 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
15816 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
15817 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
15818 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
15821 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
15822 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
15823 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
15824 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
15825 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
15828 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
15829 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
15830 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
15831 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
15832 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
15835 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
15836 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
15837 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
15838 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
15839 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
15842 /* privileged (public) methods */
15843 this.hex = function (s) {
15844 return rstr2hex(rstr(s, utf8));
15846 this.b64 = function (s) {
15847 return rstr2b64(rstr(s, utf8), b64pad);
15849 this.any = function (s, e) {
15850 return rstr2any(rstr(s, utf8), e);
15852 this.hex_hmac = function (k, d) {
15853 return rstr2hex(rstr_hmac(k, d));
15855 this.b64_hmac = function (k, d) {
15856 return rstr2b64(rstr_hmac(k, d), b64pad);
15858 this.any_hmac = function (k, d, e) {
15859 return rstr2any(rstr_hmac(k, d), e);
15862 * Perform a simple self-test to see if the VM is working
15863 * @return {String} Hexadecimal hash sample
15866 this.vm_test = function () {
15867 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
15870 * @description Enable/disable uppercase hexadecimal returned string
15872 * @return {Object} this
15875 this.setUpperCase = function (a) {
15876 if (typeof a === 'boolean' ) { hexcase = a; }
15880 * @description Defines a base64 pad string
15881 * @param {string} Pad
15882 * @return {Object} this
15885 this.setPad = function (a) {
15886 if (typeof a !== 'undefined' ) { b64pad = a; }
15890 * @description Defines a base64 pad string
15892 * @return {Object} this
15895 this.setUTF8 = function (a) {
15896 if (typeof a === 'boolean') { utf8 = a; }
15900 /* private methods */
15903 * Calculate the rmd160 of a raw string
15906 s = (utf8) ? utf8Encode(s) : s;
15907 return binl2rstr(binl(rstr2binl(s), s.length * 8));
15911 * Calculate the HMAC-rmd160 of a key and some data (raw strings)
15913 function rstr_hmac(key, data) {
15914 key = (utf8) ? utf8Encode(key) : key;
15915 data = (utf8) ? utf8Encode(data) : data;
15917 bkey = rstr2binl(key),
15918 ipad = Array(16), opad = Array(16);
15920 if (bkey.length > 16) {
15921 bkey = binl(bkey, key.length * 8);
15924 for (i = 0; i < 16; i+=1) {
15925 ipad[i] = bkey[i] ^ 0x36363636;
15926 opad[i] = bkey[i] ^ 0x5C5C5C5C;
15928 hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
15929 return binl2rstr(binl(opad.concat(hash), 512 + 160));
15933 * Convert an array of little-endian words to a string
15935 function binl2rstr(input) {
15936 var i, output = '', l = input.length * 32;
15937 for (i = 0; i < l; i += 8) {
15938 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
15944 * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
15946 function binl(x, len) {
15953 A1, B1, C1, D1, E1,
15954 A2, B2, C2, D2, E2;
15956 /* append padding */
15957 x[len >> 5] |= 0x80 << (len % 32);
15958 x[(((len + 64) >>> 9) << 4) + 14] = len;
15961 for (i = 0; i < l; i+=16) {
15962 A1 = A2 = h0; B1 = B2 = h1; C1 = C2 = h2; D1 = D2 = h3; E1 = E2 = h4;
15963 for (j = 0; j <= 79; j+=1) {
15964 T = safe_add(A1, rmd160_f(j, B1, C1, D1));
15965 T = safe_add(T, x[i + rmd160_r1[j]]);
15966 T = safe_add(T, rmd160_K1(j));
15967 T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
15968 A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
15969 T = safe_add(A2, rmd160_f(79-j, B2, C2, D2));
15970 T = safe_add(T, x[i + rmd160_r2[j]]);
15971 T = safe_add(T, rmd160_K2(j));
15972 T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
15973 A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
15976 T = safe_add(h1, safe_add(C1, D2));
15977 h1 = safe_add(h2, safe_add(D1, E2));
15978 h2 = safe_add(h3, safe_add(E1, A2));
15979 h3 = safe_add(h4, safe_add(A1, B2));
15980 h4 = safe_add(h0, safe_add(B1, C2));
15983 return [h0, h1, h2, h3, h4];
15986 // specific algorithm methods
15987 function rmd160_f(j, x, y, z) {
15988 return ( 0 <= j && j <= 15) ? (x ^ y ^ z) :
15989 (16 <= j && j <= 31) ? (x & y) | (~x & z) :
15990 (32 <= j && j <= 47) ? (x | ~y) ^ z :
15991 (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
15992 (64 <= j && j <= 79) ? x ^ (y | ~z) :
15993 'rmd160_f: j out of range';
15996 function rmd160_K1(j) {
15997 return ( 0 <= j && j <= 15) ? 0x00000000 :
15998 (16 <= j && j <= 31) ? 0x5a827999 :
15999 (32 <= j && j <= 47) ? 0x6ed9eba1 :
16000 (48 <= j && j <= 63) ? 0x8f1bbcdc :
16001 (64 <= j && j <= 79) ? 0xa953fd4e :
16002 'rmd160_K1: j out of range';
16005 function rmd160_K2(j){
16006 return ( 0 <= j && j <= 15) ? 0x50a28be6 :
16007 (16 <= j && j <= 31) ? 0x5c4dd124 :
16008 (32 <= j && j <= 47) ? 0x6d703ef3 :
16009 (48 <= j && j <= 63) ? 0x7a6d76e9 :
16010 (64 <= j && j <= 79) ? 0x00000000 :
16011 'rmd160_K2: j out of range';
16017 (function( window, undefined ) {
16018 var freeExports = false;
16019 if (typeof exports === 'object' ) {
16020 freeExports = exports;
16021 if (exports && typeof global === 'object' && global && global === global.global ) { window = global; }
16024 if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
16025 // define as an anonymous module, so, through path mapping, it can be aliased
16026 define(function () { return Hashes; });
16028 else if ( freeExports ) {
16029 // in Node.js or RingoJS v0.8.0+
16030 if ( typeof module === 'object' && module && module.exports === freeExports ) {
16031 module.exports = Hashes;
16033 // in Narwhal or RingoJS v0.7.0-
16035 freeExports.Hashes = Hashes;
16039 // in a browser or Rhino
16040 window.Hashes = Hashes;
16046 },{}],2:[function(require,module,exports){
16049 var hashes = require('jshashes'),
16050 xtend = require('xtend'),
16051 sha1 = new hashes.SHA1();
16055 ohauth.qsString = function(obj) {
16056 return Object.keys(obj).sort().map(function(key) {
16057 return ohauth.percentEncode(key) + '=' +
16058 ohauth.percentEncode(obj[key]);
16062 ohauth.stringQs = function(str) {
16063 return str.split('&').reduce(function(obj, pair){
16064 var parts = pair.split('=');
16065 obj[decodeURIComponent(parts[0])] = (null === parts[1]) ?
16066 '' : decodeURIComponent(parts[1]);
16071 ohauth.rawxhr = function(method, url, data, headers, callback) {
16072 var xhr = new XMLHttpRequest(),
16073 twoHundred = /^20\d$/;
16074 xhr.onreadystatechange = function() {
16075 if (4 == xhr.readyState && 0 !== xhr.status) {
16076 if (twoHundred.test(xhr.status)) callback(null, xhr);
16077 else return callback(xhr, null);
16080 xhr.onerror = function(e) { return callback(e, null); };
16081 xhr.open(method, url, true);
16082 for (var h in headers) xhr.setRequestHeader(h, headers[h]);
16086 ohauth.xhr = function(method, url, auth, data, options, callback) {
16087 var headers = (options && options.header) || {
16088 'Content-Type': 'application/x-www-form-urlencoded'
16090 headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
16091 ohauth.rawxhr(method, url, data, headers, callback);
16094 ohauth.nonce = function() {
16095 for (var o = ''; o.length < 6;) {
16096 o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
16101 ohauth.authHeader = function(obj) {
16102 return Object.keys(obj).sort().map(function(key) {
16103 return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
16107 ohauth.timestamp = function() { return ~~((+new Date()) / 1000); };
16109 ohauth.percentEncode = function(s) {
16110 return encodeURIComponent(s)
16111 .replace(/\!/g, '%21').replace(/\'/g, '%27')
16112 .replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
16115 ohauth.baseString = function(method, url, params) {
16116 if (params.oauth_signature) delete params.oauth_signature;
16119 ohauth.percentEncode(url),
16120 ohauth.percentEncode(ohauth.qsString(params))].join('&');
16123 ohauth.signature = function(oauth_secret, token_secret, baseString) {
16124 return sha1.b64_hmac(
16125 ohauth.percentEncode(oauth_secret) + '&' +
16126 ohauth.percentEncode(token_secret),
16131 * Takes an options object for configuration (consumer_key,
16132 * consumer_secret, version, signature_method, token) and returns a
16133 * function that generates the Authorization header for given data.
16135 * The returned function takes these parameters:
16136 * - method: GET/POST/...
16137 * - uri: full URI with protocol, port, path and query string
16138 * - extra_params: any extra parameters (that are passed in the POST data),
16139 * can be an object or a from-urlencoded string.
16141 * Returned function returns full OAuth header with "OAuth" string in it.
16144 ohauth.headerGenerator = function(options) {
16145 options = options || {};
16146 var consumer_key = options.consumer_key || '',
16147 consumer_secret = options.consumer_secret || '',
16148 signature_method = options.signature_method || 'HMAC-SHA1',
16149 version = options.version || '1.0',
16150 token = options.token || '';
16152 return function(method, uri, extra_params) {
16153 method = method.toUpperCase();
16154 if (typeof extra_params === 'string' && extra_params.length > 0) {
16155 extra_params = ohauth.stringQs(extra_params);
16158 var uri_parts = uri.split('?', 2),
16159 base_uri = uri_parts[0];
16161 var query_params = uri_parts.length === 2 ?
16162 ohauth.stringQs(uri_parts[1]) : {};
16164 var oauth_params = {
16165 oauth_consumer_key: consumer_key,
16166 oauth_signature_method: signature_method,
16167 oauth_version: version,
16168 oauth_timestamp: ohauth.timestamp(),
16169 oauth_nonce: ohauth.nonce()
16172 if (token) oauth_params.oauth_token = token;
16174 var all_params = xtend({}, oauth_params, query_params, extra_params),
16175 base_str = ohauth.baseString(method, base_uri, all_params);
16177 oauth_params.oauth_signature = ohauth.signature(consumer_secret, token, base_str);
16179 return 'OAuth ' + ohauth.authHeader(oauth_params);
16183 module.exports = ohauth;
16185 },{"jshashes":7,"xtend":4}],6:[function(require,module,exports){
16186 module.exports = Object.keys || require('./shim');
16189 },{"./shim":8}],8:[function(require,module,exports){
16193 // modified from https://github.com/kriskowal/es5-shim
16194 var has = Object.prototype.hasOwnProperty,
16195 is = require('is'),
16196 forEach = require('foreach'),
16197 hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
16204 "propertyIsEnumerable",
16209 keysShim = function keys(object) {
16210 if (!is.object(object) && !is.array(object)) {
16211 throw new TypeError("Object.keys called on a non-object");
16214 var name, theKeys = [];
16215 for (name in object) {
16216 if (has.call(object, name)) {
16217 theKeys.push(name);
16221 if (hasDontEnumBug) {
16222 forEach(dontEnums, function (dontEnum) {
16223 if (has.call(object, dontEnum)) {
16224 theKeys.push(dontEnum);
16231 module.exports = keysShim;
16235 },{"is":9,"foreach":10}],9:[function(require,module,exports){
16239 * the definitive JavaScript type testing library
16241 * @copyright 2013 Enrico Marino
16245 var objProto = Object.prototype;
16246 var owns = objProto.hasOwnProperty;
16247 var toString = objProto.toString;
16248 var isActualNaN = function (value) {
16249 return value !== value;
16251 var NON_HOST_TYPES = {
16262 var is = module.exports = {};
16270 * Test if `value` is a type of `type`.
16272 * @param {Mixed} value value to test
16273 * @param {String} type type
16274 * @return {Boolean} true if `value` is a type of `type`, false otherwise
16279 is.type = function (value, type) {
16280 return typeof value === type;
16285 * Test if `value` is defined.
16287 * @param {Mixed} value value to test
16288 * @return {Boolean} true if 'value' is defined, false otherwise
16292 is.defined = function (value) {
16293 return value !== undefined;
16298 * Test if `value` is empty.
16300 * @param {Mixed} value value to test
16301 * @return {Boolean} true if `value` is empty, false otherwise
16305 is.empty = function (value) {
16306 var type = toString.call(value);
16309 if ('[object Array]' === type || '[object Arguments]' === type) {
16310 return value.length === 0;
16313 if ('[object Object]' === type) {
16314 for (key in value) if (owns.call(value, key)) return false;
16318 if ('[object String]' === type) {
16319 return '' === value;
16327 * Test if `value` is equal to `other`.
16329 * @param {Mixed} value value to test
16330 * @param {Mixed} other value to compare with
16331 * @return {Boolean} true if `value` is equal to `other`, false otherwise
16334 is.equal = function (value, other) {
16335 var type = toString.call(value)
16338 if (type !== toString.call(other)) {
16342 if ('[object Object]' === type) {
16343 for (key in value) {
16344 if (!is.equal(value[key], other[key])) {
16351 if ('[object Array]' === type) {
16352 key = value.length;
16353 if (key !== other.length) {
16357 if (!is.equal(value[key], other[key])) {
16364 if ('[object Function]' === type) {
16365 return value.prototype === other.prototype;
16368 if ('[object Date]' === type) {
16369 return value.getTime() === other.getTime();
16372 return value === other;
16377 * Test if `value` is hosted by `host`.
16379 * @param {Mixed} value to test
16380 * @param {Mixed} host host to test with
16381 * @return {Boolean} true if `value` is hosted by `host`, false otherwise
16385 is.hosted = function (value, host) {
16386 var type = typeof host[value];
16387 return type === 'object' ? !!host[value] : !NON_HOST_TYPES[type];
16392 * Test if `value` is an instance of `constructor`.
16394 * @param {Mixed} value value to test
16395 * @return {Boolean} true if `value` is an instance of `constructor`
16399 is.instance = is['instanceof'] = function (value, constructor) {
16400 return value instanceof constructor;
16405 * Test if `value` is null.
16407 * @param {Mixed} value value to test
16408 * @return {Boolean} true if `value` is null, false otherwise
16412 is['null'] = function (value) {
16413 return value === null;
16418 * Test if `value` is undefined.
16420 * @param {Mixed} value value to test
16421 * @return {Boolean} true if `value` is undefined, false otherwise
16425 is.undefined = function (value) {
16426 return value === undefined;
16435 * Test if `value` is an arguments object.
16437 * @param {Mixed} value value to test
16438 * @return {Boolean} true if `value` is an arguments object, false otherwise
16442 is.arguments = function (value) {
16443 var isStandardArguments = '[object Arguments]' === toString.call(value);
16444 var isOldArguments = !is.array(value) && is.arraylike(value) && is.object(value) && is.fn(value.callee);
16445 return isStandardArguments || isOldArguments;
16454 * Test if 'value' is an array.
16456 * @param {Mixed} value value to test
16457 * @return {Boolean} true if `value` is an array, false otherwise
16461 is.array = function (value) {
16462 return '[object Array]' === toString.call(value);
16466 * is.arguments.empty
16467 * Test if `value` is an empty arguments object.
16469 * @param {Mixed} value value to test
16470 * @return {Boolean} true if `value` is an empty arguments object, false otherwise
16473 is.arguments.empty = function (value) {
16474 return is.arguments(value) && value.length === 0;
16479 * Test if `value` is an empty array.
16481 * @param {Mixed} value value to test
16482 * @return {Boolean} true if `value` is an empty array, false otherwise
16485 is.array.empty = function (value) {
16486 return is.array(value) && value.length === 0;
16491 * Test if `value` is an arraylike object.
16493 * @param {Mixed} value value to test
16494 * @return {Boolean} true if `value` is an arguments object, false otherwise
16498 is.arraylike = function (value) {
16499 return !!value && !is.boolean(value)
16500 && owns.call(value, 'length')
16501 && isFinite(value.length)
16502 && is.number(value.length)
16503 && value.length >= 0;
16512 * Test if `value` is a boolean.
16514 * @param {Mixed} value value to test
16515 * @return {Boolean} true if `value` is a boolean, false otherwise
16519 is.boolean = function (value) {
16520 return '[object Boolean]' === toString.call(value);
16525 * Test if `value` is false.
16527 * @param {Mixed} value value to test
16528 * @return {Boolean} true if `value` is false, false otherwise
16532 is['false'] = function (value) {
16533 return is.boolean(value) && (value === false || value.valueOf() === false);
16538 * Test if `value` is true.
16540 * @param {Mixed} value value to test
16541 * @return {Boolean} true if `value` is true, false otherwise
16545 is['true'] = function (value) {
16546 return is.boolean(value) && (value === true || value.valueOf() === true);
16555 * Test if `value` is a date.
16557 * @param {Mixed} value value to test
16558 * @return {Boolean} true if `value` is a date, false otherwise
16562 is.date = function (value) {
16563 return '[object Date]' === toString.call(value);
16572 * Test if `value` is an html element.
16574 * @param {Mixed} value value to test
16575 * @return {Boolean} true if `value` is an HTML Element, false otherwise
16579 is.element = function (value) {
16580 return value !== undefined
16581 && typeof HTMLElement !== 'undefined'
16582 && value instanceof HTMLElement
16583 && value.nodeType === 1;
16592 * Test if `value` is an error object.
16594 * @param {Mixed} value value to test
16595 * @return {Boolean} true if `value` is an error object, false otherwise
16599 is.error = function (value) {
16600 return '[object Error]' === toString.call(value);
16608 * is.fn / is.function (deprecated)
16609 * Test if `value` is a function.
16611 * @param {Mixed} value value to test
16612 * @return {Boolean} true if `value` is a function, false otherwise
16616 is.fn = is['function'] = function (value) {
16617 var isAlert = typeof window !== 'undefined' && value === window.alert;
16618 return isAlert || '[object Function]' === toString.call(value);
16627 * Test if `value` is a number.
16629 * @param {Mixed} value value to test
16630 * @return {Boolean} true if `value` is a number, false otherwise
16634 is.number = function (value) {
16635 return '[object Number]' === toString.call(value);
16640 * Test if `value` is positive or negative infinity.
16642 * @param {Mixed} value value to test
16643 * @return {Boolean} true if `value` is positive or negative Infinity, false otherwise
16646 is.infinite = function (value) {
16647 return value === Infinity || value === -Infinity;
16652 * Test if `value` is a decimal number.
16654 * @param {Mixed} value value to test
16655 * @return {Boolean} true if `value` is a decimal number, false otherwise
16659 is.decimal = function (value) {
16660 return is.number(value) && !isActualNaN(value) && value % 1 !== 0;
16665 * Test if `value` is divisible by `n`.
16667 * @param {Number} value value to test
16668 * @param {Number} n dividend
16669 * @return {Boolean} true if `value` is divisible by `n`, false otherwise
16673 is.divisibleBy = function (value, n) {
16674 var isDividendInfinite = is.infinite(value);
16675 var isDivisorInfinite = is.infinite(n);
16676 var isNonZeroNumber = is.number(value) && !isActualNaN(value) && is.number(n) && !isActualNaN(n) && n !== 0;
16677 return isDividendInfinite || isDivisorInfinite || (isNonZeroNumber && value % n === 0);
16682 * Test if `value` is an integer.
16684 * @param value to test
16685 * @return {Boolean} true if `value` is an integer, false otherwise
16689 is.int = function (value) {
16690 return is.number(value) && !isActualNaN(value) && value % 1 === 0;
16695 * Test if `value` is greater than 'others' values.
16697 * @param {Number} value value to test
16698 * @param {Array} others values to compare with
16699 * @return {Boolean} true if `value` is greater than `others` values
16703 is.maximum = function (value, others) {
16704 if (isActualNaN(value)) {
16705 throw new TypeError('NaN is not a valid value');
16706 } else if (!is.arraylike(others)) {
16707 throw new TypeError('second argument must be array-like');
16709 var len = others.length;
16711 while (--len >= 0) {
16712 if (value < others[len]) {
16722 * Test if `value` is less than `others` values.
16724 * @param {Number} value value to test
16725 * @param {Array} others values to compare with
16726 * @return {Boolean} true if `value` is less than `others` values
16730 is.minimum = function (value, others) {
16731 if (isActualNaN(value)) {
16732 throw new TypeError('NaN is not a valid value');
16733 } else if (!is.arraylike(others)) {
16734 throw new TypeError('second argument must be array-like');
16736 var len = others.length;
16738 while (--len >= 0) {
16739 if (value > others[len]) {
16749 * Test if `value` is not a number.
16751 * @param {Mixed} value value to test
16752 * @return {Boolean} true if `value` is not a number, false otherwise
16756 is.nan = function (value) {
16757 return !is.number(value) || value !== value;
16762 * Test if `value` is an even number.
16764 * @param {Number} value value to test
16765 * @return {Boolean} true if `value` is an even number, false otherwise
16769 is.even = function (value) {
16770 return is.infinite(value) || (is.number(value) && value === value && value % 2 === 0);
16775 * Test if `value` is an odd number.
16777 * @param {Number} value value to test
16778 * @return {Boolean} true if `value` is an odd number, false otherwise
16782 is.odd = function (value) {
16783 return is.infinite(value) || (is.number(value) && value === value && value % 2 !== 0);
16788 * Test if `value` is greater than or equal to `other`.
16790 * @param {Number} value value to test
16791 * @param {Number} other value to compare with
16792 * @return {Boolean}
16796 is.ge = function (value, other) {
16797 if (isActualNaN(value) || isActualNaN(other)) {
16798 throw new TypeError('NaN is not a valid value');
16800 return !is.infinite(value) && !is.infinite(other) && value >= other;
16805 * Test if `value` is greater than `other`.
16807 * @param {Number} value value to test
16808 * @param {Number} other value to compare with
16809 * @return {Boolean}
16813 is.gt = function (value, other) {
16814 if (isActualNaN(value) || isActualNaN(other)) {
16815 throw new TypeError('NaN is not a valid value');
16817 return !is.infinite(value) && !is.infinite(other) && value > other;
16822 * Test if `value` is less than or equal to `other`.
16824 * @param {Number} value value to test
16825 * @param {Number} other value to compare with
16826 * @return {Boolean} if 'value' is less than or equal to 'other'
16830 is.le = function (value, other) {
16831 if (isActualNaN(value) || isActualNaN(other)) {
16832 throw new TypeError('NaN is not a valid value');
16834 return !is.infinite(value) && !is.infinite(other) && value <= other;
16839 * Test if `value` is less than `other`.
16841 * @param {Number} value value to test
16842 * @param {Number} other value to compare with
16843 * @return {Boolean} if `value` is less than `other`
16847 is.lt = function (value, other) {
16848 if (isActualNaN(value) || isActualNaN(other)) {
16849 throw new TypeError('NaN is not a valid value');
16851 return !is.infinite(value) && !is.infinite(other) && value < other;
16856 * Test if `value` is within `start` and `finish`.
16858 * @param {Number} value value to test
16859 * @param {Number} start lower bound
16860 * @param {Number} finish upper bound
16861 * @return {Boolean} true if 'value' is is within 'start' and 'finish'
16864 is.within = function (value, start, finish) {
16865 if (isActualNaN(value) || isActualNaN(start) || isActualNaN(finish)) {
16866 throw new TypeError('NaN is not a valid value');
16867 } else if (!is.number(value) || !is.number(start) || !is.number(finish)) {
16868 throw new TypeError('all arguments must be numbers');
16870 var isAnyInfinite = is.infinite(value) || is.infinite(start) || is.infinite(finish);
16871 return isAnyInfinite || (value >= start && value <= finish);
16880 * Test if `value` is an object.
16882 * @param {Mixed} value value to test
16883 * @return {Boolean} true if `value` is an object, false otherwise
16887 is.object = function (value) {
16888 return value && '[object Object]' === toString.call(value);
16893 * Test if `value` is a hash - a plain object literal.
16895 * @param {Mixed} value value to test
16896 * @return {Boolean} true if `value` is a hash, false otherwise
16900 is.hash = function (value) {
16901 return is.object(value) && value.constructor === Object && !value.nodeType && !value.setInterval;
16910 * Test if `value` is a regular expression.
16912 * @param {Mixed} value value to test
16913 * @return {Boolean} true if `value` is a regexp, false otherwise
16917 is.regexp = function (value) {
16918 return '[object RegExp]' === toString.call(value);
16927 * Test if `value` is a string.
16929 * @param {Mixed} value value to test
16930 * @return {Boolean} true if 'value' is a string, false otherwise
16934 is.string = function (value) {
16935 return '[object String]' === toString.call(value);
16939 },{}],10:[function(require,module,exports){
16941 var hasOwn = Object.prototype.hasOwnProperty;
16942 var toString = Object.prototype.toString;
16944 module.exports = function forEach (obj, fn, ctx) {
16945 if (toString.call(fn) !== '[object Function]') {
16946 throw new TypeError('iterator must be a function');
16948 var l = obj.length;
16950 for (var i = 0; i < l; i++) {
16951 fn.call(ctx, obj[i], i, obj);
16954 for (var k in obj) {
16955 if (hasOwn.call(obj, k)) {
16956 fn.call(ctx, obj[k], k, obj);
16967 (c) 2015, Vladimir Agafonkin
16968 RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles.
16969 https://github.com/mourner/rbush
16975 function rbush(maxEntries, format) {
16977 // jshint newcap: false, validthis: true
16978 if (!(this instanceof rbush)) return new rbush(maxEntries, format);
16980 // max entries in a node is 9 by default; min node fill is 40% for best performance
16981 this._maxEntries = Math.max(4, maxEntries || 9);
16982 this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
16985 this._initFormat(format);
16991 rbush.prototype = {
16994 return this._all(this.data, []);
16997 search: function (bbox) {
16999 var node = this.data,
17001 toBBox = this.toBBox;
17003 if (!intersects(bbox, node.bbox)) return result;
17005 var nodesToSearch = [],
17006 i, len, child, childBBox;
17009 for (i = 0, len = node.children.length; i < len; i++) {
17011 child = node.children[i];
17012 childBBox = node.leaf ? toBBox(child) : child.bbox;
17014 if (intersects(bbox, childBBox)) {
17015 if (node.leaf) result.push(child);
17016 else if (contains(bbox, childBBox)) this._all(child, result);
17017 else nodesToSearch.push(child);
17020 node = nodesToSearch.pop();
17026 collides: function (bbox) {
17028 var node = this.data,
17029 toBBox = this.toBBox;
17031 if (!intersects(bbox, node.bbox)) return false;
17033 var nodesToSearch = [],
17034 i, len, child, childBBox;
17037 for (i = 0, len = node.children.length; i < len; i++) {
17039 child = node.children[i];
17040 childBBox = node.leaf ? toBBox(child) : child.bbox;
17042 if (intersects(bbox, childBBox)) {
17043 if (node.leaf || contains(bbox, childBBox)) return true;
17044 nodesToSearch.push(child);
17047 node = nodesToSearch.pop();
17053 load: function (data) {
17054 if (!(data && data.length)) return this;
17056 if (data.length < this._minEntries) {
17057 for (var i = 0, len = data.length; i < len; i++) {
17058 this.insert(data[i]);
17063 // recursively build the tree with the given data from stratch using OMT algorithm
17064 var node = this._build(data.slice(), 0, data.length - 1, 0);
17066 if (!this.data.children.length) {
17067 // save as is if tree is empty
17070 } else if (this.data.height === node.height) {
17071 // split root if trees have the same height
17072 this._splitRoot(this.data, node);
17075 if (this.data.height < node.height) {
17076 // swap trees if inserted one is bigger
17077 var tmpNode = this.data;
17082 // insert the small tree into the large tree at appropriate level
17083 this._insert(node, this.data.height - node.height - 1, true);
17089 insert: function (item) {
17090 if (item) this._insert(item, this.data.height - 1);
17094 clear: function () {
17104 remove: function (item) {
17105 if (!item) return this;
17107 var node = this.data,
17108 bbox = this.toBBox(item),
17111 i, parent, index, goingUp;
17113 // depth-first iterative tree traversal
17114 while (node || path.length) {
17116 if (!node) { // go up
17118 parent = path[path.length - 1];
17123 if (node.leaf) { // check current node
17124 index = node.children.indexOf(item);
17126 if (index !== -1) {
17127 // item found, remove the item and condense tree upwards
17128 node.children.splice(index, 1);
17130 this._condense(path);
17135 if (!goingUp && !node.leaf && contains(node.bbox, bbox)) { // go down
17140 node = node.children[0];
17142 } else if (parent) { // go right
17144 node = parent.children[i];
17147 } else node = null; // nothing found
17153 toBBox: function (item) { return item; },
17155 compareMinX: function (a, b) { return a[0] - b[0]; },
17156 compareMinY: function (a, b) { return a[1] - b[1]; },
17158 toJSON: function () { return this.data; },
17160 fromJSON: function (data) {
17165 _all: function (node, result) {
17166 var nodesToSearch = [];
17168 if (node.leaf) result.push.apply(result, node.children);
17169 else nodesToSearch.push.apply(nodesToSearch, node.children);
17171 node = nodesToSearch.pop();
17176 _build: function (items, left, right, height) {
17178 var N = right - left + 1,
17179 M = this._maxEntries,
17183 // reached leaf level; return leaf
17185 children: items.slice(left, right + 1),
17190 calcBBox(node, this.toBBox);
17195 // target height of the bulk-loaded tree
17196 height = Math.ceil(Math.log(N) / Math.log(M));
17198 // target number of root entries to maximize storage utilization
17199 M = Math.ceil(N / Math.pow(M, height - 1));
17209 // split the items into M mostly square tiles
17211 var N2 = Math.ceil(N / M),
17212 N1 = N2 * Math.ceil(Math.sqrt(M)),
17213 i, j, right2, right3;
17215 multiSelect(items, left, right, N1, this.compareMinX);
17217 for (i = left; i <= right; i += N1) {
17219 right2 = Math.min(i + N1 - 1, right);
17221 multiSelect(items, i, right2, N2, this.compareMinY);
17223 for (j = i; j <= right2; j += N2) {
17225 right3 = Math.min(j + N2 - 1, right2);
17227 // pack each entry recursively
17228 node.children.push(this._build(items, j, right3, height - 1));
17232 calcBBox(node, this.toBBox);
17237 _chooseSubtree: function (bbox, node, level, path) {
17239 var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
17244 if (node.leaf || path.length - 1 === level) break;
17246 minArea = minEnlargement = Infinity;
17248 for (i = 0, len = node.children.length; i < len; i++) {
17249 child = node.children[i];
17250 area = bboxArea(child.bbox);
17251 enlargement = enlargedArea(bbox, child.bbox) - area;
17253 // choose entry with the least area enlargement
17254 if (enlargement < minEnlargement) {
17255 minEnlargement = enlargement;
17256 minArea = area < minArea ? area : minArea;
17257 targetNode = child;
17259 } else if (enlargement === minEnlargement) {
17260 // otherwise choose one with the smallest area
17261 if (area < minArea) {
17263 targetNode = child;
17274 _insert: function (item, level, isNode) {
17276 var toBBox = this.toBBox,
17277 bbox = isNode ? item.bbox : toBBox(item),
17280 // find the best node for accommodating the item, saving all nodes along the path too
17281 var node = this._chooseSubtree(bbox, this.data, level, insertPath);
17283 // put the item into the node
17284 node.children.push(item);
17285 extend(node.bbox, bbox);
17287 // split on node overflow; propagate upwards if necessary
17288 while (level >= 0) {
17289 if (insertPath[level].children.length > this._maxEntries) {
17290 this._split(insertPath, level);
17295 // adjust bboxes along the insertion path
17296 this._adjustParentBBoxes(bbox, insertPath, level);
17299 // split overflowed node into two
17300 _split: function (insertPath, level) {
17302 var node = insertPath[level],
17303 M = node.children.length,
17304 m = this._minEntries;
17306 this._chooseSplitAxis(node, m, M);
17308 var splitIndex = this._chooseSplitIndex(node, m, M);
17311 children: node.children.splice(splitIndex, node.children.length - splitIndex),
17312 height: node.height,
17317 if (node.leaf) newNode.leaf = true;
17319 calcBBox(node, this.toBBox);
17320 calcBBox(newNode, this.toBBox);
17322 if (level) insertPath[level - 1].children.push(newNode);
17323 else this._splitRoot(node, newNode);
17326 _splitRoot: function (node, newNode) {
17329 children: [node, newNode],
17330 height: node.height + 1,
17334 calcBBox(this.data, this.toBBox);
17337 _chooseSplitIndex: function (node, m, M) {
17339 var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
17341 minOverlap = minArea = Infinity;
17343 for (i = m; i <= M - m; i++) {
17344 bbox1 = distBBox(node, 0, i, this.toBBox);
17345 bbox2 = distBBox(node, i, M, this.toBBox);
17347 overlap = intersectionArea(bbox1, bbox2);
17348 area = bboxArea(bbox1) + bboxArea(bbox2);
17350 // choose distribution with minimum overlap
17351 if (overlap < minOverlap) {
17352 minOverlap = overlap;
17355 minArea = area < minArea ? area : minArea;
17357 } else if (overlap === minOverlap) {
17358 // otherwise choose distribution with minimum area
17359 if (area < minArea) {
17369 // sorts node children by the best axis for split
17370 _chooseSplitAxis: function (node, m, M) {
17372 var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
17373 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
17374 xMargin = this._allDistMargin(node, m, M, compareMinX),
17375 yMargin = this._allDistMargin(node, m, M, compareMinY);
17377 // if total distributions margin value is minimal for x, sort by minX,
17378 // otherwise it's already sorted by minY
17379 if (xMargin < yMargin) node.children.sort(compareMinX);
17382 // total margin of all possible split distributions where each node is at least m full
17383 _allDistMargin: function (node, m, M, compare) {
17385 node.children.sort(compare);
17387 var toBBox = this.toBBox,
17388 leftBBox = distBBox(node, 0, m, toBBox),
17389 rightBBox = distBBox(node, M - m, M, toBBox),
17390 margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
17393 for (i = m; i < M - m; i++) {
17394 child = node.children[i];
17395 extend(leftBBox, node.leaf ? toBBox(child) : child.bbox);
17396 margin += bboxMargin(leftBBox);
17399 for (i = M - m - 1; i >= m; i--) {
17400 child = node.children[i];
17401 extend(rightBBox, node.leaf ? toBBox(child) : child.bbox);
17402 margin += bboxMargin(rightBBox);
17408 _adjustParentBBoxes: function (bbox, path, level) {
17409 // adjust bboxes along the given tree path
17410 for (var i = level; i >= 0; i--) {
17411 extend(path[i].bbox, bbox);
17415 _condense: function (path) {
17416 // go through the path, removing empty nodes and updating bboxes
17417 for (var i = path.length - 1, siblings; i >= 0; i--) {
17418 if (path[i].children.length === 0) {
17420 siblings = path[i - 1].children;
17421 siblings.splice(siblings.indexOf(path[i]), 1);
17423 } else this.clear();
17425 } else calcBBox(path[i], this.toBBox);
17429 _initFormat: function (format) {
17430 // data format (minX, minY, maxX, maxY accessors)
17432 // uses eval-type function compilation instead of just accepting a toBBox function
17433 // because the algorithms are very sensitive to sorting functions performance,
17434 // so they should be dead simple and without inner calls
17436 // jshint evil: true
17438 var compareArr = ['return a', ' - b', ';'];
17440 this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
17441 this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
17443 this.toBBox = new Function('a', 'return [a' + format.join(', a') + '];');
17448 // calculate node's bbox from bboxes of its children
17449 function calcBBox(node, toBBox) {
17450 node.bbox = distBBox(node, 0, node.children.length, toBBox);
17453 // min bounding rectangle of node children from k to p-1
17454 function distBBox(node, k, p, toBBox) {
17455 var bbox = empty();
17457 for (var i = k, child; i < p; i++) {
17458 child = node.children[i];
17459 extend(bbox, node.leaf ? toBBox(child) : child.bbox);
17465 function empty() { return [Infinity, Infinity, -Infinity, -Infinity]; }
17467 function extend(a, b) {
17468 a[0] = Math.min(a[0], b[0]);
17469 a[1] = Math.min(a[1], b[1]);
17470 a[2] = Math.max(a[2], b[2]);
17471 a[3] = Math.max(a[3], b[3]);
17475 function compareNodeMinX(a, b) { return a.bbox[0] - b.bbox[0]; }
17476 function compareNodeMinY(a, b) { return a.bbox[1] - b.bbox[1]; }
17478 function bboxArea(a) { return (a[2] - a[0]) * (a[3] - a[1]); }
17479 function bboxMargin(a) { return (a[2] - a[0]) + (a[3] - a[1]); }
17481 function enlargedArea(a, b) {
17482 return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) *
17483 (Math.max(b[3], a[3]) - Math.min(b[1], a[1]));
17486 function intersectionArea(a, b) {
17487 var minX = Math.max(a[0], b[0]),
17488 minY = Math.max(a[1], b[1]),
17489 maxX = Math.min(a[2], b[2]),
17490 maxY = Math.min(a[3], b[3]);
17492 return Math.max(0, maxX - minX) *
17493 Math.max(0, maxY - minY);
17496 function contains(a, b) {
17497 return a[0] <= b[0] &&
17503 function intersects(a, b) {
17504 return b[0] <= a[2] &&
17510 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
17511 // combines selection algorithm with binary divide & conquer approach
17513 function multiSelect(arr, left, right, n, compare) {
17514 var stack = [left, right],
17517 while (stack.length) {
17518 right = stack.pop();
17519 left = stack.pop();
17521 if (right - left <= n) continue;
17523 mid = left + Math.ceil((right - left) / n / 2) * n;
17524 select(arr, left, right, mid, compare);
17526 stack.push(left, mid, mid, right);
17530 // Floyd-Rivest selection algorithm:
17531 // sort an array between left and right (inclusive) so that the smallest k elements come first (unordered)
17532 function select(arr, left, right, k, compare) {
17533 var n, i, z, s, sd, newLeft, newRight, t, j;
17535 while (right > left) {
17536 if (right - left > 600) {
17537 n = right - left + 1;
17540 s = 0.5 * Math.exp(2 * z / 3);
17541 sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (i - n / 2 < 0 ? -1 : 1);
17542 newLeft = Math.max(left, Math.floor(k - i * s / n + sd));
17543 newRight = Math.min(right, Math.floor(k + (n - i) * s / n + sd));
17544 select(arr, newLeft, newRight, k, compare);
17551 swap(arr, left, k);
17552 if (compare(arr[right], t) > 0) swap(arr, left, right);
17558 while (compare(arr[i], t) < 0) i++;
17559 while (compare(arr[j], t) > 0) j--;
17562 if (compare(arr[left], t) === 0) swap(arr, left, j);
17565 swap(arr, j, right);
17568 if (j <= k) left = j + 1;
17569 if (k <= j) right = j - 1;
17573 function swap(arr, i, j) {
17580 // export as AMD/CommonJS module or global variable
17581 if (typeof define === 'function' && define.amd) define('rbush', function () { return rbush; });
17582 else if (typeof module !== 'undefined') module.exports = rbush;
17583 else if (typeof self !== 'undefined') self.rbush = rbush;
17584 else window.rbush = rbush;
17587 (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;
17588 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){
17589 module.exports = element;
17590 module.exports.pair = pair;
17591 module.exports.format = format;
17592 module.exports.formatPair = formatPair;
17594 function element(x, dims) {
17595 return search(x, dims).val;
17598 function formatPair(x) {
17599 return format(x.lat, 'lat') + ' ' + format(x.lon, 'lon');
17602 // Is 0 North or South?
17603 function format(x, dim) {
17608 dir = dirs[x >= 0 ? 0 : 1],
17610 whole = Math.floor(abs),
17611 fraction = abs - whole,
17612 fractionMinutes = fraction * 60,
17613 minutes = Math.floor(fractionMinutes),
17614 seconds = Math.floor((fractionMinutes - minutes) * 60);
17616 return whole + '° ' +
17617 (minutes ? minutes + "' " : '') +
17618 (seconds ? seconds + '" ' : '') + dir;
17621 function search(x, dims, r) {
17622 if (!dims) dims = 'NSEW';
17623 if (typeof x !== 'string') return { val: null, regex: r };
17624 r = r || /[\s\,]*([\-|\—|\―]?[0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/gi;
17626 if (!m) return { val: null, regex: r };
17627 else if (m[4] && dims.indexOf(m[4]) === -1) return { val: null, regex: r };
17629 val: (((m[1]) ? parseFloat(m[1]) : 0) +
17630 ((m[2] ? parseFloat(m[2]) / 60 : 0)) +
17631 ((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
17632 ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1),
17639 function pair(x, dims) {
17641 var one = search(x, dims);
17642 if (one.val === null) return null;
17643 var two = search(x, dims, one.regex);
17644 if (two.val === null) return null;
17645 // null if one/two are not contiguous.
17646 if (one.raw + two.raw !== x) return null;
17647 if (one.dim) return swapdim(one.val, two.val, one.dim);
17648 else return [one.val, two.val];
17651 function swapdim(a, b, dim) {
17652 if (dim == 'N' || dim == 'S') return [a, b];
17653 if (dim == 'W' || dim == 'E') return [b, a];
17659 ;toGeoJSON = (function() {
17662 var removeSpace = (/\s*/g),
17663 trimSpace = (/^\s*|\s*$/g),
17664 splitSpace = (/\s+/);
17665 // generate a short, numeric hash of a string
17666 function okhash(x) {
17667 if (!x || !x.length) return 0;
17668 for (var i = 0, h = 0; i < x.length; i++) {
17669 h = ((h << 5) - h) + x.charCodeAt(i) | 0;
17672 // all Y children of X
17673 function get(x, y) { return x.getElementsByTagName(y); }
17674 function attr(x, y) { return x.getAttribute(y); }
17675 function attrf(x, y) { return parseFloat(attr(x, y)); }
17676 // one Y child of X, if any, otherwise null
17677 function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
17678 // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
17679 function norm(el) { if (el.normalize) { el.normalize(); } return el; }
17680 // cast array x into numbers
17681 function numarray(x) {
17682 for (var j = 0, o = []; j < x.length; j++) o[j] = parseFloat(x[j]);
17685 function clean(x) {
17687 for (var i in x) if (x[i]) o[i] = x[i];
17690 // get the content of a text node, if any
17691 function nodeVal(x) { if (x) {norm(x);} return x && x.firstChild && x.firstChild.nodeValue; }
17692 // get one coordinate from a coordinate array, if any
17693 function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
17694 // get all coordinates from a coordinate array as [[],[]]
17695 function coord(v) {
17696 var coords = v.replace(trimSpace, '').split(splitSpace),
17698 for (var i = 0; i < coords.length; i++) {
17699 o.push(coord1(coords[i]));
17703 function coordPair(x) { return [attrf(x, 'lon'), attrf(x, 'lat')]; }
17705 // create a new feature collection parent object
17708 type: 'FeatureCollection',
17713 var styleSupport = false;
17714 if (typeof XMLSerializer !== 'undefined') {
17715 var serializer = new XMLSerializer();
17716 styleSupport = true;
17718 function xml2str(str) { return serializer.serializeToString(str); }
17721 kml: function(doc, o) {
17725 // styleindex keeps track of hashed styles in order to match features
17727 // atomic geospatial types supported by KML - MultiGeometry is
17728 // handled separately
17729 geotypes = ['Polygon', 'LineString', 'Point', 'Track'],
17730 // all root placemarks in the file
17731 placemarks = get(doc, 'Placemark'),
17732 styles = get(doc, 'Style');
17734 if (styleSupport) for (var k = 0; k < styles.length; k++) {
17735 styleIndex['#' + attr(styles[k], 'id')] = okhash(xml2str(styles[k])).toString(16);
17737 for (var j = 0; j < placemarks.length; j++) {
17738 gj.features = gj.features.concat(getPlacemark(placemarks[j]));
17740 function gxCoord(v) { return numarray(v.split(' ')); }
17741 function gxCoords(root) {
17742 var elems = get(root, 'coord', 'gx'), coords = [];
17743 for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
17746 function getGeometry(root) {
17747 var geomNode, geomNodes, i, j, k, geoms = [];
17748 if (get1(root, 'MultiGeometry')) return getGeometry(get1(root, 'MultiGeometry'));
17749 if (get1(root, 'MultiTrack')) return getGeometry(get1(root, 'MultiTrack'));
17750 for (i = 0; i < geotypes.length; i++) {
17751 geomNodes = get(root, geotypes[i]);
17753 for (j = 0; j < geomNodes.length; j++) {
17754 geomNode = geomNodes[j];
17755 if (geotypes[i] == 'Point') {
17758 coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
17760 } else if (geotypes[i] == 'LineString') {
17762 type: 'LineString',
17763 coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
17765 } else if (geotypes[i] == 'Polygon') {
17766 var rings = get(geomNode, 'LinearRing'),
17768 for (k = 0; k < rings.length; k++) {
17769 coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
17773 coordinates: coords
17775 } else if (geotypes[i] == 'Track') {
17777 type: 'LineString',
17778 coordinates: gxCoords(geomNode)
17786 function getPlacemark(root) {
17787 var geoms = getGeometry(root), i, properties = {},
17788 name = nodeVal(get1(root, 'name')),
17789 styleUrl = nodeVal(get1(root, 'styleUrl')),
17790 description = nodeVal(get1(root, 'description')),
17791 extendedData = get1(root, 'ExtendedData');
17793 if (!geoms.length) return [];
17794 if (name) properties.name = name;
17795 if (styleUrl && styleIndex[styleUrl]) {
17796 properties.styleUrl = styleUrl;
17797 properties.styleHash = styleIndex[styleUrl];
17799 if (description) properties.description = description;
17800 if (extendedData) {
17801 var datas = get(extendedData, 'Data'),
17802 simpleDatas = get(extendedData, 'SimpleData');
17804 for (i = 0; i < datas.length; i++) {
17805 properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
17807 for (i = 0; i < simpleDatas.length; i++) {
17808 properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
17813 geometry: (geoms.length === 1) ? geoms[0] : {
17814 type: 'GeometryCollection',
17817 properties: properties
17822 gpx: function(doc, o) {
17824 tracks = get(doc, 'trk'),
17825 routes = get(doc, 'rte'),
17826 waypoints = get(doc, 'wpt'),
17827 // a feature collection
17829 for (i = 0; i < tracks.length; i++) {
17830 gj.features.push(getLinestring(tracks[i], 'trkpt'));
17832 for (i = 0; i < routes.length; i++) {
17833 gj.features.push(getLinestring(routes[i], 'rtept'));
17835 for (i = 0; i < waypoints.length; i++) {
17836 gj.features.push(getPoint(waypoints[i]));
17838 function getLinestring(node, pointname) {
17839 var j, pts = get(node, pointname), line = [];
17840 for (j = 0; j < pts.length; j++) {
17841 line.push(coordPair(pts[j]));
17845 properties: getProperties(node),
17847 type: 'LineString',
17852 function getPoint(node) {
17853 var prop = getProperties(node);
17854 prop.ele = nodeVal(get1(node, 'ele'));
17855 prop.sym = nodeVal(get1(node, 'sym'));
17861 coordinates: coordPair(node)
17865 function getProperties(node) {
17866 var meta = ['name', 'desc', 'author', 'copyright', 'link',
17867 'time', 'keywords'],
17870 for (k = 0; k < meta.length; k++) {
17871 prop[meta[k]] = nodeVal(get1(node, meta[k]));
17873 return clean(prop);
17881 if (typeof module !== 'undefined') module.exports = toGeoJSON;
17883 * marked - a markdown parser
17884 * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
17885 * https://github.com/chjj/marked
17891 * Block-Level Grammar
17896 code: /^( {4}[^\n]+\n*)+/,
17898 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17899 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17901 lheading: /^([^\n]+)\n *(=|-){3,} *\n*/,
17902 blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
17903 list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17904 html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
17905 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17907 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17911 block.bullet = /(?:[*+-]|\d+\.)/;
17912 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17913 block.item = replace(block.item, 'gm')
17914 (/bull/g, block.bullet)
17917 block.list = replace(block.list)
17918 (/bull/g, block.bullet)
17919 ('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
17922 block._tag = '(?!(?:'
17923 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17924 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17925 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
17927 block.html = replace(block.html)
17928 ('comment', /<!--[\s\S]*?-->/)
17929 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17930 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17931 (/tag/g, block._tag)
17934 block.paragraph = replace(block.paragraph)
17936 ('heading', block.heading)
17937 ('lheading', block.lheading)
17938 ('blockquote', block.blockquote)
17939 ('tag', '<' + block._tag)
17944 * Normal Block Grammar
17947 block.normal = merge({}, block);
17950 * GFM Block Grammar
17953 block.gfm = merge({}, block.normal, {
17954 fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
17958 block.gfm.paragraph = replace(block.paragraph)
17959 ('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|')
17963 * GFM + Tables Block Grammar
17966 block.tables = merge({}, block.gfm, {
17967 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17968 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17975 function Lexer(options) {
17977 this.tokens.links = {};
17978 this.options = options || marked.defaults;
17979 this.rules = block.normal;
17981 if (this.options.gfm) {
17982 if (this.options.tables) {
17983 this.rules = block.tables;
17985 this.rules = block.gfm;
17991 * Expose Block Rules
17994 Lexer.rules = block;
17997 * Static Lex Method
18000 Lexer.lex = function(src, options) {
18001 var lexer = new Lexer(options);
18002 return lexer.lex(src);
18009 Lexer.prototype.lex = function(src) {
18011 .replace(/\r\n|\r/g, '\n')
18012 .replace(/\t/g, ' ')
18013 .replace(/\u00a0/g, ' ')
18014 .replace(/\u2424/g, '\n');
18016 return this.token(src, true);
18023 Lexer.prototype.token = function(src, top) {
18024 var src = src.replace(/^ +$/gm, '')
18037 if (cap = this.rules.newline.exec(src)) {
18038 src = src.substring(cap[0].length);
18039 if (cap[0].length > 1) {
18047 if (cap = this.rules.code.exec(src)) {
18048 src = src.substring(cap[0].length);
18049 cap = cap[0].replace(/^ {4}/gm, '');
18052 text: !this.options.pedantic
18053 ? cap.replace(/\n+$/, '')
18060 if (cap = this.rules.fences.exec(src)) {
18061 src = src.substring(cap[0].length);
18071 if (cap = this.rules.heading.exec(src)) {
18072 src = src.substring(cap[0].length);
18075 depth: cap[1].length,
18081 // table no leading pipe (gfm)
18082 if (top && (cap = this.rules.nptable.exec(src))) {
18083 src = src.substring(cap[0].length);
18087 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18088 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18089 cells: cap[3].replace(/\n$/, '').split('\n')
18092 for (i = 0; i < item.align.length; i++) {
18093 if (/^ *-+: *$/.test(item.align[i])) {
18094 item.align[i] = 'right';
18095 } else if (/^ *:-+: *$/.test(item.align[i])) {
18096 item.align[i] = 'center';
18097 } else if (/^ *:-+ *$/.test(item.align[i])) {
18098 item.align[i] = 'left';
18100 item.align[i] = null;
18104 for (i = 0; i < item.cells.length; i++) {
18105 item.cells[i] = item.cells[i].split(/ *\| */);
18108 this.tokens.push(item);
18114 if (cap = this.rules.lheading.exec(src)) {
18115 src = src.substring(cap[0].length);
18118 depth: cap[2] === '=' ? 1 : 2,
18125 if (cap = this.rules.hr.exec(src)) {
18126 src = src.substring(cap[0].length);
18134 if (cap = this.rules.blockquote.exec(src)) {
18135 src = src.substring(cap[0].length);
18138 type: 'blockquote_start'
18141 cap = cap[0].replace(/^ *> ?/gm, '');
18143 // Pass `top` to keep the current
18144 // "toplevel" state. This is exactly
18145 // how markdown.pl works.
18146 this.token(cap, top);
18149 type: 'blockquote_end'
18156 if (cap = this.rules.list.exec(src)) {
18157 src = src.substring(cap[0].length);
18161 type: 'list_start',
18162 ordered: bull.length > 1
18165 // Get each top-level item.
18166 cap = cap[0].match(this.rules.item);
18172 for (; i < l; i++) {
18175 // Remove the list item's bullet
18176 // so it is seen as the next token.
18177 space = item.length;
18178 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18180 // Outdent whatever the
18181 // list item contains. Hacky.
18182 if (~item.indexOf('\n ')) {
18183 space -= item.length;
18184 item = !this.options.pedantic
18185 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18186 : item.replace(/^ {1,4}/gm, '');
18189 // Determine whether the next list item belongs here.
18190 // Backpedal if it does not belong in this list.
18191 if (this.options.smartLists && i !== l - 1) {
18192 b = block.bullet.exec(cap[i+1])[0];
18193 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18194 src = cap.slice(i + 1).join('\n') + src;
18199 // Determine whether item is loose or not.
18200 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18201 // for discount behavior.
18202 loose = next || /\n\n(?!\s*$)/.test(item);
18204 next = item[item.length-1] === '\n';
18205 if (!loose) loose = next;
18210 ? 'loose_item_start'
18211 : 'list_item_start'
18215 this.token(item, false);
18218 type: 'list_item_end'
18230 if (cap = this.rules.html.exec(src)) {
18231 src = src.substring(cap[0].length);
18233 type: this.options.sanitize
18236 pre: cap[1] === 'pre' || cap[1] === 'script',
18243 if (top && (cap = this.rules.def.exec(src))) {
18244 src = src.substring(cap[0].length);
18245 this.tokens.links[cap[1].toLowerCase()] = {
18253 if (top && (cap = this.rules.table.exec(src))) {
18254 src = src.substring(cap[0].length);
18258 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18259 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18260 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18263 for (i = 0; i < item.align.length; i++) {
18264 if (/^ *-+: *$/.test(item.align[i])) {
18265 item.align[i] = 'right';
18266 } else if (/^ *:-+: *$/.test(item.align[i])) {
18267 item.align[i] = 'center';
18268 } else if (/^ *:-+ *$/.test(item.align[i])) {
18269 item.align[i] = 'left';
18271 item.align[i] = null;
18275 for (i = 0; i < item.cells.length; i++) {
18276 item.cells[i] = item.cells[i]
18277 .replace(/^ *\| *| *\| *$/g, '')
18281 this.tokens.push(item);
18286 // top-level paragraph
18287 if (top && (cap = this.rules.paragraph.exec(src))) {
18288 src = src.substring(cap[0].length);
18291 text: cap[1][cap[1].length-1] === '\n'
18292 ? cap[1].slice(0, -1)
18299 if (cap = this.rules.text.exec(src)) {
18300 // Top-level should never reach here.
18301 src = src.substring(cap[0].length);
18311 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18315 return this.tokens;
18319 * Inline-Level Grammar
18323 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18324 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18326 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18327 link: /^!?\[(inside)\]\(href\)/,
18328 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18329 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18330 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18331 em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18332 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18333 br: /^ {2,}\n(?!\s*$)/,
18335 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18338 inline._inside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
18339 inline._href = /\s*<?([^\s]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18341 inline.link = replace(inline.link)
18342 ('inside', inline._inside)
18343 ('href', inline._href)
18346 inline.reflink = replace(inline.reflink)
18347 ('inside', inline._inside)
18351 * Normal Inline Grammar
18354 inline.normal = merge({}, inline);
18357 * Pedantic Inline Grammar
18360 inline.pedantic = merge({}, inline.normal, {
18361 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18362 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18366 * GFM Inline Grammar
18369 inline.gfm = merge({}, inline.normal, {
18370 escape: replace(inline.escape)('])', '~|])')(),
18371 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18372 del: /^~~(?=\S)([\s\S]*?\S)~~/,
18373 text: replace(inline.text)
18375 ('|', '|https?://|')
18380 * GFM + Line Breaks Inline Grammar
18383 inline.breaks = merge({}, inline.gfm, {
18384 br: replace(inline.br)('{2,}', '*')(),
18385 text: replace(inline.gfm.text)('{2,}', '*')()
18389 * Inline Lexer & Compiler
18392 function InlineLexer(links, options) {
18393 this.options = options || marked.defaults;
18394 this.links = links;
18395 this.rules = inline.normal;
18399 Error('Tokens array requires a `links` property.');
18402 if (this.options.gfm) {
18403 if (this.options.breaks) {
18404 this.rules = inline.breaks;
18406 this.rules = inline.gfm;
18408 } else if (this.options.pedantic) {
18409 this.rules = inline.pedantic;
18414 * Expose Inline Rules
18417 InlineLexer.rules = inline;
18420 * Static Lexing/Compiling Method
18423 InlineLexer.output = function(src, links, options) {
18424 var inline = new InlineLexer(links, options);
18425 return inline.output(src);
18432 InlineLexer.prototype.output = function(src) {
18441 if (cap = this.rules.escape.exec(src)) {
18442 src = src.substring(cap[0].length);
18448 if (cap = this.rules.autolink.exec(src)) {
18449 src = src.substring(cap[0].length);
18450 if (cap[2] === '@') {
18451 text = cap[1][6] === ':'
18452 ? this.mangle(cap[1].substring(7))
18453 : this.mangle(cap[1]);
18454 href = this.mangle('mailto:') + text;
18456 text = escape(cap[1]);
18468 if (cap = this.rules.url.exec(src)) {
18469 src = src.substring(cap[0].length);
18470 text = escape(cap[1]);
18481 if (cap = this.rules.tag.exec(src)) {
18482 src = src.substring(cap[0].length);
18483 out += this.options.sanitize
18490 if (cap = this.rules.link.exec(src)) {
18491 src = src.substring(cap[0].length);
18492 out += this.outputLink(cap, {
18500 if ((cap = this.rules.reflink.exec(src))
18501 || (cap = this.rules.nolink.exec(src))) {
18502 src = src.substring(cap[0].length);
18503 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18504 link = this.links[link.toLowerCase()];
18505 if (!link || !link.href) {
18507 src = cap[0].substring(1) + src;
18510 out += this.outputLink(cap, link);
18515 if (cap = this.rules.strong.exec(src)) {
18516 src = src.substring(cap[0].length);
18518 + this.output(cap[2] || cap[1])
18524 if (cap = this.rules.em.exec(src)) {
18525 src = src.substring(cap[0].length);
18527 + this.output(cap[2] || cap[1])
18533 if (cap = this.rules.code.exec(src)) {
18534 src = src.substring(cap[0].length);
18536 + escape(cap[2], true)
18542 if (cap = this.rules.br.exec(src)) {
18543 src = src.substring(cap[0].length);
18549 if (cap = this.rules.del.exec(src)) {
18550 src = src.substring(cap[0].length);
18552 + this.output(cap[1])
18558 if (cap = this.rules.text.exec(src)) {
18559 src = src.substring(cap[0].length);
18560 out += escape(cap[0]);
18566 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18577 InlineLexer.prototype.outputLink = function(cap, link) {
18578 if (cap[0][0] !== '!') {
18580 + escape(link.href)
18584 + escape(link.title)
18588 + this.output(cap[1])
18591 return '<img src="'
18592 + escape(link.href)
18598 + escape(link.title)
18606 * Smartypants Transformations
18609 InlineLexer.prototype.smartypants = function(text) {
18610 if (!this.options.smartypants) return text;
18612 .replace(/--/g, '—')
18613 .replace(/'([^']*)'/g, '‘$1’')
18614 .replace(/"([^"]*)"/g, '“$1”')
18615 .replace(/\.{3}/g, '…');
18622 InlineLexer.prototype.mangle = function(text) {
18628 for (; i < l; i++) {
18629 ch = text.charCodeAt(i);
18630 if (Math.random() > 0.5) {
18631 ch = 'x' + ch.toString(16);
18633 out += '&#' + ch + ';';
18640 * Parsing & Compiling
18643 function Parser(options) {
18646 this.options = options || marked.defaults;
18650 * Static Parse Method
18653 Parser.parse = function(src, options) {
18654 var parser = new Parser(options);
18655 return parser.parse(src);
18662 Parser.prototype.parse = function(src) {
18663 this.inline = new InlineLexer(src.links, this.options);
18664 this.tokens = src.reverse();
18667 while (this.next()) {
18678 Parser.prototype.next = function() {
18679 return this.token = this.tokens.pop();
18683 * Preview Next Token
18686 Parser.prototype.peek = function() {
18687 return this.tokens[this.tokens.length-1] || 0;
18691 * Parse Text Tokens
18694 Parser.prototype.parseText = function() {
18695 var body = this.token.text;
18697 while (this.peek().type === 'text') {
18698 body += '\n' + this.next().text;
18701 return this.inline.output(body);
18705 * Parse Current Token
18708 Parser.prototype.tok = function() {
18709 switch (this.token.type) {
18720 + this.inline.output(this.token.text)
18726 if (this.options.highlight) {
18727 var code = this.options.highlight(this.token.text, this.token.lang);
18728 if (code != null && code !== this.token.text) {
18729 this.token.escaped = true;
18730 this.token.text = code;
18734 if (!this.token.escaped) {
18735 this.token.text = escape(this.token.text, true);
18738 return '<pre><code'
18741 + this.options.langPrefix
18747 + '</code></pre>\n';
18758 body += '<thead>\n<tr>\n';
18759 for (i = 0; i < this.token.header.length; i++) {
18760 heading = this.inline.output(this.token.header[i]);
18761 body += this.token.align[i]
18762 ? '<th align="' + this.token.align[i] + '">' + heading + '</th>\n'
18763 : '<th>' + heading + '</th>\n';
18765 body += '</tr>\n</thead>\n';
18768 body += '<tbody>\n'
18769 for (i = 0; i < this.token.cells.length; i++) {
18770 row = this.token.cells[i];
18772 for (j = 0; j < row.length; j++) {
18773 cell = this.inline.output(row[j]);
18774 body += this.token.align[j]
18775 ? '<td align="' + this.token.align[j] + '">' + cell + '</td>\n'
18776 : '<td>' + cell + '</td>\n';
18780 body += '</tbody>\n';
18786 case 'blockquote_start': {
18789 while (this.next().type !== 'blockquote_end') {
18790 body += this.tok();
18793 return '<blockquote>\n'
18795 + '</blockquote>\n';
18797 case 'list_start': {
18798 var type = this.token.ordered ? 'ol' : 'ul'
18801 while (this.next().type !== 'list_end') {
18802 body += this.tok();
18813 case 'list_item_start': {
18816 while (this.next().type !== 'list_item_end') {
18817 body += this.token.type === 'text'
18826 case 'loose_item_start': {
18829 while (this.next().type !== 'list_item_end') {
18830 body += this.tok();
18838 return !this.token.pre && !this.options.pedantic
18839 ? this.inline.output(this.token.text)
18842 case 'paragraph': {
18844 + this.inline.output(this.token.text)
18859 function escape(html, encode) {
18861 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
18862 .replace(/</g, '<')
18863 .replace(/>/g, '>')
18864 .replace(/"/g, '"')
18865 .replace(/'/g, ''');
18868 function replace(regex, opt) {
18869 regex = regex.source;
18871 return function self(name, val) {
18872 if (!name) return new RegExp(regex, opt);
18873 val = val.source || val;
18874 val = val.replace(/(^|[^\[])\^/g, '$1');
18875 regex = regex.replace(name, val);
18883 function merge(obj) {
18888 for (; i < arguments.length; i++) {
18889 target = arguments[i];
18890 for (key in target) {
18891 if (Object.prototype.hasOwnProperty.call(target, key)) {
18892 obj[key] = target[key];
18904 function marked(src, opt, callback) {
18905 if (callback || typeof opt === 'function') {
18911 if (opt) opt = merge({}, marked.defaults, opt);
18913 var tokens = Lexer.lex(tokens, opt)
18914 , highlight = opt.highlight
18916 , l = tokens.length
18919 if (!highlight || highlight.length < 3) {
18920 return callback(null, Parser.parse(tokens, opt));
18923 var done = function() {
18924 delete opt.highlight;
18925 var out = Parser.parse(tokens, opt);
18926 opt.highlight = highlight;
18927 return callback(null, out);
18930 for (; i < l; i++) {
18932 if (token.type !== 'code') return;
18934 return highlight(token.text, token.lang, function(err, code) {
18935 if (code == null || code === token.text) {
18936 return --pending || done();
18939 token.escaped = true;
18940 --pending || done();
18948 if (opt) opt = merge({}, marked.defaults, opt);
18949 return Parser.parse(Lexer.lex(src, opt), opt);
18951 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18952 if ((opt || marked.defaults).silent) {
18953 return '<p>An error occured:</p><pre>'
18954 + escape(e.message + '', true)
18966 marked.setOptions = function(opt) {
18967 merge(marked.defaults, opt);
18971 marked.defaults = {
18980 langPrefix: 'lang-'
18987 marked.Parser = Parser;
18988 marked.parser = Parser.parse;
18990 marked.Lexer = Lexer;
18991 marked.lexer = Lexer.lex;
18993 marked.InlineLexer = InlineLexer;
18994 marked.inlineLexer = InlineLexer.output;
18996 marked.parse = marked;
18998 if (typeof exports === 'object') {
18999 module.exports = marked;
19000 } else if (typeof define === 'function' && define.amd) {
19001 define(function() { return marked; });
19003 this.marked = marked;
19006 }).call(function() {
19007 return this || (typeof window !== 'undefined' ? window : global);
19011 window.iD = function () {
19012 window.locale.en = iD.data.en;
19013 window.locale.current('en');
19015 var dispatch = d3.dispatch('enter', 'exit'),
19018 // https://github.com/openstreetmap/iD/issues/772
19019 // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
19021 try { storage = localStorage; } catch (e) {} // eslint-disable-line no-empty
19022 storage = storage || (function() {
19025 getItem: function(k) { return s[k]; },
19026 setItem: function(k, v) { s[k] = v; },
19027 removeItem: function(k) { delete s[k]; }
19031 context.storage = function(k, v) {
19033 if (arguments.length === 1) return storage.getItem(k);
19034 else if (v === null) storage.removeItem(k);
19035 else storage.setItem(k, v);
19037 // localstorage quota exceeded
19038 /* eslint-disable no-console */
19039 if (typeof console !== 'undefined') console.error('localStorage quota exceeded');
19040 /* eslint-enable no-console */
19045 /* Straight accessors. Avoid using these if you can. */
19046 var ui, connection, history;
19047 context.ui = function() { return ui; };
19048 context.connection = function() { return connection; };
19049 context.history = function() { return history; };
19053 function entitiesLoaded(err, result) {
19054 if (!err) history.merge(result.data, result.extent);
19057 context.preauth = function(options) {
19058 connection.switch(options);
19062 context.loadTiles = function(projection, dimensions, callback) {
19063 function done(err, result) {
19064 entitiesLoaded(err, result);
19065 if (callback) callback(err, result);
19067 connection.loadTiles(projection, dimensions, done);
19070 context.loadEntity = function(id, callback) {
19071 function done(err, result) {
19072 entitiesLoaded(err, result);
19073 if (callback) callback(err, result);
19075 connection.loadEntity(id, done);
19078 context.zoomToEntity = function(id, zoomTo) {
19079 if (zoomTo !== false) {
19080 this.loadEntity(id, function(err, result) {
19082 var entity = _.find(result.data, function(e) { return e.id === id; });
19083 if (entity) { map.zoomTo(entity); }
19087 map.on('drawn.zoomToEntity', function() {
19088 if (!context.hasEntity(id)) return;
19089 map.on('drawn.zoomToEntity', null);
19090 context.on('enter.zoomToEntity', null);
19091 context.enter(iD.modes.Select(context, [id]));
19094 context.on('enter.zoomToEntity', function() {
19095 if (mode.id !== 'browse') {
19096 map.on('drawn.zoomToEntity', null);
19097 context.on('enter.zoomToEntity', null);
19102 var minEditableZoom = 16;
19103 context.minEditableZoom = function(_) {
19104 if (!arguments.length) return minEditableZoom;
19105 minEditableZoom = _;
19106 connection.tileZoom(_);
19112 var inIntro = false;
19113 context.inIntro = function(_) {
19114 if (!arguments.length) return inIntro;
19119 context.save = function() {
19120 if (inIntro || (mode && mode.id === 'save') || d3.select('.modal').size()) return;
19122 if (history.hasChanges()) return t('save.unsaved_changes');
19125 context.flush = function() {
19126 context.debouncedSave.cancel();
19127 connection.flush();
19130 _.each(iD.services, function(service) {
19131 var reset = service().reset;
19132 if (reset) reset(context);
19139 context.hasEntity = function(id) {
19140 return history.graph().hasEntity(id);
19142 context.entity = function(id) {
19143 return history.graph().entity(id);
19145 context.childNodes = function(way) {
19146 return history.graph().childNodes(way);
19148 context.geometry = function(id) {
19149 return context.entity(id).geometry(history.graph());
19155 context.mode = function() {
19158 context.enter = function(newMode) {
19161 dispatch.exit(mode);
19166 dispatch.enter(mode);
19169 context.selectedIDs = function() {
19170 if (mode && mode.selectedIDs) {
19171 return mode.selectedIDs();
19179 context.install = function(behavior) {
19180 context.surface().call(behavior);
19182 context.uninstall = function(behavior) {
19183 context.surface().call(behavior.off);
19188 var copyIDs = [], copyGraph;
19189 context.copyGraph = function() { return copyGraph; };
19190 context.copyIDs = function(_) {
19191 if (!arguments.length) return copyIDs;
19193 copyGraph = history.graph();
19200 context.background = function() { return background; };
19205 context.features = function() { return features; };
19206 context.hasHiddenConnections = function(id) {
19207 var graph = history.graph(),
19208 entity = graph.entity(id);
19209 return features.hasHiddenConnections(entity, graph);
19215 context.map = function() { return map; };
19216 context.layers = function() { return map.layers; };
19217 context.surface = function() { return map.surface; };
19218 context.editable = function() { return map.editable(); };
19220 context.surfaceRect = function() {
19221 // Work around a bug in Firefox.
19222 // http://stackoverflow.com/questions/18153989/
19223 // https://bugzilla.mozilla.org/show_bug.cgi?id=530985
19224 return context.surface().node().parentNode.getBoundingClientRect();
19229 var debugTile = false, debugCollision = false;
19230 context.debugTile = function(_) {
19231 if (!arguments.length) return debugTile;
19235 context.debugCollision = function(_) {
19236 if (!arguments.length) return debugCollision;
19237 debugCollision = _;
19244 context.presets = function(_) {
19245 if (!arguments.length) return presets;
19247 iD.areaKeys = presets.areaKeys();
19253 context.imagery = function(_) {
19254 background.load(_);
19260 var container, embed;
19261 context.container = function(_) {
19262 if (!arguments.length) return container;
19264 container.classed('id-container', true);
19267 context.embed = function(_) {
19268 if (!arguments.length) return embed;
19276 context.taginfo = function(_) {
19277 if (!arguments.length) return taginfo;
19284 var assetPath = '';
19285 context.assetPath = function(_) {
19286 if (!arguments.length) return assetPath;
19292 context.assetMap = function(_) {
19293 if (!arguments.length) return assetMap;
19298 context.asset = function(_) {
19299 var filename = assetPath + _;
19300 return assetMap[filename] || filename;
19303 context.imagePath = function(_) {
19304 return context.asset('img/' + _);
19307 var locale, localePath;
19308 context.locale = function(loc, path) {
19312 // Also set iD.detect().locale (unless we detected 'en-us' and openstreetmap wants 'en')..
19313 if (!(loc.toLowerCase() === 'en' && iD.detect().locale.toLowerCase() === 'en-us')) {
19314 iD.detect().locale = loc;
19320 context.loadLocale = function(cb) {
19321 if (locale && locale !== 'en' && iD.data.locales.indexOf(locale) !== -1) {
19322 localePath = localePath || context.asset('locales/' + locale + '.json');
19323 d3.json(localePath, function(err, result) {
19324 window.locale[locale] = result;
19325 window.locale.current(locale);
19336 context.projection = iD.geo.RawMercator();
19338 locale = iD.detect().locale;
19339 if (locale && iD.data.locales.indexOf(locale) === -1) {
19340 locale = locale.split('-')[0];
19343 history = iD.History(context);
19344 context.graph = history.graph;
19345 context.changes = history.changes;
19346 context.intersects = history.intersects;
19348 // Debounce save, since it's a synchronous localStorage write,
19349 // and history changes can happen frequently (e.g. when dragging).
19350 context.debouncedSave = _.debounce(context.save, 350);
19351 function withDebouncedSave(fn) {
19352 return function() {
19353 var result = fn.apply(history, arguments);
19354 context.debouncedSave();
19359 context.perform = withDebouncedSave(history.perform);
19360 context.replace = withDebouncedSave(history.replace);
19361 context.pop = withDebouncedSave(history.pop);
19362 context.overwrite = withDebouncedSave(history.overwrite);
19363 context.undo = withDebouncedSave(history.undo);
19364 context.redo = withDebouncedSave(history.redo);
19366 ui = iD.ui(context);
19368 connection = iD.Connection();
19370 background = iD.Background(context);
19372 features = iD.Features(context);
19374 map = iD.Map(context);
19375 context.mouse = map.mouse;
19376 context.extent = map.extent;
19377 context.pan = map.pan;
19378 context.zoomIn = map.zoomIn;
19379 context.zoomOut = map.zoomOut;
19380 context.zoomInFurther = map.zoomInFurther;
19381 context.zoomOutFurther = map.zoomOutFurther;
19382 context.redrawEnable = map.redrawEnable;
19384 presets = iD.presets();
19386 return d3.rebind(context, dispatch, 'on');
19390 iD.version = '1.9.3';
19395 var ua = navigator.userAgent,
19398 m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
19400 detected.browser = m[1];
19401 detected.version = m[2];
19403 if (!detected.browser) {
19404 m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
19406 detected.browser = 'msie';
19407 detected.version = m[1];
19410 if (!detected.browser) {
19411 m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
19413 detected.browser = 'Opera';
19414 detected.version = m[2];
19417 if (!detected.browser) {
19418 m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
19420 detected.browser = m[1];
19421 detected.version = m[2];
19422 m = ua.match(/version\/([\.\d]+)/i);
19423 if (m !== null) detected.version = m[1];
19426 if (!detected.browser) {
19427 detected.browser = navigator.appName;
19428 detected.version = navigator.appVersion;
19431 // keep major.minor version only..
19432 detected.version = detected.version.split(/\W/).slice(0,2).join('.');
19434 if (detected.browser.toLowerCase() === 'msie') {
19435 detected.ie = true;
19436 detected.browser = 'Internet Explorer';
19437 detected.support = parseFloat(detected.version) >= 11;
19439 detected.ie = false;
19440 detected.support = true;
19443 // Added due to incomplete svg style support. See #715
19444 detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 );
19446 detected.locale = (navigator.languages && navigator.languages.length)
19447 ? navigator.languages[0] : (navigator.language || navigator.userLanguage || 'en-US');
19449 detected.filedrop = (window.FileReader && 'ondrop' in window);
19452 return navigator.userAgent.indexOf(x) !== -1;
19456 detected.os = 'win';
19457 detected.platform = 'Windows';
19459 else if (nav('Mac')) {
19460 detected.os = 'mac';
19461 detected.platform = 'Macintosh';
19463 else if (nav('X11') || nav('Linux')) {
19464 detected.os = 'linux';
19465 detected.platform = 'Linux';
19468 detected.os = 'win';
19469 detected.platform = 'Unknown';
19472 iD.detect = function() { return detected; };
19475 iD.services.mapillary = function() {
19476 var mapillary = {},
19477 dispatch = d3.dispatch('loadedImages', 'loadedSigns'),
19478 apibase = 'https://a.mapillary.com/v2/',
19479 urlImage = 'https://www.mapillary.com/map/im/',
19480 urlThumb = 'https://d1cuyjsrcm0gby.cloudfront.net/',
19481 clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi',
19486 function loadSignStyles(context) {
19487 d3.select('head').selectAll('#traffico')
19491 .attr('id', 'traffico')
19492 .attr('rel', 'stylesheet')
19493 .attr('href', context.asset('traffico/stylesheets/traffico.css'));
19496 function loadSignDefs(context) {
19497 if (!iD.services.mapillary.sign_defs) {
19498 iD.services.mapillary.sign_defs = {};
19499 _.each(['au', 'br', 'ca', 'de', 'us'], function(region) {
19500 d3.json(context.asset('traffico/string-maps/' + region + '-map.json'), function(err, data) {
19502 if (region === 'de') region = 'eu';
19503 iD.services.mapillary.sign_defs[region] = data;
19509 function abortRequest(i) {
19513 function nearNullIsland(x, y, z) {
19515 var center = Math.pow(2, z - 1),
19516 width = Math.pow(2, z - 6),
19517 min = center - (width / 2),
19518 max = center + (width / 2) - 1;
19519 return x >= min && x <= max && y >= min && y <= max;
19524 function getTiles(projection, dimensions) {
19525 var s = projection.scale() * 2 * Math.PI,
19526 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
19527 ts = 256 * Math.pow(2, z - tileZoom),
19529 s / 2 - projection.translate()[0],
19530 s / 2 - projection.translate()[1]];
19532 return d3.geo.tile()
19533 .scaleExtent([tileZoom, tileZoom])
19536 .translate(projection.translate())()
19537 .map(function(tile) {
19538 var x = tile[0] * ts - origin[0],
19539 y = tile[1] * ts - origin[1];
19542 id: tile.toString(),
19543 extent: iD.geo.Extent(
19544 projection.invert([x, y + ts]),
19545 projection.invert([x + ts, y]))
19551 function loadTiles(which, url, projection, dimensions) {
19552 var tiles = getTiles(projection, dimensions).filter(function(t) {
19553 var xyz = t.id.split(',');
19554 return !nearNullIsland(xyz[0], xyz[1], xyz[2]);
19557 _.filter(which.inflight, function(v, k) {
19558 var wanted = _.find(tiles, function(tile) { return k === (tile.id + ',0'); });
19559 if (!wanted) delete which.inflight[k];
19561 }).map(abortRequest);
19563 tiles.forEach(function(tile) {
19564 loadTilePage(which, url, tile, 0);
19568 function loadTilePage(which, url, tile, page) {
19569 var cache = iD.services.mapillary.cache[which],
19570 id = tile.id + ',' + String(page),
19571 rect = tile.extent.rectangle();
19573 if (cache.loaded[id] || cache.inflight[id]) return;
19575 cache.inflight[id] = d3.json(url +
19580 client_id: clientId,
19585 }), function(err, data) {
19586 cache.loaded[id] = true;
19587 delete cache.inflight[id];
19588 if (err || !data.features || !data.features.length) return;
19593 for (var i = 0; i < data.features.length; i++) {
19594 feature = data.features[i];
19595 loc = feature.geometry.coordinates;
19596 d = { key: feature.properties.key, loc: loc };
19597 if (which === 'images') d.ca = feature.properties.ca;
19598 if (which === 'signs') d.signs = feature.properties.rects;
19600 features.push([loc[0], loc[1], loc[0], loc[1], d]);
19603 cache.rtree.load(features);
19605 if (which === 'images') dispatch.loadedImages();
19606 if (which === 'signs') dispatch.loadedSigns();
19608 if (data.features.length === maxResults) {
19609 loadTilePage(which, url, tile, ++page);
19615 mapillary.loadImages = function(projection, dimensions) {
19616 var url = apibase + 'search/im/geojson?';
19617 loadTiles('images', url, projection, dimensions);
19620 mapillary.loadSigns = function(context, projection, dimensions) {
19621 var url = apibase + 'search/im/geojson/or?';
19622 loadSignStyles(context);
19623 loadSignDefs(context);
19624 loadTiles('signs', url, projection, dimensions);
19628 // partition viewport into `psize` x `psize` regions
19629 function partitionViewport(psize, projection, dimensions) {
19630 psize = psize || 16;
19631 var cols = d3.range(0, dimensions[0], psize),
19632 rows = d3.range(0, dimensions[1], psize),
19635 rows.forEach(function(y) {
19636 cols.forEach(function(x) {
19637 var min = [x, y + psize],
19638 max = [x + psize, y];
19640 iD.geo.Extent(projection.invert(min), projection.invert(max)));
19647 // no more than `limit` results per partition.
19648 function searchLimited(psize, limit, projection, dimensions, rtree) {
19649 limit = limit || 3;
19651 var partitions = partitionViewport(psize, projection, dimensions);
19652 return _.flatten(_.compact(_.map(partitions, function(extent) {
19653 return rtree.search(extent.rectangle())
19655 .map(function(d) { return d[4]; });
19659 mapillary.images = function(projection, dimensions) {
19660 var psize = 16, limit = 3;
19661 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.images.rtree);
19664 mapillary.signs = function(projection, dimensions) {
19665 var psize = 32, limit = 3;
19666 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.signs.rtree);
19669 mapillary.signsSupported = function() {
19670 var detected = iD.detect();
19671 return (!(detected.ie || detected.browser.toLowerCase() === 'safari'));
19674 mapillary.signHTML = function(d) {
19675 if (!iD.services.mapillary.sign_defs) return;
19677 var detectionPackage = d.signs[0].package,
19678 type = d.signs[0].type,
19679 country = detectionPackage.split('_')[1];
19680 return iD.services.mapillary.sign_defs[country][type];
19683 mapillary.showThumbnail = function(imageKey, position) {
19684 if (!imageKey) return;
19686 var positionClass = {
19687 'ar': (position !== 'left'),
19688 'al': (position === 'left')
19691 var thumbnail = d3.select('#content').selectAll('.mapillary-image')
19695 var enter = thumbnail.enter().append('div')
19696 .attr('class', 'mapillary-image ar');
19698 enter.append('button')
19699 .on('click', function () {
19700 mapillary.hideThumbnail();
19703 .call(iD.svg.Icon('#icon-close'));
19705 enter.append('img');
19708 .attr('class', 'link ar')
19709 .attr('target', '_blank')
19710 .call(iD.svg.Icon('#icon-out-link', 'inline'))
19712 .text(t('mapillary.view_on_mapillary'));
19715 thumbnail.selectAll('img')
19716 .attr('src', urlThumb + imageKey + '/thumb-320.jpg');
19718 var link = thumbnail.selectAll('a')
19719 .attr('href', urlImage + imageKey);
19722 thumbnail.classed(positionClass);
19723 link.classed(positionClass);
19729 .style('opacity', 1);
19732 mapillary.hideThumbnail = function() {
19733 if (iD.services.mapillary) {
19734 iD.services.mapillary.thumb = null;
19736 d3.select('#content').selectAll('.mapillary-image')
19739 .style('opacity', 0)
19743 mapillary.selectedThumbnail = function(d) {
19744 if (!iD.services.mapillary) return null;
19745 if (!arguments.length) return iD.services.mapillary.thumb;
19746 iD.services.mapillary.thumb = d;
19749 mapillary.reset = function() {
19750 var cache = iD.services.mapillary.cache;
19753 _.forEach(cache.images.inflight, abortRequest);
19754 _.forEach(cache.signs.inflight, abortRequest);
19757 iD.services.mapillary.cache = {
19758 images: { inflight: {}, loaded: {}, rtree: rbush() },
19759 signs: { inflight: {}, loaded: {}, rtree: rbush() }
19762 iD.services.mapillary.thumb = null;
19768 if (!iD.services.mapillary.cache) {
19772 return d3.rebind(mapillary, dispatch, 'on');
19774 iD.services.nominatim = function() {
19775 var nominatim = {},
19776 endpoint = 'https://nominatim.openstreetmap.org/reverse?';
19779 nominatim.countryCode = function(location, callback) {
19780 var cache = iD.services.nominatim.cache,
19781 countryCodes = cache.search([location[0], location[1], location[0], location[1]]);
19783 if (countryCodes.length > 0)
19784 return callback(null, countryCodes[0][4]);
19792 }), function(err, result) {
19794 return callback(err);
19795 else if (result && result.error)
19796 return callback(result.error);
19798 var extent = iD.geo.Extent(location).padByMeters(1000);
19800 cache.insert(extent.rectangle().concat(result.address.country_code));
19802 callback(null, result.address.country_code);
19806 nominatim.reset = function() {
19807 iD.services.nominatim.cache = rbush();
19812 if (!iD.services.nominatim.cache) {
19818 iD.services.taginfo = function() {
19820 endpoint = 'https://taginfo.openstreetmap.org/api/4/',
19822 point: 'count_nodes',
19823 vertex: 'count_nodes',
19824 area: 'count_ways',
19835 function sets(parameters, n, o) {
19836 if (parameters.geometry && o[parameters.geometry]) {
19837 parameters[n] = o[parameters.geometry];
19842 function setFilter(parameters) {
19843 return sets(parameters, 'filter', tag_filters);
19846 function setSort(parameters) {
19847 return sets(parameters, 'sortname', tag_sorts);
19850 function clean(parameters) {
19851 return _.omit(parameters, 'geometry', 'debounce');
19854 function popularKeys(parameters) {
19855 var pop_field = 'count_all';
19856 if (parameters.filter) pop_field = 'count_' + parameters.filter;
19857 return function(d) { return parseFloat(d[pop_field]) > 5000 || d.in_wiki; };
19860 function popularValues() {
19861 return function(d) { return parseFloat(d.fraction) > 0.01 || d.in_wiki; };
19864 function valKey(d) {
19871 function valKeyDescription(d) {
19874 title: d.description || d.value
19878 // sort keys with ':' lower than keys without ':'
19879 function sortKeys(a, b) {
19880 return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
19881 : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
19885 var debounced = _.debounce(d3.json, 100, true);
19887 function request(url, debounce, callback) {
19888 var cache = iD.services.taginfo.cache;
19891 callback(null, cache[url]);
19892 } else if (debounce) {
19893 debounced(url, done);
19895 d3.json(url, done);
19898 function done(err, data) {
19899 if (!err) cache[url] = data;
19900 callback(err, data);
19904 taginfo.keys = function(parameters, callback) {
19905 var debounce = parameters.debounce;
19906 parameters = clean(setSort(parameters));
19907 request(endpoint + 'keys/all?' +
19908 iD.util.qsString(_.extend({
19910 sortname: 'count_all',
19913 }, parameters)), debounce, function(err, d) {
19914 if (err) return callback(err);
19915 callback(null, d.data.filter(popularKeys(parameters)).sort(sortKeys).map(valKey));
19919 taginfo.values = function(parameters, callback) {
19920 var debounce = parameters.debounce;
19921 parameters = clean(setSort(setFilter(parameters)));
19922 request(endpoint + 'key/values?' +
19923 iD.util.qsString(_.extend({
19925 sortname: 'count_all',
19928 }, parameters)), debounce, function(err, d) {
19929 if (err) return callback(err);
19930 callback(null, d.data.filter(popularValues()).map(valKeyDescription), parameters);
19934 taginfo.docs = function(parameters, callback) {
19935 var debounce = parameters.debounce;
19936 parameters = clean(setSort(parameters));
19938 var path = 'key/wiki_pages?';
19939 if (parameters.value) path = 'tag/wiki_pages?';
19940 else if (parameters.rtype) path = 'relation/wiki_pages?';
19942 request(endpoint + path + iD.util.qsString(parameters), debounce, function(err, d) {
19943 if (err) return callback(err);
19944 callback(null, d.data);
19948 taginfo.endpoint = function(_) {
19949 if (!arguments.length) return endpoint;
19954 taginfo.reset = function() {
19955 iD.services.taginfo.cache = {};
19960 if (!iD.services.taginfo.cache) {
19966 iD.services.wikipedia = function() {
19968 endpoint = 'https://en.wikipedia.org/w/api.php?';
19970 wiki.search = function(lang, query, callback) {
19971 lang = lang || 'en';
19972 d3.jsonp(endpoint.replace('en', lang) +
19977 srinfo: 'suggestion',
19979 callback: '{callback}',
19981 }), function(data) {
19982 if (!data.query) return;
19983 callback(query, data.query.search.map(function(d) {
19989 wiki.suggestions = function(lang, query, callback) {
19990 lang = lang || 'en';
19991 d3.jsonp(endpoint.replace('en', lang) +
19993 action: 'opensearch',
19997 callback: '{callback}',
20000 callback(d[0], d[1]);
20004 wiki.translations = function(lang, title, callback) {
20005 d3.jsonp(endpoint.replace('en', lang) +
20010 callback: '{callback}',
20014 var list = d.query.pages[Object.keys(d.query.pages)[0]],
20016 if (list && list.langlinks) {
20017 list.langlinks.forEach(function(d) {
20018 translations[d.lang] = d['*'];
20020 callback(translations);
20029 iD.util.tagText = function(entity) {
20030 return d3.entries(entity.tags).map(function(e) {
20031 return e.key + '=' + e.value;
20035 iD.util.entitySelector = function(ids) {
20036 return ids.length ? '.' + ids.join(',.') : 'nothing';
20039 iD.util.entityOrMemberSelector = function(ids, graph) {
20040 var s = iD.util.entitySelector(ids);
20042 ids.forEach(function(id) {
20043 var entity = graph.hasEntity(id);
20044 if (entity && entity.type === 'relation') {
20045 entity.members.forEach(function(member) {
20046 s += ',.' + member.id;
20054 iD.util.displayName = function(entity) {
20055 var localeName = 'name:' + iD.detect().locale.toLowerCase().split('-')[0];
20056 return entity.tags[localeName] || entity.tags.name || entity.tags.ref;
20059 iD.util.displayType = function(id) {
20061 n: t('inspector.node'),
20062 w: t('inspector.way'),
20063 r: t('inspector.relation')
20067 iD.util.stringQs = function(str) {
20068 return str.split('&').reduce(function(obj, pair){
20069 var parts = pair.split('=');
20070 if (parts.length === 2) {
20071 obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
20077 iD.util.qsString = function(obj, noencode) {
20078 function softEncode(s) {
20079 // encode everything except special characters used in certain hash parameters:
20080 // "/" in map states, ":", ",", {" and "}" in background
20081 return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
20083 return Object.keys(obj).sort().map(function(key) {
20084 return encodeURIComponent(key) + '=' + (
20085 noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
20089 iD.util.prefixDOMProperty = function(property) {
20090 var prefixes = ['webkit', 'ms', 'moz', 'o'],
20092 n = prefixes.length,
20098 property = property.substr(0, 1).toUpperCase() + property.substr(1);
20101 if (prefixes[i] + property in s)
20102 return prefixes[i] + property;
20107 iD.util.prefixCSSProperty = function(property) {
20108 var prefixes = ['webkit', 'ms', 'Moz', 'O'],
20110 n = prefixes.length,
20111 s = document.body.style;
20113 if (property.toLowerCase() in s)
20114 return property.toLowerCase();
20117 if (prefixes[i] + property in s)
20118 return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
20124 iD.util.setTransform = function(el, x, y, scale) {
20125 var prop = iD.util.transformProperty = iD.util.transformProperty || iD.util.prefixCSSProperty('Transform'),
20126 translate = iD.detect().opera ?
20127 'translate(' + x + 'px,' + y + 'px)' :
20128 'translate3d(' + x + 'px,' + y + 'px,0)';
20129 return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
20132 iD.util.getStyle = function(selector) {
20133 for (var i = 0; i < document.styleSheets.length; i++) {
20134 var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules || [];
20135 for (var k = 0; k < rules.length; k++) {
20136 var selectorText = rules[k].selectorText && rules[k].selectorText.split(', ');
20137 if (_.contains(selectorText, selector)) {
20144 iD.util.editDistance = function(a, b) {
20145 if (a.length === 0) return b.length;
20146 if (b.length === 0) return a.length;
20148 for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
20149 for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
20150 for (i = 1; i <= b.length; i++) {
20151 for (j = 1; j <= a.length; j++) {
20152 if (b.charAt(i-1) === a.charAt(j-1)) {
20153 matrix[i][j] = matrix[i-1][j-1];
20155 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
20156 Math.min(matrix[i][j-1] + 1, // insertion
20157 matrix[i-1][j] + 1)); // deletion
20161 return matrix[b.length][a.length];
20164 // a d3.mouse-alike which
20165 // 1. Only works on HTML elements, not SVG
20166 // 2. Does not cause style recalculation
20167 iD.util.fastMouse = function(container) {
20168 var rect = container.getBoundingClientRect(),
20169 rectLeft = rect.left,
20170 rectTop = rect.top,
20171 clientLeft = +container.clientLeft,
20172 clientTop = +container.clientTop;
20173 return function(e) {
20175 e.clientX - rectLeft - clientLeft,
20176 e.clientY - rectTop - clientTop];
20180 /* eslint-disable no-proto */
20181 iD.util.getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
20182 /* eslint-enable no-proto */
20184 iD.util.asyncMap = function(inputs, func, callback) {
20185 var remaining = inputs.length,
20189 inputs.forEach(function(d, i) {
20190 func(d, function done(err, data) {
20194 if (!remaining) callback(errors, results);
20199 // wraps an index to an interval [0..length-1]
20200 iD.util.wrap = function(index, length) {
20202 index += Math.ceil(-index/length)*length;
20203 return index % length;
20205 // A per-domain session mutex backed by a cookie and dead man's
20206 // switch. If the session crashes, the mutex will auto-release
20207 // after 5 seconds.
20209 iD.util.SessionMutex = function(name) {
20214 var expires = new Date();
20215 expires.setSeconds(expires.getSeconds() + 5);
20216 document.cookie = name + '=1; expires=' + expires.toUTCString();
20219 mutex.lock = function() {
20220 if (intervalID) return true;
20221 var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
20222 if (cookie) return false;
20224 intervalID = window.setInterval(renew, 4000);
20228 mutex.unlock = function() {
20229 if (!intervalID) return;
20230 document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
20231 clearInterval(intervalID);
20235 mutex.locked = function() {
20236 return !!intervalID;
20241 iD.util.SuggestNames = function(preset, suggestions) {
20242 preset = preset.id.split('/', 2);
20246 return function(value, callback) {
20248 if (value && value.length > 2) {
20249 if (suggestions[k] && suggestions[k][v]) {
20250 for (var sugg in suggestions[k][v]) {
20251 var dist = iD.util.editDistance(value, sugg.substring(0, value.length));
20261 result.sort(function(a, b) {
20262 return a.dist - b.dist;
20265 result = result.slice(0,3);
20271 iD.geo.roundCoords = function(c) {
20272 return [Math.floor(c[0]), Math.floor(c[1])];
20275 iD.geo.interp = function(p1, p2, t) {
20276 return [p1[0] + (p2[0] - p1[0]) * t,
20277 p1[1] + (p2[1] - p1[1]) * t];
20280 // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
20281 // Returns a positive value, if OAB makes a counter-clockwise turn,
20282 // negative for clockwise turn, and zero if the points are collinear.
20283 iD.geo.cross = function(o, a, b) {
20284 return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
20287 // http://jsperf.com/id-dist-optimization
20288 iD.geo.euclideanDistance = function(a, b) {
20289 var x = a[0] - b[0], y = a[1] - b[1];
20290 return Math.sqrt((x * x) + (y * y));
20293 // using WGS84 polar radius (6356752.314245179 m)
20294 // const = 2 * PI * r / 360
20295 iD.geo.latToMeters = function(dLat) {
20296 return dLat * 110946.257617;
20299 // using WGS84 equatorial radius (6378137.0 m)
20300 // const = 2 * PI * r / 360
20301 iD.geo.lonToMeters = function(dLon, atLat) {
20302 return Math.abs(atLat) >= 90 ? 0 :
20303 dLon * 111319.490793 * Math.abs(Math.cos(atLat * (Math.PI/180)));
20306 // using WGS84 polar radius (6356752.314245179 m)
20307 // const = 2 * PI * r / 360
20308 iD.geo.metersToLat = function(m) {
20309 return m / 110946.257617;
20312 // using WGS84 equatorial radius (6378137.0 m)
20313 // const = 2 * PI * r / 360
20314 iD.geo.metersToLon = function(m, atLat) {
20315 return Math.abs(atLat) >= 90 ? 0 :
20316 m / 111319.490793 / Math.abs(Math.cos(atLat * (Math.PI/180)));
20319 // Equirectangular approximation of spherical distances on Earth
20320 iD.geo.sphericalDistance = function(a, b) {
20321 var x = iD.geo.lonToMeters(a[0] - b[0], (a[1] + b[1]) / 2),
20322 y = iD.geo.latToMeters(a[1] - b[1]);
20323 return Math.sqrt((x * x) + (y * y));
20326 iD.geo.edgeEqual = function(a, b) {
20327 return (a[0] === b[0] && a[1] === b[1]) ||
20328 (a[0] === b[1] && a[1] === b[0]);
20331 // Return the counterclockwise angle in the range (-pi, pi)
20332 // between the positive X axis and the line intersecting a and b.
20333 iD.geo.angle = function(a, b, projection) {
20334 a = projection(a.loc);
20335 b = projection(b.loc);
20336 return Math.atan2(b[1] - a[1], b[0] - a[0]);
20339 // Choose the edge with the minimal distance from `point` to its orthogonal
20340 // projection onto that edge, if such a projection exists, or the distance to
20341 // the closest vertex on that edge. Returns an object with the `index` of the
20342 // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
20343 iD.geo.chooseEdge = function(nodes, point, projection) {
20344 var dist = iD.geo.euclideanDistance,
20345 points = nodes.map(function(n) { return projection(n.loc); }),
20349 function dot(p, q) {
20350 return p[0] * q[0] + p[1] * q[1];
20353 for (var i = 0; i < points.length - 1; i++) {
20355 s = [points[i + 1][0] - o[0],
20356 points[i + 1][1] - o[1]],
20357 v = [point[0] - o[0],
20359 proj = dot(v, s) / dot(s, s),
20364 } else if (proj > 1) {
20367 p = [o[0] + proj * s[0], o[1] + proj * s[1]];
20370 var d = dist(p, point);
20374 loc = projection.invert(p);
20385 // Return the intersection point of 2 line segments.
20386 // From https://github.com/pgkelley4/line-segments-intersect
20387 // This uses the vector cross product approach described below:
20388 // http://stackoverflow.com/a/565282/786339
20389 iD.geo.lineIntersection = function(a, b) {
20390 function subtractPoints(point1, point2) {
20391 return [point1[0] - point2[0], point1[1] - point2[1]];
20393 function crossProduct(point1, point2) {
20394 return point1[0] * point2[1] - point1[1] * point2[0];
20397 var p = [a[0][0], a[0][1]],
20398 p2 = [a[1][0], a[1][1]],
20399 q = [b[0][0], b[0][1]],
20400 q2 = [b[1][0], b[1][1]],
20401 r = subtractPoints(p2, p),
20402 s = subtractPoints(q2, q),
20403 uNumerator = crossProduct(subtractPoints(q, p), r),
20404 denominator = crossProduct(r, s);
20406 if (uNumerator && denominator) {
20407 var u = uNumerator / denominator,
20408 t = crossProduct(subtractPoints(q, p), s) / denominator;
20410 if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
20411 return iD.geo.interp(p, p2, t);
20418 iD.geo.pathIntersections = function(path1, path2) {
20419 var intersections = [];
20420 for (var i = 0; i < path1.length - 1; i++) {
20421 for (var j = 0; j < path2.length - 1; j++) {
20422 var a = [ path1[i], path1[i+1] ],
20423 b = [ path2[j], path2[j+1] ],
20424 hit = iD.geo.lineIntersection(a, b);
20425 if (hit) intersections.push(hit);
20428 return intersections;
20431 // Return whether point is contained in polygon.
20433 // `point` should be a 2-item array of coordinates.
20434 // `polygon` should be an array of 2-item arrays of coordinates.
20436 // From https://github.com/substack/point-in-polygon.
20437 // ray-casting algorithm based on
20438 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
20440 iD.geo.pointInPolygon = function(point, polygon) {
20445 for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
20446 var xi = polygon[i][0], yi = polygon[i][1];
20447 var xj = polygon[j][0], yj = polygon[j][1];
20449 var intersect = ((yi > y) !== (yj > y)) &&
20450 (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
20451 if (intersect) inside = !inside;
20457 iD.geo.polygonContainsPolygon = function(outer, inner) {
20458 return _.every(inner, function(point) {
20459 return iD.geo.pointInPolygon(point, outer);
20463 iD.geo.polygonIntersectsPolygon = function(outer, inner, checkSegments) {
20464 function testSegments(outer, inner) {
20465 for (var i = 0; i < outer.length - 1; i++) {
20466 for (var j = 0; j < inner.length - 1; j++) {
20467 var a = [ outer[i], outer[i+1] ],
20468 b = [ inner[j], inner[j+1] ];
20469 if (iD.geo.lineIntersection(a, b)) return true;
20475 function testPoints(outer, inner) {
20476 return _.some(inner, function(point) {
20477 return iD.geo.pointInPolygon(point, outer);
20481 return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
20484 iD.geo.pathLength = function(path) {
20487 for (var i = 0; i < path.length - 1; i++) {
20488 dx = path[i][0] - path[i + 1][0];
20489 dy = path[i][1] - path[i + 1][1];
20490 length += Math.sqrt(dx * dx + dy * dy);
20494 iD.geo.Extent = function geoExtent(min, max) {
20495 if (!(this instanceof iD.geo.Extent)) return new iD.geo.Extent(min, max);
20496 if (min instanceof iD.geo.Extent) {
20498 } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
20502 this[0] = min || [ Infinity, Infinity];
20503 this[1] = max || min || [-Infinity, -Infinity];
20507 iD.geo.Extent.prototype = new Array(2);
20509 _.extend(iD.geo.Extent.prototype, {
20510 equals: function (obj) {
20511 return this[0][0] === obj[0][0] &&
20512 this[0][1] === obj[0][1] &&
20513 this[1][0] === obj[1][0] &&
20514 this[1][1] === obj[1][1];
20517 extend: function(obj) {
20518 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20519 return iD.geo.Extent([Math.min(obj[0][0], this[0][0]),
20520 Math.min(obj[0][1], this[0][1])],
20521 [Math.max(obj[1][0], this[1][0]),
20522 Math.max(obj[1][1], this[1][1])]);
20525 _extend: function(extent) {
20526 this[0][0] = Math.min(extent[0][0], this[0][0]);
20527 this[0][1] = Math.min(extent[0][1], this[0][1]);
20528 this[1][0] = Math.max(extent[1][0], this[1][0]);
20529 this[1][1] = Math.max(extent[1][1], this[1][1]);
20533 return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
20536 center: function() {
20537 return [(this[0][0] + this[1][0]) / 2,
20538 (this[0][1] + this[1][1]) / 2];
20541 rectangle: function() {
20542 return [this[0][0], this[0][1], this[1][0], this[1][1]];
20545 polygon: function() {
20547 [this[0][0], this[0][1]],
20548 [this[0][0], this[1][1]],
20549 [this[1][0], this[1][1]],
20550 [this[1][0], this[0][1]],
20551 [this[0][0], this[0][1]]
20555 contains: function(obj) {
20556 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20557 return obj[0][0] >= this[0][0] &&
20558 obj[0][1] >= this[0][1] &&
20559 obj[1][0] <= this[1][0] &&
20560 obj[1][1] <= this[1][1];
20563 intersects: function(obj) {
20564 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20565 return obj[0][0] <= this[1][0] &&
20566 obj[0][1] <= this[1][1] &&
20567 obj[1][0] >= this[0][0] &&
20568 obj[1][1] >= this[0][1];
20571 intersection: function(obj) {
20572 if (!this.intersects(obj)) return new iD.geo.Extent();
20573 return new iD.geo.Extent([Math.max(obj[0][0], this[0][0]),
20574 Math.max(obj[0][1], this[0][1])],
20575 [Math.min(obj[1][0], this[1][0]),
20576 Math.min(obj[1][1], this[1][1])]);
20579 percentContainedIn: function(obj) {
20580 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
20581 var a1 = this.intersection(obj).area(),
20584 if (a1 === Infinity || a2 === Infinity || a1 === 0 || a2 === 0) {
20591 padByMeters: function(meters) {
20592 var dLat = iD.geo.metersToLat(meters),
20593 dLon = iD.geo.metersToLon(meters, this.center()[1]);
20594 return iD.geo.Extent(
20595 [this[0][0] - dLon, this[0][1] - dLat],
20596 [this[1][0] + dLon, this[1][1] + dLat]);
20599 toParam: function() {
20600 return this.rectangle().join(',');
20604 iD.geo.Turn = function(turn) {
20605 if (!(this instanceof iD.geo.Turn))
20606 return new iD.geo.Turn(turn);
20607 _.extend(this, turn);
20610 iD.geo.Intersection = function(graph, vertexId) {
20611 var vertex = graph.entity(vertexId),
20612 parentWays = graph.parentWays(vertex),
20616 function addHighway(way, adjacentNodeId) {
20617 if (highways[adjacentNodeId]) {
20618 coincident.push(adjacentNodeId);
20620 highways[adjacentNodeId] = way;
20624 // Pre-split ways that would need to be split in
20625 // order to add a restriction. The real split will
20626 // happen when the restriction is added.
20627 parentWays.forEach(function(way) {
20628 if (!way.tags.highway || way.isArea() || way.isDegenerate())
20631 var isFirst = (vertexId === way.first()),
20632 isLast = (vertexId === way.last()),
20633 isAffix = (isFirst || isLast),
20634 isClosingNode = (isFirst && isLast);
20636 if (isAffix && !isClosingNode) {
20637 var index = (isFirst ? 1 : way.nodes.length - 2);
20638 addHighway(way, way.nodes[index]);
20641 var splitIndex, wayA, wayB, indexA, indexB;
20642 if (isClosingNode) {
20643 splitIndex = Math.ceil(way.nodes.length / 2); // split at midpoint
20644 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
20645 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
20647 indexB = way.nodes.length - 2;
20649 splitIndex = _.indexOf(way.nodes, vertex.id, 1); // split at vertexid
20650 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
20651 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
20652 indexA = splitIndex - 1;
20653 indexB = splitIndex + 1;
20655 graph = graph.replace(wayA).replace(wayB);
20656 addHighway(wayA, way.nodes[indexA]);
20657 addHighway(wayB, way.nodes[indexB]);
20661 // remove any ways from this intersection that are coincident
20662 // (i.e. any adjacent node used by more than one intersecting way)
20663 coincident.forEach(function (n) {
20664 delete highways[n];
20668 var intersection = {
20669 highways: highways,
20670 ways: _.values(highways),
20674 intersection.adjacentNodeId = function(fromWayId) {
20675 return _.find(_.keys(highways), function(k) {
20676 return highways[k].id === fromWayId;
20680 intersection.turns = function(fromNodeId) {
20681 var start = highways[fromNodeId];
20685 if (start.first() === vertex.id && start.tags.oneway === 'yes')
20687 if (start.last() === vertex.id && start.tags.oneway === '-1')
20690 function withRestriction(turn) {
20691 graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
20692 if (relation.tags.type !== 'restriction')
20695 var f = relation.memberByRole('from'),
20696 t = relation.memberByRole('to'),
20697 v = relation.memberByRole('via');
20699 if (f && f.id === turn.from.way &&
20700 v && v.id === turn.via.node &&
20701 t && t.id === turn.to.way) {
20702 turn.restriction = relation.id;
20703 } else if (/^only_/.test(relation.tags.restriction) &&
20704 f && f.id === turn.from.way &&
20705 v && v.id === turn.via.node &&
20706 t && t.id !== turn.to.way) {
20707 turn.restriction = relation.id;
20708 turn.indirect_restriction = true;
20712 return iD.geo.Turn(turn);
20717 way: start.id.split(/-(a|b)/)[0]
20719 via = { node: vertex.id },
20722 _.each(highways, function(end, adjacentNodeId) {
20727 if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
20728 turns.push(withRestriction({
20732 node: adjacentNodeId,
20733 way: end.id.split(/-(a|b)/)[0]
20739 if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
20740 turns.push(withRestriction({
20744 node: adjacentNodeId,
20745 way: end.id.split(/-(a|b)/)[0]
20753 if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
20754 turns.push(withRestriction({
20765 return intersection;
20769 iD.geo.inferRestriction = function(graph, from, via, to, projection) {
20770 var fromWay = graph.entity(from.way),
20771 fromNode = graph.entity(from.node),
20772 toWay = graph.entity(to.way),
20773 toNode = graph.entity(to.node),
20774 viaNode = graph.entity(via.node),
20775 fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
20776 (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
20777 toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
20778 (toWay.tags.oneway === '-1' && toWay.last() === via.node),
20779 angle = iD.geo.angle(viaNode, fromNode, projection) -
20780 iD.geo.angle(viaNode, toNode, projection);
20782 angle = angle * 180 / Math.PI;
20787 if (fromNode === toNode)
20788 return 'no_u_turn';
20789 if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
20790 return 'no_u_turn';
20792 return 'no_right_turn';
20794 return 'no_left_turn';
20796 return 'no_straight_on';
20798 // For fixing up rendering of multipolygons with tags on the outer member.
20799 // https://github.com/openstreetmap/iD/issues/613
20800 iD.geo.isSimpleMultipolygonOuterMember = function(entity, graph) {
20801 if (entity.type !== 'way')
20804 var parents = graph.parentRelations(entity);
20805 if (parents.length !== 1)
20808 var parent = parents[0];
20809 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
20812 var members = parent.members, member;
20813 for (var i = 0; i < members.length; i++) {
20814 member = members[i];
20815 if (member.id === entity.id && member.role && member.role !== 'outer')
20816 return false; // Not outer member
20817 if (member.id !== entity.id && (!member.role || member.role === 'outer'))
20818 return false; // Not a simple multipolygon
20824 iD.geo.simpleMultipolygonOuterMember = function(entity, graph) {
20825 if (entity.type !== 'way')
20828 var parents = graph.parentRelations(entity);
20829 if (parents.length !== 1)
20832 var parent = parents[0];
20833 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
20836 var members = parent.members, member, outerMember;
20837 for (var i = 0; i < members.length; i++) {
20838 member = members[i];
20839 if (!member.role || member.role === 'outer') {
20841 return false; // Not a simple multipolygon
20842 outerMember = member;
20846 return outerMember && graph.hasEntity(outerMember.id);
20849 // Join `array` into sequences of connecting ways.
20851 // Segments which share identical start/end nodes will, as much as possible,
20852 // be connected with each other.
20854 // The return value is a nested array. Each constituent array contains elements
20855 // of `array` which have been determined to connect. Each consitituent array
20856 // also has a `nodes` property whose value is an ordered array of member nodes,
20857 // with appropriate order reversal and start/end coordinate de-duplication.
20859 // Members of `array` must have, at minimum, `type` and `id` properties.
20860 // Thus either an array of `iD.Way`s or a relation member array may be
20863 // If an member has a `tags` property, its tags will be reversed via
20864 // `iD.actions.Reverse` in the output.
20866 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
20867 // false) and non-way members are ignored.
20869 iD.geo.joinWays = function(array, graph) {
20870 var joined = [], member, current, nodes, first, last, i, how, what;
20872 array = array.filter(function(member) {
20873 return member.type === 'way' && graph.hasEntity(member.id);
20876 function resolve(member) {
20877 return graph.childNodes(graph.entity(member.id));
20880 function reverse(member) {
20881 return member.tags ? iD.actions.Reverse(member.id, {reverseOneway: true})(graph).entity(member.id) : member;
20884 while (array.length) {
20885 member = array.shift();
20886 current = [member];
20887 current.nodes = nodes = resolve(member).slice();
20888 joined.push(current);
20890 while (array.length && _.first(nodes) !== _.last(nodes)) {
20891 first = _.first(nodes);
20892 last = _.last(nodes);
20894 for (i = 0; i < array.length; i++) {
20896 what = resolve(member);
20898 if (last === _.first(what)) {
20900 what = what.slice(1);
20902 } else if (last === _.last(what)) {
20904 what = what.slice(0, -1).reverse();
20905 member = reverse(member);
20907 } else if (first === _.last(what)) {
20908 how = nodes.unshift;
20909 what = what.slice(0, -1);
20911 } else if (first === _.first(what)) {
20912 how = nodes.unshift;
20913 what = what.slice(1).reverse();
20914 member = reverse(member);
20922 break; // No more joinable ways.
20924 how.apply(current, [member]);
20925 how.apply(nodes, what);
20927 array.splice(i, 1);
20934 Bypasses features of D3's default projection stream pipeline that are unnecessary:
20935 * Antimeridian clipping
20936 * Spherical rotation
20939 iD.geo.RawMercator = function () {
20940 var project = d3.geo.mercator.raw,
20941 k = 512 / Math.PI, // scale
20942 x = 0, y = 0, // translate
20943 clipExtent = [[0, 0], [0, 0]];
20945 function projection(point) {
20946 point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
20947 return [point[0] * k + x, y - point[1] * k];
20950 projection.invert = function(point) {
20951 point = project.invert((point[0] - x) / k, (y - point[1]) / k);
20952 return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
20955 projection.scale = function(_) {
20956 if (!arguments.length) return k;
20961 projection.translate = function(_) {
20962 if (!arguments.length) return [x, y];
20968 projection.clipExtent = function(_) {
20969 if (!arguments.length) return clipExtent;
20974 projection.stream = d3.geo.transform({
20975 point: function(x, y) {
20976 x = projection([x, y]);
20977 this.stream.point(x[0], x[1]);
20984 iD.actions.AddEntity = function(way) {
20985 return function(graph) {
20986 return graph.replace(way);
20989 iD.actions.AddMember = function(relationId, member, memberIndex) {
20990 return function(graph) {
20991 var relation = graph.entity(relationId);
20993 if (isNaN(memberIndex) && member.type === 'way') {
20994 var members = relation.indexedMembers();
20995 members.push(member);
20997 var joined = iD.geo.joinWays(members, graph);
20998 for (var i = 0; i < joined.length; i++) {
20999 var segment = joined[i];
21000 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
21001 if (segment[j] !== member)
21005 memberIndex = segment[j + 1].index;
21006 } else if (j === segment.length - 1) {
21007 memberIndex = segment[j - 1].index + 1;
21009 memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
21015 return graph.replace(relation.addMember(member, memberIndex));
21018 iD.actions.AddMidpoint = function(midpoint, node) {
21019 return function(graph) {
21020 graph = graph.replace(node.move(midpoint.loc));
21022 var parents = _.intersection(
21023 graph.parentWays(graph.entity(midpoint.edge[0])),
21024 graph.parentWays(graph.entity(midpoint.edge[1])));
21026 parents.forEach(function(way) {
21027 for (var i = 0; i < way.nodes.length - 1; i++) {
21028 if (iD.geo.edgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
21029 graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
21031 // Add only one midpoint on doubled-back segments,
21032 // turning them into self-intersections.
21041 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
21042 iD.actions.AddVertex = function(wayId, nodeId, index) {
21043 return function(graph) {
21044 return graph.replace(graph.entity(wayId).addNode(nodeId, index));
21047 iD.actions.ChangeMember = function(relationId, member, memberIndex) {
21048 return function(graph) {
21049 return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
21052 iD.actions.ChangePreset = function(entityId, oldPreset, newPreset) {
21053 return function(graph) {
21054 var entity = graph.entity(entityId),
21055 geometry = entity.geometry(graph),
21056 tags = entity.tags;
21058 if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
21059 if (newPreset) tags = newPreset.applyTags(tags, geometry);
21061 return graph.replace(entity.update({tags: tags}));
21064 iD.actions.ChangeTags = function(entityId, tags) {
21065 return function(graph) {
21066 var entity = graph.entity(entityId);
21067 return graph.replace(entity.update({tags: tags}));
21070 iD.actions.Circularize = function(wayId, projection, maxAngle) {
21071 maxAngle = (maxAngle || 20) * Math.PI / 180;
21073 var action = function(graph) {
21074 var way = graph.entity(wayId);
21076 if (!way.isConvex(graph)) {
21077 graph = action.makeConvex(graph);
21080 var nodes = _.uniq(graph.childNodes(way)),
21081 keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
21082 points = nodes.map(function(n) { return projection(n.loc); }),
21083 keyPoints = keyNodes.map(function(n) { return projection(n.loc); }),
21084 centroid = (points.length === 2) ? iD.geo.interp(points[0], points[1], 0.5) : d3.geom.polygon(points).centroid(),
21085 radius = d3.median(points, function(p) { return iD.geo.euclideanDistance(centroid, p); }),
21086 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
21089 // we need atleast two key nodes for the algorithm to work
21090 if (!keyNodes.length) {
21091 keyNodes = [nodes[0]];
21092 keyPoints = [points[0]];
21095 if (keyNodes.length === 1) {
21096 var index = nodes.indexOf(keyNodes[0]),
21097 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
21099 keyNodes.push(nodes[oppositeIndex]);
21100 keyPoints.push(points[oppositeIndex]);
21103 // key points and nodes are those connected to the ways,
21104 // they are projected onto the circle, inbetween nodes are moved
21105 // to constant intervals between key nodes, extra inbetween nodes are
21106 // added if necessary.
21107 for (var i = 0; i < keyPoints.length; i++) {
21108 var nextKeyNodeIndex = (i + 1) % keyNodes.length,
21109 startNode = keyNodes[i],
21110 endNode = keyNodes[nextKeyNodeIndex],
21111 startNodeIndex = nodes.indexOf(startNode),
21112 endNodeIndex = nodes.indexOf(endNode),
21113 numberNewPoints = -1,
21114 indexRange = endNodeIndex - startNodeIndex,
21115 distance, totalAngle, eachAngle, startAngle, endAngle,
21116 angle, loc, node, j,
21117 inBetweenNodes = [];
21119 if (indexRange < 0) {
21120 indexRange += nodes.length;
21123 // position this key node
21124 distance = iD.geo.euclideanDistance(centroid, keyPoints[i]);
21125 if (distance === 0) { distance = 1e-4; }
21127 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius,
21128 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
21129 graph = graph.replace(keyNodes[i].move(projection.invert(keyPoints[i])));
21131 // figure out the between delta angle we want to match to
21132 startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
21133 endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
21134 totalAngle = endAngle - startAngle;
21136 // detects looping around -pi/pi
21137 if (totalAngle * sign > 0) {
21138 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
21143 eachAngle = totalAngle / (indexRange + numberNewPoints);
21144 } while (Math.abs(eachAngle) > maxAngle);
21146 // move existing points
21147 for (j = 1; j < indexRange; j++) {
21148 angle = startAngle + j * eachAngle;
21149 loc = projection.invert([
21150 centroid[0] + Math.cos(angle)*radius,
21151 centroid[1] + Math.sin(angle)*radius]);
21153 node = nodes[(j + startNodeIndex) % nodes.length].move(loc);
21154 graph = graph.replace(node);
21157 // add new inbetween nodes if necessary
21158 for (j = 0; j < numberNewPoints; j++) {
21159 angle = startAngle + (indexRange + j) * eachAngle;
21160 loc = projection.invert([
21161 centroid[0] + Math.cos(angle) * radius,
21162 centroid[1] + Math.sin(angle) * radius]);
21164 node = iD.Node({loc: loc});
21165 graph = graph.replace(node);
21167 nodes.splice(endNodeIndex + j, 0, node);
21168 inBetweenNodes.push(node.id);
21171 // Check for other ways that share these keyNodes..
21172 // If keyNodes are adjacent in both ways,
21173 // we can add inBetween nodes to that shared way too..
21174 if (indexRange === 1 && inBetweenNodes.length) {
21175 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
21176 endIndex1 = way.nodes.lastIndexOf(endNode.id),
21177 wayDirection1 = (endIndex1 - startIndex1);
21178 if (wayDirection1 < -1) { wayDirection1 = 1; }
21180 /* eslint-disable no-loop-func */
21181 _.each(_.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
21182 if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
21183 var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
21184 endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
21185 wayDirection2 = (endIndex2 - startIndex2),
21186 insertAt = endIndex2;
21187 if (wayDirection2 < -1) { wayDirection2 = 1; }
21189 if (wayDirection1 !== wayDirection2) {
21190 inBetweenNodes.reverse();
21191 insertAt = startIndex2;
21193 for (j = 0; j < inBetweenNodes.length; j++) {
21194 sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
21196 graph = graph.replace(sharedWay);
21199 /* eslint-enable no-loop-func */
21204 // update the way to have all the new nodes
21205 ids = nodes.map(function(n) { return n.id; });
21208 way = way.update({nodes: ids});
21209 graph = graph.replace(way);
21214 action.makeConvex = function(graph) {
21215 var way = graph.entity(wayId),
21216 nodes = _.uniq(graph.childNodes(way)),
21217 points = nodes.map(function(n) { return projection(n.loc); }),
21218 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
21219 hull = d3.geom.hull(points);
21221 // D3 convex hulls go counterclockwise..
21227 for (var i = 0; i < hull.length - 1; i++) {
21228 var startIndex = points.indexOf(hull[i]),
21229 endIndex = points.indexOf(hull[i+1]),
21230 indexRange = (endIndex - startIndex);
21232 if (indexRange < 0) {
21233 indexRange += nodes.length;
21236 // move interior nodes to the surface of the convex hull..
21237 for (var j = 1; j < indexRange; j++) {
21238 var point = iD.geo.interp(hull[i], hull[i+1], j / indexRange),
21239 node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
21240 graph = graph.replace(node);
21246 action.disabled = function(graph) {
21247 if (!graph.entity(wayId).isClosed())
21248 return 'not_closed';
21253 // Connect the ways at the given nodes.
21255 // The last node will survive. All other nodes will be replaced with
21256 // the surviving node in parent ways, and then removed.
21258 // Tags and relation memberships of of non-surviving nodes are merged
21259 // to the survivor.
21261 // This is the inverse of `iD.actions.Disconnect`.
21264 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
21265 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
21267 iD.actions.Connect = function(nodeIds) {
21268 return function(graph) {
21269 var survivor = graph.entity(_.last(nodeIds));
21271 for (var i = 0; i < nodeIds.length - 1; i++) {
21272 var node = graph.entity(nodeIds[i]);
21274 /* eslint-disable no-loop-func */
21275 graph.parentWays(node).forEach(function(parent) {
21276 if (!parent.areAdjacent(node.id, survivor.id)) {
21277 graph = graph.replace(parent.replaceNode(node.id, survivor.id));
21281 graph.parentRelations(node).forEach(function(parent) {
21282 graph = graph.replace(parent.replaceMember(node, survivor));
21284 /* eslint-enable no-loop-func */
21286 survivor = survivor.mergeTags(node.tags);
21287 graph = iD.actions.DeleteNode(node.id)(graph);
21290 graph = graph.replace(survivor);
21295 iD.actions.CopyEntities = function(ids, fromGraph) {
21298 var action = function(graph) {
21299 ids.forEach(function(id) {
21300 fromGraph.entity(id).copy(fromGraph, copies);
21303 for (var id in copies) {
21304 graph = graph.replace(copies[id]);
21310 action.copies = function() {
21316 iD.actions.DeleteMember = function(relationId, memberIndex) {
21317 return function(graph) {
21318 var relation = graph.entity(relationId)
21319 .removeMember(memberIndex);
21321 graph = graph.replace(relation);
21323 if (relation.isDegenerate())
21324 graph = iD.actions.DeleteRelation(relation.id)(graph);
21329 iD.actions.DeleteMultiple = function(ids) {
21331 way: iD.actions.DeleteWay,
21332 node: iD.actions.DeleteNode,
21333 relation: iD.actions.DeleteRelation
21336 var action = function(graph) {
21337 ids.forEach(function(id) {
21338 if (graph.hasEntity(id)) { // It may have been deleted aready.
21339 graph = actions[graph.entity(id).type](id)(graph);
21346 action.disabled = function(graph) {
21347 for (var i = 0; i < ids.length; i++) {
21349 disabled = actions[graph.entity(id).type](id).disabled(graph);
21350 if (disabled) return disabled;
21356 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
21357 iD.actions.DeleteNode = function(nodeId) {
21358 var action = function(graph) {
21359 var node = graph.entity(nodeId);
21361 graph.parentWays(node)
21362 .forEach(function(parent) {
21363 parent = parent.removeNode(nodeId);
21364 graph = graph.replace(parent);
21366 if (parent.isDegenerate()) {
21367 graph = iD.actions.DeleteWay(parent.id)(graph);
21371 graph.parentRelations(node)
21372 .forEach(function(parent) {
21373 parent = parent.removeMembersWithID(nodeId);
21374 graph = graph.replace(parent);
21376 if (parent.isDegenerate()) {
21377 graph = iD.actions.DeleteRelation(parent.id)(graph);
21381 return graph.remove(node);
21384 action.disabled = function() {
21390 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
21391 iD.actions.DeleteRelation = function(relationId) {
21392 function deleteEntity(entity, graph) {
21393 return !graph.parentWays(entity).length &&
21394 !graph.parentRelations(entity).length &&
21395 !entity.hasInterestingTags();
21398 var action = function(graph) {
21399 var relation = graph.entity(relationId);
21401 graph.parentRelations(relation)
21402 .forEach(function(parent) {
21403 parent = parent.removeMembersWithID(relationId);
21404 graph = graph.replace(parent);
21406 if (parent.isDegenerate()) {
21407 graph = iD.actions.DeleteRelation(parent.id)(graph);
21411 _.uniq(_.pluck(relation.members, 'id')).forEach(function(memberId) {
21412 graph = graph.replace(relation.removeMembersWithID(memberId));
21414 var entity = graph.entity(memberId);
21415 if (deleteEntity(entity, graph)) {
21416 graph = iD.actions.DeleteMultiple([memberId])(graph);
21420 return graph.remove(relation);
21423 action.disabled = function(graph) {
21424 if (!graph.entity(relationId).isComplete(graph))
21425 return 'incomplete_relation';
21430 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
21431 iD.actions.DeleteWay = function(wayId) {
21432 function deleteNode(node, graph) {
21433 return !graph.parentWays(node).length &&
21434 !graph.parentRelations(node).length &&
21435 !node.hasInterestingTags();
21438 var action = function(graph) {
21439 var way = graph.entity(wayId);
21441 graph.parentRelations(way)
21442 .forEach(function(parent) {
21443 parent = parent.removeMembersWithID(wayId);
21444 graph = graph.replace(parent);
21446 if (parent.isDegenerate()) {
21447 graph = iD.actions.DeleteRelation(parent.id)(graph);
21451 _.uniq(way.nodes).forEach(function(nodeId) {
21452 graph = graph.replace(way.removeNode(nodeId));
21454 var node = graph.entity(nodeId);
21455 if (deleteNode(node, graph)) {
21456 graph = graph.remove(node);
21460 return graph.remove(way);
21463 action.disabled = function(graph) {
21464 var disabled = false;
21466 graph.parentRelations(graph.entity(wayId)).forEach(function(parent) {
21467 var type = parent.tags.type,
21468 role = parent.memberById(wayId).role || 'outer';
21469 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
21470 disabled = 'part_of_relation';
21479 iD.actions.DeprecateTags = function(entityId) {
21480 return function(graph) {
21481 var entity = graph.entity(entityId),
21482 newtags = _.clone(entity.tags),
21486 // This handles deprecated tags with a single condition
21487 for (var i = 0; i < iD.data.deprecated.length; i++) {
21489 rule = iD.data.deprecated[i];
21490 var match = _.pairs(rule.old)[0],
21491 replacements = rule.replace ? _.pairs(rule.replace) : null;
21493 if (entity.tags[match[0]] && match[1] === '*') {
21495 var value = entity.tags[match[0]];
21496 if (replacements && !newtags[replacements[0][0]]) {
21497 newtags[replacements[0][0]] = value;
21499 delete newtags[match[0]];
21502 } else if (entity.tags[match[0]] === match[1]) {
21503 newtags = _.assign({}, rule.replace || {}, _.omit(newtags, match[0]));
21509 return graph.replace(entity.update({tags: newtags}));
21515 iD.actions.DiscardTags = function(difference) {
21516 return function(graph) {
21517 function discardTags(entity) {
21518 if (!_.isEmpty(entity.tags)) {
21520 _.each(entity.tags, function(v, k) {
21521 if (v) tags[k] = v;
21524 graph = graph.replace(entity.update({
21525 tags: _.omit(tags, iD.data.discarded)
21530 difference.modified().forEach(discardTags);
21531 difference.created().forEach(discardTags);
21536 // Disconect the ways at the given node.
21538 // Optionally, disconnect only the given ways.
21540 // For testing convenience, accepts an ID to assign to the (first) new node.
21541 // Normally, this will be undefined and the way will automatically
21542 // be assigned a new ID.
21544 // This is the inverse of `iD.actions.Connect`.
21547 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
21548 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
21550 iD.actions.Disconnect = function(nodeId, newNodeId) {
21553 var action = function(graph) {
21554 var node = graph.entity(nodeId),
21555 connections = action.connections(graph);
21557 connections.forEach(function(connection) {
21558 var way = graph.entity(connection.wayID),
21559 newNode = iD.Node({id: newNodeId, loc: node.loc, tags: node.tags});
21561 graph = graph.replace(newNode);
21562 if (connection.index === 0 && way.isArea()) {
21563 // replace shared node with shared node..
21564 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
21566 // replace shared node with multiple new nodes..
21567 graph = graph.replace(way.updateNode(newNode.id, connection.index));
21574 action.connections = function(graph) {
21575 var candidates = [],
21577 parentWays = graph.parentWays(graph.entity(nodeId));
21579 parentWays.forEach(function(way) {
21580 if (wayIds && wayIds.indexOf(way.id) === -1) {
21584 if (way.isArea() && (way.nodes[0] === nodeId)) {
21585 candidates.push({wayID: way.id, index: 0});
21587 way.nodes.forEach(function(waynode, index) {
21588 if (waynode === nodeId) {
21589 candidates.push({wayID: way.id, index: index});
21595 return keeping ? candidates : candidates.slice(1);
21598 action.disabled = function(graph) {
21599 var connections = action.connections(graph);
21600 if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
21601 return 'not_connected';
21603 var parentWays = graph.parentWays(graph.entity(nodeId)),
21604 seenRelationIds = {},
21607 parentWays.forEach(function(way) {
21608 if (wayIds && wayIds.indexOf(way.id) === -1)
21611 var relations = graph.parentRelations(way);
21612 relations.forEach(function(relation) {
21613 if (relation.id in seenRelationIds) {
21614 sharedRelation = relation;
21616 seenRelationIds[relation.id] = true;
21621 if (sharedRelation)
21625 action.limitWays = function(_) {
21626 if (!arguments.length) return wayIds;
21633 // Join ways at the end node they share.
21635 // This is the inverse of `iD.actions.Split`.
21638 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
21639 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
21641 iD.actions.Join = function(ids) {
21643 function groupEntitiesByGeometry(graph) {
21644 var entities = ids.map(function(id) { return graph.entity(id); });
21645 return _.extend({line: []}, _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
21648 var action = function(graph) {
21649 var ways = ids.map(graph.entity, graph),
21650 survivor = ways[0];
21652 // Prefer to keep an existing way.
21653 for (var i = 0; i < ways.length; i++) {
21654 if (!ways[i].isNew()) {
21655 survivor = ways[i];
21660 var joined = iD.geo.joinWays(ways, graph)[0];
21662 survivor = survivor.update({nodes: _.pluck(joined.nodes, 'id')});
21663 graph = graph.replace(survivor);
21665 joined.forEach(function(way) {
21666 if (way.id === survivor.id)
21669 graph.parentRelations(way).forEach(function(parent) {
21670 graph = graph.replace(parent.replaceMember(way, survivor));
21673 survivor = survivor.mergeTags(way.tags);
21675 graph = graph.replace(survivor);
21676 graph = iD.actions.DeleteWay(way.id)(graph);
21682 action.disabled = function(graph) {
21683 var geometries = groupEntitiesByGeometry(graph);
21684 if (ids.length < 2 || ids.length !== geometries.line.length)
21685 return 'not_eligible';
21687 var joined = iD.geo.joinWays(ids.map(graph.entity, graph), graph);
21688 if (joined.length > 1)
21689 return 'not_adjacent';
21691 var nodeIds = _.pluck(joined[0].nodes, 'id').slice(1, -1),
21694 conflicting = false;
21696 joined[0].forEach(function(way) {
21697 var parents = graph.parentRelations(way);
21698 parents.forEach(function(parent) {
21699 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
21703 for (var k in way.tags) {
21704 if (!(k in tags)) {
21705 tags[k] = way.tags[k];
21706 } else if (tags[k] && iD.interestingTag(k) && tags[k] !== way.tags[k]) {
21707 conflicting = true;
21713 return 'restriction';
21716 return 'conflicting_tags';
21721 iD.actions.Merge = function(ids) {
21722 function groupEntitiesByGeometry(graph) {
21723 var entities = ids.map(function(id) { return graph.entity(id); });
21724 return _.extend({point: [], area: [], line: [], relation: []},
21725 _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
21728 var action = function(graph) {
21729 var geometries = groupEntitiesByGeometry(graph),
21730 target = geometries.area[0] || geometries.line[0],
21731 points = geometries.point;
21733 points.forEach(function(point) {
21734 target = target.mergeTags(point.tags);
21736 graph.parentRelations(point).forEach(function(parent) {
21737 graph = graph.replace(parent.replaceMember(point, target));
21740 graph = graph.remove(point);
21743 graph = graph.replace(target);
21748 action.disabled = function(graph) {
21749 var geometries = groupEntitiesByGeometry(graph);
21750 if (geometries.point.length === 0 ||
21751 (geometries.area.length + geometries.line.length) !== 1 ||
21752 geometries.relation.length !== 0)
21753 return 'not_eligible';
21758 iD.actions.MergePolygon = function(ids, newRelationId) {
21760 function groupEntities(graph) {
21761 var entities = ids.map(function (id) { return graph.entity(id); });
21766 }, _.groupBy(entities, function(entity) {
21767 if (entity.type === 'way' && entity.isClosed()) {
21768 return 'closedWay';
21769 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
21770 return 'multipolygon';
21777 var action = function(graph) {
21778 var entities = groupEntities(graph);
21780 // An array representing all the polygons that are part of the multipolygon.
21782 // Each element is itself an array of objects with an id property, and has a
21783 // locs property which is an array of the locations forming the polygon.
21784 var polygons = entities.multipolygon.reduce(function(polygons, m) {
21785 return polygons.concat(iD.geo.joinWays(m.members, graph));
21786 }, []).concat(entities.closedWay.map(function(d) {
21787 var member = [{id: d.id}];
21788 member.nodes = graph.childNodes(d);
21792 // contained is an array of arrays of boolean values,
21793 // where contained[j][k] is true iff the jth way is
21794 // contained by the kth way.
21795 var contained = polygons.map(function(w, i) {
21796 return polygons.map(function(d, n) {
21797 if (i === n) return null;
21798 return iD.geo.polygonContainsPolygon(
21799 _.pluck(d.nodes, 'loc'),
21800 _.pluck(w.nodes, 'loc'));
21804 // Sort all polygons as either outer or inner ways
21808 while (polygons.length) {
21809 extractUncontained(polygons);
21810 polygons = polygons.filter(isContained);
21811 contained = contained.filter(isContained).map(filterContained);
21814 function isContained(d, i) {
21815 return _.any(contained[i]);
21818 function filterContained(d) {
21819 return d.filter(isContained);
21822 function extractUncontained(polygons) {
21823 polygons.forEach(function(d, i) {
21824 if (!isContained(d, i)) {
21825 d.forEach(function(member) {
21829 role: outer ? 'outer' : 'inner'
21837 // Move all tags to one relation
21838 var relation = entities.multipolygon[0] ||
21839 iD.Relation({ id: newRelationId, tags: { type: 'multipolygon' }});
21841 entities.multipolygon.slice(1).forEach(function(m) {
21842 relation = relation.mergeTags(m.tags);
21843 graph = graph.remove(m);
21846 entities.closedWay.forEach(function(way) {
21847 function isThisOuter(m) {
21848 return m.id === way.id && m.role !== 'inner';
21850 if (members.some(isThisOuter)) {
21851 relation = relation.mergeTags(way.tags);
21852 graph = graph.replace(way.update({ tags: {} }));
21856 return graph.replace(relation.update({
21858 tags: _.omit(relation.tags, 'area')
21862 action.disabled = function(graph) {
21863 var entities = groupEntities(graph);
21864 if (entities.other.length > 0 ||
21865 entities.closedWay.length + entities.multipolygon.length < 2)
21866 return 'not_eligible';
21867 if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
21868 return 'incomplete_relation';
21873 iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser) {
21874 var option = 'safe', // 'safe', 'force_local', 'force_remote'
21878 return _.isFunction(formatUser) ? formatUser(d) : d;
21882 function mergeLocation(remote, target) {
21883 function pointEqual(a, b) {
21884 var epsilon = 1e-6;
21885 return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
21888 if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
21891 if (option === 'force_remote') {
21892 return target.update({loc: remote.loc});
21895 conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
21900 function mergeNodes(base, remote, target) {
21901 if (option === 'force_local' || _.isEqual(target.nodes, remote.nodes)) {
21904 if (option === 'force_remote') {
21905 return target.update({nodes: remote.nodes});
21908 var ccount = conflicts.length,
21909 o = base.nodes || [],
21910 a = target.nodes || [],
21911 b = remote.nodes || [],
21913 hunks = Diff3.diff3_merge(a, o, b, true);
21915 for (var i = 0; i < hunks.length; i++) {
21916 var hunk = hunks[i];
21918 nodes.push.apply(nodes, hunk.ok);
21920 // for all conflicts, we can assume c.a !== c.b
21921 // because `diff3_merge` called with `true` option to exclude false conflicts..
21922 var c = hunk.conflict;
21923 if (_.isEqual(c.o, c.a)) { // only changed remotely
21924 nodes.push.apply(nodes, c.b);
21925 } else if (_.isEqual(c.o, c.b)) { // only changed locally
21926 nodes.push.apply(nodes, c.a);
21927 } else { // changed both locally and remotely
21928 conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
21934 return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
21938 function mergeChildren(targetWay, children, updates, graph) {
21939 function isUsed(node, targetWay) {
21940 var parentWays = _.pluck(graph.parentWays(node), 'id');
21941 return node.hasInterestingTags() ||
21942 _.without(parentWays, targetWay.id).length > 0 ||
21943 graph.parentRelations(node).length > 0;
21946 var ccount = conflicts.length;
21948 for (var i = 0; i < children.length; i++) {
21949 var id = children[i],
21950 node = graph.hasEntity(id);
21952 // remove unused childNodes..
21953 if (targetWay.nodes.indexOf(id) === -1) {
21954 if (node && !isUsed(node, targetWay)) {
21955 updates.removeIds.push(id);
21960 // restore used childNodes..
21961 var local = localGraph.hasEntity(id),
21962 remote = remoteGraph.hasEntity(id),
21965 if (option === 'force_remote' && remote && remote.visible) {
21966 updates.replacements.push(remote);
21968 } else if (option === 'force_local' && local) {
21969 target = iD.Entity(local);
21971 target = target.update({ version: remote.version });
21973 updates.replacements.push(target);
21975 } else if (option === 'safe' && local && remote && local.version !== remote.version) {
21976 target = iD.Entity(local, { version: remote.version });
21977 if (remote.visible) {
21978 target = mergeLocation(remote, target);
21980 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
21983 if (conflicts.length !== ccount) break;
21984 updates.replacements.push(target);
21992 function updateChildren(updates, graph) {
21993 for (var i = 0; i < updates.replacements.length; i++) {
21994 graph = graph.replace(updates.replacements[i]);
21996 if (updates.removeIds.length) {
21997 graph = iD.actions.DeleteMultiple(updates.removeIds)(graph);
22003 function mergeMembers(remote, target) {
22004 if (option === 'force_local' || _.isEqual(target.members, remote.members)) {
22007 if (option === 'force_remote') {
22008 return target.update({members: remote.members});
22011 conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
22016 function mergeTags(base, remote, target) {
22017 function ignoreKey(k) {
22018 return _.contains(iD.data.discarded, k);
22021 if (option === 'force_local' || _.isEqual(target.tags, remote.tags)) {
22024 if (option === 'force_remote') {
22025 return target.update({tags: remote.tags});
22028 var ccount = conflicts.length,
22029 o = base.tags || {},
22030 a = target.tags || {},
22031 b = remote.tags || {},
22032 keys = _.reject(_.union(_.keys(o), _.keys(a), _.keys(b)), ignoreKey),
22036 for (var i = 0; i < keys.length; i++) {
22039 if (o[k] !== b[k] && a[k] !== b[k]) { // changed remotely..
22040 if (o[k] !== a[k]) { // changed locally..
22041 conflicts.push(t('merge_remote_changes.conflict.tags',
22042 { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
22044 } else { // unchanged locally, accept remote change..
22045 if (b.hasOwnProperty(k)) {
22055 return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
22059 // `graph.base()` is the common ancestor of the two graphs.
22060 // `localGraph` contains user's edits up to saving
22061 // `remoteGraph` contains remote edits to modified nodes
22062 // `graph` must be a descendent of `localGraph` and may include
22063 // some conflict resolution actions performed on it.
22065 // --- ... --- `localGraph` -- ... -- `graph`
22067 // `graph.base()` --- ... --- `remoteGraph`
22069 var action = function(graph) {
22070 var updates = { replacements: [], removeIds: [] },
22071 base = graph.base().entities[id],
22072 local = localGraph.entity(id),
22073 remote = remoteGraph.entity(id),
22074 target = iD.Entity(local, { version: remote.version });
22077 if (!remote.visible) {
22078 if (option === 'force_remote') {
22079 return iD.actions.DeleteMultiple([id])(graph);
22081 } else if (option === 'force_local') {
22082 if (target.type === 'way') {
22083 target = mergeChildren(target, _.uniq(local.nodes), updates, graph);
22084 graph = updateChildren(updates, graph);
22086 return graph.replace(target);
22089 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
22090 return graph; // do nothing
22095 if (target.type === 'node') {
22096 target = mergeLocation(remote, target);
22098 } else if (target.type === 'way') {
22099 // pull in any child nodes that may not be present locally..
22100 graph.rebase(remoteGraph.childNodes(remote), [graph], false);
22101 target = mergeNodes(base, remote, target);
22102 target = mergeChildren(target, _.union(local.nodes, remote.nodes), updates, graph);
22104 } else if (target.type === 'relation') {
22105 target = mergeMembers(remote, target);
22108 target = mergeTags(base, remote, target);
22110 if (!conflicts.length) {
22111 graph = updateChildren(updates, graph).replace(target);
22117 action.withOption = function(opt) {
22122 action.conflicts = function() {
22128 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
22129 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
22130 iD.actions.Move = function(moveIds, tryDelta, projection, cache) {
22131 var delta = tryDelta;
22133 function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
22134 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
22136 function setupCache(graph) {
22137 function canMove(nodeId) {
22138 var parents = _.pluck(graph.parentWays(graph.entity(nodeId)), 'id');
22139 if (parents.length < 3) return true;
22141 // Don't move a vertex where >2 ways meet, unless all parentWays are moving too..
22142 var parentsMoving = _.all(parents, function(id) { return cache.moving[id]; });
22143 if (!parentsMoving) delete cache.moving[nodeId];
22145 return parentsMoving;
22148 function cacheEntities(ids) {
22149 _.each(ids, function(id) {
22150 if (cache.moving[id]) return;
22151 cache.moving[id] = true;
22153 var entity = graph.hasEntity(id);
22154 if (!entity) return;
22156 if (entity.type === 'node') {
22157 cache.nodes.push(id);
22158 cache.startLoc[id] = entity.loc;
22159 } else if (entity.type === 'way') {
22160 cache.ways.push(id);
22161 cacheEntities(entity.nodes);
22163 cacheEntities(_.pluck(entity.members, 'id'));
22168 function cacheIntersections(ids) {
22169 function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
22171 _.each(ids, function(id) {
22172 // consider only intersections with 1 moved and 1 unmoved way.
22173 _.each(graph.childNodes(graph.entity(id)), function(node) {
22174 var parents = graph.parentWays(node);
22175 if (parents.length !== 2) return;
22177 var moved = graph.entity(id),
22178 unmoved = _.find(parents, function(way) { return !cache.moving[way.id]; });
22179 if (!unmoved) return;
22181 // exclude ways that are overly connected..
22182 if (_.intersection(moved.nodes, unmoved.nodes).length > 2) return;
22184 if (moved.isArea() || unmoved.isArea()) return;
22186 cache.intersection[node.id] = {
22189 unmovedId: unmoved.id,
22190 movedIsEP: isEndpoint(moved, node.id),
22191 unmovedIsEP: isEndpoint(unmoved, node.id)
22203 cache.intersection = {};
22204 cache.replacedVertex = {};
22205 cache.startLoc = {};
22209 cacheEntities(moveIds);
22210 cacheIntersections(cache.ways);
22211 cache.nodes = _.filter(cache.nodes, canMove);
22218 // Place a vertex where the moved vertex used to be, to preserve way shape..
22219 function replaceMovedVertex(nodeId, wayId, graph, delta) {
22220 var way = graph.entity(wayId),
22221 moved = graph.entity(nodeId),
22222 movedIndex = way.nodes.indexOf(nodeId),
22223 len, prevIndex, nextIndex;
22225 if (way.isClosed()) {
22226 len = way.nodes.length - 1;
22227 prevIndex = (movedIndex + len - 1) % len;
22228 nextIndex = (movedIndex + len + 1) % len;
22230 len = way.nodes.length;
22231 prevIndex = movedIndex - 1;
22232 nextIndex = movedIndex + 1;
22235 var prev = graph.hasEntity(way.nodes[prevIndex]),
22236 next = graph.hasEntity(way.nodes[nextIndex]);
22238 // Don't add orig vertex at endpoint..
22239 if (!prev || !next) return graph;
22241 var key = wayId + '_' + nodeId,
22242 orig = cache.replacedVertex[key];
22245 cache.replacedVertex[key] = orig;
22246 cache.startLoc[orig.id] = cache.startLoc[nodeId];
22251 start = projection(cache.startLoc[nodeId]);
22252 end = projection.invert(vecAdd(start, delta));
22254 end = cache.startLoc[nodeId];
22256 orig = orig.move(end);
22258 var angle = Math.abs(iD.geo.angle(orig, prev, projection) -
22259 iD.geo.angle(orig, next, projection)) * 180 / Math.PI;
22261 // Don't add orig vertex if it would just make a straight line..
22262 if (angle > 175 && angle < 185) return graph;
22264 // Don't add orig vertex if another point is already nearby (within 10m)
22265 if (iD.geo.sphericalDistance(prev.loc, orig.loc) < 10 ||
22266 iD.geo.sphericalDistance(orig.loc, next.loc) < 10) return graph;
22268 // moving forward or backward along way?
22269 var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
22270 p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
22271 d1 = iD.geo.pathLength(p1),
22272 d2 = iD.geo.pathLength(p2),
22273 insertAt = (d1 < d2) ? movedIndex : nextIndex;
22275 // moving around closed loop?
22276 if (way.isClosed() && insertAt === 0) insertAt = len;
22278 way = way.addNode(orig.id, insertAt);
22279 return graph.replace(orig).replace(way);
22282 // Reorder nodes around intersections that have moved..
22283 function unZorroIntersection(intersection, graph) {
22284 var vertex = graph.entity(intersection.nodeId),
22285 way1 = graph.entity(intersection.movedId),
22286 way2 = graph.entity(intersection.unmovedId),
22287 isEP1 = intersection.movedIsEP,
22288 isEP2 = intersection.unmovedIsEP;
22290 // don't move the vertex if it is the endpoint of both ways.
22291 if (isEP1 && isEP2) return graph;
22293 var nodes1 = _.without(graph.childNodes(way1), vertex),
22294 nodes2 = _.without(graph.childNodes(way2), vertex);
22296 if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
22297 if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
22299 var edge1 = !isEP1 && iD.geo.chooseEdge(nodes1, projection(vertex.loc), projection),
22300 edge2 = !isEP2 && iD.geo.chooseEdge(nodes2, projection(vertex.loc), projection),
22303 // snap vertex to nearest edge (or some point between them)..
22304 if (!isEP1 && !isEP2) {
22305 var epsilon = 1e-4, maxIter = 10;
22306 for (var i = 0; i < maxIter; i++) {
22307 loc = iD.geo.interp(edge1.loc, edge2.loc, 0.5);
22308 edge1 = iD.geo.chooseEdge(nodes1, projection(loc), projection);
22309 edge2 = iD.geo.chooseEdge(nodes2, projection(loc), projection);
22310 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
22312 } else if (!isEP1) {
22318 graph = graph.replace(vertex.move(loc));
22320 // if zorro happened, reorder nodes..
22321 if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
22322 way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
22323 graph = graph.replace(way1);
22325 if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
22326 way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
22327 graph = graph.replace(way2);
22334 function cleanupIntersections(graph) {
22335 _.each(cache.intersection, function(obj) {
22336 graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
22337 graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
22338 graph = unZorroIntersection(obj, graph);
22344 // check if moving way endpoint can cross an unmoved way, if so limit delta..
22345 function limitDelta(graph) {
22346 _.each(cache.intersection, function(obj) {
22347 if (!obj.movedIsEP) return;
22349 var node = graph.entity(obj.nodeId),
22350 start = projection(node.loc),
22351 end = vecAdd(start, delta),
22352 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
22353 movedPath = _.map(_.pluck(movedNodes, 'loc'),
22354 function(loc) { return vecAdd(projection(loc), delta); }),
22355 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
22356 unmovedPath = _.map(_.pluck(unmovedNodes, 'loc'), projection),
22357 hits = iD.geo.pathIntersections(movedPath, unmovedPath);
22359 for (var i = 0; i < hits.length; i++) {
22360 if (_.isEqual(hits[i], end)) continue;
22361 var edge = iD.geo.chooseEdge(unmovedNodes, end, projection);
22362 delta = vecSub(projection(edge.loc), start);
22368 var action = function(graph) {
22369 if (delta[0] === 0 && delta[1] === 0) return graph;
22373 if (!_.isEmpty(cache.intersection)) {
22377 _.each(cache.nodes, function(id) {
22378 var node = graph.entity(id),
22379 start = projection(node.loc),
22380 end = vecAdd(start, delta);
22381 graph = graph.replace(node.move(projection.invert(end)));
22384 if (!_.isEmpty(cache.intersection)) {
22385 graph = cleanupIntersections(graph);
22391 action.disabled = function(graph) {
22392 function incompleteRelation(id) {
22393 var entity = graph.entity(id);
22394 return entity.type === 'relation' && !entity.isComplete(graph);
22397 if (_.any(moveIds, incompleteRelation))
22398 return 'incomplete_relation';
22401 action.delta = function() {
22407 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
22408 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
22409 iD.actions.MoveNode = function(nodeId, loc) {
22410 return function(graph) {
22411 return graph.replace(graph.entity(nodeId).move(loc));
22414 iD.actions.Noop = function() {
22415 return function(graph) {
22420 * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
22423 iD.actions.Orthogonalize = function(wayId, projection) {
22424 var threshold = 12, // degrees within right or straight to alter
22425 lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
22426 upperThreshold = Math.cos(threshold * Math.PI / 180);
22428 var action = function(graph) {
22429 var way = graph.entity(wayId),
22430 nodes = graph.childNodes(way),
22431 points = _.uniq(nodes).map(function(n) { return projection(n.loc); }),
22432 corner = {i: 0, dotp: 1},
22434 i, j, score, motions;
22436 if (nodes.length === 4) {
22437 for (i = 0; i < 1000; i++) {
22438 motions = points.map(calcMotion);
22439 points[corner.i] = addPoints(points[corner.i],motions[corner.i]);
22440 score = corner.dotp;
22441 if (score < epsilon) {
22446 graph = graph.replace(graph.entity(nodes[corner.i].id)
22447 .move(projection.invert(points[corner.i])));
22450 originalPoints = _.clone(points);
22453 for (i = 0; i < 1000; i++) {
22454 motions = points.map(calcMotion);
22455 for (j = 0; j < motions.length; j++) {
22456 points[j] = addPoints(points[j],motions[j]);
22458 var newScore = squareness(points);
22459 if (newScore < score) {
22460 best = _.clone(points);
22463 if (score < epsilon) {
22470 for (i = 0; i < points.length; i++) {
22471 // only move the points that actually moved
22472 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
22473 graph = graph.replace(graph.entity(nodes[i].id)
22474 .move(projection.invert(points[i])));
22478 // remove empty nodes on straight sections
22479 for (i = 0; i < points.length; i++) {
22480 var node = nodes[i];
22482 if (graph.parentWays(node).length > 1 ||
22483 graph.parentRelations(node).length ||
22484 node.hasInterestingTags()) {
22489 var dotp = normalizedDotProduct(i, points);
22490 if (dotp < -1 + epsilon) {
22491 graph = iD.actions.DeleteNode(nodes[i].id)(graph);
22498 function calcMotion(b, i, array) {
22499 var a = array[(i - 1 + array.length) % array.length],
22500 c = array[(i + 1) % array.length],
22501 p = subtractPoints(a, b),
22502 q = subtractPoints(c, b),
22505 scale = 2 * Math.min(iD.geo.euclideanDistance(p, [0, 0]), iD.geo.euclideanDistance(q, [0, 0]));
22506 p = normalizePoint(p, 1.0);
22507 q = normalizePoint(q, 1.0);
22509 dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
22511 // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
22512 if (array.length > 3) {
22513 if (dotp < -0.707106781186547) {
22516 } else if (dotp && Math.abs(dotp) < corner.dotp) {
22518 corner.dotp = Math.abs(dotp);
22521 return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
22525 function squareness(points) {
22526 return points.reduce(function(sum, val, i, array) {
22527 var dotp = normalizedDotProduct(i, array);
22529 dotp = filterDotProduct(dotp);
22530 return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
22534 function normalizedDotProduct(i, points) {
22535 var a = points[(i - 1 + points.length) % points.length],
22537 c = points[(i + 1) % points.length],
22538 p = subtractPoints(a, b),
22539 q = subtractPoints(c, b);
22541 p = normalizePoint(p, 1.0);
22542 q = normalizePoint(q, 1.0);
22544 return p[0] * q[0] + p[1] * q[1];
22547 function subtractPoints(a, b) {
22548 return [a[0] - b[0], a[1] - b[1]];
22551 function addPoints(a, b) {
22552 return [a[0] + b[0], a[1] + b[1]];
22555 function normalizePoint(point, scale) {
22556 var vector = [0, 0];
22557 var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
22558 if (length !== 0) {
22559 vector[0] = point[0] / length;
22560 vector[1] = point[1] / length;
22563 vector[0] *= scale;
22564 vector[1] *= scale;
22569 function filterDotProduct(dotp) {
22570 if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
22577 action.disabled = function(graph) {
22578 var way = graph.entity(wayId),
22579 nodes = graph.childNodes(way),
22580 points = _.uniq(nodes).map(function(n) { return projection(n.loc); });
22582 if (squareness(points)) {
22586 return 'not_squarish';
22591 // Create a restriction relation for `turn`, which must have the following structure:
22594 // from: { node: <node ID>, way: <way ID> },
22595 // via: { node: <node ID> },
22596 // to: { node: <node ID>, way: <way ID> },
22597 // restriction: <'no_right_turn', 'no_left_turn', etc.>
22600 // This specifies a restriction of type `restriction` when traveling from
22601 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
22602 // (The action does not check that these entities form a valid intersection.)
22604 // If `restriction` is not provided, it is automatically determined by
22605 // iD.geo.inferRestriction.
22607 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
22608 // and `to.node` are used to determine which portion of the split ways become
22609 // members of the restriction.
22611 // For testing convenience, accepts an ID to assign to the new relation.
22612 // Normally, this will be undefined and the relation will automatically
22613 // be assigned a new ID.
22615 iD.actions.RestrictTurn = function(turn, projection, restrictionId) {
22616 return function(graph) {
22617 var from = graph.entity(turn.from.way),
22618 via = graph.entity(turn.via.node),
22619 to = graph.entity(turn.to.way);
22621 function isClosingNode(way, nodeId) {
22622 return nodeId === way.first() && nodeId === way.last();
22625 function split(toOrFrom) {
22626 var newID = toOrFrom.newID || iD.Way().id;
22627 graph = iD.actions.Split(via.id, [newID])
22628 .limitWays([toOrFrom.way])(graph);
22630 var a = graph.entity(newID),
22631 b = graph.entity(toOrFrom.way);
22633 if (a.nodes.indexOf(toOrFrom.node) !== -1) {
22640 if (!from.affix(via.id) || isClosingNode(from, via.id)) {
22641 if (turn.from.node === turn.to.node) {
22643 from = to = split(turn.from)[0];
22644 } else if (turn.from.way === turn.to.way) {
22645 // Straight-on or circular
22646 var s = split(turn.from);
22651 from = split(turn.from)[0];
22655 if (!to.affix(via.id) || isClosingNode(to, via.id)) {
22656 to = split(turn.to)[0];
22659 return graph.replace(iD.Relation({
22662 type: 'restriction',
22663 restriction: turn.restriction ||
22664 iD.geo.inferRestriction(
22672 {id: from.id, type: 'way', role: 'from'},
22673 {id: via.id, type: 'node', role: 'via'},
22674 {id: to.id, type: 'way', role: 'to'}
22680 Order the nodes of a way in reverse order and reverse any direction dependent tags
22681 other than `oneway`. (We assume that correcting a backwards oneway is the primary
22682 reason for reversing a way.)
22684 The following transforms are performed:
22687 *:right=* ⟺ *:left=*
22688 *:forward=* ⟺ *:backward=*
22689 direction=up ⟺ direction=down
22690 incline=up ⟺ incline=down
22694 role=forward ⟺ role=backward
22695 role=north ⟺ role=south
22696 role=east ⟺ role=west
22698 In addition, numeric-valued `incline` tags are negated.
22700 The JOSM implementation was used as a guide, but transformations that were of unclear benefit
22701 or adjusted tags that don't seem to be used in practice were omitted.
22704 http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
22705 http://wiki.openstreetmap.org/wiki/Key:direction#Steps
22706 http://wiki.openstreetmap.org/wiki/Key:incline
22707 http://wiki.openstreetmap.org/wiki/Route#Members
22708 http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
22710 iD.actions.Reverse = function(wayId, options) {
22711 var replacements = [
22712 [/:right$/, ':left'], [/:left$/, ':right'],
22713 [/:forward$/, ':backward'], [/:backward$/, ':forward']
22715 numeric = /^([+\-]?)(?=[\d.])/,
22717 forward: 'backward',
22718 backward: 'forward',
22725 function reverseKey(key) {
22726 for (var i = 0; i < replacements.length; ++i) {
22727 var replacement = replacements[i];
22728 if (replacement[0].test(key)) {
22729 return key.replace(replacement[0], replacement[1]);
22735 function reverseValue(key, value) {
22736 if (key === 'incline' && numeric.test(value)) {
22737 return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
22738 } else if (key === 'incline' || key === 'direction') {
22739 return {up: 'down', down: 'up'}[value] || value;
22740 } else if (options && options.reverseOneway && key === 'oneway') {
22741 return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
22743 return {left: 'right', right: 'left'}[value] || value;
22747 return function(graph) {
22748 var way = graph.entity(wayId),
22749 nodes = way.nodes.slice().reverse(),
22750 tags = {}, key, role;
22752 for (key in way.tags) {
22753 tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
22756 graph.parentRelations(way).forEach(function(relation) {
22757 relation.members.forEach(function(member, index) {
22758 if (member.id === way.id && (role = roleReversals[member.role])) {
22759 relation = relation.updateMember({role: role}, index);
22760 graph = graph.replace(relation);
22765 return graph.replace(way.update({nodes: nodes, tags: tags}));
22768 iD.actions.Revert = function(id) {
22770 var action = function(graph) {
22771 var entity = graph.hasEntity(id),
22772 base = graph.base().entities[id];
22774 if (entity && !base) { // entity will be removed..
22775 if (entity.type === 'node') {
22776 graph.parentWays(entity)
22777 .forEach(function(parent) {
22778 parent = parent.removeNode(id);
22779 graph = graph.replace(parent);
22781 if (parent.isDegenerate()) {
22782 graph = iD.actions.DeleteWay(parent.id)(graph);
22787 graph.parentRelations(entity)
22788 .forEach(function(parent) {
22789 parent = parent.removeMembersWithID(id);
22790 graph = graph.replace(parent);
22792 if (parent.isDegenerate()) {
22793 graph = iD.actions.DeleteRelation(parent.id)(graph);
22798 return graph.revert(id);
22803 iD.actions.RotateWay = function(wayId, pivot, angle, projection) {
22804 return function(graph) {
22805 return graph.update(function(graph) {
22806 var way = graph.entity(wayId);
22808 _.unique(way.nodes).forEach(function(id) {
22810 var node = graph.entity(id),
22811 point = projection(node.loc),
22814 radial[0] = point[0] - pivot[0];
22815 radial[1] = point[1] - pivot[1];
22818 radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + pivot[0],
22819 radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + pivot[1]
22822 graph = graph.replace(node.move(projection.invert(point)));
22829 // Split a way at the given node.
22831 // Optionally, split only the given ways, if multiple ways share
22834 // This is the inverse of `iD.actions.Join`.
22836 // For testing convenience, accepts an ID to assign to the new way.
22837 // Normally, this will be undefined and the way will automatically
22838 // be assigned a new ID.
22841 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
22843 iD.actions.Split = function(nodeId, newWayIds) {
22846 // if the way is closed, we need to search for a partner node
22847 // to split the way at.
22849 // The following looks for a node that is both far away from
22850 // the initial node in terms of way segment length and nearby
22851 // in terms of beeline-distance. This assures that areas get
22852 // split on the most "natural" points (independent of the number
22854 // For example: bone-shaped areas get split across their waist
22855 // line, circles across the diameter.
22856 function splitArea(nodes, idxA, graph) {
22857 var lengths = new Array(nodes.length),
22863 function wrap(index) {
22864 return iD.util.wrap(index, nodes.length);
22867 function dist(nA, nB) {
22868 return iD.geo.sphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
22871 // calculate lengths
22873 for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
22874 length += dist(nodes[i], nodes[wrap(i-1)]);
22875 lengths[i] = length;
22879 for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
22880 length += dist(nodes[i], nodes[wrap(i+1)]);
22881 if (length < lengths[i])
22882 lengths[i] = length;
22885 // determine best opposite node to split
22886 for (i = 0; i < nodes.length; i++) {
22887 var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
22897 function split(graph, wayA, newWayId) {
22898 var wayB = iD.Way({id: newWayId, tags: wayA.tags}),
22901 isArea = wayA.isArea(),
22902 isOuter = iD.geo.isSimpleMultipolygonOuterMember(wayA, graph);
22904 if (wayA.isClosed()) {
22905 var nodes = wayA.nodes.slice(0, -1),
22906 idxA = _.indexOf(nodes, nodeId),
22907 idxB = splitArea(nodes, idxA, graph);
22910 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
22911 nodesB = nodes.slice(idxB, idxA + 1);
22913 nodesA = nodes.slice(idxA, idxB + 1);
22914 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
22917 var idx = _.indexOf(wayA.nodes, nodeId, 1);
22918 nodesA = wayA.nodes.slice(0, idx + 1);
22919 nodesB = wayA.nodes.slice(idx);
22922 wayA = wayA.update({nodes: nodesA});
22923 wayB = wayB.update({nodes: nodesB});
22925 graph = graph.replace(wayA);
22926 graph = graph.replace(wayB);
22928 graph.parentRelations(wayA).forEach(function(relation) {
22929 if (relation.isRestriction()) {
22930 var via = relation.memberByRole('via');
22931 if (via && wayB.contains(via.id)) {
22932 relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
22933 graph = graph.replace(relation);
22936 if (relation === isOuter) {
22937 graph = graph.replace(relation.mergeTags(wayA.tags));
22938 graph = graph.replace(wayA.update({tags: {}}));
22939 graph = graph.replace(wayB.update({tags: {}}));
22945 role: relation.memberById(wayA.id).role
22948 graph = iD.actions.AddMember(relation.id, member)(graph);
22952 if (!isOuter && isArea) {
22953 var multipolygon = iD.Relation({
22954 tags: _.extend({}, wayA.tags, {type: 'multipolygon'}),
22956 {id: wayA.id, role: 'outer', type: 'way'},
22957 {id: wayB.id, role: 'outer', type: 'way'}
22960 graph = graph.replace(multipolygon);
22961 graph = graph.replace(wayA.update({tags: {}}));
22962 graph = graph.replace(wayB.update({tags: {}}));
22968 var action = function(graph) {
22969 var candidates = action.ways(graph);
22970 for (var i = 0; i < candidates.length; i++) {
22971 graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
22976 action.ways = function(graph) {
22977 var node = graph.entity(nodeId),
22978 parents = graph.parentWays(node),
22979 hasLines = _.any(parents, function(parent) { return parent.geometry(graph) === 'line'; });
22981 return parents.filter(function(parent) {
22982 if (wayIds && wayIds.indexOf(parent.id) === -1)
22985 if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
22988 if (parent.isClosed()) {
22992 for (var i = 1; i < parent.nodes.length - 1; i++) {
22993 if (parent.nodes[i] === nodeId) {
23002 action.disabled = function(graph) {
23003 var candidates = action.ways(graph);
23004 if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
23005 return 'not_eligible';
23008 action.limitWays = function(_) {
23009 if (!arguments.length) return wayIds;
23017 * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
23020 iD.actions.Straighten = function(wayId, projection) {
23021 function positionAlongWay(n, s, e) {
23022 return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1]))/
23023 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
23026 var action = function(graph) {
23027 var way = graph.entity(wayId),
23028 nodes = graph.childNodes(way),
23029 points = nodes.map(function(n) { return projection(n.loc); }),
23030 startPoint = points[0],
23031 endPoint = points[points.length-1],
23035 for (i = 1; i < points.length-1; i++) {
23036 var node = nodes[i],
23039 if (graph.parentWays(node).length > 1 ||
23040 graph.parentRelations(node).length ||
23041 node.hasInterestingTags()) {
23043 var u = positionAlongWay(point, startPoint, endPoint),
23044 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
23045 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]);
23047 graph = graph.replace(graph.entity(node.id)
23048 .move(projection.invert([p0, p1])));
23051 if (toDelete.indexOf(node) === -1) {
23052 toDelete.push(node);
23057 for (i = 0; i < toDelete.length; i++) {
23058 graph = iD.actions.DeleteNode(toDelete[i].id)(graph);
23064 action.disabled = function(graph) {
23065 // check way isn't too bendy
23066 var way = graph.entity(wayId),
23067 nodes = graph.childNodes(way),
23068 points = nodes.map(function(n) { return projection(n.loc); }),
23069 startPoint = points[0],
23070 endPoint = points[points.length-1],
23071 threshold = 0.2 * Math.sqrt(Math.pow(startPoint[0] - endPoint[0], 2) + Math.pow(startPoint[1] - endPoint[1], 2)),
23074 for (i = 1; i < points.length-1; i++) {
23075 var point = points[i],
23076 u = positionAlongWay(point, startPoint, endPoint),
23077 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
23078 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
23079 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
23081 // to bendy if point is off by 20% of total start/end distance in projected space
23082 if (dist > threshold) {
23083 return 'too_bendy';
23090 // Remove the effects of `turn.restriction` on `turn`, which must have the
23091 // following structure:
23094 // from: { node: <node ID>, way: <way ID> },
23095 // via: { node: <node ID> },
23096 // to: { node: <node ID>, way: <way ID> },
23097 // restriction: <relation ID>
23100 // In the simple case, `restriction` is a reference to a `no_*` restriction
23101 // on the turn itself. In this case, it is simply deleted.
23103 // The more complex case is where `restriction` references an `only_*`
23104 // restriction on a different turn in the same intersection. In that case,
23105 // that restriction is also deleted, but at the same time restrictions on
23106 // the turns other than the first two are created.
23108 iD.actions.UnrestrictTurn = function(turn) {
23109 return function(graph) {
23110 return iD.actions.DeleteRelation(turn.restriction)(graph);
23114 iD.behavior.AddWay = function(context) {
23115 var event = d3.dispatch('start', 'startFromWay', 'startFromNode'),
23116 draw = iD.behavior.Draw(context);
23118 var addWay = function(surface) {
23119 draw.on('click', event.start)
23120 .on('clickWay', event.startFromWay)
23121 .on('clickNode', event.startFromNode)
23122 .on('cancel', addWay.cancel)
23123 .on('finish', addWay.cancel);
23126 .dblclickEnable(false);
23128 surface.call(draw);
23131 addWay.off = function(surface) {
23132 surface.call(draw.off);
23135 addWay.cancel = function() {
23136 window.setTimeout(function() {
23137 context.map().dblclickEnable(true);
23140 context.enter(iD.modes.Browse(context));
23143 addWay.tail = function(text) {
23148 return d3.rebind(addWay, event, 'on');
23150 iD.behavior.Breathe = function() {
23151 var duration = 800,
23152 selector = '.selected.shadow, .selected .shadow',
23153 selected = d3.select(null),
23158 function reset(selection) {
23160 .style('stroke-opacity', null)
23161 .style('stroke-width', null)
23162 .style('fill-opacity', null)
23166 function setAnimationParams(transition, fromTo) {
23168 .style('stroke-opacity', function(d) { return params[d.id][fromTo].opacity; })
23169 .style('stroke-width', function(d) { return params[d.id][fromTo].width; })
23170 .style('fill-opacity', function(d) { return params[d.id][fromTo].opacity; })
23171 .style('r', function(d) { return params[d.id][fromTo].width; });
23174 function calcAnimationParams(selection) {
23177 .each(function(d) {
23178 var s = d3.select(this),
23179 tag = s.node().tagName,
23180 p = {'from': {}, 'to': {}},
23183 // determine base opacity and width
23184 if (tag === 'circle') {
23185 opacity = parseFloat(s.style('fill-opacity') || 0.5);
23186 width = parseFloat(s.style('r') || 15.5);
23188 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
23189 width = parseFloat(s.style('stroke-width') || 10);
23192 // calculate from/to interpolation params..
23194 p.from.opacity = opacity * 0.6;
23195 p.to.opacity = opacity * 1.25;
23196 p.from.width = width * 0.9;
23197 p.to.width = width * (tag === 'circle' ? 1.5 : 1.25);
23202 function run(surface, fromTo) {
23203 var toFrom = (fromTo === 'from' ? 'to': 'from'),
23204 currSelected = surface.selectAll(selector),
23205 currClassed = surface.attr('class'),
23208 if (done || currSelected.empty()) {
23209 selected.call(reset);
23213 if (!_.isEqual(currSelected, selected) || currClassed !== classed) {
23214 selected.call(reset);
23215 classed = currClassed;
23216 selected = currSelected.call(calcAnimationParams);
23221 .call(setAnimationParams, fromTo)
23222 .duration(duration)
23223 .each(function() { ++n; })
23224 .each('end', function() {
23225 if (!--n) { // call once
23226 surface.call(run, toFrom);
23231 var breathe = function(surface) {
23233 d3.timer(function() {
23234 if (done) return true;
23236 var currSelected = surface.selectAll(selector);
23237 if (currSelected.empty()) return false;
23239 surface.call(run, 'from');
23244 breathe.off = function() {
23255 iD.behavior.Copy = function(context) {
23256 var keybinding = d3.keybinding('copy');
23258 function groupEntities(ids, graph) {
23259 var entities = ids.map(function (id) { return graph.entity(id); });
23260 return _.extend({relation: [], way: [], node: []},
23261 _.groupBy(entities, function(entity) { return entity.type; }));
23264 function getDescendants(id, graph, descendants) {
23265 var entity = graph.entity(id),
23268 descendants = descendants || {};
23270 if (entity.type === 'relation') {
23271 children = _.pluck(entity.members, 'id');
23272 } else if (entity.type === 'way') {
23273 children = entity.nodes;
23278 for (i = 0; i < children.length; i++) {
23279 if (!descendants[children[i]]) {
23280 descendants[children[i]] = true;
23281 descendants = getDescendants(children[i], graph, descendants);
23285 return descendants;
23288 function doCopy() {
23289 d3.event.preventDefault();
23290 if (context.inIntro()) return;
23292 var graph = context.graph(),
23293 selected = groupEntities(context.selectedIDs(), graph),
23298 for (i = 0; i < selected.relation.length; i++) {
23299 entity = selected.relation[i];
23300 if (!skip[entity.id] && entity.isComplete(graph)) {
23301 canCopy.push(entity.id);
23302 skip = getDescendants(entity.id, graph, skip);
23305 for (i = 0; i < selected.way.length; i++) {
23306 entity = selected.way[i];
23307 if (!skip[entity.id]) {
23308 canCopy.push(entity.id);
23309 skip = getDescendants(entity.id, graph, skip);
23312 for (i = 0; i < selected.node.length; i++) {
23313 entity = selected.node[i];
23314 if (!skip[entity.id]) {
23315 canCopy.push(entity.id);
23319 context.copyIDs(canCopy);
23323 keybinding.on(iD.ui.cmd('⌘C'), doCopy);
23324 d3.select(document).call(keybinding);
23328 copy.off = function() {
23329 d3.select(document).call(keybinding.off);
23335 `iD.behavior.drag` is like `d3.behavior.drag`, with the following differences:
23337 * The `origin` function is expected to return an [x, y] tuple rather than an
23339 * The events are `start`, `move`, and `end`.
23340 (https://github.com/mbostock/d3/issues/563)
23341 * The `start` event is not dispatched until the first cursor movement occurs.
23342 (https://github.com/mbostock/d3/pull/368)
23343 * The `move` event has a `point` and `delta` [x, y] tuple properties rather
23344 than `x`, `y`, `dx`, and `dy` properties.
23345 * The `end` event is not dispatched if no movement occurs.
23346 * An `off` function is available that unbinds the drag's internal event handlers.
23347 * Delegation is supported via the `delegate` function.
23350 iD.behavior.drag = function() {
23351 function d3_eventCancel() {
23352 d3.event.stopPropagation();
23353 d3.event.preventDefault();
23356 var event = d3.dispatch('start', 'move', 'end'),
23360 event_, target, surface;
23362 event.of = function(thiz, argumentz) {
23363 return function(e1) {
23364 var e0 = e1.sourceEvent = d3.event;
23368 event[e1.type].apply(thiz, argumentz);
23375 var d3_event_userSelectProperty = iD.util.prefixCSSProperty('UserSelect'),
23376 d3_event_userSelectSuppress = d3_event_userSelectProperty ?
23378 var selection = d3.selection(),
23379 select = selection.style(d3_event_userSelectProperty);
23380 selection.style(d3_event_userSelectProperty, 'none');
23381 return function () {
23382 selection.style(d3_event_userSelectProperty, select);
23386 var w = d3.select(window).on('selectstart.' + type, d3_eventCancel);
23387 return function () {
23388 w.on('selectstart.' + type, null);
23392 function mousedown() {
23394 event_ = event.of(target, arguments);
23395 var eventTarget = d3.event.target,
23396 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
23400 selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
23402 var w = d3.select(window)
23403 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
23404 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
23407 offset = origin.apply(target, arguments);
23408 offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
23413 if (touchId === null) d3.event.stopPropagation();
23416 var p = target.parentNode || surface;
23417 return touchId !== null ? d3.touches(p).filter(function(p) {
23418 return p.identifier === touchId;
23419 })[0] : d3.mouse(p);
23422 function dragmove() {
23425 dx = p[0] - origin_[0],
23426 dy = p[1] - origin_[1];
23428 if (dx === 0 && dy === 0)
23443 point: [p[0] + offset[0], p[1] + offset[1]],
23448 function dragend() {
23455 if (d3.event.target === eventTarget) w.on('click.drag', click, true);
23458 w.on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
23459 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
23465 w.on('click.drag', null);
23469 function drag(selection) {
23470 var matchesSelector = iD.util.prefixDOMProperty('matchesSelector'),
23471 delegate = mousedown;
23474 delegate = function() {
23476 target = d3.event.target;
23477 for (; target && target !== root; target = target.parentNode) {
23478 if (target[matchesSelector](selector) &&
23479 (!filter || filter(target.__data__))) {
23480 return mousedown.call(target, target.__data__);
23486 selection.on('mousedown.drag' + selector, delegate)
23487 .on('touchstart.drag' + selector, delegate);
23490 drag.off = function(selection) {
23491 selection.on('mousedown.drag' + selector, null)
23492 .on('touchstart.drag' + selector, null);
23495 drag.delegate = function(_) {
23496 if (!arguments.length) return selector;
23501 drag.filter = function(_) {
23502 if (!arguments.length) return origin;
23507 drag.origin = function (_) {
23508 if (!arguments.length) return origin;
23513 drag.cancel = function() {
23515 .on('mousemove.drag', null)
23516 .on('mouseup.drag', null);
23520 drag.target = function() {
23521 if (!arguments.length) return target;
23522 target = arguments[0];
23523 event_ = event.of(target, Array.prototype.slice.call(arguments, 1));
23527 drag.surface = function() {
23528 if (!arguments.length) return surface;
23529 surface = arguments[0];
23533 return d3.rebind(drag, event, 'on');
23535 iD.behavior.Draw = function(context) {
23536 var event = d3.dispatch('move', 'click', 'clickWay',
23537 'clickNode', 'undo', 'cancel', 'finish'),
23538 keybinding = d3.keybinding('draw'),
23539 hover = iD.behavior.Hover(context)
23541 .on('hover', context.ui().sidebar.hover),
23542 tail = iD.behavior.Tail(),
23543 edit = iD.behavior.Edit(context),
23544 closeTolerance = 4,
23548 if (d3.event.altKey) return {};
23549 else return d3.event.target.__data__ || {};
23552 function mousedown() {
23555 var p = context.container().node();
23556 return touchId !== null ? d3.touches(p).filter(function(p) {
23557 return p.identifier === touchId;
23558 })[0] : d3.mouse(p);
23561 var element = d3.select(this),
23562 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
23566 element.on('mousemove.draw', null);
23568 d3.select(window).on('mouseup.draw', function() {
23569 var t2 = +new Date(),
23571 dist = iD.geo.euclideanDistance(p1, p2);
23573 element.on('mousemove.draw', mousemove);
23574 d3.select(window).on('mouseup.draw', null);
23576 if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
23577 // Prevent a quick second click
23578 d3.select(window).on('click.draw-block', function() {
23579 d3.event.stopPropagation();
23582 context.map().dblclickEnable(false);
23584 window.setTimeout(function() {
23585 context.map().dblclickEnable(true);
23586 d3.select(window).on('click.draw-block', null);
23594 function mousemove() {
23595 event.move(datum());
23600 if (d.type === 'way') {
23601 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection),
23602 edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
23603 event.clickWay(choice.loc, edge);
23605 } else if (d.type === 'node') {
23606 event.clickNode(d);
23609 event.click(context.map().mouseCoordinates());
23613 function backspace() {
23614 d3.event.preventDefault();
23619 d3.event.preventDefault();
23624 d3.event.preventDefault();
23628 function draw(selection) {
23629 context.install(hover);
23630 context.install(edit);
23632 if (!context.inIntro() && !iD.behavior.Draw.usedTails[tail.text()]) {
23633 context.install(tail);
23637 .on('⌫', backspace)
23643 .on('mousedown.draw', mousedown)
23644 .on('mousemove.draw', mousemove);
23646 d3.select(document)
23652 draw.off = function(selection) {
23653 context.ui().sidebar.hover.cancel();
23654 context.uninstall(hover);
23655 context.uninstall(edit);
23657 if (!context.inIntro() && !iD.behavior.Draw.usedTails[tail.text()]) {
23658 context.uninstall(tail);
23659 iD.behavior.Draw.usedTails[tail.text()] = true;
23663 .on('mousedown.draw', null)
23664 .on('mousemove.draw', null);
23667 .on('mouseup.draw', null);
23669 d3.select(document)
23670 .call(keybinding.off);
23673 draw.tail = function(_) {
23678 return d3.rebind(draw, event, 'on');
23681 iD.behavior.Draw.usedTails = {};
23682 iD.behavior.DrawWay = function(context, wayId, index, mode, baseGraph) {
23683 var way = context.entity(wayId),
23684 isArea = context.geometry(wayId) === 'area',
23686 annotation = t((way.isDegenerate() ?
23687 'operations.start.annotation.' :
23688 'operations.continue.annotation.') + context.geometry(wayId)),
23689 draw = iD.behavior.Draw(context);
23691 var startIndex = typeof index === 'undefined' ? way.nodes.length - 1 : 0,
23692 start = iD.Node({loc: context.graph().entity(way.nodes[startIndex]).loc}),
23693 end = iD.Node({loc: context.map().mouseCoordinates()}),
23695 nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
23696 tags: _.clone(way.tags)
23699 var f = context[way.isDegenerate() ? 'replace' : 'perform'];
23701 f(iD.actions.AddEntity(end),
23702 iD.actions.AddVertex(wayId, end.id, index));
23704 f(iD.actions.AddEntity(start),
23705 iD.actions.AddEntity(end),
23706 iD.actions.AddEntity(segment));
23709 function move(datum) {
23712 if (datum.type === 'node' && datum.id !== end.id) {
23714 } else if (datum.type === 'way' && datum.id !== segment.id) {
23715 loc = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
23717 loc = context.map().mouseCoordinates();
23720 context.replace(iD.actions.MoveNode(end.id, loc));
23723 function undone() {
23725 context.enter(iD.modes.Browse(context));
23728 function setActiveElements() {
23729 var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
23730 context.surface().selectAll(iD.util.entitySelector(active))
23731 .classed('active', true);
23734 var drawWay = function(surface) {
23735 draw.on('move', move)
23736 .on('click', drawWay.add)
23737 .on('clickWay', drawWay.addWay)
23738 .on('clickNode', drawWay.addNode)
23739 .on('undo', context.undo)
23740 .on('cancel', drawWay.cancel)
23741 .on('finish', drawWay.finish);
23744 .dblclickEnable(false)
23745 .on('drawn.draw', setActiveElements);
23747 setActiveElements();
23749 surface.call(draw);
23752 .on('undone.draw', undone);
23755 drawWay.off = function(surface) {
23760 .on('drawn.draw', null);
23762 surface.call(draw.off)
23763 .selectAll('.active')
23764 .classed('active', false);
23767 .on('undone.draw', null);
23770 function ReplaceTemporaryNode(newNode) {
23771 return function(graph) {
23774 .replace(way.addNode(newNode.id, index))
23779 .replace(graph.entity(wayId).addNode(newNode.id, index))
23787 // Accept the current position of the temporary node and continue drawing.
23788 drawWay.add = function(loc) {
23790 // prevent duplicate nodes
23791 var last = context.hasEntity(way.nodes[way.nodes.length - (isArea ? 2 : 1)]);
23792 if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
23794 var newNode = iD.Node({loc: loc});
23797 iD.actions.AddEntity(newNode),
23798 ReplaceTemporaryNode(newNode),
23802 context.enter(mode);
23805 // Connect the way to an existing way.
23806 drawWay.addWay = function(loc, edge) {
23807 var previousEdge = startIndex ?
23808 [way.nodes[startIndex], way.nodes[startIndex - 1]] :
23809 [way.nodes[0], way.nodes[1]];
23811 // Avoid creating duplicate segments
23812 if (!isArea && iD.geo.edgeEqual(edge, previousEdge))
23815 var newNode = iD.Node({ loc: loc });
23818 iD.actions.AddMidpoint({ loc: loc, edge: edge}, newNode),
23819 ReplaceTemporaryNode(newNode),
23823 context.enter(mode);
23826 // Connect the way to an existing node and continue drawing.
23827 drawWay.addNode = function(node) {
23829 // Avoid creating duplicate segments
23830 if (way.areAdjacent(node.id, way.nodes[way.nodes.length - 1])) return;
23833 ReplaceTemporaryNode(node),
23837 context.enter(mode);
23840 // Finish the draw operation, removing the temporary node. If the way has enough
23841 // nodes to be valid, it's selected. Otherwise, return to browse mode.
23842 drawWay.finish = function() {
23846 window.setTimeout(function() {
23847 context.map().dblclickEnable(true);
23850 if (context.hasEntity(wayId)) {
23852 iD.modes.Select(context, [wayId])
23853 .suppressMenu(true)
23854 .newFeature(true));
23856 context.enter(iD.modes.Browse(context));
23860 // Cancel the draw operation and return to browse, deleting everything drawn.
23861 drawWay.cancel = function() {
23863 d3.functor(baseGraph),
23864 t('operations.cancel_draw.annotation'));
23866 window.setTimeout(function() {
23867 context.map().dblclickEnable(true);
23871 context.enter(iD.modes.Browse(context));
23874 drawWay.tail = function(text) {
23881 iD.behavior.Edit = function(context) {
23884 .minzoom(context.minEditableZoom());
23887 edit.off = function() {
23894 iD.behavior.Hash = function(context) {
23895 var s0 = null, // cached location.hash
23896 lat = 90 - 1e-8; // allowable latitude range
23898 var parser = function(map, s) {
23899 var q = iD.util.stringQs(s);
23900 var args = (q.map || '').split('/').map(Number);
23901 if (args.length < 3 || args.some(isNaN)) {
23902 return true; // replace bogus hash
23903 } else if (s !== formatter(map).slice(1)) {
23904 map.centerZoom([args[1],
23905 Math.min(lat, Math.max(-lat, args[2]))], args[0]);
23909 var formatter = function(map) {
23910 var mode = context.mode(),
23911 center = map.center(),
23913 precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)),
23914 q = _.omit(iD.util.stringQs(location.hash.substring(1)), 'comment'),
23917 if (mode && mode.id === 'browse') {
23920 var selected = context.selectedIDs().filter(function(id) {
23921 return !context.entity(id).isNew();
23923 if (selected.length) {
23924 newParams.id = selected.join(',');
23928 newParams.map = zoom.toFixed(2) +
23929 '/' + center[0].toFixed(precision) +
23930 '/' + center[1].toFixed(precision);
23932 return '#' + iD.util.qsString(_.assign(q, newParams), true);
23935 function update() {
23936 if (context.inIntro()) return;
23937 var s1 = formatter(context.map());
23938 if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map!
23941 var throttledUpdate = _.throttle(update, 500);
23943 function hashchange() {
23944 if (location.hash === s0) return; // ignore spurious hashchange events
23945 if (parser(context.map(), (s0 = location.hash).substring(1))) {
23946 update(); // replace bogus hash
23952 .on('move.hash', throttledUpdate);
23955 .on('enter.hash', throttledUpdate);
23958 .on('hashchange.hash', hashchange);
23960 if (location.hash) {
23961 var q = iD.util.stringQs(location.hash.substring(1));
23962 if (q.id) context.zoomToEntity(q.id.split(',')[0], !q.map);
23963 if (q.comment) context.storage('comment', q.comment);
23965 if (q.map) hash.hadHash = true;
23969 hash.off = function() {
23970 throttledUpdate.cancel();
23973 .on('move.hash', null);
23976 .on('enter.hash', null);
23979 .on('hashchange.hash', null);
23981 location.hash = '';
23987 The hover behavior adds the `.hover` class on mouseover to all elements to which
23988 the identical datum is bound, and removes it on mouseout.
23990 The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
23991 representation may consist of several elements scattered throughout the DOM hierarchy.
23992 Only one of these elements can have the :hover pseudo-class, but all of them will
23993 have the .hover class.
23995 iD.behavior.Hover = function() {
23996 var dispatch = d3.dispatch('hover'),
24001 function keydown() {
24002 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
24003 dispatch.hover(null);
24004 selection.selectAll('.hover')
24005 .classed('hover-suppressed', true)
24006 .classed('hover', false);
24011 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
24012 dispatch.hover(target ? target.id : null);
24013 selection.selectAll('.hover-suppressed')
24014 .classed('hover-suppressed', false)
24015 .classed('hover', true);
24019 var hover = function(__) {
24022 function enter(d) {
24023 if (d === target) return;
24027 selection.selectAll('.hover')
24028 .classed('hover', false);
24029 selection.selectAll('.hover-suppressed')
24030 .classed('hover-suppressed', false);
24032 if (target instanceof iD.Entity) {
24033 var selector = '.' + target.id;
24035 if (target.type === 'relation') {
24036 target.members.forEach(function(member) {
24037 selector += ', .' + member.id;
24041 var suppressed = altDisables && d3.event && d3.event.altKey;
24043 selection.selectAll(selector)
24044 .classed(suppressed ? 'hover-suppressed' : 'hover', true);
24046 dispatch.hover(target.id);
24048 dispatch.hover(null);
24054 function mouseover() {
24056 var target = d3.event.target;
24057 enter(target ? target.__data__ : null);
24060 function mouseout() {
24062 var target = d3.event.relatedTarget;
24063 enter(target ? target.__data__ : null);
24066 function mousedown() {
24069 .on('mouseup.hover', mouseup);
24072 function mouseup() {
24077 .on('mouseover.hover', mouseover)
24078 .on('mouseout.hover', mouseout)
24079 .on('mousedown.hover', mousedown)
24080 .on('mouseup.hover', mouseup);
24083 .on('keydown.hover', keydown)
24084 .on('keyup.hover', keyup);
24087 hover.off = function(selection) {
24088 selection.selectAll('.hover')
24089 .classed('hover', false);
24090 selection.selectAll('.hover-suppressed')
24091 .classed('hover-suppressed', false);
24094 .on('mouseover.hover', null)
24095 .on('mouseout.hover', null)
24096 .on('mousedown.hover', null)
24097 .on('mouseup.hover', null);
24100 .on('keydown.hover', null)
24101 .on('keyup.hover', null)
24102 .on('mouseup.hover', null);
24105 hover.altDisables = function(_) {
24106 if (!arguments.length) return altDisables;
24111 return d3.rebind(hover, dispatch, 'on');
24113 iD.behavior.Lasso = function(context) {
24115 var behavior = function(selection) {
24118 function mousedown() {
24119 var button = 0; // left
24120 if (d3.event.button === button && d3.event.shiftKey === true) {
24124 .on('mousemove.lasso', mousemove)
24125 .on('mouseup.lasso', mouseup);
24127 d3.event.stopPropagation();
24131 function mousemove() {
24133 lasso = iD.ui.Lasso(context);
24134 context.surface().call(lasso);
24137 lasso.p(context.mouse());
24140 function normalize(a, b) {
24142 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
24143 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
24146 function lassoed() {
24147 if (!lasso) return [];
24149 var graph = context.graph(),
24150 bounds = lasso.extent().map(context.projection.invert),
24151 extent = iD.geo.Extent(normalize(bounds[0], bounds[1]));
24153 return _.pluck(context.intersects(extent).filter(function(entity) {
24154 return entity.type === 'node' &&
24155 iD.geo.pointInPolygon(context.projection(entity.loc), lasso.coordinates) &&
24156 !context.features().isHidden(entity, graph, entity.geometry(graph));
24160 function mouseup() {
24162 .on('mousemove.lasso', null)
24163 .on('mouseup.lasso', null);
24165 if (!lasso) return;
24167 var ids = lassoed();
24171 context.enter(iD.modes.Select(context, ids));
24176 .on('mousedown.lasso', mousedown);
24179 behavior.off = function(selection) {
24180 selection.on('mousedown.lasso', null);
24185 iD.behavior.Paste = function(context) {
24186 var keybinding = d3.keybinding('paste');
24188 function omitTag(v, k) {
24196 k === 'description' ||
24197 k.indexOf('name') !== -1 ||
24198 k.indexOf('wiki') === 0 ||
24199 k.indexOf('addr:') === 0 ||
24200 k.indexOf('contact:') === 0
24204 function doPaste() {
24205 d3.event.preventDefault();
24206 if (context.inIntro()) return;
24208 var baseGraph = context.graph(),
24209 mouse = context.mouse(),
24210 projection = context.projection,
24211 viewport = iD.geo.Extent(projection.clipExtent()).polygon();
24213 if (!iD.geo.pointInPolygon(mouse, viewport)) return;
24215 var extent = iD.geo.Extent(),
24216 oldIDs = context.copyIDs(),
24217 oldGraph = context.copyGraph(),
24220 if (!oldIDs.length) return;
24222 var action = iD.actions.CopyEntities(oldIDs, oldGraph);
24223 context.perform(action);
24225 var copies = action.copies();
24226 for (var id in copies) {
24227 var oldEntity = oldGraph.entity(id),
24228 newEntity = copies[id];
24230 extent._extend(oldEntity.extent(oldGraph));
24231 newIDs.push(newEntity.id);
24232 context.perform(iD.actions.ChangeTags(newEntity.id, _.omit(newEntity.tags, omitTag)));
24235 // Put pasted objects where mouse pointer is..
24236 var center = projection(extent.center()),
24237 delta = [ mouse[0] - center[0], mouse[1] - center[1] ];
24239 context.perform(iD.actions.Move(newIDs, delta, projection));
24240 context.enter(iD.modes.Move(context, newIDs, baseGraph));
24244 keybinding.on(iD.ui.cmd('⌘V'), doPaste);
24245 d3.select(document).call(keybinding);
24249 paste.off = function() {
24250 d3.select(document).call(keybinding.off);
24255 iD.behavior.Select = function(context) {
24256 function keydown() {
24257 if (d3.event && d3.event.shiftKey) {
24259 .classed('behavior-multiselect', true);
24264 if (!d3.event || !d3.event.shiftKey) {
24266 .classed('behavior-multiselect', false);
24271 var datum = d3.event.target.__data__,
24272 lasso = d3.select('#surface .lasso').node(),
24273 mode = context.mode();
24275 if (!(datum instanceof iD.Entity)) {
24276 if (!d3.event.shiftKey && !lasso && mode.id !== 'browse')
24277 context.enter(iD.modes.Browse(context));
24279 } else if (!d3.event.shiftKey && !lasso) {
24280 // Avoid re-entering Select mode with same entity.
24281 if (context.selectedIDs().length !== 1 || context.selectedIDs()[0] !== datum.id) {
24282 context.enter(iD.modes.Select(context, [datum.id]));
24284 mode.suppressMenu(false).reselect();
24286 } else if (context.selectedIDs().indexOf(datum.id) >= 0) {
24287 var selectedIDs = _.without(context.selectedIDs(), datum.id);
24288 context.enter(selectedIDs.length ?
24289 iD.modes.Select(context, selectedIDs) :
24290 iD.modes.Browse(context));
24293 context.enter(iD.modes.Select(context, context.selectedIDs().concat([datum.id])));
24297 var behavior = function(selection) {
24299 .on('keydown.select', keydown)
24300 .on('keyup.select', keyup);
24302 selection.on('click.select', click);
24307 behavior.off = function(selection) {
24309 .on('keydown.select', null)
24310 .on('keyup.select', null);
24312 selection.on('click.select', null);
24319 iD.behavior.Tail = function() {
24323 tooltipSize = [0, 0],
24324 selectionSize = [0, 0];
24326 function tail(selection) {
24330 .on('resize.tail', function() { selectionSize = selection.dimensions(); });
24333 container.style('display', 'block');
24334 tooltipSize = container.dimensions();
24337 function mousemove() {
24338 if (container.style('display') === 'none') show();
24339 var xoffset = ((d3.event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
24340 -tooltipSize[0] - xmargin : xmargin;
24341 container.classed('left', xoffset > 0);
24342 iD.util.setTransform(container, d3.event.clientX + xoffset, d3.event.clientY);
24345 function mouseleave() {
24346 if (d3.event.relatedTarget !== container.node()) {
24347 container.style('display', 'none');
24351 function mouseenter() {
24352 if (d3.event.relatedTarget !== container.node()) {
24357 container = d3.select(document.body)
24359 .style('display', 'none')
24360 .attr('class', 'tail tooltip-inner');
24362 container.append('div')
24366 .on('mousemove.tail', mousemove)
24367 .on('mouseenter.tail', mouseenter)
24368 .on('mouseleave.tail', mouseleave);
24371 .on('mousemove.tail', mousemove);
24373 tooltipSize = container.dimensions();
24374 selectionSize = selection.dimensions();
24377 tail.off = function(selection) {
24381 .on('mousemove.tail', null)
24385 .on('mousemove.tail', null)
24386 .on('mouseenter.tail', null)
24387 .on('mouseleave.tail', null);
24390 .on('resize.tail', null);
24393 tail.text = function(_) {
24394 if (!arguments.length) return text;
24402 iD.modes.AddArea = function(context) {
24406 title: t('modes.add_area.title'),
24407 description: t('modes.add_area.description'),
24411 var behavior = iD.behavior.AddWay(context)
24412 .tail(t('modes.add_area.tail'))
24413 .on('start', start)
24414 .on('startFromWay', startFromWay)
24415 .on('startFromNode', startFromNode),
24416 defaultTags = {area: 'yes'};
24418 function start(loc) {
24419 var graph = context.graph(),
24420 node = iD.Node({loc: loc}),
24421 way = iD.Way({tags: defaultTags});
24424 iD.actions.AddEntity(node),
24425 iD.actions.AddEntity(way),
24426 iD.actions.AddVertex(way.id, node.id),
24427 iD.actions.AddVertex(way.id, node.id));
24429 context.enter(iD.modes.DrawArea(context, way.id, graph));
24432 function startFromWay(loc, edge) {
24433 var graph = context.graph(),
24434 node = iD.Node({loc: loc}),
24435 way = iD.Way({tags: defaultTags});
24438 iD.actions.AddEntity(node),
24439 iD.actions.AddEntity(way),
24440 iD.actions.AddVertex(way.id, node.id),
24441 iD.actions.AddVertex(way.id, node.id),
24442 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
24444 context.enter(iD.modes.DrawArea(context, way.id, graph));
24447 function startFromNode(node) {
24448 var graph = context.graph(),
24449 way = iD.Way({tags: defaultTags});
24452 iD.actions.AddEntity(way),
24453 iD.actions.AddVertex(way.id, node.id),
24454 iD.actions.AddVertex(way.id, node.id));
24456 context.enter(iD.modes.DrawArea(context, way.id, graph));
24459 mode.enter = function() {
24460 context.install(behavior);
24463 mode.exit = function() {
24464 context.uninstall(behavior);
24469 iD.modes.AddLine = function(context) {
24473 title: t('modes.add_line.title'),
24474 description: t('modes.add_line.description'),
24478 var behavior = iD.behavior.AddWay(context)
24479 .tail(t('modes.add_line.tail'))
24480 .on('start', start)
24481 .on('startFromWay', startFromWay)
24482 .on('startFromNode', startFromNode);
24484 function start(loc) {
24485 var baseGraph = context.graph(),
24486 node = iD.Node({loc: loc}),
24490 iD.actions.AddEntity(node),
24491 iD.actions.AddEntity(way),
24492 iD.actions.AddVertex(way.id, node.id));
24494 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24497 function startFromWay(loc, edge) {
24498 var baseGraph = context.graph(),
24499 node = iD.Node({loc: loc}),
24503 iD.actions.AddEntity(node),
24504 iD.actions.AddEntity(way),
24505 iD.actions.AddVertex(way.id, node.id),
24506 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
24508 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24511 function startFromNode(node) {
24512 var baseGraph = context.graph(),
24516 iD.actions.AddEntity(way),
24517 iD.actions.AddVertex(way.id, node.id));
24519 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
24522 mode.enter = function() {
24523 context.install(behavior);
24526 mode.exit = function() {
24527 context.uninstall(behavior);
24532 iD.modes.AddPoint = function(context) {
24536 title: t('modes.add_point.title'),
24537 description: t('modes.add_point.description'),
24541 var behavior = iD.behavior.Draw(context)
24542 .tail(t('modes.add_point.tail'))
24544 .on('clickWay', addWay)
24545 .on('clickNode', addNode)
24546 .on('cancel', cancel)
24547 .on('finish', cancel);
24549 function add(loc) {
24550 var node = iD.Node({loc: loc});
24553 iD.actions.AddEntity(node),
24554 t('operations.add.annotation.point'));
24557 iD.modes.Select(context, [node.id])
24558 .suppressMenu(true)
24559 .newFeature(true));
24562 function addWay(loc) {
24566 function addNode(node) {
24570 function cancel() {
24571 context.enter(iD.modes.Browse(context));
24574 mode.enter = function() {
24575 context.install(behavior);
24578 mode.exit = function() {
24579 context.uninstall(behavior);
24584 iD.modes.Browse = function(context) {
24588 title: t('modes.browse.title'),
24589 description: t('modes.browse.description')
24593 iD.behavior.Paste(context),
24594 iD.behavior.Hover(context)
24595 .on('hover', context.ui().sidebar.hover),
24596 iD.behavior.Select(context),
24597 iD.behavior.Lasso(context),
24598 iD.modes.DragNode(context).behavior];
24600 mode.enter = function() {
24601 behaviors.forEach(function(behavior) {
24602 context.install(behavior);
24605 // Get focus on the body.
24606 if (document.activeElement && document.activeElement.blur) {
24607 document.activeElement.blur();
24611 context.ui().sidebar.show(sidebar);
24613 context.ui().sidebar.select(null);
24617 mode.exit = function() {
24618 context.ui().sidebar.hover.cancel();
24619 behaviors.forEach(function(behavior) {
24620 context.uninstall(behavior);
24624 context.ui().sidebar.hide();
24628 mode.sidebar = function(_) {
24629 if (!arguments.length) return sidebar;
24636 iD.modes.DragNode = function(context) {
24647 hover = iD.behavior.Hover(context)
24649 .on('hover', context.ui().sidebar.hover),
24650 edit = iD.behavior.Edit(context);
24652 function edge(point, size) {
24653 var pad = [30, 100, 30, 100];
24654 if (point[0] > size[0] - pad[0]) return [-10, 0];
24655 else if (point[0] < pad[2]) return [10, 0];
24656 else if (point[1] > size[1] - pad[1]) return [0, -10];
24657 else if (point[1] < pad[3]) return [0, 10];
24661 function startNudge(nudge) {
24662 if (nudgeInterval) window.clearInterval(nudgeInterval);
24663 nudgeInterval = window.setInterval(function() {
24664 context.pan(nudge);
24668 function stopNudge() {
24669 if (nudgeInterval) window.clearInterval(nudgeInterval);
24670 nudgeInterval = null;
24673 function moveAnnotation(entity) {
24674 return t('operations.move.annotation.' + entity.geometry(context.graph()));
24677 function connectAnnotation(entity) {
24678 return t('operations.connect.annotation.' + entity.geometry(context.graph()));
24681 function origin(entity) {
24682 return context.projection(entity.loc);
24685 function start(entity) {
24686 cancelled = d3.event.sourceEvent.shiftKey ||
24687 context.features().hasHiddenConnections(entity, context.graph());
24689 if (cancelled) return behavior.cancel();
24691 wasMidpoint = entity.type === 'midpoint';
24693 var midpoint = entity;
24694 entity = iD.Node();
24695 context.perform(iD.actions.AddMidpoint(midpoint, entity));
24697 var vertex = context.surface()
24698 .selectAll('.' + entity.id);
24699 behavior.target(vertex.node(), entity);
24703 iD.actions.Noop());
24706 activeIDs = _.pluck(context.graph().parentWays(entity), 'id');
24707 activeIDs.push(entity.id);
24709 context.enter(mode);
24713 if (d3.event.sourceEvent.altKey) {
24717 return d3.event.sourceEvent.target.__data__ || {};
24720 // via https://gist.github.com/shawnbot/4166283
24721 function childOf(p, c) {
24722 if (p === c) return false;
24723 while (c && c !== p) c = c.parentNode;
24727 function move(entity) {
24728 if (cancelled) return;
24729 d3.event.sourceEvent.stopPropagation();
24731 var nudge = childOf(context.container().node(),
24732 d3.event.sourceEvent.toElement) &&
24733 edge(d3.event.point, context.map().dimensions());
24735 if (nudge) startNudge(nudge);
24738 var loc = context.projection.invert(d3.event.point);
24741 if (d.type === 'node' && d.id !== entity.id) {
24743 } else if (d.type === 'way' && !d3.select(d3.event.sourceEvent.target).classed('fill')) {
24744 loc = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
24748 iD.actions.MoveNode(entity.id, loc),
24749 moveAnnotation(entity));
24752 function end(entity) {
24753 if (cancelled) return;
24757 if (d.type === 'way') {
24758 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection);
24760 iD.actions.AddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
24761 connectAnnotation(d));
24763 } else if (d.type === 'node' && d.id !== entity.id) {
24765 iD.actions.Connect([d.id, entity.id]),
24766 connectAnnotation(d));
24768 } else if (wasMidpoint) {
24771 t('operations.add.annotation.vertex'));
24776 moveAnnotation(entity));
24779 var reselection = selectedIDs.filter(function(id) {
24780 return context.graph().hasEntity(id);
24783 if (reselection.length) {
24785 iD.modes.Select(context, reselection)
24786 .suppressMenu(true));
24788 context.enter(iD.modes.Browse(context));
24792 function cancel() {
24794 context.enter(iD.modes.Browse(context));
24797 function setActiveElements() {
24798 context.surface().selectAll(iD.util.entitySelector(activeIDs))
24799 .classed('active', true);
24802 var behavior = iD.behavior.drag()
24803 .delegate('g.node, g.point, g.midpoint')
24804 .surface(context.surface().node())
24806 .on('start', start)
24810 mode.enter = function() {
24811 context.install(hover);
24812 context.install(edit);
24815 .on('undone.drag-node', cancel);
24818 .on('drawn.drag-node', setActiveElements);
24820 setActiveElements();
24823 mode.exit = function() {
24824 context.ui().sidebar.hover.cancel();
24825 context.uninstall(hover);
24826 context.uninstall(edit);
24829 .on('undone.drag-node', null);
24832 .on('drawn.drag-node', null);
24835 .selectAll('.active')
24836 .classed('active', false);
24841 mode.selectedIDs = function(_) {
24842 if (!arguments.length) return selectedIDs;
24847 mode.behavior = behavior;
24851 iD.modes.DrawArea = function(context, wayId, baseGraph) {
24859 mode.enter = function() {
24860 var way = context.entity(wayId),
24861 headId = way.nodes[way.nodes.length - 2],
24862 tailId = way.first();
24864 behavior = iD.behavior.DrawWay(context, wayId, -1, mode, baseGraph)
24865 .tail(t('modes.draw_area.tail'));
24867 var addNode = behavior.addNode;
24869 behavior.addNode = function(node) {
24870 if (node.id === headId || node.id === tailId) {
24877 context.install(behavior);
24880 mode.exit = function() {
24881 context.uninstall(behavior);
24884 mode.selectedIDs = function() {
24890 iD.modes.DrawLine = function(context, wayId, baseGraph, affix) {
24898 mode.enter = function() {
24899 var way = context.entity(wayId),
24900 index = (affix === 'prefix') ? 0 : undefined,
24901 headId = (affix === 'prefix') ? way.first() : way.last();
24903 behavior = iD.behavior.DrawWay(context, wayId, index, mode, baseGraph)
24904 .tail(t('modes.draw_line.tail'));
24906 var addNode = behavior.addNode;
24908 behavior.addNode = function(node) {
24909 if (node.id === headId) {
24916 context.install(behavior);
24919 mode.exit = function() {
24920 context.uninstall(behavior);
24923 mode.selectedIDs = function() {
24929 iD.modes.Move = function(context, entityIDs, baseGraph) {
24935 var keybinding = d3.keybinding('move'),
24936 edit = iD.behavior.Edit(context),
24937 annotation = entityIDs.length === 1 ?
24938 t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
24939 t('operations.move.annotation.multiple'),
24944 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
24946 function edge(point, size) {
24947 var pad = [30, 100, 30, 100];
24948 if (point[0] > size[0] - pad[0]) return [-10, 0];
24949 else if (point[0] < pad[2]) return [10, 0];
24950 else if (point[1] > size[1] - pad[1]) return [0, -10];
24951 else if (point[1] < pad[3]) return [0, 10];
24955 function startNudge(nudge) {
24956 if (nudgeInterval) window.clearInterval(nudgeInterval);
24957 nudgeInterval = window.setInterval(function() {
24958 context.pan(nudge);
24960 var currMouse = context.mouse(),
24961 origMouse = context.projection(origin),
24962 delta = vecSub(vecSub(currMouse, origMouse), nudge),
24963 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
24965 context.overwrite(action, annotation);
24970 function stopNudge() {
24971 if (nudgeInterval) window.clearInterval(nudgeInterval);
24972 nudgeInterval = null;
24976 var currMouse = context.mouse(),
24977 origMouse = context.projection(origin),
24978 delta = vecSub(currMouse, origMouse),
24979 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
24981 context.overwrite(action, annotation);
24983 var nudge = edge(currMouse, context.map().dimensions());
24984 if (nudge) startNudge(nudge);
24988 function finish() {
24989 d3.event.stopPropagation();
24990 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
24994 function cancel() {
24996 while (context.graph() !== baseGraph) context.pop();
24997 context.enter(iD.modes.Browse(context));
25000 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
25005 function undone() {
25006 context.enter(iD.modes.Browse(context));
25009 mode.enter = function() {
25010 origin = context.map().mouseCoordinates();
25013 context.install(edit);
25020 .on('mousemove.move', move)
25021 .on('click.move', finish);
25024 .on('undone.move', undone);
25030 d3.select(document)
25034 mode.exit = function() {
25037 context.uninstall(edit);
25040 .on('mousemove.move', null)
25041 .on('click.move', null);
25044 .on('undone.move', null);
25051 iD.modes.RotateWay = function(context, wayId) {
25057 var keybinding = d3.keybinding('rotate-way'),
25058 edit = iD.behavior.Edit(context);
25060 mode.enter = function() {
25061 context.install(edit);
25063 var annotation = t('operations.rotate.annotation.' + context.geometry(wayId)),
25064 way = context.graph().entity(wayId),
25065 nodes = _.uniq(context.graph().childNodes(way)),
25066 points = nodes.map(function(n) { return context.projection(n.loc); }),
25067 pivot = d3.geom.polygon(points).centroid(),
25074 function rotate() {
25076 var mousePoint = context.mouse(),
25077 newAngle = Math.atan2(mousePoint[1] - pivot[1], mousePoint[0] - pivot[0]);
25079 if (typeof angle === 'undefined') angle = newAngle;
25082 iD.actions.RotateWay(wayId, pivot, newAngle - angle, context.projection),
25088 function finish() {
25089 d3.event.stopPropagation();
25090 context.enter(iD.modes.Select(context, [wayId])
25091 .suppressMenu(true));
25094 function cancel() {
25096 context.enter(iD.modes.Select(context, [wayId])
25097 .suppressMenu(true));
25100 function undone() {
25101 context.enter(iD.modes.Browse(context));
25105 .on('mousemove.rotate-way', rotate)
25106 .on('click.rotate-way', finish);
25109 .on('undone.rotate-way', undone);
25115 d3.select(document)
25119 mode.exit = function() {
25120 context.uninstall(edit);
25123 .on('mousemove.rotate-way', null)
25124 .on('click.rotate-way', null);
25127 .on('undone.rotate-way', null);
25134 iD.modes.Save = function(context) {
25135 var ui = iD.ui.Commit(context)
25136 .on('cancel', cancel)
25139 function cancel() {
25140 context.enter(iD.modes.Browse(context));
25143 function save(e, tryAgain) {
25144 function withChildNodes(ids, graph) {
25145 return _.uniq(_.reduce(ids, function(result, id) {
25146 var e = graph.entity(id);
25147 if (e.type === 'way') {
25149 var cn = graph.childNodes(e);
25150 result.push.apply(result, _.pluck(_.filter(cn, 'version'), 'id'));
25152 /* eslint-disable no-console */
25153 if (typeof console !== 'undefined') console.error(err);
25154 /* eslint-enable no-console */
25161 var loading = iD.ui.Loading(context).message(t('save.uploading')).blocking(true),
25162 history = context.history(),
25163 origChanges = history.changes(iD.actions.DiscardTags(history.difference())),
25164 localGraph = context.graph(),
25165 remoteGraph = iD.Graph(history.base(), true),
25166 modified = _.filter(history.difference().summary(), {changeType: 'modified'}),
25167 toCheck = _.pluck(_.pluck(modified, 'entity'), 'id'),
25168 toLoad = withChildNodes(toCheck, localGraph),
25172 if (!tryAgain) history.perform(iD.actions.Noop()); // checkpoint
25173 context.container().call(loading);
25175 if (toCheck.length) {
25176 context.connection().loadMultiple(toLoad, loaded);
25182 // Reload modified entities into an alternate graph and check for conflicts..
25183 function loaded(err, result) {
25184 if (errors.length) return;
25188 msg: err.responseText,
25189 details: [ t('save.status_code', { code: err.status }) ]
25195 _.each(result.data, function(entity) {
25196 remoteGraph.replace(entity);
25197 toLoad = _.without(toLoad, entity.id);
25199 // Because loadMultiple doesn't download /full like loadEntity,
25200 // need to also load children that aren't already being checked..
25201 if (!entity.visible) return;
25202 if (entity.type === 'way') {
25203 loadMore.push.apply(loadMore,
25204 _.difference(entity.nodes, toCheck, toLoad, loadMore));
25205 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
25206 loadMore.push.apply(loadMore,
25207 _.difference(_.pluck(entity.members, 'id'), toCheck, toLoad, loadMore));
25211 if (loadMore.length) {
25212 toLoad.push.apply(toLoad, loadMore);
25213 context.connection().loadMultiple(loadMore, loaded);
25216 if (!toLoad.length) {
25223 function checkConflicts() {
25224 function choice(id, text, action) {
25225 return { id: id, text: text, action: function() { history.replace(action); } };
25227 function formatUser(d) {
25228 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
25230 function entityName(entity) {
25231 return iD.util.displayName(entity) || (iD.util.displayType(entity.id) + ' ' + entity.id);
25234 function compareVersions(local, remote) {
25235 if (local.version !== remote.version) return false;
25237 if (local.type === 'way') {
25238 var children = _.union(local.nodes, remote.nodes);
25240 for (var i = 0; i < children.length; i++) {
25241 var a = localGraph.hasEntity(children[i]),
25242 b = remoteGraph.hasEntity(children[i]);
25244 if (a && b && a.version !== b.version) return false;
25251 _.each(toCheck, function(id) {
25252 var local = localGraph.entity(id),
25253 remote = remoteGraph.entity(id);
25255 if (compareVersions(local, remote)) return;
25257 var action = iD.actions.MergeRemoteChanges,
25258 merge = action(id, localGraph, remoteGraph, formatUser);
25260 history.replace(merge);
25262 var mergeConflicts = merge.conflicts();
25263 if (!mergeConflicts.length) return; // merged safely
25265 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
25266 forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
25267 keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
25268 keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
25272 name: entityName(local),
25273 details: mergeConflicts,
25276 choice(id, keepMine, forceLocal),
25277 choice(id, keepTheirs, forceRemote)
25286 function finalize() {
25287 if (conflicts.length) {
25288 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
25290 } else if (errors.length) {
25293 var changes = history.changes(iD.actions.DiscardTags(history.difference()));
25294 if (changes.modified.length || changes.created.length || changes.deleted.length) {
25295 context.connection().putChangeset(
25298 history.imageryUsed(),
25299 function(err, changeset_id) {
25302 msg: err.responseText,
25303 details: [ t('save.status_code', { code: err.status }) ]
25307 history.clearSaved();
25308 success(e, changeset_id);
25309 // Add delay to allow for postgres replication #1646 #2678
25310 window.setTimeout(function() {
25316 } else { // changes were insignificant or reverted by user
25325 function showConflicts() {
25326 var selection = context.container()
25327 .select('#sidebar')
25329 .attr('class','sidebar-component');
25333 selection.call(iD.ui.Conflicts(context)
25335 .on('download', function() {
25336 var data = JXON.stringify(context.connection().osmChangeJXON('CHANGEME', origChanges)),
25337 win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
25340 .on('cancel', function() {
25342 selection.remove();
25344 .on('save', function() {
25345 for (var i = 0; i < conflicts.length; i++) {
25346 if (conflicts[i].chosen === 1) { // user chose "keep theirs"
25347 var entity = context.hasEntity(conflicts[i].id);
25348 if (entity && entity.type === 'way') {
25349 var children = _.uniq(entity.nodes);
25350 for (var j = 0; j < children.length; j++) {
25351 history.replace(iD.actions.Revert(children[j]));
25354 history.replace(iD.actions.Revert(conflicts[i].id));
25358 selection.remove();
25365 function showErrors() {
25366 var selection = iD.ui.confirm(context.container());
25372 .select('.modal-section.header')
25374 .text(t('save.error'));
25376 addErrors(selection, errors);
25377 selection.okButton();
25381 function addErrors(selection, data) {
25382 var message = selection
25383 .select('.modal-section.message-text');
25385 var items = message
25386 .selectAll('.error-container')
25389 var enter = items.enter()
25391 .attr('class', 'error-container');
25395 .attr('class', 'error-description')
25397 .classed('hide-toggle', true)
25398 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
25399 .on('click', function() {
25400 var error = d3.select(this),
25401 detail = d3.select(this.nextElementSibling),
25402 exp = error.classed('expanded');
25404 detail.style('display', exp ? 'none' : 'block');
25405 error.classed('expanded', !exp);
25407 d3.event.preventDefault();
25410 var details = enter
25412 .attr('class', 'error-detail-container')
25413 .style('display', 'none');
25417 .attr('class', 'error-detail-list')
25419 .data(function(d) { return d.details || []; })
25422 .attr('class', 'error-detail-item')
25423 .text(function(d) { return d; });
25432 function success(e, changeset_id) {
25433 context.enter(iD.modes.Browse(context)
25434 .sidebar(iD.ui.Success(context)
25439 .on('cancel', function() {
25440 context.ui().sidebar.hide();
25448 mode.enter = function() {
25449 context.connection().authenticate(function(err) {
25453 context.ui().sidebar.show(ui);
25458 mode.exit = function() {
25459 context.ui().sidebar.hide();
25464 iD.modes.Select = function(context, selectedIDs) {
25470 var keybinding = d3.keybinding('select'),
25473 iD.behavior.Copy(context),
25474 iD.behavior.Paste(context),
25475 iD.behavior.Breathe(context),
25476 iD.behavior.Hover(context),
25477 iD.behavior.Select(context),
25478 iD.behavior.Lasso(context),
25479 iD.modes.DragNode(context)
25480 .selectedIDs(selectedIDs)
25484 newFeature = false,
25485 suppressMenu = false;
25487 var wrap = context.container()
25488 .select('.inspector-wrap');
25491 function singular() {
25492 if (selectedIDs.length === 1) {
25493 return context.hasEntity(selectedIDs[0]);
25497 function closeMenu() {
25499 context.surface().call(radialMenu.close);
25503 function positionMenu() {
25504 if (suppressMenu || !radialMenu) { return; }
25506 var entity = singular();
25507 if (entity && context.geometry(entity.id) === 'relation') {
25508 suppressMenu = true;
25509 } else if (entity && entity.type === 'node') {
25510 radialMenu.center(context.projection(entity.loc));
25512 var point = context.mouse(),
25513 viewport = iD.geo.Extent(context.projection.clipExtent()).polygon();
25514 if (iD.geo.pointInPolygon(point, viewport)) {
25515 radialMenu.center(point);
25517 suppressMenu = true;
25522 function showMenu() {
25524 if (!suppressMenu && radialMenu) {
25525 context.surface().call(radialMenu);
25529 function toggleMenu() {
25530 if (d3.select('.radial-menu').empty()) {
25537 mode.selectedIDs = function() {
25538 return selectedIDs;
25541 mode.reselect = function() {
25542 var surfaceNode = context.surface().node();
25543 if (surfaceNode.focus) { // FF doesn't support it
25544 surfaceNode.focus();
25551 mode.newFeature = function(_) {
25552 if (!arguments.length) return newFeature;
25557 mode.suppressMenu = function(_) {
25558 if (!arguments.length) return suppressMenu;
25563 mode.enter = function() {
25564 function update() {
25566 if (_.any(selectedIDs, function(id) { return !context.hasEntity(id); })) {
25567 // Exit mode if selected entity gets undone
25568 context.enter(iD.modes.Browse(context));
25572 function dblclick() {
25573 var target = d3.select(d3.event.target),
25574 datum = target.datum();
25576 if (datum instanceof iD.Way && !target.classed('fill')) {
25577 var choice = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection),
25580 var prev = datum.nodes[choice.index - 1],
25581 next = datum.nodes[choice.index];
25584 iD.actions.AddMidpoint({loc: choice.loc, edge: [prev, next]}, node),
25585 t('operations.add.annotation.vertex'));
25587 d3.event.preventDefault();
25588 d3.event.stopPropagation();
25592 function selectElements(drawn) {
25593 var entity = singular();
25594 if (entity && context.geometry(entity.id) === 'relation') {
25595 suppressMenu = true;
25599 var selection = context.surface()
25600 .selectAll(iD.util.entityOrMemberSelector(selectedIDs, context.graph()));
25602 if (selection.empty()) {
25603 if (drawn) { // Exit mode if selected DOM elements have disappeared..
25604 context.enter(iD.modes.Browse(context));
25608 .classed('selected', true);
25613 if (!context.inIntro()) {
25614 context.enter(iD.modes.Browse(context));
25619 behaviors.forEach(function(behavior) {
25620 context.install(behavior);
25623 var operations = _.without(d3.values(iD.operations), iD.operations.Delete)
25624 .map(function(o) { return o(selectedIDs, context); })
25625 .filter(function(o) { return o.available(); });
25627 operations.unshift(iD.operations.Delete(selectedIDs, context));
25630 .on('⎋', esc, true)
25631 .on('space', toggleMenu);
25633 operations.forEach(function(operation) {
25634 operation.keys.forEach(function(key) {
25635 keybinding.on(key, function() {
25636 if (!(context.inIntro() || operation.disabled())) {
25643 d3.select(document)
25646 radialMenu = iD.ui.RadialMenu(context, operations);
25648 context.ui().sidebar
25649 .select(singular() ? singular().id : null, newFeature);
25652 .on('undone.select', update)
25653 .on('redone.select', update);
25656 .on('move.select', closeMenu)
25657 .on('drawn.select', selectElements);
25661 var show = d3.event && !suppressMenu;
25667 timeout = window.setTimeout(function() {
25673 .on('dblclick.select', dblclick);
25676 if (selectedIDs.length > 1) {
25677 var entities = iD.ui.SelectionList(context, selectedIDs);
25678 context.ui().sidebar.show(entities);
25682 mode.exit = function() {
25683 if (timeout) window.clearTimeout(timeout);
25685 if (inspector) wrap.call(inspector.close);
25687 behaviors.forEach(function(behavior) {
25688 context.uninstall(behavior);
25693 radialMenu = undefined;
25696 .on('undone.select', null)
25697 .on('redone.select', null);
25700 .on('dblclick.select', null)
25701 .selectAll('.selected')
25702 .classed('selected', false);
25704 context.map().on('drawn.select', null);
25705 context.ui().sidebar.hide();
25710 iD.operations = {};
25711 iD.operations.Circularize = function(selectedIDs, context) {
25712 var entityId = selectedIDs[0],
25713 entity = context.entity(entityId),
25714 extent = entity.extent(context.graph()),
25715 geometry = context.geometry(entityId),
25716 action = iD.actions.Circularize(entityId, context.projection);
25718 var operation = function() {
25719 var annotation = t('operations.circularize.annotation.' + geometry);
25720 context.perform(action, annotation);
25723 operation.available = function() {
25724 return selectedIDs.length === 1 &&
25725 entity.type === 'way' &&
25726 _.uniq(entity.nodes).length > 1;
25729 operation.disabled = function() {
25731 if (extent.percentContainedIn(context.extent()) < 0.8) {
25732 reason = 'too_large';
25733 } else if (context.hasHiddenConnections(entityId)) {
25734 reason = 'connected_to_hidden';
25736 return action.disabled(context.graph()) || reason;
25739 operation.tooltip = function() {
25740 var disable = operation.disabled();
25742 t('operations.circularize.' + disable) :
25743 t('operations.circularize.description.' + geometry);
25746 operation.id = 'circularize';
25747 operation.keys = [t('operations.circularize.key')];
25748 operation.title = t('operations.circularize.title');
25752 iD.operations.Continue = function(selectedIDs, context) {
25753 var graph = context.graph(),
25754 entities = selectedIDs.map(function(id) { return graph.entity(id); }),
25755 geometries = _.extend({line: [], vertex: []},
25756 _.groupBy(entities, function(entity) { return entity.geometry(graph); })),
25757 vertex = geometries.vertex[0];
25759 function candidateWays() {
25760 return graph.parentWays(vertex).filter(function(parent) {
25761 return parent.geometry(graph) === 'line' &&
25762 parent.affix(vertex.id) &&
25763 (geometries.line.length === 0 || geometries.line[0] === parent);
25767 var operation = function() {
25768 var candidate = candidateWays()[0];
25769 context.enter(iD.modes.DrawLine(
25773 candidate.affix(vertex.id)));
25776 operation.available = function() {
25777 return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
25778 !context.features().hasHiddenConnections(vertex, context.graph());
25781 operation.disabled = function() {
25782 var candidates = candidateWays();
25783 if (candidates.length === 0)
25784 return 'not_eligible';
25785 if (candidates.length > 1)
25789 operation.tooltip = function() {
25790 var disable = operation.disabled();
25792 t('operations.continue.' + disable) :
25793 t('operations.continue.description');
25796 operation.id = 'continue';
25797 operation.keys = [t('operations.continue.key')];
25798 operation.title = t('operations.continue.title');
25802 iD.operations.Delete = function(selectedIDs, context) {
25803 var action = iD.actions.DeleteMultiple(selectedIDs);
25805 var operation = function() {
25809 if (selectedIDs.length > 1) {
25810 annotation = t('operations.delete.annotation.multiple', {n: selectedIDs.length});
25813 var id = selectedIDs[0],
25814 entity = context.entity(id),
25815 geometry = context.geometry(id),
25816 parents = context.graph().parentWays(entity),
25817 parent = parents[0];
25819 annotation = t('operations.delete.annotation.' + geometry);
25821 // Select the next closest node in the way.
25822 if (geometry === 'vertex' && parents.length === 1 && parent.nodes.length > 2) {
25823 var nodes = parent.nodes,
25824 i = nodes.indexOf(id);
25828 } else if (i === nodes.length - 1) {
25831 var a = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
25832 b = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
25833 i = a < b ? i - 1 : i + 1;
25836 nextSelectedID = nodes[i];
25840 if (nextSelectedID && context.hasEntity(nextSelectedID)) {
25841 context.enter(iD.modes.Select(context, [nextSelectedID]));
25843 context.enter(iD.modes.Browse(context));
25851 operation.available = function() {
25855 operation.disabled = function() {
25857 if (_.any(selectedIDs, context.hasHiddenConnections)) {
25858 reason = 'connected_to_hidden';
25860 return action.disabled(context.graph()) || reason;
25863 operation.tooltip = function() {
25864 var disable = operation.disabled();
25866 t('operations.delete.' + disable) :
25867 t('operations.delete.description');
25870 operation.id = 'delete';
25871 operation.keys = [iD.ui.cmd('⌘⌫'), iD.ui.cmd('⌘⌦')];
25872 operation.title = t('operations.delete.title');
25876 iD.operations.Disconnect = function(selectedIDs, context) {
25877 var vertices = _.filter(selectedIDs, function vertex(entityId) {
25878 return context.geometry(entityId) === 'vertex';
25881 var entityId = vertices[0],
25882 action = iD.actions.Disconnect(entityId);
25884 if (selectedIDs.length > 1) {
25885 action.limitWays(_.without(selectedIDs, entityId));
25888 var operation = function() {
25889 context.perform(action, t('operations.disconnect.annotation'));
25892 operation.available = function() {
25893 return vertices.length === 1;
25896 operation.disabled = function() {
25898 if (_.any(selectedIDs, context.hasHiddenConnections)) {
25899 reason = 'connected_to_hidden';
25901 return action.disabled(context.graph()) || reason;
25904 operation.tooltip = function() {
25905 var disable = operation.disabled();
25907 t('operations.disconnect.' + disable) :
25908 t('operations.disconnect.description');
25911 operation.id = 'disconnect';
25912 operation.keys = [t('operations.disconnect.key')];
25913 operation.title = t('operations.disconnect.title');
25917 iD.operations.Merge = function(selectedIDs, context) {
25918 var join = iD.actions.Join(selectedIDs),
25919 merge = iD.actions.Merge(selectedIDs),
25920 mergePolygon = iD.actions.MergePolygon(selectedIDs);
25922 var operation = function() {
25923 var annotation = t('operations.merge.annotation', {n: selectedIDs.length}),
25926 if (!join.disabled(context.graph())) {
25928 } else if (!merge.disabled(context.graph())) {
25931 action = mergePolygon;
25934 context.perform(action, annotation);
25935 context.enter(iD.modes.Select(context, selectedIDs.filter(function(id) { return context.hasEntity(id); }))
25936 .suppressMenu(true));
25939 operation.available = function() {
25940 return selectedIDs.length >= 2;
25943 operation.disabled = function() {
25944 return join.disabled(context.graph()) &&
25945 merge.disabled(context.graph()) &&
25946 mergePolygon.disabled(context.graph());
25949 operation.tooltip = function() {
25950 var j = join.disabled(context.graph()),
25951 m = merge.disabled(context.graph()),
25952 p = mergePolygon.disabled(context.graph());
25954 if (j === 'restriction' && m && p)
25955 return t('operations.merge.restriction', {relation: context.presets().item('type/restriction').name()});
25957 if (p === 'incomplete_relation' && j && m)
25958 return t('operations.merge.incomplete_relation');
25961 return t('operations.merge.' + j);
25963 return t('operations.merge.description');
25966 operation.id = 'merge';
25967 operation.keys = [t('operations.merge.key')];
25968 operation.title = t('operations.merge.title');
25972 iD.operations.Move = function(selectedIDs, context) {
25973 var extent = selectedIDs.reduce(function(extent, id) {
25974 return extent.extend(context.entity(id).extent(context.graph()));
25975 }, iD.geo.Extent());
25977 var operation = function() {
25978 context.enter(iD.modes.Move(context, selectedIDs));
25981 operation.available = function() {
25982 return selectedIDs.length > 1 ||
25983 context.entity(selectedIDs[0]).type !== 'node';
25986 operation.disabled = function() {
25988 if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
25989 reason = 'too_large';
25990 } else if (_.any(selectedIDs, context.hasHiddenConnections)) {
25991 reason = 'connected_to_hidden';
25993 return iD.actions.Move(selectedIDs).disabled(context.graph()) || reason;
25996 operation.tooltip = function() {
25997 var disable = operation.disabled();
25999 t('operations.move.' + disable) :
26000 t('operations.move.description');
26003 operation.id = 'move';
26004 operation.keys = [t('operations.move.key')];
26005 operation.title = t('operations.move.title');
26009 iD.operations.Orthogonalize = function(selectedIDs, context) {
26010 var entityId = selectedIDs[0],
26011 entity = context.entity(entityId),
26012 extent = entity.extent(context.graph()),
26013 geometry = context.geometry(entityId),
26014 action = iD.actions.Orthogonalize(entityId, context.projection);
26016 var operation = function() {
26017 var annotation = t('operations.orthogonalize.annotation.' + geometry);
26018 context.perform(action, annotation);
26021 operation.available = function() {
26022 return selectedIDs.length === 1 &&
26023 entity.type === 'way' &&
26024 entity.isClosed() &&
26025 _.uniq(entity.nodes).length > 2;
26028 operation.disabled = function() {
26030 if (extent.percentContainedIn(context.extent()) < 0.8) {
26031 reason = 'too_large';
26032 } else if (context.hasHiddenConnections(entityId)) {
26033 reason = 'connected_to_hidden';
26035 return action.disabled(context.graph()) || reason;
26038 operation.tooltip = function() {
26039 var disable = operation.disabled();
26041 t('operations.orthogonalize.' + disable) :
26042 t('operations.orthogonalize.description.' + geometry);
26045 operation.id = 'orthogonalize';
26046 operation.keys = [t('operations.orthogonalize.key')];
26047 operation.title = t('operations.orthogonalize.title');
26051 iD.operations.Reverse = function(selectedIDs, context) {
26052 var entityId = selectedIDs[0];
26054 var operation = function() {
26056 iD.actions.Reverse(entityId),
26057 t('operations.reverse.annotation'));
26060 operation.available = function() {
26061 return selectedIDs.length === 1 &&
26062 context.geometry(entityId) === 'line';
26065 operation.disabled = function() {
26069 operation.tooltip = function() {
26070 return t('operations.reverse.description');
26073 operation.id = 'reverse';
26074 operation.keys = [t('operations.reverse.key')];
26075 operation.title = t('operations.reverse.title');
26079 iD.operations.Rotate = function(selectedIDs, context) {
26080 var entityId = selectedIDs[0],
26081 entity = context.entity(entityId),
26082 extent = entity.extent(context.graph()),
26083 geometry = context.geometry(entityId);
26085 var operation = function() {
26086 context.enter(iD.modes.RotateWay(context, entityId));
26089 operation.available = function() {
26090 if (selectedIDs.length !== 1 || entity.type !== 'way')
26092 if (geometry === 'area')
26094 if (entity.isClosed() &&
26095 context.graph().parentRelations(entity).some(function(r) { return r.isMultipolygon(); }))
26100 operation.disabled = function() {
26101 if (extent.percentContainedIn(context.extent()) < 0.8) {
26102 return 'too_large';
26103 } else if (context.hasHiddenConnections(entityId)) {
26104 return 'connected_to_hidden';
26110 operation.tooltip = function() {
26111 var disable = operation.disabled();
26113 t('operations.rotate.' + disable) :
26114 t('operations.rotate.description');
26117 operation.id = 'rotate';
26118 operation.keys = [t('operations.rotate.key')];
26119 operation.title = t('operations.rotate.title');
26123 iD.operations.Split = function(selectedIDs, context) {
26124 var vertices = _.filter(selectedIDs, function vertex(entityId) {
26125 return context.geometry(entityId) === 'vertex';
26128 var entityId = vertices[0],
26129 action = iD.actions.Split(entityId);
26131 if (selectedIDs.length > 1) {
26132 action.limitWays(_.without(selectedIDs, entityId));
26135 var operation = function() {
26138 var ways = action.ways(context.graph());
26139 if (ways.length === 1) {
26140 annotation = t('operations.split.annotation.' + context.geometry(ways[0].id));
26142 annotation = t('operations.split.annotation.multiple', {n: ways.length});
26145 var difference = context.perform(action, annotation);
26146 context.enter(iD.modes.Select(context, difference.extantIDs()));
26149 operation.available = function() {
26150 return vertices.length === 1;
26153 operation.disabled = function() {
26155 if (_.any(selectedIDs, context.hasHiddenConnections)) {
26156 reason = 'connected_to_hidden';
26158 return action.disabled(context.graph()) || reason;
26161 operation.tooltip = function() {
26162 var disable = operation.disabled();
26164 return t('operations.split.' + disable);
26167 var ways = action.ways(context.graph());
26168 if (ways.length === 1) {
26169 return t('operations.split.description.' + context.geometry(ways[0].id));
26171 return t('operations.split.description.multiple');
26175 operation.id = 'split';
26176 operation.keys = [t('operations.split.key')];
26177 operation.title = t('operations.split.title');
26181 iD.operations.Straighten = function(selectedIDs, context) {
26182 var entityId = selectedIDs[0],
26183 action = iD.actions.Straighten(entityId, context.projection);
26185 function operation() {
26186 var annotation = t('operations.straighten.annotation');
26187 context.perform(action, annotation);
26190 operation.available = function() {
26191 var entity = context.entity(entityId);
26192 return selectedIDs.length === 1 &&
26193 entity.type === 'way' &&
26194 !entity.isClosed() &&
26195 _.uniq(entity.nodes).length > 2;
26198 operation.disabled = function() {
26200 if (context.hasHiddenConnections(entityId)) {
26201 reason = 'connected_to_hidden';
26203 return action.disabled(context.graph()) || reason;
26206 operation.tooltip = function() {
26207 var disable = operation.disabled();
26209 t('operations.straighten.' + disable) :
26210 t('operations.straighten.description');
26213 operation.id = 'straighten';
26214 operation.keys = [t('operations.straighten.key')];
26215 operation.title = t('operations.straighten.title');
26219 iD.Connection = function(useHttps) {
26220 if (typeof useHttps !== 'boolean') {
26221 useHttps = window.location.protocol === 'https:';
26224 var event = d3.dispatch('authenticating', 'authenticated', 'auth', 'loading', 'loaded'),
26225 protocol = useHttps ? 'https:' : 'http:',
26226 url = protocol + '//www.openstreetmap.org',
26232 url: protocol + '//www.openstreetmap.org',
26233 oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
26234 oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
26235 loading: authenticating,
26236 done: authenticated
26240 memberStr = 'member',
26243 relationStr = 'relation',
26248 connection.changesetURL = function(changesetId) {
26249 return url + '/changeset/' + changesetId;
26252 connection.changesetsURL = function(center, zoom) {
26253 var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
26254 return url + '/history#map=' +
26255 Math.floor(zoom) + '/' +
26256 center[1].toFixed(precision) + '/' +
26257 center[0].toFixed(precision);
26260 connection.entityURL = function(entity) {
26261 return url + '/' + entity.type + '/' + entity.osmId();
26264 connection.userURL = function(username) {
26265 return url + '/user/' + username;
26268 connection.loadFromURL = function(url, callback) {
26269 function done(err, dom) {
26270 return callback(err, parse(dom));
26272 return d3.xml(url).get(done);
26275 connection.loadEntity = function(id, callback) {
26276 var type = iD.Entity.id.type(id),
26277 osmID = iD.Entity.id.toOSM(id);
26279 connection.loadFromURL(
26280 url + '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
26281 function(err, entities) {
26282 if (callback) callback(err, {data: entities});
26286 connection.loadEntityVersion = function(id, version, callback) {
26287 var type = iD.Entity.id.type(id),
26288 osmID = iD.Entity.id.toOSM(id);
26290 connection.loadFromURL(
26291 url + '/api/0.6/' + type + '/' + osmID + '/' + version,
26292 function(err, entities) {
26293 if (callback) callback(err, {data: entities});
26297 connection.loadMultiple = function(ids, callback) {
26298 _.each(_.groupBy(_.uniq(ids), iD.Entity.id.type), function(v, k) {
26299 var type = k + 's',
26300 osmIDs = _.map(v, iD.Entity.id.toOSM);
26302 _.each(_.chunk(osmIDs, 150), function(arr) {
26303 connection.loadFromURL(
26304 url + '/api/0.6/' + type + '?' + type + '=' + arr.join(),
26305 function(err, entities) {
26306 if (callback) callback(err, {data: entities});
26312 function authenticating() {
26313 event.authenticating();
26316 function authenticated() {
26317 event.authenticated();
26320 function getLoc(attrs) {
26321 var lon = attrs.lon && attrs.lon.value,
26322 lat = attrs.lat && attrs.lat.value;
26323 return [parseFloat(lon), parseFloat(lat)];
26326 function getNodes(obj) {
26327 var elems = obj.getElementsByTagName(ndStr),
26328 nodes = new Array(elems.length);
26329 for (var i = 0, l = elems.length; i < l; i++) {
26330 nodes[i] = 'n' + elems[i].attributes.ref.value;
26335 function getTags(obj) {
26336 var elems = obj.getElementsByTagName(tagStr),
26338 for (var i = 0, l = elems.length; i < l; i++) {
26339 var attrs = elems[i].attributes;
26340 tags[attrs.k.value] = attrs.v.value;
26345 function getMembers(obj) {
26346 var elems = obj.getElementsByTagName(memberStr),
26347 members = new Array(elems.length);
26348 for (var i = 0, l = elems.length; i < l; i++) {
26349 var attrs = elems[i].attributes;
26351 id: attrs.type.value[0] + attrs.ref.value,
26352 type: attrs.type.value,
26353 role: attrs.role.value
26359 function getVisible(attrs) {
26360 return (!attrs.visible || attrs.visible.value !== 'false');
26364 node: function nodeData(obj) {
26365 var attrs = obj.attributes;
26366 return new iD.Node({
26367 id: iD.Entity.id.fromOSM(nodeStr, attrs.id.value),
26368 loc: getLoc(attrs),
26369 version: attrs.version.value,
26370 user: attrs.user && attrs.user.value,
26371 tags: getTags(obj),
26372 visible: getVisible(attrs)
26376 way: function wayData(obj) {
26377 var attrs = obj.attributes;
26378 return new iD.Way({
26379 id: iD.Entity.id.fromOSM(wayStr, attrs.id.value),
26380 version: attrs.version.value,
26381 user: attrs.user && attrs.user.value,
26382 tags: getTags(obj),
26383 nodes: getNodes(obj),
26384 visible: getVisible(attrs)
26388 relation: function relationData(obj) {
26389 var attrs = obj.attributes;
26390 return new iD.Relation({
26391 id: iD.Entity.id.fromOSM(relationStr, attrs.id.value),
26392 version: attrs.version.value,
26393 user: attrs.user && attrs.user.value,
26394 tags: getTags(obj),
26395 members: getMembers(obj),
26396 visible: getVisible(attrs)
26401 function parse(dom) {
26402 if (!dom || !dom.childNodes) return;
26404 var root = dom.childNodes[0],
26405 children = root.childNodes,
26408 for (var i = 0, l = children.length; i < l; i++) {
26409 var child = children[i],
26410 parser = parsers[child.nodeName];
26412 entities.push(parser(child));
26419 connection.authenticated = function() {
26420 return oauth.authenticated();
26423 // Generate Changeset XML. Returns a string.
26424 connection.changesetJXON = function(tags) {
26428 tag: _.map(tags, function(value, key) {
26429 return { '@k': key, '@v': value };
26438 // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
26439 // XML. Returns a string.
26440 connection.osmChangeJXON = function(changeset_id, changes) {
26441 function nest(x, order) {
26443 for (var i = 0; i < x.length; i++) {
26444 var tagName = Object.keys(x[i])[0];
26445 if (!groups[tagName]) groups[tagName] = [];
26446 groups[tagName].push(x[i][tagName]);
26449 order.forEach(function(o) {
26450 if (groups[o]) ordered[o] = groups[o];
26455 function rep(entity) {
26456 return entity.asJXON(changeset_id);
26462 '@generator': 'iD',
26463 'create': nest(changes.created.map(rep), ['node', 'way', 'relation']),
26464 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
26465 'delete': _.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {'@if-unused': true})
26470 connection.changesetTags = function(comment, imageryUsed) {
26471 var detected = iD.detect(),
26473 created_by: 'iD ' + iD.version,
26474 imagery_used: imageryUsed.join(';').substr(0, 255),
26475 host: (window.location.origin + window.location.pathname).substr(0, 255),
26476 locale: detected.locale
26480 tags.comment = comment.substr(0, 255);
26486 connection.putChangeset = function(changes, comment, imageryUsed, callback) {
26489 path: '/api/0.6/changeset/create',
26490 options: { header: { 'Content-Type': 'text/xml' } },
26491 content: JXON.stringify(connection.changesetJXON(connection.changesetTags(comment, imageryUsed)))
26492 }, function(err, changeset_id) {
26493 if (err) return callback(err);
26496 path: '/api/0.6/changeset/' + changeset_id + '/upload',
26497 options: { header: { 'Content-Type': 'text/xml' } },
26498 content: JXON.stringify(connection.osmChangeJXON(changeset_id, changes))
26500 if (err) return callback(err);
26501 // POST was successful, safe to call the callback.
26502 // Still attempt to close changeset, but ignore response because #2667
26503 // Add delay to allow for postgres replication #1646 #2678
26504 window.setTimeout(function() { callback(null, changeset_id); }, 2500);
26507 path: '/api/0.6/changeset/' + changeset_id + '/close',
26508 options: { header: { 'Content-Type': 'text/xml' } }
26509 }, d3.functor(true));
26514 connection.userDetails = function(callback) {
26516 callback(undefined, userDetails);
26520 function done(err, user_details) {
26521 if (err) return callback(err);
26523 var u = user_details.getElementsByTagName('user')[0],
26524 img = u.getElementsByTagName('img'),
26527 if (img && img[0] && img[0].getAttribute('href')) {
26528 image_url = img[0].getAttribute('href');
26532 display_name: u.attributes.display_name.value,
26533 image_url: image_url,
26534 id: u.attributes.id.value
26537 callback(undefined, userDetails);
26540 oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
26543 connection.userChangesets = function(callback) {
26544 connection.userDetails(function(err, user) {
26545 if (err) return callback(err);
26547 function done(changesets) {
26548 callback(undefined, Array.prototype.map.call(changesets.getElementsByTagName('changeset'),
26549 function (changeset) {
26550 return { tags: getTags(changeset) };
26554 d3.xml(url + '/api/0.6/changesets?user=' + user.id).get()
26556 .on('error', callback);
26560 connection.status = function(callback) {
26561 function done(capabilities) {
26562 var apiStatus = capabilities.getElementsByTagName('status');
26563 callback(undefined, apiStatus[0].getAttribute('api'));
26565 d3.xml(url + '/api/capabilities').get()
26567 .on('error', callback);
26570 function abortRequest(i) { i.abort(); }
26572 connection.tileZoom = function(_) {
26573 if (!arguments.length) return tileZoom;
26578 connection.loadTiles = function(projection, dimensions, callback) {
26582 var s = projection.scale() * 2 * Math.PI,
26583 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
26584 ts = 256 * Math.pow(2, z - tileZoom),
26586 s / 2 - projection.translate()[0],
26587 s / 2 - projection.translate()[1]];
26589 var tiles = d3.geo.tile()
26590 .scaleExtent([tileZoom, tileZoom])
26593 .translate(projection.translate())()
26594 .map(function(tile) {
26595 var x = tile[0] * ts - origin[0],
26596 y = tile[1] * ts - origin[1];
26599 id: tile.toString(),
26600 extent: iD.geo.Extent(
26601 projection.invert([x, y + ts]),
26602 projection.invert([x + ts, y]))
26606 function bboxUrl(tile) {
26607 return url + '/api/0.6/map?bbox=' + tile.extent.toParam();
26610 _.filter(inflight, function(v, i) {
26611 var wanted = _.find(tiles, function(tile) {
26612 return i === tile.id;
26614 if (!wanted) delete inflight[i];
26616 }).map(abortRequest);
26618 tiles.forEach(function(tile) {
26621 if (loadedTiles[id] || inflight[id]) return;
26623 if (_.isEmpty(inflight)) {
26627 inflight[id] = connection.loadFromURL(bboxUrl(tile), function(err, parsed) {
26628 loadedTiles[id] = true;
26629 delete inflight[id];
26631 if (callback) callback(err, _.extend({data: parsed}, tile));
26633 if (_.isEmpty(inflight)) {
26640 connection.switch = function(options) {
26642 oauth.options(_.extend({
26643 loading: authenticating,
26644 done: authenticated
26647 connection.flush();
26651 connection.toggle = function(_) {
26656 connection.flush = function() {
26657 userDetails = undefined;
26658 _.forEach(inflight, abortRequest);
26664 connection.loadedTiles = function(_) {
26665 if (!arguments.length) return loadedTiles;
26670 connection.logout = function() {
26671 userDetails = undefined;
26677 connection.authenticate = function(callback) {
26678 userDetails = undefined;
26679 function done(err, res) {
26681 if (callback) callback(err, res);
26683 return oauth.authenticate(done);
26686 return d3.rebind(connection, event, 'on');
26689 iD.Difference represents the difference between two graphs.
26690 It knows how to calculate the set of entities that were
26691 created, modified, or deleted, and also contains the logic
26692 for recursively extending a difference to the complete set
26693 of entities that will require a redraw, taking into account
26694 child and parent relationships.
26696 iD.Difference = function(base, head) {
26697 var changes = {}, length = 0;
26699 function changed(h, b) {
26700 return h !== b && !_.isEqual(_.omit(h, 'v'), _.omit(b, 'v'));
26703 _.each(head.entities, function(h, id) {
26704 var b = base.entities[id];
26705 if (changed(h, b)) {
26706 changes[id] = {base: b, head: h};
26711 _.each(base.entities, function(b, id) {
26712 var h = head.entities[id];
26713 if (!changes[id] && changed(h, b)) {
26714 changes[id] = {base: b, head: h};
26719 function addParents(parents, result) {
26720 for (var i = 0; i < parents.length; i++) {
26721 var parent = parents[i];
26723 if (parent.id in result)
26726 result[parent.id] = parent;
26727 addParents(head.parentRelations(parent), result);
26731 var difference = {};
26733 difference.length = function() {
26737 difference.changes = function() {
26741 difference.extantIDs = function() {
26743 _.each(changes, function(change, id) {
26744 if (change.head) result.push(id);
26749 difference.modified = function() {
26751 _.each(changes, function(change) {
26752 if (change.base && change.head) result.push(change.head);
26757 difference.created = function() {
26759 _.each(changes, function(change) {
26760 if (!change.base && change.head) result.push(change.head);
26765 difference.deleted = function() {
26767 _.each(changes, function(change) {
26768 if (change.base && !change.head) result.push(change.base);
26773 difference.summary = function() {
26776 function addEntity(entity, graph, changeType) {
26777 relevant[entity.id] = {
26780 changeType: changeType
26784 function addParents(entity) {
26785 var parents = head.parentWays(entity);
26786 for (var j = parents.length - 1; j >= 0; j--) {
26787 var parent = parents[j];
26788 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
26792 _.each(changes, function(change) {
26793 if (change.head && change.head.geometry(head) !== 'vertex') {
26794 addEntity(change.head, head, change.base ? 'modified' : 'created');
26796 } else if (change.base && change.base.geometry(base) !== 'vertex') {
26797 addEntity(change.base, base, 'deleted');
26799 } else if (change.base && change.head) { // modified vertex
26800 var moved = !_.isEqual(change.base.loc, change.head.loc),
26801 retagged = !_.isEqual(change.base.tags, change.head.tags);
26804 addParents(change.head);
26807 if (retagged || (moved && change.head.hasInterestingTags())) {
26808 addEntity(change.head, head, 'modified');
26811 } else if (change.head && change.head.hasInterestingTags()) { // created vertex
26812 addEntity(change.head, head, 'created');
26814 } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
26815 addEntity(change.base, base, 'deleted');
26819 return d3.values(relevant);
26822 difference.complete = function(extent) {
26823 var result = {}, id, change;
26825 for (id in changes) {
26826 change = changes[id];
26828 var h = change.head,
26833 (!h || !h.intersects(extent, head)) &&
26834 (!b || !b.intersects(extent, base)))
26839 if (entity.type === 'way') {
26840 var nh = h ? h.nodes : [],
26841 nb = b ? b.nodes : [],
26844 diff = _.difference(nh, nb);
26845 for (i = 0; i < diff.length; i++) {
26846 result[diff[i]] = head.hasEntity(diff[i]);
26849 diff = _.difference(nb, nh);
26850 for (i = 0; i < diff.length; i++) {
26851 result[diff[i]] = head.hasEntity(diff[i]);
26855 addParents(head.parentWays(entity), result);
26856 addParents(head.parentRelations(entity), result);
26864 iD.Entity = function(attrs) {
26865 // For prototypal inheritance.
26866 if (this instanceof iD.Entity) return;
26868 // Create the appropriate subtype.
26869 if (attrs && attrs.type) {
26870 return iD.Entity[attrs.type].apply(this, arguments);
26871 } else if (attrs && attrs.id) {
26872 return iD.Entity[iD.Entity.id.type(attrs.id)].apply(this, arguments);
26875 // Initialize a generic Entity (used only in tests).
26876 return (new iD.Entity()).initialize(arguments);
26879 iD.Entity.id = function(type) {
26880 return iD.Entity.id.fromOSM(type, iD.Entity.id.next[type]--);
26883 iD.Entity.id.next = {node: -1, way: -1, relation: -1};
26885 iD.Entity.id.fromOSM = function(type, id) {
26886 return type[0] + id;
26889 iD.Entity.id.toOSM = function(id) {
26890 return id.slice(1);
26893 iD.Entity.id.type = function(id) {
26894 return {'n': 'node', 'w': 'way', 'r': 'relation'}[id[0]];
26897 // A function suitable for use as the second argument to d3.selection#data().
26898 iD.Entity.key = function(entity) {
26899 return entity.id + 'v' + (entity.v || 0);
26902 iD.Entity.prototype = {
26905 initialize: function(sources) {
26906 for (var i = 0; i < sources.length; ++i) {
26907 var source = sources[i];
26908 for (var prop in source) {
26909 if (Object.prototype.hasOwnProperty.call(source, prop)) {
26910 if (source[prop] === undefined) {
26913 this[prop] = source[prop];
26919 if (!this.id && this.type) {
26920 this.id = iD.Entity.id(this.type);
26922 if (!this.hasOwnProperty('visible')) {
26923 this.visible = true;
26927 Object.freeze(this);
26928 Object.freeze(this.tags);
26930 if (this.loc) Object.freeze(this.loc);
26931 if (this.nodes) Object.freeze(this.nodes);
26932 if (this.members) Object.freeze(this.members);
26938 copy: function(resolver, copies) {
26939 if (copies[this.id])
26940 return copies[this.id];
26942 var copy = iD.Entity(this, {id: undefined, user: undefined, version: undefined});
26943 copies[this.id] = copy;
26948 osmId: function() {
26949 return iD.Entity.id.toOSM(this.id);
26952 isNew: function() {
26953 return this.osmId() < 0;
26956 update: function(attrs) {
26957 return iD.Entity(this, attrs, {v: 1 + (this.v || 0)});
26960 mergeTags: function(tags) {
26961 var merged = _.clone(this.tags), changed = false;
26962 for (var k in tags) {
26963 var t1 = merged[k],
26968 } else if (t1 !== t2) {
26970 merged[k] = _.union(t1.split(/;\s*/), t2.split(/;\s*/)).join(';');
26973 return changed ? this.update({tags: merged}) : this;
26976 intersects: function(extent, resolver) {
26977 return this.extent(resolver).intersects(extent);
26980 isUsed: function(resolver) {
26981 return _.without(Object.keys(this.tags), 'area').length > 0 ||
26982 resolver.parentRelations(this).length > 0;
26985 hasInterestingTags: function() {
26986 return _.keys(this.tags).some(iD.interestingTag);
26989 isHighwayIntersection: function() {
26993 deprecatedTags: function() {
26994 var tags = _.pairs(this.tags);
26995 var deprecated = {};
26997 iD.data.deprecated.forEach(function(d) {
26998 var match = _.pairs(d.old)[0];
26999 tags.forEach(function(t) {
27000 if (t[0] === match[0] &&
27001 (t[1] === match[1] || match[1] === '*')) {
27002 deprecated[t[0]] = t[1];
27010 iD.Graph = function(other, mutable) {
27011 if (!(this instanceof iD.Graph)) return new iD.Graph(other, mutable);
27013 if (other instanceof iD.Graph) {
27014 var base = other.base();
27015 this.entities = _.assign(Object.create(base.entities), other.entities);
27016 this._parentWays = _.assign(Object.create(base.parentWays), other._parentWays);
27017 this._parentRels = _.assign(Object.create(base.parentRels), other._parentRels);
27020 this.entities = Object.create({});
27021 this._parentWays = Object.create({});
27022 this._parentRels = Object.create({});
27023 this.rebase(other || [], [this]);
27026 this.transients = {};
27027 this._childNodes = {};
27028 this.frozen = !mutable;
27031 iD.Graph.prototype = {
27032 hasEntity: function(id) {
27033 return this.entities[id];
27036 entity: function(id) {
27037 var entity = this.entities[id];
27039 throw new Error('entity ' + id + ' not found');
27044 transient: function(entity, key, fn) {
27045 var id = entity.id,
27046 transients = this.transients[id] ||
27047 (this.transients[id] = {});
27049 if (transients[key] !== undefined) {
27050 return transients[key];
27053 transients[key] = fn.call(entity);
27055 return transients[key];
27058 parentWays: function(entity) {
27059 var parents = this._parentWays[entity.id],
27063 for (var i = 0; i < parents.length; i++) {
27064 result.push(this.entity(parents[i]));
27070 isPoi: function(entity) {
27071 var parentWays = this._parentWays[entity.id];
27072 return !parentWays || parentWays.length === 0;
27075 isShared: function(entity) {
27076 var parentWays = this._parentWays[entity.id];
27077 return parentWays && parentWays.length > 1;
27080 parentRelations: function(entity) {
27081 var parents = this._parentRels[entity.id],
27085 for (var i = 0; i < parents.length; i++) {
27086 result.push(this.entity(parents[i]));
27092 childNodes: function(entity) {
27093 if (this._childNodes[entity.id]) return this._childNodes[entity.id];
27094 if (!entity.nodes) return [];
27097 for (var i = 0; i < entity.nodes.length; i++) {
27098 nodes[i] = this.entity(entity.nodes[i]);
27101 if (iD.debug) Object.freeze(nodes);
27103 this._childNodes[entity.id] = nodes;
27104 return this._childNodes[entity.id];
27109 'entities': iD.util.getPrototypeOf(this.entities),
27110 'parentWays': iD.util.getPrototypeOf(this._parentWays),
27111 'parentRels': iD.util.getPrototypeOf(this._parentRels)
27115 // Unlike other graph methods, rebase mutates in place. This is because it
27116 // is used only during the history operation that merges newly downloaded
27117 // data into each state. To external consumers, it should appear as if the
27118 // graph always contained the newly downloaded data.
27119 rebase: function(entities, stack, force) {
27120 var base = this.base(),
27123 for (i = 0; i < entities.length; i++) {
27124 var entity = entities[i];
27126 if (!entity.visible || (!force && base.entities[entity.id]))
27129 // Merging data into the base graph
27130 base.entities[entity.id] = entity;
27131 this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
27133 // Restore provisionally-deleted nodes that are discovered to have an extant parent
27134 if (entity.type === 'way') {
27135 for (j = 0; j < entity.nodes.length; j++) {
27136 id = entity.nodes[j];
27137 for (k = 1; k < stack.length; k++) {
27138 var ents = stack[k].entities;
27139 if (ents.hasOwnProperty(id) && ents[id] === undefined) {
27147 for (i = 0; i < stack.length; i++) {
27148 stack[i]._updateRebased();
27152 _updateRebased: function() {
27153 var base = this.base(),
27154 i, k, child, id, keys;
27156 keys = Object.keys(this._parentWays);
27157 for (i = 0; i < keys.length; i++) {
27159 if (base.parentWays[child]) {
27160 for (k = 0; k < base.parentWays[child].length; k++) {
27161 id = base.parentWays[child][k];
27162 if (!this.entities.hasOwnProperty(id) && !_.contains(this._parentWays[child], id)) {
27163 this._parentWays[child].push(id);
27169 keys = Object.keys(this._parentRels);
27170 for (i = 0; i < keys.length; i++) {
27172 if (base.parentRels[child]) {
27173 for (k = 0; k < base.parentRels[child].length; k++) {
27174 id = base.parentRels[child][k];
27175 if (!this.entities.hasOwnProperty(id) && !_.contains(this._parentRels[child], id)) {
27176 this._parentRels[child].push(id);
27182 this.transients = {};
27184 // this._childNodes is not updated, under the assumption that
27185 // ways are always downloaded with their child nodes.
27188 // Updates calculated properties (parentWays, parentRels) for the specified change
27189 _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
27191 parentWays = parentWays || this._parentWays;
27192 parentRels = parentRels || this._parentRels;
27194 var type = entity && entity.type || oldentity && oldentity.type,
27195 removed, added, ways, rels, i;
27198 if (type === 'way') {
27200 // Update parentWays
27201 if (oldentity && entity) {
27202 removed = _.difference(oldentity.nodes, entity.nodes);
27203 added = _.difference(entity.nodes, oldentity.nodes);
27204 } else if (oldentity) {
27205 removed = oldentity.nodes;
27207 } else if (entity) {
27209 added = entity.nodes;
27211 for (i = 0; i < removed.length; i++) {
27212 parentWays[removed[i]] = _.without(parentWays[removed[i]], oldentity.id);
27214 for (i = 0; i < added.length; i++) {
27215 ways = _.without(parentWays[added[i]], entity.id);
27216 ways.push(entity.id);
27217 parentWays[added[i]] = ways;
27220 } else if (type === 'relation') {
27222 // Update parentRels
27223 if (oldentity && entity) {
27224 removed = _.difference(oldentity.members, entity.members);
27225 added = _.difference(entity.members, oldentity);
27226 } else if (oldentity) {
27227 removed = oldentity.members;
27229 } else if (entity) {
27231 added = entity.members;
27233 for (i = 0; i < removed.length; i++) {
27234 parentRels[removed[i].id] = _.without(parentRels[removed[i].id], oldentity.id);
27236 for (i = 0; i < added.length; i++) {
27237 rels = _.without(parentRels[added[i].id], entity.id);
27238 rels.push(entity.id);
27239 parentRels[added[i].id] = rels;
27244 replace: function(entity) {
27245 if (this.entities[entity.id] === entity)
27248 return this.update(function() {
27249 this._updateCalculated(this.entities[entity.id], entity);
27250 this.entities[entity.id] = entity;
27254 remove: function(entity) {
27255 return this.update(function() {
27256 this._updateCalculated(entity, undefined);
27257 this.entities[entity.id] = undefined;
27261 revert: function(id) {
27262 var baseEntity = this.base().entities[id],
27263 headEntity = this.entities[id];
27265 if (headEntity === baseEntity)
27268 return this.update(function() {
27269 this._updateCalculated(headEntity, baseEntity);
27270 delete this.entities[id];
27274 update: function() {
27275 var graph = this.frozen ? iD.Graph(this, true) : this;
27277 for (var i = 0; i < arguments.length; i++) {
27278 arguments[i].call(graph, graph);
27281 if (this.frozen) graph.frozen = true;
27286 // Obliterates any existing entities
27287 load: function(entities) {
27288 var base = this.base();
27289 this.entities = Object.create(base.entities);
27291 for (var i in entities) {
27292 this.entities[i] = entities[i];
27293 this._updateCalculated(base.entities[i], this.entities[i]);
27299 iD.History = function(context) {
27300 var stack, index, tree,
27301 imageryUsed = ['Bing'],
27302 dispatch = d3.dispatch('change', 'undone', 'redone'),
27303 lock = iD.util.SessionMutex('lock');
27305 function perform(actions) {
27306 actions = Array.prototype.slice.call(actions);
27310 if (!_.isFunction(_.last(actions))) {
27311 annotation = actions.pop();
27314 var graph = stack[index].graph;
27315 for (var i = 0; i < actions.length; i++) {
27316 graph = actions[i](graph);
27321 annotation: annotation,
27322 imageryUsed: imageryUsed
27326 function change(previous) {
27327 var difference = iD.Difference(previous, history.graph());
27328 dispatch.change(difference);
27332 // iD uses namespaced keys so multiple installations do not conflict
27333 function getKey(n) {
27334 return 'iD_' + window.location.origin + '_' + n;
27338 graph: function() {
27339 return stack[index].graph;
27343 return stack[0].graph;
27346 merge: function(entities, extent) {
27347 stack[0].graph.rebase(entities, _.pluck(stack, 'graph'), false);
27348 tree.rebase(entities, false);
27350 dispatch.change(undefined, extent);
27353 perform: function() {
27354 var previous = stack[index].graph;
27356 stack = stack.slice(0, index + 1);
27357 stack.push(perform(arguments));
27360 return change(previous);
27363 replace: function() {
27364 var previous = stack[index].graph;
27366 // assert(index == stack.length - 1)
27367 stack[index] = perform(arguments);
27369 return change(previous);
27373 var previous = stack[index].graph;
27378 return change(previous);
27382 // Same as calling pop and then perform
27383 overwrite: function() {
27384 var previous = stack[index].graph;
27390 stack = stack.slice(0, index + 1);
27391 stack.push(perform(arguments));
27394 return change(previous);
27398 var previous = stack[index].graph;
27400 // Pop to the next annotated state.
27401 while (index > 0) {
27403 if (stack[index].annotation) break;
27407 return change(previous);
27411 var previous = stack[index].graph;
27413 while (index < stack.length - 1) {
27415 if (stack[index].annotation) break;
27419 return change(previous);
27422 undoAnnotation: function() {
27425 if (stack[i].annotation) return stack[i].annotation;
27430 redoAnnotation: function() {
27432 while (i <= stack.length - 1) {
27433 if (stack[i].annotation) return stack[i].annotation;
27438 intersects: function(extent) {
27439 return tree.intersects(extent, stack[index].graph);
27442 difference: function() {
27443 var base = stack[0].graph,
27444 head = stack[index].graph;
27445 return iD.Difference(base, head);
27448 changes: function(action) {
27449 var base = stack[0].graph,
27450 head = stack[index].graph;
27453 head = action(head);
27456 var difference = iD.Difference(base, head);
27459 modified: difference.modified(),
27460 created: difference.created(),
27461 deleted: difference.deleted()
27465 validate: function(changes) {
27466 return _(iD.validations)
27467 .map(function(fn) { return fn()(changes, stack[index].graph); })
27472 hasChanges: function() {
27473 return this.difference().length() > 0;
27476 imageryUsed: function(sources) {
27478 imageryUsed = sources;
27481 return _(stack.slice(1, index + 1))
27482 .pluck('imageryUsed')
27485 .without(undefined, 'Custom')
27490 reset: function() {
27491 stack = [{graph: iD.Graph()}];
27493 tree = iD.Tree(stack[0].graph);
27498 toJSON: function() {
27499 if (!this.hasChanges()) return;
27501 var allEntities = {},
27505 var s = stack.map(function(i) {
27506 var modified = [], deleted = [];
27508 _.forEach(i.graph.entities, function(entity, id) {
27510 var key = iD.Entity.key(entity);
27511 allEntities[key] = entity;
27512 modified.push(key);
27517 // make sure that the originals of changed or deleted entities get merged
27518 // into the base of the stack after restoring the data from JSON.
27519 if (id in base.graph.entities) {
27520 baseEntities[id] = base.graph.entities[id];
27522 // get originals of parent entities too
27523 _.forEach(base.graph._parentWays[id], function(parentId) {
27524 if (parentId in base.graph.entities) {
27525 baseEntities[parentId] = base.graph.entities[parentId];
27532 if (modified.length) x.modified = modified;
27533 if (deleted.length) x.deleted = deleted;
27534 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
27535 if (i.annotation) x.annotation = i.annotation;
27540 return JSON.stringify({
27542 entities: _.values(allEntities),
27543 baseEntities: _.values(baseEntities),
27545 nextIDs: iD.Entity.id.next,
27550 fromJSON: function(json, loadChildNodes) {
27551 var h = JSON.parse(json),
27552 loadComplete = true;
27554 iD.Entity.id.next = h.nextIDs;
27557 if (h.version === 2 || h.version === 3) {
27558 var allEntities = {};
27560 h.entities.forEach(function(entity) {
27561 allEntities[iD.Entity.key(entity)] = iD.Entity(entity);
27564 if (h.version === 3) {
27565 // This merges originals for changed entities into the base of
27566 // the stack even if the current stack doesn't have them (for
27567 // example when iD has been restarted in a different region)
27568 var baseEntities = h.baseEntities.map(function(d) { return iD.Entity(d); });
27569 stack[0].graph.rebase(baseEntities, _.pluck(stack, 'graph'), true);
27570 tree.rebase(baseEntities, true);
27572 // When we restore a modified way, we also need to fetch any missing
27573 // childnodes that would normally have been downloaded with it.. #2142
27574 if (loadChildNodes) {
27575 var missing = _(baseEntities)
27576 .filter('type', 'way')
27580 .reject(function(n) { return stack[0].graph.hasEntity(n); })
27583 if (!_.isEmpty(missing)) {
27584 loadComplete = false;
27585 context.redrawEnable(false);
27587 var loading = iD.ui.Loading(context).blocking(true);
27588 context.container().call(loading);
27590 var childNodesLoaded = function(err, result) {
27592 var visible = _.groupBy(result.data, 'visible');
27593 if (!_.isEmpty(visible.true)) {
27594 missing = _.difference(missing, _.pluck(visible.true, 'id'));
27595 stack[0].graph.rebase(visible.true, _.pluck(stack, 'graph'), true);
27596 tree.rebase(visible.true, true);
27599 // fetch older versions of nodes that were deleted..
27600 _.each(visible.false, function(entity) {
27601 context.connection()
27602 .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
27606 if (err || _.isEmpty(missing)) {
27608 context.redrawEnable(true);
27613 context.connection().loadMultiple(missing, childNodesLoaded);
27618 stack = h.stack.map(function(d) {
27619 var entities = {}, entity;
27622 d.modified.forEach(function(key) {
27623 entity = allEntities[key];
27624 entities[entity.id] = entity;
27629 d.deleted.forEach(function(id) {
27630 entities[id] = undefined;
27635 graph: iD.Graph(stack[0].graph).load(entities),
27636 annotation: d.annotation,
27637 imageryUsed: d.imageryUsed
27641 } else { // original version
27642 stack = h.stack.map(function(d) {
27645 for (var i in d.entities) {
27646 var entity = d.entities[i];
27647 entities[i] = entity === 'undefined' ? undefined : iD.Entity(entity);
27650 d.graph = iD.Graph(stack[0].graph).load(entities);
27655 if (loadComplete) {
27663 if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
27667 clearSaved: function() {
27668 context.debouncedSave.cancel();
27669 if (lock.locked()) context.storage(getKey('saved_history'), null);
27674 return lock.lock();
27677 unlock: function() {
27681 // is iD not open in another window and it detects that
27682 // there's a history stored in localStorage that's recoverable?
27683 restorableChanges: function() {
27684 return lock.locked() && !!context.storage(getKey('saved_history'));
27687 // load history from a version stored in localStorage
27688 restore: function() {
27689 if (!lock.locked()) return;
27691 var json = context.storage(getKey('saved_history'));
27692 if (json) history.fromJSON(json, true);
27701 return d3.rebind(history, dispatch, 'on');
27703 iD.Node = iD.Entity.node = function iD_Node() {
27704 if (!(this instanceof iD_Node)) {
27705 return (new iD_Node()).initialize(arguments);
27706 } else if (arguments.length) {
27707 this.initialize(arguments);
27711 iD.Node.prototype = Object.create(iD.Entity.prototype);
27713 _.extend(iD.Node.prototype, {
27716 extent: function() {
27717 return new iD.geo.Extent(this.loc);
27720 geometry: function(graph) {
27721 return graph.transient(this, 'geometry', function() {
27722 return graph.isPoi(this) ? 'point' : 'vertex';
27726 move: function(loc) {
27727 return this.update({loc: loc});
27730 isIntersection: function(resolver) {
27731 return resolver.transient(this, 'isIntersection', function() {
27732 return resolver.parentWays(this).filter(function(parent) {
27733 return (parent.tags.highway ||
27734 parent.tags.waterway ||
27735 parent.tags.railway ||
27736 parent.tags.aeroway) &&
27737 parent.geometry(resolver) === 'line';
27742 isHighwayIntersection: function(resolver) {
27743 return resolver.transient(this, 'isHighwayIntersection', function() {
27744 return resolver.parentWays(this).filter(function(parent) {
27745 return parent.tags.highway && parent.geometry(resolver) === 'line';
27750 asJXON: function(changeset_id) {
27753 '@id': this.osmId(),
27754 '@lon': this.loc[0],
27755 '@lat': this.loc[1],
27756 '@version': (this.version || 0),
27757 tag: _.map(this.tags, function(v, k) {
27758 return { keyAttributes: { k: k, v: v } };
27762 if (changeset_id) r.node['@changeset'] = changeset_id;
27766 asGeoJSON: function() {
27769 coordinates: this.loc
27773 iD.Relation = iD.Entity.relation = function iD_Relation() {
27774 if (!(this instanceof iD_Relation)) {
27775 return (new iD_Relation()).initialize(arguments);
27776 } else if (arguments.length) {
27777 this.initialize(arguments);
27781 iD.Relation.prototype = Object.create(iD.Entity.prototype);
27783 iD.Relation.creationOrder = function(a, b) {
27784 var aId = parseInt(iD.Entity.id.toOSM(a.id), 10);
27785 var bId = parseInt(iD.Entity.id.toOSM(b.id), 10);
27787 if (aId < 0 || bId < 0) return aId - bId;
27791 _.extend(iD.Relation.prototype, {
27795 copy: function(resolver, copies) {
27796 if (copies[this.id])
27797 return copies[this.id];
27799 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
27801 var members = this.members.map(function(member) {
27802 return _.extend({}, member, {id: resolver.entity(member.id).copy(resolver, copies).id});
27805 copy = copy.update({members: members});
27806 copies[this.id] = copy;
27811 extent: function(resolver, memo) {
27812 return resolver.transient(this, 'extent', function() {
27813 if (memo && memo[this.id]) return iD.geo.Extent();
27815 memo[this.id] = true;
27817 var extent = iD.geo.Extent();
27818 for (var i = 0; i < this.members.length; i++) {
27819 var member = resolver.hasEntity(this.members[i].id);
27821 extent._extend(member.extent(resolver, memo));
27828 geometry: function(graph) {
27829 return graph.transient(this, 'geometry', function() {
27830 return this.isMultipolygon() ? 'area' : 'relation';
27834 isDegenerate: function() {
27835 return this.members.length === 0;
27838 // Return an array of members, each extended with an 'index' property whose value
27839 // is the member index.
27840 indexedMembers: function() {
27841 var result = new Array(this.members.length);
27842 for (var i = 0; i < this.members.length; i++) {
27843 result[i] = _.extend({}, this.members[i], {index: i});
27848 // Return the first member with the given role. A copy of the member object
27849 // is returned, extended with an 'index' property whose value is the member index.
27850 memberByRole: function(role) {
27851 for (var i = 0; i < this.members.length; i++) {
27852 if (this.members[i].role === role) {
27853 return _.extend({}, this.members[i], {index: i});
27858 // Return the first member with the given id. A copy of the member object
27859 // is returned, extended with an 'index' property whose value is the member index.
27860 memberById: function(id) {
27861 for (var i = 0; i < this.members.length; i++) {
27862 if (this.members[i].id === id) {
27863 return _.extend({}, this.members[i], {index: i});
27868 // Return the first member with the given id and role. A copy of the member object
27869 // is returned, extended with an 'index' property whose value is the member index.
27870 memberByIdAndRole: function(id, role) {
27871 for (var i = 0; i < this.members.length; i++) {
27872 if (this.members[i].id === id && this.members[i].role === role) {
27873 return _.extend({}, this.members[i], {index: i});
27878 addMember: function(member, index) {
27879 var members = this.members.slice();
27880 members.splice(index === undefined ? members.length : index, 0, member);
27881 return this.update({members: members});
27884 updateMember: function(member, index) {
27885 var members = this.members.slice();
27886 members.splice(index, 1, _.extend({}, members[index], member));
27887 return this.update({members: members});
27890 removeMember: function(index) {
27891 var members = this.members.slice();
27892 members.splice(index, 1);
27893 return this.update({members: members});
27896 removeMembersWithID: function(id) {
27897 var members = _.reject(this.members, function(m) { return m.id === id; });
27898 return this.update({members: members});
27901 // Wherever a member appears with id `needle.id`, replace it with a member
27902 // with id `replacement.id`, type `replacement.type`, and the original role,
27903 // unless a member already exists with that id and role. Return an updated
27905 replaceMember: function(needle, replacement) {
27906 if (!this.memberById(needle.id))
27911 for (var i = 0; i < this.members.length; i++) {
27912 var member = this.members[i];
27913 if (member.id !== needle.id) {
27914 members.push(member);
27915 } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
27916 members.push({id: replacement.id, type: replacement.type, role: member.role});
27920 return this.update({members: members});
27923 asJXON: function(changeset_id) {
27926 '@id': this.osmId(),
27927 '@version': this.version || 0,
27928 member: _.map(this.members, function(member) {
27929 return { keyAttributes: { type: member.type, role: member.role, ref: iD.Entity.id.toOSM(member.id) } };
27931 tag: _.map(this.tags, function(v, k) {
27932 return { keyAttributes: { k: k, v: v } };
27936 if (changeset_id) r.relation['@changeset'] = changeset_id;
27940 asGeoJSON: function(resolver) {
27941 return resolver.transient(this, 'GeoJSON', function () {
27942 if (this.isMultipolygon()) {
27944 type: 'MultiPolygon',
27945 coordinates: this.multipolygon(resolver)
27949 type: 'FeatureCollection',
27950 properties: this.tags,
27951 features: this.members.map(function (member) {
27952 return _.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
27959 area: function(resolver) {
27960 return resolver.transient(this, 'area', function() {
27961 return d3.geo.area(this.asGeoJSON(resolver));
27965 isMultipolygon: function() {
27966 return this.tags.type === 'multipolygon';
27969 isComplete: function(resolver) {
27970 for (var i = 0; i < this.members.length; i++) {
27971 if (!resolver.hasEntity(this.members[i].id)) {
27978 isRestriction: function() {
27979 return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
27982 // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
27983 // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
27985 // This corresponds to the structure needed for rendering a multipolygon path using a
27986 // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
27988 // In the case of invalid geometries, this function will still return a result which
27989 // includes the nodes of all way members, but some Nds may be unclosed and some inner
27990 // rings not matched with the intended outer ring.
27992 multipolygon: function(resolver) {
27993 var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
27994 inners = this.members.filter(function(m) { return 'inner' === m.role; });
27996 outers = iD.geo.joinWays(outers, resolver);
27997 inners = iD.geo.joinWays(inners, resolver);
27999 outers = outers.map(function(outer) { return _.pluck(outer.nodes, 'loc'); });
28000 inners = inners.map(function(inner) { return _.pluck(inner.nodes, 'loc'); });
28002 var result = outers.map(function(o) {
28003 // Heuristic for detecting counterclockwise winding order. Assumes
28004 // that OpenStreetMap polygons are not hemisphere-spanning.
28005 return [d3.geo.area({type: 'Polygon', coordinates: [o]}) > 2 * Math.PI ? o.reverse() : o];
28008 function findOuter(inner) {
28011 for (o = 0; o < outers.length; o++) {
28013 if (iD.geo.polygonContainsPolygon(outer, inner))
28017 for (o = 0; o < outers.length; o++) {
28019 if (iD.geo.polygonIntersectsPolygon(outer, inner))
28024 for (var i = 0; i < inners.length; i++) {
28025 var inner = inners[i];
28027 if (d3.geo.area({type: 'Polygon', coordinates: [inner]}) < 2 * Math.PI) {
28028 inner = inner.reverse();
28031 var o = findOuter(inners[i]);
28032 if (o !== undefined)
28033 result[o].push(inners[i]);
28035 result.push([inners[i]]); // Invalid geometry
28043 'chair_lift': true,
28044 'mixed_lift': true,
28049 'magic_carpet': true,
28054 'motorway_link': true
28060 'piste:halfpipe': true
28084 iD.interestingTag = function (key) {
28085 return key !== 'attribution' &&
28086 key !== 'created_by' &&
28087 key !== 'source' &&
28089 key.indexOf('tiger:') !== 0;
28092 iD.Tree = function(head) {
28093 var rtree = rbush(),
28096 function entityRectangle(entity) {
28097 var rect = entity.extent(head).rectangle();
28098 rect.id = entity.id;
28099 rectangles[entity.id] = rect;
28103 function updateParents(entity, insertions, memo) {
28104 head.parentWays(entity).forEach(function(way) {
28105 if (rectangles[way.id]) {
28106 rtree.remove(rectangles[way.id]);
28107 insertions[way.id] = way;
28109 updateParents(way, insertions, memo);
28112 head.parentRelations(entity).forEach(function(relation) {
28113 if (memo[entity.id]) return;
28114 memo[entity.id] = true;
28115 if (rectangles[relation.id]) {
28116 rtree.remove(rectangles[relation.id]);
28117 insertions[relation.id] = relation;
28119 updateParents(relation, insertions, memo);
28125 tree.rebase = function(entities, force) {
28126 var insertions = {};
28128 for (var i = 0; i < entities.length; i++) {
28129 var entity = entities[i];
28131 if (!entity.visible)
28134 if (head.entities.hasOwnProperty(entity.id) || rectangles[entity.id]) {
28137 } else if (rectangles[entity.id]) {
28138 rtree.remove(rectangles[entity.id]);
28142 insertions[entity.id] = entity;
28143 updateParents(entity, insertions, {});
28146 rtree.load(_.map(insertions, entityRectangle));
28151 tree.intersects = function(extent, graph) {
28152 if (graph !== head) {
28153 var diff = iD.Difference(head, graph),
28158 diff.deleted().forEach(function(entity) {
28159 rtree.remove(rectangles[entity.id]);
28160 delete rectangles[entity.id];
28163 diff.modified().forEach(function(entity) {
28164 rtree.remove(rectangles[entity.id]);
28165 insertions[entity.id] = entity;
28166 updateParents(entity, insertions, {});
28169 diff.created().forEach(function(entity) {
28170 insertions[entity.id] = entity;
28173 rtree.load(_.map(insertions, entityRectangle));
28176 return rtree.search(extent.rectangle()).map(function(rect) {
28177 return head.entity(rect.id);
28183 iD.Way = iD.Entity.way = function iD_Way() {
28184 if (!(this instanceof iD_Way)) {
28185 return (new iD_Way()).initialize(arguments);
28186 } else if (arguments.length) {
28187 this.initialize(arguments);
28191 iD.Way.prototype = Object.create(iD.Entity.prototype);
28193 _.extend(iD.Way.prototype, {
28197 copy: function(resolver, copies) {
28198 if (copies[this.id])
28199 return copies[this.id];
28201 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
28203 var nodes = this.nodes.map(function(id) {
28204 return resolver.entity(id).copy(resolver, copies).id;
28207 copy = copy.update({nodes: nodes});
28208 copies[this.id] = copy;
28213 extent: function(resolver) {
28214 return resolver.transient(this, 'extent', function() {
28215 var extent = iD.geo.Extent();
28216 for (var i = 0; i < this.nodes.length; i++) {
28217 var node = resolver.hasEntity(this.nodes[i]);
28219 extent._extend(node.extent());
28226 first: function() {
28227 return this.nodes[0];
28231 return this.nodes[this.nodes.length - 1];
28234 contains: function(node) {
28235 return this.nodes.indexOf(node) >= 0;
28238 affix: function(node) {
28239 if (this.nodes[0] === node) return 'prefix';
28240 if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
28243 layer: function() {
28244 // explicit layer tag, clamp between -10, 10..
28245 if (this.tags.layer !== undefined) {
28246 return Math.max(-10, Math.min(+(this.tags.layer), 10));
28249 // implied layer tag..
28250 if (this.tags.location === 'overground') return 1;
28251 if (this.tags.location === 'underground') return -1;
28252 if (this.tags.location === 'underwater') return -10;
28254 if (this.tags.power === 'line') return 10;
28255 if (this.tags.power === 'minor_line') return 10;
28256 if (this.tags.aerialway) return 10;
28257 if (this.tags.bridge) return 1;
28258 if (this.tags.cutting) return -1;
28259 if (this.tags.tunnel) return -1;
28260 if (this.tags.waterway) return -1;
28261 if (this.tags.man_made === 'pipeline') return -10;
28262 if (this.tags.boundary) return -10;
28266 isOneWay: function() {
28267 // explicit oneway tag..
28268 if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
28269 if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
28271 // implied oneway tag..
28272 for (var key in this.tags) {
28273 if (key in iD.oneWayTags && (this.tags[key] in iD.oneWayTags[key]))
28279 isClosed: function() {
28280 return this.nodes.length > 0 && this.first() === this.last();
28283 isConvex: function(resolver) {
28284 if (!this.isClosed() || this.isDegenerate()) return null;
28286 var nodes = _.uniq(resolver.childNodes(this)),
28287 coords = _.pluck(nodes, 'loc'),
28288 curr = 0, prev = 0;
28290 for (var i = 0; i < coords.length; i++) {
28291 var o = coords[(i+1) % coords.length],
28293 b = coords[(i+2) % coords.length],
28294 res = iD.geo.cross(o, a, b);
28296 curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
28299 } else if (prev && curr !== prev) {
28307 isArea: function() {
28308 if (this.tags.area === 'yes')
28310 if (!this.isClosed() || this.tags.area === 'no')
28312 for (var key in this.tags)
28313 if (key in iD.areaKeys && !(this.tags[key] in iD.areaKeys[key]))
28318 isDegenerate: function() {
28319 return _.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
28322 areAdjacent: function(n1, n2) {
28323 for (var i = 0; i < this.nodes.length; i++) {
28324 if (this.nodes[i] === n1) {
28325 if (this.nodes[i - 1] === n2) return true;
28326 if (this.nodes[i + 1] === n2) return true;
28332 geometry: function(graph) {
28333 return graph.transient(this, 'geometry', function() {
28334 return this.isArea() ? 'area' : 'line';
28338 addNode: function(id, index) {
28339 var nodes = this.nodes.slice();
28340 nodes.splice(index === undefined ? nodes.length : index, 0, id);
28341 return this.update({nodes: nodes});
28344 updateNode: function(id, index) {
28345 var nodes = this.nodes.slice();
28346 nodes.splice(index, 1, id);
28347 return this.update({nodes: nodes});
28350 replaceNode: function(needle, replacement) {
28351 if (this.nodes.indexOf(needle) < 0)
28354 var nodes = this.nodes.slice();
28355 for (var i = 0; i < nodes.length; i++) {
28356 if (nodes[i] === needle) {
28357 nodes[i] = replacement;
28360 return this.update({nodes: nodes});
28363 removeNode: function(id) {
28366 for (var i = 0; i < this.nodes.length; i++) {
28367 var node = this.nodes[i];
28368 if (node !== id && nodes[nodes.length - 1] !== node) {
28373 // Preserve circularity
28374 if (this.nodes.length > 1 && this.first() === id && this.last() === id && nodes[nodes.length - 1] !== nodes[0]) {
28375 nodes.push(nodes[0]);
28378 return this.update({nodes: nodes});
28381 asJXON: function(changeset_id) {
28384 '@id': this.osmId(),
28385 '@version': this.version || 0,
28386 nd: _.map(this.nodes, function(id) {
28387 return { keyAttributes: { ref: iD.Entity.id.toOSM(id) } };
28389 tag: _.map(this.tags, function(v, k) {
28390 return { keyAttributes: { k: k, v: v } };
28394 if (changeset_id) r.way['@changeset'] = changeset_id;
28398 asGeoJSON: function(resolver) {
28399 return resolver.transient(this, 'GeoJSON', function() {
28400 var coordinates = _.pluck(resolver.childNodes(this), 'loc');
28401 if (this.isArea() && this.isClosed()) {
28404 coordinates: [coordinates]
28408 type: 'LineString',
28409 coordinates: coordinates
28415 area: function(resolver) {
28416 return resolver.transient(this, 'area', function() {
28417 var nodes = resolver.childNodes(this);
28421 coordinates: [_.pluck(nodes, 'loc')]
28424 if (!this.isClosed() && nodes.length) {
28425 json.coordinates[0].push(nodes[0].loc);
28428 var area = d3.geo.area(json);
28430 // Heuristic for detecting counterclockwise winding order. Assumes
28431 // that OpenStreetMap polygons are not hemisphere-spanning.
28432 if (area > 2 * Math.PI) {
28433 json.coordinates[0] = json.coordinates[0].reverse();
28434 area = d3.geo.area(json);
28437 return isNaN(area) ? 0 : area;
28441 iD.Background = function(context) {
28442 var dispatch = d3.dispatch('change'),
28443 baseLayer = iD.TileLayer().projection(context.projection),
28444 overlayLayers = [],
28448 function findSource(id) {
28449 return _.find(backgroundSources, function(d) {
28450 return d.id && d.id === id;
28455 function background(selection) {
28456 var base = selection.selectAll('.layer-background')
28460 .insert('div', '.layer-data')
28461 .attr('class', 'layer layer-background');
28463 base.call(baseLayer);
28465 var overlays = selection.selectAll('.layer-overlay')
28466 .data(overlayLayers, function(d) { return d.source().name(); });
28469 .insert('div', '.layer-data')
28470 .attr('class', 'layer layer-overlay');
28472 overlays.each(function(layer) {
28473 d3.select(this).call(layer);
28481 background.updateImagery = function() {
28482 var b = background.baseLayerSource(),
28483 o = overlayLayers.map(function (d) { return d.source().id; }).join(','),
28484 q = iD.util.stringQs(location.hash.substring(1));
28487 if (id === 'custom') {
28488 id = 'custom:' + b.template;
28494 delete q.background;
28503 location.replace('#' + iD.util.qsString(q, true));
28505 var imageryUsed = [b.imageryUsed()];
28507 overlayLayers.forEach(function (d) {
28508 var source = d.source();
28509 if (!source.isLocatorOverlay()) {
28510 imageryUsed.push(source.imageryUsed());
28514 var gpx = context.layers().layer('gpx');
28515 if (gpx && gpx.enabled() && gpx.hasGpx()) {
28516 imageryUsed.push('Local GPX');
28519 context.history().imageryUsed(imageryUsed);
28522 background.sources = function(extent) {
28523 return backgroundSources.filter(function(source) {
28524 return source.intersects(extent);
28528 background.dimensions = function(_) {
28529 baseLayer.dimensions(_);
28531 overlayLayers.forEach(function(layer) {
28532 layer.dimensions(_);
28536 background.baseLayerSource = function(d) {
28537 if (!arguments.length) return baseLayer.source();
28539 baseLayer.source(d);
28541 background.updateImagery();
28546 background.bing = function() {
28547 background.baseLayerSource(findSource('Bing'));
28550 background.showsLayer = function(d) {
28551 return d === baseLayer.source() ||
28552 (d.id === 'custom' && baseLayer.source().id === 'custom') ||
28553 overlayLayers.some(function(l) { return l.source() === d; });
28556 background.overlayLayerSources = function() {
28557 return overlayLayers.map(function (l) { return l.source(); });
28560 background.toggleOverlayLayer = function(d) {
28563 for (var i = 0; i < overlayLayers.length; i++) {
28564 layer = overlayLayers[i];
28565 if (layer.source() === d) {
28566 overlayLayers.splice(i, 1);
28568 background.updateImagery();
28573 layer = iD.TileLayer()
28575 .projection(context.projection)
28576 .dimensions(baseLayer.dimensions());
28578 overlayLayers.push(layer);
28580 background.updateImagery();
28583 background.nudge = function(d, zoom) {
28584 baseLayer.source().nudge(d, zoom);
28589 background.offset = function(d) {
28590 if (!arguments.length) return baseLayer.source().offset();
28591 baseLayer.source().offset(d);
28596 background.load = function(imagery) {
28597 function parseMap(qmap) {
28598 if (!qmap) return false;
28599 var args = qmap.split('/').map(Number);
28600 if (args.length < 3 || args.some(isNaN)) return false;
28601 return iD.geo.Extent([args[1], args[2]]);
28604 var q = iD.util.stringQs(location.hash.substring(1)),
28605 chosen = q.background || q.layer,
28606 extent = parseMap(q.map),
28609 backgroundSources = imagery.map(function(source) {
28610 if (source.type === 'bing') {
28611 return iD.BackgroundSource.Bing(source, dispatch);
28613 return iD.BackgroundSource(source);
28617 backgroundSources.unshift(iD.BackgroundSource.None());
28619 if (!chosen && extent) {
28620 best = _.find(this.sources(extent), function(s) { return s.best(); });
28623 if (chosen && chosen.indexOf('custom:') === 0) {
28624 background.baseLayerSource(iD.BackgroundSource.Custom(chosen.replace(/^custom:/, '')));
28626 background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
28629 var locator = _.find(backgroundSources, function(d) {
28630 return d.overlay && d.default;
28634 background.toggleOverlayLayer(locator);
28637 var overlays = (q.overlays || '').split(',');
28638 overlays.forEach(function(overlay) {
28639 overlay = findSource(overlay);
28640 if (overlay) background.toggleOverlayLayer(overlay);
28644 var gpx = context.layers().layer('gpx');
28645 if (gpx) { gpx.url(q.gpx); }
28649 return d3.rebind(background, dispatch, 'on');
28651 iD.BackgroundSource = function(data) {
28652 var source = _.clone(data),
28654 name = source.name,
28655 best = !!source.best;
28657 source.scaleExtent = data.scaleExtent || [0, 20];
28658 source.overzoom = data.overzoom !== false;
28660 source.offset = function(_) {
28661 if (!arguments.length) return offset;
28666 source.nudge = function(_, zoomlevel) {
28667 offset[0] += _[0] / Math.pow(2, zoomlevel);
28668 offset[1] += _[1] / Math.pow(2, zoomlevel);
28672 source.name = function() {
28676 source.best = function() {
28680 source.imageryUsed = function() {
28681 return source.id || name;
28684 source.url = function(coord) {
28685 return data.template
28686 .replace('{x}', coord[0])
28687 .replace('{y}', coord[1])
28688 // TMS-flipped y coordinate
28689 .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
28690 .replace(/\{z(oom)?\}/, coord[2])
28691 .replace(/\{switch:([^}]+)\}/, function(s, r) {
28692 var subdomains = r.split(',');
28693 return subdomains[(coord[0] + coord[1]) % subdomains.length];
28695 .replace('{u}', function() {
28697 for (var zoom = coord[2]; zoom > 0; zoom--) {
28699 var mask = 1 << (zoom - 1);
28700 if ((coord[0] & mask) !== 0) b++;
28701 if ((coord[1] & mask) !== 0) b += 2;
28708 source.intersects = function(extent) {
28709 extent = extent.polygon();
28710 return !data.polygon || data.polygon.some(function(polygon) {
28711 return iD.geo.polygonIntersectsPolygon(polygon, extent, true);
28715 source.validZoom = function(z) {
28716 return source.scaleExtent[0] <= z &&
28717 (source.overzoom || source.scaleExtent[1] > z);
28720 source.isLocatorOverlay = function() {
28721 return name === 'Locator Overlay';
28724 source.copyrightNotices = function() {};
28729 iD.BackgroundSource.Bing = function(data, dispatch) {
28730 // http://msdn.microsoft.com/en-us/library/ff701716.aspx
28731 // http://msdn.microsoft.com/en-us/library/ff701701.aspx
28733 data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
28735 var bing = iD.BackgroundSource(data),
28736 key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
28737 url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
28738 key + '&jsonp={callback}',
28741 d3.jsonp(url, function(json) {
28742 providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
28744 attribution: provider.attribution,
28745 areas: provider.coverageAreas.map(function(area) {
28747 zoom: [area.zoomMin, area.zoomMax],
28748 extent: iD.geo.Extent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
28756 bing.copyrightNotices = function(zoom, extent) {
28757 zoom = Math.min(zoom, 21);
28758 return providers.filter(function(provider) {
28759 return _.any(provider.areas, function(area) {
28760 return extent.intersects(area.extent) &&
28761 area.zoom[0] <= zoom &&
28762 area.zoom[1] >= zoom;
28764 }).map(function(provider) {
28765 return provider.attribution;
28769 bing.logo = 'bing_maps.png';
28770 bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
28775 iD.BackgroundSource.None = function() {
28776 var source = iD.BackgroundSource({id: 'none', template: ''});
28778 source.name = function() {
28779 return t('background.none');
28782 source.imageryUsed = function() {
28789 iD.BackgroundSource.Custom = function(template) {
28790 var source = iD.BackgroundSource({id: 'custom', template: template});
28792 source.name = function() {
28793 return t('background.custom');
28796 source.imageryUsed = function() {
28797 return 'Custom (' + template + ')';
28802 iD.Features = function(context) {
28803 var traffic_roads = {
28805 'motorway_link': true,
28807 'trunk_link': true,
28809 'primary_link': true,
28811 'secondary_link': true,
28813 'tertiary_link': true,
28814 'residential': true,
28815 'unclassified': true,
28816 'living_street': true
28819 var service_roads = {
28831 'pedestrian': true,
28835 var past_futures = {
28837 'construction': true,
28839 'dismantled': true,
28842 'demolished': true,
28843 'obliterated': true
28846 var dispatch = d3.dispatch('change', 'redraw'),
28854 function update() {
28855 _hidden = features.hidden();
28860 function defineFeature(k, filter, max) {
28864 enabled: true, // whether the user wants it enabled..
28866 currentMax: (max || Infinity),
28867 defaultMax: (max || Infinity),
28868 enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
28869 disable: function() { this.enabled = false; this.currentMax = 0; },
28870 hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
28871 autoHidden: function() { return this.hidden() && this.currentMax > 0; }
28876 defineFeature('points', function isPoint(entity, resolver, geometry) {
28877 return geometry === 'point';
28880 defineFeature('traffic_roads', function isTrafficRoad(entity) {
28881 return traffic_roads[entity.tags.highway];
28884 defineFeature('service_roads', function isServiceRoad(entity) {
28885 return service_roads[entity.tags.highway];
28888 defineFeature('paths', function isPath(entity) {
28889 return paths[entity.tags.highway];
28892 defineFeature('buildings', function isBuilding(entity) {
28894 !!entity.tags['building:part'] ||
28895 (!!entity.tags.building && entity.tags.building !== 'no') ||
28896 entity.tags.amenity === 'shelter' ||
28897 entity.tags.parking === 'multi-storey' ||
28898 entity.tags.parking === 'sheds' ||
28899 entity.tags.parking === 'carports' ||
28900 entity.tags.parking === 'garage_boxes'
28904 defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
28905 return geometry === 'area' &&
28906 !_features.buildings.filter(entity) &&
28907 !_features.water.filter(entity);
28910 defineFeature('boundaries', function isBoundary(entity) {
28911 return !!entity.tags.boundary;
28914 defineFeature('water', function isWater(entity) {
28916 !!entity.tags.waterway ||
28917 entity.tags.natural === 'water' ||
28918 entity.tags.natural === 'coastline' ||
28919 entity.tags.natural === 'bay' ||
28920 entity.tags.landuse === 'pond' ||
28921 entity.tags.landuse === 'basin' ||
28922 entity.tags.landuse === 'reservoir' ||
28923 entity.tags.landuse === 'salt_pond'
28927 defineFeature('rail', function isRail(entity) {
28929 !!entity.tags.railway ||
28930 entity.tags.landuse === 'railway'
28932 traffic_roads[entity.tags.highway] ||
28933 service_roads[entity.tags.highway] ||
28934 paths[entity.tags.highway]
28938 defineFeature('power', function isPower(entity) {
28939 return !!entity.tags.power;
28942 // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
28943 defineFeature('past_future', function isPastFuture(entity) {
28945 traffic_roads[entity.tags.highway] ||
28946 service_roads[entity.tags.highway] ||
28947 paths[entity.tags.highway]
28948 ) { return false; }
28950 var strings = Object.keys(entity.tags);
28952 for (var i = 0; i < strings.length; i++) {
28953 var s = strings[i];
28954 if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
28959 // Lines or areas that don't match another feature filter.
28960 // IMPORTANT: The 'others' feature must be the last one defined,
28961 // so that code in getMatches can skip this test if `hasMatch = true`
28962 defineFeature('others', function isOther(entity, resolver, geometry) {
28963 return (geometry === 'line' || geometry === 'area');
28967 function features() {}
28969 features.features = function() {
28973 features.keys = function() {
28977 features.enabled = function(k) {
28978 if (!arguments.length) {
28979 return _.filter(_keys, function(k) { return _features[k].enabled; });
28981 return _features[k] && _features[k].enabled;
28984 features.disabled = function(k) {
28985 if (!arguments.length) {
28986 return _.reject(_keys, function(k) { return _features[k].enabled; });
28988 return _features[k] && !_features[k].enabled;
28991 features.hidden = function(k) {
28992 if (!arguments.length) {
28993 return _.filter(_keys, function(k) { return _features[k].hidden(); });
28995 return _features[k] && _features[k].hidden();
28998 features.autoHidden = function(k) {
28999 if (!arguments.length) {
29000 return _.filter(_keys, function(k) { return _features[k].autoHidden(); });
29002 return _features[k] && _features[k].autoHidden();
29005 features.enable = function(k) {
29006 if (_features[k] && !_features[k].enabled) {
29007 _features[k].enable();
29012 features.disable = function(k) {
29013 if (_features[k] && _features[k].enabled) {
29014 _features[k].disable();
29019 features.toggle = function(k) {
29020 if (_features[k]) {
29021 (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
29026 features.resetStats = function() {
29027 _.each(_features, function(f) { f.count = 0; });
29031 features.gatherStats = function(d, resolver, dimensions) {
29032 var needsRedraw = false,
29033 type = _.groupBy(d, function(ent) { return ent.type; }),
29034 entities = [].concat(type.relation || [], type.way || [], type.node || []),
29035 currHidden, geometry, matches;
29037 _.each(_features, function(f) { f.count = 0; });
29039 // adjust the threshold for point/building culling based on viewport size..
29040 // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
29041 _cullFactor = dimensions[0] * dimensions[1] / 1000000;
29043 for (var i = 0; i < entities.length; i++) {
29044 geometry = entities[i].geometry(resolver);
29045 if (!(geometry === 'vertex' || geometry === 'relation')) {
29046 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
29047 for (var j = 0; j < matches.length; j++) {
29048 _features[matches[j]].count++;
29053 currHidden = features.hidden();
29054 if (currHidden !== _hidden) {
29055 _hidden = currHidden;
29056 needsRedraw = true;
29060 return needsRedraw;
29063 features.stats = function() {
29064 _.each(_keys, function(k) { _stats[k] = _features[k].count; });
29068 features.clear = function(d) {
29069 for (var i = 0; i < d.length; i++) {
29070 features.clearEntity(d[i]);
29074 features.clearEntity = function(entity) {
29075 delete _cache[iD.Entity.key(entity)];
29078 features.reset = function() {
29082 features.getMatches = function(entity, resolver, geometry) {
29083 if (geometry === 'vertex' || geometry === 'relation') return {};
29085 var ent = iD.Entity.key(entity);
29086 if (!_cache[ent]) {
29090 if (!_cache[ent].matches) {
29094 for (var i = 0; i < _keys.length; i++) {
29095 if (_keys[i] === 'others') {
29096 if (hasMatch) continue;
29098 // Multipolygon members:
29100 // 1. is a way that hasn't matched other "interesting" feature rules,
29101 // 2. and it belongs to a single parent multipolygon relation
29102 // ...then match whatever feature rules the parent multipolygon has matched.
29103 // see #2548, #2887
29106 // For this to work, getMatches must be called on relations before ways.
29108 if (entity.type === 'way') {
29109 var parents = features.getParents(entity, resolver, geometry);
29110 if (parents.length === 1 && parents[0].isMultipolygon()) {
29111 var pkey = iD.Entity.key(parents[0]);
29112 if (_cache[pkey] && _cache[pkey].matches) {
29113 matches = _.clone(_cache[pkey].matches);
29120 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
29121 matches[_keys[i]] = hasMatch = true;
29124 _cache[ent].matches = matches;
29127 return _cache[ent].matches;
29130 features.getParents = function(entity, resolver, geometry) {
29131 if (geometry === 'point') return [];
29133 var ent = iD.Entity.key(entity);
29134 if (!_cache[ent]) {
29138 if (!_cache[ent].parents) {
29140 if (geometry === 'vertex') {
29141 parents = resolver.parentWays(entity);
29142 } else { // 'line', 'area', 'relation'
29143 parents = resolver.parentRelations(entity);
29145 _cache[ent].parents = parents;
29147 return _cache[ent].parents;
29150 features.isHiddenFeature = function(entity, resolver, geometry) {
29151 if (!_hidden.length) return false;
29152 if (!entity.version) return false;
29154 var matches = features.getMatches(entity, resolver, geometry);
29156 for (var i = 0; i < _hidden.length; i++) {
29157 if (matches[_hidden[i]]) return true;
29162 features.isHiddenChild = function(entity, resolver, geometry) {
29163 if (!_hidden.length) return false;
29164 if (!entity.version || geometry === 'point') return false;
29166 var parents = features.getParents(entity, resolver, geometry);
29167 if (!parents.length) return false;
29169 for (var i = 0; i < parents.length; i++) {
29170 if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
29177 features.hasHiddenConnections = function(entity, resolver) {
29178 if (!_hidden.length) return false;
29179 var childNodes, connections;
29181 if (entity.type === 'midpoint') {
29182 childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
29185 childNodes = entity.nodes ? resolver.childNodes(entity) : [];
29186 connections = features.getParents(entity, resolver, entity.geometry(resolver));
29189 // gather ways connected to child nodes..
29190 connections = _.reduce(childNodes, function(result, e) {
29191 return resolver.isShared(e) ? _.union(result, resolver.parentWays(e)) : result;
29194 return connections.length ? _.any(connections, function(e) {
29195 return features.isHidden(e, resolver, e.geometry(resolver));
29199 features.isHidden = function(entity, resolver, geometry) {
29200 if (!_hidden.length) return false;
29201 if (!entity.version) return false;
29203 var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
29204 return fn(entity, resolver, geometry);
29207 features.filter = function(d, resolver) {
29208 if (!_hidden.length) return d;
29211 for (var i = 0; i < d.length; i++) {
29213 if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
29214 result.push(entity);
29220 return d3.rebind(features, dispatch, 'on');
29222 iD.Map = function(context) {
29223 var dimensions = [1, 1],
29224 dispatch = d3.dispatch('move', 'drawn'),
29225 projection = context.projection,
29226 zoom = d3.behavior.zoom()
29227 .translate(projection.translate())
29228 .scale(projection.scale() * 2 * Math.PI)
29229 .scaleExtent([1024, 256 * Math.pow(2, 24)])
29230 .on('zoom', zoomPan),
29231 dblclickEnabled = true,
29232 redrawEnabled = true,
29234 transformed = false,
29236 drawLayers = iD.svg.Layers(projection, context),
29237 drawPoints = iD.svg.Points(projection, context),
29238 drawVertices = iD.svg.Vertices(projection, context),
29239 drawLines = iD.svg.Lines(projection),
29240 drawAreas = iD.svg.Areas(projection),
29241 drawMidpoints = iD.svg.Midpoints(projection, context),
29242 drawLabels = iD.svg.Labels(projection, context),
29249 function map(selection) {
29251 .on('change.map', redraw);
29252 context.background()
29253 .on('change.map', redraw);
29255 .on('redraw.map', redraw);
29257 .on('change.map', function() {
29258 context.background().updateImagery();
29263 .on('dblclick.map', dblClick)
29266 supersurface = selection.append('div')
29267 .attr('id', 'supersurface')
29268 .call(iD.util.setTransform, 0, 0);
29270 // Need a wrapper div because Opera can't cope with an absolutely positioned
29271 // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
29272 wrapper = supersurface
29274 .attr('class', 'layer layer-data');
29276 map.surface = surface = wrapper
29278 .selectAll('.surface')
29279 .attr('id', 'surface');
29282 .on('mousedown.zoom', function() {
29283 if (d3.event.button === 2) {
29284 d3.event.stopPropagation();
29287 .on('mouseup.zoom', function() {
29288 if (resetTransform()) redraw();
29290 .on('mousemove.map', function() {
29291 mousemove = d3.event;
29293 .on('mouseover.vertices', function() {
29294 if (map.editable() && !transformed) {
29295 var hover = d3.event.target.__data__;
29296 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
29297 dispatch.drawn({full: false});
29300 .on('mouseout.vertices', function() {
29301 if (map.editable() && !transformed) {
29302 var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__;
29303 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
29304 dispatch.drawn({full: false});
29310 .call(context.background());
29313 context.on('enter.map', function() {
29314 if (map.editable() && !transformed) {
29315 var all = context.intersects(map.extent()),
29316 filter = d3.functor(true),
29317 graph = context.graph();
29319 all = context.features().filter(all, graph);
29321 .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
29322 .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
29323 dispatch.drawn({full: false});
29327 map.dimensions(selection.dimensions());
29329 drawLabels.supersurface(supersurface);
29332 function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }
29334 function drawVector(difference, extent) {
29335 var graph = context.graph(),
29336 features = context.features(),
29337 all = context.intersects(map.extent()),
29341 var complete = difference.complete(map.extent());
29342 data = _.compact(_.values(complete));
29343 filter = function(d) { return d.id in complete; };
29344 features.clear(data);
29347 // force a full redraw if gatherStats detects that a feature
29348 // should be auto-hidden (e.g. points or buildings)..
29349 if (features.gatherStats(all, graph, dimensions)) {
29350 extent = undefined;
29354 data = context.intersects(map.extent().intersection(extent));
29355 var set = d3.set(_.pluck(data, 'id'));
29356 filter = function(d) { return set.has(d.id); };
29360 filter = d3.functor(true);
29364 data = features.filter(data, graph);
29367 .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
29368 .call(drawLines, graph, data, filter)
29369 .call(drawAreas, graph, data, filter)
29370 .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
29371 .call(drawLabels, graph, data, filter, dimensions, !difference && !extent)
29372 .call(drawPoints, graph, data, filter);
29374 dispatch.drawn({full: true});
29377 function editOff() {
29378 context.features().resetStats();
29379 surface.selectAll('.layer-osm *').remove();
29380 dispatch.drawn({full: true});
29383 function dblClick() {
29384 if (!dblclickEnabled) {
29385 d3.event.preventDefault();
29386 d3.event.stopImmediatePropagation();
29390 function zoomPan() {
29391 if (Math.log(d3.event.scale) / Math.LN2 - 8 < minzoom) {
29392 surface.interrupt();
29393 iD.ui.flash(context.container())
29394 .select('.content')
29395 .text(t('cannot_zoom'));
29396 setZoom(context.minEditableZoom(), true);
29398 dispatch.move(map);
29403 .translate(d3.event.translate)
29404 .scale(d3.event.scale / (2 * Math.PI));
29406 var scale = d3.event.scale / transformStart[0],
29407 tX = (d3.event.translate[0] / scale - transformStart[1][0]) * scale,
29408 tY = (d3.event.translate[1] / scale - transformStart[1][1]) * scale;
29410 transformed = true;
29411 iD.util.setTransform(supersurface, tX, tY, scale);
29414 dispatch.move(map);
29417 function resetTransform() {
29418 if (!transformed) return false;
29420 surface.selectAll('.radial-menu').interrupt().remove();
29421 iD.util.setTransform(supersurface, 0, 0);
29422 transformed = false;
29426 function redraw(difference, extent) {
29427 if (!surface || !redrawEnabled) return;
29429 clearTimeout(timeoutId);
29431 // If we are in the middle of a zoom/pan, we can't do differenced redraws.
29432 // It would result in artifacts where differenced entities are redrawn with
29433 // one transform and unchanged entities with another.
29434 if (resetTransform()) {
29435 difference = extent = undefined;
29438 var zoom = String(~~map.zoom());
29439 if (surface.attr('data-zoom') !== zoom) {
29440 surface.attr('data-zoom', zoom)
29441 .classed('low-zoom', zoom <= 16);
29445 supersurface.call(context.background());
29449 if (map.editable()) {
29450 context.loadTiles(projection, dimensions);
29451 drawVector(difference, extent);
29460 projection.scale() * 2 * Math.PI,
29461 projection.translate().slice()];
29467 function queueRedraw() {
29468 clearTimeout(timeoutId);
29469 timeoutId = setTimeout(function() { redraw(); }, 300);
29472 function pointLocation(p) {
29473 var translate = projection.translate(),
29474 scale = projection.scale() * 2 * Math.PI;
29475 return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
29478 function locationPoint(l) {
29479 var translate = projection.translate(),
29480 scale = projection.scale() * 2 * Math.PI;
29481 return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
29484 map.mouse = function() {
29485 var e = mousemove || d3.event, s;
29486 while ((s = e.sourceEvent)) e = s;
29490 map.mouseCoordinates = function() {
29491 return projection.invert(map.mouse());
29494 map.dblclickEnable = function(_) {
29495 if (!arguments.length) return dblclickEnabled;
29496 dblclickEnabled = _;
29500 map.redrawEnable = function(_) {
29501 if (!arguments.length) return redrawEnabled;
29506 function interpolateZoom(_) {
29507 var k = projection.scale(),
29508 t = projection.translate();
29510 surface.node().__chart__ = {
29517 projection.scale(k).translate(t); // undo setZoom projection changes
29519 zoom.event(surface.transition());
29522 function setZoom(_, force) {
29523 if (_ === map.zoom() && !force)
29525 var scale = 256 * Math.pow(2, _),
29526 center = pxCenter(),
29527 l = pointLocation(center);
29528 scale = Math.max(1024, Math.min(256 * Math.pow(2, 24), scale));
29529 projection.scale(scale / (2 * Math.PI));
29531 var t = projection.translate();
29532 l = locationPoint(l);
29533 t[0] += center[0] - l[0];
29534 t[1] += center[1] - l[1];
29535 projection.translate(t);
29536 zoom.translate(projection.translate());
29540 function setCenter(_) {
29541 var c = map.center();
29542 if (_[0] === c[0] && _[1] === c[1])
29544 var t = projection.translate(),
29546 ll = projection(_);
29547 projection.translate([
29548 t[0] - ll[0] + pxC[0],
29549 t[1] - ll[1] + pxC[1]]);
29550 zoom.translate(projection.translate());
29554 map.pan = function(d) {
29555 var t = projection.translate();
29558 projection.translate(t);
29559 zoom.translate(projection.translate());
29560 dispatch.move(map);
29564 map.dimensions = function(_) {
29565 if (!arguments.length) return dimensions;
29566 var center = map.center();
29568 drawLayers.dimensions(dimensions);
29569 context.background().dimensions(dimensions);
29570 projection.clipExtent([[0, 0], dimensions]);
29571 mouse = iD.util.fastMouse(supersurface.node());
29576 function zoomIn(integer) {
29577 interpolateZoom(~~map.zoom() + integer);
29580 function zoomOut(integer) {
29581 interpolateZoom(~~map.zoom() - integer);
29584 map.zoomIn = function() { zoomIn(1); };
29585 map.zoomInFurther = function() { zoomIn(4); };
29587 map.zoomOut = function() { zoomOut(1); };
29588 map.zoomOutFurther = function() { zoomOut(4); };
29590 map.center = function(loc) {
29591 if (!arguments.length) {
29592 return projection.invert(pxCenter());
29595 if (setCenter(loc)) {
29596 dispatch.move(map);
29602 map.zoom = function(z) {
29603 if (!arguments.length) {
29604 return Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8, 0);
29608 surface.interrupt();
29609 iD.ui.flash(context.container())
29610 .select('.content')
29611 .text(t('cannot_zoom'));
29612 z = context.minEditableZoom();
29616 dispatch.move(map);
29622 map.zoomTo = function(entity, zoomLimits) {
29623 var extent = entity.extent(context.graph());
29624 if (!isFinite(extent.area())) return;
29626 var zoom = map.trimmedExtentZoom(extent);
29627 zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
29628 map.centerZoom(extent.center(), Math.min(Math.max(zoom, zoomLimits[0]), zoomLimits[1]));
29631 map.centerZoom = function(loc, z) {
29632 var centered = setCenter(loc),
29633 zoomed = setZoom(z);
29635 if (centered || zoomed) {
29636 dispatch.move(map);
29642 map.centerEase = function(loc) {
29643 var from = map.center().slice(),
29647 surface.one('mousedown.ease', function() {
29651 d3.timer(function() {
29652 if (stop) return true;
29653 map.center(iD.geo.interp(from, loc, (t += 1) / 10));
29659 map.extent = function(_) {
29660 if (!arguments.length) {
29661 return new iD.geo.Extent(projection.invert([0, dimensions[1]]),
29662 projection.invert([dimensions[0], 0]));
29664 var extent = iD.geo.Extent(_);
29665 map.centerZoom(extent.center(), map.extentZoom(extent));
29669 map.trimmedExtent = function(_) {
29670 if (!arguments.length) {
29671 var headerY = 60, footerY = 30, pad = 10;
29672 return new iD.geo.Extent(projection.invert([pad, dimensions[1] - footerY - pad]),
29673 projection.invert([dimensions[0] - pad, headerY + pad]));
29675 var extent = iD.geo.Extent(_);
29676 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
29680 function calcZoom(extent, dim) {
29681 var tl = projection([extent[0][0], extent[1][1]]),
29682 br = projection([extent[1][0], extent[0][1]]);
29684 // Calculate maximum zoom that fits extent
29685 var hFactor = (br[0] - tl[0]) / dim[0],
29686 vFactor = (br[1] - tl[1]) / dim[1],
29687 hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
29688 vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
29689 newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
29694 map.extentZoom = function(_) {
29695 return calcZoom(iD.geo.Extent(_), dimensions);
29698 map.trimmedExtentZoom = function(_) {
29699 var trimY = 120, trimX = 40,
29700 trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
29701 return calcZoom(iD.geo.Extent(_), trimmed);
29704 map.editable = function() {
29705 return map.zoom() >= context.minEditableZoom();
29708 map.minzoom = function(_) {
29709 if (!arguments.length) return minzoom;
29714 map.layers = drawLayers;
29716 return d3.rebind(map, dispatch, 'on');
29718 iD.TileLayer = function() {
29719 var tileSize = 256,
29720 tile = d3.geo.tile(),
29725 transformProp = iD.util.prefixCSSProperty('Transform'),
29726 source = d3.functor('');
29729 // blacklist overlay tiles around Null Island..
29730 function nearNullIsland(x, y, z) {
29732 var center = Math.pow(2, z - 1),
29733 width = Math.pow(2, z - 6),
29734 min = center - (width / 2),
29735 max = center + (width / 2) - 1;
29736 return x >= min && x <= max && y >= min && y <= max;
29741 function tileSizeAtZoom(d, z) {
29742 var epsilon = 0.002;
29743 return ((tileSize * Math.pow(2, z - d[2])) / tileSize) + epsilon;
29746 function atZoom(t, distance) {
29747 var power = Math.pow(2, distance);
29749 Math.floor(t[0] * power),
29750 Math.floor(t[1] * power),
29754 function lookUp(d) {
29755 for (var up = -1; up > -d[2]; up--) {
29756 var tile = atZoom(d, up);
29757 if (cache[source.url(tile)] !== false) {
29763 function uniqueBy(a, n) {
29764 var o = [], seen = {};
29765 for (var i = 0; i < a.length; i++) {
29766 if (seen[a[i][n]] === undefined) {
29768 seen[a[i][n]] = true;
29774 function addSource(d) {
29775 d.push(source.url(d));
29779 // Update tiles based on current state of `projection`.
29780 function background(selection) {
29781 tile.scale(projection.scale() * 2 * Math.PI)
29782 .translate(projection.translate());
29785 projection.scale() * Math.PI - projection.translate()[0],
29786 projection.scale() * Math.PI - projection.translate()[1]];
29788 z = Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
29793 // Derive the tiles onscreen, remove those offscreen and position them.
29794 // Important that this part not depend on `projection` because it's
29795 // rentered when tiles load/error (see #644).
29796 function render(selection) {
29799 if (source.validZoom(z)) {
29800 tile().forEach(function(d) {
29802 if (d[3] === '') return;
29803 if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
29805 if (cache[d[3]] === false && lookUp(d)) {
29806 requests.push(addSource(lookUp(d)));
29810 requests = uniqueBy(requests, 3).filter(function(r) {
29811 if (!!source.overlay && nearNullIsland(r[0], r[1], r[2])) {
29814 // don't re-request tiles which have failed in the past
29815 return cache[r[3]] !== false;
29819 var pixelOffset = [
29820 source.offset()[0] * Math.pow(2, z),
29821 source.offset()[1] * Math.pow(2, z)
29825 cache[d[3]] = true;
29829 .classed('tile-loaded', true);
29833 function error(d) {
29834 cache[d[3]] = false;
29842 function imageTransform(d) {
29843 var _ts = tileSize * Math.pow(2, z - d[2]);
29844 var scale = tileSizeAtZoom(d, z);
29845 return 'translate(' +
29846 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
29847 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
29848 'scale(' + scale + ',' + scale + ')';
29851 var image = selection
29853 .data(requests, function(d) { return d[3]; });
29856 .style(transformProp, imageTransform)
29857 .classed('tile-removing', true)
29859 var tile = d3.select(this);
29860 window.setTimeout(function() {
29861 if (tile.classed('tile-removing')) {
29867 image.enter().append('img')
29868 .attr('class', 'tile')
29869 .attr('src', function(d) { return d[3]; })
29870 .on('error', error)
29874 .style(transformProp, imageTransform)
29875 .classed('tile-removing', false);
29878 background.projection = function(_) {
29879 if (!arguments.length) return projection;
29884 background.dimensions = function(_) {
29885 if (!arguments.length) return tile.size();
29890 background.source = function(_) {
29891 if (!arguments.length) return source;
29894 tile.scaleExtent(source.scaleExtent);
29901 PointTransform: function(projection) {
29902 return function(entity) {
29903 // http://jsperf.com/short-array-join
29904 var pt = projection(entity.loc);
29905 return 'translate(' + pt[0] + ',' + pt[1] + ')';
29909 Path: function(projection, graph, polygon) {
29911 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
29912 project = projection.stream,
29913 path = d3.geo.path()
29914 .projection({stream: function(output) { return polygon ? project(output) : project(clip(output)); }});
29916 return function(entity) {
29917 if (entity.id in cache) {
29918 return cache[entity.id];
29920 return cache[entity.id] = path(entity.asGeoJSON(graph));
29925 OneWaySegments: function(projection, graph, dt) {
29926 return function(entity) {
29932 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
29933 coordinates = graph.childNodes(entity).map(function(n) {
29937 if (entity.tags.oneway === '-1') coordinates.reverse();
29940 type: 'LineString',
29941 coordinates: coordinates
29942 }, projection.stream(clip({
29943 lineStart: function() {},
29944 lineEnd: function() {
29947 point: function(x, y) {
29951 var span = iD.geo.euclideanDistance(a, b) - offset;
29954 var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
29955 dx = dt * Math.cos(angle),
29956 dy = dt * Math.sin(angle),
29957 p = [a[0] + offset * Math.cos(angle),
29958 a[1] + offset * Math.sin(angle)];
29960 var segment = 'M' + a[0] + ',' + a[1] +
29961 'L' + p[0] + ',' + p[1];
29963 for (span -= dt; span >= 0; span -= dt) {
29966 segment += 'L' + p[0] + ',' + p[1];
29969 segment += 'L' + b[0] + ',' + b[1];
29970 segments.push({id: entity.id, index: i, d: segment});
29985 RelationMemberTags: function(graph) {
29986 return function(entity) {
29987 var tags = entity.tags;
29988 graph.parentRelations(entity).forEach(function(relation) {
29989 var type = relation.tags.type;
29990 if (type === 'multipolygon' || type === 'boundary') {
29991 tags = _.extend({}, relation.tags, tags);
29998 iD.svg.Areas = function(projection) {
29999 // Patterns only work in Firefox when set directly on element.
30000 // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
30002 wetland: 'wetland',
30005 construction: 'construction',
30006 military: 'construction',
30007 cemetery: 'cemetery',
30008 grave_yard: 'cemetery',
30011 farmland: 'farmland',
30015 var patternKeys = ['landuse', 'natural', 'amenity'];
30017 function setPattern(d) {
30018 for (var i = 0; i < patternKeys.length; i++) {
30019 if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
30020 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
30024 this.style.fill = this.style.stroke = '';
30027 return function drawAreas(surface, graph, entities, filter) {
30028 var path = iD.svg.Path(projection, graph, true),
30032 for (var i = 0; i < entities.length; i++) {
30033 var entity = entities[i];
30034 if (entity.geometry(graph) !== 'area') continue;
30036 multipolygon = iD.geo.isSimpleMultipolygonOuterMember(entity, graph);
30037 if (multipolygon) {
30038 areas[multipolygon.id] = {
30039 entity: multipolygon.mergeTags(entity.tags),
30040 area: Math.abs(entity.area(graph))
30042 } else if (!areas[entity.id]) {
30043 areas[entity.id] = {
30045 area: Math.abs(entity.area(graph))
30050 areas = d3.values(areas).filter(function hasPath(a) { return path(a.entity); });
30051 areas.sort(function areaSort(a, b) { return b.area - a.area; });
30052 areas = _.pluck(areas, 'entity');
30054 var strokes = areas.filter(function(area) {
30055 return area.type === 'way';
30065 var clipPaths = surface.selectAll('defs').selectAll('.clipPath')
30067 .data(data.clip, iD.Entity.key);
30070 .append('clipPath')
30071 .attr('class', 'clipPath')
30072 .attr('id', function(entity) { return entity.id + '-clippath'; })
30075 clipPaths.selectAll('path')
30081 var areagroup = surface
30082 .selectAll('.layer-areas')
30083 .selectAll('g.areagroup')
30084 .data(['fill', 'shadow', 'stroke']);
30088 .attr('class', function(d) { return 'layer areagroup area-' + d; });
30090 var paths = areagroup
30093 .data(function(layer) { return data[layer]; }, iD.Entity.key);
30095 // Remove exiting areas first, so they aren't included in the `fills`
30096 // array used for sorting below (https://github.com/openstreetmap/iD/issues/1903).
30100 var fills = surface.selectAll('.area-fill path.area')[0];
30102 var bisect = d3.bisector(function(node) {
30103 return -node.__data__.area(graph);
30106 function sortedByArea(entity) {
30107 if (this.__data__ === 'fill') {
30108 return fills[bisect(fills, -entity.area(graph))];
30113 .insert('path', sortedByArea)
30114 .each(function(entity) {
30115 var layer = this.parentNode.__data__;
30117 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
30119 if (layer === 'fill') {
30120 this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
30121 setPattern.apply(this, arguments);
30124 .call(iD.svg.TagClasses());
30131 A standalone SVG element that contains only a `defs` sub-element. To be
30132 used once globally, since defs IDs must be unique within a document.
30134 iD.svg.Defs = function(context) {
30136 function SVGSpriteDefinition(id, href) {
30137 return function(defs) {
30138 d3.xml(href, 'image/svg+xml', function(err, svg) {
30140 defs.node().appendChild(
30141 d3.select(svg.documentElement).attr('id', id).node()
30147 return function drawDefs(selection) {
30148 var defs = selection.append('defs');
30151 defs.append('marker')
30153 id: 'oneway-marker',
30154 viewBox: '0 0 10 10',
30159 markerUnits: 'strokeWidth',
30163 .attr('class', 'oneway')
30164 .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')
30165 .attr('stroke', 'none')
30166 .attr('fill', '#000')
30167 .attr('opacity', '0.5');
30170 var patterns = defs.selectAll('pattern')
30172 // pattern name, pattern image name
30173 ['wetland', 'wetland'],
30174 ['construction', 'construction'],
30175 ['cemetery', 'cemetery'],
30176 ['orchard', 'orchard'],
30177 ['farmland', 'farmland'],
30186 return 'pattern-' + d[0];
30190 patternUnits: 'userSpaceOnUse'
30193 patterns.append('rect')
30199 'class': function (d) {
30200 return 'pattern-color-' + d[0];
30204 patterns.append('image')
30211 .attr('xlink:href', function (d) {
30212 return context.imagePath('pattern/' + d[1] + '.png');
30217 .data([12, 18, 20, 32, 45])
30218 .enter().append('clipPath')
30219 .attr('id', function (d) {
30220 return 'clip-square-' + d;
30225 .attr('width', function (d) {
30228 .attr('height', function (d) {
30232 defs.call(SVGSpriteDefinition(
30234 context.imagePath('iD-sprite.svg')));
30236 defs.call(SVGSpriteDefinition(
30238 context.imagePath('maki-sprite.svg')));
30241 iD.svg.Gpx = function(projection, context, dispatch) {
30242 var showLabels = true,
30246 if (iD.svg.Gpx.initialized) return; // run once
30248 iD.svg.Gpx.geojson = {};
30249 iD.svg.Gpx.enabled = true;
30252 d3.event.stopPropagation();
30253 d3.event.preventDefault();
30254 d3.event.dataTransfer.dropEffect = 'copy';
30258 .attr('dropzone', 'copy')
30259 .on('drop.localgpx', function() {
30260 d3.event.stopPropagation();
30261 d3.event.preventDefault();
30262 if (!iD.detect().filedrop) return;
30263 drawGpx.files(d3.event.dataTransfer.files);
30265 .on('dragenter.localgpx', over)
30266 .on('dragexit.localgpx', over)
30267 .on('dragover.localgpx', over);
30269 iD.svg.Gpx.initialized = true;
30273 function drawGpx(surface) {
30274 var geojson = iD.svg.Gpx.geojson,
30275 enabled = iD.svg.Gpx.enabled;
30277 layer = surface.selectAll('.layer-gpx')
30278 .data(enabled ? [0] : []);
30282 .attr('class', 'layer-gpx');
30294 .attr('class', 'gpx');
30299 var path = d3.geo.path()
30300 .projection(projection);
30306 var labels = layer.selectAll('text')
30307 .data(showLabels && geojson.features ? geojson.features : []);
30311 .attr('class', 'gpx');
30317 .text(function(d) {
30318 return d.properties.desc || d.properties.name;
30320 .attr('x', function(d) {
30321 var centroid = path.centroid(d);
30322 return centroid[0] + 7;
30324 .attr('y', function(d) {
30325 var centroid = path.centroid(d);
30326 return centroid[1];
30331 function toDom(x) {
30332 return (new DOMParser()).parseFromString(x, 'text/xml');
30335 drawGpx.showLabels = function(_) {
30336 if (!arguments.length) return showLabels;
30341 drawGpx.enabled = function(_) {
30342 if (!arguments.length) return iD.svg.Gpx.enabled;
30343 iD.svg.Gpx.enabled = _;
30348 drawGpx.hasGpx = function() {
30349 var geojson = iD.svg.Gpx.geojson;
30350 return (!(_.isEmpty(geojson) || _.isEmpty(geojson.features)));
30353 drawGpx.geojson = function(gj) {
30354 if (!arguments.length) return iD.svg.Gpx.geojson;
30355 if (_.isEmpty(gj) || _.isEmpty(gj.features)) return this;
30356 iD.svg.Gpx.geojson = gj;
30361 drawGpx.url = function(url) {
30362 d3.text(url, function(err, data) {
30364 drawGpx.geojson(toGeoJSON.gpx(toDom(data)));
30370 drawGpx.files = function(fileList) {
30371 if (!fileList.length) return this;
30372 var f = fileList[0],
30373 reader = new FileReader();
30375 reader.onload = function(e) {
30376 drawGpx.geojson(toGeoJSON.gpx(toDom(e.target.result))).fitZoom();
30379 reader.readAsText(f);
30383 drawGpx.fitZoom = function() {
30384 if (!this.hasGpx()) return this;
30385 var geojson = iD.svg.Gpx.geojson;
30387 var map = context.map(),
30388 viewport = map.trimmedExtent().polygon(),
30389 coords = _.reduce(geojson.features, function(coords, feature) {
30390 var c = feature.geometry.coordinates;
30391 return _.union(coords, feature.geometry.type === 'Point' ? [c] : c);
30394 if (!iD.geo.polygonIntersectsPolygon(viewport, coords, true)) {
30395 var extent = iD.geo.Extent(d3.geo.bounds(geojson));
30396 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
30405 iD.svg.Icon = function(name, svgklass, useklass) {
30406 return function drawIcon(selection) {
30407 selection.selectAll('svg')
30411 .attr('class', 'icon ' + (svgklass || ''))
30413 .attr('xlink:href', name)
30414 .attr('class', useklass);
30417 iD.svg.Labels = function(projection, context) {
30418 var path = d3.geo.path().projection(projection);
30420 // Replace with dict and iterate over entities tags instead?
30421 var label_stack = [
30422 ['line', 'aeroway'],
30423 ['line', 'highway'],
30424 ['line', 'railway'],
30425 ['line', 'waterway'],
30426 ['area', 'aeroway'],
30427 ['area', 'amenity'],
30428 ['area', 'building'],
30429 ['area', 'historic'],
30430 ['area', 'leisure'],
30431 ['area', 'man_made'],
30432 ['area', 'natural'],
30434 ['area', 'tourism'],
30435 ['point', 'aeroway'],
30436 ['point', 'amenity'],
30437 ['point', 'building'],
30438 ['point', 'historic'],
30439 ['point', 'leisure'],
30440 ['point', 'man_made'],
30441 ['point', 'natural'],
30443 ['point', 'tourism'],
30449 var default_size = 12;
30451 var font_sizes = label_stack.map(function(d) {
30452 var style = iD.util.getStyle('text.' + d[0] + '.tag-' + d[1]),
30453 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
30454 if (m) return parseInt(m[1], 10);
30456 style = iD.util.getStyle('text.' + d[0]);
30457 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
30458 if (m) return parseInt(m[1], 10);
30460 return default_size;
30465 var pointOffsets = [
30466 [15, -11, 'start'], // right
30467 [10, -11, 'start'], // unused right now
30471 var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25,
30472 75, 20, 80, 15, 95, 10, 90, 5, 95];
30475 var noIcons = ['building', 'landuse', 'natural'];
30476 function blacklisted(preset) {
30477 return _.any(noIcons, function(s) {
30478 return preset.id.indexOf(s) >= 0;
30482 function get(array, prop) {
30483 return function(d, i) { return array[i][prop]; };
30486 var textWidthCache = {};
30488 function textWidth(text, size, elem) {
30489 var c = textWidthCache[size];
30490 if (!c) c = textWidthCache[size] = {};
30496 c[text] = elem.getComputedTextLength();
30500 var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
30501 if (str === null) {
30502 return size / 3 * 2 * text.length;
30504 return size / 3 * (2 * text.length + str.length);
30509 function drawLineLabels(group, entities, filter, classes, labels) {
30510 var texts = group.selectAll('text.' + classes)
30512 .data(entities, iD.Entity.key);
30516 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
30517 .append('textPath')
30518 .attr('class', 'textpath');
30521 texts.selectAll('.textpath')
30523 .data(entities, iD.Entity.key)
30525 'startOffset': '50%',
30526 'xlink:href': function(d) { return '#labelpath-' + d.id; }
30528 .text(iD.util.displayName);
30530 texts.exit().remove();
30533 function drawLinePaths(group, entities, filter, classes, labels) {
30534 var halos = group.selectAll('path')
30536 .data(entities, iD.Entity.key);
30540 .style('stroke-width', get(labels, 'font-size'))
30541 .attr('id', function(d) { return 'labelpath-' + d.id; })
30542 .attr('class', classes);
30544 halos.attr('d', get(labels, 'lineString'));
30546 halos.exit().remove();
30549 function drawPointLabels(group, entities, filter, classes, labels) {
30550 var texts = group.selectAll('text.' + classes)
30552 .data(entities, iD.Entity.key);
30556 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; });
30558 texts.attr('x', get(labels, 'x'))
30559 .attr('y', get(labels, 'y'))
30560 .style('text-anchor', get(labels, 'textAnchor'))
30561 .text(iD.util.displayName)
30562 .each(function(d, i) { textWidth(iD.util.displayName(d), labels[i].height, this); });
30564 texts.exit().remove();
30568 function drawAreaLabels(group, entities, filter, classes, labels) {
30569 entities = entities.filter(hasText);
30570 labels = labels.filter(hasText);
30571 return drawPointLabels(group, entities, filter, classes, labels);
30573 function hasText(d, i) {
30574 return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
30578 function drawAreaIcons(group, entities, filter, classes, labels) {
30579 var icons = group.selectAll('use')
30581 .data(entities, iD.Entity.key);
30585 .attr('class', 'icon areaicon')
30586 .attr('width', '18px')
30587 .attr('height', '18px');
30589 icons.attr('transform', get(labels, 'transform'))
30590 .attr('xlink:href', function(d) {
30591 var icon = context.presets().match(d, context.graph()).icon;
30592 return '#' + icon + (icon === 'hairdresser' ? '-24': '-18'); // workaround: maki hairdresser-18 broken?
30596 icons.exit().remove();
30599 function reverse(p) {
30600 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
30601 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
30604 function lineString(nodes) {
30605 return 'M' + nodes.join('L');
30608 function subpath(nodes, from, to) {
30609 function segmentLength(i) {
30610 var dx = nodes[i][0] - nodes[i + 1][0];
30611 var dy = nodes[i][1] - nodes[i + 1][1];
30612 return Math.sqrt(dx * dx + dy * dy);
30616 start, end, i0, i1;
30617 for (var i = 0; i < nodes.length - 1; i++) {
30618 var current = segmentLength(i);
30620 if (!start && sofar + current >= from) {
30621 portion = (from - sofar) / current;
30623 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
30624 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
30628 if (!end && sofar + current >= to) {
30629 portion = (to - sofar) / current;
30631 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
30632 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
30639 var ret = nodes.slice(i0, i1);
30640 ret.unshift(start);
30646 function hideOnMouseover() {
30647 var layers = d3.select(this)
30648 .selectAll('.layer-label, .layer-halo');
30650 layers.selectAll('.proximate')
30651 .classed('proximate', false);
30653 var mouse = context.mouse(),
30655 rect = [mouse[0] - pad, mouse[1] - pad, mouse[0] + pad, mouse[1] + pad],
30656 ids = _.pluck(rtree.search(rect), 'id');
30658 if (!ids.length) return;
30659 layers.selectAll('.' + ids.join(', .'))
30660 .classed('proximate', true);
30663 var rtree = rbush(),
30666 function drawLabels(surface, graph, entities, filter, dimensions, fullRedraw) {
30667 var hidePoints = !surface.selectAll('.node.point').node();
30669 var labelable = [], i, k, entity;
30670 for (i = 0; i < label_stack.length; i++) labelable.push([]);
30676 for (i = 0; i < entities.length; i++) {
30677 rtree.remove(rectangles[entities[i].id]);
30681 // Split entities into groups specified by label_stack
30682 for (i = 0; i < entities.length; i++) {
30683 entity = entities[i];
30684 var geometry = entity.geometry(graph);
30686 if (geometry === 'vertex')
30688 if (hidePoints && geometry === 'point')
30691 var preset = geometry === 'area' && context.presets().match(entity, graph),
30692 icon = preset && !blacklisted(preset) && preset.icon;
30694 if (!icon && !iD.util.displayName(entity))
30697 for (k = 0; k < label_stack.length; k++) {
30698 if (geometry === label_stack[k][0] && entity.tags[label_stack[k][1]]) {
30699 labelable[k].push(entity);
30717 // Try and find a valid label for labellable entities
30718 for (k = 0; k < labelable.length; k++) {
30719 var font_size = font_sizes[k];
30720 for (i = 0; i < labelable[k].length; i++) {
30721 entity = labelable[k][i];
30722 var name = iD.util.displayName(entity),
30723 width = name && textWidth(name, font_size),
30725 if (entity.geometry(graph) === 'point') {
30726 p = getPointLabel(entity, width, font_size);
30727 } else if (entity.geometry(graph) === 'line') {
30728 p = getLineLabel(entity, width, font_size);
30729 } else if (entity.geometry(graph) === 'area') {
30730 p = getAreaLabel(entity, width, font_size);
30733 p.classes = entity.geometry(graph) + ' tag-' + label_stack[k][1];
30734 positions[entity.geometry(graph)].push(p);
30735 labelled[entity.geometry(graph)].push(entity);
30740 function getPointLabel(entity, width, height) {
30741 var coord = projection(entity.loc),
30743 offset = pointOffsets[0],
30747 x: coord[0] + offset[0],
30748 y: coord[1] + offset[1],
30749 textAnchor: offset[2]
30751 var rect = [p.x - m, p.y - m, p.x + width + m, p.y + height + m];
30752 if (tryInsert(rect, entity.id)) return p;
30756 function getLineLabel(entity, width, height) {
30757 var nodes = _.pluck(graph.childNodes(entity), 'loc').map(projection),
30758 length = iD.geo.pathLength(nodes);
30759 if (length < width + 20) return;
30761 for (var i = 0; i < lineOffsets.length; i++) {
30762 var offset = lineOffsets[i],
30763 middle = offset / 100 * length,
30764 start = middle - width/2;
30765 if (start < 0 || start + width > length) continue;
30766 var sub = subpath(nodes, start, start + width),
30767 rev = reverse(sub),
30769 Math.min(sub[0][0], sub[sub.length - 1][0]) - 10,
30770 Math.min(sub[0][1], sub[sub.length - 1][1]) - 10,
30771 Math.max(sub[0][0], sub[sub.length - 1][0]) + 20,
30772 Math.max(sub[0][1], sub[sub.length - 1][1]) + 30
30774 if (rev) sub = sub.reverse();
30775 if (tryInsert(rect, entity.id)) return {
30776 'font-size': height + 2,
30777 lineString: lineString(sub),
30778 startOffset: offset + '%'
30783 function getAreaLabel(entity, width, height) {
30784 var centroid = path.centroid(entity.asGeoJSON(graph, true)),
30785 extent = entity.extent(graph),
30786 entitywidth = projection(extent[1])[0] - projection(extent[0])[0],
30789 if (isNaN(centroid[0]) || entitywidth < 20) return;
30791 var iconX = centroid[0] - (iconSize/2),
30792 iconY = centroid[1] - (iconSize/2),
30793 textOffset = iconSize + 5;
30796 transform: 'translate(' + iconX + ',' + iconY + ')'
30799 if (width && entitywidth >= width + 20) {
30801 p.y = centroid[1] + textOffset;
30802 p.textAnchor = 'middle';
30804 rect = [p.x - width/2, p.y, p.x + width/2, p.y + height + textOffset];
30806 rect = [iconX, iconY, iconX + iconSize, iconY + iconSize];
30809 if (tryInsert(rect, entity.id)) return p;
30813 function tryInsert(rect, id) {
30814 // Check that label is visible
30815 if (rect[0] < 0 || rect[1] < 0 || rect[2] > dimensions[0] ||
30816 rect[3] > dimensions[1]) return false;
30817 var v = rtree.search(rect).length === 0;
30820 rtree.insert(rect);
30821 rectangles[id] = rect;
30826 var label = surface.selectAll('.layer-label'),
30827 halo = surface.selectAll('.layer-halo');
30830 drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
30831 drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
30834 drawLinePaths(halo, labelled.line, filter, '', positions.line);
30835 drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
30836 drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
30839 drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
30840 drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
30841 drawAreaIcons(label, labelled.area, filter, 'arealabel-icon', positions.area);
30844 var showDebug = context.debugCollision();
30845 var debug = label.selectAll('.layer-label-debug')
30846 .data(showDebug ? [true] : []);
30850 .attr('class', 'layer-label-debug');
30856 var gj = rtree.all().map(function(d) {
30857 return { type: 'Polygon', coordinates: [[
30866 var debugboxes = debug.selectAll('.bbox').data(gj);
30870 .attr('class', 'bbox');
30876 .attr('d', d3.geo.path().projection(null));
30880 drawLabels.supersurface = function(supersurface) {
30882 .on('mousemove.hidelabels', hideOnMouseover)
30883 .on('mousedown.hidelabels', function () {
30884 supersurface.on('mousemove.hidelabels', null);
30886 .on('mouseup.hidelabels', function () {
30887 supersurface.on('mousemove.hidelabels', hideOnMouseover);
30893 iD.svg.Layers = function(projection, context) {
30894 var dispatch = d3.dispatch('change'),
30895 svg = d3.select(null),
30897 { id: 'osm', layer: iD.svg.Osm(projection, context, dispatch) },
30898 { id: 'gpx', layer: iD.svg.Gpx(projection, context, dispatch) },
30899 { id: 'mapillary-images', layer: iD.svg.MapillaryImages(projection, context, dispatch) },
30900 { id: 'mapillary-signs', layer: iD.svg.MapillarySigns(projection, context, dispatch) }
30904 function drawLayers(selection) {
30905 svg = selection.selectAll('.surface')
30910 .attr('class', 'surface')
30913 var groups = svg.selectAll('.data-layer')
30918 .attr('class', function(d) { return 'data-layer data-layer-' + d.id; });
30921 .each(function(d) { d3.select(this).call(d.layer); });
30927 drawLayers.all = function() {
30931 drawLayers.layer = function(id) {
30932 var obj = _.find(layers, 'id', id);
30933 return obj && obj.layer;
30936 drawLayers.only = function(what) {
30937 var arr = [].concat(what);
30938 drawLayers.remove(_.difference(_.pluck(layers, 'id'), arr));
30942 drawLayers.remove = function(what) {
30943 var arr = [].concat(what);
30944 arr.forEach(function(id) {
30945 layers = _.reject(layers, 'id', id);
30951 drawLayers.add = function(what) {
30952 var arr = [].concat(what);
30953 arr.forEach(function(obj) {
30954 if ('id' in obj && 'layer' in obj) {
30962 drawLayers.dimensions = function(_) {
30963 if (!arguments.length) return svg.dimensions();
30965 layers.forEach(function(obj) {
30966 if (obj.layer.dimensions) {
30967 obj.layer.dimensions(_);
30974 return d3.rebind(drawLayers, dispatch, 'on');
30976 iD.svg.Lines = function(projection) {
30978 var highway_stack = {
30993 function waystack(a, b) {
30994 var as = 0, bs = 0;
30996 if (a.tags.highway) { as -= highway_stack[a.tags.highway]; }
30997 if (b.tags.highway) { bs -= highway_stack[b.tags.highway]; }
31001 return function drawLines(surface, graph, entities, filter) {
31002 var ways = [], pathdata = {}, onewaydata = {},
31003 getPath = iD.svg.Path(projection, graph);
31005 for (var i = 0; i < entities.length; i++) {
31006 var entity = entities[i],
31007 outer = iD.geo.simpleMultipolygonOuterMember(entity, graph);
31009 ways.push(entity.mergeTags(outer.tags));
31010 } else if (entity.geometry(graph) === 'line') {
31015 ways = ways.filter(getPath);
31017 pathdata = _.groupBy(ways, function(way) { return way.layer(); });
31019 _.forOwn(pathdata, function(v, k) {
31020 onewaydata[k] = _(v)
31021 .filter(function(d) { return d.isOneWay(); })
31022 .map(iD.svg.OneWaySegments(projection, graph, 35))
31027 var layergroup = surface
31028 .selectAll('.layer-lines')
31029 .selectAll('g.layergroup')
31030 .data(d3.range(-10, 11));
31034 .attr('class', function(d) { return 'layer layergroup layer' + String(d); });
31037 var linegroup = layergroup
31038 .selectAll('g.linegroup')
31039 .data(['shadow', 'casing', 'stroke']);
31043 .attr('class', function(d) { return 'layer linegroup line-' + d; });
31046 var lines = linegroup
31050 function() { return pathdata[this.parentNode.parentNode.__data__] || []; },
31054 // Optimization: call simple TagClasses only on enter selection. This
31055 // works because iD.Entity.key is defined to include the entity v attribute.
31058 .attr('class', function(d) { return 'way line ' + this.parentNode.__data__ + ' ' + d.id; })
31059 .call(iD.svg.TagClasses());
31063 .attr('d', getPath)
31064 .call(iD.svg.TagClasses().tags(iD.svg.RelationMemberTags(graph)));
31070 var onewaygroup = layergroup
31071 .selectAll('g.onewaygroup')
31074 onewaygroup.enter()
31076 .attr('class', 'layer onewaygroup');
31079 var oneways = onewaygroup
31083 function() { return onewaydata[this.parentNode.parentNode.__data__] || []; },
31084 function(d) { return [d.id, d.index]; }
31089 .attr('class', 'oneway')
31090 .attr('marker-mid', 'url(#oneway-marker)');
31093 .attr('d', function(d) { return d.d; });
31095 if (iD.detect().ie) {
31096 oneways.each(function() { this.parentNode.insertBefore(this, this); });
31104 iD.svg.MapillaryImages = function(projection, context, dispatch) {
31105 var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000),
31107 layer = d3.select(null),
31112 if (iD.svg.MapillaryImages.initialized) return; // run once
31113 iD.svg.MapillaryImages.enabled = false;
31114 iD.svg.MapillaryImages.initialized = true;
31117 function getMapillary() {
31118 if (iD.services.mapillary && !_mapillary) {
31119 _mapillary = iD.services.mapillary().on('loadedImages', debouncedRedraw);
31120 } else if (!iD.services.mapillary && _mapillary) {
31126 function showThumbnail(image) {
31127 var mapillary = getMapillary();
31128 if (!mapillary) return;
31130 var thumb = mapillary.selectedThumbnail(),
31131 posX = projection(image.loc)[0],
31132 width = layer.dimensions()[0],
31133 position = (posX < width / 2) ? 'right' : 'left';
31136 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31137 .classed('selected', function(d) { return d.key === thumb.key; });
31140 mapillary.showThumbnail(image.key, position);
31143 function hideThumbnail() {
31144 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31145 .classed('selected', false);
31147 var mapillary = getMapillary();
31149 mapillary.hideThumbnail();
31153 function showLayer() {
31156 .style('opacity', 0)
31159 .style('opacity', 1)
31160 .each('end', debouncedRedraw);
31163 function hideLayer() {
31164 debouncedRedraw.cancel();
31169 .style('opacity', 0)
31170 .each('end', editOff);
31173 function editOn() {
31174 layer.style('display', 'block');
31177 function editOff() {
31178 layer.selectAll('.viewfield-group').remove();
31179 layer.style('display', 'none');
31182 function transform(d) {
31183 var t = iD.svg.PointTransform(projection)(d);
31184 if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
31188 function update() {
31189 var mapillary = getMapillary(),
31190 data = (mapillary ? mapillary.images(projection, layer.dimensions()) : []);
31192 var markers = layer.selectAll('.viewfield-group')
31193 .data(data, function(d) { return d.key; });
31196 var enter = markers.enter()
31198 .attr('class', 'viewfield-group');
31200 enter.append('path')
31201 .attr('class', 'viewfield')
31202 .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
31203 .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');
31205 enter.append('circle')
31216 .attr('transform', transform);
31219 function drawImages(selection) {
31220 var enabled = iD.svg.MapillaryImages.enabled,
31221 mapillary = getMapillary();
31223 layer = selection.selectAll('.layer-mapillary-images')
31224 .data(mapillary ? [0] : []);
31228 .attr('class', 'layer-mapillary-images')
31229 .style('display', enabled ? 'block' : 'none')
31230 .on('click', function() { // deselect/select
31231 var mapillary = getMapillary();
31232 if (!mapillary) return;
31233 var d = d3.event.target.__data__,
31234 thumb = mapillary.selectedThumbnail();
31235 if (thumb && thumb.key === d.key) {
31238 mapillary.selectedThumbnail(d);
31239 context.map().centerEase(d.loc);
31243 .on('mouseover', function() {
31244 var mapillary = getMapillary();
31245 if (!mapillary) return;
31246 showThumbnail(d3.event.target.__data__);
31248 .on('mouseout', function() {
31249 var mapillary = getMapillary();
31250 if (!mapillary) return;
31251 var thumb = mapillary.selectedThumbnail();
31253 showThumbnail(thumb);
31263 if (mapillary && ~~context.map().zoom() >= minZoom) {
31266 mapillary.loadImages(projection, layer.dimensions());
31273 drawImages.enabled = function(_) {
31274 if (!arguments.length) return iD.svg.MapillaryImages.enabled;
31275 iD.svg.MapillaryImages.enabled = _;
31276 if (iD.svg.MapillaryImages.enabled) {
31285 drawImages.supported = function() {
31286 return !!getMapillary();
31289 drawImages.dimensions = function(_) {
31290 if (!arguments.length) return layer.dimensions();
31291 layer.dimensions(_);
31298 iD.svg.MapillarySigns = function(projection, context, dispatch) {
31299 var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000),
31301 layer = d3.select(null),
31306 if (iD.svg.MapillarySigns.initialized) return; // run once
31307 iD.svg.MapillarySigns.enabled = false;
31308 iD.svg.MapillarySigns.initialized = true;
31311 function getMapillary() {
31312 if (iD.services.mapillary && !_mapillary) {
31313 _mapillary = iD.services.mapillary().on('loadedSigns', debouncedRedraw);
31314 } else if (!iD.services.mapillary && _mapillary) {
31320 function showThumbnail(image) {
31321 var mapillary = getMapillary();
31322 if (!mapillary) return;
31324 var thumb = mapillary.selectedThumbnail(),
31325 posX = projection(image.loc)[0],
31326 width = layer.dimensions()[0],
31327 position = (posX < width / 2) ? 'right' : 'left';
31330 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31331 .classed('selected', function(d) { return d.key === thumb.key; });
31334 mapillary.showThumbnail(image.key, position);
31337 function hideThumbnail() {
31338 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
31339 .classed('selected', false);
31341 var mapillary = getMapillary();
31343 mapillary.hideThumbnail();
31347 function showLayer() {
31352 function hideLayer() {
31353 debouncedRedraw.cancel();
31358 function editOn() {
31359 layer.style('display', 'block');
31362 function editOff() {
31363 layer.selectAll('.icon-sign').remove();
31364 layer.style('display', 'none');
31367 function update() {
31368 var mapillary = getMapillary(),
31369 data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []);
31371 var signs = layer.selectAll('.icon-sign')
31372 .data(data, function(d) { return d.key; });
31375 var enter = signs.enter()
31376 .append('foreignObject')
31377 .attr('class', 'icon-sign')
31378 .attr('width', '32px') // for Firefox
31379 .attr('height', '32px'); // for Firefox
31382 .append('xhtml:body')
31383 .html(mapillary.signHTML);
31386 .on('click', function(d) { // deselect/select
31387 var mapillary = getMapillary();
31388 if (!mapillary) return;
31389 var thumb = mapillary.selectedThumbnail();
31390 if (thumb && thumb.key === d.key) {
31393 mapillary.selectedThumbnail(d);
31394 context.map().centerEase(d.loc);
31398 .on('mouseover', showThumbnail)
31399 .on('mouseout', function() {
31400 var mapillary = getMapillary();
31401 if (!mapillary) return;
31402 var thumb = mapillary.selectedThumbnail();
31404 showThumbnail(thumb);
31416 .attr('transform', iD.svg.PointTransform(projection));
31419 function drawSigns(selection) {
31420 var enabled = iD.svg.MapillarySigns.enabled,
31421 mapillary = getMapillary();
31423 layer = selection.selectAll('.layer-mapillary-signs')
31424 .data(mapillary ? [0] : []);
31428 .attr('class', 'layer-mapillary-signs')
31429 .style('display', enabled ? 'block' : 'none')
31430 .attr('transform', 'translate(-16, -16)'); // center signs on loc
31436 if (mapillary && ~~context.map().zoom() >= minZoom) {
31439 mapillary.loadSigns(context, projection, layer.dimensions());
31446 drawSigns.enabled = function(_) {
31447 if (!arguments.length) return iD.svg.MapillarySigns.enabled;
31448 iD.svg.MapillarySigns.enabled = _;
31449 if (iD.svg.MapillarySigns.enabled) {
31458 drawSigns.supported = function() {
31459 var mapillary = getMapillary();
31460 return (mapillary && mapillary.signsSupported());
31463 drawSigns.dimensions = function(_) {
31464 if (!arguments.length) return layer.dimensions();
31465 layer.dimensions(_);
31472 iD.svg.Midpoints = function(projection, context) {
31473 return function drawMidpoints(surface, graph, entities, filter, extent) {
31474 var poly = extent.polygon(),
31477 for (var i = 0; i < entities.length; i++) {
31478 var entity = entities[i];
31480 if (entity.type !== 'way')
31482 if (!filter(entity))
31484 if (context.selectedIDs().indexOf(entity.id) < 0)
31487 var nodes = graph.childNodes(entity);
31488 for (var j = 0; j < nodes.length - 1; j++) {
31492 id = [a.id, b.id].sort().join('-');
31494 if (midpoints[id]) {
31495 midpoints[id].parents.push(entity);
31497 if (iD.geo.euclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
31498 var point = iD.geo.interp(a.loc, b.loc, 0.5),
31501 if (extent.intersects(point)) {
31504 for (var k = 0; k < 4; k++) {
31505 point = iD.geo.lineIntersection([a.loc, b.loc], [poly[k], poly[k+1]]);
31507 iD.geo.euclideanDistance(projection(a.loc), projection(point)) > 20 &&
31508 iD.geo.euclideanDistance(projection(b.loc), projection(point)) > 20)
31521 edge: [a.id, b.id],
31530 function midpointFilter(d) {
31531 if (midpoints[d.id])
31534 for (var i = 0; i < d.parents.length; i++)
31535 if (filter(d.parents[i]))
31541 var groups = surface.selectAll('.layer-hit').selectAll('g.midpoint')
31542 .filter(midpointFilter)
31543 .data(_.values(midpoints), function(d) { return d.id; });
31545 var enter = groups.enter()
31546 .insert('g', ':first-child')
31547 .attr('class', 'midpoint');
31549 enter.append('polygon')
31550 .attr('points', '-6,8 10,0 -6,-8')
31551 .attr('class', 'shadow');
31553 enter.append('polygon')
31554 .attr('points', '-3,4 5,0 -3,-4')
31555 .attr('class', 'fill');
31558 .attr('transform', function(d) {
31559 var translate = iD.svg.PointTransform(projection),
31560 a = context.entity(d.edge[0]),
31561 b = context.entity(d.edge[1]),
31562 angle = Math.round(iD.geo.angle(a, b, projection) * (180 / Math.PI));
31563 return translate(d) + ' rotate(' + angle + ')';
31565 .call(iD.svg.TagClasses().tags(
31566 function(d) { return d.parents[0].tags; }
31569 // Propagate data bindings.
31570 groups.select('polygon.shadow');
31571 groups.select('polygon.fill');
31577 iD.svg.Osm = function() {
31578 return function drawOsm(selection) {
31579 var layers = selection.selectAll('.layer-osm')
31580 .data(['areas', 'lines', 'hit', 'halo', 'label']);
31582 layers.enter().append('g')
31583 .attr('class', function(d) { return 'layer-osm layer-' + d; });
31586 iD.svg.Points = function(projection, context) {
31587 function markerPath(selection, klass) {
31589 .attr('class', klass)
31590 .attr('transform', 'translate(-8, -23)')
31591 .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');
31594 function sortY(a, b) {
31595 return b.loc[1] - a.loc[1];
31598 return function drawPoints(surface, graph, entities, filter) {
31599 var wireframe = surface.classed('fill-wireframe'),
31600 points = wireframe ? [] : _.filter(entities, function(e) {
31601 return e.geometry(graph) === 'point';
31604 points.sort(sortY);
31606 var groups = surface.selectAll('.layer-hit').selectAll('g.point')
31608 .data(points, iD.Entity.key);
31610 var group = groups.enter()
31612 .attr('class', function(d) { return 'node point ' + d.id; })
31615 group.append('path')
31616 .call(markerPath, 'shadow');
31618 group.append('path')
31619 .call(markerPath, 'stroke');
31621 group.append('use')
31622 .attr('transform', 'translate(-6, -20)')
31623 .attr('class', 'icon')
31624 .attr('width', '12px')
31625 .attr('height', '12px');
31627 groups.attr('transform', iD.svg.PointTransform(projection))
31628 .call(iD.svg.TagClasses());
31630 // Selecting the following implicitly
31631 // sets the data (point entity) on the element
31632 groups.select('.shadow');
31633 groups.select('.stroke');
31634 groups.select('.icon')
31635 .attr('xlink:href', function(entity) {
31636 var preset = context.presets().match(entity, graph);
31637 return preset.icon ? '#' + preset.icon + '-12' : '';
31644 iD.svg.TagClasses = function() {
31646 'building', 'highway', 'railway', 'waterway', 'aeroway',
31647 'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
31651 'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
31652 'razed', 'demolished', 'obliterated'
31655 'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
31656 'surface', 'tracktype', 'crossing'
31658 tagClassRe = /^tag-/,
31659 tags = function(entity) { return entity.tags; };
31662 var tagClasses = function(selection) {
31663 selection.each(function tagClassesEach(entity) {
31664 var value = this.className,
31665 classes, primary, status;
31667 if (value.baseVal !== undefined) value = value.baseVal;
31669 classes = value.trim().split(/\s+/).filter(function(name) {
31670 return name.length && !tagClassRe.test(name);
31673 var t = tags(entity), i, k, v;
31675 // pick at most one primary classification tag..
31676 for (i = 0; i < primaries.length; i++) {
31679 if (!v || v === 'no') continue;
31682 if (statuses.indexOf(v) !== -1) { // e.g. `railway=abandoned`
31684 classes += ' tag-' + k;
31686 classes += ' tag-' + k + ' tag-' + k + '-' + v;
31692 // add at most one status tag, only if relates to primary tag..
31694 for (i = 0; i < statuses.length; i++) {
31697 if (!v || v === 'no') continue;
31699 if (v === 'yes') { // e.g. `railway=rail + abandoned=yes`
31702 else if (primary && primary === v) { // e.g. `railway=rail + abandoned=railway`
31704 } else if (!primary && primaries.indexOf(v) !== -1) { // e.g. `abandoned=railway`
31707 classes += ' tag-' + v;
31708 } // else ignore e.g. `highway=path + abandoned=railway`
31715 classes += ' tag-status tag-status-' + status;
31718 // add any secondary (structure) tags
31719 for (i = 0; i < secondaries.length; i++) {
31720 k = secondaries[i];
31722 if (!v || v === 'no') continue;
31723 classes += ' tag-' + k + ' tag-' + k + '-' + v;
31726 // For highways, look for surface tagging..
31727 if (primary === 'highway') {
31728 var paved = (t.highway !== 'track');
31731 if (k in iD.pavedTags) {
31732 paved = !!iD.pavedTags[k][v];
31737 classes += ' tag-unpaved';
31741 classes = classes.trim();
31743 if (classes !== value) {
31744 d3.select(this).attr('class', classes);
31749 tagClasses.tags = function(_) {
31750 if (!arguments.length) return tags;
31757 iD.svg.Turns = function(projection) {
31758 return function drawTurns(surface, graph, turns) {
31759 function key(turn) {
31760 return [turn.from.node + turn.via.node + turn.to.node].join('-');
31763 function icon(turn) {
31764 var u = turn.u ? '-u' : '';
31765 if (!turn.restriction)
31766 return '#turn-yes' + u;
31767 var restriction = graph.entity(turn.restriction).tags.restriction;
31769 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
31772 var groups = surface.selectAll('.layer-hit').selectAll('g.turn')
31776 var enter = groups.enter().append('g')
31777 .attr('class', 'turn');
31779 var nEnter = enter.filter(function (turn) { return !turn.u; });
31781 nEnter.append('rect')
31782 .attr('transform', 'translate(-22, -12)')
31783 .attr('width', '44')
31784 .attr('height', '24');
31786 nEnter.append('use')
31787 .attr('transform', 'translate(-22, -12)')
31788 .attr('width', '44')
31789 .attr('height', '24');
31792 var uEnter = enter.filter(function (turn) { return turn.u; });
31794 uEnter.append('circle')
31797 uEnter.append('use')
31798 .attr('transform', 'translate(-16, -16)')
31799 .attr('width', '32')
31800 .attr('height', '32');
31805 .attr('transform', function (turn) {
31806 var v = graph.entity(turn.via.node),
31807 t = graph.entity(turn.to.node),
31808 a = iD.geo.angle(v, t, projection),
31809 p = projection(v.loc),
31810 r = turn.u ? 0 : 60;
31812 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
31813 'rotate(' + a * 180 / Math.PI + ')';
31816 groups.select('use')
31817 .attr('xlink:href', icon);
31819 groups.select('rect');
31820 groups.select('circle');
31830 iD.svg.Vertices = function(projection, context) {
31832 // z16-, z17, z18+, tagged
31833 shadow: [6, 7.5, 7.5, 11.5],
31834 stroke: [2.5, 3.5, 3.5, 7],
31835 fill: [1, 1.5, 1.5, 1.5]
31840 function siblingAndChildVertices(ids, graph, extent) {
31843 function addChildVertices(entity) {
31844 if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
31846 if (entity.type === 'way') {
31847 for (i = 0; i < entity.nodes.length; i++) {
31848 addChildVertices(graph.entity(entity.nodes[i]));
31850 } else if (entity.type === 'relation') {
31851 for (i = 0; i < entity.members.length; i++) {
31852 var member = context.hasEntity(entity.members[i].id);
31854 addChildVertices(member);
31857 } else if (entity.intersects(extent, graph)) {
31858 vertices[entity.id] = entity;
31863 ids.forEach(function(id) {
31864 var entity = context.hasEntity(id);
31865 if (entity && entity.type === 'node') {
31866 vertices[entity.id] = entity;
31867 context.graph().parentWays(entity).forEach(function(entity) {
31868 addChildVertices(entity);
31870 } else if (entity) {
31871 addChildVertices(entity);
31878 function draw(selection, vertices, klass, graph, zoom) {
31880 z = (zoom < 17 ? 0 : zoom < 18 ? 1 : 2);
31882 var groups = selection
31883 .data(vertices, iD.Entity.key);
31885 function icon(entity) {
31886 if (entity.id in icons) return icons[entity.id];
31888 entity.hasInterestingTags() &&
31889 context.presets().match(entity, graph).icon;
31890 return icons[entity.id];
31893 function setClass(klass) {
31894 return function(entity) {
31895 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
31899 function setAttributes(selection) {
31900 ['shadow','stroke','fill'].forEach(function(klass) {
31901 var rads = radiuses[klass];
31902 selection.selectAll('.' + klass)
31903 .each(function(entity) {
31904 var i = z && icon(entity),
31906 r = rads[i ? 3 : z];
31907 this.setAttribute('cx', c);
31908 this.setAttribute('cy', -c);
31909 this.setAttribute('r', r);
31910 if (i && klass === 'fill') {
31911 this.setAttribute('visibility', 'hidden');
31913 this.removeAttribute('visibility');
31918 selection.selectAll('use')
31921 this.removeAttribute('visibility');
31923 this.setAttribute('visibility', 'hidden');
31928 var enter = groups.enter()
31930 .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
31932 enter.append('circle')
31933 .each(setClass('shadow'));
31935 enter.append('circle')
31936 .each(setClass('stroke'));
31938 // Vertices with icons get a `use`.
31939 enter.filter(function(d) { return icon(d); })
31941 .attr('transform', 'translate(-6, -6)')
31942 .attr('xlink:href', function(d) { return '#' + icon(d) + '-12'; })
31943 .attr('width', '12px')
31944 .attr('height', '12px')
31945 .each(setClass('icon'));
31947 // Vertices with tags get a fill.
31948 enter.filter(function(d) { return d.hasInterestingTags(); })
31950 .each(setClass('fill'));
31953 .attr('transform', iD.svg.PointTransform(projection))
31954 .classed('shared', function(entity) { return graph.isShared(entity); })
31955 .call(setAttributes);
31961 function drawVertices(surface, graph, entities, filter, extent, zoom) {
31962 var selected = siblingAndChildVertices(context.selectedIDs(), graph, extent),
31963 wireframe = surface.classed('fill-wireframe'),
31966 for (var i = 0; i < entities.length; i++) {
31967 var entity = entities[i],
31968 geometry = entity.geometry(graph);
31970 if (wireframe && geometry === 'point') {
31971 vertices.push(entity);
31975 if (geometry !== 'vertex')
31978 if (entity.id in selected ||
31979 entity.hasInterestingTags() ||
31980 entity.isIntersection(graph)) {
31981 vertices.push(entity);
31985 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-persistent')
31987 .call(draw, vertices, 'vertex-persistent', graph, zoom);
31989 drawHover(surface, graph, extent, zoom);
31992 function drawHover(surface, graph, extent, zoom) {
31993 var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent) : {};
31995 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-hover')
31996 .call(draw, d3.values(hovered), 'vertex-hover', graph, zoom);
31999 drawVertices.drawHover = function(surface, graph, target, extent, zoom) {
32000 if (target === hover) return;
32002 drawHover(surface, graph, extent, zoom);
32005 return drawVertices;
32007 iD.ui = function(context) {
32008 function render(container) {
32009 var map = context.map();
32011 if (iD.detect().opera) container.classed('opera', true);
32013 var hash = iD.behavior.Hash(context);
32017 if (!hash.hadHash) {
32018 map.centerZoom([0, 0], 2);
32021 container.append('svg')
32022 .attr('id', 'defs')
32023 .call(iD.svg.Defs(context));
32025 container.append('div')
32026 .attr('id', 'sidebar')
32027 .attr('class', 'col4')
32030 var content = container.append('div')
32031 .attr('id', 'content');
32033 var bar = content.append('div')
32035 .attr('class', 'fillD');
32037 content.append('div')
32042 .call(iD.ui.MapInMap(context));
32044 content.append('div')
32045 .call(iD.ui.Info(context));
32048 .attr('class', 'spacer col4');
32050 var limiter = bar.append('div')
32051 .attr('class', 'limiter');
32053 limiter.append('div')
32054 .attr('class', 'button-wrap joined col3')
32055 .call(iD.ui.Modes(context), limiter);
32057 limiter.append('div')
32058 .attr('class', 'button-wrap joined col1')
32059 .call(iD.ui.UndoRedo(context));
32061 limiter.append('div')
32062 .attr('class', 'button-wrap col1')
32063 .call(iD.ui.Save(context));
32066 .attr('class', 'full-screen')
32067 .call(iD.ui.FullScreen(context));
32070 .attr('class', 'spinner')
32071 .call(iD.ui.Spinner(context));
32073 var controls = bar.append('div')
32074 .attr('class', 'map-controls');
32076 controls.append('div')
32077 .attr('class', 'map-control zoombuttons')
32078 .call(iD.ui.Zoom(context));
32080 controls.append('div')
32081 .attr('class', 'map-control geolocate-control')
32082 .call(iD.ui.Geolocate(context));
32084 controls.append('div')
32085 .attr('class', 'map-control background-control')
32086 .call(iD.ui.Background(context));
32088 controls.append('div')
32089 .attr('class', 'map-control map-data-control')
32090 .call(iD.ui.MapData(context));
32092 controls.append('div')
32093 .attr('class', 'map-control help-control')
32094 .call(iD.ui.Help(context));
32096 var about = content.append('div')
32097 .attr('id', 'about');
32099 about.append('div')
32100 .attr('id', 'attrib')
32101 .call(iD.ui.Attribution(context));
32103 var footer = about.append('div')
32104 .attr('id', 'footer')
32105 .attr('class', 'fillD');
32107 footer.append('div')
32108 .attr('class', 'api-status')
32109 .call(iD.ui.Status(context));
32111 footer.append('div')
32112 .attr('id', 'scale-block')
32113 .call(iD.ui.Scale(context));
32115 var aboutList = footer.append('div')
32116 .attr('id', 'info-block')
32118 .attr('id', 'about-list');
32120 if (!context.embed()) {
32121 aboutList.call(iD.ui.Account(context));
32124 aboutList.append('li')
32126 .attr('target', '_blank')
32127 .attr('tabindex', -1)
32128 .attr('href', 'https://github.com/openstreetmap/iD')
32131 var issueLinks = aboutList.append('li');
32133 issueLinks.append('a')
32134 .attr('target', '_blank')
32135 .attr('tabindex', -1)
32136 .attr('href', 'https://github.com/openstreetmap/iD/issues')
32137 .call(iD.svg.Icon('#icon-bug', 'light'))
32138 .call(bootstrap.tooltip()
32139 .title(t('report_a_bug'))
32143 issueLinks.append('a')
32144 .attr('target', '_blank')
32145 .attr('tabindex', -1)
32146 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
32147 .call(iD.svg.Icon('#icon-translate', 'light'))
32148 .call(bootstrap.tooltip()
32149 .title(t('help_translate'))
32153 aboutList.append('li')
32154 .attr('class', 'feature-warning')
32155 .attr('tabindex', -1)
32156 .call(iD.ui.FeatureInfo(context));
32158 aboutList.append('li')
32159 .attr('class', 'user-list')
32160 .attr('tabindex', -1)
32161 .call(iD.ui.Contributors(context));
32163 window.onbeforeunload = function() {
32164 return context.save();
32167 window.onunload = function() {
32168 context.history().unlock();
32171 var mapDimensions = map.dimensions();
32173 d3.select(window).on('resize.editor', function() {
32174 mapDimensions = content.dimensions(null);
32175 map.dimensions(mapDimensions);
32179 return function() {
32180 d3.event.preventDefault();
32181 if (!context.inIntro()) context.pan(d);
32188 var keybinding = d3.keybinding('main')
32189 .on('⌫', function() { d3.event.preventDefault(); })
32190 .on('←', pan([pa, 0]))
32191 .on('↑', pan([0, pa]))
32192 .on('→', pan([-pa, 0]))
32193 .on('↓', pan([0, -pa]))
32194 .on('⇧←', pan([mapDimensions[0], 0]))
32195 .on('⇧↑', pan([0, mapDimensions[1]]))
32196 .on('⇧→', pan([-mapDimensions[0], 0]))
32197 .on('⇧↓', pan([0, -mapDimensions[1]]))
32198 .on(iD.ui.cmd('⌘←'), pan([mapDimensions[0], 0]))
32199 .on(iD.ui.cmd('⌘↑'), pan([0, mapDimensions[1]]))
32200 .on(iD.ui.cmd('⌘→'), pan([-mapDimensions[0], 0]))
32201 .on(iD.ui.cmd('⌘↓'), pan([0, -mapDimensions[1]]));
32203 d3.select(document)
32206 context.enter(iD.modes.Browse(context));
32208 context.container()
32209 .call(iD.ui.Splash(context))
32210 .call(iD.ui.Restore(context));
32212 var authenticating = iD.ui.Loading(context)
32213 .message(t('loading_auth'));
32215 context.connection()
32216 .on('authenticating.ui', function() {
32217 context.container()
32218 .call(authenticating);
32220 .on('authenticated.ui', function() {
32221 authenticating.close();
32225 function ui(container) {
32226 context.container(container);
32227 context.loadLocale(function() {
32232 ui.sidebar = iD.ui.Sidebar(context);
32237 iD.ui.tooltipHtml = function(text, key) {
32238 var s = '<span>' + text + '</span>';
32240 s += '<div class="keyhint-wrap">' +
32241 '<span> ' + (t('tooltip_keyhint')) + ' </span>' +
32242 '<span class="keyhint"> ' + key + '</span></div>';
32246 iD.ui.Account = function(context) {
32247 var connection = context.connection();
32249 function update(selection) {
32250 if (!connection.authenticated()) {
32251 selection.selectAll('#userLink, #logoutLink')
32252 .classed('hide', true);
32256 connection.userDetails(function(err, details) {
32257 var userLink = selection.select('#userLink'),
32258 logoutLink = selection.select('#logoutLink');
32261 logoutLink.html('');
32265 selection.selectAll('#userLink, #logoutLink')
32266 .classed('hide', false);
32269 userLink.append('a')
32270 .attr('href', connection.userURL(details.display_name))
32271 .attr('target', '_blank');
32273 // Add thumbnail or dont
32274 if (details.image_url) {
32275 userLink.append('img')
32276 .attr('class', 'icon pre-text user-icon')
32277 .attr('src', details.image_url);
32280 .call(iD.svg.Icon('#icon-avatar', 'pre-text light'));
32284 userLink.append('span')
32285 .attr('class', 'label')
32286 .text(details.display_name);
32288 logoutLink.append('a')
32289 .attr('class', 'logout')
32292 .on('click.logout', function() {
32293 d3.event.preventDefault();
32294 connection.logout();
32299 return function(selection) {
32300 selection.append('li')
32301 .attr('id', 'logoutLink')
32302 .classed('hide', true);
32304 selection.append('li')
32305 .attr('id', 'userLink')
32306 .classed('hide', true);
32308 connection.on('auth.account', function() { update(selection); });
32312 iD.ui.Attribution = function(context) {
32315 function attribution(data, klass) {
32316 var div = selection.selectAll('.' + klass)
32321 .attr('class', klass);
32323 var background = div.selectAll('.attribution')
32324 .data(data, function(d) { return d.name(); });
32328 .attr('class', 'attribution')
32329 .each(function(d) {
32330 if (d.terms_html) {
32332 .html(d.terms_html);
32336 var source = d.terms_text || d.id || d.name();
32339 source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
32345 .attr('href', d.terms_url)
32346 .attr('target', '_blank')
32357 var copyright = background.selectAll('.copyright-notice')
32358 .data(function(d) {
32359 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
32360 return notice ? [notice] : [];
32365 .attr('class', 'copyright-notice');
32367 copyright.text(String);
32373 function update() {
32374 attribution([context.background().baseLayerSource()], 'base-layer-attribution');
32375 attribution(context.background().overlayLayerSources().filter(function (s) {
32376 return s.validZoom(context.map().zoom());
32377 }), 'overlay-layer-attribution');
32380 return function(select) {
32381 selection = select;
32383 context.background()
32384 .on('change.attribution', update);
32387 .on('move.attribution', _.throttle(update, 400, {leading: false}));
32392 iD.ui.Background = function(context) {
32394 opacities = [1, 0.75, 0.5, 0.25],
32396 ['right', [0.5, 0]],
32397 ['top', [0, -0.5]],
32398 ['left', [-0.5, 0]],
32399 ['bottom', [0, 0.5]]],
32400 opacityDefault = (context.storage('background-opacity') !== null) ?
32401 (+context.storage('background-opacity')) : 1.0,
32402 customTemplate = context.storage('background-custom-template') || '';
32404 // Can be 0 from <1.3.0 use or due to issue #1923.
32405 if (opacityDefault === 0) opacityDefault = 1.0;
32407 function background(selection) {
32409 function sortSources(a, b) {
32410 return a.best() ? -1
32412 : a.id === 'none' ? 1
32413 : b.id === 'none' ? -1
32414 : d3.ascending(a, b);
32417 function setOpacity(d) {
32418 var bg = context.container().selectAll('.layer-background')
32420 .style('opacity', d)
32421 .attr('data-opacity', d);
32423 if (!iD.detect().opera) {
32424 iD.util.setTransform(bg, 0, 0);
32427 opacityList.selectAll('li')
32428 .classed('active', function(_) { return _ === d; });
32430 context.storage('background-opacity', d);
32433 function selectLayer() {
32434 function active(d) {
32435 return context.background().showsLayer(d);
32438 content.selectAll('.layer, .custom_layer')
32439 .classed('active', active)
32440 .selectAll('input')
32441 .property('checked', active);
32444 function clickSetSource(d) {
32445 d3.event.preventDefault();
32446 context.background().baseLayerSource(d);
32450 function editCustom() {
32451 d3.event.preventDefault();
32452 var template = window.prompt(t('background.custom_prompt'), customTemplate);
32454 template.indexOf('google.com') !== -1 ||
32455 template.indexOf('googleapis.com') !== -1 ||
32456 template.indexOf('google.ru') !== -1) {
32460 setCustom(template);
32463 function setCustom(template) {
32464 context.background().baseLayerSource(iD.BackgroundSource.Custom(template));
32466 context.storage('background-custom-template', template);
32469 function clickSetOverlay(d) {
32470 d3.event.preventDefault();
32471 context.background().toggleOverlayLayer(d);
32475 function drawList(layerList, type, change, filter) {
32476 var sources = context.background()
32477 .sources(context.map().extent())
32480 var layerLinks = layerList.selectAll('li.layer')
32481 .data(sources, function(d) { return d.name(); })
32482 .sort(sortSources);
32484 var enter = layerLinks.enter()
32485 .insert('li', '.custom_layer')
32486 .attr('class', 'layer')
32487 .classed('best', function(d) { return d.best(); });
32489 // only set tooltips for layers with tooltips
32490 enter.filter(function(d) { return d.description; })
32491 .call(bootstrap.tooltip()
32492 .title(function(d) { return d.description; })
32493 .placement('top'));
32495 enter.filter(function(d) { return d.best(); })
32497 .attr('class', 'best')
32498 .call(bootstrap.tooltip()
32499 .title(t('background.best_imagery'))
32500 .placement('left'))
32504 var label = enter.append('label');
32506 label.append('input')
32507 .attr('type', type)
32508 .attr('name', 'layers')
32509 .on('change', change);
32511 label.append('span')
32512 .text(function(d) { return d.name(); });
32517 layerList.style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
32520 function update() {
32521 backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
32522 overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
32526 var source = context.background().baseLayerSource();
32527 if (source.id === 'custom') {
32528 customTemplate = source.template;
32534 function offsetToMeters(offset) {
32535 var equatRadius = 6356752.314245179,
32536 polarRadius = 6378137.0,
32540 offset[0] * 2 * Math.PI * equatRadius / tileSize,
32541 -offset[1] * 2 * Math.PI * polarRadius / tileSize
32545 function metersToOffset(meters) {
32546 var equatRadius = 6356752.314245179,
32547 polarRadius = 6378137.0,
32551 meters[0] * tileSize / (2 * Math.PI * equatRadius),
32552 -meters[1] * tileSize / (2 * Math.PI * polarRadius)
32556 function updateOffsetVal() {
32557 var meters = offsetToMeters(context.background().offset()),
32558 x = +meters[0].toFixed(2),
32559 y = +meters[1].toFixed(2);
32561 d3.selectAll('.nudge-inner-rect')
32563 .classed('error', false)
32564 .property('value', x + ', ' + y);
32566 d3.selectAll('.nudge-reset')
32567 .classed('disabled', function() {
32568 return (x === 0 && y === 0);
32572 function resetOffset() {
32573 context.background().offset([0, 0]);
32577 function nudge(d) {
32578 context.background().nudge(d, context.map().zoom());
32582 function buttonOffset(d) {
32583 var timeout = window.setTimeout(function() {
32584 interval = window.setInterval(nudge.bind(null, d), 100);
32588 d3.select(window).on('mouseup', function() {
32589 window.clearInterval(interval);
32590 window.clearTimeout(timeout);
32591 d3.select(window).on('mouseup', null);
32597 function inputOffset() {
32598 var input = d3.select(this);
32599 var d = input.node().value;
32601 if (d === '') return resetOffset();
32603 d = d.replace(/;/g, ',').split(',').map(function(n) {
32604 // if n is NaN, it will always get mapped to false.
32605 return !isNaN(n) && n;
32608 if (d.length !== 2 || !d[0] || !d[1]) {
32609 input.classed('error', true);
32613 context.background().offset(metersToOffset(d));
32617 function dragOffset() {
32618 var origin = [d3.event.clientX, d3.event.clientY];
32621 .on('mousemove.offset', function() {
32622 var latest = [d3.event.clientX, d3.event.clientY];
32624 -(origin[0] - latest[0]) / 4,
32625 -(origin[1] - latest[1]) / 4
32631 .on('mouseup.offset', function() {
32633 .on('mousemove.offset', null)
32634 .on('mouseup.offset', null);
32637 d3.event.preventDefault();
32644 function toggle() {
32645 if (d3.event) d3.event.preventDefault();
32646 tooltip.hide(button);
32647 setVisible(!button.classed('active'));
32650 function setVisible(show) {
32651 if (show !== shown) {
32652 button.classed('active', show);
32656 selection.on('mousedown.background-inside', function() {
32657 return d3.event.stopPropagation();
32659 content.style('display', 'block')
32660 .style('right', '-300px')
32663 .style('right', '0px');
32665 content.style('display', 'block')
32666 .style('right', '0px')
32669 .style('right', '-300px')
32670 .each('end', function() {
32671 d3.select(this).style('display', 'none');
32673 selection.on('mousedown.background-inside', null);
32679 var content = selection.append('div')
32680 .attr('class', 'fillL map-overlay col3 content hide'),
32681 tooltip = bootstrap.tooltip()
32684 .title(iD.ui.tooltipHtml(t('background.description'), key)),
32685 button = selection.append('button')
32686 .attr('tabindex', -1)
32687 .on('click', toggle)
32688 .call(iD.svg.Icon('#icon-layers', 'light'))
32693 /* opacity switcher */
32695 var opa = content.append('div')
32696 .attr('class', 'opacity-options-wrapper');
32699 .text(t('background.title'));
32701 var opacityList = opa.append('ul')
32702 .attr('class', 'opacity-options');
32704 opacityList.selectAll('div.opacity')
32708 .attr('data-original-title', function(d) {
32709 return t('background.percent_brightness', { opacity: (d * 100) });
32711 .on('click.set-opacity', setOpacity)
32712 .html('<div class="select-box"></div>')
32713 .call(bootstrap.tooltip()
32714 .placement('left'))
32716 .attr('class', 'opacity')
32717 .style('opacity', function(d) { return 1.25 - d; });
32720 /* background switcher */
32722 var backgroundList = content.append('ul')
32723 .attr('class', 'layer-list');
32725 var custom = backgroundList.append('li')
32726 .attr('class', 'custom_layer')
32727 .datum(iD.BackgroundSource.Custom());
32729 custom.append('button')
32730 .attr('class', 'layer-browse')
32731 .call(bootstrap.tooltip()
32732 .title(t('background.custom_button'))
32733 .placement('left'))
32734 .on('click', editCustom)
32735 .call(iD.svg.Icon('#icon-search'));
32737 var label = custom.append('label');
32739 label.append('input')
32740 .attr('type', 'radio')
32741 .attr('name', 'layers')
32742 .on('change', function () {
32743 if (customTemplate) {
32744 setCustom(customTemplate);
32750 label.append('span')
32751 .text(t('background.custom'));
32753 content.append('div')
32754 .attr('class', 'imagery-faq')
32756 .attr('target', '_blank')
32757 .attr('tabindex', -1)
32758 .call(iD.svg.Icon('#icon-out-link', 'inline'))
32759 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
32761 .text(t('background.imagery_source_faq'));
32763 var overlayList = content.append('ul')
32764 .attr('class', 'layer-list');
32766 var controls = content.append('div')
32767 .attr('class', 'controls-list');
32770 /* minimap toggle */
32772 var minimapLabel = controls
32774 .call(bootstrap.tooltip()
32776 .title(iD.ui.tooltipHtml(t('background.minimap.tooltip'), '/'))
32780 minimapLabel.classed('minimap-toggle', true)
32782 .attr('type', 'checkbox')
32783 .on('change', function() {
32784 iD.ui.MapInMap.toggle();
32785 d3.event.preventDefault();
32788 minimapLabel.append('span')
32789 .text(t('background.minimap.description'));
32792 /* imagery offset controls */
32794 var adjustments = content.append('div')
32795 .attr('class', 'adjustments');
32797 adjustments.append('a')
32798 .text(t('background.fix_misalignment'))
32800 .classed('hide-toggle', true)
32801 .classed('expanded', false)
32802 .on('click', function() {
32803 var exp = d3.select(this).classed('expanded');
32804 nudgeContainer.style('display', exp ? 'none' : 'block');
32805 d3.select(this).classed('expanded', !exp);
32806 d3.event.preventDefault();
32809 var nudgeContainer = adjustments.append('div')
32810 .attr('class', 'nudge-container cf')
32811 .style('display', 'none');
32813 nudgeContainer.append('div')
32814 .attr('class', 'nudge-instructions')
32815 .text(t('background.offset'));
32817 var nudgeRect = nudgeContainer.append('div')
32818 .attr('class', 'nudge-outer-rect')
32819 .on('mousedown', dragOffset);
32821 nudgeRect.append('div')
32822 .attr('class', 'nudge-inner-rect')
32824 .on('change', inputOffset)
32825 .on('mousedown', function() {
32826 d3.event.stopPropagation();
32829 nudgeContainer.append('div')
32830 .selectAll('button')
32831 .data(directions).enter()
32833 .attr('class', function(d) { return d[0] + ' nudge'; })
32834 .on('mousedown', function(d) {
32835 buttonOffset(d[1]);
32838 nudgeContainer.append('button')
32839 .attr('title', t('background.reset'))
32840 .attr('class', 'nudge-reset disabled')
32841 .on('click', resetOffset)
32842 .call(iD.svg.Icon('#icon-undo'));
32845 .on('move.background-update', _.debounce(update, 1000));
32847 context.background()
32848 .on('change.background-update', update);
32852 setOpacity(opacityDefault);
32854 var keybinding = d3.keybinding('background')
32859 d3.select(document)
32862 context.surface().on('mousedown.background-outside', hide);
32863 context.container().on('mousedown.background-outside', hide);
32868 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
32869 // For example, ⌘Z -> Ctrl+Z
32870 iD.ui.cmd = function(code) {
32871 if (iD.detect().os === 'mac') {
32875 if (iD.detect().os === 'win') {
32876 if (code === '⌘⇧Z') return 'Ctrl+Y';
32888 for (var i = 0; i < code.length; i++) {
32889 if (code[i] in replacements) {
32890 result += replacements[code[i]] + '+';
32898 iD.ui.Commit = function(context) {
32899 var dispatch = d3.dispatch('cancel', 'save');
32901 function commit(selection) {
32902 var changes = context.history().changes(),
32903 summary = context.history().difference().summary();
32905 function zoomToEntity(change) {
32906 var entity = change.entity;
32907 if (change.changeType !== 'deleted' &&
32908 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
32909 context.map().zoomTo(entity);
32910 context.surface().selectAll(
32911 iD.util.entityOrMemberSelector([entity.id], context.graph()))
32912 .classed('hover', true);
32916 var header = selection.append('div')
32917 .attr('class', 'header fillL');
32919 header.append('h3')
32920 .text(t('commit.title'));
32922 var body = selection.append('div')
32923 .attr('class', 'body');
32927 var commentSection = body.append('div')
32928 .attr('class', 'modal-section form-field commit-form');
32930 commentSection.append('label')
32931 .attr('class', 'form-label')
32932 .text(t('commit.message_label'));
32934 var commentField = commentSection.append('textarea')
32935 .attr('placeholder', t('commit.description_placeholder'))
32936 .attr('maxlength', 255)
32937 .property('value', context.storage('comment') || '')
32938 .on('input.save', enableDisableSaveButton)
32939 .on('change.save', enableDisableSaveButton)
32940 .on('input.save', detectForClippy)
32941 .on('change.save', detectForClippy)
32942 .on('blur.save', function() {
32943 context.storage('comment', this.value);
32946 function enableDisableSaveButton() {
32947 d3.selectAll('.save-section .save-button')
32948 .attr('disabled', (this.value.length ? null : true));
32951 function detectForClippy() {
32952 var googleWarning = clippyArea
32955 .data(this.value.match(/google/i) ? [true] : []);
32957 googleWarning.exit().remove();
32959 googleWarning.enter()
32961 .attr('target', '_blank')
32962 .attr('tabindex', -1)
32963 .call(iD.svg.Icon('#icon-alert', 'inline'))
32964 .attr('href', t('commit.google_warning_link'))
32966 .text(t('commit.google_warning'));
32969 commentField.node().select();
32971 context.connection().userChangesets(function (err, changesets) {
32976 for (var i = 0; i < changesets.length; i++) {
32977 if (changesets[i].tags.comment) {
32979 title: changesets[i].tags.comment,
32980 value: changesets[i].tags.comment
32985 commentField.call(d3.combobox().caseSensitive(true).data(comments));
32988 var clippyArea = commentSection.append('div')
32989 .attr('class', 'clippy-area');
32992 var changeSetInfo = commentSection.append('div')
32993 .attr('class', 'changeset-info');
32995 changeSetInfo.append('a')
32996 .attr('target', '_blank')
32997 .attr('tabindex', -1)
32998 .call(iD.svg.Icon('#icon-out-link', 'inline'))
32999 .attr('href', t('commit.about_changeset_comments_link'))
33001 .text(t('commit.about_changeset_comments'));
33004 var warnings = body.selectAll('div.warning-section')
33005 .data([context.history().validate(changes)])
33008 .attr('class', 'modal-section warning-section fillL2')
33009 .style('display', function(d) { return _.isEmpty(d) ? 'none' : null; })
33010 .style('background', '#ffb');
33012 warnings.append('h3')
33013 .text(t('commit.warnings'));
33015 var warningLi = warnings.append('ul')
33016 .attr('class', 'changeset-list')
33018 .data(function(d) { return d; })
33022 .on('mouseover', mouseover)
33023 .on('mouseout', mouseout)
33024 .on('click', warningClick);
33027 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
33030 .append('strong').text(function(d) {
33034 warningLi.filter(function(d) { return d.tooltip; })
33035 .call(bootstrap.tooltip()
33036 .title(function(d) { return d.tooltip; })
33041 // Upload Explanation
33042 var saveSection = body.append('div')
33043 .attr('class','modal-section save-section fillL cf');
33045 var prose = saveSection.append('p')
33046 .attr('class', 'commit-info')
33047 .html(t('commit.upload_explanation'));
33049 context.connection().userDetails(function(err, user) {
33052 var userLink = d3.select(document.createElement('div'));
33054 if (user.image_url) {
33055 userLink.append('img')
33056 .attr('src', user.image_url)
33057 .attr('class', 'icon pre-text user-icon');
33060 userLink.append('a')
33061 .attr('class','user-info')
33062 .text(user.display_name)
33063 .attr('href', context.connection().userURL(user.display_name))
33064 .attr('tabindex', -1)
33065 .attr('target', '_blank');
33067 prose.html(t('commit.upload_explanation_with_user', {user: userLink.html()}));
33072 var buttonSection = saveSection.append('div')
33073 .attr('class','buttons fillL cf');
33075 var cancelButton = buttonSection.append('button')
33076 .attr('class', 'secondary-action col5 button cancel-button')
33077 .on('click.cancel', function() { dispatch.cancel(); });
33079 cancelButton.append('span')
33080 .attr('class', 'label')
33081 .text(t('commit.cancel'));
33083 var saveButton = buttonSection.append('button')
33084 .attr('class', 'action col5 button save-button')
33085 .attr('disabled', function() {
33086 var n = d3.select('.commit-form textarea').node();
33087 return (n && n.value.length) ? null : true;
33089 .on('click.save', function() {
33091 comment: commentField.node().value
33095 saveButton.append('span')
33096 .attr('class', 'label')
33097 .text(t('commit.save'));
33101 var changeSection = body.selectAll('div.commit-section')
33105 .attr('class', 'commit-section modal-section fillL2');
33107 changeSection.append('h3')
33108 .text(t('commit.changes', {count: summary.length}));
33110 var li = changeSection.append('ul')
33111 .attr('class', 'changeset-list')
33116 .on('mouseover', mouseover)
33117 .on('mouseout', mouseout)
33118 .on('click', zoomToEntity);
33120 li.each(function(d) {
33122 .call(iD.svg.Icon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
33126 .attr('class', 'change-type')
33127 .text(function(d) {
33128 return t('commit.' + d.changeType) + ' ';
33131 li.append('strong')
33132 .attr('class', 'entity-type')
33133 .text(function(d) {
33134 return context.presets().match(d.entity, d.graph).name();
33138 .attr('class', 'entity-name')
33139 .text(function(d) {
33140 var name = iD.util.displayName(d.entity) || '',
33142 if (name !== '') string += ':';
33143 return string += ' ' + name;
33146 li.style('opacity', 0)
33148 .style('opacity', 1);
33151 function mouseover(d) {
33153 context.surface().selectAll(
33154 iD.util.entityOrMemberSelector([d.entity.id], context.graph())
33155 ).classed('hover', true);
33159 function mouseout() {
33160 context.surface().selectAll('.hover')
33161 .classed('hover', false);
33164 function warningClick(d) {
33166 context.map().zoomTo(d.entity);
33168 iD.modes.Select(context, [d.entity.id])
33169 .suppressMenu(true));
33173 // Call the enableDisableSaveButton and detectForClippy methods
33174 // off the bat, in case a changeset comment is recovered from
33176 commentField.trigger('input');
33179 return d3.rebind(commit, dispatch, 'on');
33181 iD.ui.confirm = function(selection) {
33182 var modal = iD.ui.modal(selection);
33184 modal.select('.modal')
33185 .classed('modal-alert', true);
33187 var section = modal.select('.content');
33189 section.append('div')
33190 .attr('class', 'modal-section header');
33192 section.append('div')
33193 .attr('class', 'modal-section message-text');
33195 var buttons = section.append('div')
33196 .attr('class', 'modal-section buttons cf');
33198 modal.okButton = function() {
33201 .attr('class', 'action col4')
33202 .on('click.confirm', function() {
33205 .text(t('confirm.okay'));
33212 iD.ui.Conflicts = function(context) {
33213 var dispatch = d3.dispatch('download', 'cancel', 'save'),
33216 function conflicts(selection) {
33217 var header = selection
33219 .attr('class', 'header fillL');
33223 .attr('class', 'fr')
33224 .on('click', function() { dispatch.cancel(); })
33225 .call(iD.svg.Icon('#icon-close'));
33229 .text(t('save.conflict.header'));
33231 var body = selection
33233 .attr('class', 'body fillL');
33237 .attr('class', 'conflicts-help')
33238 .text(t('save.conflict.help'))
33240 .attr('class', 'conflicts-download')
33241 .text(t('save.conflict.download_changes'))
33242 .on('click.download', function() { dispatch.download(); });
33246 .attr('class', 'conflict-container fillL3')
33247 .call(showConflict, 0);
33251 .attr('class', 'conflicts-done')
33252 .attr('opacity', 0)
33253 .style('display', 'none')
33254 .text(t('save.conflict.done'));
33258 .attr('class','buttons col12 joined conflicts-buttons');
33262 .attr('disabled', list.length > 1)
33263 .attr('class', 'action conflicts-button col6')
33264 .text(t('save.title'))
33265 .on('click.try_again', function() { dispatch.save(); });
33269 .attr('class', 'secondary-action conflicts-button col6')
33270 .text(t('confirm.cancel'))
33271 .on('click.cancel', function() { dispatch.cancel(); });
33275 function showConflict(selection, index) {
33276 if (index < 0 || index >= list.length) return;
33278 var parent = d3.select(selection.node().parentNode);
33280 // enable save button if this is the last conflict being reviewed..
33281 if (index === list.length - 1) {
33282 window.setTimeout(function() {
33283 parent.select('.conflicts-button')
33284 .attr('disabled', null);
33286 parent.select('.conflicts-done')
33288 .attr('opacity', 1)
33289 .style('display', 'block');
33293 var item = selection
33294 .selectAll('.conflict')
33295 .data([list[index]]);
33297 var enter = item.enter()
33299 .attr('class', 'conflict');
33303 .attr('class', 'conflict-count')
33304 .text(t('save.conflict.count', { num: index + 1, total: list.length }));
33308 .attr('class', 'conflict-description')
33310 .text(function(d) { return d.name; })
33311 .on('click', function(d) {
33312 zoomToEntity(d.id);
33313 d3.event.preventDefault();
33316 var details = enter
33318 .attr('class', 'conflict-detail-container');
33322 .attr('class', 'conflict-detail-list')
33324 .data(function(d) { return d.details || []; })
33327 .attr('class', 'conflict-detail-item')
33328 .html(function(d) { return d; });
33332 .attr('class', 'conflict-choices')
33337 .attr('class', 'conflict-nav-buttons joined cf')
33338 .selectAll('button')
33339 .data(['previous', 'next'])
33342 .text(function(d) { return t('save.conflict.' + d); })
33343 .attr('class', 'conflict-nav-button action col6')
33344 .attr('disabled', function(d, i) {
33345 return (i === 0 && index === 0) ||
33346 (i === 1 && index === list.length - 1) || null;
33348 .on('click', function(d, i) {
33349 var container = parent.select('.conflict-container'),
33350 sign = (i === 0 ? -1 : 1);
33353 .selectAll('.conflict')
33357 .call(showConflict, index + sign);
33359 d3.event.preventDefault();
33367 function addChoices(selection) {
33368 var choices = selection
33370 .attr('class', 'layer-list')
33372 .data(function(d) { return d.choices || []; });
33374 var enter = choices.enter()
33376 .attr('class', 'layer');
33383 .attr('type', 'radio')
33384 .attr('name', function(d) { return d.id; })
33385 .on('change', function(d, i) {
33386 var ul = this.parentNode.parentNode.parentNode;
33387 ul.__data__.chosen = i;
33393 .text(function(d) { return d.text; });
33396 .each(function(d, i) {
33397 var ul = this.parentNode;
33398 if (ul.__data__.chosen === i) choose(ul, d);
33402 function choose(ul, datum) {
33403 if (d3.event) d3.event.preventDefault();
33407 .classed('active', function(d) { return d === datum; })
33408 .selectAll('input')
33409 .property('checked', function(d) { return d === datum; });
33411 var extent = iD.geo.Extent(),
33414 entity = context.graph().hasEntity(datum.id);
33415 if (entity) extent._extend(entity.extent(context.graph()));
33419 entity = context.graph().hasEntity(datum.id);
33420 if (entity) extent._extend(entity.extent(context.graph()));
33422 zoomToEntity(datum.id, extent);
33425 function zoomToEntity(id, extent) {
33426 context.surface().selectAll('.hover')
33427 .classed('hover', false);
33429 var entity = context.graph().hasEntity(id);
33432 context.map().trimmedExtent(extent);
33434 context.map().zoomTo(entity);
33436 context.surface().selectAll(
33437 iD.util.entityOrMemberSelector([entity.id], context.graph()))
33438 .classed('hover', true);
33443 // The conflict list should be an array of objects like:
33446 // name: entityName(local),
33447 // details: merge.conflicts(),
33450 // choice(id, keepMine, forceLocal),
33451 // choice(id, keepTheirs, forceRemote)
33454 conflicts.list = function(_) {
33455 if (!arguments.length) return list;
33460 return d3.rebind(conflicts, dispatch, 'on');
33462 iD.ui.Contributors = function(context) {
33463 var debouncedUpdate = _.debounce(function() { update(); }, 1000),
33466 wrap = d3.select(null);
33468 function update() {
33470 entities = context.intersects(context.map().extent());
33472 entities.forEach(function(entity) {
33473 if (entity && entity.user) users[entity.user] = true;
33476 var u = Object.keys(users),
33477 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
33480 .call(iD.svg.Icon('#icon-nearby', 'pre-text light'));
33482 var userList = d3.select(document.createElement('span'));
33484 userList.selectAll()
33488 .attr('class', 'user-link')
33489 .attr('href', function(d) { return context.connection().userURL(d); })
33490 .attr('target', '_blank')
33491 .attr('tabindex', -1)
33494 if (u.length > limit) {
33495 var count = d3.select(document.createElement('span'));
33498 .attr('target', '_blank')
33499 .attr('tabindex', -1)
33500 .attr('href', function() {
33501 return context.connection().changesetsURL(context.map().center(), context.map().zoom());
33503 .text(u.length - limit + 1);
33505 wrap.append('span')
33506 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
33509 wrap.append('span')
33510 .html(t('contributors.list', { users: userList.html() }));
33517 .style('opacity', 0);
33519 } else if (hidden) {
33522 .style('opacity', 1);
33526 return function(selection) {
33530 context.connection().on('loaded.contributors', debouncedUpdate);
33531 context.map().on('move.contributors', debouncedUpdate);
33534 iD.ui.Disclosure = function() {
33535 var dispatch = d3.dispatch('toggled'),
33538 content = function () {};
33540 var disclosure = function(selection) {
33541 var $link = selection.selectAll('.hide-toggle')
33544 $link.enter().append('a')
33546 .attr('class', 'hide-toggle');
33549 .on('click', toggle)
33550 .classed('expanded', expanded);
33552 var $body = selection.selectAll('div')
33555 $body.enter().append('div');
33557 $body.classed('hide', !expanded)
33560 function toggle() {
33561 expanded = !expanded;
33562 $link.classed('expanded', expanded);
33563 $body.call(iD.ui.Toggle(expanded));
33564 dispatch.toggled(expanded);
33568 disclosure.title = function(_) {
33569 if (!arguments.length) return title;
33574 disclosure.expanded = function(_) {
33575 if (!arguments.length) return expanded;
33580 disclosure.content = function(_) {
33581 if (!arguments.length) return content;
33586 return d3.rebind(disclosure, dispatch, 'on');
33588 iD.ui.EntityEditor = function(context) {
33589 var dispatch = d3.dispatch('choose'),
33591 coalesceChanges = false,
33598 var presetEditor = iD.ui.preset(context)
33599 .on('change', changeTags);
33600 var rawTagEditor = iD.ui.RawTagEditor(context)
33601 .on('change', changeTags);
33603 function entityEditor(selection) {
33604 var entity = context.entity(id),
33605 tags = _.clone(entity.tags);
33607 var $header = selection.selectAll('.header')
33611 var $enter = $header.enter().append('div')
33612 .attr('class', 'header fillL cf');
33614 $enter.append('button')
33615 .attr('class', 'fl preset-reset preset-choose')
33619 $enter.append('button')
33620 .attr('class', 'fr preset-close')
33621 .call(iD.svg.Icon(modified ? '#icon-apply' : '#icon-close'));
33623 $enter.append('h3');
33626 $header.select('h3')
33627 .text(t('inspector.edit'));
33629 $header.select('.preset-close')
33630 .on('click', function() {
33631 context.enter(iD.modes.Browse(context));
33634 var $body = selection.selectAll('.inspector-body')
33638 $enter = $body.enter().append('div')
33639 .attr('class', 'inspector-body');
33641 $enter.append('div')
33642 .attr('class', 'preset-list-item inspector-inner')
33644 .attr('class', 'preset-list-button-wrap')
33646 .attr('class', 'preset-list-button preset-reset')
33647 .call(bootstrap.tooltip()
33648 .title(t('inspector.back_tooltip'))
33649 .placement('bottom'))
33651 .attr('class', 'label');
33653 $body.select('.preset-list-button-wrap')
33654 .call(reference.button);
33656 $body.select('.preset-list-item')
33657 .call(reference.body);
33659 $enter.append('div')
33660 .attr('class', 'inspector-border inspector-preset');
33662 $enter.append('div')
33663 .attr('class', 'inspector-border raw-tag-editor inspector-inner');
33665 $enter.append('div')
33666 .attr('class', 'inspector-border raw-member-editor inspector-inner');
33668 $enter.append('div')
33669 .attr('class', 'raw-membership-editor inspector-inner');
33671 selection.selectAll('.preset-reset')
33672 .on('click', function() {
33673 dispatch.choose(preset);
33677 $body.select('.preset-list-item button')
33678 .call(iD.ui.PresetIcon()
33679 .geometry(context.geometry(id))
33682 $body.select('.preset-list-item .label')
33683 .text(preset.name());
33685 $body.select('.inspector-preset')
33692 $body.select('.raw-tag-editor')
33699 if (entity.type === 'relation') {
33700 $body.select('.raw-member-editor')
33701 .style('display', 'block')
33702 .call(iD.ui.RawMemberEditor(context)
33705 $body.select('.raw-member-editor')
33706 .style('display', 'none');
33709 $body.select('.raw-membership-editor')
33710 .call(iD.ui.RawMembershipEditor(context)
33713 function historyChanged() {
33714 if (state === 'hide') return;
33716 var entity = context.hasEntity(id),
33717 graph = context.graph();
33718 if (!entity) return;
33720 entityEditor.preset(context.presets().match(entity, graph));
33721 entityEditor.modified(base !== graph);
33722 entityEditor(selection);
33726 .on('change.entity-editor', historyChanged);
33729 function clean(o) {
33731 function cleanVal(k, v) {
33732 function keepSpaces(k) {
33733 var whitelist = ['opening_hours', 'service_times', 'collection_times',
33734 'operating_times', 'smoking_hours', 'happy_hours'];
33735 return _.any(whitelist, function(s) { return k.indexOf(s) !== -1; });
33738 var blacklist = ['description', 'note', 'fixme'];
33739 if (_.any(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
33741 var cleaned = v.split(';')
33742 .map(function(s) { return s.trim(); })
33743 .join(keepSpaces(k) ? '; ' : ';');
33745 // The code below is not intended to validate websites and emails.
33746 // It is only intended to prevent obvious copy-paste errors. (#2323)
33748 // clean website- and email-like tags
33749 if (k.indexOf('website') !== -1 ||
33750 k.indexOf('email') !== -1 ||
33751 cleaned.indexOf('http') === 0) {
33753 .replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
33760 var out = {}, k, v;
33762 if (k && (v = o[k]) !== undefined) {
33763 out[k] = cleanVal(k, v);
33769 // Tag changes that fire on input can all get coalesced into a single
33770 // history operation when the user leaves the field. #2342
33771 function changeTags(changed, onInput) {
33772 var entity = context.entity(id),
33773 annotation = t('operations.change_tags.annotation'),
33774 tags = _.extend({}, entity.tags, changed);
33777 tags = clean(tags);
33779 if (!_.isEqual(entity.tags, tags)) {
33780 if (coalesceChanges) {
33781 context.overwrite(iD.actions.ChangeTags(id, tags), annotation);
33783 context.perform(iD.actions.ChangeTags(id, tags), annotation);
33784 coalesceChanges = !!onInput;
33789 entityEditor.modified = function(_) {
33790 if (!arguments.length) return modified;
33792 d3.selectAll('button.preset-close use')
33793 .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
33796 entityEditor.state = function(_) {
33797 if (!arguments.length) return state;
33799 return entityEditor;
33802 entityEditor.entityID = function(_) {
33803 if (!arguments.length) return id;
33805 base = context.graph();
33806 entityEditor.preset(context.presets().match(context.entity(id), base));
33807 entityEditor.modified(false);
33808 coalesceChanges = false;
33809 return entityEditor;
33812 entityEditor.preset = function(_) {
33813 if (!arguments.length) return preset;
33814 if (_ !== preset) {
33816 reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context)
33819 return entityEditor;
33822 return d3.rebind(entityEditor, dispatch, 'on');
33824 iD.ui.FeatureInfo = function(context) {
33825 function update(selection) {
33826 var features = context.features(),
33827 stats = features.stats(),
33829 hiddenList = _.compact(_.map(features.hidden(), function(k) {
33832 return String(stats[k]) + ' ' + t('feature.' + k + '.description');
33836 selection.html('');
33838 if (hiddenList.length) {
33839 var tooltip = bootstrap.tooltip()
33842 .title(function() {
33843 return iD.ui.tooltipHtml(hiddenList.join('<br/>'));
33846 var warning = selection.append('a')
33848 .attr('tabindex', -1)
33849 .html(t('feature_info.hidden_warning', { count: count }))
33851 .on('click', function() {
33852 tooltip.hide(warning);
33853 // open map data panel?
33854 d3.event.preventDefault();
33859 .classed('hide', !hiddenList.length);
33862 return function(selection) {
33865 context.features().on('change.feature_info', function() {
33870 iD.ui.FeatureList = function(context) {
33871 var geocodeResults;
33873 function featureList(selection) {
33874 var header = selection.append('div')
33875 .attr('class', 'header fillL cf');
33877 header.append('h3')
33878 .text(t('inspector.feature_list'));
33880 function keypress() {
33881 var q = search.property('value'),
33882 items = list.selectAll('.feature-list-item');
33883 if (d3.event.keyCode === 13 && q.length && items.size()) {
33884 click(items.datum());
33888 function inputevent() {
33889 geocodeResults = undefined;
33893 var searchWrap = selection.append('div')
33894 .attr('class', 'search-header');
33896 var search = searchWrap.append('input')
33897 .attr('placeholder', t('inspector.search'))
33898 .attr('type', 'search')
33899 .on('keypress', keypress)
33900 .on('input', inputevent);
33903 .call(iD.svg.Icon('#icon-search', 'pre-text'));
33905 var listWrap = selection.append('div')
33906 .attr('class', 'inspector-body');
33908 var list = listWrap.append('div')
33909 .attr('class', 'feature-list cf');
33912 .on('exit.feature-list', clearSearch);
33914 .on('drawn.feature-list', mapDrawn);
33916 function clearSearch() {
33917 search.property('value', '');
33921 function mapDrawn(e) {
33927 function features() {
33930 graph = context.graph(),
33931 q = search.property('value').toLowerCase();
33933 if (!q) return result;
33935 var idMatch = q.match(/^([nwr])([0-9]+)$/);
33940 geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
33941 type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
33946 var locationMatch = sexagesimal.pair(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
33948 if (locationMatch) {
33949 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
33953 type: t('inspector.location'),
33954 name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
33959 function addEntity(entity) {
33960 if (entity.id in entities || result.length > 200)
33963 entities[entity.id] = true;
33965 var name = iD.util.displayName(entity) || '';
33966 if (name.toLowerCase().indexOf(q) >= 0) {
33970 geometry: context.geometry(entity.id),
33971 type: context.presets().match(entity, graph).name(),
33976 graph.parentRelations(entity).forEach(function(parent) {
33981 var visible = context.surface().selectAll('.point, .line, .area')[0];
33982 for (var i = 0; i < visible.length && result.length <= 200; i++) {
33983 addEntity(visible[i].__data__);
33986 (geocodeResults || []).forEach(function(d) {
33987 // https://github.com/openstreetmap/iD/issues/1890
33988 if (d.osm_type && d.osm_id) {
33990 id: iD.Entity.id.fromOSM(d.osm_type, d.osm_id),
33991 geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
33992 type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
33993 : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
33994 name: d.display_name,
33995 extent: new iD.geo.Extent(
33996 [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
33997 [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
34005 function drawList() {
34006 var value = search.property('value'),
34007 results = features();
34009 list.classed('filtered', value.length);
34011 var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
34013 var resultsIndicator = list.selectAll('.no-results-item')
34015 .enter().append('button')
34016 .property('disabled', true)
34017 .attr('class', 'no-results-item')
34018 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
34020 resultsIndicator.append('span')
34021 .attr('class', 'entity-name');
34023 list.selectAll('.no-results-item .entity-name')
34024 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
34026 list.selectAll('.geocode-item')
34028 .enter().append('button')
34029 .attr('class', 'geocode-item')
34030 .on('click', geocode)
34032 .attr('class', 'label')
34034 .attr('class', 'entity-name')
34035 .text(t('geocoder.search'));
34037 list.selectAll('.no-results-item')
34038 .style('display', (value.length && !results.length) ? 'block' : 'none');
34040 list.selectAll('.geocode-item')
34041 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
34043 list.selectAll('.feature-list-item')
34047 var items = list.selectAll('.feature-list-item')
34048 .data(results, function(d) { return d.id; });
34050 var enter = items.enter()
34051 .insert('button', '.geocode-item')
34052 .attr('class', 'feature-list-item')
34053 .on('mouseover', mouseover)
34054 .on('mouseout', mouseout)
34055 .on('click', click);
34059 .attr('class', 'label');
34061 label.each(function(d) {
34063 .call(iD.svg.Icon('#icon-' + d.geometry, 'pre-text'));
34066 label.append('span')
34067 .attr('class', 'entity-type')
34068 .text(function(d) { return d.type; });
34070 label.append('span')
34071 .attr('class', 'entity-name')
34072 .text(function(d) { return d.name; });
34074 enter.style('opacity', 0)
34076 .style('opacity', 1);
34084 function mouseover(d) {
34085 if (d.id === -1) return;
34087 context.surface().selectAll(iD.util.entityOrMemberSelector([d.id], context.graph()))
34088 .classed('hover', true);
34091 function mouseout() {
34092 context.surface().selectAll('.hover')
34093 .classed('hover', false);
34096 function click(d) {
34097 d3.event.preventDefault();
34099 context.map().centerZoom([d.location[1], d.location[0]], 20);
34101 else if (d.entity) {
34102 if (d.entity.type === 'node') {
34103 context.map().center(d.entity.loc);
34104 } else if (d.entity.type === 'way') {
34105 var center = context.projection(context.map().center()),
34106 edge = iD.geo.chooseEdge(context.childNodes(d.entity), center, context.projection);
34107 context.map().center(edge.loc);
34109 context.enter(iD.modes.Select(context, [d.entity.id]).suppressMenu(true));
34111 context.zoomToEntity(d.id);
34115 function geocode() {
34116 var searchVal = encodeURIComponent(search.property('value'));
34117 d3.json('https://nominatim.openstreetmap.org/search/' + searchVal + '?limit=10&format=json', function(err, resp) {
34118 geocodeResults = resp || [];
34124 return featureList;
34126 iD.ui.flash = function(selection) {
34127 var modal = iD.ui.modal(selection);
34129 modal.select('.modal').classed('modal-flash', true);
34131 modal.select('.content')
34132 .classed('modal-section', true)
34134 .attr('class', 'description');
34136 modal.on('click.flash', function() { modal.remove(); });
34138 setTimeout(function() {
34145 iD.ui.FullScreen = function(context) {
34146 var element = context.container().node(),
34147 keybinding = d3.keybinding('full-screen');
34150 function getFullScreenFn() {
34151 if (element.requestFullscreen) {
34152 return element.requestFullscreen;
34153 } else if (element.msRequestFullscreen) {
34154 return element.msRequestFullscreen;
34155 } else if (element.mozRequestFullScreen) {
34156 return element.mozRequestFullScreen;
34157 } else if (element.webkitRequestFullscreen) {
34158 return element.webkitRequestFullscreen;
34162 function getExitFullScreenFn() {
34163 if (document.exitFullscreen) {
34164 return document.exitFullscreen;
34165 } else if (document.msExitFullscreen) {
34166 return document.msExitFullscreen;
34167 } else if (document.mozCancelFullScreen) {
34168 return document.mozCancelFullScreen;
34169 } else if (document.webkitExitFullscreen) {
34170 return document.webkitExitFullscreen;
34174 function isFullScreen() {
34175 return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement ||
34176 document.msFullscreenElement;
34179 function isSupported() {
34180 return !!getFullScreenFn();
34183 function fullScreen() {
34184 d3.event.preventDefault();
34185 if (!isFullScreen()) {
34186 // button.classed('active', true);
34187 getFullScreenFn().apply(element);
34189 // button.classed('active', false);
34190 getExitFullScreenFn().apply(document);
34194 return function() { // selection) {
34195 if (!isSupported())
34198 // var tooltip = bootstrap.tooltip()
34199 // .placement('left');
34201 // button = selection.append('button')
34202 // .attr('title', t('full_screen'))
34203 // .attr('tabindex', -1)
34204 // .on('click', fullScreen)
34207 // button.append('span')
34208 // .attr('class', 'icon full-screen');
34211 .on('f11', fullScreen)
34212 .on(iD.ui.cmd('⌘⇧F'), fullScreen);
34214 d3.select(document)
34218 iD.ui.Geolocate = function(context) {
34219 var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
34220 locating = iD.ui.Loading(context).message(t('geolocate.locating')).blocking(true),
34224 context.enter(iD.modes.Browse(context));
34225 context.container().call(locating);
34226 navigator.geolocation.getCurrentPosition(success, error, geoOptions);
34228 // This timeout ensures that we still call finish() even if
34229 // the user declines to share their location in Firefox
34230 timeoutId = setTimeout(finish, 10000 /* 10sec */ );
34233 function success(position) {
34234 var map = context.map(),
34235 extent = iD.geo.Extent([position.coords.longitude, position.coords.latitude])
34236 .padByMeters(position.coords.accuracy);
34238 map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
34246 function finish() {
34247 locating.close(); // unblock ui
34248 if (timeoutId) { clearTimeout(timeoutId); }
34249 timeoutId = undefined;
34252 return function(selection) {
34253 if (!navigator.geolocation) return;
34255 selection.append('button')
34256 .attr('tabindex', -1)
34257 .attr('title', t('geolocate.title'))
34258 .on('click', click)
34259 .call(iD.svg.Icon('#icon-geolocate', 'light'))
34260 .call(bootstrap.tooltip()
34261 .placement('left'));
34264 iD.ui.Help = function(context) {
34269 'help.editing_saving',
34278 var docs = docKeys.map(function(key) {
34281 title: text.split('\n')[0].replace('#', '').trim(),
34282 html: marked(text.split('\n').slice(1).join('\n'))
34286 function help(selection) {
34292 function toggle() {
34293 if (d3.event) d3.event.preventDefault();
34294 tooltip.hide(button);
34295 setVisible(!button.classed('active'));
34298 function setVisible(show) {
34299 if (show !== shown) {
34300 button.classed('active', show);
34304 selection.on('mousedown.help-inside', function() {
34305 return d3.event.stopPropagation();
34307 pane.style('display', 'block')
34308 .style('right', '-500px')
34311 .style('right', '0px');
34313 pane.style('right', '0px')
34316 .style('right', '-500px')
34317 .each('end', function() {
34318 d3.select(this).style('display', 'none');
34320 selection.on('mousedown.help-inside', null);
34325 function clickHelp(d, i) {
34326 pane.property('scrollTop', 0);
34327 doctitle.html(d.title);
34329 body.selectAll('a')
34330 .attr('target', '_blank');
34331 menuItems.classed('selected', function(m) {
34332 return m.title === d.title;
34338 var prevLink = nav.append('a')
34339 .attr('class', 'previous')
34340 .on('click', function() {
34341 clickHelp(docs[i - 1], i - 1);
34343 prevLink.append('span').html('◄ ' + docs[i - 1].title);
34345 if (i < docs.length - 1) {
34346 var nextLink = nav.append('a')
34347 .attr('class', 'next')
34348 .on('click', function() {
34349 clickHelp(docs[i + 1], i + 1);
34351 nextLink.append('span').html(docs[i + 1].title + ' ►');
34355 function clickWalkthrough() {
34356 d3.select(document.body).call(iD.ui.intro(context));
34361 var pane = selection.append('div')
34362 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
34363 tooltip = bootstrap.tooltip()
34366 .title(iD.ui.tooltipHtml(t('help.title'), key)),
34367 button = selection.append('button')
34368 .attr('tabindex', -1)
34369 .on('click', toggle)
34370 .call(iD.svg.Icon('#icon-help', 'light'))
34375 var toc = pane.append('ul')
34376 .attr('class', 'toc');
34378 var menuItems = toc.selectAll('li')
34383 .html(function(d) { return d.title; })
34384 .on('click', clickHelp);
34387 .attr('class','walkthrough')
34389 .text(t('splash.walkthrough'))
34390 .on('click', clickWalkthrough);
34392 var content = pane.append('div')
34393 .attr('class', 'left-content');
34395 var doctitle = content.append('h2')
34396 .text(t('help.title'));
34398 var body = content.append('div')
34399 .attr('class', 'body');
34401 var nav = content.append('div')
34402 .attr('class', 'nav');
34404 clickHelp(docs[0], 0);
34406 var keybinding = d3.keybinding('help')
34411 d3.select(document)
34414 context.surface().on('mousedown.help-outside', hide);
34415 context.container().on('mousedown.help-outside', hide);
34420 iD.ui.Info = function(context) {
34421 var key = iD.ui.cmd('⌘I'),
34422 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
34425 function info(selection) {
34426 function radiansToMeters(r) {
34427 // using WGS84 authalic radius (6371007.1809 m)
34428 return r * 6371007.1809;
34431 function steradiansToSqmeters(r) {
34432 // http://gis.stackexchange.com/a/124857/40446
34433 return r / 12.56637 * 510065621724000;
34436 function toLineString(feature) {
34437 if (feature.type === 'LineString') return feature;
34439 var result = { type: 'LineString', coordinates: [] };
34440 if (feature.type === 'Polygon') {
34441 result.coordinates = feature.coordinates[0];
34442 } else if (feature.type === 'MultiPolygon') {
34443 result.coordinates = feature.coordinates[0][0];
34449 function displayLength(m) {
34450 var d = m * (imperial ? 3.28084 : 1),
34469 // drop unnecessary precision
34470 p = d > 1000 ? 0 : d > 100 ? 1 : 2;
34472 return String(d.toFixed(p)) + ' ' + unit;
34475 function displayArea(m2) {
34476 var d = m2 * (imperial ? 10.7639111056 : 1),
34477 d1, d2, p1, p2, unit1, unit2;
34480 if (d >= 6969600) { // > 0.25mi² show mi²
34488 if (d > 4356 && d < 43560000) { // 0.1 - 1000 acres
34494 if (d >= 250000) { // > 0.25km² show km²
34502 if (d > 1000 && d < 10000000) { // 0.1 - 1000 hectares
34508 // drop unnecessary precision
34509 p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
34510 p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
34512 return String(d1.toFixed(p1)) + ' ' + unit1 +
34513 (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
34517 function redraw() {
34518 if (hidden) return;
34520 var resolver = context.graph(),
34521 selected = _.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
34522 singular = selected.length === 1 ? selected[0] : null,
34523 extent = iD.geo.Extent(),
34528 .attr('class', 'infobox-heading fillD')
34529 .text(singular || t('infobox.selected', { n: selected.length }));
34531 if (!selected.length) return;
34534 for (var i = 0; i < selected.length; i++) {
34535 entity = context.entity(selected[i]);
34536 extent._extend(entity.extent(resolver));
34538 center = extent.center();
34541 var list = wrap.append('ul');
34543 // multiple wrap, just display extent center..
34546 .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
34550 // single wrap, display details..
34551 if (!entity) return;
34552 var geometry = entity.geometry(resolver);
34554 if (geometry === 'line' || geometry === 'area') {
34555 var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
34556 feature = entity.asGeoJSON(resolver),
34557 length = radiansToMeters(d3.geo.length(toLineString(feature))),
34558 lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')),
34559 centroid = d3.geo.centroid(feature);
34562 .text(t('infobox.geometry') + ': ' +
34563 (closed ? t('infobox.closed') + ' ' : '') + t('geometry.' + geometry) );
34566 var area = steradiansToSqmeters(entity.area(resolver));
34568 .text(t('infobox.area') + ': ' + displayArea(area));
34572 .text(lengthLabel + ': ' + displayLength(length));
34575 .text(t('infobox.centroid') + ': ' + centroid[0].toFixed(5) + ', ' + centroid[1].toFixed(5));
34578 var toggle = imperial ? 'imperial' : 'metric';
34580 .text(t('infobox.' + toggle))
34582 .attr('class', 'button')
34583 .on('click', function() {
34584 d3.event.preventDefault();
34585 imperial = !imperial;
34590 var centerLabel = t('infobox.' + (entity.type === 'node' ? 'location' : 'center'));
34593 .text(t('infobox.geometry') + ': ' + t('geometry.' + geometry));
34596 .text(centerLabel + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
34601 function toggle() {
34602 if (d3.event) d3.event.preventDefault();
34608 .style('display', 'block')
34609 .style('opacity', 1)
34612 .style('opacity', 0)
34613 .each('end', function() {
34614 d3.select(this).style('display', 'none');
34618 .style('display', 'block')
34619 .style('opacity', 0)
34622 .style('opacity', 1);
34629 var wrap = selection.selectAll('.infobox')
34634 .attr('class', 'infobox fillD2')
34635 .style('display', (hidden ? 'none' : 'block'));
34638 .on('drawn.info', redraw);
34642 var keybinding = d3.keybinding('info')
34645 d3.select(document)
34651 iD.ui.Inspector = function(context) {
34652 var presetList = iD.ui.PresetList(context),
34653 entityEditor = iD.ui.EntityEditor(context),
34656 newFeature = false;
34658 function inspector(selection) {
34660 .entityID(entityID)
34661 .autofocus(newFeature)
34662 .on('choose', setPreset);
34666 .entityID(entityID)
34667 .on('choose', showList);
34669 var $wrap = selection.selectAll('.panewrap')
34672 var $enter = $wrap.enter().append('div')
34673 .attr('class', 'panewrap');
34675 $enter.append('div')
34676 .attr('class', 'preset-list-pane pane');
34678 $enter.append('div')
34679 .attr('class', 'entity-editor-pane pane');
34681 var $presetPane = $wrap.select('.preset-list-pane');
34682 var $editorPane = $wrap.select('.entity-editor-pane');
34684 var graph = context.graph(),
34685 entity = context.entity(entityID),
34686 showEditor = state === 'hover' ||
34687 entity.isUsed(graph) ||
34688 entity.isHighwayIntersection(graph);
34691 $wrap.style('right', '0%');
34692 $editorPane.call(entityEditor);
34694 $wrap.style('right', '-100%');
34695 $presetPane.call(presetList);
34698 var $footer = selection.selectAll('.footer')
34701 $footer.enter().append('div')
34702 .attr('class', 'footer');
34704 selection.select('.footer')
34705 .call(iD.ui.ViewOnOSM(context)
34706 .entityID(entityID));
34708 function showList(preset) {
34710 .styleTween('right', function() { return d3.interpolate('0%', '-100%'); });
34712 $presetPane.call(presetList
34717 function setPreset(preset) {
34719 .styleTween('right', function() { return d3.interpolate('-100%', '0%'); });
34721 $editorPane.call(entityEditor
34726 inspector.state = function(_) {
34727 if (!arguments.length) return state;
34729 entityEditor.state(state);
34733 inspector.entityID = function(_) {
34734 if (!arguments.length) return entityID;
34739 inspector.newFeature = function(_) {
34740 if (!arguments.length) return newFeature;
34747 iD.ui.intro = function(context) {
34750 function intro(selection) {
34752 function localizedName(id) {
34754 n2140018997: 'city_hall',
34755 n367813436: 'fire_department',
34756 w203988286: 'memory_isle_park',
34757 w203972937: 'riverwalk_trail',
34758 w203972938: 'riverwalk_trail',
34759 w203972940: 'riverwalk_trail',
34760 w41785752: 'w_michigan_ave',
34761 w134150789: 'w_michigan_ave',
34762 w134150795: 'w_michigan_ave',
34763 w134150800: 'w_michigan_ave',
34764 w134150811: 'w_michigan_ave',
34765 w134150802: 'e_michigan_ave',
34766 w134150836: 'e_michigan_ave',
34767 w41074896: 'e_michigan_ave',
34768 w17965834: 'spring_st',
34769 w203986457: 'scidmore_park',
34770 w203049587: 'petting_zoo',
34771 w17967397: 'n_andrews_st',
34772 w17967315: 's_andrews_st',
34773 w17967326: 'n_constantine_st',
34774 w17966400: 's_constantine_st',
34775 w170848823: 'rocky_river',
34776 w170848824: 'rocky_river',
34777 w170848331: 'rocky_river',
34778 w17967752: 'railroad_dr',
34779 w17965998: 'conrail_rr',
34780 w134150845: 'conrail_rr',
34781 w170989131: 'st_joseph_river',
34782 w143497377: 'n_main_st',
34783 w134150801: 's_main_st',
34784 w134150830: 's_main_st',
34785 w17966462: 's_main_st',
34786 w17967734: 'water_st',
34787 w17964996: 'foster_st',
34788 w170848330: 'portage_river',
34789 w17965351: 'flower_st',
34790 w17965502: 'elm_st',
34791 w17965402: 'walnut_st',
34792 w17964793: 'morris_ave',
34793 w17967444: 'east_st',
34794 w17966984: 'portage_ave'
34796 return features[id] && t('intro.graph.' + features[id]);
34799 context.enter(iD.modes.Browse(context));
34801 // Save current map state
34802 var history = context.history().toJSON(),
34803 hash = window.location.hash,
34804 center = context.map().center(),
34805 zoom = context.map().zoom(),
34806 background = context.background().baseLayerSource(),
34807 opacity = d3.selectAll('#map .layer-background').style('opacity'),
34808 loadedTiles = context.connection().loadedTiles(),
34809 baseEntities = context.history().graph().base().entities,
34813 context.inIntro(true);
34815 // Load semi-real data used in intro
34816 context.connection().toggle(false).flush();
34817 context.history().reset();
34819 introGraph = JSON.parse(iD.introGraph);
34820 for (var key in introGraph) {
34821 introGraph[key] = iD.Entity(introGraph[key]);
34822 name = localizedName(key);
34824 introGraph[key].tags.name = name;
34827 context.history().merge(d3.values(iD.Graph().load(introGraph).entities));
34828 context.background().bing();
34830 d3.selectAll('#map .layer-background').style('opacity', 1);
34832 var curtain = d3.curtain();
34833 selection.call(curtain);
34835 function reveal(box, text, options) {
34836 options = options || {};
34837 if (text) curtain.reveal(box, text, options.tooltipClass, options.duration);
34838 else curtain.reveal(box, '', '', options.duration);
34841 var steps = ['navigation', 'point', 'area', 'line', 'startEditing'].map(function(step, i) {
34842 var s = iD.ui.intro[step](context, reveal)
34843 .on('done', function() {
34844 entered.filter(function(d) {
34845 return d.title === s.title;
34846 }).classed('finished', true);
34847 enter(steps[i + 1]);
34852 steps[steps.length - 1].on('startEditing', function() {
34855 d3.selectAll('#map .layer-background').style('opacity', opacity);
34856 context.connection().toggle(true).flush().loadedTiles(loadedTiles);
34857 context.history().reset().merge(d3.values(baseEntities));
34858 context.background().baseLayerSource(background);
34859 if (history) context.history().fromJSON(history, false);
34860 context.map().centerZoom(center, zoom);
34861 window.location.replace(hash);
34862 context.inIntro(false);
34865 var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
34867 var buttonwrap = navwrap.append('div')
34868 .attr('class', 'joined')
34869 .selectAll('button.step');
34871 var entered = buttonwrap
34875 .attr('class', 'step')
34876 .on('click', enter);
34879 .call(iD.svg.Icon('#icon-apply', 'pre-text'));
34883 .text(function(d) { return t(d.title); });
34887 function enter (newStep) {
34888 if (step) { step.exit(); }
34890 context.enter(iD.modes.Browse(context));
34895 entered.classed('active', function(d) {
34896 return d.title === step.title;
34904 iD.ui.intro.pointBox = function(point, context) {
34905 var rect = context.surfaceRect();
34906 point = context.projection(point);
34908 left: point[0] + rect.left - 30,
34909 top: point[1] + rect.top - 50,
34915 iD.ui.intro.pad = function(box, padding, context) {
34916 if (box instanceof Array) {
34917 var rect = context.surfaceRect();
34918 box = context.projection(box);
34920 left: box[0] + rect.left,
34921 top: box[1] + rect.top
34925 left: box.left - padding,
34926 top: box.top - padding,
34927 width: (box.width || 0) + 2 * padding,
34928 height: (box.width || 0) + 2 * padding
34932 iD.ui.intro.icon = function(name, svgklass) {
34933 return '<svg class="icon ' + (svgklass || '') + '">' +
34934 '<use xlink:href="' + name + '"></use></svg>';
34936 iD.ui.Lasso = function(context) {
34937 var group, polygon;
34939 lasso.coordinates = [];
34941 function lasso(selection) {
34943 context.container().classed('lasso', true);
34945 group = selection.append('g')
34946 .attr('class', 'lasso hide');
34948 polygon = group.append('path')
34949 .attr('class', 'lasso-path');
34951 group.call(iD.ui.Toggle(true));
34957 polygon.data([lasso.coordinates])
34958 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
34962 lasso.extent = function () {
34963 return lasso.coordinates.reduce(function(extent, point) {
34964 return extent.extend(iD.geo.Extent(point));
34965 }, iD.geo.Extent());
34968 lasso.p = function(_) {
34969 if (!arguments.length) return lasso;
34970 lasso.coordinates.push(_);
34975 lasso.close = function() {
34977 group.call(iD.ui.Toggle(false, function() {
34978 d3.select(this).remove();
34981 context.container().classed('lasso', false);
34986 iD.ui.Loading = function(context) {
34991 var loading = function(selection) {
34992 modal = iD.ui.modal(selection, blocking);
34994 var loadertext = modal.select('.content')
34995 .classed('loading-modal', true)
34997 .attr('class', 'modal-section fillL');
34999 loadertext.append('img')
35000 .attr('class', 'loader')
35001 .attr('src', context.imagePath('loader-white.gif'));
35003 loadertext.append('h3')
35006 modal.select('button.close')
35007 .attr('class', 'hide');
35012 loading.message = function(_) {
35013 if (!arguments.length) return message;
35018 loading.blocking = function(_) {
35019 if (!arguments.length) return blocking;
35024 loading.close = function() {
35030 iD.ui.MapData = function(context) {
35032 features = context.features().keys(),
35033 layers = context.layers(),
35034 fills = ['wireframe', 'partial', 'full'],
35035 fillDefault = context.storage('area-fill') || 'partial',
35036 fillSelected = fillDefault;
35039 function map_data(selection) {
35041 function showsFeature(d) {
35042 return context.features().enabled(d);
35045 function autoHiddenFeature(d) {
35046 return context.features().autoHidden(d);
35049 function clickFeature(d) {
35050 context.features().toggle(d);
35054 function showsFill(d) {
35055 return fillSelected === d;
35058 function setFill(d) {
35059 _.each(fills, function(opt) {
35060 context.surface().classed('fill-' + opt, Boolean(opt === d));
35064 if (d !== 'wireframe') {
35066 context.storage('area-fill', d);
35071 function toggleLayer(which) {
35072 var layer = layers.layer(which);
35074 layer.enabled(!layer.enabled());
35079 function clickGpx() {
35080 toggleLayer('gpx');
35083 function clickMapillaryImages() {
35084 toggleLayer('mapillary-images');
35087 function clickMapillarySigns() {
35088 toggleLayer('mapillary-signs');
35092 function drawMapillaryItems(selection) {
35093 var mapillaryImages = layers.layer('mapillary-images'),
35094 mapillarySigns = layers.layer('mapillary-signs'),
35095 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
35096 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
35097 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
35098 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
35100 var mapillaryList = selection
35101 .selectAll('.layer-list-mapillary')
35108 .attr('class', 'layer-list layer-list-mapillary');
35110 var mapillaryImageLayerItem = mapillaryList
35111 .selectAll('.list-item-mapillary-images')
35112 .data(supportsMapillaryImages ? [0] : []);
35114 var enterImages = mapillaryImageLayerItem.enter()
35116 .attr('class', 'list-item-mapillary-images');
35118 var labelImages = enterImages.append('label')
35119 .call(bootstrap.tooltip()
35120 .title(t('mapillary_images.tooltip'))
35121 .placement('top'));
35123 labelImages.append('input')
35124 .attr('type', 'checkbox')
35125 .on('change', clickMapillaryImages);
35127 labelImages.append('span')
35128 .text(t('mapillary_images.title'));
35131 var mapillarySignLayerItem = mapillaryList
35132 .selectAll('.list-item-mapillary-signs')
35133 .data(supportsMapillarySigns ? [0] : []);
35135 var enterSigns = mapillarySignLayerItem.enter()
35137 .attr('class', 'list-item-mapillary-signs');
35139 var labelSigns = enterSigns.append('label')
35140 .call(bootstrap.tooltip()
35141 .title(t('mapillary_signs.tooltip'))
35142 .placement('top'));
35144 labelSigns.append('input')
35145 .attr('type', 'checkbox')
35146 .on('change', clickMapillarySigns);
35148 labelSigns.append('span')
35149 .text(t('mapillary_signs.title'));
35152 mapillaryImageLayerItem
35153 .classed('active', showsMapillaryImages)
35154 .selectAll('input')
35155 .property('checked', showsMapillaryImages);
35157 mapillarySignLayerItem
35158 .classed('active', showsMapillarySigns)
35159 .selectAll('input')
35160 .property('checked', showsMapillarySigns);
35163 mapillaryImageLayerItem.exit()
35165 mapillarySignLayerItem.exit()
35170 function drawGpxItem(selection) {
35171 var gpx = layers.layer('gpx'),
35172 hasGpx = gpx && gpx.hasGpx(),
35173 showsGpx = hasGpx && gpx.enabled();
35175 var gpxLayerItem = selection
35176 .selectAll('.layer-list-gpx')
35177 .data(gpx ? [0] : []);
35180 var enter = gpxLayerItem.enter()
35182 .attr('class', 'layer-list layer-list-gpx')
35184 .classed('list-item-gpx', true);
35186 enter.append('button')
35187 .attr('class', 'list-item-gpx-extent')
35188 .call(bootstrap.tooltip()
35189 .title(t('gpx.zoom'))
35190 .placement('left'))
35191 .on('click', function() {
35192 d3.event.preventDefault();
35193 d3.event.stopPropagation();
35196 .call(iD.svg.Icon('#icon-search'));
35198 enter.append('button')
35199 .attr('class', 'list-item-gpx-browse')
35200 .call(bootstrap.tooltip()
35201 .title(t('gpx.browse'))
35202 .placement('left'))
35203 .on('click', function() {
35204 d3.select(document.createElement('input'))
35205 .attr('type', 'file')
35206 .on('change', function() {
35207 gpx.files(d3.event.target.files);
35211 .call(iD.svg.Icon('#icon-geolocate'));
35213 var labelGpx = enter.append('label')
35214 .call(bootstrap.tooltip()
35215 .title(t('gpx.drag_drop'))
35216 .placement('top'));
35218 labelGpx.append('input')
35219 .attr('type', 'checkbox')
35220 .on('change', clickGpx);
35222 labelGpx.append('span')
35223 .text(t('gpx.local_layer'));
35227 .classed('active', showsGpx)
35228 .selectAll('input')
35229 .property('disabled', !hasGpx)
35230 .property('checked', showsGpx);
35233 gpxLayerItem.exit()
35238 function drawList(selection, data, type, name, change, active) {
35239 var items = selection.selectAll('li')
35243 var enter = items.enter()
35245 .attr('class', 'layer')
35246 .call(bootstrap.tooltip()
35248 .title(function(d) {
35249 var tip = t(name + '.' + d + '.tooltip'),
35250 key = (d === 'wireframe' ? 'W' : null);
35252 if (name === 'feature' && autoHiddenFeature(d)) {
35253 tip += '<div>' + t('map_data.autohidden') + '</div>';
35255 return iD.ui.tooltipHtml(tip, key);
35260 var label = enter.append('label');
35262 label.append('input')
35263 .attr('type', type)
35264 .attr('name', name)
35265 .on('change', change);
35267 label.append('span')
35268 .text(function(d) { return t(name + '.' + d + '.description'); });
35272 .classed('active', active)
35273 .selectAll('input')
35274 .property('checked', active)
35275 .property('indeterminate', function(d) {
35276 return (name === 'feature' && autoHiddenFeature(d));
35285 function update() {
35286 dataLayerContainer.call(drawMapillaryItems);
35287 dataLayerContainer.call(drawGpxItem);
35289 fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
35291 featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
35294 function hidePanel() {
35298 function togglePanel() {
35299 if (d3.event) d3.event.preventDefault();
35300 tooltip.hide(button);
35301 setVisible(!button.classed('active'));
35304 function toggleWireframe() {
35306 d3.event.preventDefault();
35307 d3.event.stopPropagation();
35309 setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
35310 context.map().pan([0,0]); // trigger a redraw
35313 function setVisible(show) {
35314 if (show !== shown) {
35315 button.classed('active', show);
35320 selection.on('mousedown.map_data-inside', function() {
35321 return d3.event.stopPropagation();
35323 content.style('display', 'block')
35324 .style('right', '-300px')
35327 .style('right', '0px');
35329 content.style('display', 'block')
35330 .style('right', '0px')
35333 .style('right', '-300px')
35334 .each('end', function() {
35335 d3.select(this).style('display', 'none');
35337 selection.on('mousedown.map_data-inside', null);
35343 var content = selection.append('div')
35344 .attr('class', 'fillL map-overlay col3 content hide'),
35345 tooltip = bootstrap.tooltip()
35348 .title(iD.ui.tooltipHtml(t('map_data.description'), key)),
35349 button = selection.append('button')
35350 .attr('tabindex', -1)
35351 .on('click', togglePanel)
35352 .call(iD.svg.Icon('#icon-data', 'light'))
35356 content.append('h4')
35357 .text(t('map_data.title'));
35361 content.append('a')
35362 .text(t('map_data.data_layers'))
35364 .classed('hide-toggle', true)
35365 .classed('expanded', true)
35366 .on('click', function() {
35367 var exp = d3.select(this).classed('expanded');
35368 dataLayerContainer.style('display', exp ? 'none' : 'block');
35369 d3.select(this).classed('expanded', !exp);
35370 d3.event.preventDefault();
35373 var dataLayerContainer = content.append('div')
35374 .attr('class', 'data-data-layers')
35375 .style('display', 'block');
35379 content.append('a')
35380 .text(t('map_data.fill_area'))
35382 .classed('hide-toggle', true)
35383 .classed('expanded', false)
35384 .on('click', function() {
35385 var exp = d3.select(this).classed('expanded');
35386 fillContainer.style('display', exp ? 'none' : 'block');
35387 d3.select(this).classed('expanded', !exp);
35388 d3.event.preventDefault();
35391 var fillContainer = content.append('div')
35392 .attr('class', 'data-area-fills')
35393 .style('display', 'none');
35395 var fillList = fillContainer.append('ul')
35396 .attr('class', 'layer-list layer-fill-list');
35400 content.append('a')
35401 .text(t('map_data.map_features'))
35403 .classed('hide-toggle', true)
35404 .classed('expanded', false)
35405 .on('click', function() {
35406 var exp = d3.select(this).classed('expanded');
35407 featureContainer.style('display', exp ? 'none' : 'block');
35408 d3.select(this).classed('expanded', !exp);
35409 d3.event.preventDefault();
35412 var featureContainer = content.append('div')
35413 .attr('class', 'data-feature-filters')
35414 .style('display', 'none');
35416 var featureList = featureContainer.append('ul')
35417 .attr('class', 'layer-list layer-feature-list');
35421 .on('change.map_data-update', update);
35423 setFill(fillDefault);
35425 var keybinding = d3.keybinding('features')
35426 .on(key, togglePanel)
35427 .on('W', toggleWireframe)
35428 .on('B', hidePanel)
35429 .on('H', hidePanel);
35431 d3.select(document)
35434 context.surface().on('mousedown.map_data-outside', hidePanel);
35435 context.container().on('mousedown.map_data-outside', hidePanel);
35440 iD.ui.MapInMap = function(context) {
35443 function map_in_map(selection) {
35444 var backgroundLayer = iD.TileLayer(),
35445 overlayLayers = {},
35446 projection = iD.geo.RawMercator(),
35447 gpxLayer = iD.svg.Gpx(projection, context).showLabels(false),
35448 zoom = d3.behavior.zoom()
35449 .scaleExtent([ztok(0.5), ztok(24)])
35450 .on('zoom', zoomPan),
35451 transformed = false,
35454 zDiff = 6, // by default, minimap renders at (main zoom - 6)
35455 tStart, tLast, tCurr, kLast, kCurr, tiles, svg, timeoutId;
35457 function ztok(z) { return 256 * Math.pow(2, z); }
35458 function ktoz(k) { return Math.log(k) / Math.LN2 - 8; }
35461 function startMouse() {
35462 context.surface().on('mouseup.map-in-map-outside', endMouse);
35463 context.container().on('mouseup.map-in-map-outside', endMouse);
35465 tStart = tLast = tCurr = projection.translate();
35470 function zoomPan() {
35471 var e = d3.event.sourceEvent,
35472 t = d3.event.translate,
35473 k = d3.event.scale,
35474 zMain = ktoz(context.projection.scale() * 2 * Math.PI),
35477 // restrict minimap zoom to < (main zoom - 3)
35478 if (zMini > zMain - 3) {
35480 zoom.scale(kCurr).translate(tCurr); // restore last good values
35486 zDiff = zMain - zMini;
35488 var scale = kCurr / kLast,
35489 tX = (tCurr[0] / scale - tLast[0]) * scale,
35490 tY = (tCurr[1] / scale - tLast[1]) * scale;
35492 iD.util.setTransform(tiles, tX, tY, scale);
35493 iD.util.setTransform(svg, 0, 0, scale);
35494 transformed = true;
35498 e.preventDefault();
35499 e.stopPropagation();
35503 function endMouse() {
35504 context.surface().on('mouseup.map-in-map-outside', null);
35505 context.container().on('mouseup.map-in-map-outside', null);
35507 updateProjection();
35510 if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) {
35511 var dMini = wrap.dimensions(),
35512 cMini = [ dMini[0] / 2, dMini[1] / 2 ];
35514 context.map().center(projection.invert(cMini));
35519 function updateProjection() {
35520 var loc = context.map().center(),
35521 dMini = wrap.dimensions(),
35522 cMini = [ dMini[0] / 2, dMini[1] / 2 ],
35523 tMain = context.projection.translate(),
35524 kMain = context.projection.scale(),
35525 zMain = ktoz(kMain * 2 * Math.PI),
35526 zMini = Math.max(zMain - zDiff, 0.5),
35527 kMini = ztok(zMini);
35531 .scale(kMini / (2 * Math.PI));
35533 var s = projection(loc),
35534 mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0],
35536 cMini[0] - s[0] + tMain[0] + mouse[0],
35537 cMini[1] - s[1] + tMain[1] + mouse[1]
35542 .clipExtent([[0, 0], dMini]);
35549 tLast = tCurr = tMini;
35550 kLast = kCurr = kMini;
35553 iD.util.setTransform(tiles, 0, 0);
35554 iD.util.setTransform(svg, 0, 0);
35555 transformed = false;
35560 function redraw() {
35561 if (hidden) return;
35563 updateProjection();
35565 var dMini = wrap.dimensions(),
35566 zMini = ktoz(projection.scale() * 2 * Math.PI);
35568 // setup tile container
35570 .selectAll('.map-in-map-tiles')
35576 .attr('class', 'map-in-map-tiles');
35578 // redraw background
35580 .source(context.background().baseLayerSource())
35581 .projection(projection)
35582 .dimensions(dMini);
35584 var background = tiles
35585 .selectAll('.map-in-map-background')
35590 .attr('class', 'map-in-map-background');
35593 .call(backgroundLayer);
35597 var overlaySources = context.background().overlayLayerSources();
35598 var activeOverlayLayers = [];
35599 for (var i = 0; i < overlaySources.length; i++) {
35600 if (overlaySources[i].validZoom(zMini)) {
35601 if (!overlayLayers[i]) overlayLayers[i] = iD.TileLayer();
35602 activeOverlayLayers.push(overlayLayers[i]
35603 .source(overlaySources[i])
35604 .projection(projection)
35605 .dimensions(dMini));
35609 var overlay = tiles
35610 .selectAll('.map-in-map-overlay')
35615 .attr('class', 'map-in-map-overlay');
35617 var overlays = overlay
35619 .data(activeOverlayLayers, function(d) { return d.source().name(); });
35621 overlays.enter().append('div');
35622 overlays.each(function(layer) {
35623 d3.select(this).call(layer);
35631 .selectAll('.map-in-map-gpx')
35632 .data(gpxLayer.enabled() ? [0] : []);
35636 .attr('class', 'map-in-map-gpx');
35641 gpx.call(gpxLayer);
35644 // redraw bounding box
35646 var getPath = d3.geo.path().projection(projection),
35647 bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
35649 svg = wrap.selectAll('.map-in-map-svg')
35654 .attr('class', 'map-in-map-svg');
35656 var path = svg.selectAll('.map-in-map-bbox')
35661 .attr('class', 'map-in-map-bbox');
35664 .attr('d', getPath)
35665 .classed('thick', function(d) { return getPath.area(d) < 30; });
35670 function queueRedraw() {
35671 clearTimeout(timeoutId);
35672 timeoutId = setTimeout(function() { redraw(); }, 300);
35676 function toggle() {
35677 if (d3.event) d3.event.preventDefault();
35681 var label = d3.select('.minimap-toggle');
35682 label.classed('active', !hidden)
35683 .select('input').property('checked', !hidden);
35687 .style('display', 'block')
35688 .style('opacity', 1)
35691 .style('opacity', 0)
35692 .each('end', function() {
35693 d3.select(this).style('display', 'none');
35697 .style('display', 'block')
35698 .style('opacity', 0)
35701 .style('opacity', 1);
35707 iD.ui.MapInMap.toggle = toggle;
35709 var wrap = selection.selectAll('.map-in-map')
35714 .attr('class', 'map-in-map')
35715 .style('display', (hidden ? 'none' : 'block'))
35716 .on('mousedown.map-in-map', startMouse)
35717 .on('mouseup.map-in-map', endMouse)
35719 .on('dblclick.zoom', null);
35722 .on('drawn.map-in-map', function(drawn) {
35723 if (drawn.full === true) redraw();
35728 var keybinding = d3.keybinding('map-in-map')
35731 d3.select(document)
35737 iD.ui.modal = function(selection, blocking) {
35738 var keybinding = d3.keybinding('modal');
35739 var previous = selection.select('div.modal');
35740 var animate = previous.empty();
35742 previous.transition()
35744 .style('opacity', 0)
35747 var shaded = selection
35749 .attr('class', 'shaded')
35750 .style('opacity', 0);
35752 shaded.close = function() {
35756 .style('opacity',0)
35761 .style('top','0px');
35767 var modal = shaded.append('div')
35768 .attr('class', 'modal fillL col6');
35771 shaded.on('click.remove-modal', function() {
35772 if (d3.event.target === this) {
35777 modal.append('button')
35778 .attr('class', 'close')
35779 .on('click', shaded.close)
35780 .call(iD.svg.Icon('#icon-close'));
35783 .on('⌫', shaded.close)
35784 .on('⎋', shaded.close);
35786 d3.select(document).call(keybinding);
35789 modal.append('div')
35790 .attr('class', 'content');
35793 shaded.transition().style('opacity', 1);
35795 shaded.style('opacity', 1);
35800 iD.ui.Modes = function(context) {
35802 iD.modes.AddPoint(context),
35803 iD.modes.AddLine(context),
35804 iD.modes.AddArea(context)];
35806 function editable() {
35807 return context.editable() && context.mode().id !== 'save';
35810 return function(selection) {
35811 var buttons = selection.selectAll('button.add-button')
35814 buttons.enter().append('button')
35815 .attr('tabindex', -1)
35816 .attr('class', function(mode) { return mode.id + ' add-button col4'; })
35817 .on('click.mode-buttons', function(mode) {
35818 if (mode.id === context.mode().id) {
35819 context.enter(iD.modes.Browse(context));
35821 context.enter(mode);
35824 .call(bootstrap.tooltip()
35825 .placement('bottom')
35827 .title(function(mode) {
35828 return iD.ui.tooltipHtml(mode.description, mode.key);
35832 .on('move.modes', _.debounce(update, 500));
35835 .on('enter.modes', update);
35837 buttons.each(function(d) {
35839 .call(iD.svg.Icon('#icon-' + d.button, 'pre-text'));
35842 buttons.append('span')
35843 .attr('class', 'label')
35844 .text(function(mode) { return mode.title; });
35846 context.on('enter.editor', function(entered) {
35847 buttons.classed('active', function(mode) { return entered.button === mode.button; });
35848 context.container()
35849 .classed('mode-' + entered.id, true);
35852 context.on('exit.editor', function(exited) {
35853 context.container()
35854 .classed('mode-' + exited.id, false);
35857 var keybinding = d3.keybinding('mode-buttons');
35859 modes.forEach(function(m) {
35860 keybinding.on(m.key, function() { if (editable()) context.enter(m); });
35863 d3.select(document)
35866 function update() {
35867 buttons.property('disabled', !editable());
35871 iD.ui.Notice = function(context) {
35872 return function(selection) {
35873 var div = selection.append('div')
35874 .attr('class', 'notice');
35876 var button = div.append('button')
35877 .attr('class', 'zoom-to notice')
35878 .on('click', function() { context.map().zoom(context.minEditableZoom()); });
35881 .call(iD.svg.Icon('#icon-plus', 'pre-text'))
35883 .attr('class', 'label')
35884 .text(t('zoom_in_edit'));
35886 function disableTooHigh() {
35887 div.style('display', context.editable() ? 'none' : 'block');
35891 .on('move.notice', _.debounce(disableTooHigh, 500));
35896 iD.ui.PresetIcon = function() {
35897 var preset, geometry;
35899 function presetIcon(selection) {
35900 selection.each(render);
35903 function render() {
35904 var selection = d3.select(this),
35905 p = preset.apply(this, arguments),
35906 geom = geometry.apply(this, arguments),
35907 icon = p.icon || (geom === 'line' ? 'other-line' : 'marker-stroked'),
35908 maki = iD.data.featureIcons.hasOwnProperty(icon + '-24');
35910 if (icon === 'dentist') maki = true; // workaround for dentist icon missing in `maki-sprite.json`
35912 function tag_classes(p) {
35914 for (var i in p.tags) {
35916 if (p.tags[i] !== '*') {
35917 s += ' tag-' + i + '-' + p.tags[i];
35923 var $fill = selection.selectAll('.preset-icon-fill')
35926 $fill.enter().append('div');
35928 $fill.attr('class', function() {
35929 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
35932 var $frame = selection.selectAll('.preset-icon-frame')
35937 .call(iD.svg.Icon('#preset-icon-frame'));
35939 $frame.attr('class', function() {
35940 return 'preset-icon-frame ' + (geom === 'area' ? '' : 'hide');
35944 var $icon = selection.selectAll('.preset-icon')
35949 .attr('class', 'preset-icon')
35950 .call(iD.svg.Icon(''));
35953 .attr('class', 'preset-icon preset-icon-' + (maki ? '32' : (geom === 'area' ? '44' : '60')));
35955 $icon.selectAll('svg')
35956 .attr('class', function() {
35957 return 'icon ' + icon + tag_classes(p);
35960 $icon.selectAll('use') // workaround: maki parking-24 broken?
35961 .attr('href', '#' + icon + (maki ? ( icon === 'parking' ? '-18' : '-24') : ''));
35964 presetIcon.preset = function(_) {
35965 if (!arguments.length) return preset;
35966 preset = d3.functor(_);
35970 presetIcon.geometry = function(_) {
35971 if (!arguments.length) return geometry;
35972 geometry = d3.functor(_);
35978 iD.ui.preset = function(context) {
35979 var event = d3.dispatch('change'),
35986 function UIField(field, entity, show) {
35987 field = _.clone(field);
35989 field.input = iD.ui.preset[field.type](field, context)
35990 .on('change', event.change);
35992 if (field.input.entity) field.input.entity(entity);
35994 field.keys = field.keys || [field.key];
35998 field.shown = function() {
35999 return field.id === 'name' || field.show || _.any(field.keys, function(key) { return !!tags[key]; });
36002 field.modified = function() {
36003 var original = context.graph().base().entities[entity.id];
36004 return _.any(field.keys, function(key) {
36005 return original ? tags[key] !== original.tags[key] : tags[key];
36009 field.revert = function() {
36010 var original = context.graph().base().entities[entity.id],
36012 field.keys.forEach(function(key) {
36013 t[key] = original ? original.tags[key] : undefined;
36018 field.present = function() {
36019 return _.any(field.keys, function(key) {
36024 field.remove = function() {
36026 field.keys.forEach(function(key) {
36027 t[key] = undefined;
36035 function fieldKey(field) {
36039 function presets(selection) {
36040 selection.call(iD.ui.Disclosure()
36041 .title(t('inspector.all_fields'))
36042 .expanded(context.storage('preset_fields.expanded') !== 'false')
36043 .on('toggled', toggled)
36044 .content(content));
36046 function toggled(expanded) {
36047 context.storage('preset_fields.expanded', expanded);
36051 function content(selection) {
36053 var entity = context.entity(id),
36054 geometry = context.geometry(id);
36056 fields = [UIField(context.presets().field('name'), entity)];
36058 preset.fields.forEach(function(field) {
36059 if (field.matchGeometry(geometry)) {
36060 fields.push(UIField(field, entity, true));
36064 if (entity.isHighwayIntersection(context.graph())) {
36065 fields.push(UIField(context.presets().field('restrictions'), entity, true));
36068 context.presets().universal().forEach(function(field) {
36069 if (preset.fields.indexOf(field) < 0) {
36070 fields.push(UIField(field, entity));
36075 var shown = fields.filter(function(field) { return field.shown(); }),
36076 notShown = fields.filter(function(field) { return !field.shown(); });
36078 var $form = selection.selectAll('.preset-form')
36081 $form.enter().append('div')
36082 .attr('class', 'preset-form inspector-inner fillL3');
36084 var $fields = $form.selectAll('.form-field')
36085 .data(shown, fieldKey);
36089 var $enter = $fields.enter()
36091 .attr('class', function(field) {
36092 return 'form-field form-field-' + field.id;
36095 var $label = $enter.append('label')
36096 .attr('class', 'form-label')
36097 .attr('for', function(field) { return 'preset-input-' + field.id; })
36098 .text(function(field) { return field.label(); });
36100 var wrap = $label.append('div')
36101 .attr('class', 'form-label-button-wrap');
36103 wrap.append('button')
36104 .attr('class', 'remove-icon')
36105 .call(iD.svg.Icon('#operation-delete'));
36107 wrap.append('button')
36108 .attr('class', 'modified-icon')
36109 .attr('tabindex', -1)
36110 .call(iD.svg.Icon('#icon-undo'));
36114 $fields.select('.form-label-button-wrap .remove-icon')
36115 .on('click', remove);
36117 $fields.select('.modified-icon')
36118 .on('click', revert);
36122 .classed('modified', function(field) {
36123 return field.modified();
36125 .classed('present', function(field) {
36126 return field.present();
36128 .each(function(field) {
36129 var reference = iD.ui.TagReference(field.reference || {key: field.key}, context);
36131 if (state === 'hover') {
36132 reference.showing(false);
36137 .selectAll('input')
36138 .on('keydown', function() {
36139 if (d3.event.keyCode === 13) { // enter
36140 context.enter(iD.modes.Browse(context));
36143 .call(reference.body)
36144 .select('.form-label-button-wrap')
36145 .call(reference.button);
36147 field.input.tags(tags);
36153 notShown = notShown.map(function(field) {
36155 title: field.label(),
36156 value: field.label(),
36161 var $more = selection.selectAll('.more-fields')
36162 .data((notShown.length > 0) ? [0] : []);
36164 $more.enter().append('div')
36165 .attr('class', 'more-fields')
36167 .text(t('inspector.add_fields'));
36169 var $input = $more.selectAll('.value')
36172 $input.enter().append('input')
36173 .attr('class', 'value')
36174 .attr('type', 'text');
36177 .attr('placeholder', function() {
36178 var placeholder = [];
36179 for (var field in notShown) {
36180 placeholder.push(notShown[field].title);
36182 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
36184 .call(d3.combobox().data(notShown)
36186 .on('accept', show));
36194 function show(field) {
36195 field = field.field;
36197 content(selection);
36198 field.input.focus();
36201 function revert(field) {
36202 d3.event.stopPropagation();
36203 d3.event.preventDefault();
36204 event.change(field.revert());
36207 function remove(field) {
36208 d3.event.stopPropagation();
36209 d3.event.preventDefault();
36210 event.change(field.remove());
36214 presets.preset = function(_) {
36215 if (!arguments.length) return preset;
36216 if (preset && preset.id === _.id) return presets;
36222 presets.state = function(_) {
36223 if (!arguments.length) return state;
36228 presets.tags = function(_) {
36229 if (!arguments.length) return tags;
36231 // Don't reset fields here.
36235 presets.entityID = function(_) {
36236 if (!arguments.length) return id;
36237 if (id === _) return presets;
36243 return d3.rebind(presets, event, 'on');
36245 iD.ui.PresetList = function(context) {
36246 var event = d3.dispatch('choose'),
36251 function presetList(selection) {
36252 var geometry = context.geometry(id),
36253 presets = context.presets().matchGeometry(geometry);
36255 selection.html('');
36257 var messagewrap = selection.append('div')
36258 .attr('class', 'header fillL cf');
36260 var message = messagewrap.append('h3')
36261 .text(t('inspector.choose'));
36263 if (context.entity(id).isUsed(context.graph())) {
36264 messagewrap.append('button')
36265 .attr('class', 'preset-choose')
36266 .on('click', function() { event.choose(currentPreset); })
36270 messagewrap.append('button')
36271 .attr('class', 'close')
36272 .on('click', function() {
36273 context.enter(iD.modes.Browse(context));
36275 .call(iD.svg.Icon('#icon-close'));
36278 function keydown() {
36279 // hack to let delete shortcut work when search is autofocused
36280 if (search.property('value').length === 0 &&
36281 (d3.event.keyCode === d3.keybinding.keyCodes['⌫'] ||
36282 d3.event.keyCode === d3.keybinding.keyCodes['⌦'])) {
36283 d3.event.preventDefault();
36284 d3.event.stopPropagation();
36285 iD.operations.Delete([id], context)();
36286 } else if (search.property('value').length === 0 &&
36287 (d3.event.ctrlKey || d3.event.metaKey) &&
36288 d3.event.keyCode === d3.keybinding.keyCodes.z) {
36289 d3.event.preventDefault();
36290 d3.event.stopPropagation();
36292 } else if (!d3.event.ctrlKey && !d3.event.metaKey) {
36293 d3.select(this).on('keydown', null);
36297 function keypress() {
36299 var value = search.property('value');
36300 if (d3.event.keyCode === 13 && value.length) {
36301 list.selectAll('.preset-list-item:first-child').datum().choose();
36305 function inputevent() {
36306 var value = search.property('value');
36307 list.classed('filtered', value.length);
36308 if (value.length) {
36309 var results = presets.search(value, geometry);
36310 message.text(t('inspector.results', {
36311 n: results.collection.length,
36314 list.call(drawList, results);
36316 list.call(drawList, context.presets().defaults(geometry, 36));
36317 message.text(t('inspector.choose'));
36321 var searchWrap = selection.append('div')
36322 .attr('class', 'search-header');
36324 var search = searchWrap.append('input')
36325 .attr('class', 'preset-search-input')
36326 .attr('placeholder', t('inspector.search'))
36327 .attr('type', 'search')
36328 .on('keydown', keydown)
36329 .on('keypress', keypress)
36330 .on('input', inputevent);
36333 .call(iD.svg.Icon('#icon-search', 'pre-text'));
36336 search.node().focus();
36339 var listWrap = selection.append('div')
36340 .attr('class', 'inspector-body');
36342 var list = listWrap.append('div')
36343 .attr('class', 'preset-list fillL cf')
36344 .call(drawList, context.presets().defaults(geometry, 36));
36347 function drawList(list, presets) {
36348 var collection = presets.collection.map(function(preset) {
36349 return preset.members ? CategoryItem(preset) : PresetItem(preset);
36352 var items = list.selectAll('.preset-list-item')
36353 .data(collection, function(d) { return d.preset.id; });
36355 items.enter().append('div')
36356 .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
36357 .classed('current', function(item) { return item.preset === currentPreset; })
36358 .each(function(item) {
36359 d3.select(this).call(item);
36361 .style('opacity', 0)
36363 .style('opacity', 1);
36371 function CategoryItem(preset) {
36372 var box, sublist, shown = false;
36374 function item(selection) {
36375 var wrap = selection.append('div')
36376 .attr('class', 'preset-list-button-wrap category col12');
36378 wrap.append('button')
36379 .attr('class', 'preset-list-button')
36380 .classed('expanded', false)
36381 .call(iD.ui.PresetIcon()
36382 .geometry(context.geometry(id))
36384 .on('click', function() {
36385 var isExpanded = d3.select(this).classed('expanded');
36386 var triangle = isExpanded ? '▶ ' : '▼ ';
36387 d3.select(this).classed('expanded', !isExpanded);
36388 d3.select(this).selectAll('.label').text(triangle + preset.name());
36392 .attr('class', 'label')
36394 return '▶ ' + preset.name();
36397 box = selection.append('div')
36398 .attr('class', 'subgrid col12')
36399 .style('max-height', '0px')
36400 .style('opacity', 0);
36403 .attr('class', 'arrow');
36405 sublist = box.append('div')
36406 .attr('class', 'preset-list fillL3 cf fl');
36409 item.choose = function() {
36410 if (!box || !sublist) return;
36416 .style('opacity', '0')
36417 .style('max-height', '0px')
36418 .style('padding-bottom', '0px');
36421 sublist.call(drawList, preset.members);
36424 .style('opacity', '1')
36425 .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
36426 .style('padding-bottom', '20px');
36430 item.preset = preset;
36435 function PresetItem(preset) {
36436 function item(selection) {
36437 var wrap = selection.append('div')
36438 .attr('class', 'preset-list-button-wrap col12');
36440 wrap.append('button')
36441 .attr('class', 'preset-list-button')
36442 .call(iD.ui.PresetIcon()
36443 .geometry(context.geometry(id))
36445 .on('click', item.choose)
36447 .attr('class', 'label')
36448 .text(preset.name());
36450 wrap.call(item.reference.button);
36451 selection.call(item.reference.body);
36454 item.choose = function() {
36455 context.presets().choose(preset);
36458 iD.actions.ChangePreset(id, currentPreset, preset),
36459 t('operations.change_tags.annotation'));
36461 event.choose(preset);
36464 item.help = function() {
36465 d3.event.stopPropagation();
36466 item.reference.toggle();
36469 item.preset = preset;
36470 item.reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context);
36475 presetList.autofocus = function(_) {
36476 if (!arguments.length) return autofocus;
36481 presetList.entityID = function(_) {
36482 if (!arguments.length) return id;
36484 presetList.preset(context.presets().match(context.entity(id), context.graph()));
36488 presetList.preset = function(_) {
36489 if (!arguments.length) return currentPreset;
36494 return d3.rebind(presetList, event, 'on');
36496 iD.ui.RadialMenu = function(context, operations) {
36501 var radialMenu = function(selection) {
36502 if (!operations.length)
36505 selection.node().parentNode.focus();
36507 function click(operation) {
36508 d3.event.stopPropagation();
36509 if (operation.disabled())
36512 radialMenu.close();
36515 menu = selection.append('g')
36516 .attr('class', 'radial-menu')
36517 .attr('transform', 'translate(' + center + ')')
36518 .attr('opacity', 0);
36521 .attr('opacity', 1);
36526 a1 = a0 + (operations.length - 1) * a;
36528 menu.append('path')
36529 .attr('class', 'radial-menu-background')
36530 .attr('d', 'M' + r * Math.sin(a0) + ',' +
36532 ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
36533 (r * Math.sin(a1) + 1e-3) + ',' +
36534 (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
36535 .attr('stroke-width', 50)
36536 .attr('stroke-linecap', 'round');
36538 var button = menu.selectAll()
36542 .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
36543 .classed('disabled', function(d) { return d.disabled(); })
36544 .attr('transform', function(d, i) {
36545 return 'translate(' + iD.geo.roundCoords([
36546 r * Math.sin(a0 + i * a),
36547 r * Math.cos(a0 + i * a)]).join(',') + ')';
36550 button.append('circle')
36552 .on('click', click)
36553 .on('mousedown', mousedown)
36554 .on('mouseover', mouseover)
36555 .on('mouseout', mouseout);
36557 button.append('use')
36558 .attr('transform', 'translate(-10,-10)')
36559 .attr('width', '20')
36560 .attr('height', '20')
36561 .attr('xlink:href', function(d) { return '#operation-' + d.id; });
36563 tooltip = d3.select(document.body)
36565 .attr('class', 'tooltip-inner radial-menu-tooltip');
36567 function mousedown() {
36568 d3.event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
36571 function mouseover(d, i) {
36572 var rect = context.surfaceRect(),
36573 angle = a0 + i * a,
36574 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
36575 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
36576 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
36577 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
36580 .style('top', null)
36581 .style('left', null)
36582 .style('bottom', null)
36583 .style('right', null)
36584 .style('display', 'block')
36585 .html(iD.ui.tooltipHtml(d.tooltip(), d.keys[0]));
36589 .style('right', right)
36590 .style('top', top);
36591 } else if (i >= 4) {
36593 .style('left', left)
36594 .style('bottom', bottom);
36597 .style('left', left)
36598 .style('top', top);
36602 function mouseout() {
36603 tooltip.style('display', 'none');
36607 radialMenu.close = function() {
36610 .style('pointer-events', 'none')
36612 .attr('opacity', 0)
36621 radialMenu.center = function(_) {
36622 if (!arguments.length) return center;
36629 iD.ui.RawMemberEditor = function(context) {
36632 function selectMember(d) {
36633 d3.event.preventDefault();
36634 context.enter(iD.modes.Select(context, [d.id]));
36637 function changeRole(d) {
36638 var role = d3.select(this).property('value');
36639 var member = {id: d.id, type: d.type, role: role};
36641 iD.actions.ChangeMember(d.relation.id, member, d.index),
36642 t('operations.change_role.annotation'));
36645 function deleteMember(d) {
36647 iD.actions.DeleteMember(d.relation.id, d.index),
36648 t('operations.delete_member.annotation'));
36650 if (!context.hasEntity(d.relation.id)) {
36651 context.enter(iD.modes.Browse(context));
36655 function rawMemberEditor(selection) {
36656 var entity = context.entity(id),
36659 entity.members.forEach(function(member, index) {
36666 member: context.hasEntity(member.id)
36670 selection.call(iD.ui.Disclosure()
36671 .title(t('inspector.all_members') + ' (' + memberships.length + ')')
36673 .on('toggled', toggled)
36674 .content(content));
36676 function toggled(expanded) {
36678 selection.node().parentNode.scrollTop += 200;
36682 function content($wrap) {
36683 var $list = $wrap.selectAll('.member-list')
36686 $list.enter().append('ul')
36687 .attr('class', 'member-list');
36689 var $items = $list.selectAll('li')
36690 .data(memberships, function(d) {
36691 return iD.Entity.key(d.relation) + ',' + d.index + ',' +
36692 (d.member ? iD.Entity.key(d.member) : 'incomplete');
36695 var $enter = $items.enter().append('li')
36696 .attr('class', 'member-row form-field')
36697 .classed('member-incomplete', function(d) { return !d.member; });
36699 $enter.each(function(d) {
36701 var $label = d3.select(this).append('label')
36702 .attr('class', 'form-label')
36705 .on('click', selectMember);
36707 $label.append('span')
36708 .attr('class', 'member-entity-type')
36709 .text(function(d) { return context.presets().match(d.member, context.graph()).name(); });
36711 $label.append('span')
36712 .attr('class', 'member-entity-name')
36713 .text(function(d) { return iD.util.displayName(d.member); });
36716 d3.select(this).append('label')
36717 .attr('class', 'form-label')
36718 .text(t('inspector.incomplete'));
36722 $enter.append('input')
36723 .attr('class', 'member-role')
36724 .property('type', 'text')
36725 .attr('maxlength', 255)
36726 .attr('placeholder', t('inspector.role'))
36727 .property('value', function(d) { return d.role; })
36728 .on('change', changeRole);
36730 $enter.append('button')
36731 .attr('tabindex', -1)
36732 .attr('class', 'remove button-input-action member-delete minor')
36733 .on('click', deleteMember)
36734 .call(iD.svg.Icon('#operation-delete'));
36741 rawMemberEditor.entityID = function(_) {
36742 if (!arguments.length) return id;
36744 return rawMemberEditor;
36747 return rawMemberEditor;
36749 iD.ui.RawMembershipEditor = function(context) {
36752 function selectRelation(d) {
36753 d3.event.preventDefault();
36754 context.enter(iD.modes.Select(context, [d.relation.id]));
36757 function changeRole(d) {
36758 var role = d3.select(this).property('value');
36760 iD.actions.ChangeMember(d.relation.id, _.extend({}, d.member, {role: role}), d.index),
36761 t('operations.change_role.annotation'));
36764 function addMembership(d, role) {
36769 iD.actions.AddMember(d.relation.id, {id: id, type: context.entity(id).type, role: role}),
36770 t('operations.add_member.annotation'));
36773 var relation = iD.Relation();
36776 iD.actions.AddEntity(relation),
36777 iD.actions.AddMember(relation.id, {id: id, type: context.entity(id).type, role: role}),
36778 t('operations.add.annotation.relation'));
36780 context.enter(iD.modes.Select(context, [relation.id]));
36784 function deleteMembership(d) {
36786 iD.actions.DeleteMember(d.relation.id, d.index),
36787 t('operations.delete_member.annotation'));
36790 function relations(q) {
36791 var newRelation = {
36793 value: t('inspector.new_relation')
36796 graph = context.graph();
36798 context.intersects(context.extent()).forEach(function(entity) {
36799 if (entity.type !== 'relation' || entity.id === id)
36802 var presetName = context.presets().match(entity, graph).name(),
36803 entityName = iD.util.displayName(entity) || '';
36805 var value = presetName + ' ' + entityName;
36806 if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
36815 result.sort(function(a, b) {
36816 return iD.Relation.creationOrder(a.relation, b.relation);
36819 // Dedupe identical names by appending relation id - see #2891
36820 var dupeGroups = _(result)
36822 .filter(function(v) { return v.length > 1; })
36825 dupeGroups.forEach(function(group) {
36826 group.forEach(function(obj) {
36827 obj.value += ' ' + obj.relation.id;
36831 result.unshift(newRelation);
36836 function rawMembershipEditor(selection) {
36837 var entity = context.entity(id),
36840 context.graph().parentRelations(entity).forEach(function(relation) {
36841 relation.members.forEach(function(member, index) {
36842 if (member.id === entity.id) {
36843 memberships.push({relation: relation, member: member, index: index});
36848 selection.call(iD.ui.Disclosure()
36849 .title(t('inspector.all_relations') + ' (' + memberships.length + ')')
36851 .on('toggled', toggled)
36852 .content(content));
36854 function toggled(expanded) {
36856 selection.node().parentNode.scrollTop += 200;
36860 function content($wrap) {
36861 var $list = $wrap.selectAll('.member-list')
36864 $list.enter().append('ul')
36865 .attr('class', 'member-list');
36867 var $items = $list.selectAll('li.member-row-normal')
36868 .data(memberships, function(d) { return iD.Entity.key(d.relation) + ',' + d.index; });
36870 var $enter = $items.enter().append('li')
36871 .attr('class', 'member-row member-row-normal form-field');
36873 var $label = $enter.append('label')
36874 .attr('class', 'form-label')
36877 .on('click', selectRelation);
36879 $label.append('span')
36880 .attr('class', 'member-entity-type')
36881 .text(function(d) { return context.presets().match(d.relation, context.graph()).name(); });
36883 $label.append('span')
36884 .attr('class', 'member-entity-name')
36885 .text(function(d) { return iD.util.displayName(d.relation); });
36887 $enter.append('input')
36888 .attr('class', 'member-role')
36889 .property('type', 'text')
36890 .attr('maxlength', 255)
36891 .attr('placeholder', t('inspector.role'))
36892 .property('value', function(d) { return d.member.role; })
36893 .on('change', changeRole);
36895 $enter.append('button')
36896 .attr('tabindex', -1)
36897 .attr('class', 'remove button-input-action member-delete minor')
36898 .on('click', deleteMembership)
36899 .call(iD.svg.Icon('#operation-delete'));
36905 var $new = $list.selectAll('.member-row-new')
36908 $enter = $new.enter().append('li')
36909 .attr('class', 'member-row member-row-new form-field');
36911 $enter.append('input')
36912 .attr('type', 'text')
36913 .attr('class', 'member-entity-input')
36914 .call(d3.combobox()
36916 .fetcher(function(value, callback) {
36917 callback(relations(value));
36919 .on('accept', function(d) {
36920 addMembership(d, $new.select('.member-role').property('value'));
36923 $enter.append('input')
36924 .attr('class', 'member-role')
36925 .property('type', 'text')
36926 .attr('maxlength', 255)
36927 .attr('placeholder', t('inspector.role'))
36928 .on('change', changeRole);
36930 $enter.append('button')
36931 .attr('tabindex', -1)
36932 .attr('class', 'remove button-input-action member-delete minor')
36933 .on('click', deleteMembership)
36934 .call(iD.svg.Icon('#operation-delete'));
36937 $list.selectAll('.member-row-new')
36941 var $add = $wrap.selectAll('.add-relation')
36946 .attr('class', 'add-relation')
36947 .call(iD.svg.Icon('#icon-plus', 'light'));
36949 $wrap.selectAll('.add-relation')
36950 .on('click', function() {
36953 $list.selectAll('.member-entity-input').node().focus();
36958 rawMembershipEditor.entityID = function(_) {
36959 if (!arguments.length) return id;
36961 return rawMembershipEditor;
36964 return rawMembershipEditor;
36966 iD.ui.RawTagEditor = function(context) {
36967 var event = d3.dispatch('change'),
36974 function rawTagEditor(selection) {
36975 var count = Object.keys(tags).filter(function(d) { return d; }).length;
36977 selection.call(iD.ui.Disclosure()
36978 .title(t('inspector.all_tags') + ' (' + count + ')')
36979 .expanded(context.storage('raw_tag_editor.expanded') === 'true' || preset.isFallback())
36980 .on('toggled', toggled)
36981 .content(content));
36983 function toggled(expanded) {
36984 context.storage('raw_tag_editor.expanded', expanded);
36986 selection.node().parentNode.scrollTop += 200;
36991 function content($wrap) {
36992 var entries = d3.entries(tags);
36994 if (!entries.length || showBlank) {
36996 entries.push({key: '', value: ''});
36999 var $list = $wrap.selectAll('.tag-list')
37002 $list.enter().append('ul')
37003 .attr('class', 'tag-list');
37005 var $newTag = $wrap.selectAll('.add-tag')
37010 .attr('class', 'add-tag')
37011 .call(iD.svg.Icon('#icon-plus', 'light'));
37013 $newTag.on('click', addTag);
37015 var $items = $list.selectAll('li')
37016 .data(entries, function(d) { return d.key; });
37020 var $enter = $items.enter().append('li')
37021 .attr('class', 'tag-row cf');
37023 $enter.append('div')
37024 .attr('class', 'key-wrap')
37026 .property('type', 'text')
37027 .attr('class', 'key')
37028 .attr('maxlength', 255);
37030 $enter.append('div')
37031 .attr('class', 'input-wrap-position')
37033 .property('type', 'text')
37034 .attr('class', 'value')
37035 .attr('maxlength', 255);
37037 $enter.append('button')
37038 .attr('tabindex', -1)
37039 .attr('class', 'remove minor')
37040 .call(iD.svg.Icon('#operation-delete'));
37042 if (context.taginfo()) {
37043 $enter.each(bindTypeahead);
37050 $items.each(function(tag) {
37051 var isRelation = (context.entity(id).type === 'relation'),
37053 if (isRelation && tag.key === 'type')
37054 reference = iD.ui.TagReference({rtype: tag.value}, context);
37056 reference = iD.ui.TagReference({key: tag.key, value: tag.value}, context);
37058 if (state === 'hover') {
37059 reference.showing(false);
37063 .call(reference.button)
37064 .call(reference.body);
37067 $items.select('input.key')
37068 .attr('title', function(d) { return d.key; })
37069 .value(function(d) { return d.key; })
37070 .on('blur', keyChange)
37071 .on('change', keyChange);
37073 $items.select('input.value')
37074 .attr('title', function(d) { return d.value; })
37075 .value(function(d) { return d.value; })
37076 .on('blur', valueChange)
37077 .on('change', valueChange)
37078 .on('keydown.push-more', pushMore);
37080 $items.select('button.remove')
37081 .on('click', removeTag);
37087 function pushMore() {
37088 if (d3.event.keyCode === 9 && !d3.event.shiftKey &&
37089 $list.selectAll('li:last-child input.value').node() === this) {
37094 function bindTypeahead() {
37095 var row = d3.select(this),
37096 key = row.selectAll('input.key'),
37097 value = row.selectAll('input.value');
37099 function sort(value, data) {
37100 var sameletter = [],
37102 for (var i = 0; i < data.length; i++) {
37103 if (data[i].value.substring(0, value.length) === value) {
37104 sameletter.push(data[i]);
37106 other.push(data[i]);
37109 return sameletter.concat(other);
37112 key.call(d3.combobox()
37113 .fetcher(function(value, callback) {
37114 context.taginfo().keys({
37116 geometry: context.geometry(id),
37118 }, function(err, data) {
37119 if (!err) callback(sort(value, data));
37123 value.call(d3.combobox()
37124 .fetcher(function(value, callback) {
37125 context.taginfo().values({
37128 geometry: context.geometry(id),
37130 }, function(err, data) {
37131 if (!err) callback(sort(value, data));
37136 function unbind() {
37137 var row = d3.select(this);
37139 row.selectAll('input.key')
37140 .call(d3.combobox.off);
37142 row.selectAll('input.value')
37143 .call(d3.combobox.off);
37146 function keyChange(d) {
37148 kNew = this.value.trim(),
37151 if (kNew && kNew !== kOld) {
37152 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
37154 suffix = +(match[2] || 1);
37155 while (tags[kNew]) { // rename key if already in use
37156 kNew = base + '_' + suffix++;
37159 tag[kOld] = undefined;
37160 tag[kNew] = d.value;
37161 d.key = kNew; // Maintain DOM identity through the subsequent update.
37166 function valueChange(d) {
37168 tag[d.key] = this.value;
37172 function removeTag(d) {
37174 tag[d.key] = undefined;
37176 d3.select(this.parentNode).remove();
37179 function addTag() {
37180 // Wrapped in a setTimeout in case it's being called from a blur
37181 // handler. Without the setTimeout, the call to `content` would
37182 // wipe out the pending value change.
37183 setTimeout(function() {
37186 $list.selectAll('li:last-child input.key').node().focus();
37191 rawTagEditor.state = function(_) {
37192 if (!arguments.length) return state;
37194 return rawTagEditor;
37197 rawTagEditor.preset = function(_) {
37198 if (!arguments.length) return preset;
37200 return rawTagEditor;
37203 rawTagEditor.tags = function(_) {
37204 if (!arguments.length) return tags;
37206 return rawTagEditor;
37209 rawTagEditor.entityID = function(_) {
37210 if (!arguments.length) return id;
37212 return rawTagEditor;
37215 return d3.rebind(rawTagEditor, event, 'on');
37217 iD.ui.Restore = function(context) {
37218 return function(selection) {
37219 if (!context.history().lock() || !context.history().restorableChanges())
37222 var modal = iD.ui.modal(selection, true);
37224 modal.select('.modal')
37225 .attr('class', 'modal fillL col6');
37227 var introModal = modal.select('.content');
37229 introModal.attr('class','cf');
37231 introModal.append('div')
37232 .attr('class', 'modal-section')
37234 .text(t('restore.heading'));
37236 introModal.append('div')
37237 .attr('class','modal-section')
37239 .text(t('restore.description'));
37241 var buttonWrap = introModal.append('div')
37242 .attr('class', 'modal-actions cf');
37244 var restore = buttonWrap.append('button')
37245 .attr('class', 'restore col6')
37246 .text(t('restore.restore'))
37247 .on('click', function() {
37248 context.history().restore();
37252 buttonWrap.append('button')
37253 .attr('class', 'reset col6')
37254 .text(t('restore.reset'))
37255 .on('click', function() {
37256 context.history().clearSaved();
37260 restore.node().focus();
37263 iD.ui.Save = function(context) {
37264 var history = context.history(),
37265 key = iD.ui.cmd('⌘S');
37267 function saving() {
37268 return context.mode().id === 'save';
37272 d3.event.preventDefault();
37273 if (!context.inIntro() && !saving() && history.hasChanges()) {
37274 context.enter(iD.modes.Save(context));
37278 return function(selection) {
37279 var tooltip = bootstrap.tooltip()
37280 .placement('bottom')
37282 .title(iD.ui.tooltipHtml(t('save.no_changes'), key));
37284 var button = selection.append('button')
37285 .attr('class', 'save col12 disabled')
37286 .attr('tabindex', -1)
37290 button.append('span')
37291 .attr('class', 'label')
37292 .text(t('save.title'));
37294 button.append('span')
37295 .attr('class', 'count')
37298 var keybinding = d3.keybinding('undo-redo')
37299 .on(key, save, true);
37301 d3.select(document)
37304 var numChanges = 0;
37306 context.history().on('change.save', function() {
37307 var _ = history.difference().summary().length;
37308 if (_ === numChanges)
37312 tooltip.title(iD.ui.tooltipHtml(t(numChanges > 0 ?
37313 'save.help' : 'save.no_changes'), key));
37316 .classed('disabled', numChanges === 0)
37317 .classed('has-count', numChanges > 0);
37319 button.select('span.count')
37323 context.on('enter.save', function() {
37324 button.property('disabled', saving());
37325 if (saving()) button.call(tooltip.hide);
37329 iD.ui.Scale = function(context) {
37330 var projection = context.projection,
37334 function scaleDefs(loc1, loc2) {
37335 var lat = (loc2[1] + loc1[1]) / 2,
37336 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
37337 conversion = (imperial ? 3.28084 : 1),
37338 dist = iD.geo.lonToMeters(loc2[0] - loc1[0], lat) * conversion,
37339 scale = { dist: 0, px: 0, text: '' },
37340 buckets, i, val, dLon;
37343 buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
37345 buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
37348 // determine a user-friendly endpoint for the scale
37349 for (i = 0; i < buckets.length; i++) {
37352 scale.dist = Math.floor(dist / val) * val;
37357 dLon = iD.geo.metersToLon(scale.dist / conversion, lat);
37358 scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
37361 if (scale.dist >= 5280) {
37362 scale.dist /= 5280;
37363 scale.text = String(scale.dist) + ' mi';
37365 scale.text = String(scale.dist) + ' ft';
37368 if (scale.dist >= 1000) {
37369 scale.dist /= 1000;
37370 scale.text = String(scale.dist) + ' km';
37372 scale.text = String(scale.dist) + ' m';
37379 function update(selection) {
37380 // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
37381 var dims = context.map().dimensions(),
37382 loc1 = projection.invert([0, dims[1]]),
37383 loc2 = projection.invert([maxLength, dims[1]]),
37384 scale = scaleDefs(loc1, loc2);
37386 selection.select('#scalepath')
37387 .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
37389 selection.select('#scaletext')
37390 .attr('x', scale.px + 8)
37391 .attr('y', tickHeight)
37395 return function(selection) {
37396 var g = selection.append('svg')
37397 .attr('id', 'scale')
37399 .attr('transform', 'translate(10,11)');
37401 g.append('path').attr('id', 'scalepath');
37402 g.append('text').attr('id', 'scaletext');
37406 context.map().on('move.scale', function() {
37411 iD.ui.SelectionList = function(context, selectedIDs) {
37413 function selectEntity(entity) {
37414 context.enter(iD.modes.Select(context, [entity.id]).suppressMenu(true));
37418 function selectionList(selection) {
37419 selection.classed('selection-list-pane', true);
37421 var header = selection.append('div')
37422 .attr('class', 'header fillL cf');
37424 header.append('h3')
37425 .text(t('inspector.multiselect'));
37427 var listWrap = selection.append('div')
37428 .attr('class', 'inspector-body');
37430 var list = listWrap.append('div')
37431 .attr('class', 'feature-list cf');
37433 context.history().on('change.selection-list', drawList);
37436 function drawList() {
37437 var entities = selectedIDs
37438 .map(function(id) { return context.hasEntity(id); })
37439 .filter(function(entity) { return entity; });
37441 var items = list.selectAll('.feature-list-item')
37442 .data(entities, iD.Entity.key);
37444 var enter = items.enter().append('button')
37445 .attr('class', 'feature-list-item')
37446 .on('click', selectEntity);
37449 var label = enter.append('div')
37450 .attr('class', 'label')
37451 .call(iD.svg.Icon('', 'pre-text'));
37453 label.append('span')
37454 .attr('class', 'entity-type');
37456 label.append('span')
37457 .attr('class', 'entity-name');
37460 items.selectAll('use')
37461 .attr('href', function() {
37462 var entity = this.parentNode.parentNode.__data__;
37463 return '#icon-' + context.geometry(entity.id);
37466 items.selectAll('.entity-type')
37467 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
37469 items.selectAll('.entity-name')
37470 .text(function(entity) { return iD.util.displayName(entity); });
37478 return selectionList;
37481 iD.ui.Sidebar = function(context) {
37482 var inspector = iD.ui.Inspector(context),
37485 function sidebar(selection) {
37486 var featureListWrap = selection.append('div')
37487 .attr('class', 'feature-list-pane')
37488 .call(iD.ui.FeatureList(context));
37490 selection.call(iD.ui.Notice(context));
37492 var inspectorWrap = selection.append('div')
37493 .attr('class', 'inspector-hidden inspector-wrap fr');
37495 function hover(id) {
37496 if (!current && context.hasEntity(id)) {
37497 featureListWrap.classed('inspector-hidden', true);
37498 inspectorWrap.classed('inspector-hidden', false)
37499 .classed('inspector-hover', true);
37501 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
37506 inspectorWrap.call(inspector);
37508 } else if (!current) {
37509 featureListWrap.classed('inspector-hidden', false);
37510 inspectorWrap.classed('inspector-hidden', true);
37511 inspector.state('hide');
37515 sidebar.hover = _.throttle(hover, 200);
37517 sidebar.select = function(id, newFeature) {
37518 if (!current && id) {
37519 featureListWrap.classed('inspector-hidden', true);
37520 inspectorWrap.classed('inspector-hidden', false)
37521 .classed('inspector-hover', false);
37523 if (inspector.entityID() !== id || inspector.state() !== 'select') {
37527 .newFeature(newFeature);
37529 inspectorWrap.call(inspector);
37531 } else if (!current) {
37532 featureListWrap.classed('inspector-hidden', false);
37533 inspectorWrap.classed('inspector-hidden', true);
37534 inspector.state('hide');
37538 sidebar.show = function(component) {
37539 featureListWrap.classed('inspector-hidden', true);
37540 inspectorWrap.classed('inspector-hidden', true);
37541 if (current) current.remove();
37542 current = selection.append('div')
37543 .attr('class', 'sidebar-component')
37547 sidebar.hide = function() {
37548 featureListWrap.classed('inspector-hidden', false);
37549 inspectorWrap.classed('inspector-hidden', true);
37550 if (current) current.remove();
37555 sidebar.hover = function() {};
37556 sidebar.hover.cancel = function() {};
37557 sidebar.select = function() {};
37558 sidebar.show = function() {};
37559 sidebar.hide = function() {};
37563 iD.ui.SourceSwitch = function(context) {
37567 d3.event.preventDefault();
37569 if (context.history().hasChanges() &&
37570 !window.confirm(t('source_switch.lose_changes'))) return;
37572 var live = d3.select(this)
37575 context.connection()
37576 .switch(live ? keys[1] : keys[0]);
37578 context.enter(iD.modes.Browse(context));
37582 .text(live ? t('source_switch.dev') : t('source_switch.live'))
37583 .classed('live', !live);
37586 var sourceSwitch = function(selection) {
37587 selection.append('a')
37589 .text(t('source_switch.live'))
37590 .classed('live', true)
37591 .attr('tabindex', -1)
37592 .on('click', click);
37595 sourceSwitch.keys = function(_) {
37596 if (!arguments.length) return keys;
37598 return sourceSwitch;
37601 return sourceSwitch;
37603 iD.ui.Spinner = function(context) {
37604 var connection = context.connection();
37606 return function(selection) {
37607 var img = selection.append('img')
37608 .attr('src', context.imagePath('loader-black.gif'))
37609 .style('opacity', 0);
37611 connection.on('loading.spinner', function() {
37613 .style('opacity', 1);
37616 connection.on('loaded.spinner', function() {
37618 .style('opacity', 0);
37622 iD.ui.Splash = function(context) {
37623 return function(selection) {
37624 if (context.storage('sawSplash'))
37627 context.storage('sawSplash', true);
37629 var modal = iD.ui.modal(selection);
37631 modal.select('.modal')
37632 .attr('class', 'modal-splash modal col6');
37634 var introModal = modal.select('.content')
37636 .attr('class', 'fillL');
37638 introModal.append('div')
37639 .attr('class','modal-section cf')
37640 .append('h3').text(t('splash.welcome'));
37642 introModal.append('div')
37643 .attr('class','modal-section')
37645 .html(t('splash.text', {
37646 version: iD.version,
37647 website: '<a href="http://ideditor.com/">ideditor.com</a>',
37648 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
37651 var buttons = introModal.append('div').attr('class', 'modal-actions cf');
37653 buttons.append('button')
37654 .attr('class', 'col6 walkthrough')
37655 .text(t('splash.walkthrough'))
37656 .on('click', function() {
37657 d3.select(document.body).call(iD.ui.intro(context));
37661 buttons.append('button')
37662 .attr('class', 'col6 start')
37663 .text(t('splash.start'))
37664 .on('click', modal.close);
37666 modal.select('button.close').attr('class','hide');
37670 iD.ui.Status = function(context) {
37671 var connection = context.connection(),
37674 return function(selection) {
37676 function update() {
37678 connection.status(function(err, apiStatus) {
37680 selection.html('');
37682 if (err && errCount++ < 2) return;
37685 selection.text(t('status.error'));
37687 } else if (apiStatus === 'readonly') {
37688 selection.text(t('status.readonly'));
37690 } else if (apiStatus === 'offline') {
37691 selection.text(t('status.offline'));
37694 selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
37695 if (!err) errCount = 0;
37700 connection.on('auth', function() { update(selection); });
37701 window.setInterval(update, 90000);
37705 iD.ui.Success = function(context) {
37706 var dispatch = d3.dispatch('cancel'),
37709 function success(selection) {
37710 var message = (changeset.comment || t('success.edited_osm')).substring(0, 130) +
37711 ' ' + context.connection().changesetURL(changeset.id);
37713 var header = selection.append('div')
37714 .attr('class', 'header fillL');
37716 header.append('button')
37717 .attr('class', 'fr')
37718 .on('click', function() { dispatch.cancel(); })
37719 .call(iD.svg.Icon('#icon-close'));
37721 header.append('h3')
37722 .text(t('success.just_edited'));
37724 var body = selection.append('div')
37725 .attr('class', 'body save-success fillL');
37728 .html(t('success.help_html'));
37731 .attr('class', 'details')
37732 .attr('target', '_blank')
37733 .attr('tabindex', -1)
37734 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37735 .attr('href', t('success.help_link_url'))
37737 .text(t('success.help_link_text'));
37739 var changesetURL = context.connection().changesetURL(changeset.id);
37742 .attr('class', 'button col12 osm')
37743 .attr('target', '_blank')
37744 .attr('href', changesetURL)
37745 .text(t('success.view_on_osm'));
37748 facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
37749 twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
37750 google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
37753 body.selectAll('.button.social')
37754 .data(d3.entries(sharing))
37757 .attr('class', 'button social col4')
37758 .attr('target', '_blank')
37759 .attr('href', function(d) { return d.value; })
37760 .call(bootstrap.tooltip()
37761 .title(function(d) { return t('success.' + d.key); })
37762 .placement('bottom'))
37763 .each(function(d) { d3.select(this).call(iD.svg.Icon('#logo-' + d.key, 'social')); });
37766 success.changeset = function(_) {
37767 if (!arguments.length) return changeset;
37772 return d3.rebind(success, dispatch, 'on');
37774 iD.ui.TagReference = function(tag, context) {
37775 var tagReference = {},
37781 function findLocal(data) {
37782 var locale = iD.detect().locale.toLowerCase(),
37785 localized = _.find(data, function(d) {
37786 return d.lang.toLowerCase() === locale;
37788 if (localized) return localized;
37790 // try the non-regional version of a language, like
37791 // 'en' if the language is 'en-US'
37792 if (locale.indexOf('-') !== -1) {
37793 var first = locale.split('-')[0];
37794 localized = _.find(data, function(d) {
37795 return d.lang.toLowerCase() === first;
37797 if (localized) return localized;
37800 // finally fall back to english
37801 return _.find(data, function(d) {
37802 return d.lang.toLowerCase() === 'en';
37806 function load(param) {
37807 button.classed('tag-reference-loading', true);
37809 context.taginfo().docs(param, function show(err, data) {
37811 if (!err && data) {
37812 docs = findLocal(data);
37817 if (!docs || !docs.description) {
37818 if (param.hasOwnProperty('value')) {
37819 load(_.omit(param, 'value')); // retry with key only
37821 body.append('p').text(t('inspector.no_documentation_key'));
37827 if (docs.image && docs.image.thumb_url_prefix) {
37830 .attr('class', 'wiki-image')
37831 .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
37832 .on('load', function() { done(); })
37833 .on('error', function() { d3.select(this).remove(); done(); });
37840 .text(docs.description);
37844 .attr('target', '_blank')
37845 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
37846 .call(iD.svg.Icon('#icon-out-link', 'inline'))
37848 .text(t('inspector.reference'));
37855 button.classed('tag-reference-loading', false);
37859 .style('max-height', '200px')
37860 .style('opacity', '1');
37865 function hide(selection) {
37866 selection = selection || body.transition().duration(200);
37869 .style('max-height', '0px')
37870 .style('opacity', '0');
37875 tagReference.button = function(selection) {
37876 button = selection.selectAll('.tag-reference-button')
37881 .attr('class', 'tag-reference-button')
37882 .attr('tabindex', -1)
37883 .call(iD.svg.Icon('#icon-inspect'));
37885 button.on('click', function () {
37886 d3.event.stopPropagation();
37887 d3.event.preventDefault();
37890 } else if (loaded) {
37893 if (context.taginfo()) {
37900 tagReference.body = function(selection) {
37901 body = selection.selectAll('.tag-reference-body')
37904 body.enter().append('div')
37905 .attr('class', 'tag-reference-body cf')
37906 .style('max-height', '0')
37907 .style('opacity', '0');
37909 if (showing === false) {
37914 tagReference.showing = function(_) {
37915 if (!arguments.length) return showing;
37917 return tagReference;
37920 return tagReference;
37922 // toggles the visibility of ui elements, using a combination of the
37923 // hide class, which sets display=none, and a d3 transition for opacity.
37924 // this will cause blinking when called repeatedly, so check that the
37925 // value actually changes between calls.
37926 iD.ui.Toggle = function(show, callback) {
37927 return function(selection) {
37929 .style('opacity', show ? 0 : 1)
37930 .classed('hide', false)
37932 .style('opacity', show ? 1 : 0)
37933 .each('end', function() {
37935 .classed('hide', !show)
37936 .style('opacity', null);
37937 if (callback) callback.apply(this);
37941 iD.ui.UndoRedo = function(context) {
37944 cmd: iD.ui.cmd('⌘Z'),
37945 action: function() { if (!(context.inIntro() || saving())) context.undo(); },
37946 annotation: function() { return context.history().undoAnnotation(); }
37949 cmd: iD.ui.cmd('⌘⇧Z'),
37950 action: function() {if (!(context.inIntro() || saving())) context.redo(); },
37951 annotation: function() { return context.history().redoAnnotation(); }
37954 function saving() {
37955 return context.mode().id === 'save';
37958 return function(selection) {
37959 var tooltip = bootstrap.tooltip()
37960 .placement('bottom')
37962 .title(function (d) {
37963 return iD.ui.tooltipHtml(d.annotation() ?
37964 t(d.id + '.tooltip', {action: d.annotation()}) :
37965 t(d.id + '.nothing'), d.cmd);
37968 var buttons = selection.selectAll('button')
37970 .enter().append('button')
37971 .attr('class', 'col6 disabled')
37972 .on('click', function(d) { return d.action(); })
37975 buttons.each(function(d) {
37977 .call(iD.svg.Icon('#icon-' + d.id));
37980 var keybinding = d3.keybinding('undo')
37981 .on(commands[0].cmd, function() { d3.event.preventDefault(); commands[0].action(); })
37982 .on(commands[1].cmd, function() { d3.event.preventDefault(); commands[1].action(); });
37984 d3.select(document)
37988 .on('change.undo_redo', update);
37991 .on('enter.undo_redo', update);
37993 function update() {
37995 .property('disabled', saving())
37996 .classed('disabled', function(d) { return !d.annotation(); })
37998 var selection = d3.select(this);
37999 if (selection.property('tooltipVisible')) {
38000 selection.call(tooltip.show);
38006 iD.ui.ViewOnOSM = function(context) {
38009 function viewOnOSM(selection) {
38010 var entity = context.entity(id);
38012 selection.style('display', entity.isNew() ? 'none' : null);
38014 var $link = selection.selectAll('.view-on-osm')
38019 .attr('class', 'view-on-osm')
38020 .attr('target', '_blank')
38021 .call(iD.svg.Icon('#icon-out-link', 'inline'))
38023 .text(t('inspector.view_on_osm'));
38026 .attr('href', context.connection().entityURL(entity));
38029 viewOnOSM.entityID = function(_) {
38030 if (!arguments.length) return id;
38037 iD.ui.Zoom = function(context) {
38041 title: t('zoom.in'),
38042 action: context.zoomIn,
38047 title: t('zoom.out'),
38048 action: context.zoomOut,
38052 function zoomIn() {
38053 d3.event.preventDefault();
38054 if (!context.inIntro()) context.zoomIn();
38057 function zoomOut() {
38058 d3.event.preventDefault();
38059 if (!context.inIntro()) context.zoomOut();
38062 function zoomInFurther() {
38063 d3.event.preventDefault();
38064 if (!context.inIntro()) context.zoomInFurther();
38067 function zoomOutFurther() {
38068 d3.event.preventDefault();
38069 if (!context.inIntro()) context.zoomOutFurther();
38073 return function(selection) {
38074 var button = selection.selectAll('button')
38076 .enter().append('button')
38077 .attr('tabindex', -1)
38078 .attr('class', function(d) { return d.id; })
38079 .on('click.editor', function(d) { d.action(); })
38080 .call(bootstrap.tooltip()
38083 .title(function(d) {
38084 return iD.ui.tooltipHtml(d.title, d.key);
38087 button.each(function(d) {
38089 .call(iD.svg.Icon('#icon-' + d.icon, 'light'));
38092 var keybinding = d3.keybinding('zoom');
38094 _.each(['=','ffequals','plus','ffplus'], function(key) {
38095 keybinding.on(key, zoomIn);
38096 keybinding.on('⇧' + key, zoomIn);
38097 keybinding.on(iD.ui.cmd('⌘' + key), zoomInFurther);
38098 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomInFurther);
38100 _.each(['-','ffminus','_','dash'], function(key) {
38101 keybinding.on(key, zoomOut);
38102 keybinding.on('⇧' + key, zoomOut);
38103 keybinding.on(iD.ui.cmd('⌘' + key), zoomOutFurther);
38104 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomOutFurther);
38107 d3.select(document)
38111 iD.ui.preset.access = function(field) {
38112 var dispatch = d3.dispatch('change'),
38115 function access(selection) {
38116 var wrap = selection.selectAll('.preset-input-wrap')
38119 wrap.enter().append('div')
38120 .attr('class', 'cf preset-input-wrap')
38123 items = wrap.select('ul').selectAll('li')
38128 var enter = items.enter().append('li')
38129 .attr('class', function(d) { return 'cf preset-access-' + d; });
38131 enter.append('span')
38132 .attr('class', 'col6 label preset-label-access')
38133 .attr('for', function(d) { return 'preset-input-access-' + d; })
38134 .text(function(d) { return field.t('types.' + d); });
38136 enter.append('div')
38137 .attr('class', 'col6 preset-input-access-wrap')
38139 .attr('type', 'text')
38140 .attr('class', 'preset-input-access')
38141 .attr('id', function(d) { return 'preset-input-access-' + d; })
38142 .each(function(d) {
38144 .call(d3.combobox()
38145 .data(access.options(d)));
38150 wrap.selectAll('.preset-input-access')
38151 .on('change', change)
38152 .on('blur', change);
38155 function change(d) {
38157 tag[d] = d3.select(this).value() || undefined;
38158 dispatch.change(tag);
38161 access.options = function(type) {
38162 var options = ['no', 'permissive', 'private', 'destination'];
38164 if (type !== 'access') {
38165 options.unshift('yes');
38166 options.push('designated');
38168 if (type === 'bicycle') {
38169 options.push('dismount');
38173 return options.map(function(option) {
38175 title: field.t('options.' + option + '.description'),
38181 var placeholders = {
38183 foot: 'designated',
38184 motor_vehicle: 'no'
38188 motor_vehicle: 'no',
38194 motor_vehicle: 'no'
38197 motor_vehicle: 'no',
38198 bicycle: 'designated'
38201 motor_vehicle: 'no',
38202 horse: 'designated'
38206 motor_vehicle: 'no',
38212 motor_vehicle: 'yes',
38217 motor_vehicle: 'yes'
38221 motor_vehicle: 'yes',
38227 motor_vehicle: 'yes',
38233 motor_vehicle: 'yes',
38239 motor_vehicle: 'yes',
38245 motor_vehicle: 'yes',
38251 motor_vehicle: 'yes',
38257 motor_vehicle: 'yes',
38262 motor_vehicle: 'yes'
38266 motor_vehicle: 'yes',
38272 motor_vehicle: 'yes',
38278 motor_vehicle: 'yes',
38284 access.tags = function(tags) {
38285 items.selectAll('.preset-input-access')
38286 .value(function(d) { return tags[d] || ''; })
38287 .attr('placeholder', function() {
38288 return tags.access ? tags.access : field.placeholder();
38291 // items.selectAll('#preset-input-access-access')
38292 // .attr('placeholder', 'yes');
38294 _.forEach(placeholders[tags.highway], function(v, k) {
38295 items.selectAll('#preset-input-access-' + k)
38296 .attr('placeholder', function() { return (tags.access || v); });
38300 access.focus = function() {
38301 items.selectAll('.preset-input-access')
38305 return d3.rebind(access, dispatch, 'on');
38307 iD.ui.preset.address = function(field, context) {
38308 var dispatch = d3.dispatch('init', 'change'),
38321 function getStreets() {
38322 var extent = entity.extent(context.graph()),
38323 l = extent.center(),
38324 box = iD.geo.Extent(l).padByMeters(200);
38326 return context.intersects(box)
38327 .filter(isAddressable)
38329 var loc = context.projection([
38330 (extent[0][0] + extent[1][0]) / 2,
38331 (extent[0][1] + extent[1][1]) / 2]),
38332 choice = iD.geo.chooseEdge(context.childNodes(d), loc, context.projection);
38334 title: d.tags.name,
38335 value: d.tags.name,
38336 dist: choice.distance
38338 }).sort(function(a, b) {
38339 return a.dist - b.dist;
38342 function isAddressable(d) {
38343 return d.tags.highway && d.tags.name && d.type === 'way';
38347 function getCities() {
38348 var extent = entity.extent(context.graph()),
38349 l = extent.center(),
38350 box = iD.geo.Extent(l).padByMeters(200);
38352 return context.intersects(box)
38353 .filter(isAddressable)
38356 title: d.tags['addr:city'] || d.tags.name,
38357 value: d.tags['addr:city'] || d.tags.name,
38358 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
38360 }).sort(function(a, b) {
38361 return a.dist - b.dist;
38364 function isAddressable(d) {
38366 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
38369 if (d.tags.place && d.tags.name && (
38370 d.tags.place === 'city' ||
38371 d.tags.place === 'town' ||
38372 d.tags.place === 'village'))
38375 if (d.tags['addr:city']) return true;
38381 function getPostCodes() {
38382 var extent = entity.extent(context.graph()),
38383 l = extent.center(),
38384 box = iD.geo.Extent(l).padByMeters(200);
38386 return context.intersects(box)
38387 .filter(isAddressable)
38390 title: d.tags['addr:postcode'],
38391 value: d.tags['addr:postcode'],
38392 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
38394 }).sort(function(a, b) {
38395 return a.dist - b.dist;
38398 function isAddressable(d) {
38399 return d.tags['addr:postcode'];
38403 function address(selection) {
38404 isInitialized = false;
38406 wrap = selection.selectAll('.preset-input-wrap')
38413 .attr('class', 'preset-input-wrap');
38415 var center = entity.extent(context.graph()).center(),
38418 iD.services.nominatim().countryCode(center, function (err, countryCode) {
38419 addressFormat = _.find(iD.data.addressFormats, function (a) {
38420 return a && a.countryCodes && _.contains(a.countryCodes, countryCode);
38421 }) || _.first(iD.data.addressFormats);
38424 // Normalize widths.
38425 var total = _.reduce(r, function(sum, field) {
38426 return sum + (widths[field] || 0.5);
38429 return r.map(function (field) {
38432 width: (widths[field] || 0.5) / total
38437 wrap.selectAll('div')
38438 .data(addressFormat.format)
38441 .attr('class', 'addr-row')
38442 .selectAll('input')
38446 .property('type', 'text')
38447 .attr('placeholder', function (d) { return field.t('placeholders.' + d.id); })
38448 .attr('class', function (d) { return 'addr-' + d.id; })
38449 .style('width', function (d) { return d.width * 100 + '%'; });
38453 wrap.selectAll('.addr-street')
38454 .call(d3.combobox()
38455 .fetcher(function(value, callback) {
38456 callback(getStreets());
38459 wrap.selectAll('.addr-city')
38460 .call(d3.combobox()
38461 .fetcher(function(value, callback) {
38462 callback(getCities());
38465 wrap.selectAll('.addr-postcode')
38466 .call(d3.combobox()
38467 .fetcher(function(value, callback) {
38468 callback(getPostCodes());
38471 wrap.selectAll('input')
38472 .on('blur', change())
38473 .on('change', change());
38475 wrap.selectAll('input:not(.combobox-input)')
38476 .on('input', change(true));
38479 isInitialized = true;
38483 function change(onInput) {
38484 return function() {
38487 wrap.selectAll('input')
38488 .each(function (field) {
38489 tags['addr:' + field.id] = this.value || undefined;
38492 dispatch.change(tags, onInput);
38496 function updateTags(tags) {
38497 wrap.selectAll('input')
38498 .value(function (field) {
38499 return tags['addr:' + field.id] || '';
38503 address.entity = function(_) {
38504 if (!arguments.length) return entity;
38509 address.tags = function(tags) {
38510 if (isInitialized) {
38513 dispatch.on('init', function () {
38519 address.focus = function() {
38520 var node = wrap.selectAll('input').node();
38521 if (node) node.focus();
38524 return d3.rebind(address, dispatch, 'on');
38526 iD.ui.preset.check =
38527 iD.ui.preset.defaultcheck = function(field) {
38528 var dispatch = d3.dispatch('change'),
38529 options = field.strings && field.strings.options,
38532 entity, value, box, text, label;
38535 for (var k in options) {
38536 values.push(k === 'undefined' ? undefined : k);
38537 texts.push(field.t('options.' + k, { 'default': options[k] }));
38540 values = [undefined, 'yes'];
38541 texts = [t('inspector.unknown'), t('inspector.check.yes')];
38542 if (field.type === 'check') {
38544 texts.push(t('inspector.check.no'));
38548 var check = function(selection) {
38549 // hack: pretend oneway field is a oneway_yes field
38550 // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
38551 if (field.id === 'oneway') {
38552 for (var key in entity.tags) {
38553 if (key in iD.oneWayTags && (entity.tags[key] in iD.oneWayTags[key])) {
38554 texts[0] = t('presets.fields.oneway_yes.options.undefined');
38560 selection.classed('checkselect', 'true');
38562 label = selection.selectAll('.preset-input-wrap')
38565 var enter = label.enter().append('label')
38566 .attr('class', 'preset-input-wrap');
38568 enter.append('input')
38569 .property('indeterminate', field.type === 'check')
38570 .attr('type', 'checkbox')
38571 .attr('id', 'preset-input-' + field.id);
38573 enter.append('span')
38575 .attr('class', 'value');
38577 box = label.select('input')
38578 .on('click', function() {
38580 t[field.key] = values[(values.indexOf(value) + 1) % values.length];
38581 dispatch.change(t);
38582 d3.event.stopPropagation();
38585 text = label.select('span.value');
38588 check.entity = function(_) {
38589 if (!arguments.length) return entity;
38594 check.tags = function(tags) {
38595 value = tags[field.key];
38596 box.property('indeterminate', field.type === 'check' && !value);
38597 box.property('checked', value === 'yes');
38598 text.text(texts[values.indexOf(value)]);
38599 label.classed('set', !!value);
38602 check.focus = function() {
38603 box.node().focus();
38606 return d3.rebind(check, dispatch, 'on');
38608 iD.ui.preset.combo =
38609 iD.ui.preset.typeCombo = function(field, context) {
38610 var dispatch = d3.dispatch('change'),
38611 optstrings = field.strings && field.strings.options,
38612 optarray = field.options,
38613 snake_case = (field.snake_case || (field.snake_case === undefined)),
38617 function snake(s) {
38618 return s.replace(/\s+/g, '_');
38621 function unsnake(s) {
38622 return s.replace(/_+/g, ' ');
38625 function clean(s) {
38626 return s.split(';')
38627 .map(function(s) { return s.trim(); })
38631 function optString() {
38632 return _.find(_.keys(strings), function(k) {
38633 return strings[k] === input.value();
38637 function combo(selection) {
38638 var combobox = d3.combobox();
38640 input = selection.selectAll('input')
38643 var enter = input.enter()
38645 .attr('type', 'text')
38646 .attr('id', 'preset-input-' + field.id);
38648 if (optstrings) { enter.attr('readonly', 'readonly'); }
38652 .on('change', change)
38653 .on('blur', change)
38656 _.each(optstrings, function(v, k) {
38657 strings[k] = field.t('options.' + k, { 'default': v });
38660 } else if (optarray) {
38661 _.each(optarray, function(k) {
38662 strings[k] = (snake_case ? unsnake(k) : k);
38665 } else if (context.taginfo()) {
38666 context.taginfo().values({key: field.key}, function(err, data) {
38668 _.each(_.pluck(data, 'value'), function(k) {
38669 strings[k] = (snake_case ? unsnake(k) : k);
38677 function stringsLoaded() {
38678 var keys = _.keys(strings),
38682 combobox.data(keys.map(function(k) {
38683 var s = strings[k],
38685 o.title = o.value = s;
38686 if (s.length < 20) { strs.push(s); }
38690 placeholders = strs.length > 1 ? strs : keys;
38691 input.attr('placeholder', field.placeholder() ||
38692 (placeholders.slice(0, 3).join(', ') + '...'));
38696 function change() {
38697 var value = optString() || clean(input.value());
38700 value = snake(value);
38702 if (field.type === 'typeCombo' && !value) {
38707 t[field.key] = value || undefined;
38708 dispatch.change(t);
38711 combo.tags = function(tags) {
38712 var key = tags[field.key],
38713 optstring = optString(),
38714 value = strings[key] || key || '';
38716 if (field.type === 'typeCombo' && value.toLowerCase() === 'yes') {
38719 if (!optstring && snake_case) {
38720 value = unsnake(value);
38722 input.value(value);
38725 combo.focus = function() {
38726 input.node().focus();
38729 return d3.rebind(combo, dispatch, 'on');
38731 iD.ui.preset.cycleway = function(field) {
38732 var dispatch = d3.dispatch('change'),
38735 function cycleway(selection) {
38736 var wrap = selection.selectAll('.preset-input-wrap')
38739 wrap.enter().append('div')
38740 .attr('class', 'cf preset-input-wrap')
38743 items = wrap.select('ul').selectAll('li')
38748 var enter = items.enter().append('li')
38749 .attr('class', function(d) { return 'cf preset-cycleway-' + d; });
38751 enter.append('span')
38752 .attr('class', 'col6 label preset-label-cycleway')
38753 .attr('for', function(d) { return 'preset-input-cycleway-' + d; })
38754 .text(function(d) { return field.t('types.' + d); });
38756 enter.append('div')
38757 .attr('class', 'col6 preset-input-cycleway-wrap')
38759 .attr('type', 'text')
38760 .attr('class', 'preset-input-cycleway')
38761 .attr('id', function(d) { return 'preset-input-cycleway-' + d; })
38762 .each(function(d) {
38764 .call(d3.combobox()
38765 .data(cycleway.options(d)));
38770 wrap.selectAll('.preset-input-cycleway')
38771 .on('change', change)
38772 .on('blur', change);
38775 function change() {
38776 var inputs = d3.selectAll('.preset-input-cycleway')[0],
38777 left = d3.select(inputs[0]).value(),
38778 right = d3.select(inputs[1]).value(),
38780 if (left === 'none' || left === '') { left = undefined; }
38781 if (right === 'none' || right === '') { right = undefined; }
38783 // Always set both left and right as changing one can affect the other
38785 cycleway: undefined,
38786 'cycleway:left': left,
38787 'cycleway:right': right
38790 // If the left and right tags match, use the cycleway tag to tag both
38791 // sides the same way
38792 if (left === right) {
38795 'cycleway:left': undefined,
38796 'cycleway:right': undefined
38800 dispatch.change(tag);
38803 cycleway.options = function() {
38804 return d3.keys(field.strings.options).map(function(option) {
38806 title: field.t('options.' + option + '.description'),
38812 cycleway.tags = function(tags) {
38813 items.selectAll('.preset-input-cycleway')
38814 .value(function(d) {
38815 // If cycleway is set, always return that
38816 if (tags.cycleway) {
38817 return tags.cycleway;
38819 return tags[d] || '';
38821 .attr('placeholder', field.placeholder());
38824 cycleway.focus = function() {
38825 items.selectAll('.preset-input-cycleway')
38829 return d3.rebind(cycleway, dispatch, 'on');
38831 iD.ui.preset.text =
38832 iD.ui.preset.number =
38834 iD.ui.preset.email =
38835 iD.ui.preset.url = function(field) {
38837 var dispatch = d3.dispatch('change'),
38840 function i(selection) {
38841 input = selection.selectAll('input')
38844 input.enter().append('input')
38845 .attr('type', field.type)
38846 .attr('id', 'preset-input-' + field.id)
38847 .attr('placeholder', field.placeholder() || t('inspector.unknown'));
38850 .on('input', change(true))
38851 .on('blur', change())
38852 .on('change', change());
38854 if (field.type === 'number') {
38855 input.attr('type', 'text');
38857 var spinControl = selection.selectAll('.spin-control')
38860 var enter = spinControl.enter().append('div')
38861 .attr('class', 'spin-control');
38863 enter.append('button')
38865 .attr('class', 'increment');
38867 enter.append('button')
38869 .attr('class', 'decrement');
38871 spinControl.selectAll('button')
38872 .on('click', function(d) {
38873 d3.event.preventDefault();
38874 var num = parseInt(input.node().value || 0, 10);
38875 if (!isNaN(num)) input.node().value = num + d;
38881 function change(onInput) {
38882 return function() {
38884 t[field.key] = input.value() || undefined;
38885 dispatch.change(t, onInput);
38889 i.tags = function(tags) {
38890 input.value(tags[field.key] || '');
38893 i.focus = function() {
38894 input.node().focus();
38897 return d3.rebind(i, dispatch, 'on');
38899 iD.ui.preset.localized = function(field, context) {
38900 var dispatch = d3.dispatch('change', 'input'),
38901 wikipedia = iD.services.wikipedia(),
38902 input, localizedInputs, wikiTitles,
38905 function i(selection) {
38906 input = selection.selectAll('.localized-main')
38909 input.enter().append('input')
38910 .attr('type', 'text')
38911 .attr('id', 'preset-input-' + field.id)
38912 .attr('class', 'localized-main')
38913 .attr('placeholder', field.placeholder());
38915 if (field.id === 'name') {
38916 var preset = context.presets().match(entity, context.graph());
38917 input.call(d3.combobox().fetcher(
38918 iD.util.SuggestNames(preset, iD.data.suggestions)
38923 .on('input', change(true))
38924 .on('blur', change())
38925 .on('change', change());
38927 var translateButton = selection.selectAll('.localized-add')
38930 translateButton.enter()
38932 .attr('class', 'button-input-action localized-add minor')
38933 .call(iD.svg.Icon('#icon-plus'))
38934 .call(bootstrap.tooltip()
38935 .title(t('translate.translate'))
38936 .placement('left'));
38939 .on('click', addNew);
38941 localizedInputs = selection.selectAll('.localized-wrap')
38944 localizedInputs.enter().append('div')
38945 .attr('class', 'localized-wrap');
38948 function addNew() {
38949 d3.event.preventDefault();
38950 var data = localizedInputs.selectAll('div.entry').data();
38951 var defaultLang = iD.detect().locale.toLowerCase().split('-')[0];
38952 var langExists = _.find(data, function(datum) { return datum.lang === defaultLang;});
38953 var isLangEn = defaultLang.indexOf('en') > -1;
38954 if (isLangEn || langExists) {
38957 data.push({ lang: defaultLang, value: '' });
38958 localizedInputs.call(render, data);
38961 function change(onInput) {
38962 return function() {
38964 t[field.key] = d3.select(this).value() || undefined;
38965 dispatch.change(t, onInput);
38969 function key(lang) { return field.key + ':' + lang; }
38971 function changeLang(d) {
38972 var lang = d3.select(this).value(),
38974 language = _.find(iD.data.wikipedia, function(d) {
38975 return d[0].toLowerCase() === lang.toLowerCase() ||
38976 d[1].toLowerCase() === lang.toLowerCase();
38979 if (language) lang = language[2];
38981 if (d.lang && d.lang !== lang) {
38982 t[key(d.lang)] = undefined;
38985 var value = d3.select(this.parentNode)
38986 .selectAll('.localized-value')
38989 if (lang && value) {
38990 t[key(lang)] = value;
38991 } else if (lang && wikiTitles && wikiTitles[d.lang]) {
38992 t[key(lang)] = wikiTitles[d.lang];
38996 dispatch.change(t);
38999 function changeValue(d) {
39000 if (!d.lang) return;
39002 t[key(d.lang)] = d3.select(this).value() || undefined;
39003 dispatch.change(t);
39006 function fetcher(value, cb) {
39007 var v = value.toLowerCase();
39009 cb(iD.data.wikipedia.filter(function(d) {
39010 return d[0].toLowerCase().indexOf(v) >= 0 ||
39011 d[1].toLowerCase().indexOf(v) >= 0 ||
39012 d[2].toLowerCase().indexOf(v) >= 0;
39013 }).map(function(d) {
39014 return { value: d[1] };
39018 function render(selection, data) {
39019 var wraps = selection.selectAll('div.entry').
39020 data(data, function(d) { return d.lang; });
39022 var innerWrap = wraps.enter()
39023 .insert('div', ':first-child');
39025 innerWrap.attr('class', 'entry')
39027 var wrap = d3.select(this);
39028 var langcombo = d3.combobox().fetcher(fetcher);
39030 var label = wrap.append('label')
39031 .attr('class','form-label')
39032 .text(t('translate.localized_translation_label'))
39033 .attr('for','localized-lang');
39035 label.append('button')
39036 .attr('class', 'minor remove')
39037 .on('click', function(d){
39038 d3.event.preventDefault();
39040 t[key(d.lang)] = undefined;
39041 dispatch.change(t);
39042 d3.select(this.parentNode.parentNode)
39044 .style('max-height','240px')
39046 .style('opacity', '0')
39047 .style('max-height','0px')
39050 .call(iD.svg.Icon('#operation-delete'));
39052 wrap.append('input')
39053 .attr('class', 'localized-lang')
39054 .attr('type', 'text')
39055 .attr('placeholder',t('translate.localized_translation_language'))
39056 .on('blur', changeLang)
39057 .on('change', changeLang)
39060 wrap.append('input')
39061 .on('blur', changeValue)
39062 .on('change', changeValue)
39063 .attr('type', 'text')
39064 .attr('placeholder', t('translate.localized_translation_name'))
39065 .attr('class', 'localized-value');
39069 .style('margin-top', '0px')
39070 .style('max-height', '0px')
39071 .style('opacity', '0')
39074 .style('margin-top', '10px')
39075 .style('max-height', '240px')
39076 .style('opacity', '1')
39077 .each('end', function() {
39079 .style('max-height', '')
39080 .style('overflow', 'visible');
39086 .style('max-height','0px')
39087 .style('opacity', '0')
39088 .style('top','-10px')
39091 var entry = selection.selectAll('.entry');
39093 entry.select('.localized-lang')
39094 .value(function(d) {
39095 var lang = _.find(iD.data.wikipedia, function(lang) { return lang[2] === d.lang; });
39096 return lang ? lang[1] : d.lang;
39099 entry.select('.localized-value')
39100 .value(function(d) { return d.value; });
39103 i.tags = function(tags) {
39104 // Fetch translations from wikipedia
39105 if (tags.wikipedia && !wikiTitles) {
39107 var wm = tags.wikipedia.match(/([^:]+):(.+)/);
39108 if (wm && wm[0] && wm[1]) {
39109 wikipedia.translations(wm[1], wm[2], function(d) {
39115 input.value(tags[field.key] || '');
39117 var postfixed = [], k, m;
39119 m = k.match(/^(.*):([a-zA-Z_-]+)$/);
39120 if (m && m[1] === field.key && m[2]) {
39121 postfixed.push({ lang: m[2], value: tags[k] });
39125 localizedInputs.call(render, postfixed.reverse());
39128 i.focus = function() {
39129 input.node().focus();
39132 i.entity = function(_) {
39136 return d3.rebind(i, dispatch, 'on');
39138 iD.ui.preset.maxspeed = function(field, context) {
39139 var dispatch = d3.dispatch('change'),
39146 var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
39147 imperialValues = [20, 25, 30, 35, 40, 45, 50, 55, 65, 70];
39149 function maxspeed(selection) {
39150 combobox = d3.combobox();
39151 var unitCombobox = d3.combobox().data(['km/h', 'mph'].map(comboValues));
39153 input = selection.selectAll('#preset-input-' + field.id)
39156 input.enter().append('input')
39157 .attr('type', 'text')
39158 .attr('id', 'preset-input-' + field.id)
39159 .attr('placeholder', field.placeholder());
39163 .on('change', change)
39164 .on('blur', change);
39166 var childNodes = context.graph().childNodes(context.entity(entity.id)),
39167 loc = childNodes[~~(childNodes.length/2)].loc;
39169 imperial = _.any(iD.data.imperial.features, function(f) {
39170 return _.any(f.geometry.coordinates, function(d) {
39171 return iD.geo.pointInPolygon(loc, d[0]);
39175 unitInput = selection.selectAll('input.maxspeed-unit')
39178 unitInput.enter().append('input')
39179 .attr('type', 'text')
39180 .attr('class', 'maxspeed-unit');
39183 .on('blur', changeUnits)
39184 .on('change', changeUnits)
39185 .call(unitCombobox);
39187 function changeUnits() {
39188 imperial = unitInput.value() === 'mph';
39189 unitInput.value(imperial ? 'mph' : 'km/h');
39196 function setSuggestions() {
39197 combobox.data((imperial ? imperialValues : metricValues).map(comboValues));
39198 unitInput.value(imperial ? 'mph' : 'km/h');
39201 function comboValues(d) {
39203 value: d.toString(),
39204 title: d.toString()
39208 function change() {
39210 value = input.value();
39213 tag[field.key] = undefined;
39214 } else if (isNaN(value) || !imperial) {
39215 tag[field.key] = value;
39217 tag[field.key] = value + ' mph';
39220 dispatch.change(tag);
39223 maxspeed.tags = function(tags) {
39224 var value = tags[field.key];
39226 if (value && value.indexOf('mph') >= 0) {
39227 value = parseInt(value, 10);
39229 } else if (value) {
39235 input.value(value || '');
39238 maxspeed.focus = function() {
39239 input.node().focus();
39242 maxspeed.entity = function(_) {
39246 return d3.rebind(maxspeed, dispatch, 'on');
39248 iD.ui.preset.radio = function(field) {
39249 var dispatch = d3.dispatch('change'),
39250 labels, radios, placeholder;
39252 function radio(selection) {
39253 selection.classed('preset-radio', true);
39255 var wrap = selection.selectAll('.preset-input-wrap')
39258 var buttonWrap = wrap.enter().append('div')
39259 .attr('class', 'preset-input-wrap toggle-list');
39261 buttonWrap.append('span')
39262 .attr('class', 'placeholder');
39264 placeholder = selection.selectAll('.placeholder');
39266 labels = wrap.selectAll('label')
39267 .data(field.options || field.keys);
39269 var enter = labels.enter().append('label');
39271 enter.append('input')
39272 .attr('type', 'radio')
39273 .attr('name', field.id)
39274 .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
39275 .attr('checked', false);
39277 enter.append('span')
39278 .text(function(d) { return field.t('options.' + d, { 'default': d }); });
39280 radios = labels.selectAll('input')
39281 .on('change', change);
39284 function change() {
39286 if (field.key) t[field.key] = undefined;
39287 radios.each(function(d) {
39288 var active = d3.select(this).property('checked');
39290 if (active) t[field.key] = d;
39292 t[d] = active ? 'yes' : undefined;
39295 dispatch.change(t);
39298 radio.tags = function(tags) {
39299 function checked(d) {
39301 return tags[field.key] === d;
39303 return !!(tags[d] && tags[d] !== 'no');
39307 labels.classed('active', checked);
39308 radios.property('checked', checked);
39309 var selection = radios.filter(function() { return this.checked; });
39310 if (selection.empty()) {
39311 placeholder.text(t('inspector.none'));
39313 placeholder.text(selection.attr('value'));
39317 radio.focus = function() {
39318 radios.node().focus();
39321 return d3.rebind(radio, dispatch, 'on');
39323 iD.ui.preset.restrictions = function(field, context) {
39324 var dispatch = d3.dispatch('change'),
39325 hover = iD.behavior.Hover(context),
39330 function restrictions(selection) {
39331 // if form field is hidden or has detached from dom, clean up.
39332 if (!d3.select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
39333 selection.call(restrictions.off);
39337 var wrap = selection.selectAll('.preset-input-wrap')
39340 var enter = wrap.enter()
39342 .attr('class', 'preset-input-wrap');
39346 .attr('class', 'restriction-help');
39349 var intersection = iD.geo.Intersection(context.graph(), vertexID),
39350 graph = intersection.graph,
39351 vertex = graph.entity(vertexID),
39352 filter = d3.functor(true),
39353 extent = iD.geo.Extent(),
39354 projection = iD.geo.RawMercator();
39356 var d = wrap.dimensions(),
39357 c = [d[0] / 2, d[1] / 2],
39361 .scale(256 * Math.pow(2, z) / (2 * Math.PI));
39363 var s = projection(vertex.loc);
39366 .translate([c[0] - s[0], c[1] - s[1]])
39367 .clipExtent([[0, 0], d]);
39369 var drawLayers = iD.svg.Layers(projection, context).only('osm').dimensions(d),
39370 drawVertices = iD.svg.Vertices(projection, context),
39371 drawLines = iD.svg.Lines(projection, context),
39372 drawTurns = iD.svg.Turns(projection, context);
39376 .selectAll('.surface')
39380 var surface = wrap.selectAll('.surface');
39384 .call(drawVertices, graph, [vertex], filter, extent, z)
39385 .call(drawLines, graph, intersection.ways, filter)
39386 .call(drawTurns, graph, intersection.turns(fromNodeID));
39389 .on('click.restrictions', click)
39390 .on('mouseover.restrictions', mouseover)
39391 .on('mouseout.restrictions', mouseout);
39394 .selectAll('.selected')
39395 .classed('selected', false);
39399 .selectAll('.' + intersection.highways[fromNodeID].id)
39400 .classed('selected', true);
39406 .on('change.restrictions', render);
39409 .on('resize.restrictions', function() {
39410 wrap.dimensions(null);
39415 var datum = d3.event.target.__data__;
39416 if (datum instanceof iD.Entity) {
39417 fromNodeID = intersection.adjacentNodeId(datum.id);
39419 } else if (datum instanceof iD.geo.Turn) {
39420 if (datum.restriction) {
39422 iD.actions.UnrestrictTurn(datum, projection),
39423 t('operations.restriction.annotation.delete'));
39426 iD.actions.RestrictTurn(datum, projection),
39427 t('operations.restriction.annotation.create'));
39432 function mouseover() {
39433 var datum = d3.event.target.__data__;
39434 if (datum instanceof iD.geo.Turn) {
39435 var graph = context.graph(),
39436 presets = context.presets(),
39439 if (datum.restriction) {
39440 preset = presets.match(graph.entity(datum.restriction), graph);
39442 preset = presets.item('type/restriction/' +
39443 iD.geo.inferRestriction(
39451 wrap.selectAll('.restriction-help')
39452 .text(t('operations.restriction.help.' +
39453 (datum.restriction ? 'toggle_off' : 'toggle_on'),
39454 {restriction: preset.name()}));
39458 function mouseout() {
39459 wrap.selectAll('.restriction-help')
39460 .text(t('operations.restriction.help.' +
39461 (fromNodeID ? 'toggle' : 'select')));
39464 function render() {
39465 if (context.hasEntity(vertexID)) {
39466 restrictions(selection);
39471 restrictions.entity = function(_) {
39472 if (!vertexID || vertexID !== _.id) {
39478 restrictions.tags = function() {};
39479 restrictions.focus = function() {};
39481 restrictions.off = function(selection) {
39482 selection.selectAll('.surface')
39484 .on('click.restrictions', null)
39485 .on('mouseover.restrictions', null)
39486 .on('mouseout.restrictions', null);
39489 .on('change.restrictions', null);
39492 .on('resize.restrictions', null);
39495 return d3.rebind(restrictions, dispatch, 'on');
39497 iD.ui.preset.textarea = function(field) {
39498 var dispatch = d3.dispatch('change'),
39501 function i(selection) {
39502 input = selection.selectAll('textarea')
39505 input.enter().append('textarea')
39506 .attr('id', 'preset-input-' + field.id)
39507 .attr('placeholder', field.placeholder() || t('inspector.unknown'))
39508 .attr('maxlength', 255);
39511 .on('input', change(true))
39512 .on('blur', change())
39513 .on('change', change());
39516 function change(onInput) {
39517 return function() {
39519 t[field.key] = input.value() || undefined;
39520 dispatch.change(t, onInput);
39524 i.tags = function(tags) {
39525 input.value(tags[field.key] || '');
39528 i.focus = function() {
39529 input.node().focus();
39532 return d3.rebind(i, dispatch, 'on');
39534 iD.ui.preset.wikipedia = function(field, context) {
39535 var dispatch = d3.dispatch('change'),
39536 wikipedia = iD.services.wikipedia(),
39537 link, entity, lang, title;
39539 function i(selection) {
39540 var langcombo = d3.combobox()
39541 .fetcher(function(value, cb) {
39542 var v = value.toLowerCase();
39544 cb(iD.data.wikipedia.filter(function(d) {
39545 return d[0].toLowerCase().indexOf(v) >= 0 ||
39546 d[1].toLowerCase().indexOf(v) >= 0 ||
39547 d[2].toLowerCase().indexOf(v) >= 0;
39548 }).map(function(d) {
39549 return { value: d[1] };
39553 var titlecombo = d3.combobox()
39554 .fetcher(function(value, cb) {
39556 if (!value) value = context.entity(entity.id).tags.name || '';
39557 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
39559 searchfn(language()[2], value, function(query, data) {
39560 cb(data.map(function(d) {
39561 return { value: d };
39566 lang = selection.selectAll('input.wiki-lang')
39569 lang.enter().append('input')
39570 .attr('type', 'text')
39571 .attr('class', 'wiki-lang')
39572 .attr('placeholder', t('translate.localized_translation_language'))
39577 .on('blur', changeLang)
39578 .on('change', changeLang);
39580 title = selection.selectAll('input.wiki-title')
39583 title.enter().append('input')
39584 .attr('type', 'text')
39585 .attr('class', 'wiki-title')
39586 .attr('id', 'preset-input-' + field.id);
39590 .on('blur', change)
39591 .on('change', change);
39593 link = selection.selectAll('a.wiki-link')
39596 link.enter().append('a')
39597 .attr('class', 'wiki-link button-input-action minor')
39598 .attr('target', '_blank')
39599 .call(iD.svg.Icon('#icon-out-link', 'inline'));
39602 function language() {
39603 var value = lang.value().toLowerCase();
39604 var locale = iD.detect().locale.toLowerCase();
39605 var localeLanguage;
39606 return _.find(iD.data.wikipedia, function(d) {
39607 if (d[2] === locale) localeLanguage = d;
39608 return d[0].toLowerCase() === value ||
39609 d[1].toLowerCase() === value ||
39611 }) || localeLanguage || ['English', 'English', 'en'];
39614 function changeLang() {
39615 lang.value(language()[1]);
39619 function change() {
39620 var value = title.value(),
39621 m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
39622 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
39626 // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
39627 value = decodeURIComponent(m[2]).replace(/_/g, ' ');
39630 // Best-effort `anchordecode:` implementation
39631 anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
39633 anchor = decodeURIComponent(m[3]);
39635 value += '#' + anchor.replace(/_/g, ' ');
39637 value = value.slice(0, 1).toUpperCase() + value.slice(1);
39639 title.value(value);
39643 t[field.key] = value ? language()[2] + ':' + value : undefined;
39644 dispatch.change(t);
39647 i.tags = function(tags) {
39648 var value = tags[field.key] || '',
39649 m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
39650 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
39651 anchor = m && m[3];
39653 // value in correct format
39656 title.value(m[2] + (anchor ? ('#' + anchor) : ''));
39659 // Best-effort `anchorencode:` implementation
39660 anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
39662 anchor = anchor.replace(/ /g, '_');
39665 link.attr('href', 'https://' + m[1] + '.wikipedia.org/wiki/' +
39666 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : ''));
39668 // unrecognized value format
39670 title.value(value);
39671 if (value && value !== '') {
39674 link.attr('href', 'https://en.wikipedia.org/wiki/Special:Search?search=' + value);
39678 i.entity = function(_) {
39682 i.focus = function() {
39683 title.node().focus();
39686 return d3.rebind(i, dispatch, 'on');
39688 iD.ui.intro.area = function(context, reveal) {
39689 var event = d3.dispatch('done'),
39693 title: 'intro.areas.title'
39696 step.enter = function() {
39697 var playground = [-85.63552, 41.94159],
39698 corner = [-85.63565411045074, 41.9417715536927];
39699 context.map().centerZoom(playground, 19);
39700 reveal('button.add-area',
39701 t('intro.areas.add', { button: iD.ui.intro.icon('#icon-area', 'pre-text') }),
39702 { tooltipClass: 'intro-areas-add' });
39704 context.on('enter.intro', addArea);
39706 function addArea(mode) {
39707 if (mode.id !== 'add-area') return;
39708 context.on('enter.intro', drawArea);
39710 var padding = 120 * Math.pow(2, context.map().zoom() - 19);
39711 var pointBox = iD.ui.intro.pad(corner, padding, context);
39712 reveal(pointBox, t('intro.areas.corner'));
39714 context.map().on('move.intro', function() {
39715 padding = 120 * Math.pow(2, context.map().zoom() - 19);
39716 pointBox = iD.ui.intro.pad(corner, padding, context);
39717 reveal(pointBox, t('intro.areas.corner'), {duration: 0});
39721 function drawArea(mode) {
39722 if (mode.id !== 'draw-area') return;
39723 context.on('enter.intro', enterSelect);
39725 var padding = 150 * Math.pow(2, context.map().zoom() - 19);
39726 var pointBox = iD.ui.intro.pad(playground, padding, context);
39727 reveal(pointBox, t('intro.areas.place'));
39729 context.map().on('move.intro', function() {
39730 padding = 150 * Math.pow(2, context.map().zoom() - 19);
39731 pointBox = iD.ui.intro.pad(playground, padding, context);
39732 reveal(pointBox, t('intro.areas.place'), {duration: 0});
39736 function enterSelect(mode) {
39737 if (mode.id !== 'select') return;
39738 context.map().on('move.intro', null);
39739 context.on('enter.intro', null);
39741 timeout = setTimeout(function() {
39742 reveal('.preset-search-input',
39743 t('intro.areas.search',
39744 { name: context.presets().item('leisure/playground').name() }));
39745 d3.select('.preset-search-input').on('keyup.intro', keySearch);
39749 function keySearch() {
39750 var first = d3.select('.preset-list-item:first-child');
39751 if (first.classed('preset-leisure-playground')) {
39752 reveal(first.select('.preset-list-button').node(), t('intro.areas.choose'));
39753 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
39754 d3.select('.preset-search-input').on('keyup.intro', null);
39758 function selectedPreset() {
39760 t('intro.areas.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39761 context.on('exit.intro', event.done);
39765 step.exit = function() {
39766 window.clearTimeout(timeout);
39767 context.on('enter.intro', null);
39768 context.on('exit.intro', null);
39769 context.history().on('change.intro', null);
39770 context.map().on('move.intro', null);
39771 d3.select('.preset-search-input').on('keyup.intro', null);
39774 return d3.rebind(step, event, 'on');
39776 iD.ui.intro.line = function(context, reveal) {
39777 var event = d3.dispatch('done'),
39781 title: 'intro.lines.title'
39784 function timeout(f, t) {
39785 timeouts.push(window.setTimeout(f, t));
39788 function eventCancel() {
39789 d3.event.stopPropagation();
39790 d3.event.preventDefault();
39793 step.enter = function() {
39794 var centroid = [-85.62830, 41.95699];
39795 var midpoint = [-85.62975395449628, 41.95787501510204];
39796 var start = [-85.6297754121684, 41.95805253325314];
39797 var intersection = [-85.62974496187628, 41.95742515554585];
39799 context.map().centerZoom(start, 18);
39800 reveal('button.add-line',
39801 t('intro.lines.add', { button: iD.ui.intro.icon('#icon-line', 'pre-text') }),
39802 { tooltipClass: 'intro-lines-add' });
39804 context.on('enter.intro', addLine);
39806 function addLine(mode) {
39807 if (mode.id !== 'add-line') return;
39808 context.on('enter.intro', drawLine);
39810 var padding = 150 * Math.pow(2, context.map().zoom() - 18);
39811 var pointBox = iD.ui.intro.pad(start, padding, context);
39812 reveal(pointBox, t('intro.lines.start'));
39814 context.map().on('move.intro', function() {
39815 padding = 150 * Math.pow(2, context.map().zoom() - 18);
39816 pointBox = iD.ui.intro.pad(start, padding, context);
39817 reveal(pointBox, t('intro.lines.start'), {duration: 0});
39821 function drawLine(mode) {
39822 if (mode.id !== 'draw-line') return;
39823 context.history().on('change.intro', addIntersection);
39824 context.on('enter.intro', retry);
39826 var padding = 300 * Math.pow(2, context.map().zoom() - 19);
39827 var pointBox = iD.ui.intro.pad(midpoint, padding, context);
39828 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}));
39830 context.map().on('move.intro', function() {
39831 padding = 300 * Math.pow(2, context.map().zoom() - 19);
39832 pointBox = iD.ui.intro.pad(midpoint, padding, context);
39833 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}), {duration: 0});
39837 // ended line before creating intersection
39838 function retry(mode) {
39839 if (mode.id !== 'select') return;
39840 var pointBox = iD.ui.intro.pad(intersection, 30, context),
39841 ids = mode.selectedIDs();
39842 reveal(pointBox, t('intro.lines.restart', {name: t('intro.graph.flower_st')}));
39843 d3.select(window).on('mousedown.intro', eventCancel, true);
39845 timeout(function() {
39846 context.replace(iD.actions.DeleteMultiple(ids));
39852 function addIntersection(changes) {
39853 if ( _.any(changes.created(), function(d) {
39854 return d.type === 'node' && context.graph().parentWays(d).length > 1;
39856 context.history().on('change.intro', null);
39857 context.on('enter.intro', enterSelect);
39859 var padding = 900 * Math.pow(2, context.map().zoom() - 19);
39860 var pointBox = iD.ui.intro.pad(centroid, padding, context);
39861 reveal(pointBox, t('intro.lines.finish'));
39863 context.map().on('move.intro', function() {
39864 padding = 900 * Math.pow(2, context.map().zoom() - 19);
39865 pointBox = iD.ui.intro.pad(centroid, padding, context);
39866 reveal(pointBox, t('intro.lines.finish'), {duration: 0});
39871 function enterSelect(mode) {
39872 if (mode.id !== 'select') return;
39873 context.map().on('move.intro', null);
39874 context.on('enter.intro', null);
39875 d3.select('#curtain').style('pointer-events', 'all');
39880 function presetCategory() {
39881 timeout(function() {
39882 d3.select('#curtain').style('pointer-events', 'none');
39883 var road = d3.select('.preset-category-road .preset-list-button');
39884 reveal(road.node(), t('intro.lines.road'));
39885 road.one('click.intro', roadCategory);
39889 function roadCategory() {
39890 timeout(function() {
39891 var grid = d3.select('.subgrid');
39892 reveal(grid.node(), t('intro.lines.residential'));
39893 grid.selectAll(':not(.preset-highway-residential) .preset-list-button')
39894 .one('click.intro', retryPreset);
39895 grid.selectAll('.preset-highway-residential .preset-list-button')
39896 .one('click.intro', roadDetails);
39900 // selected wrong road type
39901 function retryPreset() {
39902 timeout(function() {
39903 var preset = d3.select('.entity-editor-pane .preset-list-button');
39904 reveal(preset.node(), t('intro.lines.wrong_preset'));
39905 preset.one('click.intro', presetCategory);
39909 function roadDetails() {
39911 t('intro.lines.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
39912 context.on('exit.intro', event.done);
39917 step.exit = function() {
39918 d3.select(window).on('mousedown.intro', null, true);
39919 d3.select('#curtain').style('pointer-events', 'none');
39920 timeouts.forEach(window.clearTimeout);
39921 context.on('enter.intro', null);
39922 context.on('exit.intro', null);
39923 context.map().on('move.intro', null);
39924 context.history().on('change.intro', null);
39927 return d3.rebind(step, event, 'on');
39929 iD.ui.intro.navigation = function(context, reveal) {
39930 var event = d3.dispatch('done'),
39934 title: 'intro.navigation.title'
39937 function set(f, t) {
39938 timeouts.push(window.setTimeout(f, t));
39941 function eventCancel() {
39942 d3.event.stopPropagation();
39943 d3.event.preventDefault();
39946 step.enter = function() {
39947 var rect = context.surfaceRect(),
39949 left: rect.left + 10,
39950 top: rect.top + 70,
39951 width: rect.width - 70,
39952 height: rect.height - 170
39955 context.map().centerZoom([-85.63591, 41.94285], 19);
39957 reveal(map, t('intro.navigation.drag'));
39959 context.map().on('move.intro', _.debounce(function() {
39960 context.map().on('move.intro', null);
39962 context.on('enter.intro', inspectTownHall);
39965 function townhall() {
39966 var hall = [-85.63645945147184, 41.942986488012565];
39968 var point = context.projection(hall);
39969 if (point[0] < 0 || point[0] > rect.width ||
39970 point[1] < 0 || point[1] > rect.height) {
39971 context.map().center(hall);
39974 var box = iD.ui.intro.pointBox(hall, context);
39975 reveal(box, t('intro.navigation.select'));
39977 context.map().on('move.intro', function() {
39978 var box = iD.ui.intro.pointBox(hall, context);
39979 reveal(box, t('intro.navigation.select'), {duration: 0});
39983 function inspectTownHall(mode) {
39984 if (mode.id !== 'select') return;
39985 context.on('enter.intro', null);
39986 context.map().on('move.intro', null);
39988 reveal('.entity-editor-pane',
39989 t('intro.navigation.pane', { button: iD.ui.intro.icon('#icon-close', 'pre-text') }));
39990 context.on('exit.intro', streetSearch);
39994 function streetSearch() {
39995 context.on('exit.intro', null);
39996 reveal('.search-header input',
39997 t('intro.navigation.search', { name: t('intro.graph.spring_st') }));
39998 d3.select('.search-header input').on('keyup.intro', searchResult);
40001 function searchResult() {
40002 var first = d3.select('.feature-list-item:nth-child(0n+2)'), // skip No Results item
40003 firstName = first.select('.entity-name'),
40004 name = t('intro.graph.spring_st');
40006 if (!firstName.empty() && firstName.text() === name) {
40007 reveal(first.node(), t('intro.navigation.choose', { name: name }));
40008 context.on('exit.intro', selectedStreet);
40009 d3.select('.search-header input')
40010 .on('keydown.intro', eventCancel, true)
40011 .on('keyup.intro', null);
40015 function selectedStreet() {
40016 var springSt = [-85.63585099140167, 41.942506848938926];
40017 context.map().center(springSt);
40018 context.on('exit.intro', event.done);
40020 reveal('.entity-editor-pane',
40021 t('intro.navigation.chosen', {
40022 name: t('intro.graph.spring_st'),
40023 button: iD.ui.intro.icon('#icon-close', 'pre-text')
40029 step.exit = function() {
40030 timeouts.forEach(window.clearTimeout);
40031 context.map().on('move.intro', null);
40032 context.on('enter.intro', null);
40033 context.on('exit.intro', null);
40034 d3.select('.search-header input')
40035 .on('keydown.intro', null)
40036 .on('keyup.intro', null);
40039 return d3.rebind(step, event, 'on');
40041 iD.ui.intro.point = function(context, reveal) {
40042 var event = d3.dispatch('done'),
40046 title: 'intro.points.title'
40049 function setTimeout(f, t) {
40050 timeouts.push(window.setTimeout(f, t));
40053 function eventCancel() {
40054 d3.event.stopPropagation();
40055 d3.event.preventDefault();
40058 step.enter = function() {
40059 context.map().centerZoom([-85.63279, 41.94394], 19);
40060 reveal('button.add-point',
40061 t('intro.points.add', { button: iD.ui.intro.icon('#icon-point', 'pre-text') }),
40062 { tooltipClass: 'intro-points-add' });
40064 var corner = [-85.632481,41.944094];
40066 context.on('enter.intro', addPoint);
40068 function addPoint(mode) {
40069 if (mode.id !== 'add-point') return;
40070 context.on('enter.intro', enterSelect);
40072 var pointBox = iD.ui.intro.pad(corner, 150, context);
40073 reveal(pointBox, t('intro.points.place'));
40075 context.map().on('move.intro', function() {
40076 pointBox = iD.ui.intro.pad(corner, 150, context);
40077 reveal(pointBox, t('intro.points.place'), {duration: 0});
40081 function enterSelect(mode) {
40082 if (mode.id !== 'select') return;
40083 context.map().on('move.intro', null);
40084 context.on('enter.intro', null);
40086 setTimeout(function() {
40087 reveal('.preset-search-input',
40088 t('intro.points.search', {name: context.presets().item('amenity/cafe').name()}));
40089 d3.select('.preset-search-input').on('keyup.intro', keySearch);
40093 function keySearch() {
40094 var first = d3.select('.preset-list-item:first-child');
40095 if (first.classed('preset-amenity-cafe')) {
40096 reveal(first.select('.preset-list-button').node(), t('intro.points.choose'));
40097 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
40098 d3.select('.preset-search-input')
40099 .on('keydown.intro', eventCancel, true)
40100 .on('keyup.intro', null);
40104 function selectedPreset() {
40105 setTimeout(function() {
40106 reveal('.entity-editor-pane', t('intro.points.describe'), {tooltipClass: 'intro-points-describe'});
40107 context.history().on('change.intro', closeEditor);
40108 context.on('exit.intro', selectPoint);
40112 function closeEditor() {
40113 d3.select('.preset-search-input').on('keydown.intro', null);
40114 context.history().on('change.intro', null);
40115 reveal('.entity-editor-pane',
40116 t('intro.points.close', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
40119 function selectPoint() {
40120 context.on('exit.intro', null);
40121 context.history().on('change.intro', null);
40122 context.on('enter.intro', enterReselect);
40124 var pointBox = iD.ui.intro.pad(corner, 150, context);
40125 reveal(pointBox, t('intro.points.reselect'));
40127 context.map().on('move.intro', function() {
40128 pointBox = iD.ui.intro.pad(corner, 150, context);
40129 reveal(pointBox, t('intro.points.reselect'), {duration: 0});
40133 function enterReselect(mode) {
40134 if (mode.id !== 'select') return;
40135 context.map().on('move.intro', null);
40136 context.on('enter.intro', null);
40138 setTimeout(function() {
40139 reveal('.entity-editor-pane',
40140 t('intro.points.fixname', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
40141 context.on('exit.intro', deletePoint);
40145 function deletePoint() {
40146 context.on('exit.intro', null);
40147 context.on('enter.intro', enterDelete);
40149 var pointBox = iD.ui.intro.pad(corner, 150, context);
40150 reveal(pointBox, t('intro.points.reselect_delete'));
40152 context.map().on('move.intro', function() {
40153 pointBox = iD.ui.intro.pad(corner, 150, context);
40154 reveal(pointBox, t('intro.points.reselect_delete'), {duration: 0});
40158 function enterDelete(mode) {
40159 if (mode.id !== 'select') return;
40160 context.map().on('move.intro', null);
40161 context.on('enter.intro', null);
40162 context.on('exit.intro', deletePoint);
40163 context.map().on('move.intro', deletePoint);
40164 context.history().on('change.intro', deleted);
40166 setTimeout(function() {
40167 var node = d3.select('.radial-menu-item-delete').node();
40168 var pointBox = iD.ui.intro.pad(node.getBoundingClientRect(), 50, context);
40170 t('intro.points.delete', { button: iD.ui.intro.icon('#operation-delete', 'pre-text') }));
40174 function deleted(changed) {
40175 if (changed.deleted().length) event.done();
40180 step.exit = function() {
40181 timeouts.forEach(window.clearTimeout);
40182 context.on('exit.intro', null);
40183 context.on('enter.intro', null);
40184 context.map().on('move.intro', null);
40185 context.history().on('change.intro', null);
40186 d3.select('.preset-search-input')
40187 .on('keyup.intro', null)
40188 .on('keydown.intro', null);
40191 return d3.rebind(step, event, 'on');
40193 iD.ui.intro.startEditing = function(context, reveal) {
40194 var event = d3.dispatch('done', 'startEditing'),
40199 title: 'intro.startediting.title'
40202 function timeout(f, t) {
40203 timeouts.push(window.setTimeout(f, t));
40206 step.enter = function() {
40207 reveal('.map-control.help-control',
40208 t('intro.startediting.help', { button: iD.ui.intro.icon('#icon-help', 'pre-text') }));
40210 timeout(function() {
40211 reveal('#bar button.save', t('intro.startediting.save'));
40214 timeout(function() {
40215 reveal('#surface');
40218 timeout(function() {
40219 modal = iD.ui.modal(context.container());
40221 modal.select('.modal')
40222 .attr('class', 'modal-splash modal col6');
40224 modal.selectAll('.close').remove();
40226 var startbutton = modal.select('.content')
40227 .attr('class', 'fillL')
40229 .attr('class', 'modal-section huge-modal-button')
40230 .on('click', function() {
40234 startbutton.append('div')
40235 .attr('class','illustration');
40236 startbutton.append('h2')
40237 .text(t('intro.startediting.start'));
40239 event.startEditing();
40243 step.exit = function() {
40244 if (modal) modal.remove();
40245 timeouts.forEach(window.clearTimeout);
40248 return d3.rebind(step, event, 'on');
40250 iD.presets = function() {
40252 // an iD.presets.Collection with methods for
40253 // loading new data and returning defaults
40255 var all = iD.presets.Collection([]),
40256 defaults = { area: all, line: all, point: all, vertex: all, relation: all },
40259 recent = iD.presets.Collection([]);
40261 // Index of presets by (geometry, tag key).
40270 all.match = function(entity, resolver) {
40271 var geometry = entity.geometry(resolver),
40272 geometryMatches = index[geometry],
40276 for (var k in entity.tags) {
40277 var keyMatches = geometryMatches[k];
40278 if (!keyMatches) continue;
40280 for (var i = 0; i < keyMatches.length; i++) {
40281 var score = keyMatches[i].matchScore(entity);
40282 if (score > best) {
40284 match = keyMatches[i];
40289 return match || all.item(geometry);
40292 // Because of the open nature of tagging, iD will never have a complete
40293 // list of tags used in OSM, so we want it to have logic like "assume
40294 // that a closed way with an amenity tag is an area, unless the amenity
40295 // is one of these specific types". This function computes a structure
40296 // that allows testing of such conditions, based on the presets designated
40297 // as as supporting (or not supporting) the area geometry.
40299 // The returned object L is a whitelist/blacklist of tags. A closed way
40300 // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
40301 // (see `iD.Way#isArea()`). In other words, the keys of L form the whitelist,
40302 // and the subkeys form the blacklist.
40303 all.areaKeys = function() {
40305 ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],
40306 presets = _.reject(all.collection, 'suggestion');
40309 presets.forEach(function(d) {
40310 for (var key in d.tags) break;
40312 if (ignore.indexOf(key) !== -1) return;
40314 if (d.geometry.indexOf('area') !== -1) {
40315 areaKeys[key] = areaKeys[key] || {};
40320 presets.forEach(function(d) {
40321 for (var key in d.tags) break;
40323 if (ignore.indexOf(key) !== -1) return;
40325 var value = d.tags[key];
40326 if (d.geometry.indexOf('area') === -1 &&
40327 d.geometry.indexOf('line') !== -1 &&
40328 key in areaKeys && value !== '*') {
40329 areaKeys[key][value] = true;
40336 all.load = function(d) {
40339 _.forEach(d.fields, function(d, id) {
40340 fields[id] = iD.presets.Field(id, d);
40341 if (d.universal) universal.push(fields[id]);
40346 _.forEach(d.presets, function(d, id) {
40347 all.collection.push(iD.presets.Preset(id, d, fields));
40351 if (d.categories) {
40352 _.forEach(d.categories, function(d, id) {
40353 all.collection.push(iD.presets.Category(id, d, all));
40358 var getItem = _.bind(all.item, all);
40360 area: iD.presets.Collection(d.defaults.area.map(getItem)),
40361 line: iD.presets.Collection(d.defaults.line.map(getItem)),
40362 point: iD.presets.Collection(d.defaults.point.map(getItem)),
40363 vertex: iD.presets.Collection(d.defaults.vertex.map(getItem)),
40364 relation: iD.presets.Collection(d.defaults.relation.map(getItem))
40368 for (var i = 0; i < all.collection.length; i++) {
40369 var preset = all.collection[i],
40370 geometry = preset.geometry;
40372 for (var j = 0; j < geometry.length; j++) {
40373 var g = index[geometry[j]];
40374 for (var k in preset.tags) {
40375 (g[k] = g[k] || []).push(preset);
40383 all.field = function(id) {
40387 all.universal = function() {
40391 all.defaults = function(geometry, n) {
40392 var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
40393 def = _.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
40394 return iD.presets.Collection(_.unique(rec.concat(def).concat(all.item(geometry))));
40397 all.choose = function(preset) {
40398 if (!preset.isFallback()) {
40399 recent = iD.presets.Collection(_.unique([preset].concat(recent.collection)));
40406 iD.presets.Category = function(id, category, all) {
40407 category = _.clone(category);
40411 category.members = iD.presets.Collection(category.members.map(function(id) {
40412 return all.item(id);
40415 category.matchGeometry = function(geometry) {
40416 return category.geometry.indexOf(geometry) >= 0;
40419 category.matchScore = function() { return -1; };
40421 category.name = function() {
40422 return t('presets.categories.' + id + '.name', {'default': id});
40425 category.terms = function() {
40431 iD.presets.Collection = function(collection) {
40433 var maxSearchResults = 50,
40434 maxSuggestionResults = 10;
40438 collection: collection,
40440 item: function(id) {
40441 return _.find(collection, function(d) {
40442 return d.id === id;
40446 matchGeometry: function(geometry) {
40447 return iD.presets.Collection(collection.filter(function(d) {
40448 return d.matchGeometry(geometry);
40452 search: function(value, geometry) {
40453 if (!value) return this;
40455 value = value.toLowerCase();
40457 var searchable = _.filter(collection, function(a) {
40458 return a.searchable !== false && a.suggestion !== true;
40460 suggestions = _.filter(collection, function(a) {
40461 return a.suggestion === true;
40464 function leading(a) {
40465 var index = a.indexOf(value);
40466 return index === 0 || a[index - 1] === ' ';
40469 // matches value to preset.name
40470 var leading_name = _.filter(searchable, function(a) {
40471 return leading(a.name().toLowerCase());
40472 }).sort(function(a, b) {
40473 var i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
40474 if (i === 0) return a.name().length - b.name().length;
40478 // matches value to preset.terms values
40479 var leading_terms = _.filter(searchable, function(a) {
40480 return _.any(a.terms() || [], leading);
40483 // matches value to preset.tags values
40484 var leading_tag_values = _.filter(searchable, function(a) {
40485 return _.any(_.without(_.values(a.tags || {}), '*'), leading);
40489 // finds close matches to value in preset.name
40490 var levenstein_name = searchable.map(function(a) {
40493 dist: iD.util.editDistance(value, a.name().toLowerCase())
40495 }).filter(function(a) {
40496 return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
40497 }).sort(function(a, b) {
40498 return a.dist - b.dist;
40499 }).map(function(a) {
40503 // finds close matches to value in preset.terms
40504 var leventstein_terms = _.filter(searchable, function(a) {
40505 return _.any(a.terms() || [], function(b) {
40506 return iD.util.editDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
40510 function suggestionName(name) {
40511 var nameArray = name.split(' - ');
40512 if (nameArray.length > 1) {
40513 name = nameArray.slice(0, nameArray.length-1).join(' - ');
40515 return name.toLowerCase();
40518 var leading_suggestions = _.filter(suggestions, function(a) {
40519 return leading(suggestionName(a.name()));
40520 }).sort(function(a, b) {
40521 a = suggestionName(a.name());
40522 b = suggestionName(b.name());
40523 var i = a.indexOf(value) - b.indexOf(value);
40524 if (i === 0) return a.length - b.length;
40528 var leven_suggestions = suggestions.map(function(a) {
40531 dist: iD.util.editDistance(value, suggestionName(a.name()))
40533 }).filter(function(a) {
40534 return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
40535 }).sort(function(a, b) {
40536 return a.dist - b.dist;
40537 }).map(function(a) {
40541 var other = presets.item(geometry);
40543 var results = leading_name.concat(
40545 leading_tag_values,
40546 leading_suggestions.slice(0, maxSuggestionResults+5),
40549 leven_suggestions.slice(0, maxSuggestionResults)
40550 ).slice(0, maxSearchResults-1);
40552 return iD.presets.Collection(_.unique(
40553 results.concat(other)
40560 iD.presets.Field = function(id, field) {
40561 field = _.clone(field);
40565 field.matchGeometry = function(geometry) {
40566 return !field.geometry || field.geometry === geometry;
40569 field.t = function(scope, options) {
40570 return t('presets.fields.' + id + '.' + scope, options);
40573 field.label = function() {
40574 return field.t('label', {'default': id});
40577 var placeholder = field.placeholder;
40578 field.placeholder = function() {
40579 return field.t('placeholder', {'default': placeholder});
40584 iD.presets.Preset = function(id, preset, fields) {
40585 preset = _.clone(preset);
40588 preset.fields = (preset.fields || []).map(getFields);
40589 preset.geometry = (preset.geometry || []);
40591 function getFields(f) {
40595 preset.matchGeometry = function(geometry) {
40596 return preset.geometry.indexOf(geometry) >= 0;
40599 var matchScore = preset.matchScore || 1;
40600 preset.matchScore = function(entity) {
40601 var tags = preset.tags,
40604 for (var t in tags) {
40605 if (entity.tags[t] === tags[t]) {
40606 score += matchScore;
40607 } else if (tags[t] === '*' && t in entity.tags) {
40608 score += matchScore / 2;
40617 preset.t = function(scope, options) {
40618 return t('presets.presets.' + id + '.' + scope, options);
40621 var name = preset.name;
40622 preset.name = function() {
40623 if (preset.suggestion) {
40624 id = id.split('/');
40625 id = id[0] + '/' + id[1];
40626 return name + ' - ' + t('presets.presets.' + id + '.name');
40628 return preset.t('name', {'default': name});
40631 preset.terms = function() {
40632 return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
40635 preset.isFallback = function() {
40636 var tagCount = Object.keys(preset.tags).length;
40637 return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
40640 preset.reference = function(geometry) {
40641 var key = Object.keys(preset.tags)[0],
40642 value = preset.tags[key];
40644 if (geometry === 'relation' && key === 'type') {
40645 return { rtype: value };
40646 } else if (value === '*') {
40647 return { key: key };
40649 return { key: key, value: value };
40653 var removeTags = preset.removeTags || preset.tags;
40654 preset.removeTags = function(tags, geometry) {
40655 tags = _.omit(tags, _.keys(removeTags));
40657 for (var f in preset.fields) {
40658 var field = preset.fields[f];
40659 if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
40660 delete tags[field.key];
40668 var applyTags = preset.addTags || preset.tags;
40669 preset.applyTags = function(tags, geometry) {
40672 tags = _.clone(tags);
40674 for (k in applyTags) {
40675 if (applyTags[k] === '*') {
40678 tags[k] = applyTags[k];
40682 // Add area=yes if necessary.
40683 // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
40684 // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
40685 // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
40686 if (geometry === 'area') {
40687 var needsAreaTag = true;
40688 if (preset.geometry.indexOf('line') === -1) {
40689 for (k in applyTags) {
40690 if (k in iD.areaKeys) {
40691 needsAreaTag = false;
40696 if (needsAreaTag) {
40701 for (var f in preset.fields) {
40702 var field = preset.fields[f];
40703 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
40704 tags[field.key] = field.default;
40713 iD.validations = {};
40714 iD.validations.DeprecatedTag = function() {
40716 var validation = function(changes) {
40718 for (var i = 0; i < changes.created.length; i++) {
40719 var change = changes.created[i],
40720 deprecatedTags = change.deprecatedTags();
40722 if (!_.isEmpty(deprecatedTags)) {
40723 var tags = iD.util.tagText({ tags: deprecatedTags });
40725 id: 'deprecated_tags',
40726 message: t('validations.deprecated_tags', { tags: tags }),
40736 iD.validations.ManyDeletions = function() {
40737 var threshold = 100;
40739 var validation = function(changes) {
40741 if (changes.deleted.length > threshold) {
40743 id: 'many_deletions',
40744 message: t('validations.many_deletions', { n: changes.deleted.length })
40752 iD.validations.MissingTag = function() {
40754 var validation = function(changes, graph) {
40756 for (var i = 0; i < changes.created.length; i++) {
40757 var change = changes.created[i],
40758 geometry = change.geometry(graph);
40760 if ((geometry === 'point' || geometry === 'line' || geometry === 'area') && !change.isUsed(graph)) {
40763 message: t('validations.untagged_' + geometry),
40764 tooltip: t('validations.untagged_' + geometry + '_tooltip'),
40774 iD.validations.TagSuggestsArea = function() {
40776 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
40777 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
40778 function tagSuggestsArea(tags) {
40779 if (_.isEmpty(tags)) return false;
40781 var presence = ['landuse', 'amenities', 'tourism', 'shop'];
40782 for (var i = 0; i < presence.length; i++) {
40783 if (tags[presence[i]] !== undefined) {
40784 return presence[i] + '=' + tags[presence[i]];
40788 if (tags.building && tags.building === 'yes') return 'building=yes';
40791 var validation = function(changes, graph) {
40793 for (var i = 0; i < changes.created.length; i++) {
40794 var change = changes.created[i],
40795 geometry = change.geometry(graph),
40796 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
40800 id: 'tag_suggests_area',
40801 message: t('validations.tag_suggests_area', { tag: suggestion }),
40812 window.locale = { _current: 'en' };
40814 locale.current = function(_) {
40815 if (!arguments.length) return locale._current;
40816 if (locale[_] !== undefined) locale._current = _;
40817 else if (locale[_.split('-')[0]]) locale._current = _.split('-')[0];
40821 function t(s, o, loc) {
40822 loc = loc || locale._current;
40824 var path = s.split(".").reverse(),
40827 while (rep !== undefined && path.length) rep = rep[path.pop()];
40829 if (rep !== undefined) {
40830 if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
40834 if (loc !== 'en') {
40835 return t(s, o, 'en');
40838 if (o && 'default' in o) {
40839 return o['default'];
40842 var missing = 'Missing ' + loc + ' translation: ' + s;
40843 if (typeof console !== "undefined") console.error(missing);
40847 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"],["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"],["South Azerbaijani","تۆرکجه","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","गोवा कोंकणी / Gova 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","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"],["Lojban","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 (Netherlands)","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":{"id":0},"geometry":{"type":"MultiPolygon","coordinates":[[[[-1.426496,50.639342],[-1.445953,50.648139],[-1.452789,50.654283],[-1.485951,50.669338],[-1.497426,50.672309],[-1.535146,50.669379],[-1.551503,50.665107],[-1.569488,50.658026],[-1.545318,50.686103],[-1.50593,50.707709],[-1.418691,50.733791],[-1.420888,50.730455],[-1.423451,50.7237],[-1.425364,50.72012],[-1.400868,50.721991],[-1.377553,50.734198],[-1.343495,50.761054],[-1.318512,50.772162],[-1.295766,50.773179],[-1.144276,50.733791],[-1.119537,50.734198],[-1.10912,50.732856],[-1.097035,50.726955],[-1.096425,50.724433],[-1.097646,50.71601],[-1.097035,50.713324],[-1.094228,50.712633],[-1.085561,50.714016],[-1.082753,50.713324],[-1.062327,50.692816],[-1.062327,50.685289],[-1.066965,50.685248],[-1.069651,50.683498],[-1.071889,50.680976],[-1.075307,50.678534],[-1.112701,50.671454],[-1.128651,50.666449],[-1.156361,50.650784],[-1.162221,50.645982],[-1.164703,50.640937],[-1.164666,50.639543],[-1.426496,50.639342]]],[[[-7.240314,55.050389],[-7.013736,55.1615],[-6.958913,55.20349],[-6.571562,55.268366],[-6.509633,55.31398],[-6.226158,55.344406],[-6.07105,55.25001],[-5.712696,55.017635],[-5.242021,54.415204],[-5.695554,54.14284],[-5.72473,54.07455],[-6.041633,54.006238],[-6.153953,54.054931],[-6.220539,54.098803],[-6.242502,54.099758],[-6.263661,54.104682],[-6.269887,54.097927],[-6.28465,54.105226],[-6.299585,54.104037],[-6.313796,54.099696],[-6.327128,54.097888],[-6.338962,54.102952],[-6.346662,54.109877],[-6.354827,54.110652],[-6.368108,54.097319],[-6.369348,54.091118],[-6.367643,54.083418],[-6.366919,54.075098],[-6.371157,54.066778],[-6.377513,54.063264],[-6.401026,54.060887],[-6.426761,54.05541],[-6.433892,54.055306],[-6.4403,54.057993],[-6.446243,54.062438],[-6.450222,54.066675],[-6.450894,54.068432],[-6.47854,54.067709],[-6.564013,54.04895],[-6.571868,54.049519],[-6.587164,54.053343],[-6.595071,54.052412],[-6.60029,54.04895],[-6.605217,54.044475],[-6.610987,54.039235],[-6.616465,54.037271],[-6.630624,54.041819],[-6.657289,54.061146],[-6.672534,54.068432],[-6.657082,54.091945],[-6.655791,54.103314],[-6.666436,54.114786],[-6.643957,54.131839],[-6.634552,54.150133],[-6.640339,54.168013],[-6.648448,54.173665],[-6.663025,54.183826],[-6.683954,54.194368],[-6.694651,54.197985],[-6.706537,54.198915],[-6.717234,54.195143],[-6.724779,54.188631],[-6.73284,54.183567],[-6.744777,54.184187],[-6.766481,54.192352],[-6.787824,54.202998],[-6.807358,54.21633],[-6.823946,54.23235],[-6.829733,54.242375],[-6.833196,54.25209],[-6.837743,54.260513],[-6.846683,54.266456],[-6.882185,54.277257],[-6.864667,54.282734],[-6.856657,54.292811],[-6.858414,54.307332],[-6.870015,54.326001],[-6.879705,54.341594],[-6.885957,54.345624],[-6.897895,54.346193],[-6.905956,54.349035],[-6.915051,54.365933],[-6.922028,54.372703],[-6.984091,54.403089],[-7.017836,54.413166],[-7.049255,54.411512],[-7.078504,54.394717],[-7.127028,54.349759],[-7.159894,54.335186],[-7.168059,54.335031],[-7.185629,54.336943],[-7.18947,54.335692],[-7.19245,54.334721],[-7.193949,54.329967],[-7.191468,54.323869],[-7.187644,54.318804],[-7.185009,54.317254],[-7.184647,54.316634],[-7.192399,54.307384],[-7.193691,54.307539],[-7.199168,54.303457],[-7.206661,54.304903],[-7.211467,54.30418],[-7.209038,54.293431],[-7.1755,54.283664],[-7.181495,54.269763],[-7.14589,54.25209],[-7.159739,54.24067],[-7.153331,54.224237],[-7.174725,54.216072],[-7.229502,54.207545],[-7.240871,54.202326],[-7.249088,54.197416],[-7.255496,54.190854],[-7.261128,54.18088],[-7.256322,54.176901],[-7.247021,54.17225],[-7.24578,54.166979],[-7.265366,54.16114],[-7.26087,54.151166],[-7.263505,54.140986],[-7.27074,54.132253],[-7.280042,54.126155],[-7.293788,54.122021],[-7.297353,54.125896],[-7.29632,54.134991],[-7.296423,54.146515],[-7.295028,54.155404],[-7.292134,54.162638],[-7.295545,54.165119],[-7.325982,54.154577],[-7.333165,54.149409],[-7.333165,54.142743],[-7.310324,54.114683],[-7.316489,54.11428],[-7.326964,54.113597],[-7.375488,54.123312],[-7.390216,54.121194],[-7.39466,54.121917],[-7.396624,54.126258],[-7.403962,54.135043],[-7.41223,54.136438],[-7.422255,54.135456],[-7.425769,54.136955],[-7.414659,54.145688],[-7.439619,54.146929],[-7.480753,54.127653],[-7.502302,54.125121],[-7.609014,54.139901],[-7.620796,54.144965],[-7.624052,54.153336],[-7.625706,54.162173],[-7.632682,54.168529],[-7.70477,54.200362],[-7.722599,54.202326],[-7.782078,54.2],[-7.836959,54.204341],[-7.856441,54.211421],[-7.86967,54.226872],[-7.873649,54.271055],[-7.880264,54.287023],[-7.894966,54.293586],[-7.93411,54.297049],[-7.942075,54.298873],[-7.950802,54.300873],[-7.96801,54.31219],[-7.981033,54.326556],[-8.002194,54.357923],[-8.03134,54.358027],[-8.05648,54.365882],[-8.079941,54.380196],[-8.122419,54.415233],[-8.146346,54.430736],[-8.156035,54.439055],[-8.158128,54.447117],[-8.161177,54.454817],[-8.173837,54.461741],[-8.168467,54.463477],[-8.15017,54.46939],[-8.097046,54.478588],[-8.072448,54.487063],[-8.060976,54.493316],[-8.05586,54.497553],[-8.043561,54.512229],[-8.023278,54.529696],[-8.002194,54.543442],[-7.926411,54.533055],[-7.887137,54.532125],[-7.848844,54.54091],[-7.749264,54.596152],[-7.707871,54.604162],[-7.707944,54.604708],[-7.707951,54.604763],[-7.710558,54.624264],[-7.721204,54.625866],[-7.736758,54.619251],[-7.753553,54.614497],[-7.769159,54.618011],[-7.801199,54.634806],[-7.814996,54.639457],[-7.822541,54.638113],[-7.838044,54.63124],[-7.846416,54.631447],[-7.85427,54.636408],[-7.864347,54.649069],[-7.872771,54.652221],[-7.890082,54.655063],[-7.906619,54.661316],[-7.914835,54.671651],[-7.907135,54.686689],[-7.913233,54.688653],[-7.929666,54.696714],[-7.880109,54.711029],[-7.845899,54.731027],[-7.832153,54.730614],[-7.803576,54.716145],[-7.770503,54.706016],[-7.736603,54.707463],[-7.70229,54.718883],[-7.667512,54.738779],[-7.649683,54.744877],[-7.61537,54.739347],[-7.585398,54.744722],[-7.566639,54.738675],[-7.556149,54.738365],[-7.543075,54.741673],[-7.543023,54.743791],[-7.548398,54.747202],[-7.551705,54.754695],[-7.549741,54.779603],[-7.543385,54.793091],[-7.470831,54.845284],[-7.45507,54.863009],[-7.444735,54.884455],[-7.444735,54.894893],[-7.448972,54.920318],[-7.445251,54.932152],[-7.436983,54.938301],[-7.417139,54.943056],[-7.415755,54.944372],[-7.408665,54.951117],[-7.407424,54.959437],[-7.413109,54.984965],[-7.409078,54.992045],[-7.403755,54.99313],[-7.40112,54.994836],[-7.405254,55.003569],[-7.376987,55.02889],[-7.366962,55.035557],[-7.355024,55.040931],[-7.291152,55.046615],[-7.282987,55.051835],[-7.275288,55.058863],[-7.266503,55.065167],[-7.247097,55.069328],[-7.2471,55.069322],[-7.256744,55.050686],[-7.240956,55.050279],[-7.240314,55.050389]]],[[[-13.688588,57.596259],[-13.690419,57.596259],[-13.691314,57.596503],[-13.691314,57.597154],[-13.690419,57.597805],[-13.688588,57.597805],[-13.687652,57.597154],[-13.687652,57.596869],[-13.688588,57.596259]]],[[[-4.839121,54.469789],[-4.979941,54.457977],[-5.343644,54.878637],[-5.308469,55.176452],[-6.272566,55.418443],[-8.690528,57.833706],[-6.344705,59.061083],[-4.204785,58.63305],[-2.31566,60.699068],[-1.695335,60.76432],[-1.58092,60.866001],[-0.17022,60.897204],[-0.800508,59.770037],[-1.292368,57.732574],[-1.850077,55.766368],[-1.73054,55.782219],[1.892395,52.815229],[1.742775,51.364209],[1.080173,50.847526],[0.000774,50.664982],[-0.162997,50.752401],[-0.725152,50.731879],[-0.768853,50.741516],[-0.770985,50.736884],[-0.789947,50.730048],[-0.812815,50.734768],[-0.877742,50.761156],[-0.942879,50.758338],[-0.992581,50.737379],[-1.18513,50.766989],[-1.282741,50.792353],[-1.375004,50.772063],[-1.523427,50.719605],[-1.630649,50.695128],[-1.663617,50.670508],[-1.498021,50.40831],[-4.097427,49.735486],[-6.825199,49.700905],[-5.541541,51.446591],[-6.03361,51.732369],[-4.791746,52.635365],[-4.969244,52.637413],[-5.049473,53.131209],[-4.787393,53.409491],[-4.734148,53.424866],[-4.917096,53.508212],[-4.839121,54.469789]]]]}},{"type":"Feature","properties":{"id":0},"geometry":{"type":"MultiPolygon","coordinates":[[[[-157.018938,19.300864],[-179.437336,27.295312],[-179.480084,28.991459],[-168.707465,26.30325],[-163.107414,24.60499],[-153.841679,20.079306],[-154.233846,19.433391],[-153.61725,18.900587],[-154.429471,18.171036],[-156.780638,18.718492],[-157.018938,19.300864]]],[[[-78.91269,43.037032],[-78.964351,42.976393],[-78.981718,42.979043],[-78.998055,42.991111],[-79.01189,43.004358],[-79.022046,43.010539],[-79.023076,43.017015],[-79.00983,43.050867],[-79.011449,43.065291],[-78.993051,43.066174],[-78.975536,43.069707],[-78.958905,43.070884],[-78.943304,43.065291],[-78.917399,43.058521],[-78.908569,43.049396],[-78.91269,43.037032]]],[[[-123.03529,48.992515],[-123.035308,48.992499],[-123.045277,48.984361],[-123.08849,48.972235],[-123.089345,48.987982],[-123.090484,48.992499],[-123.090488,48.992515],[-123.035306,48.992515],[-123.03529,48.992515]]],[[[-103.837038,29.279906],[-103.864121,29.281366],[-103.928122,29.293019],[-104.01915,29.32033],[-104.057313,29.339037],[-104.105424,29.385675],[-104.139789,29.400584],[-104.161648,29.416759],[-104.194514,29.448927],[-104.212291,29.484661],[-104.218698,29.489829],[-104.227148,29.493033],[-104.251022,29.508588],[-104.267171,29.526571],[-104.292751,29.532824],[-104.320604,29.532255],[-104.338484,29.524013],[-104.349026,29.537578],[-104.430443,29.582795],[-104.437832,29.58543],[-104.444008,29.589203],[-104.448555,29.597678],[-104.452069,29.607109],[-104.455222,29.613387],[-104.469381,29.625402],[-104.516639,29.654315],[-104.530824,29.667906],[-104.535036,29.677802],[-104.535191,29.687853],[-104.537103,29.702116],[-104.543666,29.71643],[-104.561391,29.745421],[-104.570279,29.787511],[-104.583586,29.802575],[-104.601207,29.81477],[-104.619682,29.833064],[-104.623764,29.841487],[-104.637588,29.887996],[-104.656346,29.908201],[-104.660635,29.918433],[-104.663478,29.923084],[-104.676526,29.93683],[-104.680479,29.942308],[-104.682469,29.952126],[-104.680117,29.967784],[-104.680479,29.976466],[-104.699108,30.03145],[-104.701589,30.055324],[-104.698592,30.075271],[-104.684639,30.111135],[-104.680479,30.134131],[-104.67867,30.170356],[-104.681564,30.192939],[-104.695853,30.208441],[-104.715231,30.243995],[-104.724585,30.252211],[-104.742155,30.25986],[-104.74939,30.264459],[-104.761689,30.284199],[-104.774143,30.311588],[-104.788767,30.335927],[-104.807732,30.346418],[-104.8129,30.350707],[-104.814967,30.360577],[-104.816001,30.371997],[-104.818274,30.380524],[-104.824269,30.38719],[-104.83755,30.394063],[-104.844939,30.40104],[-104.853259,30.41215],[-104.855016,30.417473],[-104.853621,30.423984],[-104.852432,30.438867],[-104.854655,30.448737],[-104.864473,30.462018],[-104.866695,30.473025],[-104.865248,30.479898],[-104.859615,30.491112],[-104.859254,30.497261],[-104.863026,30.502377],[-104.879718,30.510852],[-104.882146,30.520929],[-104.884007,30.541858],[-104.886591,30.551883],[-104.898166,30.569401],[-104.928242,30.599529],[-104.93434,30.610536],[-104.941057,30.61405],[-104.972735,30.618029],[-104.98276,30.620716],[-104.989117,30.629553],[-104.991649,30.640301],[-104.992941,30.651464],[-104.995783,30.661747],[-105.008495,30.676992],[-105.027977,30.690117],[-105.049475,30.699264],[-105.06813,30.702675],[-105.087043,30.709806],[-105.133604,30.757917],[-105.140425,30.750476],[-105.153241,30.763188],[-105.157788,30.76572],[-105.160889,30.764118],[-105.162698,30.774919],[-105.167297,30.781171],[-105.17479,30.783962],[-105.185125,30.784634],[-105.195306,30.787941],[-105.204917,30.80241],[-105.2121,30.805718],[-105.21825,30.806803],[-105.229257,30.810214],[-105.232874,30.809128],[-105.239851,30.801532],[-105.243985,30.799103],[-105.249049,30.798845],[-105.259488,30.802979],[-105.265844,30.808405],[-105.270753,30.814348],[-105.277006,30.819412],[-105.334315,30.843803],[-105.363771,30.850366],[-105.376173,30.859565],[-105.41555,30.902456],[-105.496682,30.95651],[-105.530789,30.991701],[-105.555955,31.002605],[-105.565722,31.016661],[-105.578641,31.052163],[-105.59094,31.071438],[-105.605875,31.081928],[-105.623496,31.090351],[-105.643805,31.103684],[-105.668042,31.127869],[-105.675225,31.131951],[-105.692278,31.137635],[-105.76819,31.18001],[-105.777854,31.192722],[-105.78483,31.211016],[-105.861983,31.288376],[-105.880147,31.300881],[-105.896994,31.305997],[-105.897149,31.309511],[-105.908802,31.317004],[-105.928052,31.326461],[-105.934563,31.335504],[-105.941772,31.352351],[-105.948515,31.361239],[-105.961202,31.371006],[-106.004739,31.396948],[-106.021147,31.402167],[-106.046261,31.404648],[-106.065304,31.410952],[-106.099385,31.428884],[-106.141113,31.439167],[-106.164316,31.447797],[-106.174471,31.460251],[-106.209249,31.477305],[-106.215424,31.483919],[-106.21744,31.488725],[-106.218731,31.494616],[-106.222891,31.50459],[-106.232658,31.519938],[-106.274749,31.562622],[-106.286298,31.580141],[-106.312292,31.648612],[-106.331309,31.68215],[-106.35849,31.717548],[-106.39177,31.745919],[-106.428951,31.758476],[-106.473135,31.755065],[-106.492797,31.759044],[-106.501425,31.766344],[-106.506052,31.770258],[-106.517189,31.773824],[-106.558969,31.773876],[-106.584859,31.773927],[-106.610697,31.773979],[-106.636587,31.774082],[-106.662477,31.774134],[-106.688315,31.774237],[-106.714205,31.774237],[-106.740095,31.774289],[-106.765933,31.774392],[-106.791823,31.774444],[-106.817713,31.774496],[-106.843603,31.774547],[-106.869441,31.774599],[-106.895331,31.774702],[-106.921221,31.774702],[-106.947111,31.774754],[-106.973001,31.774857],[-106.998891,31.774909],[-107.02478,31.774961],[-107.05067,31.775013],[-107.076509,31.775064],[-107.102398,31.775168],[-107.128288,31.775168],[-107.154127,31.775219],[-107.180016,31.775374],[-107.205906,31.775374],[-107.231796,31.775426],[-107.257634,31.775478],[-107.283524,31.775529],[-107.309414,31.775633],[-107.335252,31.775684],[-107.361142,31.775788],[-107.387032,31.775788],[-107.412896,31.775839],[-107.438786,31.775943],[-107.464676,31.775994],[-107.490566,31.776098],[-107.516404,31.776149],[-107.542294,31.776201],[-107.568184,31.776253],[-107.594074,31.776304],[-107.619964,31.776408],[-107.645854,31.776459],[-107.671744,31.776459],[-107.697633,31.776563],[-107.723472,31.776614],[-107.749362,31.776666],[-107.775251,31.776718],[-107.801141,31.77677],[-107.82698,31.776873],[-107.852869,31.776925],[-107.878759,31.776925],[-107.904598,31.777028],[-107.930487,31.77708],[-107.956377,31.777131],[-107.982216,31.777183],[-108.008105,31.777235],[-108.033995,31.777338],[-108.059885,31.77739],[-108.085723,31.77739],[-108.111613,31.777545],[-108.137503,31.777545],[-108.163341,31.777648],[-108.189283,31.7777],[-108.215121,31.777751],[-108.215121,31.770723],[-108.215121,31.763695],[-108.215121,31.756667],[-108.215121,31.749639],[-108.215121,31.74256],[-108.215121,31.735583],[-108.215121,31.728555],[-108.215121,31.721476],[-108.215121,31.714396],[-108.215121,31.70742],[-108.215121,31.700392],[-108.215121,31.693312],[-108.215121,31.686284],[-108.215121,31.679256],[-108.215121,31.672176],[-108.21507,31.665148],[-108.215018,31.658172],[-108.215018,31.651092],[-108.215018,31.644064],[-108.215018,31.637036],[-108.215018,31.630008],[-108.215018,31.62298],[-108.215018,31.615952],[-108.215018,31.608873],[-108.215018,31.601845],[-108.215018,31.594817],[-108.215018,31.587789],[-108.215018,31.580761],[-108.215018,31.573733],[-108.215018,31.566653],[-108.215018,31.559625],[-108.214966,31.552597],[-108.214966,31.545569],[-108.214966,31.538489],[-108.214966,31.531461],[-108.214966,31.524485],[-108.214966,31.517405],[-108.214966,31.510378],[-108.214966,31.503401],[-108.214966,31.496322],[-108.214966,31.489242],[-108.214966,31.482214],[-108.214966,31.475238],[-108.214966,31.468158],[-108.214966,31.46113],[-108.214966,31.454102],[-108.214966,31.447074],[-108.214915,31.440046],[-108.214863,31.432966],[-108.214863,31.425938],[-108.214863,31.41891],[-108.214863,31.411882],[-108.214863,31.404803],[-108.214863,31.397826],[-108.214863,31.390798],[-108.214863,31.383719],[-108.214863,31.376639],[-108.214863,31.369663],[-108.214863,31.362635],[-108.214863,31.355555],[-108.214863,31.348527],[-108.214863,31.341551],[-108.214863,31.334471],[-108.214811,31.327443],[-108.257573,31.327391],[-108.300336,31.327391],[-108.34302,31.327391],[-108.385731,31.327391],[-108.428442,31.327391],[-108.471152,31.327391],[-108.513837,31.327391],[-108.556547,31.327391],[-108.59931,31.327391],[-108.64202,31.327391],[-108.684757,31.327391],[-108.727467,31.327391],[-108.770178,31.327391],[-108.812914,31.327391],[-108.855625,31.327391],[-108.898335,31.327391],[-108.941046,31.327391],[-108.968282,31.327391],[-108.983731,31.327391],[-109.026493,31.327391],[-109.04743,31.327391],[-109.069203,31.327391],[-109.111914,31.327391],[-109.154599,31.327391],[-109.197361,31.327391],[-109.240072,31.32734],[-109.282782,31.32734],[-109.325519,31.32734],[-109.368229,31.32734],[-109.410914,31.32734],[-109.45365,31.32734],[-109.496387,31.32734],[-109.539071,31.32734],[-109.581808,31.32734],[-109.624493,31.32734],[-109.667177,31.32734],[-109.709965,31.32734],[-109.75265,31.32734],[-109.795335,31.32734],[-109.838123,31.32734],[-109.880808,31.32734],[-109.923596,31.327288],[-109.96628,31.327236],[-110.008965,31.327236],[-110.051702,31.327236],[-110.094386,31.327236],[-110.137071,31.327236],[-110.179807,31.327236],[-110.222544,31.327236],[-110.265229,31.327236],[-110.308017,31.327236],[-110.350753,31.327236],[-110.39349,31.327236],[-110.436174,31.327236],[-110.478859,31.327236],[-110.521595,31.327236],[-110.56428,31.327236],[-110.606965,31.327236],[-110.649727,31.327236],[-110.692438,31.327236],[-110.7352,31.327236],[-110.777885,31.327236],[-110.820595,31.327236],[-110.863358,31.327236],[-110.906068,31.327236],[-110.948753,31.327185],[-111.006269,31.327185],[-111.067118,31.333644],[-111.094455,31.342532],[-111.145924,31.359069],[-111.197446,31.375554],[-111.248864,31.392142],[-111.300333,31.40873],[-111.351803,31.425318],[-111.403299,31.441855],[-111.454768,31.458339],[-111.506238,31.474979],[-111.915464,31.601431],[-112.324715,31.727987],[-112.733967,31.854543],[-113.143218,31.981046],[-113.552444,32.107602],[-113.961696,32.234132],[-114.370921,32.360687],[-114.780147,32.487243],[-114.816785,32.498534],[-114.819373,32.499363],[-114.822108,32.50024],[-114.809447,32.511324],[-114.795546,32.552226],[-114.794203,32.574111],[-114.802678,32.594497],[-114.786813,32.621033],[-114.781542,32.628061],[-114.758804,32.64483],[-114.751156,32.65222],[-114.739477,32.669066],[-114.731209,32.686636],[-114.723871,32.711519],[-114.724284,32.712835],[-114.724285,32.712836],[-114.764541,32.709839],[-114.838076,32.704206],[-114.911612,32.698703],[-114.985199,32.693122],[-115.058734,32.687567],[-115.13227,32.681986],[-115.205806,32.676456],[-115.27929,32.670823],[-115.352851,32.665346],[-115.426386,32.659765],[-115.499922,32.654209],[-115.573535,32.648654],[-115.647019,32.643073],[-115.720529,32.637518],[-115.794064,32.631963],[-115.8676,32.626408],[-115.941213,32.620827],[-116.014748,32.615271],[-116.088232,32.609664],[-116.161742,32.604161],[-116.235329,32.598554],[-116.308891,32.593025],[-116.382426,32.587469],[-116.455962,32.581888],[-116.529472,32.576333],[-116.603007,32.570804],[-116.676543,32.565223],[-116.750104,32.559667],[-116.82364,32.554086],[-116.897201,32.548531],[-116.970737,32.542976],[-117.044221,32.537421],[-117.125121,32.531669],[-117.125969,32.538258],[-117.239623,32.531308],[-120.274098,32.884264],[-121.652736,34.467248],[-124.367265,37.662798],[-126.739806,41.37928],[-126.996297,45.773888],[-124.770704,48.44258],[-123.734053,48.241906],[-123.1663,48.27837],[-123.193018,48.501035],[-123.176987,48.65482],[-122.912481,48.753561],[-122.899122,48.897797],[-122.837671,48.97502],[-122.743986,48.980582],[-122.753,48.992499],[-122.753012,48.992515],[-122.653258,48.992515],[-122.433375,48.992515],[-122.213517,48.992515],[-121.993763,48.992515],[-121.773958,48.992515],[-121.554152,48.992515],[-121.33432,48.992515],[-121.114515,48.992515],[-95.396937,48.99267],[-95.177106,48.99267],[-95.168527,48.995047],[-95.161887,49.001145],[-95.159329,49.01179],[-95.159665,49.10951],[-95.160027,49.223353],[-95.160337,49.313012],[-95.160569,49.369494],[-95.102821,49.35394],[-94.982518,49.356162],[-94.926087,49.345568],[-94.856195,49.318283],[-94.839142,49.308878],[-94.827256,49.292858],[-94.819892,49.252034],[-94.810358,49.229606],[-94.806121,49.210899],[-94.811185,49.166561],[-94.803743,49.146407],[-94.792039,49.12646],[-94.753772,49.026156],[-94.711217,48.914586],[-94.711734,48.862755],[-94.712147,48.842446],[-94.713284,48.823843],[-94.710907,48.807513],[-94.701786,48.790098],[-94.688893,48.778832],[-94.592852,48.726433],[-94.519161,48.70447],[-94.4795,48.700698],[-94.311577,48.713927],[-94.292586,48.711912],[-94.284034,48.709069],[-94.274499,48.704108],[-94.265482,48.697752],[-94.258454,48.690828],[-94.255767,48.683541],[-94.252459,48.662405],[-94.251038,48.65729],[-94.23215,48.652019],[-94.03485,48.643311],[-93.874885,48.636206],[-93.835741,48.617137],[-93.809386,48.543576],[-93.778664,48.519468],[-93.756779,48.516549],[-93.616297,48.531302],[-93.599889,48.526341],[-93.566584,48.538279],[-93.491756,48.542309],[-93.459924,48.557399],[-93.45225,48.572721],[-93.453774,48.586958],[-93.451475,48.597422],[-93.417316,48.604114],[-93.385716,48.614863],[-93.25774,48.630314],[-93.131701,48.62463],[-92.97972,48.61768],[-92.955588,48.612228],[-92.884197,48.579878],[-92.72555,48.548692],[-92.648604,48.536263],[-92.630181,48.519468],[-92.627468,48.502777],[-92.646743,48.497428],[-92.691366,48.489858],[-92.710641,48.482882],[-92.718909,48.459782],[-92.704052,48.445158],[-92.677129,48.441747],[-92.657053,48.438233],[-92.570521,48.446656],[-92.526932,48.445623],[-92.490629,48.433117],[-92.474532,48.410483],[-92.467581,48.394282],[-92.467064,48.353225],[-92.462465,48.329299],[-92.451381,48.312685],[-92.41823,48.282041],[-92.38464,48.232406],[-92.371851,48.222587],[-92.353815,48.222897],[-92.327874,48.229435],[-92.303663,48.239279],[-92.291029,48.249562],[-92.292062,48.270336],[-92.301416,48.290645],[-92.303095,48.310928],[-92.281598,48.33178],[-92.259118,48.339635],[-92.154732,48.350125],[-92.070499,48.346714],[-92.043421,48.334596],[-92.030114,48.313176],[-92.021355,48.287441],[-92.007997,48.262482],[-91.992158,48.247909],[-91.975492,48.236566],[-91.957302,48.228323],[-91.852244,48.195974],[-91.764988,48.187344],[-91.744137,48.179593],[-91.727575,48.168327],[-91.695509,48.13758],[-91.716438,48.112051],[-91.692512,48.097866],[-91.618615,48.089572],[-91.597479,48.090399],[-91.589676,48.088332],[-91.581098,48.080942],[-91.579806,48.070969],[-91.585129,48.06084],[-91.586989,48.052572],[-91.574845,48.048205],[-91.487098,48.053476],[-91.464722,48.048955],[-91.446274,48.040738],[-91.427929,48.036449],[-91.3654,48.057843],[-91.276362,48.064768],[-91.23807,48.082648],[-91.203963,48.107659],[-91.071103,48.170859],[-91.02816,48.184838],[-91.008109,48.194372],[-90.923153,48.227109],[-90.873802,48.234344],[-90.840678,48.220107],[-90.837939,48.210547],[-90.848843,48.198713],[-90.849721,48.189566],[-90.843003,48.176983],[-90.83427,48.171789],[-90.823883,48.168327],[-90.812307,48.160989],[-90.803057,48.147166],[-90.796701,48.117064],[-90.786469,48.10045],[-90.750347,48.083991],[-90.701307,48.08456],[-90.611079,48.103499],[-90.586843,48.104817],[-90.573872,48.097892],[-90.562194,48.088849],[-90.542014,48.083733],[-90.531601,48.08456],[-90.501887,48.094275],[-90.490493,48.096239],[-90.483465,48.094482],[-90.477858,48.091536],[-90.470623,48.089882],[-90.178625,48.116444],[-90.120386,48.115359],[-90.073257,48.101199],[-90.061036,48.091019],[-90.008222,48.029731],[-89.995329,48.018595],[-89.980317,48.010094],[-89.92045,47.98746],[-89.902441,47.985909],[-89.803454,48.013763],[-89.780975,48.017199],[-89.763302,48.017303],[-89.745964,48.013763],[-89.724596,48.005908],[-89.712788,48.003376],[-89.678656,48.008699],[-89.65659,48.007975],[-89.593105,47.996503],[-89.581753,47.996333],[-89.586724,47.992938],[-89.310872,47.981097],[-89.072861,48.046842],[-88.49789,48.212841],[-88.286621,48.156675],[-85.939935,47.280501],[-84.784644,46.770068],[-84.516909,46.435083],[-84.489712,46.446652],[-84.491052,46.457658],[-84.478301,46.466467],[-84.465408,46.478172],[-84.448096,46.489722],[-84.42324,46.511581],[-84.389702,46.520262],[-84.352469,46.522743],[-84.30534,46.501607],[-84.242011,46.526464],[-84.197285,46.546359],[-84.147676,46.541346],[-84.110443,46.526464],[-84.158812,46.433343],[-84.147676,46.399882],[-84.129046,46.375026],[-84.10543,46.347741],[-84.105944,46.346374],[-84.117195,46.347157],[-84.117489,46.338326],[-84.122361,46.331922],[-84.112061,46.287102],[-84.092672,46.227469],[-84.111983,46.20337],[-84.015118,46.149712],[-83.957038,46.045736],[-83.676821,46.15388],[-83.429449,46.086221],[-83.523049,45.892052],[-83.574563,45.890259],[-82.551615,44.857931],[-82.655591,43.968545],[-82.440632,43.096285],[-82.460131,43.084392],[-82.458894,43.083247],[-82.431813,43.039387],[-82.424748,43.02408],[-82.417242,43.01731],[-82.416369,43.01742],[-82.416412,43.017143],[-82.414603,42.983243],[-82.430442,42.951307],[-82.453179,42.918983],[-82.464781,42.883637],[-82.468036,42.863974],[-82.482325,42.835113],[-82.485271,42.818524],[-82.473618,42.798164],[-82.470982,42.790568],[-82.471344,42.779845],[-82.476951,42.761474],[-82.48341,42.719254],[-82.511264,42.646675],[-82.526224,42.619906],[-82.549246,42.590941],[-82.575833,42.571795],[-82.608467,42.561098],[-82.644331,42.557817],[-82.644698,42.557533],[-82.644932,42.561634],[-82.637132,42.568405],[-82.60902,42.579296],[-82.616673,42.582828],[-82.636985,42.599607],[-82.625357,42.616092],[-82.629331,42.626394],[-82.638751,42.633459],[-82.644344,42.640524],[-82.644166,42.641056],[-82.716083,42.617461],[-82.777592,42.408506],[-82.888693,42.406093],[-82.889991,42.403266],[-82.905739,42.387665],[-82.923842,42.374419],[-82.937972,42.366176],[-82.947686,42.363527],[-82.979624,42.359406],[-83.042618,42.340861],[-83.061899,42.32732],[-83.081622,42.30907],[-83.11342,42.279619],[-83.145306,42.066968],[-83.177398,41.960666],[-83.21512,41.794493],[-82.219051,41.516445],[-80.345329,42.13344],[-80.316455,42.123137],[-79.270266,42.591872],[-79.221058,42.582892],[-78.871842,42.860012],[-78.875011,42.867184],[-78.896205,42.897209],[-78.901651,42.908101],[-78.90901,42.952255],[-78.913426,42.957848],[-78.932118,42.9708],[-78.936386,42.979631],[-78.927997,43.002003],[-78.893114,43.029379],[-78.887963,43.051456],[-78.914897,43.076477],[-79.026167,43.086485],[-79.065231,43.10573],[-79.065273,43.105897],[-79.065738,43.120237],[-79.061423,43.130288],[-79.055583,43.138427],[-79.051604,43.146851],[-79.04933,43.159847],[-79.048607,43.170622],[-79.053775,43.260358],[-79.058425,43.277799],[-79.058631,43.2782],[-78.990696,43.286947],[-78.862059,43.324332],[-78.767813,43.336418],[-78.516117,43.50645],[-76.363317,43.943219],[-76.396746,44.106667],[-76.364697,44.111631],[-76.366146,44.117349],[-76.357462,44.131478],[-76.183493,44.223025],[-76.162644,44.229888],[-76.176117,44.30795],[-76.046414,44.354817],[-75.928746,44.391137],[-75.852508,44.381639],[-75.849095,44.386103],[-75.847623,44.392579],[-75.84674,44.398172],[-75.845415,44.40141],[-75.780803,44.432318],[-75.770205,44.446153],[-75.772266,44.463815],[-75.779184,44.48236],[-75.791496,44.496513],[-75.791183,44.496768],[-75.754622,44.527567],[-75.69969,44.581673],[-75.578199,44.661513],[-75.455958,44.741766],[-75.341831,44.816749],[-75.270233,44.863774],[-75.129647,44.925166],[-75.075594,44.935501],[-75.058721,44.941031],[-75.0149,44.96599],[-74.998647,44.972398],[-74.940201,44.987746],[-74.903744,45.005213],[-74.88651,45.009398],[-74.868474,45.010122],[-74.741557,44.998857],[-74.712961,44.999254],[-74.695875,44.99803],[-74.596114,44.998495],[-74.496352,44.999012],[-74.197146,45.000458],[-71.703551,45.012757],[-71.603816,45.013274],[-71.505848,45.013731],[-71.50408,45.013739],[-71.506613,45.037045],[-71.504752,45.052962],[-71.497259,45.066553],[-71.45659,45.110994],[-71.451215,45.121691],[-71.445996,45.140295],[-71.441604,45.150682],[-71.413026,45.186184],[-71.406567,45.204942],[-71.42269,45.217189],[-71.449045,45.226905],[-71.438813,45.233468],[-71.394888,45.241529],[-71.381245,45.250779],[-71.3521,45.278323],[-71.334323,45.28871],[-71.311534,45.294136],[-71.293396,45.292327],[-71.20937,45.254758],[-71.185133,45.248557],[-71.160329,45.245767],[-71.141725,45.252329],[-71.111029,45.287108],[-71.095242,45.300905],[-71.085553,45.304213],[-71.084952,45.304293],[-71.064211,45.307055],[-71.054418,45.310362],[-71.036667,45.323385],[-71.027598,45.33465],[-71.016539,45.343125],[-70.993155,45.347827],[-70.968118,45.34452],[-70.951608,45.332014],[-70.906908,45.246232],[-70.892412,45.234604],[-70.874351,45.245663],[-70.870605,45.255275],[-70.872491,45.274189],[-70.870243,45.283129],[-70.862621,45.290363],[-70.842389,45.301215],[-70.835258,45.309794],[-70.83208,45.328552],[-70.835465,45.373097],[-70.833837,45.393096],[-70.825982,45.410459],[-70.812986,45.42343],[-70.794873,45.430406],[-70.771877,45.430045],[-70.75255,45.422345],[-70.718004,45.397282],[-70.696739,45.388652],[-70.675785,45.388704],[-70.65359,45.395473],[-70.641316,45.408496],[-70.650257,45.427461],[-70.668162,45.439036],[-70.707385,45.4564],[-70.722836,45.470921],[-70.732009,45.491591],[-70.730329,45.507973],[-70.686792,45.572723],[-70.589614,45.651788],[-70.572406,45.662279],[-70.514735,45.681709],[-70.484763,45.699641],[-70.4728,45.703568],[-70.450424,45.703723],[-70.439132,45.705893],[-70.419315,45.716901],[-70.407351,45.731525],[-70.402442,45.749663],[-70.403941,45.771161],[-70.408282,45.781651],[-70.413682,45.787697],[-70.41717,45.793795],[-70.415232,45.804389],[-70.409935,45.810745],[-70.389807,45.825059],[-70.312654,45.867641],[-70.283173,45.890482],[-70.262528,45.923038],[-70.255939,45.948876],[-70.263148,45.956834],[-70.280434,45.959315],[-70.303947,45.968616],[-70.316298,45.982982],[-70.316892,45.999002],[-70.306143,46.035331],[-70.303637,46.038483],[-70.294309,46.044943],[-70.29201,46.048663],[-70.293017,46.054038],[-70.296092,46.057862],[-70.300795,46.061737],[-70.304774,46.065975],[-70.311362,46.071866],[-70.312629,46.079566],[-70.30033,46.089281],[-70.26444,46.106593],[-70.24948,46.120597],[-70.244002,46.141009],[-70.249247,46.162765],[-70.263329,46.183229],[-70.284801,46.191859],[-70.280899,46.211857],[-70.253407,46.251493],[-70.236173,46.288339],[-70.223693,46.300793],[-70.201886,46.305495],[-70.199509,46.315262],[-70.197028,46.336863],[-70.188398,46.358412],[-70.167418,46.368179],[-70.153052,46.372829],[-70.074323,46.419545],[-70.061817,46.445409],[-70.050086,46.511271],[-70.032723,46.609766],[-70.023628,46.661287],[-70.007763,46.704075],[-69.989961,46.721697],[-69.899708,46.811562],[-69.809403,46.901299],[-69.719099,46.991086],[-69.628794,47.080797],[-69.538464,47.17061],[-69.448159,47.260346],[-69.357906,47.350134],[-69.267628,47.439844],[-69.25091,47.452919],[-69.237268,47.45881],[-69.221972,47.459688],[-69.069655,47.431886],[-69.054023,47.418399],[-69.054333,47.389253],[-69.066193,47.32967],[-69.065134,47.296339],[-69.06356,47.290809],[-69.057486,47.269467],[-69.0402,47.249055],[-68.906229,47.190221],[-68.889718,47.190609],[-68.761819,47.23704],[-68.71779,47.245231],[-68.668801,47.243422],[-68.644203,47.245283],[-68.6256,47.255205],[-68.607926,47.269829],[-68.58524,47.28249],[-68.539662,47.299853],[-68.518009,47.304762],[-68.492016,47.307553],[-68.466746,47.305692],[-68.435327,47.291275],[-68.422563,47.293109],[-68.410212,47.297424],[-68.385614,47.301713],[-68.383392,47.307139],[-68.384839,47.315873],[-68.382049,47.32781],[-68.347839,47.358506],[-68.299728,47.367833],[-68.24645,47.360573],[-68.197047,47.341401],[-68.184335,47.333133],[-68.156068,47.306674],[-68.145061,47.301455],[-68.115398,47.292282],[-68.101446,47.286185],[-68.039382,47.245231],[-67.993184,47.223217],[-67.962436,47.197689],[-67.953703,47.18663],[-67.949982,47.172936],[-67.943419,47.164538],[-67.899132,47.138778],[-67.870607,47.107358],[-67.854742,47.09785],[-67.813556,47.081908],[-67.808699,47.075138],[-67.805185,47.035631],[-67.802549,46.901247],[-67.800017,46.766785],[-67.797433,46.632297],[-67.794849,46.497861],[-67.792317,46.363476],[-67.789733,46.229014],[-67.78715,46.094552],[-67.784566,45.960142],[-67.782757,45.95053],[-67.776556,45.942933],[-67.767461,45.935957],[-67.759658,45.928567],[-67.757849,45.919472],[-67.769425,45.903969],[-67.787356,45.890017],[-67.799242,45.875651],[-67.792627,45.858907],[-67.776091,45.840821],[-67.772835,45.828057],[-67.779863,45.815706],[-67.794126,45.799169],[-67.80627,45.781754],[-67.811127,45.76651],[-67.810816,45.762414],[-67.817811,45.754896],[-67.821785,45.740767],[-67.827673,45.739001],[-67.868884,45.744593],[-67.856815,45.723694],[-67.835768,45.703971],[-67.793821,45.676301],[-67.733034,45.651869],[-67.723173,45.645393],[-67.711546,45.642155],[-67.697564,45.64922],[-67.66695,45.620077],[-67.649435,45.611247],[-67.603073,45.605948],[-67.561862,45.596234],[-67.54052,45.593879],[-67.442056,45.603593],[-67.440939,45.604586],[-67.431306,45.597941],[-67.422107,45.568796],[-67.42619,45.533449],[-67.443036,45.522184],[-67.467531,45.508283],[-67.493214,45.493142],[-67.48231,45.455521],[-67.428825,45.38705],[-67.434561,45.350308],[-67.459056,45.318424],[-67.468668,45.301835],[-67.475024,45.282353],[-67.471303,45.266282],[-67.427585,45.236568],[-67.390533,45.193108],[-67.356272,45.165926],[-67.31922,45.153886],[-67.284648,45.169699],[-67.279584,45.179052],[-67.279222,45.187372],[-67.277207,45.195072],[-67.267336,45.202513],[-67.254986,45.205045],[-67.242428,45.202565],[-67.219071,45.192126],[-67.206166,45.189401],[-67.176015,45.178656],[-67.191274,45.180365],[-67.204376,45.178209],[-67.204724,45.177791],[-67.152423,45.148932],[-67.048033,45.043407],[-66.962727,45.047088],[-66.857192,44.968696],[-66.897268,44.817275],[-67.2159,44.593511],[-67.122366,44.423624],[-67.68447,44.192544],[-67.459678,40.781645],[-76.607854,32.495823],[-76.798479,32.713735],[-78.561892,29.037718],[-78.892446,29.039659],[-79.762295,26.719312],[-80.026352,24.932961],[-82.368794,23.994833],[-83.806281,29.068506],[-87.460772,29.089961],[-87.922646,28.666131],[-90.461001,28.246758],[-91.787336,29.11536],[-93.311871,29.12431],[-96.423449,26.057857],[-97.129057,25.991017],[-97.129509,25.966833],[-97.139358,25.965876],[-97.202171,25.960893],[-97.202176,25.960857],[-97.204941,25.960639],[-97.253051,25.963481],[-97.266358,25.960639],[-97.2692,25.944361],[-97.287649,25.928651],[-97.310981,25.922088],[-97.328447,25.933302],[-97.351107,25.918419],[-97.355112,25.912786],[-97.35227,25.894493],[-97.345165,25.871704],[-97.345733,25.852222],[-97.36599,25.843902],[-97.376015,25.846744],[-97.380124,25.853203],[-97.383121,25.860541],[-97.389891,25.865657],[-97.397823,25.865812],[-97.399476,25.861162],[-97.39989,25.855115],[-97.404179,25.851395],[-97.425418,25.854857],[-97.435727,25.869275],[-97.441309,25.884933],[-97.448259,25.892322],[-97.469421,25.892943],[-97.486319,25.895733],[-97.502209,25.901883],[-97.52027,25.912786],[-97.565177,25.954748],[-97.594322,25.966375],[-97.604787,25.979966],[-97.613055,25.995985],[-97.622641,26.00906],[-97.641451,26.022495],[-97.659874,26.03066],[-97.679614,26.034639],[-97.766948,26.039652],[-97.780306,26.043218],[-97.782321,26.058617],[-97.80201,26.063733],[-97.878181,26.063733],[-97.941666,26.056809],[-97.999233,26.064302],[-98.013057,26.063682],[-98.044166,26.048799],[-98.065457,26.042184],[-98.075146,26.046628],[-98.083311,26.070916],[-98.103103,26.074947],[-98.150232,26.063682],[-98.185062,26.065232],[-98.222656,26.075412],[-98.300429,26.111431],[-98.309809,26.121094],[-98.333037,26.15303],[-98.339264,26.159851],[-98.365774,26.160161],[-98.377272,26.163572],[-98.377272,26.173649],[-98.36934,26.19401],[-98.397193,26.201141],[-98.428845,26.217729],[-98.456544,26.225946],[-98.472383,26.207652],[-98.49295,26.230596],[-98.521527,26.240932],[-98.552791,26.248321],[-98.581627,26.262274],[-98.640564,26.24181],[-98.653663,26.244291],[-98.664696,26.250647],[-98.685289,26.268475],[-98.693325,26.270542],[-98.702239,26.271628],[-98.704255,26.27664],[-98.691465,26.290231],[-98.701413,26.299119],[-98.713169,26.303357],[-98.726217,26.30439],[-98.739911,26.303253],[-98.735932,26.320048],[-98.746397,26.332141],[-98.780839,26.351674],[-98.795851,26.368314],[-98.801329,26.372138],[-98.810295,26.372448],[-98.817323,26.368521],[-98.825023,26.366454],[-98.836081,26.372138],[-98.842334,26.365834],[-98.850835,26.364077],[-98.860524,26.366299],[-98.870214,26.372138],[-98.893029,26.367849],[-98.9299,26.39224],[-98.945377,26.378288],[-98.954136,26.393946],[-98.962844,26.399527],[-98.986951,26.400095],[-99.004056,26.393842],[-99.010515,26.392602],[-99.016432,26.394462],[-99.022995,26.403351],[-99.027878,26.406245],[-99.047645,26.406968],[-99.066351,26.404746],[-99.085498,26.40764],[-99.106427,26.423039],[-99.108907,26.434253],[-99.102525,26.446966],[-99.09374,26.459781],[-99.089373,26.47115],[-99.091492,26.484018],[-99.10299,26.512078],[-99.115108,26.525617],[-99.140946,26.531405],[-99.164873,26.540448],[-99.17128,26.563961],[-99.171548,26.56583],[-99.213953,26.568537],[-99.242801,26.579723],[-99.254575,26.6018],[-99.258844,26.614752],[-99.277683,26.638007],[-99.281951,26.649781],[-99.277389,26.657729],[-99.26635,26.653314],[-99.252662,26.644483],[-99.240299,26.639184],[-99.244861,26.652431],[-99.240299,26.697763],[-99.242507,26.713658],[-99.252368,26.743683],[-99.254575,26.75899],[-99.252368,26.799024],[-99.254575,26.810504],[-99.257666,26.813153],[-99.262229,26.814036],[-99.266497,26.817863],[-99.268263,26.827872],[-99.271649,26.832876],[-99.289458,26.84465],[-99.308444,26.830521],[-99.316539,26.822279],[-99.323457,26.810504],[-99.328166,26.797258],[-99.329197,26.789016],[-99.331699,26.78254],[-99.340383,26.77312],[-99.366728,26.761345],[-99.380269,26.777241],[-99.391896,26.796963],[-99.412207,26.796963],[-99.410883,26.808149],[-99.405437,26.818452],[-99.396606,26.824928],[-99.384979,26.824928],[-99.377178,26.816686],[-99.374823,26.804028],[-99.374234,26.791076],[-99.371291,26.783128],[-99.360694,26.780479],[-99.359369,26.790487],[-99.36452,26.810504],[-99.357897,26.822279],[-99.351274,26.83111],[-99.346123,26.840824],[-99.344062,26.855247],[-99.348772,26.899696],[-99.355101,26.920302],[-99.36452,26.934726],[-99.403377,26.952093],[-99.413974,26.964162],[-99.401758,26.985651],[-99.399991,26.999192],[-99.418831,27.007728],[-99.441938,27.013615],[-99.453271,27.019797],[-99.455332,27.025979],[-99.464751,27.039225],[-99.466959,27.047467],[-99.462544,27.057181],[-99.461635,27.056839],[-99.461728,27.056954],[-99.442039,27.089614],[-99.439404,27.098347],[-99.441419,27.107494],[-99.445734,27.114728],[-99.450178,27.120465],[-99.452452,27.125012],[-99.450333,27.145166],[-99.435786,27.188419],[-99.431988,27.207591],[-99.434029,27.22697],[-99.440902,27.244798],[-99.451832,27.26118],[-99.46612,27.276527],[-99.468963,27.278233],[-99.480409,27.283297],[-99.482941,27.286708],[-99.484879,27.294821],[-99.486584,27.297611],[-99.493199,27.30128],[-99.521362,27.311254],[-99.5148,27.321796],[-99.497591,27.338798],[-99.494026,27.348203],[-99.492889,27.358848],[-99.487721,27.37187],[-99.484621,27.391766],[-99.475706,27.414762],[-99.472916,27.426647],[-99.473639,27.463803],[-99.472916,27.468299],[-99.47643,27.48251],[-99.480409,27.490778],[-99.48829,27.494654],[-99.503689,27.495584],[-99.509503,27.500028],[-99.510071,27.510518],[-99.507074,27.533437],[-99.507203,27.57377],[-99.515006,27.588601],[-99.535031,27.604828],[-99.55503,27.613509],[-99.572264,27.61847],[-99.578232,27.622811],[-99.590247,27.642061],[-99.600169,27.646427],[-99.612442,27.643637],[-99.633526,27.633069],[-99.644869,27.632733],[-99.648642,27.636919],[-99.658693,27.654024],[-99.664739,27.659398],[-99.70037,27.659191],[-99.705692,27.66317],[-99.710674,27.670116],[-99.723056,27.687381],[-99.730652,27.691825],[-99.734037,27.702031],[-99.736311,27.713607],[-99.740445,27.722159],[-99.747344,27.726009],[-99.765198,27.731177],[-99.774577,27.735828],[-99.78685,27.748488],[-99.795428,27.761924],[-99.806963,27.771423],[-99.808167,27.772414],[-99.83292,27.776755],[-99.832971,27.782181],[-99.844779,27.793576],[-99.858241,27.803524],[-99.863357,27.804661],[-99.864727,27.814324],[-99.861858,27.83608],[-99.863357,27.845666],[-99.870928,27.854477],[-99.880204,27.859231],[-99.888007,27.864812],[-99.891288,27.876026],[-99.882684,27.89158],[-99.878808,27.901838],[-99.88134,27.906463],[-99.896766,27.912923],[-99.914336,27.928245],[-99.929916,27.946331],[-99.939683,27.961085],[-99.928289,27.975761],[-99.940717,27.983254],[-99.961852,27.987492],[-99.976606,27.992453],[-99.991127,28.007801],[-100.000584,28.02041],[-100.007457,28.033561],[-100.014123,28.050459],[-100.013503,28.056971],[-100.010506,28.063611],[-100.010196,28.068882],[-100.017585,28.070949],[-100.031538,28.081801],[-100.045077,28.095289],[-100.048023,28.102523],[-100.048901,28.115959],[-100.056498,28.137922],[-100.074895,28.154407],[-100.172873,28.198538],[-100.189203,28.201329],[-100.197626,28.207168],[-100.201192,28.220346],[-100.202949,28.234428],[-100.205946,28.242877],[-100.212819,28.245073],[-100.240724,28.249698],[-100.257932,28.260524],[-100.275089,28.277242],[-100.284339,28.296517],[-100.277931,28.314888],[-100.278551,28.331088],[-100.293899,28.353413],[-100.322631,28.386899],[-100.331675,28.422013],[-100.336326,28.458574],[-100.340201,28.464259],[-100.348315,28.470253],[-100.355549,28.478185],[-100.35679,28.489322],[-100.351622,28.496711],[-100.322631,28.510406],[-100.364024,28.524797],[-100.38423,28.537174],[-100.397769,28.557586],[-100.398751,28.568645],[-100.397097,28.592726],[-100.401438,28.60226],[-100.411463,28.609314],[-100.434821,28.619133],[-100.44619,28.626497],[-100.444898,28.643782],[-100.481381,28.686054],[-100.493939,28.708378],[-100.519054,28.804961],[-100.524996,28.814831],[-100.529285,28.819947],[-100.534453,28.830231],[-100.538639,28.835631],[-100.54515,28.83899],[-100.559671,28.839378],[-100.566234,28.842504],[-100.569696,28.84961],[-100.56334,28.86209],[-100.566234,28.869789],[-100.571763,28.8732],[-100.586543,28.879789],[-100.58954,28.883458],[-100.594966,28.899322],[-100.606955,28.910123],[-100.618841,28.917926],[-100.624318,28.924721],[-100.624783,28.93777],[-100.626696,28.948338],[-100.630778,28.956683],[-100.637909,28.962884],[-100.628918,28.98433],[-100.632793,29.005156],[-100.652224,29.044817],[-100.660854,29.102669],[-100.668967,29.116208],[-100.678165,29.119412],[-100.690826,29.121014],[-100.70204,29.12365],[-100.706846,29.130187],[-100.70974,29.135561],[-100.762501,29.173776],[-100.770098,29.187289],[-100.762088,29.208658],[-100.783172,29.243074],[-100.796143,29.257673],[-100.81609,29.270773],[-100.86389,29.290616],[-100.871797,29.296456],[-100.891227,29.318547],[-100.91474,29.337048],[-100.987397,29.366322],[-100.998301,29.372472],[-101.008068,29.380585],[-101.016232,29.390068],[-101.022175,29.40048],[-101.025948,29.414356],[-101.029617,29.442984],[-101.037782,29.460063],[-101.039026,29.460452],[-101.040188,29.457132],[-101.045487,29.451245],[-101.060205,29.449184],[-101.067711,29.45095],[-101.076101,29.453894],[-101.085962,29.454483],[-101.098031,29.449184],[-101.113043,29.466552],[-101.142774,29.475383],[-101.174124,29.475971],[-101.193699,29.469495],[-101.198703,29.473911],[-101.198851,29.476854],[-101.184132,29.497754],[-101.184868,29.512767],[-101.195171,29.521892],[-101.214157,29.518065],[-101.245213,29.493044],[-101.265818,29.487157],[-101.290545,29.49746],[-101.297315,29.503936],[-101.300995,29.512767],[-101.294372,29.520715],[-101.273177,29.524247],[-101.259195,29.533372],[-101.243888,29.554861],[-101.231966,29.580176],[-101.227845,29.599899],[-101.239178,29.616677],[-101.26052,29.613439],[-101.281272,29.597249],[-101.290545,29.575761],[-101.295255,29.570168],[-101.306146,29.574583],[-101.317626,29.584003],[-101.323955,29.592539],[-101.323661,29.603137],[-101.318804,29.616383],[-101.311445,29.628158],[-101.303497,29.634045],[-101.303669,29.631411],[-101.302727,29.633851],[-101.301073,29.649509],[-101.30978,29.654548],[-101.336239,29.654315],[-101.349029,29.660103],[-101.357684,29.667441],[-101.364351,29.676665],[-101.376624,29.700643],[-101.383368,29.718497],[-101.39962,29.740718],[-101.406545,29.752888],[-101.409309,29.765781],[-101.405098,29.778442],[-101.414012,29.774411],[-101.424218,29.771414],[-101.435096,29.770122],[-101.446103,29.771052],[-101.455689,29.77591],[-101.462433,29.788932],[-101.470908,29.791516],[-101.490286,29.785547],[-101.505763,29.773894],[-101.521809,29.765936],[-101.542893,29.771052],[-101.539689,29.779191],[-101.530516,29.796477],[-101.528604,29.801438],[-101.531912,29.811101],[-101.539172,29.817974],[-101.546458,29.820145],[-101.549766,29.815701],[-101.553977,29.796684],[-101.564907,29.786478],[-101.580281,29.781568],[-101.632216,29.775651],[-101.794531,29.795857],[-101.80298,29.801438],[-101.805978,29.811928],[-101.812695,29.812032],[-101.82409,29.805184],[-101.857602,29.805184],[-101.877524,29.810843],[-101.88742,29.81229],[-101.895455,29.808621],[-101.90238,29.803247],[-101.910881,29.799888],[-101.920157,29.798182],[-101.929613,29.797717],[-101.942662,29.803608],[-101.957054,29.814047],[-101.972246,29.818181],[-101.98793,29.805184],[-102.014595,29.810998],[-102.109344,29.80211],[-102.145647,29.815701],[-102.157248,29.824537],[-102.203679,29.846138],[-102.239775,29.849135],[-102.253444,29.855285],[-102.258276,29.873475],[-102.276181,29.869547],[-102.289023,29.878126],[-102.302175,29.889391],[-102.321011,29.893939],[-102.330235,29.888926],[-102.339769,29.870633],[-102.351061,29.866602],[-102.36323,29.864276],[-102.370723,29.857765],[-102.374547,29.848102],[-102.376589,29.821488],[-102.380051,29.811386],[-102.404132,29.780793],[-102.406096,29.777279],[-102.515288,29.784721],[-102.523066,29.782318],[-102.531127,29.769915],[-102.54154,29.762474],[-102.543349,29.760123],[-102.546578,29.757875],[-102.553141,29.756738],[-102.558309,29.759089],[-102.562882,29.769347],[-102.566758,29.771052],[-102.58531,29.764696],[-102.621225,29.747281],[-102.638743,29.743715],[-102.676054,29.74449],[-102.683469,29.743715],[-102.69104,29.736817],[-102.693624,29.729401],[-102.694709,29.720616],[-102.697758,29.709557],[-102.726748,29.664495],[-102.73127,29.650594],[-102.735507,29.649509],[-102.751656,29.622457],[-102.75176,29.620157],[-102.761346,29.603414],[-102.767598,29.59729],[-102.779665,29.592303],[-102.774084,29.579617],[-102.776461,29.575948],[-102.785892,29.571814],[-102.78075,29.558249],[-102.786512,29.550497],[-102.795478,29.54427],[-102.827311,29.470502],[-102.833951,29.461355],[-102.839067,29.45195],[-102.841134,29.438308],[-102.838705,29.426939],[-102.834984,29.415699],[-102.835191,29.403839],[-102.844545,29.390533],[-102.845578,29.384719],[-102.838033,29.370534],[-102.837672,29.366322],[-102.84656,29.361749],[-102.853872,29.361],[-102.859867,29.361155],[-102.864957,29.359527],[-102.876972,29.350871],[-102.883069,29.343766],[-102.885188,29.333379],[-102.885498,29.314801],[-102.899399,29.276095],[-102.899709,29.2639],[-102.892139,29.254391],[-102.867954,29.240387],[-102.858781,29.229147],[-102.869866,29.224781],[-102.896893,29.220285],[-102.942265,29.190209],[-102.947536,29.182018],[-102.969757,29.192845],[-102.988386,29.177135],[-103.015826,29.126776],[-103.024275,29.116157],[-103.032621,29.110214],[-103.072541,29.091404],[-103.080758,29.085203],[-103.085589,29.07572],[-103.091532,29.057866],[-103.095356,29.060294],[-103.104684,29.057866],[-103.109205,29.023372],[-103.122771,28.996474],[-103.147989,28.985105],[-103.187108,28.990221],[-103.241756,29.003502],[-103.301545,29.002365],[-103.316247,29.010065],[-103.311514,29.026043],[-103.309994,29.031175],[-103.3248,29.026808],[-103.330484,29.023733],[-103.342602,29.041226],[-103.351671,29.039417],[-103.360534,29.029831],[-103.372083,29.023733],[-103.38663,29.028798],[-103.414639,29.052414],[-103.423605,29.057866],[-103.435697,29.061121],[-103.478537,29.08205],[-103.529748,29.126776],[-103.535588,29.135122],[-103.538223,29.142408],[-103.541711,29.148816],[-103.550238,29.154656],[-103.558015,29.156206],[-103.58499,29.154656],[-103.673125,29.173569],[-103.702477,29.187858],[-103.749476,29.222972],[-103.759062,29.226848],[-103.770767,29.229845],[-103.777718,29.235297],[-103.769424,29.257543],[-103.774229,29.267517],[-103.78366,29.274803],[-103.794177,29.277594],[-103.837038,29.279906]]],[[[178.301106,52.056551],[179.595462,52.142083],[179.825447,51.992849],[179.661729,51.485763],[179.723231,51.459963],[179.408066,51.209841],[178.411463,51.523605],[177.698335,51.877899],[177.16784,51.581866],[176.487008,52.175325],[174.484678,52.08716],[172.866263,52.207379],[172.825506,52.716846],[172.747012,52.654022],[172.08261,52.952695],[172.942925,53.183013],[173.029416,52.993628],[173.127208,52.99494],[173.143321,52.990383],[173.175059,52.971747],[173.182932,52.968373],[176.45233,52.628178],[176.468135,52.488358],[177.900385,52.488358],[178.007601,52.179677],[178.301106,52.056551]]],[[[-168.899607,65.747626],[-168.909861,65.739569],[-168.926218,65.739895],[-168.942128,65.74372],[-168.951731,65.75316],[-168.942983,65.764716],[-168.920115,65.768866],[-168.907908,65.768297],[-168.902781,65.761542],[-168.899607,65.747626]]],[[[-131.160718,54.787192],[-132.853508,54.482536],[-134.77719,54.717786],[-142.6966,55.845503],[-142.861997,49.948308],[-155.675916,51.109976],[-164.492732,50.603976],[-164.691217,50.997975],[-171.246993,49.948308],[-171.215436,50.576636],[-173.341669,50.968826],[-173.362022,51.082198],[-177.799603,51.272899],[-179.155463,50.982285],[-179.476076,52.072632],[-177.11459,52.248701],[-177.146284,52.789384],[-174.777218,52.443779],[-174.773743,52.685853],[-173.653194,52.704099],[-173.790528,53.469081],[-171.063371,53.604473],[-170.777733,59.291898],[-174.324884,60.332184],[-171.736408,62.68026],[-172.315705,62.725352],[-171.995091,63.999658],[-168.501424,65.565173],[-168.714145,65.546708],[-168.853077,68.370871],[-161.115601,72.416214],[-146.132257,70.607941],[-140.692512,69.955349],[-141.145395,69.671641],[-141.015207,69.654202],[-141.006459,69.651272],[-141.005564,69.650946],[-141.005549,69.650941],[-141.005471,69.505164],[-141.001208,60.466879],[-141.001156,60.321074],[-140.994929,60.304382],[-140.979555,60.295804],[-140.909146,60.28366],[-140.768457,60.259269],[-140.660505,60.24051],[-140.533743,60.218548],[-140.518705,60.22387],[-140.506664,60.236324],[-140.475323,60.276477],[-140.462791,60.289138],[-140.447805,60.29446],[-140.424111,60.293168],[-140.32497,60.267537],[-140.169243,60.227229],[-140.01579,60.187387],[-139.967757,60.188369],[-139.916933,60.207851],[-139.826318,60.256478],[-139.728417,60.309033],[-139.679816,60.32681],[-139.628346,60.334096],[-139.517965,60.336732],[-139.413992,60.339212],[-139.262193,60.342778],[-139.101608,60.346602],[-139.079465,60.341021],[-139.06869,60.322056],[-139.073186,60.299835],[-139.113468,60.226816],[-139.149615,60.161187],[-139.183231,60.100157],[-139.182146,60.073389],[-139.112305,60.031376],[-139.060207,60.000059],[-139.051611,59.994892],[-139.003759,59.977219],[-138.842425,59.937686],[-138.742586,59.913192],[-138.704888,59.898464],[-138.697188,59.89371],[-138.692098,59.886888],[-138.654349,59.805498],[-138.63745,59.784052],[-138.59921,59.753822],[-138.488881,59.696357],[-138.363617,59.631142],[-138.219543,59.556004],[-138.067614,59.476991],[-137.91057,59.395187],[-137.758305,59.315915],[-137.611363,59.239331],[-137.594181,59.225275],[-137.582088,59.206568],[-137.5493,59.134531],[-137.521007,59.072364],[-137.484394,58.991904],[-137.507752,58.939969],[-137.50876,58.914906],[-137.486875,58.900075],[-137.453466,58.899145],[-137.423106,58.907723],[-137.338098,58.955472],[-137.2819,58.98715],[-137.172346,59.027148],[-137.062367,59.067572],[-137.047109,59.07331],[-136.942282,59.11107],[-136.840816,59.148174],[-136.785496,59.157217],[-136.671911,59.150809],[-136.613491,59.15422],[-136.569489,59.172152],[-136.484791,59.2538],[-136.483551,59.257469],[-136.466549,59.287803],[-136.467092,59.38449],[-136.467557,59.461643],[-136.415958,59.452238],[-136.36684,59.449551],[-136.319995,59.459059],[-136.275036,59.486448],[-136.244728,59.528202],[-136.258474,59.556107],[-136.29935,59.575745],[-136.350329,59.592384],[-136.2585,59.621582],[-136.145406,59.636826],[-136.02686,59.652846],[-135.923818,59.666747],[-135.830955,59.693257],[-135.641251,59.747362],[-135.482759,59.792475],[-135.465137,59.789685],[-135.404392,59.753305],[-135.345791,59.731032],[-135.259879,59.698218],[-135.221897,59.675273],[-135.192028,59.64711],[-135.157792,59.623287],[-135.106684,59.613158],[-135.087874,59.606544],[-135.032942,59.573109],[-135.018524,59.559363],[-135.016198,59.543447],[-135.01948,59.493166],[-135.023252,59.477146],[-135.037489,59.461591],[-135.078598,59.438337],[-135.095754,59.418855],[-134.993254,59.381906],[-135.00483,59.367127],[-135.014441,59.35152],[-135.016198,59.336173],[-134.979973,59.297415],[-134.95783,59.280982],[-134.932431,59.270647],[-134.839465,59.258141],[-134.74345,59.245119],[-134.70552,59.240106],[-134.692084,59.235249],[-134.68286,59.223001],[-134.671439,59.193752],[-134.66038,59.181298],[-134.610771,59.144556],[-134.582788,59.128847],[-134.556717,59.123059],[-134.509072,59.122801],[-134.477575,59.114946],[-134.451013,59.097893],[-134.398019,59.051952],[-134.387167,59.036863],[-134.385591,59.018828],[-134.399389,58.974954],[-134.343423,58.968857],[-134.329651,58.963017],[-134.320039,58.952682],[-134.32314,58.949168],[-134.330323,58.945344],[-134.333036,58.93413],[-134.327403,58.916457],[-134.316939,58.903796],[-134.22219,58.842714],[-134.108838,58.808246],[-133.983109,58.769902],[-133.87123,58.735899],[-133.831129,58.718019],[-133.796402,58.693421],[-133.700077,58.59937],[-133.626283,58.546402],[-133.547063,58.505577],[-133.463089,58.462221],[-133.392241,58.403878],[-133.43012,58.372097],[-133.41503,58.330549],[-133.374567,58.290965],[-133.257262,58.210298],[-133.165588,58.147305],[-133.142127,58.120588],[-133.094843,58.0331],[-133.075154,58.007882],[-132.99335,57.941917],[-132.917153,57.880499],[-132.83212,57.791564],[-132.70944,57.663303],[-132.629057,57.579277],[-132.552447,57.499075],[-132.455735,57.420992],[-132.362304,57.3457],[-132.304684,57.280355],[-132.230994,57.19682],[-132.276366,57.14889],[-132.34122,57.080393],[-132.16229,57.050317],[-132.031859,57.028406],[-132.107384,56.858753],[-131.871558,56.79346],[-131.865874,56.785708],[-131.872411,56.77297],[-131.882617,56.759146],[-131.887966,56.747958],[-131.886028,56.737055],[-131.880705,56.728838],[-131.864789,56.71349],[-131.838976,56.682278],[-131.830424,56.664759],[-131.826574,56.644606],[-131.832103,56.603368],[-131.825592,56.593343],[-131.799108,56.587658],[-131.692293,56.585074],[-131.585891,56.595048],[-131.560363,56.594066],[-131.536437,56.585229],[-131.491659,56.560166],[-131.345699,56.503271],[-131.215604,56.45255],[-131.100546,56.407669],[-131.016934,56.38705],[-130.839089,56.372452],[-130.760334,56.345192],[-130.645768,56.261942],[-130.602256,56.247059],[-130.495518,56.232434],[-130.47229,56.22489],[-130.458053,56.210653],[-130.427926,56.143964],[-130.418159,56.129702],[-130.403974,56.121898],[-130.290311,56.10097],[-130.243156,56.092391],[-130.211246,56.089962],[-130.116756,56.105646],[-130.094328,56.101486],[-130.071539,56.084123],[-130.039319,56.045521],[-130.026632,56.024101],[-130.01901,56.002216],[-130.014695,55.963252],[-130.016788,55.918913],[-130.019612,55.907978],[-130.019618,55.907952],[-130.022817,55.901353],[-130.049387,55.871405],[-130.104726,55.825263],[-130.136627,55.806464],[-130.148834,55.795356],[-130.163482,55.771145],[-130.167307,55.766262],[-130.170806,55.759833],[-130.173655,55.749498],[-130.170806,55.740953],[-130.163808,55.734565],[-130.160064,55.727118],[-130.167388,55.715399],[-130.155914,55.700141],[-130.142893,55.689521],[-130.131825,55.676581],[-130.126454,55.653998],[-130.12857,55.63642],[-130.135121,55.619127],[-130.153147,55.58511],[-130.148671,55.578192],[-130.146881,55.569322],[-130.146962,55.547187],[-130.112172,55.509345],[-130.101674,55.481147],[-130.095082,55.472113],[-130.065419,55.446112],[-130.057525,55.434882],[-130.052561,55.414008],[-130.054311,55.366645],[-130.05012,55.345445],[-130.039296,55.330756],[-129.989247,55.284003],[-130.031239,55.26435],[-130.050038,55.252875],[-130.067494,55.239],[-130.078236,55.233791],[-130.100494,55.230292],[-130.104726,55.225653],[-130.105702,55.211127],[-130.10912,55.200751],[-130.115793,55.191596],[-130.126454,55.180976],[-130.151967,55.163275],[-130.159983,55.153713],[-130.167592,55.129584],[-130.173695,55.117743],[-130.200266,55.104153],[-130.211781,55.084133],[-130.228871,55.04385],[-130.238678,55.03441],[-130.261342,55.022895],[-130.269846,55.016547],[-130.275706,55.006985],[-130.286366,54.983222],[-130.294342,54.971869],[-130.326568,54.952094],[-130.335561,54.938707],[-130.365387,54.907294],[-130.385243,54.896552],[-130.430816,54.881252],[-130.488759,54.844184],[-130.580312,54.806383],[-130.597485,54.803391],[-130.71074,54.733215],[-131.160718,54.787192]]]]}}]},"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","hi","hu","is","id","it","ja","kn","ko","lv","lij","lt","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","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"},"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","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","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-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"},"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"},"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/biodiesel":{"label":"Sells Biodiesel"},"fuel/diesel":{"label":"Sells Diesel"},"fuel/e10":{"label":"Sells E10"},"fuel/e85":{"label":"Sells E85"},"fuel/lpg":{"label":"Sells Propane"},"fuel/octane_100":{"label":"Sells Racing Gasoline"},"fuel/octane_91":{"label":"Sells Regular Gasoline"},"fuel/octane_95":{"label":"Sells Midgrade Gasoline"},"fuel/octane_98":{"label":"Sells Premium Gasoline"},"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"}},"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..."},"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"}},"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/cans":{"label":"Accepts Cans"},"recycling/clothes":{"label":"Accepts Clothes"},"recycling/glass":{"label":"Accepts Glass"},"recycling/glass_bottles":{"label":"Accepts Glass Bottles"},"recycling/paper":{"label":"Accepts Paper"},"recycling/plastic":{"label":"Accepts Plastic"},"recycling/type":{"label":"Recycling Type","options":{"container":"Container","centre":"Recycling Center"}},"ref":{"label":"Reference"},"relation":{"label":"Type"},"religion":{"label":"Religion"},"restriction":{"label":"Type"},"restrictions":{"label":"Turn Restrictions"},"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"},"sloped_curb":{"label":"Sloped Curb"},"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"},"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"},"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,medicine"},"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":"Ditch","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/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/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 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/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":"Chemist","terms":""},"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/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":{"fuel":{"76":{"count":314},"Neste":{"count":189},"BP":{"count":2511},"Shell":{"count":8380},"Agip":{"count":2651},"Migrol":{"count":65},"Avia":{"count":897},"Texaco":{"count":680},"Total":{"count":2607},"Statoil":{"count":596},"Esso":{"count":3652},"Jet":{"count":441},"Avanti":{"count":90},"Sainsbury's":{"count":58},"OMV":{"count":701},"Aral":{"count":1339},"Tesco":{"count":197},"JET":{"count":180},"Morrisons":{"count":111},"United":{"count":91},"Canadian Tire":{"count":66},"Mobil":{"count":613},"Caltex":{"count":1001},"Sunoco":{"count":355},"Q8":{"count":1161},"ABC":{"count":79},"ARAL":{"count":375},"CEPSA":{"count":1018},"BFT":{"count":89},"Petron":{"count":878},"Intermarché":{"count":434},"Total Access":{"count":51},"Super U":{"count":124},"Auchan":{"count":53},"Elf":{"count":129},"Carrefour":{"count":205},"Station Service E. Leclerc":{"count":530},"Shell Express":{"count":131},"Hess":{"count":127},"Flying V":{"count":129},"bft":{"count":168},"Gulf":{"count":199},"PTT":{"count":191},"St1":{"count":100},"Teboil":{"count":115},"HEM":{"count":212},"GALP":{"count":626},"OK":{"count":163},"ÖMV":{"count":101},"Tinq":{"count":215},"OKQ8":{"count":186},"Repsol":{"count":424},"Westfalen":{"count":96},"Esso Express":{"count":98},"Raiffeisenbank":{"count":117},"Tamoil":{"count":866},"Engen":{"count":241},"Sasol":{"count":59},"Topaz":{"count":78},"LPG":{"count":174},"Coop":{"count":62},"Orlen":{"count":598},"Oilibya":{"count":68},"Tango":{"count":122},"Star":{"count":319},"Петрол":{"count":84},"Cepsa":{"count":96},"OIL!":{"count":63},"Ultramar":{"count":125},"Irving":{"count":87},"Lukoil":{"count":701},"Petro-Canada":{"count":489},"7-Eleven":{"count":488},"Agrola":{"count":69},"Husky":{"count":126},"Slovnaft":{"count":219},"Sheetz":{"count":134},"Mol":{"count":61},"Petronas":{"count":159},"Газпромнефть":{"count":748},"Лукойл":{"count":1477},"Elan":{"count":112},"Роснефть":{"count":638},"Turmöl":{"count":57},"Neste A24":{"count":55},"Marathon":{"count":189},"Valero":{"count":366},"Eni":{"count":236},"Chevron":{"count":954},"ТНК":{"count":520},"REPSOL":{"count":1603},"MOL":{"count":228},"Bliska":{"count":150},"Api":{"count":302},"Arco":{"count":179},"Pemex":{"count":423},"Exxon":{"count":506},"Coles Express":{"count":115},"Petrom":{"count":259},"PETRONOR":{"count":207},"Rompetrol":{"count":174},"Lotos":{"count":178},"ОМВ":{"count":60},"BR":{"count":129},"Copec":{"count":505},"Petrobras":{"count":270},"Liberty":{"count":55},"IP":{"count":871},"Erg":{"count":596},"Eneos":{"count":97},"Citgo":{"count":279},"Metano":{"count":208},"Сургутнефтегаз":{"count":61},"EKO":{"count":59},"Eko":{"count":58},"Indipend.":{"count":172},"IES":{"count":63},"TotalErg":{"count":89},"Cenex":{"count":115},"ПТК":{"count":82},"HP":{"count":79},"Phillips 66":{"count":216},"CARREFOUR":{"count":74},"ERG":{"count":76},"Speedway":{"count":148},"Benzina":{"count":96},"Татнефть":{"count":264},"Terpel":{"count":259},"WOG":{"count":189},"Seaoil":{"count":54},"АЗС":{"count":1077},"Kwik Trip":{"count":108},"Wawa":{"count":89},"Pertamina":{"count":186},"COSMO":{"count":64},"Z":{"count":76},"Indian Oil":{"count":183},"АГЗС":{"count":494},"INA":{"count":121},"JOMO":{"count":62},"Holiday":{"count":97},"YPF":{"count":70},"IDEMITSU":{"count":87},"ENEOS":{"count":736},"Bharat Petroleum":{"count":64},"CAMPSA":{"count":615},"Casey's General Store":{"count":190},"Башнефть":{"count":60},"Kangaroo":{"count":60},"コスモ石油 (COSMO)":{"count":136},"MEROIL":{"count":77},"1-2-3":{"count":71},"出光":{"count":228,"tags":{"name:en":"IDEMITSU"}},"НК Альянс":{"count":88},"Sinclair":{"count":100},"Conoco":{"count":189},"SPBU":{"count":54},"Макпетрол":{"count":109},"Circle K":{"count":166},"Posto Ipiranga":{"count":70},"Posto Shell":{"count":54},"Phoenix":{"count":144},"Ipiranga":{"count":119},"OKKO":{"count":85},"ОККО":{"count":119},"บางจาก":{"count":60},"QuikTrip":{"count":105},"Stewart's":{"count":63},"Posto BR":{"count":68},"ป ต ท":{"count":152},"ปตท":{"count":88},"ANP":{"count":80},"Kum & Go":{"count":80},"Petrolimex":{"count":55},"Sokimex":{"count":66},"Tela":{"count":154},"Posto":{"count":71},"H-E-B":{"count":182},"Укрнафта":{"count":58},"Татнефтепродукт":{"count":54},"Afriquia":{"count":88},"Murphy USA":{"count":67},"昭和シェル (Showa-shell)":{"count":94},"エネオス":{"count":53},"CNG":{"count":94}},"pub":{"Kings Arms":{"count":67},"The Ship":{"count":89},"The White Horse":{"count":204},"The White Hart":{"count":226},"Royal Oak":{"count":150},"The Red Lion":{"count":233},"The Kings Arms":{"count":58},"The Star":{"count":73},"The Anchor":{"count":64},"The Cross Keys":{"count":55},"The Wheatsheaf":{"count":117},"The Crown Inn":{"count":67},"The Kings Head":{"count":53},"The Castle":{"count":62},"The Railway":{"count":102},"The White Lion":{"count":118},"The Bell":{"count":121},"The Bull":{"count":68},"The Plough":{"count":179},"The George":{"count":110},"The Royal Oak":{"count":209},"The Fox":{"count":74},"Prince of Wales":{"count":77},"The Rising Sun":{"count":71},"The Prince of Wales":{"count":51},"The Crown":{"count":244},"The Chequers":{"count":66},"The Swan":{"count":152},"Rose and Crown":{"count":79},"The Victoria":{"count":67},"New Inn":{"count":90},"Royal Hotel":{"count":57},"Red Lion":{"count":207},"Cross Keys":{"count":61},"The Greyhound":{"count":96},"The Black Horse":{"count":94},"The New Inn":{"count":105},"Kings Head":{"count":59},"The Albion":{"count":51},"The Angel":{"count":52},"The Queens Head":{"count":52},"The Ship Inn":{"count":83},"Rose & Crown":{"count":51},"Queens Head":{"count":52},"Irish Pub":{"count":76}},"fast_food":{"Quick":{"count":484},"McDonald's":{"count":12376,"tags":{"cuisine":"burger"}},"Subway":{"count":5576,"tags":{"cuisine":"sandwich"}},"Burger King":{"count":3734,"tags":{"cuisine":"burger"}},"Ali Baba":{"count":61},"Hungry Jacks":{"count":173,"tags":{"cuisine":"burger"}},"Red Rooster":{"count":148},"KFC":{"count":3198,"tags":{"cuisine":"chicken"}},"Domino's Pizza":{"count":985,"tags":{"cuisine":"pizza"}},"Chowking":{"count":142},"Jollibee":{"count":396},"Hesburger":{"count":102},"肯德基":{"count":86},"Wendy's":{"count":1621,"tags":{"cuisine":"burger"}},"Tim Hortons":{"count":323},"Steers":{"count":151},"Hardee's":{"count":268,"tags":{"cuisine":"burger"}},"Arby's":{"count":782},"A&W":{"count":283},"Dairy Queen":{"count":791},"Hallo Pizza":{"count":76},"Fish & Chips":{"count":93},"Harvey's":{"count":90},"麥當勞":{"count":65},"Pizza Pizza":{"count":215},"Kotipizza":{"count":74},"Jack in the Box":{"count":546,"tags":{"cuisine":"burger"}},"Istanbul":{"count":56},"Kochlöffel":{"count":68},"Döner":{"count":228},"Telepizza":{"count":201},"Sibylla":{"count":61},"Carl's Jr.":{"count":298,"tags":{"cuisine":"burger"}},"Quiznos":{"count":266,"tags":{"cuisine":"sandwich"}},"Wimpy":{"count":141},"Sonic":{"count":566,"tags":{"cuisine":"burger"}},"Taco Bell":{"count":1423,"tags":{"cuisine":"mexican"}},"Pizza Nova":{"count":63},"Papa John's":{"count":304,"tags":{"cuisine":"pizza"}},"Nordsee":{"count":159},"Mr. Sub":{"count":103},"Макдоналдс":{"count":324,"tags":{"name:en":"McDonald's"}},"Asia Imbiss":{"count":111},"Chipotle":{"count":290,"tags":{"cuisine":"mexican"}},"マクドナルド":{"count":692,"tags":{"name:en":"McDonald's","cuisine":"burger"}},"In-N-Out Burger":{"count":65},"Jimmy John's":{"count":141},"Jamba Juice":{"count":68},"Робин Сдобин":{"count":82},"Baskin Robbins":{"count":74},"ケンタッキーフライドチキン":{"count":164,"tags":{"name:en":"KFC","cuisine":"chicken"}},"吉野家":{"count":191},"Taco Time":{"count":88},"松屋":{"count":281,"tags":{"name:en":"Matsuya"}},"Little Caesars":{"count":81},"El Pollo Loco":{"count":63},"Del Taco":{"count":141},"White Castle":{"count":80},"Boston Market":{"count":66},"Chick-fil-A":{"count":257,"tags":{"cuisine":"chicken"}},"Panda Express":{"count":238,"tags":{"cuisine":"chinese"}},"Whataburger":{"count":364},"Taco John's":{"count":78},"Теремок":{"count":68},"Culver's":{"count":425},"Five Guys":{"count":141},"Church's Chicken":{"count":95},"Popeye's":{"count":167,"tags":{"cuisine":"chicken"}},"Long John Silver's":{"count":93},"Pollo Campero":{"count":62},"Zaxby's":{"count":51},"すき家":{"count":276,"tags":{"name:en":"SUKIYA"}},"モスバーガー":{"count":257,"tags":{"name:en":"MOS BURGER"}},"Русский Аппетит":{"count":69},"なか卯":{"count":63}},"restaurant":{"Pizza Hut":{"count":1180,"tags":{"cuisine":"pizza"}},"Little Chef":{"count":64},"Adler":{"count":158},"Zur Krone":{"count":90},"Deutsches Haus":{"count":90},"Krone":{"count":171},"Akropolis":{"count":152},"Schützenhaus":{"count":124},"Kreuz":{"count":74},"Waldschänke":{"count":55},"La Piazza":{"count":69},"Lamm":{"count":66},"Zur Sonne":{"count":73},"Zur Linde":{"count":204},"Poseidon":{"count":110},"Shanghai":{"count":82},"Red Lobster":{"count":235},"Zum Löwen":{"count":84},"Swiss Chalet":{"count":107},"Olympia":{"count":74},"Wagamama":{"count":64},"Frankie & Benny's":{"count":66},"Hooters":{"count":103},"Sternen":{"count":78},"Hirschen":{"count":79},"Denny's":{"count":450},"Athen":{"count":68},"Sonne":{"count":126},"Hirsch":{"count":79},"Ratskeller":{"count":150},"La Cantina":{"count":56},"Gasthaus Krone":{"count":56},"El Greco":{"count":86},"Gasthof zur Post":{"count":79},"Nando's":{"count":246},"Löwen":{"count":112},"La Pataterie":{"count":51},"Bella Napoli":{"count":53},"Pizza Express":{"count":262},"Mandarin":{"count":65},"Hong Kong":{"count":83},"Zizzi":{"count":68},"Cracker Barrel":{"count":183},"Rhodos":{"count":81},"Lindenhof":{"count":79},"Milano":{"count":54},"Dolce Vita":{"count":77},"Kirchenwirt":{"count":81},"Kantine":{"count":52},"Ochsen":{"count":95},"Spur":{"count":62},"Mykonos":{"count":59},"Lotus":{"count":66},"Applebee's":{"count":531},"Flunch":{"count":72},"Zur Post":{"count":116},"China Town":{"count":76},"La Dolce Vita":{"count":73},"Waffle House":{"count":207},"Delphi":{"count":88},"Linde":{"count":103},"Outback Steakhouse":{"count":218},"Dionysos":{"count":69},"Kelsey's":{"count":57},"Boston Pizza":{"count":165},"Bella Italia":{"count":132},"Sizzler":{"count":53},"Grüner Baum":{"count":116},"Taj Mahal":{"count":104},"Rössli":{"count":68},"Wimpy":{"count":51},"Traube":{"count":65},"Adria":{"count":52},"Red Robin":{"count":185},"Roma":{"count":61},"San Marco":{"count":67},"Hellas":{"count":55},"La Perla":{"count":67},"Vips":{"count":53},"Panera Bread":{"count":218},"Da Vinci":{"count":54},"Hippopotamus":{"count":96},"Prezzo":{"count":75},"Courtepaille":{"count":106},"Hard Rock Cafe":{"count":70},"Panorama":{"count":61},"デニーズ":{"count":82},"Sportheim":{"count":65},"餃子の王将":{"count":57},"Bären":{"count":60},"Alte Post":{"count":60},"Pizzeria Roma":{"count":51},"China Garden":{"count":66},"Vapiano":{"count":82},"Mamma Mia":{"count":64},"Schwarzer Adler":{"count":57},"IHOP":{"count":317},"Chili's":{"count":328},"Asia":{"count":51},"Olive Garden":{"count":279},"TGI Friday's":{"count":159},"Friendly's":{"count":78},"Buffalo Grill":{"count":202},"Texas Roadhouse":{"count":110},"ガスト":{"count":230,"tags":{"name:en":"Gusto"}},"Sakura":{"count":75},"Mensa":{"count":99},"The Keg":{"count":53},"サイゼリヤ":{"count":93},"La Strada":{"count":52},"Village Inn":{"count":92},"Buffalo Wild Wings":{"count":176},"Peking":{"count":59},"Boston Market":{"count":61},"Round Table Pizza":{"count":53},"Jimmy John's":{"count":69},"California Pizza Kitchen":{"count":61},"Якитория":{"count":77},"Golden Corral":{"count":101},"Perkins":{"count":105},"Ruby Tuesday":{"count":162},"Shari's":{"count":65},"Bob Evans":{"count":129},"바다횟집 (Bada Fish Restaurant)":{"count":55},"Mang Inasal":{"count":84},"Евразия":{"count":102},"ジョナサン":{"count":59},"Longhorn Steakhouse":{"count":66}},"bank":{"Chase":{"count":721},"Commonwealth Bank":{"count":232},"Citibank":{"count":277},"HSBC":{"count":1102},"Barclays":{"count":965},"Westpac":{"count":208},"NAB":{"count":131},"ANZ":{"count":218},"Lloyds Bank":{"count":547},"Landbank":{"count":81},"Sparkasse":{"count":4555},"UCPB":{"count":92},"PNB":{"count":244},"Metrobank":{"count":269},"BDO":{"count":290},"Volksbank":{"count":2591},"BPI":{"count":415},"Postbank":{"count":443},"NatWest":{"count":628},"Raiffeisenbank":{"count":2119},"Yorkshire Bank":{"count":63},"ABSA":{"count":95},"Standard Bank":{"count":109},"FNB":{"count":97},"Deutsche Bank":{"count":855},"SEB":{"count":133},"Commerzbank":{"count":806},"Targobank":{"count":166},"ABN AMRO":{"count":130},"Handelsbanken":{"count":184},"Swedbank":{"count":223},"Kreissparkasse":{"count":600},"UniCredit Bank":{"count":408},"Monte dei Paschi di Siena":{"count":132},"Caja Rural":{"count":99},"Dresdner Bank":{"count":66},"Sparda-Bank":{"count":320},"VÚB":{"count":107},"Slovenská sporiteľňa":{"count":134},"Bank of Montreal":{"count":118},"KBC":{"count":203},"Royal Bank of Scotland":{"count":111},"TSB":{"count":80},"US Bank":{"count":256},"HypoVereinsbank":{"count":561},"Bank Austria":{"count":176},"ING":{"count":496},"Erste Bank":{"count":180},"CIBC":{"count":326},"Scotiabank":{"count":413},"Caisse d'Épargne":{"count":882},"Santander":{"count":1323},"Bank of Scotland":{"count":89},"TD Canada Trust":{"count":450},"BMO":{"count":169},"Danske Bank":{"count":131},"OTP":{"count":192},"Crédit Agricole":{"count":1239},"LCL":{"count":553},"VR-Bank":{"count":430},"ČSOB":{"count":160},"Česká spořitelna":{"count":212},"BNP":{"count":112},"Royal Bank":{"count":65},"Nationwide":{"count":209},"Halifax":{"count":225},"BAWAG PSK":{"count":102},"National Bank":{"count":84},"Nedbank":{"count":80},"First National Bank":{"count":85},"Nordea":{"count":319},"Rabobank":{"count":609},"Sparkasse KölnBonn":{"count":69},"Tatra banka":{"count":67},"Berliner Sparkasse":{"count":62},"Berliner Volksbank":{"count":77},"Wells Fargo":{"count":874},"Credit Suisse":{"count":71},"Société Générale":{"count":634},"Osuuspankki":{"count":75},"Sparkasse Aachen":{"count":56},"Hamburger Sparkasse":{"count":156},"Cassa di Risparmio del Veneto":{"count":68},"BNP Paribas":{"count":617},"Banque Populaire":{"count":433},"BNP Paribas Fortis":{"count":209},"Banco Popular":{"count":291},"Bancaja":{"count":55},"Banesto":{"count":208},"La Caixa":{"count":583},"Santander Consumer Bank":{"count":88},"BRD":{"count":191},"BCR":{"count":143},"Banca Transilvania":{"count":141},"BW-Bank":{"count":97},"Komerční banka":{"count":132},"Banco Pastor":{"count":64},"Stadtsparkasse":{"count":86},"Ulster Bank":{"count":86},"Sberbank":{"count":58},"CIC":{"count":427},"Bancpost":{"count":56},"Caja Madrid":{"count":115},"Maybank":{"count":94},"中国银行":{"count":85},"Unicredit Banca":{"count":243},"Crédit Mutuel":{"count":690},"BBVA":{"count":647},"Intesa San Paolo":{"count":69},"TD Bank":{"count":206},"Belfius":{"count":231},"Bank of America":{"count":924},"RBC":{"count":230},"Alpha Bank":{"count":123},"Сбербанк":{"count":4794},"Россельхозбанк":{"count":201},"Crédit du Nord":{"count":96},"BancoEstado":{"count":80},"Millennium Bank":{"count":414},"State Bank of India":{"count":151},"Беларусбанк":{"count":242},"ING Bank Śląski":{"count":67},"Caixa Geral de Depósitos":{"count":129},"Kreissparkasse Köln":{"count":65},"Banco BCI":{"count":51},"Banco de Chile":{"count":98},"ВТБ24":{"count":326},"UBS":{"count":134},"PKO BP":{"count":265},"Chinabank":{"count":55},"PSBank":{"count":59},"Union Bank":{"count":124},"China Bank":{"count":66},"RCBC":{"count":122},"Unicaja":{"count":83},"BBK":{"count":79},"Ibercaja":{"count":69},"RBS":{"count":143},"Commercial Bank of Ceylon PLC":{"count":79},"Bank of Ireland":{"count":109},"BNL":{"count":87},"Banco Santander":{"count":138},"Banco Itaú":{"count":111},"AIB":{"count":72},"BZ WBK":{"count":77},"Banco do Brasil":{"count":557},"Caixa Econômica Federal":{"count":184},"Fifth Third Bank":{"count":84},"Banca Popolare di Vicenza":{"count":81},"Wachovia":{"count":58},"OLB":{"count":53},"みずほ銀行":{"count":78},"BES":{"count":72},"ICICI Bank":{"count":91},"HDFC Bank":{"count":91},"La Banque Postale":{"count":67},"Pekao SA":{"count":56},"Oberbank":{"count":90},"Bradesco":{"count":295},"Oldenburgische Landesbank":{"count":56},"Bendigo Bank":{"count":93},"Argenta":{"count":86},"AXA":{"count":68},"Axis Bank":{"count":61},"Banco Nación":{"count":67},"GE Money Bank":{"count":72},"Альфа-Банк":{"count":185},"Белагропромбанк":{"count":70},"Caja Círculo":{"count":65},"Banco Galicia":{"count":51},"Eurobank":{"count":97},"Banca Intesa":{"count":62},"Canara Bank":{"count":92},"Cajamar":{"count":77},"Banamex":{"count":149},"Crédit Mutuel de Bretagne":{"count":335},"Davivienda":{"count":83},"Bank Spółdzielczy":{"count":159},"Credit Agricole":{"count":157},"Bankinter":{"count":59},"Banque Nationale":{"count":63},"Bank of the West":{"count":96},"Key Bank":{"count":155},"Western Union":{"count":88},"Citizens Bank":{"count":115},"ПриватБанк":{"count":513},"Security Bank":{"count":78},"Millenium":{"count":60},"Bankia":{"count":149},"三菱東京UFJ銀行":{"count":159},"Caixa":{"count":117},"Banco de Costa Rica":{"count":63},"SunTrust Bank":{"count":73},"Itaú":{"count":338},"PBZ":{"count":52},"中国工商银行":{"count":51},"Bancolombia":{"count":89},"Райффайзен Банк Аваль":{"count":64},"Bancomer":{"count":115},"Banorte":{"count":80},"Alior Bank":{"count":81},"BOC":{"count":51},"Банк Москвы":{"count":118},"ВТБ":{"count":59},"Getin Bank":{"count":55},"Caja Duero":{"count":57},"Regions Bank":{"count":62},"Росбанк":{"count":177},"Banco Estado":{"count":72},"BCI":{"count":68},"SunTrust":{"count":68},"PNC Bank":{"count":254},"신한은행":{"count":217,"tags":{"name:en":"Sinhan Bank"}},"우리은행":{"count":291,"tags":{"name:en":"Uri Bank"}},"국민은행":{"count":165,"tags":{"name:en":"Gungmin Bank"}},"중소기업은행":{"count":52,"tags":{"name:en":"Industrial Bank of Korea"}},"광주은행":{"count":51,"tags":{"name:en":"Gwangju Bank"}},"Газпромбанк":{"count":100},"M&T Bank":{"count":92},"Caja de Burgos":{"count":51},"Santander Totta":{"count":69},"УкрСиббанк":{"count":192},"Ощадбанк":{"count":364},"Уралсиб":{"count":85},"りそな銀行":{"count":225,"tags":{"name:en":"Mizuho Bank"}},"Ecobank":{"count":66},"Cajero Automatico Bancared":{"count":145},"Промсвязьбанк":{"count":93},"三井住友銀行":{"count":129},"Banco Provincia":{"count":67},"BB&T":{"count":147},"Возрождение":{"count":59},"Capital One":{"count":59},"横浜銀行":{"count":51},"Bank Mandiri":{"count":62},"Banco de la Nación":{"count":92},"Banco G&T Continental":{"count":62},"Peoples Bank":{"count":60},"工商银行":{"count":51},"Совкомбанк":{"count":55},"Provincial":{"count":56},"Banco de Desarrollo Banrural":{"count":73},"Banco Bradesco":{"count":65},"Bicentenario":{"count":182},"ლიბერთი ბანკი":{"count":54,"tags":{"name:en":"Liberty Bank"}},"Banesco":{"count":108},"Mercantil":{"count":75},"Bank BRI":{"count":53},"Del Tesoro":{"count":91},"하나은행":{"count":77},"CityCommerce Bank":{"count":71},"De Venezuela":{"count":117}},"car_rental":{"Europcar":{"count":291},"Budget":{"count":92},"Sixt":{"count":161},"Avis":{"count":282},"Hertz":{"count":293},"Enterprise":{"count":199},"stadtmobil CarSharing-Station":{"count":148}},"pharmacy":{"Rowlands Pharmacy":{"count":71},"Boots":{"count":840},"Marien-Apotheke":{"count":314},"Mercury Drug":{"count":426},"Löwen-Apotheke":{"count":356},"Superdrug":{"count":117},"Sonnen-Apotheke":{"count":311},"Rathaus-Apotheke":{"count":132},"Engel-Apotheke":{"count":123},"Hirsch-Apotheke":{"count":83},"Stern-Apotheke":{"count":67},"Lloyds Pharmacy":{"count":295},"Rosen-Apotheke":{"count":208},"Stadt-Apotheke":{"count":302},"Markt-Apotheke":{"count":164},"Аптека":{"count":1989},"Pharmasave":{"count":64},"Brunnen-Apotheke":{"count":53},"Shoppers Drug Mart":{"count":430},"Apotheke am Markt":{"count":60},"Alte Apotheke":{"count":88},"Neue Apotheke":{"count":109},"Gintarinė vaistinė":{"count":101},"Rats-Apotheke":{"count":84},"Adler Apotheke":{"count":313},"Pharmacie Centrale":{"count":64},"Walgreens":{"count":1619},"Rite Aid":{"count":745},"Apotheke":{"count":165},"Linden-Apotheke":{"count":211},"Bahnhof-Apotheke":{"count":66},"Burg-Apotheke":{"count":55},"Jean Coutu":{"count":62},"Pharmaprix":{"count":60},"Farmacias Ahumada":{"count":104},"Farmacia Comunale":{"count":113},"Farmacias Cruz Verde":{"count":86},"Cruz Verde":{"count":99},"Hubertus Apotheke":{"count":52},"CVS":{"count":1560},"Farmacias SalcoBrand":{"count":133},"Фармация":{"count":120},"Bären-Apotheke":{"count":74},"Clicks":{"count":113},"セイジョー":{"count":53},"マツモトキヨシ":{"count":115},"Dr. Max":{"count":51},"Вита":{"count":106},"Радуга":{"count":70},"サンドラッグ":{"count":61},"Apteka":{"count":366},"Первая помощь":{"count":74},"Ригла":{"count":113},"Имплозия":{"count":63},"Kinney Drugs":{"count":68},"Классика":{"count":67},"Ljekarna":{"count":53},"SalcoBrand":{"count":88},"Аптека 36,6":{"count":224},"Фармакор":{"count":75},"スギ薬局":{"count":84},"Аптечный пункт":{"count":148},"Невис":{"count":60},"トモズ (Tomod's)":{"count":83},"Eurovaistinė":{"count":65},"Farmacity":{"count":68},"аптека":{"count":96},"The Generics Pharmacy":{"count":95},"Farmatodo":{"count":123},"Duane Reade":{"count":61},"H-E-B":{"count":262},"Фармленд":{"count":82},"ドラッグてらしま (Drug Terashima)":{"count":96},"Арніка":{"count":125},"ავერსი (Aversi)":{"count":62},"Farmahorro":{"count":58}},"cafe":{"Starbucks":{"count":4238,"tags":{"cuisine":"coffee_shop"}},"Cafeteria":{"count":115},"Costa":{"count":618},"Caffè Nero":{"count":169},"Кафе":{"count":226},"Café Central":{"count":61},"Second Cup":{"count":193},"Dunkin Donuts":{"count":428,"tags":{"cuisine":"donut"}},"Espresso House":{"count":53},"Segafredo":{"count":69},"Coffee Time":{"count":94},"Cafe Coffee Day":{"count":120},"Eiscafe Venezia":{"count":180},"スターバックス":{"count":251,"tags":{"name:en":"Starbucks"}},"Шоколадница":{"count":145},"Pret A Manger":{"count":119},"Столовая":{"count":391},"Jamba Juice":{"count":53},"ドトール":{"count":164,"tags":{"name:en":"DOUTOR"}},"Tchibo":{"count":100},"Кофе Хауз":{"count":104},"Caribou Coffee":{"count":100},"Уют":{"count":51},"Шашлычная":{"count":58},"คาเฟ่ อเมซอน":{"count":62},"Traveler's Coffee":{"count":60},"カフェ・ド・クリエ":{"count":67,"tags":{"name:en":"Cafe de CRIE"}},"Cafe Amazon":{"count":65}}},"shop":{"supermarket":{"Budgens":{"count":88},"Morrisons":{"count":411},"Interspar":{"count":142},"Merkur":{"count":107},"Sainsbury's":{"count":547},"Lidl":{"count":7130},"Edeka":{"count":2293},"Coles":{"count":400},"Iceland":{"count":315},"Coop":{"count":2100},"Tesco":{"count":1297},"Woolworths":{"count":541},"Zielpunkt":{"count":239},"Nahkauf":{"count":170},"Billa":{"count":1432},"Kaufland":{"count":1004},"Plus":{"count":120},"ALDI":{"count":5172},"Checkers":{"count":128},"Tesco Metro":{"count":137},"NP":{"count":153},"Penny":{"count":1759},"Norma":{"count":1068},"Asda":{"count":225},"Netto":{"count":4379},"Rewe":{"count":2645},"Aldi Süd":{"count":594},"Real":{"count":246},"Tesco Express":{"count":406},"King Soopers":{"count":72},"Kiwi":{"count":167},"Pick n Pay":{"count":241},"ICA":{"count":192},"Tengelmann":{"count":188},"Carrefour":{"count":1640},"Waitrose":{"count":258},"Spar":{"count":2386},"Hofer":{"count":442},"M-Preis":{"count":76},"tegut":{"count":210},"Sainsbury's Local":{"count":118},"E-Center":{"count":66},"Aldi Nord":{"count":210},"nahkauf":{"count":84},"Meijer":{"count":76},"Safeway":{"count":410},"Costco":{"count":152},"Albert":{"count":185},"Jumbo":{"count":194},"Shoprite":{"count":244},"MPreis":{"count":54},"Penny Market":{"count":429},"Tesco Extra":{"count":123},"Albert Heijn":{"count":476},"IGA":{"count":363},"Super U":{"count":488},"Metro":{"count":260},"Neukauf":{"count":77},"Migros":{"count":459},"Marktkauf":{"count":121},"Delikatesy Centrum":{"count":59},"C1000":{"count":307},"Hoogvliet":{"count":53},"Food Basics":{"count":75},"Casino":{"count":264},"Penny Markt":{"count":466},"Giant":{"count":191},"COOP Jednota":{"count":73},"Rema 1000":{"count":368},"Kaufpark":{"count":96},"ALDI SÜD":{"count":113},"Simply Market":{"count":330},"Konzum":{"count":230},"Carrefour Express":{"count":353},"Eurospar":{"count":270},"Mercator":{"count":125},"Famila":{"count":130},"Hemköp":{"count":82},"real,-":{"count":81},"Markant":{"count":88},"Volg":{"count":135},"Leader Price":{"count":267},"Treff 3000":{"count":94},"SuperBrugsen":{"count":67},"Kaiser's":{"count":256},"K+K":{"count":106},"Unimarkt":{"count":86},"Carrefour City":{"count":126},"Sobeys":{"count":122},"S-Market":{"count":109},"Combi":{"count":55},"Denner":{"count":276},"Konsum":{"count":133},"Franprix":{"count":312},"Monoprix":{"count":198},"Diska":{"count":69},"PENNY":{"count":79},"Dia":{"count":835},"Giant Eagle":{"count":85},"NORMA":{"count":115},"AD Delhaize":{"count":63},"Auchan":{"count":152},"Mercadona":{"count":769},"Consum":{"count":130},"Carrefour Market":{"count":80},"Whole Foods":{"count":210,"tags":{"shop":"supermarket"}},"Pam":{"count":56},"sky":{"count":105},"Despar":{"count":146},"Eroski":{"count":208},"Costcutter":{"count":63},"Maxi":{"count":108},"Colruyt":{"count":180},"The Co-operative":{"count":64},"Intermarché":{"count":1210},"Delhaize":{"count":207},"CBA":{"count":176},"Shopi":{"count":53},"Walmart":{"count":644},"Kroger":{"count":317},"Albertsons":{"count":242},"Trader Joe's":{"count":235},"Feneberg":{"count":58},"denn's Biomarkt":{"count":52},"dm":{"count":114},"Kvickly":{"count":55},"Makro":{"count":140},"Dico":{"count":53},"Nah & Frisch":{"count":73},"Champion":{"count":59},"ICA Supermarket":{"count":51},"Fakta":{"count":235},"Магнит":{"count":1760},"Caprabo":{"count":103},"Famiglia Cooperativa":{"count":64},"Народная 7Я семьЯ":{"count":154},"Esselunga":{"count":85},"Maxima":{"count":102},"Petit Casino":{"count":111},"Wasgau":{"count":60},"Pingo Doce":{"count":253},"Match":{"count":140},"Profi":{"count":60},"Lider":{"count":65},"Unimarc":{"count":177},"The Co-operative Food":{"count":190},"Santa Isabel":{"count":128},"Седьмой континент":{"count":79},"HIT":{"count":59},"Rimi":{"count":106},"Conad":{"count":304},"Фуршет":{"count":76},"Willys":{"count":56},"Farmfoods":{"count":64},"U Express":{"count":51},"Фора":{"count":52},"Dunnes Stores":{"count":73},"Сільпо":{"count":125},"マルエツ":{"count":59},"Piggly Wiggly":{"count":57},"Crai":{"count":54},"El Árbol":{"count":73},"Centre Commercial E. Leclerc":{"count":549},"Foodland":{"count":100},"Super Brugsen":{"count":67},"Дикси":{"count":683},"Пятёрочка":{"count":1344},"Publix":{"count":339},"Føtex":{"count":66},"coop":{"count":73},"Fressnapf":{"count":69},"Coop Konsum":{"count":79},"Carrefour Contact":{"count":83},"No Frills":{"count":105},"Plodine":{"count":52},"ADEG":{"count":68},"Minipreço":{"count":111},"Biedronka":{"count":1335},"Eurospin":{"count":155},"Семья":{"count":62},"Gadis":{"count":53},"Евроопт":{"count":68},"Centra":{"count":51},"Квартал":{"count":82},"New World":{"count":69},"Countdown":{"count":95},"Reliance Fresh":{"count":61},"Stokrotka":{"count":98},"Coop Jednota":{"count":74},"Fred Meyer":{"count":64},"Irma":{"count":58},"Continente":{"count":75},"Price Chopper":{"count":99},"Game":{"count":52},"Soriana":{"count":93},"Alimerka":{"count":64},"Piotr i Paweł":{"count":53},"Перекресток":{"count":312},"Maxima X":{"count":117},"Карусель":{"count":55},"ALDI Nord":{"count":51},"Condis":{"count":67},"Sam's Club":{"count":138},"Копейка":{"count":87},"Géant Casino":{"count":54},"ASDA":{"count":180},"Intermarche":{"count":115},"Stop & Shop":{"count":66},"Food Lion":{"count":216},"Harris Teeter":{"count":92},"Foodworks":{"count":62},"Polo Market":{"count":86},"Лента":{"count":51},"西友 (SEIYU)":{"count":58},"H-E-B":{"count":293},"Атак":{"count":53},"Полушка":{"count":139},"Extra":{"count":82},"Lewiatan":{"count":94},"Sigma":{"count":51},"АТБ":{"count":322},"Społem":{"count":55},"Bodega Aurrera":{"count":82},"Tesco Lotus":{"count":77},"Мария-Ра":{"count":108},"Магнолия":{"count":72},"Магазин":{"count":120},"Монетка":{"count":174},"Hy-Vee":{"count":75},"Walmart Supercenter":{"count":133},"Hannaford":{"count":57},"Wegmans":{"count":83},"業務スーパー":{"count":61},"Norfa XL":{"count":55},"ヨークマート (YorkMart)":{"count":64},"Leclerc Drive":{"count":76}},"electronics":{"Media Markt":{"count":285},"Maplin":{"count":65},"Best Buy":{"count":345},"Future Shop":{"count":73},"Saturn":{"count":134},"Currys":{"count":80},"Radio Shack":{"count":269},"Euronics":{"count":115},"Expert":{"count":123},"Эльдорадо":{"count":184},"Darty":{"count":74},"М.Видео":{"count":89},"ヤマダ電機":{"count":51}},"convenience":{"Shell":{"count":255},"Spar":{"count":1119},"McColl's":{"count":100},"Tesco Express":{"count":426},"Sainsbury's Local":{"count":104},"Aral":{"count":56},"One Stop":{"count":146},"The Co-operative Food":{"count":115},"Londis":{"count":352},"7-Eleven":{"count":4440},"CBA":{"count":135},"Coop":{"count":678},"Sale":{"count":80},"Statoil":{"count":69},"Sheetz":{"count":54},"Konzum":{"count":173},"Siwa":{"count":216},"Mercator":{"count":57},"Esso":{"count":67},"COOP Jednota":{"count":181},"Mac's":{"count":152},"Alepa":{"count":62},"Hasty Market":{"count":54},"K-Market":{"count":54},"Costcutter":{"count":292},"Valintatalo":{"count":62},"Casino":{"count":90},"Franprix":{"count":61},"Circle K":{"count":289},"セブンイレブン":{"count":3011,"tags":{"name:en":"7-Eleven"}},"ローソン":{"count":1596,"tags":{"name:en":"LAWSON"}},"BP":{"count":163},"Tesco":{"count":55},"Petit Casino":{"count":233},"Volg":{"count":116},"Mace":{"count":115},"Mini Market":{"count":272},"Nisa Local":{"count":77},"Dorfladen":{"count":75},"Продукты":{"count":4285},"Mini Stop":{"count":228},"LAWSON":{"count":419},"デイリーヤマザキ":{"count":141},"Biedronka":{"count":83},"Надежда":{"count":56},"Mobil":{"count":66},"Nisa":{"count":51},"Premier":{"count":129},"ABC":{"count":152},"ミニストップ":{"count":316,"tags":{"name:en":"MINISTOP"}},"サンクス":{"count":560,"tags":{"name:en":"sunkus"}},"スリーエフ":{"count":88},"8 à Huit":{"count":61},"Tchibo":{"count":56},"Żabka":{"count":546},"Almacen":{"count":229},"Vival":{"count":194},"FamilyMart":{"count":529},"ファミリーマート":{"count":1608,"tags":{"name:en":"FamilyMart"}},"Carrefour City":{"count":57},"Sunkus":{"count":62},"Casey's General Store":{"count":95},"セブンイレブン(Seven-Eleven)":{"count":65},"Jednota":{"count":58},"Магазин":{"count":915},"Гастроном":{"count":152},"Centra":{"count":111},"Магнит":{"count":701},"サークルK":{"count":538,"tags":{"name:en":"Circle K"}},"Wawa":{"count":135},"Proxi":{"count":123},"Универсам":{"count":78},"Перекресток":{"count":51},"Groszek":{"count":65},"Select":{"count":62},"Večerka":{"count":51},"Potraviny":{"count":249},"Смак":{"count":78},"Эконом":{"count":55},"Березка":{"count":77},"Społem":{"count":93},"Carrefour Express":{"count":84},"Cumberland Farms":{"count":63},"Chevron":{"count":59},"Coop Jednota":{"count":66},"Tesco Lotus Express":{"count":67},"Kiosk":{"count":55},"Sklep spożywczy":{"count":130},"24 часа":{"count":58},"Минимаркет":{"count":102},"Oxxo":{"count":669},"Пятёрочка":{"count":398},"abc":{"count":74},"7/11":{"count":51},"Stewart's":{"count":255},"Продукти":{"count":171},"ローソンストア100 (LAWSON STORE 100)":{"count":85},"Дикси":{"count":119},"Радуга":{"count":86},"ローソンストア100":{"count":76},"เซเว่นอีเลฟเว่น":{"count":185},"Delikatesy Centrum":{"count":53},"Citgo":{"count":62},"Фортуна":{"count":51},"Kum & Go":{"count":59},"Мария-Ра":{"count":76},"Picard":{"count":57},"Four Square":{"count":52},"Визит":{"count":57},"Авоська":{"count":55},"Dollar General":{"count":127},"Studenac":{"count":76},"Central Convenience Store":{"count":55},"Монетка":{"count":62},"продукты":{"count":114},"Теремок":{"count":56},"Kwik Trip":{"count":69},"Кулинария":{"count":55},"全家":{"count":90},"Мечта":{"count":54},"Epicerie":{"count":102},"Кировский":{"count":67},"Food Mart":{"count":117},"Delikatesy":{"count":81},"ポプラ":{"count":54},"Lewiatan":{"count":135},"Продуктовый магазин":{"count":149},"Продуктовый":{"count":84},"セイコーマート (Seicomart)":{"count":72},"Виктория":{"count":70},"Весна":{"count":57},"Mini Market Non-Stop":{"count":60},"QuikTrip":{"count":75},"Копеечка":{"count":51},"Royal Farms":{"count":51},"Alfamart":{"count":103},"Indomaret":{"count":141},"магазин":{"count":171},"全家便利商店":{"count":156},"Boutique":{"count":59},"მარკეტი (Market)":{"count":144},"Stores":{"count":61}},"chemist":{"dm":{"count":939},"Müller":{"count":212},"Schlecker":{"count":187},"Etos":{"count":467},"Bipa":{"count":289},"Rossmann":{"count":1669},"DM Drogeriemarkt":{"count":55},"Ihr Platz":{"count":73},"Douglas":{"count":62},"Kruidvat":{"count":123}},"car_repair":{"Peugeot":{"count":83},"Kwik Fit":{"count":128},"ATU":{"count":261},"Midas":{"count":202},"Feu Vert":{"count":113},"Norauto":{"count":152},"Speedy":{"count":115},"Автозапчасти":{"count":212},"Renault":{"count":171},"Pit Stop":{"count":58},"Jiffy Lube":{"count":198},"Шиномонтаж":{"count":1157},"СТО":{"count":395},"O'Reilly Auto Parts":{"count":81},"Carglass":{"count":112},"шиномонтаж":{"count":62},"Citroen":{"count":51},"Euromaster":{"count":87},"Firestone":{"count":88},"Автосервис":{"count":361},"Advance Auto Parts":{"count":52},"Roady":{"count":56}},"furniture":{"IKEA":{"count":169},"Jysk":{"count":109},"Roller":{"count":78},"Dänisches Bettenlager":{"count":309},"Conforama":{"count":99},"Matratzen Concord":{"count":52},"Мебель":{"count":210},"But":{"count":63}},"doityourself":{"Hornbach":{"count":123},"B&Q":{"count":225},"Hubo":{"count":77},"Mr Bricolage":{"count":88},"Gamma":{"count":111},"OBI":{"count":422},"Lowes":{"count":1152},"Wickes":{"count":123},"Hagebau":{"count":59},"Max Bahr":{"count":79},"Castorama":{"count":153},"Rona":{"count":61},"Home Depot":{"count":865},"Toom Baumarkt":{"count":71},"Homebase":{"count":225},"Baumax":{"count":95},"Lagerhaus":{"count":79},"Bauhaus":{"count":186},"Canadian Tire":{"count":97},"Leroy Merlin":{"count":209},"Hellweg":{"count":58},"Brico":{"count":98},"Bricomarché":{"count":235},"Toom":{"count":67},"Hagebaumarkt":{"count":107},"Praktiker":{"count":122},"Menards":{"count":70},"Weldom":{"count":73},"Bunnings Warehouse":{"count":91},"Ace Hardware":{"count":147},"Home Hardware":{"count":72},"Хозтовары":{"count":86},"Стройматериалы":{"count":197},"Bricorama":{"count":60},"Point P":{"count":59}},"stationery":{"Staples":{"count":299},"McPaper":{"count":83},"Office Depot":{"count":98},"Канцтовары":{"count":63}},"car":{"Skoda":{"count":97},"BMW":{"count":149},"Citroen":{"count":277},"Renault":{"count":382},"Mercedes-Benz":{"count":235},"Volvo":{"count":96},"Ford":{"count":239},"Volkswagen":{"count":217},"Mazda":{"count":105},"Mitsubishi":{"count":73},"Fiat":{"count":93},"Автозапчасти":{"count":277},"Opel":{"count":165},"Audi":{"count":121},"Toyota":{"count":271},"Nissan":{"count":189},"Suzuki":{"count":75},"Honda":{"count":157},"Peugeot":{"count":308},"Шиномонтаж":{"count":259},"Hyundai":{"count":166},"Subaru":{"count":58},"Chevrolet":{"count":86},"Автомагазин":{"count":72}},"clothes":{"Matalan":{"count":90},"KiK":{"count":1219},"H&M":{"count":658},"Urban Outfitters":{"count":63},"Vögele":{"count":132},"Zeeman":{"count":121},"Takko":{"count":515},"Adler":{"count":55},"C&A":{"count":506},"Zara":{"count":217},"Vero Moda":{"count":95},"NKD":{"count":486},"Ernsting's family":{"count":312},"Winners":{"count":65},"River Island":{"count":59},"Next":{"count":176},"Gap":{"count":81},"Adidas":{"count":92},"Woolworths":{"count":117},"Mr Price":{"count":88},"Jet":{"count":61},"Pep":{"count":134},"Edgars":{"count":110},"Ackermans":{"count":91},"Truworths":{"count":65},"Ross":{"count":93},"Burton":{"count":51},"Dorothy Perkins":{"count":53},"Deichmann":{"count":61},"Lindex":{"count":73},"s.Oliver":{"count":56},"Cecil":{"count":51},"Dress Barn":{"count":52},"Old Navy":{"count":174},"Jack & Jones":{"count":52},"Pimkie":{"count":73},"Esprit":{"count":231},"Primark":{"count":92},"Bonita":{"count":155},"Mexx":{"count":67},"Gerry Weber":{"count":71},"Tally Weijl":{"count":70},"Mango":{"count":133},"TK Maxx":{"count":84},"Benetton":{"count":101},"Ulla Popken":{"count":61},"AWG":{"count":66},"Tommy Hilfiger":{"count":75},"New Yorker":{"count":180},"Orsay":{"count":73},"Jeans Fritz":{"count":51},"Charles Vögele":{"count":69},"New Look":{"count":126},"Lacoste":{"count":78},"Etam":{"count":53},"Kiabi":{"count":148},"Jack Wolfskin":{"count":60},"American Apparel":{"count":57},"Men's Wearhouse":{"count":54},"Intimissimi":{"count":52},"United Colors of Benetton":{"count":96},"Jules":{"count":63},"Second Hand":{"count":53},"AOKI":{"count":57},"Calzedonia":{"count":68},"洋服の青山":{"count":100},"Levi's":{"count":63},"Celio":{"count":74},"TJ Maxx":{"count":57},"Promod":{"count":82},"Street One":{"count":72},"ユニクロ":{"count":59},"Banana Republic":{"count":57},"Одежда":{"count":75},"Marshalls":{"count":56},"La Halle":{"count":62},"Peacocks":{"count":89},"しまむら":{"count":60}},"books":{"Bruna":{"count":58},"Waterstones":{"count":90},"Libro":{"count":57},"Barnes & Noble":{"count":267},"Weltbild":{"count":74},"Thalia":{"count":121},"Книги":{"count":112}},"department_store":{"Debenhams":{"count":67},"Canadian Tire":{"count":75},"Karstadt":{"count":64},"Walmart":{"count":517},"Kmart":{"count":143},"Target":{"count":574},"Galeria Kaufhof":{"count":61},"Marks & Spencer":{"count":66},"Big W":{"count":57},"Woolworth":{"count":78},"Универмаг":{"count":72},"Sears":{"count":235},"Walmart Supercenter":{"count":101},"Kohl's":{"count":153},"Macy's":{"count":147},"Sam's Club":{"count":54},"JCPenney":{"count":66}},"alcohol":{"Alko":{"count":145},"The Beer Store":{"count":150},"Systembolaget":{"count":210},"LCBO":{"count":239},"Ароматный мир":{"count":62},"Bargain Booze":{"count":62},"Nicolas":{"count":119},"BWS":{"count":70},"Botilleria":{"count":77},"SAQ":{"count":72},"Gall & Gall":{"count":512},"Живое пиво":{"count":70}},"bakery":{"Kamps":{"count":252},"Banette":{"count":52},"Bäckerei Schmidt":{"count":57},"Anker":{"count":73},"Hofpfisterei":{"count":111},"Greggs":{"count":276},"Oebel":{"count":57},"Boulangerie":{"count":266},"Stadtbäckerei":{"count":57},"Steinecke":{"count":145},"Ihle":{"count":76},"Goldilocks":{"count":59},"Dat Backhus":{"count":67},"K&U":{"count":61},"Der Beck":{"count":96},"Thürmann":{"count":54},"Backwerk":{"count":95},"Schäfer's":{"count":51},"Panaderia":{"count":168},"Goeken backen":{"count":51},"Stadtbäckerei Junge":{"count":51},"Boulangerie Patisserie":{"count":119},"Paul":{"count":81},"Хлеб":{"count":89},"Пекарня":{"count":52},"Кулиничи":{"count":51}},"sports":{"Sports Direct":{"count":57},"Decathlon":{"count":309},"Intersport":{"count":283},"Sports Authority":{"count":75},"Спортмастер":{"count":87},"Sport 2000":{"count":90},"Dick's Sporting Goods":{"count":77}},"variety_store":{"Tedi":{"count":157},"Dollarama":{"count":103},"Family Dollar":{"count":61},"Dollar Tree":{"count":110},"Dollar General":{"count":80}},"pet":{"Fressnapf":{"count":318},"PetSmart":{"count":177},"Das Futterhaus":{"count":69},"Pets at Home":{"count":62},"Petco":{"count":101},"Зоомагазин":{"count":100}},"shoes":{"Deichmann":{"count":622},"Reno":{"count":183},"Ecco":{"count":55},"Clarks":{"count":109},"La Halle aux Chaussures":{"count":69},"Brantano":{"count":71},"Geox":{"count":51},"Salamander":{"count":51},"Обувь":{"count":100},"Payless Shoe Source":{"count":67},"Famous Footwear":{"count":59},"Quick Schuh":{"count":72},"Shoe Zone":{"count":55},"Foot Locker":{"count":82},"Bata":{"count":101},"ЦентрОбувь":{"count":51}},"toys":{"La Grande Récré":{"count":56},"Toys R Us":{"count":151,"tags":{"shop":"toys"}},"Intertoys":{"count":57},"Детский мир":{"count":86},"Игрушки":{"count":58}},"travel_agency":{"Flight Centre":{"count":92},"Thomas Cook":{"count":119}},"jewelry":{"Bijou Brigitte":{"count":57},"Christ":{"count":57},"Swarovski":{"count":74}},"optician":{"Fielmann":{"count":232},"Apollo Optik":{"count":150},"Vision Express":{"count":58},"Оптика":{"count":182},"Optic 2000":{"count":98},"Alain Afflelou":{"count":73},"Specsavers":{"count":124},"Krys":{"count":77},"Atol":{"count":55}},"video":{"Blockbuster":{"count":184},"World of Video":{"count":64}},"mobile_phone":{"Билайн":{"count":128},"ソフトバンクショップ (SoftBank shop)":{"count":255},"Vodafone":{"count":355},"O2":{"count":208},"Carphone Warehouse":{"count":127},"Orange":{"count":246},"Verizon Wireless":{"count":125},"Sprint":{"count":109},"T-Mobile":{"count":175},"МТС":{"count":352},"Евросеть":{"count":506},"Bell":{"count":190},"The Phone House":{"count":83},"SFR":{"count":71},"Связной":{"count":439},"Мегафон":{"count":251},"AT&T":{"count":124},"ドコモショップ (docomo shop)":{"count":114},"au":{"count":65},"Movistar":{"count":77},"Bitė":{"count":72}},"hifi":{},"computer":{"PC World":{"count":55},"DNS":{"count":128}},"hairdresser":{"Klier":{"count":119},"Supercuts":{"count":106},"Hairkiller":{"count":51},"Great Clips":{"count":182},"Парикмахерская":{"count":510},"Стиль":{"count":51},"Franck Provost":{"count":70},"Салон красоты":{"count":70}},"hardware":{"1000 мелочей":{"count":61},"Хозтовары":{"count":151},"Стройматериалы":{"count":54}},"motorcycle":{"Yamaha":{"count":67},"Honda":{"count":69}}}},"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"]]}]};