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, attachTo) {
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() {
6371 if (input.property('selectionEnd') === input.property('value').length) {
6379 if (!suggestions.length) return;
6380 idx = Math.max(Math.min(idx + dir, suggestions.length - 1), 0);
6381 input.property('value', suggestions[idx].value);
6387 var value = input.property('value'),
6388 start = input.property('selectionStart'),
6389 end = input.property('selectionEnd');
6392 value = value.substring(0, start);
6398 function fetch(v, cb) {
6399 fetcher.call(input, v, function(_) {
6405 function autocomplete() {
6406 var v = caseSensitive ? value() : value().toLowerCase();
6410 for (var i = 0; i < suggestions.length; i++) {
6411 var suggestion = suggestions[i].value,
6412 compare = caseSensitive ? suggestion : suggestion.toLowerCase();
6414 if (compare.indexOf(v) === 0) {
6416 input.property('value', suggestion);
6417 input.node().setSelectionRange(v.length, suggestion.length);
6424 if (suggestions.length >= minItems && document.activeElement === input.node()) {
6431 var options = container
6432 .selectAll('a.combobox-option')
6433 .data(suggestions, function(d) { return d.value; });
6435 options.enter().append('a')
6436 .attr('class', 'combobox-option')
6437 .text(function(d) { return d.value; });
6440 .attr('title', function(d) { return d.title; })
6441 .classed('selected', function(d, i) { return i == idx; })
6442 .on('mouseover', select)
6443 .on('click', accept)
6449 var node = attachTo ? attachTo.node() : input.node(),
6450 rect = node.getBoundingClientRect();
6453 'left': rect.left + 'px',
6454 'width': rect.width + 'px',
6455 'top': rect.height + rect.top + 'px'
6459 function select(d, i) {
6464 function ensureVisible() {
6465 var node = container.selectAll('a.selected').node();
6466 if (node) node.scrollIntoView();
6469 function accept(d) {
6472 .property('value', d.value)
6479 combobox.fetcher = function(_) {
6480 if (!arguments.length) return fetcher;
6485 combobox.data = function(_) {
6486 if (!arguments.length) return data;
6491 combobox.minItems = function(_) {
6492 if (!arguments.length) return minItems;
6497 combobox.caseSensitive = function(_) {
6498 if (!arguments.length) return caseSensitive;
6503 return d3.rebind(combobox, event, 'on');
6506 d3.combobox.off = function(input) {
6511 .on('focus.typeahead', null)
6512 .on('blur.typeahead', null)
6513 .on('keydown.typeahead', null)
6514 .on('keyup.typeahead', null)
6515 .on('input.typeahead', null)
6517 d3.select(this.parentNode).selectAll('.combobox-caret')
6518 .filter(function(d) { return d === input.node(); })
6519 .on('mousedown', null);
6522 d3.select(document.body)
6523 .on('scroll.combobox', null);
6525 d3.geo.tile = function() {
6526 var size = [960, 500],
6528 scaleExtent = [0, 20],
6529 translate = [size[0] / 2, size[1] / 2],
6533 return Math.min(scaleExtent[1], Math.max(scaleExtent[0], _));
6537 var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
6538 z0 = bound(Math.round(z + zoomDelta)),
6539 k = Math.pow(2, z - z0 + 8),
6540 origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
6542 cols = d3.range(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
6543 rows = d3.range(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
6545 rows.forEach(function(y) {
6546 cols.forEach(function(x) {
6547 tiles.push([x, y, z0]);
6551 tiles.translate = origin;
6557 tile.scaleExtent = function(_) {
6558 if (!arguments.length) return scaleExtent;
6563 tile.size = function(_) {
6564 if (!arguments.length) return size;
6569 tile.scale = function(_) {
6570 if (!arguments.length) return scale;
6575 tile.translate = function(_) {
6576 if (!arguments.length) return translate;
6581 tile.zoomDelta = function(_) {
6582 if (!arguments.length) return zoomDelta;
6589 d3.jsonp = function (url, callback) {
6591 var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
6593 while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
6597 function create(url) {
6598 var e = url.match(/callback=d3.jsonp.(\w+)/),
6599 c = e ? e[1] : rand();
6600 d3.jsonp[c] = function(data) {
6605 return 'd3.jsonp.' + c;
6608 var cb = create(url),
6609 script = d3.select('head')
6611 .attr('type', 'text/javascript')
6612 .attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
6615 * This code is licensed under the MIT license.
6617 * Copyright © 2013, iD authors.
6619 * Portions copyright © 2011, Keith Cirkel
6620 * See https://github.com/keithamus/jwerty
6623 d3.keybinding = function(namespace) {
6626 function matches(binding, event) {
6627 for (var p in binding.event) {
6628 if (event[p] != binding.event[p])
6634 function testBindings(isCapturing) {
6635 for (var i = 0; i < bindings.length; i++) {
6636 var binding = bindings[i];
6638 if (!!binding.capture === isCapturing && matches(binding, d3.event)) {
6644 function capture() {
6649 var tagName = d3.select(d3.event.target).node().tagName;
6650 if (tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA') {
6653 testBindings(false);
6656 function keybinding(selection) {
6657 selection = selection || d3.select(document);
6658 selection.on('keydown.capture' + namespace, capture, true);
6659 selection.on('keydown.bubble' + namespace, bubble, false);
6663 keybinding.off = function(selection) {
6665 selection = selection || d3.select(document);
6666 selection.on('keydown.capture' + namespace, null);
6667 selection.on('keydown.bubble' + namespace, null);
6671 keybinding.on = function(code, callback, capture) {
6684 code = code.toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
6686 for (var i = 0; i < code.length; i++) {
6687 // Normalise matching errors
6688 if (code[i] === '++') code[i] = '+';
6690 if (code[i] in d3.keybinding.modifierCodes) {
6691 binding.event[d3.keybinding.modifierProperties[d3.keybinding.modifierCodes[code[i]]]] = true;
6692 } else if (code[i] in d3.keybinding.keyCodes) {
6693 binding.event.keyCode = d3.keybinding.keyCodes[code[i]];
6697 bindings.push(binding);
6706 d3.keybinding.modifierCodes = {
6709 // CTRL key, on Mac: ⌃
6711 // ALT key, on Mac: ⌥ (Alt)
6712 '⌥': 18, alt: 18, option: 18,
6713 // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
6714 '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
6717 d3.keybinding.modifierProperties = {
6724 d3.keybinding.keyCodes = {
6725 // Backspace key, on Mac: ⌫ (Backspace)
6726 '⌫': 8, backspace: 8,
6727 // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
6728 '⇥': 9, '⇆': 9, tab: 9,
6730 '↩': 13, 'return': 13, enter: 13, '⌅': 13,
6732 'pause': 19, 'pause-break': 19,
6734 '⇪': 20, caps: 20, 'caps-lock': 20,
6735 // Escape key, on Mac: ⎋, on Windows: Esc
6736 '⎋': 27, escape: 27, esc: 27,
6739 // Page-Up key, or pgup, on Mac: ↖
6740 '↖': 33, pgup: 33, 'page-up': 33,
6741 // Page-Down key, or pgdown, on Mac: ↘
6742 '↘': 34, pgdown: 34, 'page-down': 34,
6743 // END key, on Mac: ⇟
6745 // HOME key, on Mac: ⇞
6747 // Insert key, or ins
6748 ins: 45, insert: 45,
6749 // Delete key, on Mac: ⌦ (Delete)
6750 '⌦': 46, del: 46, 'delete': 46,
6751 // Left Arrow Key, or ←
6752 '←': 37, left: 37, 'arrow-left': 37,
6753 // Up Arrow Key, or ↑
6754 '↑': 38, up: 38, 'arrow-up': 38,
6755 // Right Arrow Key, or →
6756 '→': 39, right: 39, 'arrow-right': 39,
6757 // Up Arrow Key, or ↓
6758 '↓': 40, down: 40, 'arrow-down': 40,
6759 // odities, printing characters that come out wrong:
6762 // Num-Multiply, or *
6763 '*': 106, star: 106, asterisk: 106, multiply: 106,
6765 '+': 107, 'plus': 107,
6766 // Num-Subtract, or -
6767 '-': 109, subtract: 109,
6773 ';': 186, semicolon: 186,
6775 '=': 187, 'equals': 187,
6777 ',': 188, comma: 188,
6779 // Period, or ., or full-stop
6780 '.': 190, period: 190, 'full-stop': 190,
6781 // Slash, or /, or forward-slash
6782 '/': 191, slash: 191, 'forward-slash': 191,
6783 // Tick, or `, or back-quote
6784 '`': 192, tick: 192, 'back-quote': 192,
6785 // Open bracket, or [
6786 '[': 219, 'open-bracket': 219,
6788 '\\': 220, 'back-slash': 220,
6789 // Close backet, or ]
6790 ']': 221, 'close-bracket': 221,
6791 // Apostrophe, or Quote, or '
6792 '\'': 222, quote: 222, apostrophe: 222
6798 d3.keybinding.keyCodes['num-' + n] = i;
6805 d3.keybinding.keyCodes[n] = i;
6812 d3.keybinding.keyCodes['f' + n] = i;
6819 d3.keybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i;
6822 d3.selection.prototype.one = function (type, listener, capture) {
6823 var target = this, typeOnce = type + ".once";
6825 target.on(typeOnce, null);
6826 listener.apply(this, arguments);
6828 target.on(typeOnce, one, capture);
6831 d3.selection.prototype.dimensions = function (dimensions) {
6832 var refresh = (function(node) {
6833 var cr = node.getBoundingClientRect();
6834 prop = [cr.width, cr.height];
6835 this.property('__dimensions__', prop);
6839 var node = this.node();
6841 if (!arguments.length) {
6842 if (!node) return [0,0];
6843 return this.property('__dimensions__') || refresh(node);
6845 if (dimensions === null) {
6846 if (!node) return [0,0];
6847 return refresh(node);
6851 .property('__dimensions__', [dimensions[0], dimensions[1]])
6852 .attr({width: dimensions[0], height: dimensions[1]});
6854 d3.selection.prototype.trigger = function (type) {
6855 this.each(function() {
6856 var evt = document.createEvent('HTMLEvents');
6857 evt.initEvent(type, true, true);
6858 this.dispatchEvent(evt);
6861 // Tooltips and svg mask used to highlight certain features
6862 d3.curtain = function() {
6864 var event = d3.dispatch(),
6869 function curtain(selection) {
6871 surface = selection.append('svg')
6872 .attr('id', 'curtain')
6875 'pointer-events': 'none',
6876 'position': 'absolute',
6881 darkness = surface.append('path')
6885 'class': 'curtain-darkness'
6888 d3.select(window).on('resize.curtain', resize);
6890 tooltip = selection.append('div')
6891 .attr('class', 'tooltip')
6892 .style('z-index', 1002);
6894 tooltip.append('div').attr('class', 'tooltip-arrow');
6895 tooltip.append('div').attr('class', 'tooltip-inner');
6901 width: window.innerWidth,
6902 height: window.innerHeight
6904 curtain.cut(darkness.datum());
6908 curtain.reveal = function(box, text, tooltipclass, duration) {
6909 if (typeof box === 'string') box = d3.select(box).node();
6910 if (box.getBoundingClientRect) box = box.getBoundingClientRect();
6912 curtain.cut(box, duration);
6915 // pseudo markdown bold text hack
6916 var parts = text.split('**');
6917 var html = parts[0] ? '<span>' + parts[0] + '</span>' : '';
6918 if (parts[1]) html += '<span class="bold">' + parts[1] + '</span>';
6920 var dimensions = tooltip.classed('in', true)
6921 .select('.tooltip-inner')
6927 var w = window.innerWidth,
6928 h = window.innerHeight;
6930 if (box.top + box.height < Math.min(100, box.width + box.left)) {
6932 pos = [box.left + box.width / 2 - dimensions[0]/ 2, box.top + box.height];
6934 } else if (box.left + box.width + 300 < window.innerWidth) {
6936 pos = [box.left + box.width, box.top + box.height / 2 - dimensions[1] / 2];
6938 } else if (box.left > 300) {
6940 pos = [box.left - 200, box.top + box.height / 2 - dimensions[1] / 2];
6943 pos = [box.left, box.top + box.height];
6947 Math.min(Math.max(10, pos[0]), w - dimensions[0] - 10),
6948 Math.min(Math.max(10, pos[1]), h - dimensions[1] - 10)
6952 if (duration !== 0 || !tooltip.classed(side)) tooltip.call(iD.ui.Toggle(true));
6955 .style('top', pos[1] + 'px')
6956 .style('left', pos[0] + 'px')
6957 .attr('class', 'curtain-tooltip tooltip in ' + side + ' ' + tooltipclass)
6958 .select('.tooltip-inner')
6962 tooltip.call(iD.ui.Toggle(false));
6966 curtain.cut = function(datum, duration) {
6967 darkness.datum(datum);
6969 (duration === 0 ? darkness : darkness.transition().duration(duration || 600))
6970 .attr('d', function(d) {
6971 var string = "M 0,0 L 0," + window.innerHeight + " L " +
6972 window.innerWidth + "," + window.innerHeight + "L" +
6973 window.innerWidth + ",0 Z";
6975 if (!d) return string;
6976 return string + 'M' +
6977 d.left + ',' + d.top + 'L' +
6978 d.left + ',' + (d.top + d.height) + 'L' +
6979 (d.left + d.width) + ',' + (d.top + d.height) + 'L' +
6980 (d.left + d.width) + ',' + (d.top) + 'Z';
6985 curtain.remove = function() {
6990 return d3.rebind(curtain, event, 'on');
6992 // Like selection.property('value', ...), but avoids no-op value sets,
6993 // which can result in layout/repaint thrashing in some situations.
6994 d3.selection.prototype.value = function(value) {
6995 function d3_selection_value(value) {
6996 function valueNull() {
7000 function valueConstant() {
7001 if (this.value !== value) this.value = value;
7004 function valueFunction() {
7005 var x = value.apply(this, arguments);
7006 if (x == null) delete this.value;
7007 else if (this.value !== x) this.value = x;
7010 return value == null
7011 ? valueNull : (typeof value === "function"
7012 ? valueFunction : valueConstant);
7015 if (!arguments.length) return this.property('value');
7016 return this.each(d3_selection_value(value));
7018 // Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
7019 // Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
7021 // Permission is hereby granted, free of charge, to any person
7022 // obtaining a copy of this software and associated documentation files
7023 // (the "Software"), to deal in the Software without restriction,
7024 // including without limitation the rights to use, copy, modify, merge,
7025 // publish, distribute, sublicense, and/or sell copies of the Software,
7026 // and to permit persons to whom the Software is furnished to do so,
7027 // subject to the following conditions:
7029 // The above copyright notice and this permission notice shall be
7030 // included in all copies or substantial portions of the Software.
7032 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
7033 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
7034 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
7035 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
7036 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
7037 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
7038 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
7041 // source: https://bitbucket.org/lshift/synchrotron/src
7043 Diff3 = (function() {
7047 longest_common_subsequence: function(file1, file2) {
7048 /* Text diff algorithm following Hunt and McIlroy 1976.
7049 * J. W. Hunt and M. D. McIlroy, An algorithm for differential file
7050 * comparison, Bell Telephone Laboratories CSTR #41 (1976)
7051 * http://www.cs.dartmouth.edu/~doug/
7053 * Expects two arrays of strings.
7055 var equivalenceClasses;
7060 var c, i, j, jX, r, s;
7062 equivalenceClasses = {};
7063 for (j = 0; j < file2.length; j++) {
7065 if (equivalenceClasses[line]) {
7066 equivalenceClasses[line].push(j);
7068 equivalenceClasses[line] = [j];
7072 candidates = [{file1index: -1,
7076 for (i = 0; i < file1.length; i++) {
7078 file2indices = equivalenceClasses[line] || [];
7083 for (jX = 0; jX < file2indices.length; jX++) {
7084 j = file2indices[jX];
7086 for (s = 0; s < candidates.length; s++) {
7087 if ((candidates[s].file2index < j) &&
7088 ((s == candidates.length - 1) ||
7089 (candidates[s + 1].file2index > j)))
7093 if (s < candidates.length) {
7094 newCandidate = {file1index: i,
7096 chain: candidates[s]};
7097 if (r == candidates.length) {
7104 if (r == candidates.length) {
7105 break; // no point in examining further (j)s
7113 // At this point, we know the LCS: it's in the reverse of the
7114 // linked-list through .chain of
7115 // candidates[candidates.length - 1].
7117 return candidates[candidates.length - 1];
7120 diff_comm: function(file1, file2) {
7121 // We apply the LCS to build a "comm"-style picture of the
7122 // differences between file1 and file2.
7125 var tail1 = file1.length;
7126 var tail2 = file2.length;
7127 var common = {common: []};
7129 function processCommon() {
7130 if (common.common.length) {
7131 common.common.reverse();
7132 result.push(common);
7133 common = {common: []};
7137 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7139 candidate = candidate.chain)
7141 var different = {file1: [], file2: []};
7143 while (--tail1 > candidate.file1index) {
7144 different.file1.push(file1[tail1]);
7147 while (--tail2 > candidate.file2index) {
7148 different.file2.push(file2[tail2]);
7151 if (different.file1.length || different.file2.length) {
7153 different.file1.reverse();
7154 different.file2.reverse();
7155 result.push(different);
7159 common.common.push(file1[tail1]);
7169 diff_patch: function(file1, file2) {
7170 // We apply the LCD to build a JSON representation of a
7171 // diff(1)-style patch.
7174 var tail1 = file1.length;
7175 var tail2 = file2.length;
7177 function chunkDescription(file, offset, length) {
7179 for (var i = 0; i < length; i++) {
7180 chunk.push(file[offset + i]);
7182 return {offset: offset,
7187 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7189 candidate = candidate.chain)
7191 var mismatchLength1 = tail1 - candidate.file1index - 1;
7192 var mismatchLength2 = tail2 - candidate.file2index - 1;
7193 tail1 = candidate.file1index;
7194 tail2 = candidate.file2index;
7196 if (mismatchLength1 || mismatchLength2) {
7197 result.push({file1: chunkDescription(file1,
7198 candidate.file1index + 1,
7200 file2: chunkDescription(file2,
7201 candidate.file2index + 1,
7210 strip_patch: function(patch) {
7211 // Takes the output of Diff3.diff_patch(), and removes
7212 // information from it. It can still be used by patch(),
7213 // below, but can no longer be inverted.
7215 for (var i = 0; i < patch.length; i++) {
7216 var chunk = patch[i];
7217 newpatch.push({file1: {offset: chunk.file1.offset,
7218 length: chunk.file1.length},
7219 file2: {chunk: chunk.file2.chunk}});
7224 invert_patch: function(patch) {
7225 // Takes the output of Diff3.diff_patch(), and inverts the
7226 // sense of it, so that it can be applied to file2 to give
7227 // file1 rather than the other way around.
7229 for (var i = 0; i < patch.length; i++) {
7230 var chunk = patch[i];
7231 var tmp = chunk.file1;
7232 chunk.file1 = chunk.file2;
7237 patch: function (file, patch) {
7238 // Applies a patch to a file.
7240 // Given file1 and file2, Diff3.patch(file1,
7241 // Diff3.diff_patch(file1, file2)) should give file2.
7244 var commonOffset = 0;
7246 function copyCommon(targetOffset) {
7247 while (commonOffset < targetOffset) {
7248 result.push(file[commonOffset]);
7253 for (var chunkIndex = 0; chunkIndex < patch.length; chunkIndex++) {
7254 var chunk = patch[chunkIndex];
7255 copyCommon(chunk.file1.offset);
7256 for (var lineIndex = 0; lineIndex < chunk.file2.chunk.length; lineIndex++) {
7257 result.push(chunk.file2.chunk[lineIndex]);
7259 commonOffset += chunk.file1.length;
7262 copyCommon(file.length);
7266 diff_indices: function(file1, file2) {
7267 // We apply the LCS to give a simple representation of the
7268 // offsets and lengths of mismatched chunks in the input
7269 // files. This is used by diff3_merge_indices below.
7272 var tail1 = file1.length;
7273 var tail2 = file2.length;
7275 for (var candidate = Diff3.longest_common_subsequence(file1, file2);
7277 candidate = candidate.chain)
7279 var mismatchLength1 = tail1 - candidate.file1index - 1;
7280 var mismatchLength2 = tail2 - candidate.file2index - 1;
7281 tail1 = candidate.file1index;
7282 tail2 = candidate.file2index;
7284 if (mismatchLength1 || mismatchLength2) {
7285 result.push({file1: [tail1 + 1, mismatchLength1],
7286 file2: [tail2 + 1, mismatchLength2]});
7294 diff3_merge_indices: function (a, o, b) {
7295 // Given three files, A, O, and B, where both A and B are
7296 // independently derived from O, returns a fairly complicated
7297 // internal representation of merge decisions it's taken. The
7298 // interested reader may wish to consult
7300 // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
7301 // Formal Investigation of Diff3." In Arvind and Prasad,
7302 // editors, Foundations of Software Technology and Theoretical
7303 // Computer Science (FSTTCS), December 2007.
7305 // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
7308 var m1 = Diff3.diff_indices(o, a);
7309 var m2 = Diff3.diff_indices(o, b);
7312 function addHunk(h, side) {
7313 hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]);
7315 for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); }
7316 for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); }
7320 var commonOffset = 0;
7321 function copyCommon(targetOffset) {
7322 if (targetOffset > commonOffset) {
7323 result.push([1, commonOffset, targetOffset - commonOffset]);
7324 commonOffset = targetOffset;
7328 for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {
7329 var firstHunkIndex = hunkIndex;
7330 var hunk = hunks[hunkIndex];
7331 var regionLhs = hunk[0];
7332 var regionRhs = regionLhs + hunk[2];
7333 while (hunkIndex < hunks.length - 1) {
7334 var maybeOverlapping = hunks[hunkIndex + 1];
7335 var maybeLhs = maybeOverlapping[0];
7336 if (maybeLhs > regionRhs) break;
7337 regionRhs = maybeLhs + maybeOverlapping[2];
7341 copyCommon(regionLhs);
7342 if (firstHunkIndex == hunkIndex) {
7343 // The "overlap" was only one hunk long, meaning that
7344 // there's no conflict here. Either a and o were the
7345 // same, or b and o were the same.
7347 result.push([hunk[1], hunk[3], hunk[4]]);
7350 // A proper conflict. Determine the extents of the
7351 // regions involved from a, o and b. Effectively merge
7352 // all the hunks on the left into one giant hunk, and
7353 // do the same for the right; then, correct for skew
7354 // in the regions of o that each side changed, and
7355 // report appropriate spans for the three sides.
7357 0: [a.length, -1, o.length, -1],
7358 2: [b.length, -1, o.length, -1]
7360 for (i = firstHunkIndex; i <= hunkIndex; i++) {
7363 var r = regions[side];
7365 var oRhs = oLhs + hunk[2];
7366 var abLhs = hunk[3];
7367 var abRhs = abLhs + hunk[4];
7368 r[0] = Math.min(abLhs, r[0]);
7369 r[1] = Math.max(abRhs, r[1]);
7370 r[2] = Math.min(oLhs, r[2]);
7371 r[3] = Math.max(oRhs, r[3]);
7373 var aLhs = regions[0][0] + (regionLhs - regions[0][2]);
7374 var aRhs = regions[0][1] + (regionRhs - regions[0][3]);
7375 var bLhs = regions[2][0] + (regionLhs - regions[2][2]);
7376 var bRhs = regions[2][1] + (regionRhs - regions[2][3]);
7379 regionLhs, regionRhs - regionLhs,
7380 bLhs, bRhs - bLhs]);
7382 commonOffset = regionRhs;
7385 copyCommon(o.length);
7389 diff3_merge: function (a, o, b, excludeFalseConflicts) {
7390 // Applies the output of Diff3.diff3_merge_indices to actually
7391 // construct the merged file; the returned result alternates
7392 // between "ok" and "conflict" blocks.
7395 var files = [a, o, b];
7396 var indices = Diff3.diff3_merge_indices(a, o, b);
7399 function flushOk() {
7400 if (okLines.length) {
7401 result.push({ok: okLines});
7405 function pushOk(xs) {
7406 for (var j = 0; j < xs.length; j++) {
7407 okLines.push(xs[j]);
7411 function isTrueConflict(rec) {
7412 if (rec[2] != rec[6]) return true;
7415 for (var j = 0; j < rec[2]; j++) {
7416 if (a[j + aoff] != b[j + boff]) return true;
7421 for (var i = 0; i < indices.length; i++) {
7425 if (excludeFalseConflicts && !isTrueConflict(x)) {
7426 pushOk(files[0].slice(x[1], x[1] + x[2]));
7429 result.push({conflict: {a: a.slice(x[1], x[1] + x[2]),
7431 o: o.slice(x[3], x[3] + x[4]),
7433 b: b.slice(x[5], x[5] + x[6]),
7437 pushOk(files[side].slice(x[1], x[1] + x[2]));
7448 if (typeof module !== 'undefined') module.exports = Diff3;
7449 var JXON = new (function () {
7451 sValueProp = "keyValue", sAttributesProp = "keyAttributes", sAttrPref = "@", /* you can customize these values */
7452 aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
7454 function parseText (sValue) {
7455 if (rIsNull.test(sValue)) { return null; }
7456 if (rIsBool.test(sValue)) { return sValue.toLowerCase() === "true"; }
7457 if (isFinite(sValue)) { return parseFloat(sValue); }
7458 if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
7462 function EmptyTree () { }
7463 EmptyTree.prototype.toString = function () { return "null"; };
7464 EmptyTree.prototype.valueOf = function () { return null; };
7466 function objectify (vValue) {
7467 return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
7470 function createObjTree (oParentNode, nVerb, bFreeze, bNesteAttr) {
7472 nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(),
7473 bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
7476 sProp, vContent, nLength = 0, sCollectedTxt = "",
7477 vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
7480 for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
7481 oNode = oParentNode.childNodes.item(nItem);
7482 if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is "CDATASection" (4) */
7483 else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is "Text" (3) */
7484 else if (oNode.nodeType === 1 && !oNode.prefix) { aCache.push(oNode); } /* nodeType is "Element" (1) */
7488 var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
7490 if (!bHighVerb && (bChildren || bAttributes)) { vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; }
7492 for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
7493 sProp = aCache[nElId].nodeName.toLowerCase();
7494 vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
7495 if (vResult.hasOwnProperty(sProp)) {
7496 if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; }
7497 vResult[sProp].push(vContent);
7499 vResult[sProp] = vContent;
7506 nAttrLen = oParentNode.attributes.length,
7507 sAPrefix = bNesteAttr ? "" : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
7509 for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
7510 oAttrib = oParentNode.attributes.item(nAttrib);
7511 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
7515 if (bFreeze) { Object.freeze(oAttrParent); }
7516 vResult[sAttributesProp] = oAttrParent;
7517 nLength -= nAttrLen - 1;
7521 if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
7522 vResult[sValueProp] = vBuiltVal;
7523 } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
7524 vResult = vBuiltVal;
7527 if (bFreeze && (bHighVerb || nLength > 0)) { Object.freeze(vResult); }
7529 aCache.length = nLevelStart;
7534 function loadObjTree (oXMLDoc, oParentEl, oParentObj) {
7537 if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
7538 oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
7539 } else if (oParentObj.constructor === Date) {
7540 oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
7543 for (var sName in oParentObj) {
7544 vValue = oParentObj[sName];
7545 if (isFinite(sName) || vValue instanceof Function) { continue; } /* verbosity level is 0 */
7546 if (sName === sValueProp) {
7547 if (vValue !== null && vValue !== true) { oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); }
7548 } else if (sName === sAttributesProp) { /* verbosity level is 3 */
7549 for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); }
7550 } else if (sName.charAt(0) === sAttrPref) {
7551 oParentEl.setAttribute(sName.slice(1), vValue);
7552 } else if (vValue.constructor === Array) {
7553 for (var nItem = 0; nItem < vValue.length; nItem++) {
7554 oChild = oXMLDoc.createElement(sName);
7555 loadObjTree(oXMLDoc, oChild, vValue[nItem]);
7556 oParentEl.appendChild(oChild);
7559 oChild = oXMLDoc.createElement(sName);
7560 if (vValue instanceof Object) {
7561 loadObjTree(oXMLDoc, oChild, vValue);
7562 } else if (vValue !== null && vValue !== true) {
7563 oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
7565 oParentEl.appendChild(oChild);
7570 this.build = function (oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
7571 var _nVerb = arguments.length > 1 && typeof nVerbosity === "number" ? nVerbosity & 3 : /* put here the default verbosity level: */ 1;
7572 return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
7575 this.unbuild = function (oObjTree) {
7576 var oNewDoc = document.implementation.createDocument("", "", null);
7577 loadObjTree(oNewDoc, oNewDoc, oObjTree);
7581 this.stringify = function (oObjTree) {
7582 return (new XMLSerializer()).serializeToString(JXON.unbuild(oObjTree));
7585 // var myObject = JXON.build(doc);
7586 // we got our javascript object! try: alert(JSON.stringify(myObject));
7588 // var newDoc = JXON.unbuild(myObject);
7589 // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
7592 * lodash (Custom Build) <https://lodash.com/>
7593 * Build: `lodash --development --output js/lib/lodash.js include="includes,toPairs,assign,bind,chunk,clone,compact,debounce,difference,each,every,extend,filter,find,first,forEach,forOwn,groupBy,indexOf,intersection,isEmpty,isEqual,isFunction,keys,last,map,omit,reject,some,throttle,union,uniq,values,without,flatten,value,chain,cloneDeep,merge,pick,reduce" exports="global,node"`
7594 * Copyright jQuery Foundation and other contributors <https://jquery.org/>
7595 * Released under MIT license <https://lodash.com/license>
7596 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
7597 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
7601 /** Used as a safe reference for `undefined` in pre-ES5 environments. */
7604 /** Used as the semantic version number. */
7605 var VERSION = '4.12.0';
7607 /** Used as the size to enable large array optimizations. */
7608 var LARGE_ARRAY_SIZE = 200;
7610 /** Used as the `TypeError` message for "Functions" methods. */
7611 var FUNC_ERROR_TEXT = 'Expected a function';
7613 /** Used to stand-in for `undefined` hash values. */
7614 var HASH_UNDEFINED = '__lodash_hash_undefined__';
7616 /** Used as the internal argument placeholder. */
7617 var PLACEHOLDER = '__lodash_placeholder__';
7619 /** Used to compose bitmasks for wrapper metadata. */
7622 CURRY_BOUND_FLAG = 4,
7624 CURRY_RIGHT_FLAG = 16,
7626 PARTIAL_RIGHT_FLAG = 64,
7631 /** Used to compose bitmasks for comparison styles. */
7632 var UNORDERED_COMPARE_FLAG = 1,
7633 PARTIAL_COMPARE_FLAG = 2;
7635 /** Used to detect hot functions by number of calls within a span of milliseconds. */
7636 var HOT_COUNT = 150,
7639 /** Used to indicate the type of lazy iteratees. */
7640 var LAZY_FILTER_FLAG = 1,
7642 LAZY_WHILE_FLAG = 3;
7644 /** Used as references for various `Number` constants. */
7645 var INFINITY = 1 / 0,
7646 MAX_SAFE_INTEGER = 9007199254740991,
7647 MAX_INTEGER = 1.7976931348623157e+308,
7650 /** Used as references for the maximum length and index of an array. */
7651 var MAX_ARRAY_LENGTH = 4294967295;
7653 /** `Object#toString` result references. */
7654 var argsTag = '[object Arguments]',
7655 arrayTag = '[object Array]',
7656 boolTag = '[object Boolean]',
7657 dateTag = '[object Date]',
7658 errorTag = '[object Error]',
7659 funcTag = '[object Function]',
7660 genTag = '[object GeneratorFunction]',
7661 mapTag = '[object Map]',
7662 numberTag = '[object Number]',
7663 objectTag = '[object Object]',
7664 promiseTag = '[object Promise]',
7665 regexpTag = '[object RegExp]',
7666 setTag = '[object Set]',
7667 stringTag = '[object String]',
7668 symbolTag = '[object Symbol]',
7669 weakMapTag = '[object WeakMap]';
7671 var arrayBufferTag = '[object ArrayBuffer]',
7672 dataViewTag = '[object DataView]',
7673 float32Tag = '[object Float32Array]',
7674 float64Tag = '[object Float64Array]',
7675 int8Tag = '[object Int8Array]',
7676 int16Tag = '[object Int16Array]',
7677 int32Tag = '[object Int32Array]',
7678 uint8Tag = '[object Uint8Array]',
7679 uint8ClampedTag = '[object Uint8ClampedArray]',
7680 uint16Tag = '[object Uint16Array]',
7681 uint32Tag = '[object Uint32Array]';
7683 /** Used to match property names within property paths. */
7684 var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
7685 reIsPlainProp = /^\w*$/,
7686 rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]/g;
7689 * Used to match `RegExp`
7690 * [syntax characters](http://ecma-international.org/ecma-262/6.0/#sec-patterns).
7692 var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
7694 /** Used to match leading and trailing whitespace. */
7695 var reTrim = /^\s+|\s+$/g;
7697 /** Used to match backslashes in property paths. */
7698 var reEscapeChar = /\\(\\)?/g;
7700 /** Used to match `RegExp` flags from their coerced string values. */
7701 var reFlags = /\w*$/;
7703 /** Used to detect bad signed hexadecimal string values. */
7704 var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
7706 /** Used to detect binary string values. */
7707 var reIsBinary = /^0b[01]+$/i;
7709 /** Used to detect host constructors (Safari). */
7710 var reIsHostCtor = /^\[object .+?Constructor\]$/;
7712 /** Used to detect octal string values. */
7713 var reIsOctal = /^0o[0-7]+$/i;
7715 /** Used to detect unsigned integer values. */
7716 var reIsUint = /^(?:0|[1-9]\d*)$/;
7718 /** Used to compose unicode character classes. */
7719 var rsAstralRange = '\\ud800-\\udfff',
7720 rsComboMarksRange = '\\u0300-\\u036f\\ufe20-\\ufe23',
7721 rsComboSymbolsRange = '\\u20d0-\\u20f0',
7722 rsVarRange = '\\ufe0e\\ufe0f';
7724 /** Used to compose unicode capture groups. */
7725 var rsAstral = '[' + rsAstralRange + ']',
7726 rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']',
7727 rsFitz = '\\ud83c[\\udffb-\\udfff]',
7728 rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
7729 rsNonAstral = '[^' + rsAstralRange + ']',
7730 rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
7731 rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
7734 /** Used to compose unicode regexes. */
7735 var reOptMod = rsModifier + '?',
7736 rsOptVar = '[' + rsVarRange + ']?',
7737 rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
7738 rsSeq = rsOptVar + reOptMod + rsOptJoin,
7739 rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
7741 /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
7742 var reComplexSymbol = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
7744 /** Used to identify `toStringTag` values of typed arrays. */
7745 var typedArrayTags = {};
7746 typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
7747 typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
7748 typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
7749 typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
7750 typedArrayTags[uint32Tag] = true;
7751 typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
7752 typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
7753 typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
7754 typedArrayTags[errorTag] = typedArrayTags[funcTag] =
7755 typedArrayTags[mapTag] = typedArrayTags[numberTag] =
7756 typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
7757 typedArrayTags[setTag] = typedArrayTags[stringTag] =
7758 typedArrayTags[weakMapTag] = false;
7760 /** Used to identify `toStringTag` values supported by `_.clone`. */
7761 var cloneableTags = {};
7762 cloneableTags[argsTag] = cloneableTags[arrayTag] =
7763 cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
7764 cloneableTags[boolTag] = cloneableTags[dateTag] =
7765 cloneableTags[float32Tag] = cloneableTags[float64Tag] =
7766 cloneableTags[int8Tag] = cloneableTags[int16Tag] =
7767 cloneableTags[int32Tag] = cloneableTags[mapTag] =
7768 cloneableTags[numberTag] = cloneableTags[objectTag] =
7769 cloneableTags[regexpTag] = cloneableTags[setTag] =
7770 cloneableTags[stringTag] = cloneableTags[symbolTag] =
7771 cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
7772 cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
7773 cloneableTags[errorTag] = cloneableTags[funcTag] =
7774 cloneableTags[weakMapTag] = false;
7776 /** Used to determine if values are of the language type `Object`. */
7782 /** Built-in method references without a dependency on `root`. */
7783 var freeParseInt = parseInt;
7785 /** Detect free variable `exports`. */
7786 var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType)
7790 /** Detect free variable `module`. */
7791 var freeModule = (objectTypes[typeof module] && module && !module.nodeType)
7795 /** Detect the popular CommonJS extension `module.exports`. */
7796 var moduleExports = (freeModule && freeModule.exports === freeExports)
7800 /** Detect free variable `global` from Node.js. */
7801 var freeGlobal = checkGlobal(freeExports && freeModule && typeof global == 'object' && global);
7803 /** Detect free variable `self`. */
7804 var freeSelf = checkGlobal(objectTypes[typeof self] && self);
7806 /** Detect free variable `window`. */
7807 var freeWindow = checkGlobal(objectTypes[typeof window] && window);
7809 /** Detect `this` as the global object. */
7810 var thisGlobal = checkGlobal(objectTypes[typeof this] && this);
7813 * Used as a reference to the global object.
7815 * The `this` value is used if it's the global object to avoid Greasemonkey's
7816 * restricted `window` object, otherwise the `window` object is used.
7818 var root = freeGlobal ||
7819 ((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) ||
7820 freeSelf || thisGlobal || Function('return this')();
7822 /*--------------------------------------------------------------------------*/
7825 * Adds the key-value `pair` to `map`.
7828 * @param {Object} map The map to modify.
7829 * @param {Array} pair The key-value pair to add.
7830 * @returns {Object} Returns `map`.
7832 function addMapEntry(map, pair) {
7833 // Don't return `Map#set` because it doesn't return the map instance in IE 11.
7834 map.set(pair[0], pair[1]);
7839 * Adds `value` to `set`.
7842 * @param {Object} set The set to modify.
7843 * @param {*} value The value to add.
7844 * @returns {Object} Returns `set`.
7846 function addSetEntry(set, value) {
7852 * A faster alternative to `Function#apply`, this function invokes `func`
7853 * with the `this` binding of `thisArg` and the arguments of `args`.
7856 * @param {Function} func The function to invoke.
7857 * @param {*} thisArg The `this` binding of `func`.
7858 * @param {Array} args The arguments to invoke `func` with.
7859 * @returns {*} Returns the result of `func`.
7861 function apply(func, thisArg, args) {
7862 var length = args.length;
7864 case 0: return func.call(thisArg);
7865 case 1: return func.call(thisArg, args[0]);
7866 case 2: return func.call(thisArg, args[0], args[1]);
7867 case 3: return func.call(thisArg, args[0], args[1], args[2]);
7869 return func.apply(thisArg, args);
7873 * A specialized version of `baseAggregator` for arrays.
7876 * @param {Array} array The array to iterate over.
7877 * @param {Function} setter The function to set `accumulator` values.
7878 * @param {Function} iteratee The iteratee to transform keys.
7879 * @param {Object} accumulator The initial aggregated object.
7880 * @returns {Function} Returns `accumulator`.
7882 function arrayAggregator(array, setter, iteratee, accumulator) {
7884 length = array.length;
7886 while (++index < length) {
7887 var value = array[index];
7888 setter(accumulator, value, iteratee(value), array);
7894 * A specialized version of `_.forEach` for arrays without support for
7895 * iteratee shorthands.
7898 * @param {Array} array The array to iterate over.
7899 * @param {Function} iteratee The function invoked per iteration.
7900 * @returns {Array} Returns `array`.
7902 function arrayEach(array, iteratee) {
7904 length = array.length;
7906 while (++index < length) {
7907 if (iteratee(array[index], index, array) === false) {
7915 * A specialized version of `_.every` for arrays without support for
7916 * iteratee shorthands.
7919 * @param {Array} array The array to iterate over.
7920 * @param {Function} predicate The function invoked per iteration.
7921 * @returns {boolean} Returns `true` if all elements pass the predicate check,
7924 function arrayEvery(array, predicate) {
7926 length = array.length;
7928 while (++index < length) {
7929 if (!predicate(array[index], index, array)) {
7937 * A specialized version of `_.filter` for arrays without support for
7938 * iteratee shorthands.
7941 * @param {Array} array The array to iterate over.
7942 * @param {Function} predicate The function invoked per iteration.
7943 * @returns {Array} Returns the new filtered array.
7945 function arrayFilter(array, predicate) {
7947 length = array.length,
7951 while (++index < length) {
7952 var value = array[index];
7953 if (predicate(value, index, array)) {
7954 result[resIndex++] = value;
7961 * A specialized version of `_.includes` for arrays without support for
7962 * specifying an index to search from.
7965 * @param {Array} array The array to search.
7966 * @param {*} target The value to search for.
7967 * @returns {boolean} Returns `true` if `target` is found, else `false`.
7969 function arrayIncludes(array, value) {
7970 return !!array.length && baseIndexOf(array, value, 0) > -1;
7974 * This function is like `arrayIncludes` except that it accepts a comparator.
7977 * @param {Array} array The array to search.
7978 * @param {*} target The value to search for.
7979 * @param {Function} comparator The comparator invoked per element.
7980 * @returns {boolean} Returns `true` if `target` is found, else `false`.
7982 function arrayIncludesWith(array, value, comparator) {
7984 length = array.length;
7986 while (++index < length) {
7987 if (comparator(value, array[index])) {
7995 * A specialized version of `_.map` for arrays without support for iteratee
7999 * @param {Array} array The array to iterate over.
8000 * @param {Function} iteratee The function invoked per iteration.
8001 * @returns {Array} Returns the new mapped array.
8003 function arrayMap(array, iteratee) {
8005 length = array.length,
8006 result = Array(length);
8008 while (++index < length) {
8009 result[index] = iteratee(array[index], index, array);
8015 * Appends the elements of `values` to `array`.
8018 * @param {Array} array The array to modify.
8019 * @param {Array} values The values to append.
8020 * @returns {Array} Returns `array`.
8022 function arrayPush(array, values) {
8024 length = values.length,
8025 offset = array.length;
8027 while (++index < length) {
8028 array[offset + index] = values[index];
8034 * A specialized version of `_.reduce` for arrays without support for
8035 * iteratee shorthands.
8038 * @param {Array} array The array to iterate over.
8039 * @param {Function} iteratee The function invoked per iteration.
8040 * @param {*} [accumulator] The initial value.
8041 * @param {boolean} [initAccum] Specify using the first element of `array` as
8042 * the initial value.
8043 * @returns {*} Returns the accumulated value.
8045 function arrayReduce(array, iteratee, accumulator, initAccum) {
8047 length = array.length;
8049 if (initAccum && length) {
8050 accumulator = array[++index];
8052 while (++index < length) {
8053 accumulator = iteratee(accumulator, array[index], index, array);
8059 * A specialized version of `_.some` for arrays without support for iteratee
8063 * @param {Array} array The array to iterate over.
8064 * @param {Function} predicate The function invoked per iteration.
8065 * @returns {boolean} Returns `true` if any element passes the predicate check,
8068 function arraySome(array, predicate) {
8070 length = array.length;
8072 while (++index < length) {
8073 if (predicate(array[index], index, array)) {
8081 * The base implementation of methods like `_.find` and `_.findKey`, without
8082 * support for iteratee shorthands, which iterates over `collection` using
8086 * @param {Array|Object} collection The collection to search.
8087 * @param {Function} predicate The function invoked per iteration.
8088 * @param {Function} eachFunc The function to iterate over `collection`.
8089 * @param {boolean} [retKey] Specify returning the key of the found element
8090 * instead of the element itself.
8091 * @returns {*} Returns the found element or its key, else `undefined`.
8093 function baseFind(collection, predicate, eachFunc, retKey) {
8095 eachFunc(collection, function(value, key, collection) {
8096 if (predicate(value, key, collection)) {
8097 result = retKey ? key : value;
8105 * The base implementation of `_.findIndex` and `_.findLastIndex` without
8106 * support for iteratee shorthands.
8109 * @param {Array} array The array to search.
8110 * @param {Function} predicate The function invoked per iteration.
8111 * @param {boolean} [fromRight] Specify iterating from right to left.
8112 * @returns {number} Returns the index of the matched value, else `-1`.
8114 function baseFindIndex(array, predicate, fromRight) {
8115 var length = array.length,
8116 index = fromRight ? length : -1;
8118 while ((fromRight ? index-- : ++index < length)) {
8119 if (predicate(array[index], index, array)) {
8127 * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
8130 * @param {Array} array The array to search.
8131 * @param {*} value The value to search for.
8132 * @param {number} fromIndex The index to search from.
8133 * @returns {number} Returns the index of the matched value, else `-1`.
8135 function baseIndexOf(array, value, fromIndex) {
8136 if (value !== value) {
8137 return indexOfNaN(array, fromIndex);
8139 var index = fromIndex - 1,
8140 length = array.length;
8142 while (++index < length) {
8143 if (array[index] === value) {
8151 * The base implementation of `_.reduce` and `_.reduceRight`, without support
8152 * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
8155 * @param {Array|Object} collection The collection to iterate over.
8156 * @param {Function} iteratee The function invoked per iteration.
8157 * @param {*} accumulator The initial value.
8158 * @param {boolean} initAccum Specify using the first or last element of
8159 * `collection` as the initial value.
8160 * @param {Function} eachFunc The function to iterate over `collection`.
8161 * @returns {*} Returns the accumulated value.
8163 function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
8164 eachFunc(collection, function(value, index, collection) {
8165 accumulator = initAccum
8166 ? (initAccum = false, value)
8167 : iteratee(accumulator, value, index, collection);
8173 * The base implementation of `_.times` without support for iteratee shorthands
8174 * or max array length checks.
8177 * @param {number} n The number of times to invoke `iteratee`.
8178 * @param {Function} iteratee The function invoked per iteration.
8179 * @returns {Array} Returns the array of results.
8181 function baseTimes(n, iteratee) {
8185 while (++index < n) {
8186 result[index] = iteratee(index);
8192 * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
8193 * of key-value pairs for `object` corresponding to the property names of `props`.
8196 * @param {Object} object The object to query.
8197 * @param {Array} props The property names to get values for.
8198 * @returns {Object} Returns the key-value pairs.
8200 function baseToPairs(object, props) {
8201 return arrayMap(props, function(key) {
8202 return [key, object[key]];
8207 * The base implementation of `_.unary` without support for storing wrapper metadata.
8210 * @param {Function} func The function to cap arguments for.
8211 * @returns {Function} Returns the new capped function.
8213 function baseUnary(func) {
8214 return function(value) {
8220 * The base implementation of `_.values` and `_.valuesIn` which creates an
8221 * array of `object` property values corresponding to the property names
8225 * @param {Object} object The object to query.
8226 * @param {Array} props The property names to get values for.
8227 * @returns {Object} Returns the array of property values.
8229 function baseValues(object, props) {
8230 return arrayMap(props, function(key) {
8236 * Checks if a cache value for `key` exists.
8239 * @param {Object} cache The cache to query.
8240 * @param {string} key The key of the entry to check.
8241 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
8243 function cacheHas(cache, key) {
8244 return cache.has(key);
8248 * Checks if `value` is a global object.
8251 * @param {*} value The value to check.
8252 * @returns {null|Object} Returns `value` if it's a global object, else `null`.
8254 function checkGlobal(value) {
8255 return (value && value.Object === Object) ? value : null;
8259 * Gets the number of `placeholder` occurrences in `array`.
8262 * @param {Array} array The array to inspect.
8263 * @param {*} placeholder The placeholder to search for.
8264 * @returns {number} Returns the placeholder count.
8266 function countHolders(array, placeholder) {
8267 var length = array.length,
8271 if (array[length] === placeholder) {
8279 * Gets the index at which the first occurrence of `NaN` is found in `array`.
8282 * @param {Array} array The array to search.
8283 * @param {number} fromIndex The index to search from.
8284 * @param {boolean} [fromRight] Specify iterating from right to left.
8285 * @returns {number} Returns the index of the matched `NaN`, else `-1`.
8287 function indexOfNaN(array, fromIndex, fromRight) {
8288 var length = array.length,
8289 index = fromIndex + (fromRight ? 0 : -1);
8291 while ((fromRight ? index-- : ++index < length)) {
8292 var other = array[index];
8293 if (other !== other) {
8301 * Checks if `value` is a host object in IE < 9.
8304 * @param {*} value The value to check.
8305 * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
8307 function isHostObject(value) {
8308 // Many host objects are `Object` objects that can coerce to strings
8309 // despite having improperly defined `toString` methods.
8311 if (value != null && typeof value.toString != 'function') {
8313 result = !!(value + '');
8320 * Converts `iterator` to an array.
8323 * @param {Object} iterator The iterator to convert.
8324 * @returns {Array} Returns the converted array.
8326 function iteratorToArray(iterator) {
8330 while (!(data = iterator.next()).done) {
8331 result.push(data.value);
8337 * Converts `map` to its key-value pairs.
8340 * @param {Object} map The map to convert.
8341 * @returns {Array} Returns the key-value pairs.
8343 function mapToArray(map) {
8345 result = Array(map.size);
8347 map.forEach(function(value, key) {
8348 result[++index] = [key, value];
8354 * Replaces all `placeholder` elements in `array` with an internal placeholder
8355 * and returns an array of their indexes.
8358 * @param {Array} array The array to modify.
8359 * @param {*} placeholder The placeholder to replace.
8360 * @returns {Array} Returns the new array of placeholder indexes.
8362 function replaceHolders(array, placeholder) {
8364 length = array.length,
8368 while (++index < length) {
8369 var value = array[index];
8370 if (value === placeholder || value === PLACEHOLDER) {
8371 array[index] = PLACEHOLDER;
8372 result[resIndex++] = index;
8379 * Converts `set` to an array of its values.
8382 * @param {Object} set The set to convert.
8383 * @returns {Array} Returns the values.
8385 function setToArray(set) {
8387 result = Array(set.size);
8389 set.forEach(function(value) {
8390 result[++index] = value;
8396 * Converts `set` to its value-value pairs.
8399 * @param {Object} set The set to convert.
8400 * @returns {Array} Returns the value-value pairs.
8402 function setToPairs(set) {
8404 result = Array(set.size);
8406 set.forEach(function(value) {
8407 result[++index] = [value, value];
8413 * Converts `string` to an array.
8416 * @param {string} string The string to convert.
8417 * @returns {Array} Returns the converted array.
8419 function stringToArray(string) {
8420 return string.match(reComplexSymbol);
8423 /*--------------------------------------------------------------------------*/
8425 /** Used for built-in method references. */
8426 var arrayProto = Array.prototype,
8427 objectProto = Object.prototype;
8429 /** Used to resolve the decompiled source of functions. */
8430 var funcToString = Function.prototype.toString;
8432 /** Used to check objects for own properties. */
8433 var hasOwnProperty = objectProto.hasOwnProperty;
8435 /** Used to infer the `Object` constructor. */
8436 var objectCtorString = funcToString.call(Object);
8439 * Used to resolve the
8440 * [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
8443 var objectToString = objectProto.toString;
8445 /** Used to detect if a method is native. */
8446 var reIsNative = RegExp('^' +
8447 funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
8448 .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
8451 /** Built-in value references. */
8452 var Buffer = moduleExports ? root.Buffer : undefined,
8453 Reflect = root.Reflect,
8454 Symbol = root.Symbol,
8455 Uint8Array = root.Uint8Array,
8456 enumerate = Reflect ? Reflect.enumerate : undefined,
8457 getOwnPropertySymbols = Object.getOwnPropertySymbols,
8458 iteratorSymbol = typeof (iteratorSymbol = Symbol && Symbol.iterator) == 'symbol' ? iteratorSymbol : undefined,
8459 objectCreate = Object.create,
8460 propertyIsEnumerable = objectProto.propertyIsEnumerable,
8461 splice = arrayProto.splice;
8463 /* Built-in method references for those with the same name as other `lodash` methods. */
8464 var nativeCeil = Math.ceil,
8465 nativeGetPrototype = Object.getPrototypeOf,
8466 nativeKeys = Object.keys,
8467 nativeMax = Math.max,
8468 nativeMin = Math.min,
8469 nativeReverse = arrayProto.reverse;
8471 /* Built-in method references that are verified to be native. */
8472 var DataView = getNative(root, 'DataView'),
8473 Map = getNative(root, 'Map'),
8474 Promise = getNative(root, 'Promise'),
8475 Set = getNative(root, 'Set'),
8476 WeakMap = getNative(root, 'WeakMap'),
8477 nativeCreate = getNative(Object, 'create');
8479 /** Used to store function metadata. */
8480 var metaMap = WeakMap && new WeakMap;
8482 /** Detect if properties shadowing those on `Object.prototype` are non-enumerable. */
8483 var nonEnumShadows = !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf');
8485 /** Used to lookup unminified function names. */
8488 /** Used to detect maps, sets, and weakmaps. */
8489 var dataViewCtorString = toSource(DataView),
8490 mapCtorString = toSource(Map),
8491 promiseCtorString = toSource(Promise),
8492 setCtorString = toSource(Set),
8493 weakMapCtorString = toSource(WeakMap);
8495 /** Used to convert symbols to primitives and strings. */
8496 var symbolProto = Symbol ? Symbol.prototype : undefined,
8497 symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
8498 symbolToString = symbolProto ? symbolProto.toString : undefined;
8500 /*------------------------------------------------------------------------*/
8503 * Creates a `lodash` object which wraps `value` to enable implicit method
8504 * chain sequences. Methods that operate on and return arrays, collections,
8505 * and functions can be chained together. Methods that retrieve a single value
8506 * or may return a primitive value will automatically end the chain sequence
8507 * and return the unwrapped value. Otherwise, the value must be unwrapped
8510 * Explicit chain sequences, which must be unwrapped with `_#value`, may be
8511 * enabled using `_.chain`.
8513 * The execution of chained methods is lazy, that is, it's deferred until
8514 * `_#value` is implicitly or explicitly called.
8516 * Lazy evaluation allows several methods to support shortcut fusion.
8517 * Shortcut fusion is an optimization to merge iteratee calls; this avoids
8518 * the creation of intermediate arrays and can greatly reduce the number of
8519 * iteratee executions. Sections of a chain sequence qualify for shortcut
8520 * fusion if the section is applied to an array of at least `200` elements
8521 * and any iteratees accept only one argument. The heuristic for whether a
8522 * section qualifies for shortcut fusion is subject to change.
8524 * Chaining is supported in custom builds as long as the `_#value` method is
8525 * directly or indirectly included in the build.
8527 * In addition to lodash methods, wrappers have `Array` and `String` methods.
8529 * The wrapper `Array` methods are:
8530 * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
8532 * The wrapper `String` methods are:
8533 * `replace` and `split`
8535 * The wrapper methods that support shortcut fusion are:
8536 * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
8537 * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
8538 * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
8540 * The chainable wrapper methods are:
8541 * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
8542 * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
8543 * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
8544 * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
8545 * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
8546 * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
8547 * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
8548 * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
8549 * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
8550 * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
8551 * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
8552 * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
8553 * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
8554 * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
8555 * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
8556 * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
8557 * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
8558 * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
8559 * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
8560 * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
8561 * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
8562 * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
8563 * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
8564 * `zipObject`, `zipObjectDeep`, and `zipWith`
8566 * The wrapper methods that are **not** chainable by default are:
8567 * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
8568 * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `deburr`, `divide`, `each`,
8569 * `eachRight`, `endsWith`, `eq`, `escape`, `escapeRegExp`, `every`, `find`,
8570 * `findIndex`, `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `first`,
8571 * `floor`, `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`,
8572 * `forOwnRight`, `get`, `gt`, `gte`, `has`, `hasIn`, `head`, `identity`,
8573 * `includes`, `indexOf`, `inRange`, `invoke`, `isArguments`, `isArray`,
8574 * `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, `isBoolean`,
8575 * `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, `isEqualWith`,
8576 * `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, `isMap`,
8577 * `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, `isNumber`,
8578 * `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, `isSafeInteger`,
8579 * `isSet`, `isString`, `isUndefined`, `isTypedArray`, `isWeakMap`, `isWeakSet`,
8580 * `join`, `kebabCase`, `last`, `lastIndexOf`, `lowerCase`, `lowerFirst`,
8581 * `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, `min`, `minBy`, `multiply`,
8582 * `noConflict`, `noop`, `now`, `nth`, `pad`, `padEnd`, `padStart`, `parseInt`,
8583 * `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, `round`,
8584 * `runInContext`, `sample`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`,
8585 * `sortedIndexBy`, `sortedLastIndex`, `sortedLastIndexBy`, `startCase`,
8586 * `startsWith`, `subtract`, `sum`, `sumBy`, `template`, `times`, `toFinite`,
8587 * `toInteger`, `toJSON`, `toLength`, `toLower`, `toNumber`, `toSafeInteger`,
8588 * `toString`, `toUpper`, `trim`, `trimEnd`, `trimStart`, `truncate`, `unescape`,
8589 * `uniqueId`, `upperCase`, `upperFirst`, `value`, and `words`
8594 * @param {*} value The value to wrap in a `lodash` instance.
8595 * @returns {Object} Returns the new `lodash` wrapper instance.
8598 * function square(n) {
8602 * var wrapped = _([1, 2, 3]);
8604 * // Returns an unwrapped value.
8605 * wrapped.reduce(_.add);
8608 * // Returns a wrapped value.
8609 * var squares = wrapped.map(square);
8611 * _.isArray(squares);
8614 * _.isArray(squares.value());
8617 function lodash(value) {
8618 if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
8619 if (value instanceof LodashWrapper) {
8622 if (hasOwnProperty.call(value, '__wrapped__')) {
8623 return wrapperClone(value);
8626 return new LodashWrapper(value);
8630 * The function whose prototype chain sequence wrappers inherit from.
8634 function baseLodash() {
8635 // No operation performed.
8639 * The base constructor for creating `lodash` wrapper objects.
8642 * @param {*} value The value to wrap.
8643 * @param {boolean} [chainAll] Enable explicit method chain sequences.
8645 function LodashWrapper(value, chainAll) {
8646 this.__wrapped__ = value;
8647 this.__actions__ = [];
8648 this.__chain__ = !!chainAll;
8650 this.__values__ = undefined;
8653 // Ensure wrappers are instances of `baseLodash`.
8654 lodash.prototype = baseLodash.prototype;
8655 lodash.prototype.constructor = lodash;
8657 LodashWrapper.prototype = baseCreate(baseLodash.prototype);
8658 LodashWrapper.prototype.constructor = LodashWrapper;
8660 /*------------------------------------------------------------------------*/
8663 * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
8667 * @param {*} value The value to wrap.
8669 function LazyWrapper(value) {
8670 this.__wrapped__ = value;
8671 this.__actions__ = [];
8673 this.__filtered__ = false;
8674 this.__iteratees__ = [];
8675 this.__takeCount__ = MAX_ARRAY_LENGTH;
8676 this.__views__ = [];
8680 * Creates a clone of the lazy wrapper object.
8684 * @memberOf LazyWrapper
8685 * @returns {Object} Returns the cloned `LazyWrapper` object.
8687 function lazyClone() {
8688 var result = new LazyWrapper(this.__wrapped__);
8689 result.__actions__ = copyArray(this.__actions__);
8690 result.__dir__ = this.__dir__;
8691 result.__filtered__ = this.__filtered__;
8692 result.__iteratees__ = copyArray(this.__iteratees__);
8693 result.__takeCount__ = this.__takeCount__;
8694 result.__views__ = copyArray(this.__views__);
8699 * Reverses the direction of lazy iteration.
8703 * @memberOf LazyWrapper
8704 * @returns {Object} Returns the new reversed `LazyWrapper` object.
8706 function lazyReverse() {
8707 if (this.__filtered__) {
8708 var result = new LazyWrapper(this);
8709 result.__dir__ = -1;
8710 result.__filtered__ = true;
8712 result = this.clone();
8713 result.__dir__ *= -1;
8719 * Extracts the unwrapped value from its lazy wrapper.
8723 * @memberOf LazyWrapper
8724 * @returns {*} Returns the unwrapped value.
8726 function lazyValue() {
8727 var array = this.__wrapped__.value(),
8729 isArr = isArray(array),
8731 arrLength = isArr ? array.length : 0,
8732 view = getView(0, arrLength, this.__views__),
8735 length = end - start,
8736 index = isRight ? end : (start - 1),
8737 iteratees = this.__iteratees__,
8738 iterLength = iteratees.length,
8740 takeCount = nativeMin(length, this.__takeCount__);
8742 if (!isArr || arrLength < LARGE_ARRAY_SIZE ||
8743 (arrLength == length && takeCount == length)) {
8744 return baseWrapperValue(array, this.__actions__);
8749 while (length-- && resIndex < takeCount) {
8753 value = array[index];
8755 while (++iterIndex < iterLength) {
8756 var data = iteratees[iterIndex],
8757 iteratee = data.iteratee,
8759 computed = iteratee(value);
8761 if (type == LAZY_MAP_FLAG) {
8763 } else if (!computed) {
8764 if (type == LAZY_FILTER_FLAG) {
8771 result[resIndex++] = value;
8776 // Ensure `LazyWrapper` is an instance of `baseLodash`.
8777 LazyWrapper.prototype = baseCreate(baseLodash.prototype);
8778 LazyWrapper.prototype.constructor = LazyWrapper;
8780 /*------------------------------------------------------------------------*/
8783 * Creates a hash object.
8787 * @param {Array} [entries] The key-value pairs to cache.
8789 function Hash(entries) {
8791 length = entries ? entries.length : 0;
8794 while (++index < length) {
8795 var entry = entries[index];
8796 this.set(entry[0], entry[1]);
8801 * Removes all key-value entries from the hash.
8807 function hashClear() {
8808 this.__data__ = nativeCreate ? nativeCreate(null) : {};
8812 * Removes `key` and its value from the hash.
8817 * @param {Object} hash The hash to modify.
8818 * @param {string} key The key of the value to remove.
8819 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
8821 function hashDelete(key) {
8822 return this.has(key) && delete this.__data__[key];
8826 * Gets the hash value for `key`.
8831 * @param {string} key The key of the value to get.
8832 * @returns {*} Returns the entry value.
8834 function hashGet(key) {
8835 var data = this.__data__;
8837 var result = data[key];
8838 return result === HASH_UNDEFINED ? undefined : result;
8840 return hasOwnProperty.call(data, key) ? data[key] : undefined;
8844 * Checks if a hash value for `key` exists.
8849 * @param {string} key The key of the entry to check.
8850 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
8852 function hashHas(key) {
8853 var data = this.__data__;
8854 return nativeCreate ? data[key] !== undefined : hasOwnProperty.call(data, key);
8858 * Sets the hash `key` to `value`.
8863 * @param {string} key The key of the value to set.
8864 * @param {*} value The value to set.
8865 * @returns {Object} Returns the hash instance.
8867 function hashSet(key, value) {
8868 var data = this.__data__;
8869 data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
8873 // Add methods to `Hash`.
8874 Hash.prototype.clear = hashClear;
8875 Hash.prototype['delete'] = hashDelete;
8876 Hash.prototype.get = hashGet;
8877 Hash.prototype.has = hashHas;
8878 Hash.prototype.set = hashSet;
8880 /*------------------------------------------------------------------------*/
8883 * Creates an list cache object.
8887 * @param {Array} [entries] The key-value pairs to cache.
8889 function ListCache(entries) {
8891 length = entries ? entries.length : 0;
8894 while (++index < length) {
8895 var entry = entries[index];
8896 this.set(entry[0], entry[1]);
8901 * Removes all key-value entries from the list cache.
8905 * @memberOf ListCache
8907 function listCacheClear() {
8912 * Removes `key` and its value from the list cache.
8916 * @memberOf ListCache
8917 * @param {string} key The key of the value to remove.
8918 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
8920 function listCacheDelete(key) {
8921 var data = this.__data__,
8922 index = assocIndexOf(data, key);
8927 var lastIndex = data.length - 1;
8928 if (index == lastIndex) {
8931 splice.call(data, index, 1);
8937 * Gets the list cache value for `key`.
8941 * @memberOf ListCache
8942 * @param {string} key The key of the value to get.
8943 * @returns {*} Returns the entry value.
8945 function listCacheGet(key) {
8946 var data = this.__data__,
8947 index = assocIndexOf(data, key);
8949 return index < 0 ? undefined : data[index][1];
8953 * Checks if a list cache value for `key` exists.
8957 * @memberOf ListCache
8958 * @param {string} key The key of the entry to check.
8959 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
8961 function listCacheHas(key) {
8962 return assocIndexOf(this.__data__, key) > -1;
8966 * Sets the list cache `key` to `value`.
8970 * @memberOf ListCache
8971 * @param {string} key The key of the value to set.
8972 * @param {*} value The value to set.
8973 * @returns {Object} Returns the list cache instance.
8975 function listCacheSet(key, value) {
8976 var data = this.__data__,
8977 index = assocIndexOf(data, key);
8980 data.push([key, value]);
8982 data[index][1] = value;
8987 // Add methods to `ListCache`.
8988 ListCache.prototype.clear = listCacheClear;
8989 ListCache.prototype['delete'] = listCacheDelete;
8990 ListCache.prototype.get = listCacheGet;
8991 ListCache.prototype.has = listCacheHas;
8992 ListCache.prototype.set = listCacheSet;
8994 /*------------------------------------------------------------------------*/
8997 * Creates a map cache object to store key-value pairs.
9001 * @param {Array} [entries] The key-value pairs to cache.
9003 function MapCache(entries) {
9005 length = entries ? entries.length : 0;
9008 while (++index < length) {
9009 var entry = entries[index];
9010 this.set(entry[0], entry[1]);
9015 * Removes all key-value entries from the map.
9019 * @memberOf MapCache
9021 function mapCacheClear() {
9024 'map': new (Map || ListCache),
9030 * Removes `key` and its value from the map.
9034 * @memberOf MapCache
9035 * @param {string} key The key of the value to remove.
9036 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
9038 function mapCacheDelete(key) {
9039 return getMapData(this, key)['delete'](key);
9043 * Gets the map value for `key`.
9047 * @memberOf MapCache
9048 * @param {string} key The key of the value to get.
9049 * @returns {*} Returns the entry value.
9051 function mapCacheGet(key) {
9052 return getMapData(this, key).get(key);
9056 * Checks if a map value for `key` exists.
9060 * @memberOf MapCache
9061 * @param {string} key The key of the entry to check.
9062 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
9064 function mapCacheHas(key) {
9065 return getMapData(this, key).has(key);
9069 * Sets the map `key` to `value`.
9073 * @memberOf MapCache
9074 * @param {string} key The key of the value to set.
9075 * @param {*} value The value to set.
9076 * @returns {Object} Returns the map cache instance.
9078 function mapCacheSet(key, value) {
9079 getMapData(this, key).set(key, value);
9083 // Add methods to `MapCache`.
9084 MapCache.prototype.clear = mapCacheClear;
9085 MapCache.prototype['delete'] = mapCacheDelete;
9086 MapCache.prototype.get = mapCacheGet;
9087 MapCache.prototype.has = mapCacheHas;
9088 MapCache.prototype.set = mapCacheSet;
9090 /*------------------------------------------------------------------------*/
9094 * Creates an array cache object to store unique values.
9098 * @param {Array} [values] The values to cache.
9100 function SetCache(values) {
9102 length = values ? values.length : 0;
9104 this.__data__ = new MapCache;
9105 while (++index < length) {
9106 this.add(values[index]);
9111 * Adds `value` to the array cache.
9115 * @memberOf SetCache
9117 * @param {*} value The value to cache.
9118 * @returns {Object} Returns the cache instance.
9120 function setCacheAdd(value) {
9121 this.__data__.set(value, HASH_UNDEFINED);
9126 * Checks if `value` is in the array cache.
9130 * @memberOf SetCache
9131 * @param {*} value The value to search for.
9132 * @returns {number} Returns `true` if `value` is found, else `false`.
9134 function setCacheHas(value) {
9135 return this.__data__.has(value);
9138 // Add methods to `SetCache`.
9139 SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
9140 SetCache.prototype.has = setCacheHas;
9142 /*------------------------------------------------------------------------*/
9145 * Creates a stack cache object to store key-value pairs.
9149 * @param {Array} [entries] The key-value pairs to cache.
9151 function Stack(entries) {
9152 this.__data__ = new ListCache(entries);
9156 * Removes all key-value entries from the stack.
9162 function stackClear() {
9163 this.__data__ = new ListCache;
9167 * Removes `key` and its value from the stack.
9172 * @param {string} key The key of the value to remove.
9173 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
9175 function stackDelete(key) {
9176 return this.__data__['delete'](key);
9180 * Gets the stack value for `key`.
9185 * @param {string} key The key of the value to get.
9186 * @returns {*} Returns the entry value.
9188 function stackGet(key) {
9189 return this.__data__.get(key);
9193 * Checks if a stack value for `key` exists.
9198 * @param {string} key The key of the entry to check.
9199 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
9201 function stackHas(key) {
9202 return this.__data__.has(key);
9206 * Sets the stack `key` to `value`.
9211 * @param {string} key The key of the value to set.
9212 * @param {*} value The value to set.
9213 * @returns {Object} Returns the stack cache instance.
9215 function stackSet(key, value) {
9216 var cache = this.__data__;
9217 if (cache instanceof ListCache && cache.__data__.length == LARGE_ARRAY_SIZE) {
9218 cache = this.__data__ = new MapCache(cache.__data__);
9220 cache.set(key, value);
9224 // Add methods to `Stack`.
9225 Stack.prototype.clear = stackClear;
9226 Stack.prototype['delete'] = stackDelete;
9227 Stack.prototype.get = stackGet;
9228 Stack.prototype.has = stackHas;
9229 Stack.prototype.set = stackSet;
9231 /*------------------------------------------------------------------------*/
9234 * This function is like `assignValue` except that it doesn't assign
9235 * `undefined` values.
9238 * @param {Object} object The object to modify.
9239 * @param {string} key The key of the property to assign.
9240 * @param {*} value The value to assign.
9242 function assignMergeValue(object, key, value) {
9243 if ((value !== undefined && !eq(object[key], value)) ||
9244 (typeof key == 'number' && value === undefined && !(key in object))) {
9245 object[key] = value;
9250 * Assigns `value` to `key` of `object` if the existing value is not equivalent
9251 * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
9252 * for equality comparisons.
9255 * @param {Object} object The object to modify.
9256 * @param {string} key The key of the property to assign.
9257 * @param {*} value The value to assign.
9259 function assignValue(object, key, value) {
9260 var objValue = object[key];
9261 if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
9262 (value === undefined && !(key in object))) {
9263 object[key] = value;
9268 * Gets the index at which the `key` is found in `array` of key-value pairs.
9271 * @param {Array} array The array to search.
9272 * @param {*} key The key to search for.
9273 * @returns {number} Returns the index of the matched value, else `-1`.
9275 function assocIndexOf(array, key) {
9276 var length = array.length;
9278 if (eq(array[length][0], key)) {
9286 * Aggregates elements of `collection` on `accumulator` with keys transformed
9287 * by `iteratee` and values set by `setter`.
9290 * @param {Array|Object} collection The collection to iterate over.
9291 * @param {Function} setter The function to set `accumulator` values.
9292 * @param {Function} iteratee The iteratee to transform keys.
9293 * @param {Object} accumulator The initial aggregated object.
9294 * @returns {Function} Returns `accumulator`.
9296 function baseAggregator(collection, setter, iteratee, accumulator) {
9297 baseEach(collection, function(value, key, collection) {
9298 setter(accumulator, value, iteratee(value), collection);
9304 * The base implementation of `_.assign` without support for multiple sources
9305 * or `customizer` functions.
9308 * @param {Object} object The destination object.
9309 * @param {Object} source The source object.
9310 * @returns {Object} Returns `object`.
9312 function baseAssign(object, source) {
9313 return object && copyObject(source, keys(source), object);
9317 * The base implementation of `_.at` without support for individual paths.
9320 * @param {Object} object The object to iterate over.
9321 * @param {string[]} paths The property paths of elements to pick.
9322 * @returns {Array} Returns the picked elements.
9324 function baseAt(object, paths) {
9326 isNil = object == null,
9327 length = paths.length,
9328 result = Array(length);
9330 while (++index < length) {
9331 result[index] = isNil ? undefined : get(object, paths[index]);
9337 * The base implementation of `_.clone` and `_.cloneDeep` which tracks
9338 * traversed objects.
9341 * @param {*} value The value to clone.
9342 * @param {boolean} [isDeep] Specify a deep clone.
9343 * @param {boolean} [isFull] Specify a clone including symbols.
9344 * @param {Function} [customizer] The function to customize cloning.
9345 * @param {string} [key] The key of `value`.
9346 * @param {Object} [object] The parent object of `value`.
9347 * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
9348 * @returns {*} Returns the cloned value.
9350 function baseClone(value, isDeep, isFull, customizer, key, object, stack) {
9353 result = object ? customizer(value, key, object, stack) : customizer(value);
9355 if (result !== undefined) {
9358 if (!isObject(value)) {
9361 var isArr = isArray(value);
9363 result = initCloneArray(value);
9365 return copyArray(value, result);
9368 var tag = getTag(value),
9369 isFunc = tag == funcTag || tag == genTag;
9371 if (isBuffer(value)) {
9372 return cloneBuffer(value, isDeep);
9374 if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
9375 if (isHostObject(value)) {
9376 return object ? value : {};
9378 result = initCloneObject(isFunc ? {} : value);
9380 return copySymbols(value, baseAssign(result, value));
9383 if (!cloneableTags[tag]) {
9384 return object ? value : {};
9386 result = initCloneByTag(value, tag, baseClone, isDeep);
9389 // Check for circular references and return its corresponding clone.
9390 stack || (stack = new Stack);
9391 var stacked = stack.get(value);
9395 stack.set(value, result);
9398 var props = isFull ? getAllKeys(value) : keys(value);
9400 // Recursively populate clone (susceptible to call stack limits).
9401 arrayEach(props || value, function(subValue, key) {
9404 subValue = value[key];
9406 assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack));
9412 * The base implementation of `_.create` without support for assigning
9413 * properties to the created object.
9416 * @param {Object} prototype The object to inherit from.
9417 * @returns {Object} Returns the new object.
9419 function baseCreate(proto) {
9420 return isObject(proto) ? objectCreate(proto) : {};
9424 * The base implementation of methods like `_.difference` without support
9425 * for excluding multiple arrays or iteratee shorthands.
9428 * @param {Array} array The array to inspect.
9429 * @param {Array} values The values to exclude.
9430 * @param {Function} [iteratee] The iteratee invoked per element.
9431 * @param {Function} [comparator] The comparator invoked per element.
9432 * @returns {Array} Returns the new array of filtered values.
9434 function baseDifference(array, values, iteratee, comparator) {
9436 includes = arrayIncludes,
9438 length = array.length,
9440 valuesLength = values.length;
9446 values = arrayMap(values, baseUnary(iteratee));
9449 includes = arrayIncludesWith;
9452 else if (values.length >= LARGE_ARRAY_SIZE) {
9453 includes = cacheHas;
9455 values = new SetCache(values);
9458 while (++index < length) {
9459 var value = array[index],
9460 computed = iteratee ? iteratee(value) : value;
9462 value = (comparator || value !== 0) ? value : 0;
9463 if (isCommon && computed === computed) {
9464 var valuesIndex = valuesLength;
9465 while (valuesIndex--) {
9466 if (values[valuesIndex] === computed) {
9472 else if (!includes(values, computed, comparator)) {
9480 * The base implementation of `_.forEach` without support for iteratee shorthands.
9483 * @param {Array|Object} collection The collection to iterate over.
9484 * @param {Function} iteratee The function invoked per iteration.
9485 * @returns {Array|Object} Returns `collection`.
9487 var baseEach = createBaseEach(baseForOwn);
9490 * The base implementation of `_.every` without support for iteratee shorthands.
9493 * @param {Array|Object} collection The collection to iterate over.
9494 * @param {Function} predicate The function invoked per iteration.
9495 * @returns {boolean} Returns `true` if all elements pass the predicate check,
9498 function baseEvery(collection, predicate) {
9500 baseEach(collection, function(value, index, collection) {
9501 result = !!predicate(value, index, collection);
9508 * The base implementation of `_.filter` without support for iteratee shorthands.
9511 * @param {Array|Object} collection The collection to iterate over.
9512 * @param {Function} predicate The function invoked per iteration.
9513 * @returns {Array} Returns the new filtered array.
9515 function baseFilter(collection, predicate) {
9517 baseEach(collection, function(value, index, collection) {
9518 if (predicate(value, index, collection)) {
9526 * The base implementation of `_.flatten` with support for restricting flattening.
9529 * @param {Array} array The array to flatten.
9530 * @param {number} depth The maximum recursion depth.
9531 * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
9532 * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
9533 * @param {Array} [result=[]] The initial result value.
9534 * @returns {Array} Returns the new flattened array.
9536 function baseFlatten(array, depth, predicate, isStrict, result) {
9538 length = array.length;
9540 predicate || (predicate = isFlattenable);
9541 result || (result = []);
9543 while (++index < length) {
9544 var value = array[index];
9545 if (depth > 0 && predicate(value)) {
9547 // Recursively flatten arrays (susceptible to call stack limits).
9548 baseFlatten(value, depth - 1, predicate, isStrict, result);
9550 arrayPush(result, value);
9552 } else if (!isStrict) {
9553 result[result.length] = value;
9560 * The base implementation of `baseForOwn` which iterates over `object`
9561 * properties returned by `keysFunc` and invokes `iteratee` for each property.
9562 * Iteratee functions may exit iteration early by explicitly returning `false`.
9565 * @param {Object} object The object to iterate over.
9566 * @param {Function} iteratee The function invoked per iteration.
9567 * @param {Function} keysFunc The function to get the keys of `object`.
9568 * @returns {Object} Returns `object`.
9570 var baseFor = createBaseFor();
9573 * The base implementation of `_.forOwn` without support for iteratee shorthands.
9576 * @param {Object} object The object to iterate over.
9577 * @param {Function} iteratee The function invoked per iteration.
9578 * @returns {Object} Returns `object`.
9580 function baseForOwn(object, iteratee) {
9581 return object && baseFor(object, iteratee, keys);
9585 * The base implementation of `_.functions` which creates an array of
9586 * `object` function property names filtered from `props`.
9589 * @param {Object} object The object to inspect.
9590 * @param {Array} props The property names to filter.
9591 * @returns {Array} Returns the function names.
9593 function baseFunctions(object, props) {
9594 return arrayFilter(props, function(key) {
9595 return isFunction(object[key]);
9600 * The base implementation of `_.get` without support for default values.
9603 * @param {Object} object The object to query.
9604 * @param {Array|string} path The path of the property to get.
9605 * @returns {*} Returns the resolved value.
9607 function baseGet(object, path) {
9608 path = isKey(path, object) ? [path] : castPath(path);
9611 length = path.length;
9613 while (object != null && index < length) {
9614 object = object[toKey(path[index++])];
9616 return (index && index == length) ? object : undefined;
9620 * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
9621 * `keysFunc` and `symbolsFunc` to get the enumerable property names and
9622 * symbols of `object`.
9625 * @param {Object} object The object to query.
9626 * @param {Function} keysFunc The function to get the keys of `object`.
9627 * @param {Function} symbolsFunc The function to get the symbols of `object`.
9628 * @returns {Array} Returns the array of property names and symbols.
9630 function baseGetAllKeys(object, keysFunc, symbolsFunc) {
9631 var result = keysFunc(object);
9632 return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
9636 * The base implementation of `_.has` without support for deep paths.
9639 * @param {Object} object The object to query.
9640 * @param {Array|string} key The key to check.
9641 * @returns {boolean} Returns `true` if `key` exists, else `false`.
9643 function baseHas(object, key) {
9644 // Avoid a bug in IE 10-11 where objects with a [[Prototype]] of `null`,
9645 // that are composed entirely of index properties, return `false` for
9646 // `hasOwnProperty` checks of them.
9647 return hasOwnProperty.call(object, key) ||
9648 (typeof object == 'object' && key in object && getPrototype(object) === null);
9652 * The base implementation of `_.hasIn` without support for deep paths.
9655 * @param {Object} object The object to query.
9656 * @param {Array|string} key The key to check.
9657 * @returns {boolean} Returns `true` if `key` exists, else `false`.
9659 function baseHasIn(object, key) {
9660 return key in Object(object);
9664 * The base implementation of methods like `_.intersection`, without support
9665 * for iteratee shorthands, that accepts an array of arrays to inspect.
9668 * @param {Array} arrays The arrays to inspect.
9669 * @param {Function} [iteratee] The iteratee invoked per element.
9670 * @param {Function} [comparator] The comparator invoked per element.
9671 * @returns {Array} Returns the new array of shared values.
9673 function baseIntersection(arrays, iteratee, comparator) {
9674 var includes = comparator ? arrayIncludesWith : arrayIncludes,
9675 length = arrays[0].length,
9676 othLength = arrays.length,
9677 othIndex = othLength,
9678 caches = Array(othLength),
9679 maxLength = Infinity,
9682 while (othIndex--) {
9683 var array = arrays[othIndex];
9684 if (othIndex && iteratee) {
9685 array = arrayMap(array, baseUnary(iteratee));
9687 maxLength = nativeMin(array.length, maxLength);
9688 caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
9689 ? new SetCache(othIndex && array)
9698 while (++index < length && result.length < maxLength) {
9699 var value = array[index],
9700 computed = iteratee ? iteratee(value) : value;
9702 value = (comparator || value !== 0) ? value : 0;
9704 ? cacheHas(seen, computed)
9705 : includes(result, computed, comparator)
9707 othIndex = othLength;
9708 while (--othIndex) {
9709 var cache = caches[othIndex];
9711 ? cacheHas(cache, computed)
9712 : includes(arrays[othIndex], computed, comparator))
9718 seen.push(computed);
9727 * The base implementation of `_.invoke` without support for individual
9731 * @param {Object} object The object to query.
9732 * @param {Array|string} path The path of the method to invoke.
9733 * @param {Array} args The arguments to invoke the method with.
9734 * @returns {*} Returns the result of the invoked method.
9736 function baseInvoke(object, path, args) {
9737 if (!isKey(path, object)) {
9738 path = castPath(path);
9739 object = parent(object, path);
9742 var func = object == null ? object : object[toKey(path)];
9743 return func == null ? undefined : apply(func, object, args);
9747 * The base implementation of `_.isEqual` which supports partial comparisons
9748 * and tracks traversed objects.
9751 * @param {*} value The value to compare.
9752 * @param {*} other The other value to compare.
9753 * @param {Function} [customizer] The function to customize comparisons.
9754 * @param {boolean} [bitmask] The bitmask of comparison flags.
9755 * The bitmask may be composed of the following flags:
9756 * 1 - Unordered comparison
9757 * 2 - Partial comparison
9758 * @param {Object} [stack] Tracks traversed `value` and `other` objects.
9759 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
9761 function baseIsEqual(value, other, customizer, bitmask, stack) {
9762 if (value === other) {
9765 if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
9766 return value !== value && other !== other;
9768 return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack);
9772 * A specialized version of `baseIsEqual` for arrays and objects which performs
9773 * deep comparisons and tracks traversed objects enabling objects with circular
9774 * references to be compared.
9777 * @param {Object} object The object to compare.
9778 * @param {Object} other The other object to compare.
9779 * @param {Function} equalFunc The function to determine equivalents of values.
9780 * @param {Function} [customizer] The function to customize comparisons.
9781 * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual`
9783 * @param {Object} [stack] Tracks traversed `object` and `other` objects.
9784 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
9786 function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) {
9787 var objIsArr = isArray(object),
9788 othIsArr = isArray(other),
9793 objTag = getTag(object);
9794 objTag = objTag == argsTag ? objectTag : objTag;
9797 othTag = getTag(other);
9798 othTag = othTag == argsTag ? objectTag : othTag;
9800 var objIsObj = objTag == objectTag && !isHostObject(object),
9801 othIsObj = othTag == objectTag && !isHostObject(other),
9802 isSameTag = objTag == othTag;
9804 if (isSameTag && !objIsObj) {
9805 stack || (stack = new Stack);
9806 return (objIsArr || isTypedArray(object))
9807 ? equalArrays(object, other, equalFunc, customizer, bitmask, stack)
9808 : equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack);
9810 if (!(bitmask & PARTIAL_COMPARE_FLAG)) {
9811 var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
9812 othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
9814 if (objIsWrapped || othIsWrapped) {
9815 var objUnwrapped = objIsWrapped ? object.value() : object,
9816 othUnwrapped = othIsWrapped ? other.value() : other;
9818 stack || (stack = new Stack);
9819 return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack);
9825 stack || (stack = new Stack);
9826 return equalObjects(object, other, equalFunc, customizer, bitmask, stack);
9830 * The base implementation of `_.isMatch` without support for iteratee shorthands.
9833 * @param {Object} object The object to inspect.
9834 * @param {Object} source The object of property values to match.
9835 * @param {Array} matchData The property names, values, and compare flags to match.
9836 * @param {Function} [customizer] The function to customize comparisons.
9837 * @returns {boolean} Returns `true` if `object` is a match, else `false`.
9839 function baseIsMatch(object, source, matchData, customizer) {
9840 var index = matchData.length,
9842 noCustomizer = !customizer;
9844 if (object == null) {
9847 object = Object(object);
9849 var data = matchData[index];
9850 if ((noCustomizer && data[2])
9851 ? data[1] !== object[data[0]]
9852 : !(data[0] in object)
9857 while (++index < length) {
9858 data = matchData[index];
9860 objValue = object[key],
9863 if (noCustomizer && data[2]) {
9864 if (objValue === undefined && !(key in object)) {
9868 var stack = new Stack;
9870 var result = customizer(objValue, srcValue, key, object, source, stack);
9872 if (!(result === undefined
9873 ? baseIsEqual(srcValue, objValue, customizer, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG, stack)
9884 * The base implementation of `_.iteratee`.
9887 * @param {*} [value=_.identity] The value to convert to an iteratee.
9888 * @returns {Function} Returns the iteratee.
9890 function baseIteratee(value) {
9891 // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
9892 // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
9893 if (typeof value == 'function') {
9896 if (value == null) {
9899 if (typeof value == 'object') {
9900 return isArray(value)
9901 ? baseMatchesProperty(value[0], value[1])
9902 : baseMatches(value);
9904 return property(value);
9908 * The base implementation of `_.keys` which doesn't skip the constructor
9909 * property of prototypes or treat sparse arrays as dense.
9912 * @param {Object} object The object to query.
9913 * @returns {Array} Returns the array of property names.
9915 function baseKeys(object) {
9916 return nativeKeys(Object(object));
9920 * The base implementation of `_.keysIn` which doesn't skip the constructor
9921 * property of prototypes or treat sparse arrays as dense.
9924 * @param {Object} object The object to query.
9925 * @returns {Array} Returns the array of property names.
9927 function baseKeysIn(object) {
9928 object = object == null ? object : Object(object);
9931 for (var key in object) {
9937 // Fallback for IE < 9 with es6-shim.
9938 if (enumerate && !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf')) {
9939 baseKeysIn = function(object) {
9940 return iteratorToArray(enumerate(object));
9945 * The base implementation of `_.map` without support for iteratee shorthands.
9948 * @param {Array|Object} collection The collection to iterate over.
9949 * @param {Function} iteratee The function invoked per iteration.
9950 * @returns {Array} Returns the new mapped array.
9952 function baseMap(collection, iteratee) {
9954 result = isArrayLike(collection) ? Array(collection.length) : [];
9956 baseEach(collection, function(value, key, collection) {
9957 result[++index] = iteratee(value, key, collection);
9963 * The base implementation of `_.matches` which doesn't clone `source`.
9966 * @param {Object} source The object of property values to match.
9967 * @returns {Function} Returns the new spec function.
9969 function baseMatches(source) {
9970 var matchData = getMatchData(source);
9971 if (matchData.length == 1 && matchData[0][2]) {
9972 return matchesStrictComparable(matchData[0][0], matchData[0][1]);
9974 return function(object) {
9975 return object === source || baseIsMatch(object, source, matchData);
9980 * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
9983 * @param {string} path The path of the property to get.
9984 * @param {*} srcValue The value to match.
9985 * @returns {Function} Returns the new spec function.
9987 function baseMatchesProperty(path, srcValue) {
9988 if (isKey(path) && isStrictComparable(srcValue)) {
9989 return matchesStrictComparable(toKey(path), srcValue);
9991 return function(object) {
9992 var objValue = get(object, path);
9993 return (objValue === undefined && objValue === srcValue)
9994 ? hasIn(object, path)
9995 : baseIsEqual(srcValue, objValue, undefined, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG);
10000 * The base implementation of `_.merge` without support for multiple sources.
10003 * @param {Object} object The destination object.
10004 * @param {Object} source The source object.
10005 * @param {number} srcIndex The index of `source`.
10006 * @param {Function} [customizer] The function to customize merged values.
10007 * @param {Object} [stack] Tracks traversed source values and their merged
10010 function baseMerge(object, source, srcIndex, customizer, stack) {
10011 if (object === source) {
10014 if (!(isArray(source) || isTypedArray(source))) {
10015 var props = keysIn(source);
10017 arrayEach(props || source, function(srcValue, key) {
10020 srcValue = source[key];
10022 if (isObject(srcValue)) {
10023 stack || (stack = new Stack);
10024 baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
10027 var newValue = customizer
10028 ? customizer(object[key], srcValue, (key + ''), object, source, stack)
10031 if (newValue === undefined) {
10032 newValue = srcValue;
10034 assignMergeValue(object, key, newValue);
10040 * A specialized version of `baseMerge` for arrays and objects which performs
10041 * deep merges and tracks traversed objects enabling objects with circular
10042 * references to be merged.
10045 * @param {Object} object The destination object.
10046 * @param {Object} source The source object.
10047 * @param {string} key The key of the value to merge.
10048 * @param {number} srcIndex The index of `source`.
10049 * @param {Function} mergeFunc The function to merge values.
10050 * @param {Function} [customizer] The function to customize assigned values.
10051 * @param {Object} [stack] Tracks traversed source values and their merged
10054 function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
10055 var objValue = object[key],
10056 srcValue = source[key],
10057 stacked = stack.get(srcValue);
10060 assignMergeValue(object, key, stacked);
10063 var newValue = customizer
10064 ? customizer(objValue, srcValue, (key + ''), object, source, stack)
10067 var isCommon = newValue === undefined;
10070 newValue = srcValue;
10071 if (isArray(srcValue) || isTypedArray(srcValue)) {
10072 if (isArray(objValue)) {
10073 newValue = objValue;
10075 else if (isArrayLikeObject(objValue)) {
10076 newValue = copyArray(objValue);
10080 newValue = baseClone(srcValue, true);
10083 else if (isPlainObject(srcValue) || isArguments(srcValue)) {
10084 if (isArguments(objValue)) {
10085 newValue = toPlainObject(objValue);
10087 else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
10089 newValue = baseClone(srcValue, true);
10092 newValue = objValue;
10099 stack.set(srcValue, newValue);
10102 // Recursively merge objects and arrays (susceptible to call stack limits).
10103 mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
10105 stack['delete'](srcValue);
10106 assignMergeValue(object, key, newValue);
10110 * The base implementation of `_.pick` without support for individual
10111 * property identifiers.
10114 * @param {Object} object The source object.
10115 * @param {string[]} props The property identifiers to pick.
10116 * @returns {Object} Returns the new object.
10118 function basePick(object, props) {
10119 object = Object(object);
10120 return arrayReduce(props, function(result, key) {
10121 if (key in object) {
10122 result[key] = object[key];
10129 * The base implementation of `_.property` without support for deep paths.
10132 * @param {string} key The key of the property to get.
10133 * @returns {Function} Returns the new accessor function.
10135 function baseProperty(key) {
10136 return function(object) {
10137 return object == null ? undefined : object[key];
10142 * A specialized version of `baseProperty` which supports deep paths.
10145 * @param {Array|string} path The path of the property to get.
10146 * @returns {Function} Returns the new accessor function.
10148 function basePropertyDeep(path) {
10149 return function(object) {
10150 return baseGet(object, path);
10155 * The base implementation of `setData` without support for hot loop detection.
10158 * @param {Function} func The function to associate metadata with.
10159 * @param {*} data The metadata.
10160 * @returns {Function} Returns `func`.
10162 var baseSetData = !metaMap ? identity : function(func, data) {
10163 metaMap.set(func, data);
10168 * The base implementation of `_.slice` without an iteratee call guard.
10171 * @param {Array} array The array to slice.
10172 * @param {number} [start=0] The start position.
10173 * @param {number} [end=array.length] The end position.
10174 * @returns {Array} Returns the slice of `array`.
10176 function baseSlice(array, start, end) {
10178 length = array.length;
10181 start = -start > length ? 0 : (length + start);
10183 end = end > length ? length : end;
10187 length = start > end ? 0 : ((end - start) >>> 0);
10190 var result = Array(length);
10191 while (++index < length) {
10192 result[index] = array[index + start];
10198 * The base implementation of `_.some` without support for iteratee shorthands.
10201 * @param {Array|Object} collection The collection to iterate over.
10202 * @param {Function} predicate The function invoked per iteration.
10203 * @returns {boolean} Returns `true` if any element passes the predicate check,
10206 function baseSome(collection, predicate) {
10209 baseEach(collection, function(value, index, collection) {
10210 result = predicate(value, index, collection);
10217 * The base implementation of `_.toString` which doesn't convert nullish
10218 * values to empty strings.
10221 * @param {*} value The value to process.
10222 * @returns {string} Returns the string.
10224 function baseToString(value) {
10225 // Exit early for strings to avoid a performance hit in some environments.
10226 if (typeof value == 'string') {
10229 if (isSymbol(value)) {
10230 return symbolToString ? symbolToString.call(value) : '';
10232 var result = (value + '');
10233 return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
10237 * The base implementation of `_.uniqBy` without support for iteratee shorthands.
10240 * @param {Array} array The array to inspect.
10241 * @param {Function} [iteratee] The iteratee invoked per element.
10242 * @param {Function} [comparator] The comparator invoked per element.
10243 * @returns {Array} Returns the new duplicate free array.
10245 function baseUniq(array, iteratee, comparator) {
10247 includes = arrayIncludes,
10248 length = array.length,
10255 includes = arrayIncludesWith;
10257 else if (length >= LARGE_ARRAY_SIZE) {
10258 var set = iteratee ? null : createSet(array);
10260 return setToArray(set);
10263 includes = cacheHas;
10264 seen = new SetCache;
10267 seen = iteratee ? [] : result;
10270 while (++index < length) {
10271 var value = array[index],
10272 computed = iteratee ? iteratee(value) : value;
10274 value = (comparator || value !== 0) ? value : 0;
10275 if (isCommon && computed === computed) {
10276 var seenIndex = seen.length;
10277 while (seenIndex--) {
10278 if (seen[seenIndex] === computed) {
10283 seen.push(computed);
10285 result.push(value);
10287 else if (!includes(seen, computed, comparator)) {
10288 if (seen !== result) {
10289 seen.push(computed);
10291 result.push(value);
10298 * The base implementation of `wrapperValue` which returns the result of
10299 * performing a sequence of actions on the unwrapped `value`, where each
10300 * successive action is supplied the return value of the previous.
10303 * @param {*} value The unwrapped value.
10304 * @param {Array} actions Actions to perform to resolve the unwrapped value.
10305 * @returns {*} Returns the resolved value.
10307 function baseWrapperValue(value, actions) {
10308 var result = value;
10309 if (result instanceof LazyWrapper) {
10310 result = result.value();
10312 return arrayReduce(actions, function(result, action) {
10313 return action.func.apply(action.thisArg, arrayPush([result], action.args));
10318 * Casts `value` to an empty array if it's not an array like object.
10321 * @param {*} value The value to inspect.
10322 * @returns {Array|Object} Returns the cast array-like object.
10324 function castArrayLikeObject(value) {
10325 return isArrayLikeObject(value) ? value : [];
10329 * Casts `value` to a path array if it's not one.
10332 * @param {*} value The value to inspect.
10333 * @returns {Array} Returns the cast property path array.
10335 function castPath(value) {
10336 return isArray(value) ? value : stringToPath(value);
10340 * Creates a clone of `buffer`.
10343 * @param {Buffer} buffer The buffer to clone.
10344 * @param {boolean} [isDeep] Specify a deep clone.
10345 * @returns {Buffer} Returns the cloned buffer.
10347 function cloneBuffer(buffer, isDeep) {
10349 return buffer.slice();
10351 var result = new buffer.constructor(buffer.length);
10352 buffer.copy(result);
10357 * Creates a clone of `arrayBuffer`.
10360 * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
10361 * @returns {ArrayBuffer} Returns the cloned array buffer.
10363 function cloneArrayBuffer(arrayBuffer) {
10364 var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
10365 new Uint8Array(result).set(new Uint8Array(arrayBuffer));
10370 * Creates a clone of `dataView`.
10373 * @param {Object} dataView The data view to clone.
10374 * @param {boolean} [isDeep] Specify a deep clone.
10375 * @returns {Object} Returns the cloned data view.
10377 function cloneDataView(dataView, isDeep) {
10378 var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
10379 return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
10383 * Creates a clone of `map`.
10386 * @param {Object} map The map to clone.
10387 * @param {Function} cloneFunc The function to clone values.
10388 * @param {boolean} [isDeep] Specify a deep clone.
10389 * @returns {Object} Returns the cloned map.
10391 function cloneMap(map, isDeep, cloneFunc) {
10392 var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map);
10393 return arrayReduce(array, addMapEntry, new map.constructor);
10397 * Creates a clone of `regexp`.
10400 * @param {Object} regexp The regexp to clone.
10401 * @returns {Object} Returns the cloned regexp.
10403 function cloneRegExp(regexp) {
10404 var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
10405 result.lastIndex = regexp.lastIndex;
10410 * Creates a clone of `set`.
10413 * @param {Object} set The set to clone.
10414 * @param {Function} cloneFunc The function to clone values.
10415 * @param {boolean} [isDeep] Specify a deep clone.
10416 * @returns {Object} Returns the cloned set.
10418 function cloneSet(set, isDeep, cloneFunc) {
10419 var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set);
10420 return arrayReduce(array, addSetEntry, new set.constructor);
10424 * Creates a clone of the `symbol` object.
10427 * @param {Object} symbol The symbol object to clone.
10428 * @returns {Object} Returns the cloned symbol object.
10430 function cloneSymbol(symbol) {
10431 return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
10435 * Creates a clone of `typedArray`.
10438 * @param {Object} typedArray The typed array to clone.
10439 * @param {boolean} [isDeep] Specify a deep clone.
10440 * @returns {Object} Returns the cloned typed array.
10442 function cloneTypedArray(typedArray, isDeep) {
10443 var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
10444 return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
10448 * Creates an array that is the composition of partially applied arguments,
10449 * placeholders, and provided arguments into a single array of arguments.
10452 * @param {Array} args The provided arguments.
10453 * @param {Array} partials The arguments to prepend to those provided.
10454 * @param {Array} holders The `partials` placeholder indexes.
10455 * @params {boolean} [isCurried] Specify composing for a curried function.
10456 * @returns {Array} Returns the new array of composed arguments.
10458 function composeArgs(args, partials, holders, isCurried) {
10459 var argsIndex = -1,
10460 argsLength = args.length,
10461 holdersLength = holders.length,
10463 leftLength = partials.length,
10464 rangeLength = nativeMax(argsLength - holdersLength, 0),
10465 result = Array(leftLength + rangeLength),
10466 isUncurried = !isCurried;
10468 while (++leftIndex < leftLength) {
10469 result[leftIndex] = partials[leftIndex];
10471 while (++argsIndex < holdersLength) {
10472 if (isUncurried || argsIndex < argsLength) {
10473 result[holders[argsIndex]] = args[argsIndex];
10476 while (rangeLength--) {
10477 result[leftIndex++] = args[argsIndex++];
10483 * This function is like `composeArgs` except that the arguments composition
10484 * is tailored for `_.partialRight`.
10487 * @param {Array} args The provided arguments.
10488 * @param {Array} partials The arguments to append to those provided.
10489 * @param {Array} holders The `partials` placeholder indexes.
10490 * @params {boolean} [isCurried] Specify composing for a curried function.
10491 * @returns {Array} Returns the new array of composed arguments.
10493 function composeArgsRight(args, partials, holders, isCurried) {
10494 var argsIndex = -1,
10495 argsLength = args.length,
10497 holdersLength = holders.length,
10499 rightLength = partials.length,
10500 rangeLength = nativeMax(argsLength - holdersLength, 0),
10501 result = Array(rangeLength + rightLength),
10502 isUncurried = !isCurried;
10504 while (++argsIndex < rangeLength) {
10505 result[argsIndex] = args[argsIndex];
10507 var offset = argsIndex;
10508 while (++rightIndex < rightLength) {
10509 result[offset + rightIndex] = partials[rightIndex];
10511 while (++holdersIndex < holdersLength) {
10512 if (isUncurried || argsIndex < argsLength) {
10513 result[offset + holders[holdersIndex]] = args[argsIndex++];
10520 * Copies the values of `source` to `array`.
10523 * @param {Array} source The array to copy values from.
10524 * @param {Array} [array=[]] The array to copy values to.
10525 * @returns {Array} Returns `array`.
10527 function copyArray(source, array) {
10529 length = source.length;
10531 array || (array = Array(length));
10532 while (++index < length) {
10533 array[index] = source[index];
10539 * Copies properties of `source` to `object`.
10542 * @param {Object} source The object to copy properties from.
10543 * @param {Array} props The property identifiers to copy.
10544 * @param {Object} [object={}] The object to copy properties to.
10545 * @param {Function} [customizer] The function to customize copied values.
10546 * @returns {Object} Returns `object`.
10548 function copyObject(source, props, object, customizer) {
10549 object || (object = {});
10552 length = props.length;
10554 while (++index < length) {
10555 var key = props[index];
10557 var newValue = customizer
10558 ? customizer(object[key], source[key], key, object, source)
10561 assignValue(object, key, newValue);
10567 * Copies own symbol properties of `source` to `object`.
10570 * @param {Object} source The object to copy symbols from.
10571 * @param {Object} [object={}] The object to copy symbols to.
10572 * @returns {Object} Returns `object`.
10574 function copySymbols(source, object) {
10575 return copyObject(source, getSymbols(source), object);
10579 * Creates a function like `_.groupBy`.
10582 * @param {Function} setter The function to set accumulator values.
10583 * @param {Function} [initializer] The accumulator object initializer.
10584 * @returns {Function} Returns the new aggregator function.
10586 function createAggregator(setter, initializer) {
10587 return function(collection, iteratee) {
10588 var func = isArray(collection) ? arrayAggregator : baseAggregator,
10589 accumulator = initializer ? initializer() : {};
10591 return func(collection, setter, getIteratee(iteratee), accumulator);
10596 * Creates a function like `_.assign`.
10599 * @param {Function} assigner The function to assign values.
10600 * @returns {Function} Returns the new assigner function.
10602 function createAssigner(assigner) {
10603 return rest(function(object, sources) {
10605 length = sources.length,
10606 customizer = length > 1 ? sources[length - 1] : undefined,
10607 guard = length > 2 ? sources[2] : undefined;
10609 customizer = (assigner.length > 3 && typeof customizer == 'function')
10610 ? (length--, customizer)
10613 if (guard && isIterateeCall(sources[0], sources[1], guard)) {
10614 customizer = length < 3 ? undefined : customizer;
10617 object = Object(object);
10618 while (++index < length) {
10619 var source = sources[index];
10621 assigner(object, source, index, customizer);
10629 * Creates a `baseEach` or `baseEachRight` function.
10632 * @param {Function} eachFunc The function to iterate over a collection.
10633 * @param {boolean} [fromRight] Specify iterating from right to left.
10634 * @returns {Function} Returns the new base function.
10636 function createBaseEach(eachFunc, fromRight) {
10637 return function(collection, iteratee) {
10638 if (collection == null) {
10641 if (!isArrayLike(collection)) {
10642 return eachFunc(collection, iteratee);
10644 var length = collection.length,
10645 index = fromRight ? length : -1,
10646 iterable = Object(collection);
10648 while ((fromRight ? index-- : ++index < length)) {
10649 if (iteratee(iterable[index], index, iterable) === false) {
10658 * Creates a base function for methods like `_.forIn` and `_.forOwn`.
10661 * @param {boolean} [fromRight] Specify iterating from right to left.
10662 * @returns {Function} Returns the new base function.
10664 function createBaseFor(fromRight) {
10665 return function(object, iteratee, keysFunc) {
10667 iterable = Object(object),
10668 props = keysFunc(object),
10669 length = props.length;
10672 var key = props[fromRight ? length : ++index];
10673 if (iteratee(iterable[key], key, iterable) === false) {
10682 * Creates a function that wraps `func` to invoke it with the optional `this`
10683 * binding of `thisArg`.
10686 * @param {Function} func The function to wrap.
10687 * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
10688 * for more details.
10689 * @param {*} [thisArg] The `this` binding of `func`.
10690 * @returns {Function} Returns the new wrapped function.
10692 function createBaseWrapper(func, bitmask, thisArg) {
10693 var isBind = bitmask & BIND_FLAG,
10694 Ctor = createCtorWrapper(func);
10696 function wrapper() {
10697 var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
10698 return fn.apply(isBind ? thisArg : this, arguments);
10704 * Creates a function that produces an instance of `Ctor` regardless of
10705 * whether it was invoked as part of a `new` expression or by `call` or `apply`.
10708 * @param {Function} Ctor The constructor to wrap.
10709 * @returns {Function} Returns the new wrapped function.
10711 function createCtorWrapper(Ctor) {
10712 return function() {
10713 // Use a `switch` statement to work with class constructors. See
10714 // http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
10715 // for more details.
10716 var args = arguments;
10717 switch (args.length) {
10718 case 0: return new Ctor;
10719 case 1: return new Ctor(args[0]);
10720 case 2: return new Ctor(args[0], args[1]);
10721 case 3: return new Ctor(args[0], args[1], args[2]);
10722 case 4: return new Ctor(args[0], args[1], args[2], args[3]);
10723 case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
10724 case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
10725 case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
10727 var thisBinding = baseCreate(Ctor.prototype),
10728 result = Ctor.apply(thisBinding, args);
10730 // Mimic the constructor's `return` behavior.
10731 // See https://es5.github.io/#x13.2.2 for more details.
10732 return isObject(result) ? result : thisBinding;
10737 * Creates a function that wraps `func` to enable currying.
10740 * @param {Function} func The function to wrap.
10741 * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
10742 * for more details.
10743 * @param {number} arity The arity of `func`.
10744 * @returns {Function} Returns the new wrapped function.
10746 function createCurryWrapper(func, bitmask, arity) {
10747 var Ctor = createCtorWrapper(func);
10749 function wrapper() {
10750 var length = arguments.length,
10751 args = Array(length),
10753 placeholder = getHolder(wrapper);
10756 args[index] = arguments[index];
10758 var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
10760 : replaceHolders(args, placeholder);
10762 length -= holders.length;
10763 if (length < arity) {
10764 return createRecurryWrapper(
10765 func, bitmask, createHybridWrapper, wrapper.placeholder, undefined,
10766 args, holders, undefined, undefined, arity - length);
10768 var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
10769 return apply(fn, this, args);
10775 * Creates a function that wraps `func` to invoke it with optional `this`
10776 * binding of `thisArg`, partial application, and currying.
10779 * @param {Function|string} func The function or method name to wrap.
10780 * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
10781 * for more details.
10782 * @param {*} [thisArg] The `this` binding of `func`.
10783 * @param {Array} [partials] The arguments to prepend to those provided to
10784 * the new function.
10785 * @param {Array} [holders] The `partials` placeholder indexes.
10786 * @param {Array} [partialsRight] The arguments to append to those provided
10787 * to the new function.
10788 * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
10789 * @param {Array} [argPos] The argument positions of the new function.
10790 * @param {number} [ary] The arity cap of `func`.
10791 * @param {number} [arity] The arity of `func`.
10792 * @returns {Function} Returns the new wrapped function.
10794 function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
10795 var isAry = bitmask & ARY_FLAG,
10796 isBind = bitmask & BIND_FLAG,
10797 isBindKey = bitmask & BIND_KEY_FLAG,
10798 isCurried = bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG),
10799 isFlip = bitmask & FLIP_FLAG,
10800 Ctor = isBindKey ? undefined : createCtorWrapper(func);
10802 function wrapper() {
10803 var length = arguments.length,
10804 args = Array(length),
10808 args[index] = arguments[index];
10811 var placeholder = getHolder(wrapper),
10812 holdersCount = countHolders(args, placeholder);
10815 args = composeArgs(args, partials, holders, isCurried);
10817 if (partialsRight) {
10818 args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
10820 length -= holdersCount;
10821 if (isCurried && length < arity) {
10822 var newHolders = replaceHolders(args, placeholder);
10823 return createRecurryWrapper(
10824 func, bitmask, createHybridWrapper, wrapper.placeholder, thisArg,
10825 args, newHolders, argPos, ary, arity - length
10828 var thisBinding = isBind ? thisArg : this,
10829 fn = isBindKey ? thisBinding[func] : func;
10831 length = args.length;
10833 args = reorder(args, argPos);
10834 } else if (isFlip && length > 1) {
10837 if (isAry && ary < length) {
10840 if (this && this !== root && this instanceof wrapper) {
10841 fn = Ctor || createCtorWrapper(fn);
10843 return fn.apply(thisBinding, args);
10849 * Creates a function that wraps `func` to invoke it with the `this` binding
10850 * of `thisArg` and `partials` prepended to the arguments it receives.
10853 * @param {Function} func The function to wrap.
10854 * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
10855 * for more details.
10856 * @param {*} thisArg The `this` binding of `func`.
10857 * @param {Array} partials The arguments to prepend to those provided to
10858 * the new function.
10859 * @returns {Function} Returns the new wrapped function.
10861 function createPartialWrapper(func, bitmask, thisArg, partials) {
10862 var isBind = bitmask & BIND_FLAG,
10863 Ctor = createCtorWrapper(func);
10865 function wrapper() {
10866 var argsIndex = -1,
10867 argsLength = arguments.length,
10869 leftLength = partials.length,
10870 args = Array(leftLength + argsLength),
10871 fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
10873 while (++leftIndex < leftLength) {
10874 args[leftIndex] = partials[leftIndex];
10876 while (argsLength--) {
10877 args[leftIndex++] = arguments[++argsIndex];
10879 return apply(fn, isBind ? thisArg : this, args);
10885 * Creates a function that wraps `func` to continue currying.
10888 * @param {Function} func The function to wrap.
10889 * @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
10890 * for more details.
10891 * @param {Function} wrapFunc The function to create the `func` wrapper.
10892 * @param {*} placeholder The placeholder value.
10893 * @param {*} [thisArg] The `this` binding of `func`.
10894 * @param {Array} [partials] The arguments to prepend to those provided to
10895 * the new function.
10896 * @param {Array} [holders] The `partials` placeholder indexes.
10897 * @param {Array} [argPos] The argument positions of the new function.
10898 * @param {number} [ary] The arity cap of `func`.
10899 * @param {number} [arity] The arity of `func`.
10900 * @returns {Function} Returns the new wrapped function.
10902 function createRecurryWrapper(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
10903 var isCurry = bitmask & CURRY_FLAG,
10904 newHolders = isCurry ? holders : undefined,
10905 newHoldersRight = isCurry ? undefined : holders,
10906 newPartials = isCurry ? partials : undefined,
10907 newPartialsRight = isCurry ? undefined : partials;
10909 bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
10910 bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
10912 if (!(bitmask & CURRY_BOUND_FLAG)) {
10913 bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
10916 func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
10917 newHoldersRight, argPos, ary, arity
10920 var result = wrapFunc.apply(undefined, newData);
10921 if (isLaziable(func)) {
10922 setData(result, newData);
10924 result.placeholder = placeholder;
10929 * Creates a set of `values`.
10932 * @param {Array} values The values to add to the set.
10933 * @returns {Object} Returns the new set.
10935 var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
10936 return new Set(values);
10940 * Creates a `_.toPairs` or `_.toPairsIn` function.
10943 * @param {Function} keysFunc The function to get the keys of a given object.
10944 * @returns {Function} Returns the new pairs function.
10946 function createToPairs(keysFunc) {
10947 return function(object) {
10948 var tag = getTag(object);
10949 if (tag == mapTag) {
10950 return mapToArray(object);
10952 if (tag == setTag) {
10953 return setToPairs(object);
10955 return baseToPairs(object, keysFunc(object));
10960 * Creates a function that either curries or invokes `func` with optional
10961 * `this` binding and partially applied arguments.
10964 * @param {Function|string} func The function or method name to wrap.
10965 * @param {number} bitmask The bitmask of wrapper flags.
10966 * The bitmask may be composed of the following flags:
10969 * 4 - `_.curry` or `_.curryRight` of a bound function
10971 * 16 - `_.curryRight`
10973 * 64 - `_.partialRight`
10977 * @param {*} [thisArg] The `this` binding of `func`.
10978 * @param {Array} [partials] The arguments to be partially applied.
10979 * @param {Array} [holders] The `partials` placeholder indexes.
10980 * @param {Array} [argPos] The argument positions of the new function.
10981 * @param {number} [ary] The arity cap of `func`.
10982 * @param {number} [arity] The arity of `func`.
10983 * @returns {Function} Returns the new wrapped function.
10985 function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
10986 var isBindKey = bitmask & BIND_KEY_FLAG;
10987 if (!isBindKey && typeof func != 'function') {
10988 throw new TypeError(FUNC_ERROR_TEXT);
10990 var length = partials ? partials.length : 0;
10992 bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
10993 partials = holders = undefined;
10995 ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
10996 arity = arity === undefined ? arity : toInteger(arity);
10997 length -= holders ? holders.length : 0;
10999 if (bitmask & PARTIAL_RIGHT_FLAG) {
11000 var partialsRight = partials,
11001 holdersRight = holders;
11003 partials = holders = undefined;
11005 var data = isBindKey ? undefined : getData(func);
11008 func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
11013 mergeData(newData, data);
11016 bitmask = newData[1];
11017 thisArg = newData[2];
11018 partials = newData[3];
11019 holders = newData[4];
11020 arity = newData[9] = newData[9] == null
11021 ? (isBindKey ? 0 : func.length)
11022 : nativeMax(newData[9] - length, 0);
11024 if (!arity && bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG)) {
11025 bitmask &= ~(CURRY_FLAG | CURRY_RIGHT_FLAG);
11027 if (!bitmask || bitmask == BIND_FLAG) {
11028 var result = createBaseWrapper(func, bitmask, thisArg);
11029 } else if (bitmask == CURRY_FLAG || bitmask == CURRY_RIGHT_FLAG) {
11030 result = createCurryWrapper(func, bitmask, arity);
11031 } else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !holders.length) {
11032 result = createPartialWrapper(func, bitmask, thisArg, partials);
11034 result = createHybridWrapper.apply(undefined, newData);
11036 var setter = data ? baseSetData : setData;
11037 return setter(result, newData);
11041 * A specialized version of `baseIsEqualDeep` for arrays with support for
11042 * partial deep comparisons.
11045 * @param {Array} array The array to compare.
11046 * @param {Array} other The other array to compare.
11047 * @param {Function} equalFunc The function to determine equivalents of values.
11048 * @param {Function} customizer The function to customize comparisons.
11049 * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
11050 * for more details.
11051 * @param {Object} stack Tracks traversed `array` and `other` objects.
11052 * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
11054 function equalArrays(array, other, equalFunc, customizer, bitmask, stack) {
11055 var isPartial = bitmask & PARTIAL_COMPARE_FLAG,
11056 arrLength = array.length,
11057 othLength = other.length;
11059 if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
11062 // Assume cyclic values are equal.
11063 var stacked = stack.get(array);
11065 return stacked == other;
11069 seen = (bitmask & UNORDERED_COMPARE_FLAG) ? new SetCache : undefined;
11071 stack.set(array, other);
11073 // Ignore non-index properties.
11074 while (++index < arrLength) {
11075 var arrValue = array[index],
11076 othValue = other[index];
11079 var compared = isPartial
11080 ? customizer(othValue, arrValue, index, other, array, stack)
11081 : customizer(arrValue, othValue, index, array, other, stack);
11083 if (compared !== undefined) {
11090 // Recursively compare arrays (susceptible to call stack limits).
11092 if (!arraySome(other, function(othValue, othIndex) {
11093 if (!seen.has(othIndex) &&
11094 (arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) {
11095 return seen.add(othIndex);
11102 arrValue === othValue ||
11103 equalFunc(arrValue, othValue, customizer, bitmask, stack)
11109 stack['delete'](array);
11114 * A specialized version of `baseIsEqualDeep` for comparing objects of
11115 * the same `toStringTag`.
11117 * **Note:** This function only supports comparing values with tags of
11118 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
11121 * @param {Object} object The object to compare.
11122 * @param {Object} other The other object to compare.
11123 * @param {string} tag The `toStringTag` of the objects to compare.
11124 * @param {Function} equalFunc The function to determine equivalents of values.
11125 * @param {Function} customizer The function to customize comparisons.
11126 * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
11127 * for more details.
11128 * @param {Object} stack Tracks traversed `object` and `other` objects.
11129 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
11131 function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) {
11134 if ((object.byteLength != other.byteLength) ||
11135 (object.byteOffset != other.byteOffset)) {
11138 object = object.buffer;
11139 other = other.buffer;
11141 case arrayBufferTag:
11142 if ((object.byteLength != other.byteLength) ||
11143 !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
11150 // Coerce dates and booleans to numbers, dates to milliseconds and
11151 // booleans to `1` or `0` treating invalid dates coerced to `NaN` as
11153 return +object == +other;
11156 return object.name == other.name && object.message == other.message;
11159 // Treat `NaN` vs. `NaN` as equal.
11160 return (object != +object) ? other != +other : object == +other;
11164 // Coerce regexes to strings and treat strings, primitives and objects,
11165 // as equal. See http://www.ecma-international.org/ecma-262/6.0/#sec-regexp.prototype.tostring
11166 // for more details.
11167 return object == (other + '');
11170 var convert = mapToArray;
11173 var isPartial = bitmask & PARTIAL_COMPARE_FLAG;
11174 convert || (convert = setToArray);
11176 if (object.size != other.size && !isPartial) {
11179 // Assume cyclic values are equal.
11180 var stacked = stack.get(object);
11182 return stacked == other;
11184 bitmask |= UNORDERED_COMPARE_FLAG;
11185 stack.set(object, other);
11187 // Recursively compare objects (susceptible to call stack limits).
11188 return equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack);
11191 if (symbolValueOf) {
11192 return symbolValueOf.call(object) == symbolValueOf.call(other);
11199 * A specialized version of `baseIsEqualDeep` for objects with support for
11200 * partial deep comparisons.
11203 * @param {Object} object The object to compare.
11204 * @param {Object} other The other object to compare.
11205 * @param {Function} equalFunc The function to determine equivalents of values.
11206 * @param {Function} customizer The function to customize comparisons.
11207 * @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
11208 * for more details.
11209 * @param {Object} stack Tracks traversed `object` and `other` objects.
11210 * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
11212 function equalObjects(object, other, equalFunc, customizer, bitmask, stack) {
11213 var isPartial = bitmask & PARTIAL_COMPARE_FLAG,
11214 objProps = keys(object),
11215 objLength = objProps.length,
11216 othProps = keys(other),
11217 othLength = othProps.length;
11219 if (objLength != othLength && !isPartial) {
11222 var index = objLength;
11224 var key = objProps[index];
11225 if (!(isPartial ? key in other : baseHas(other, key))) {
11229 // Assume cyclic values are equal.
11230 var stacked = stack.get(object);
11232 return stacked == other;
11235 stack.set(object, other);
11237 var skipCtor = isPartial;
11238 while (++index < objLength) {
11239 key = objProps[index];
11240 var objValue = object[key],
11241 othValue = other[key];
11244 var compared = isPartial
11245 ? customizer(othValue, objValue, key, other, object, stack)
11246 : customizer(objValue, othValue, key, object, other, stack);
11248 // Recursively compare objects (susceptible to call stack limits).
11249 if (!(compared === undefined
11250 ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack))
11256 skipCtor || (skipCtor = key == 'constructor');
11258 if (result && !skipCtor) {
11259 var objCtor = object.constructor,
11260 othCtor = other.constructor;
11262 // Non `Object` object instances with different constructors are not equal.
11263 if (objCtor != othCtor &&
11264 ('constructor' in object && 'constructor' in other) &&
11265 !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
11266 typeof othCtor == 'function' && othCtor instanceof othCtor)) {
11270 stack['delete'](object);
11275 * Creates an array of own enumerable property names and symbols of `object`.
11278 * @param {Object} object The object to query.
11279 * @returns {Array} Returns the array of property names and symbols.
11281 function getAllKeys(object) {
11282 return baseGetAllKeys(object, keys, getSymbols);
11286 * Creates an array of own and inherited enumerable property names and
11287 * symbols of `object`.
11290 * @param {Object} object The object to query.
11291 * @returns {Array} Returns the array of property names and symbols.
11293 function getAllKeysIn(object) {
11294 return baseGetAllKeys(object, keysIn, getSymbolsIn);
11298 * Gets metadata for `func`.
11301 * @param {Function} func The function to query.
11302 * @returns {*} Returns the metadata for `func`.
11304 var getData = !metaMap ? noop : function(func) {
11305 return metaMap.get(func);
11309 * Gets the name of `func`.
11312 * @param {Function} func The function to query.
11313 * @returns {string} Returns the function name.
11315 function getFuncName(func) {
11316 var result = (func.name + ''),
11317 array = realNames[result],
11318 length = hasOwnProperty.call(realNames, result) ? array.length : 0;
11321 var data = array[length],
11322 otherFunc = data.func;
11323 if (otherFunc == null || otherFunc == func) {
11331 * Gets the argument placeholder value for `func`.
11334 * @param {Function} func The function to inspect.
11335 * @returns {*} Returns the placeholder value.
11337 function getHolder(func) {
11338 var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
11339 return object.placeholder;
11343 * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
11344 * this function returns the custom method, otherwise it returns `baseIteratee`.
11345 * If arguments are provided, the chosen function is invoked with them and
11346 * its result is returned.
11349 * @param {*} [value] The value to convert to an iteratee.
11350 * @param {number} [arity] The arity of the created iteratee.
11351 * @returns {Function} Returns the chosen function or its result.
11353 function getIteratee() {
11354 var result = lodash.iteratee || iteratee;
11355 result = result === iteratee ? baseIteratee : result;
11356 return arguments.length ? result(arguments[0], arguments[1]) : result;
11360 * Gets the "length" property value of `object`.
11362 * **Note:** This function is used to avoid a
11363 * [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) that affects
11364 * Safari on at least iOS 8.1-8.3 ARM64.
11367 * @param {Object} object The object to query.
11368 * @returns {*} Returns the "length" value.
11370 var getLength = baseProperty('length');
11373 * Gets the data for `map`.
11376 * @param {Object} map The map to query.
11377 * @param {string} key The reference key.
11378 * @returns {*} Returns the map data.
11380 function getMapData(map, key) {
11381 var data = map.__data__;
11382 return isKeyable(key)
11383 ? data[typeof key == 'string' ? 'string' : 'hash']
11388 * Gets the property names, values, and compare flags of `object`.
11391 * @param {Object} object The object to query.
11392 * @returns {Array} Returns the match data of `object`.
11394 function getMatchData(object) {
11395 var result = toPairs(object),
11396 length = result.length;
11399 result[length][2] = isStrictComparable(result[length][1]);
11405 * Gets the native function at `key` of `object`.
11408 * @param {Object} object The object to query.
11409 * @param {string} key The key of the method to get.
11410 * @returns {*} Returns the function if it's native, else `undefined`.
11412 function getNative(object, key) {
11413 var value = object[key];
11414 return isNative(value) ? value : undefined;
11418 * Gets the `[[Prototype]]` of `value`.
11421 * @param {*} value The value to query.
11422 * @returns {null|Object} Returns the `[[Prototype]]`.
11424 function getPrototype(value) {
11425 return nativeGetPrototype(Object(value));
11429 * Creates an array of the own enumerable symbol properties of `object`.
11432 * @param {Object} object The object to query.
11433 * @returns {Array} Returns the array of symbols.
11435 function getSymbols(object) {
11436 // Coerce `object` to an object to avoid non-object errors in V8.
11437 // See https://bugs.chromium.org/p/v8/issues/detail?id=3443 for more details.
11438 return getOwnPropertySymbols(Object(object));
11441 // Fallback for IE < 11.
11442 if (!getOwnPropertySymbols) {
11443 getSymbols = function() {
11449 * Creates an array of the own and inherited enumerable symbol properties
11453 * @param {Object} object The object to query.
11454 * @returns {Array} Returns the array of symbols.
11456 var getSymbolsIn = !getOwnPropertySymbols ? getSymbols : function(object) {
11459 arrayPush(result, getSymbols(object));
11460 object = getPrototype(object);
11466 * Gets the `toStringTag` of `value`.
11469 * @param {*} value The value to query.
11470 * @returns {string} Returns the `toStringTag`.
11472 function getTag(value) {
11473 return objectToString.call(value);
11476 // Fallback for data views, maps, sets, and weak maps in IE 11,
11477 // for data views in Edge, and promises in Node.js.
11478 if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
11479 (Map && getTag(new Map) != mapTag) ||
11480 (Promise && getTag(Promise.resolve()) != promiseTag) ||
11481 (Set && getTag(new Set) != setTag) ||
11482 (WeakMap && getTag(new WeakMap) != weakMapTag)) {
11483 getTag = function(value) {
11484 var result = objectToString.call(value),
11485 Ctor = result == objectTag ? value.constructor : undefined,
11486 ctorString = Ctor ? toSource(Ctor) : undefined;
11489 switch (ctorString) {
11490 case dataViewCtorString: return dataViewTag;
11491 case mapCtorString: return mapTag;
11492 case promiseCtorString: return promiseTag;
11493 case setCtorString: return setTag;
11494 case weakMapCtorString: return weakMapTag;
11502 * Gets the view, applying any `transforms` to the `start` and `end` positions.
11505 * @param {number} start The start of the view.
11506 * @param {number} end The end of the view.
11507 * @param {Array} transforms The transformations to apply to the view.
11508 * @returns {Object} Returns an object containing the `start` and `end`
11509 * positions of the view.
11511 function getView(start, end, transforms) {
11513 length = transforms.length;
11515 while (++index < length) {
11516 var data = transforms[index],
11519 switch (data.type) {
11520 case 'drop': start += size; break;
11521 case 'dropRight': end -= size; break;
11522 case 'take': end = nativeMin(end, start + size); break;
11523 case 'takeRight': start = nativeMax(start, end - size); break;
11526 return { 'start': start, 'end': end };
11530 * Checks if `path` exists on `object`.
11533 * @param {Object} object The object to query.
11534 * @param {Array|string} path The path to check.
11535 * @param {Function} hasFunc The function to check properties.
11536 * @returns {boolean} Returns `true` if `path` exists, else `false`.
11538 function hasPath(object, path, hasFunc) {
11539 path = isKey(path, object) ? [path] : castPath(path);
11543 length = path.length;
11545 while (++index < length) {
11546 var key = toKey(path[index]);
11547 if (!(result = object != null && hasFunc(object, key))) {
11550 object = object[key];
11555 var length = object ? object.length : 0;
11556 return !!length && isLength(length) && isIndex(key, length) &&
11557 (isArray(object) || isString(object) || isArguments(object));
11561 * Initializes an array clone.
11564 * @param {Array} array The array to clone.
11565 * @returns {Array} Returns the initialized clone.
11567 function initCloneArray(array) {
11568 var length = array.length,
11569 result = array.constructor(length);
11571 // Add properties assigned by `RegExp#exec`.
11572 if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
11573 result.index = array.index;
11574 result.input = array.input;
11580 * Initializes an object clone.
11583 * @param {Object} object The object to clone.
11584 * @returns {Object} Returns the initialized clone.
11586 function initCloneObject(object) {
11587 return (typeof object.constructor == 'function' && !isPrototype(object))
11588 ? baseCreate(getPrototype(object))
11593 * Initializes an object clone based on its `toStringTag`.
11595 * **Note:** This function only supports cloning values with tags of
11596 * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
11599 * @param {Object} object The object to clone.
11600 * @param {string} tag The `toStringTag` of the object to clone.
11601 * @param {Function} cloneFunc The function to clone values.
11602 * @param {boolean} [isDeep] Specify a deep clone.
11603 * @returns {Object} Returns the initialized clone.
11605 function initCloneByTag(object, tag, cloneFunc, isDeep) {
11606 var Ctor = object.constructor;
11608 case arrayBufferTag:
11609 return cloneArrayBuffer(object);
11613 return new Ctor(+object);
11616 return cloneDataView(object, isDeep);
11618 case float32Tag: case float64Tag:
11619 case int8Tag: case int16Tag: case int32Tag:
11620 case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
11621 return cloneTypedArray(object, isDeep);
11624 return cloneMap(object, isDeep, cloneFunc);
11628 return new Ctor(object);
11631 return cloneRegExp(object);
11634 return cloneSet(object, isDeep, cloneFunc);
11637 return cloneSymbol(object);
11642 * Creates an array of index keys for `object` values of arrays,
11643 * `arguments` objects, and strings, otherwise `null` is returned.
11646 * @param {Object} object The object to query.
11647 * @returns {Array|null} Returns index keys, else `null`.
11649 function indexKeys(object) {
11650 var length = object ? object.length : undefined;
11651 if (isLength(length) &&
11652 (isArray(object) || isString(object) || isArguments(object))) {
11653 return baseTimes(length, String);
11659 * Checks if `value` is a flattenable `arguments` object or array.
11662 * @param {*} value The value to check.
11663 * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
11665 function isFlattenable(value) {
11666 return isArray(value) || isArguments(value);
11670 * Checks if `value` is a valid array-like index.
11673 * @param {*} value The value to check.
11674 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
11675 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
11677 function isIndex(value, length) {
11678 length = length == null ? MAX_SAFE_INTEGER : length;
11680 (typeof value == 'number' || reIsUint.test(value)) &&
11681 (value > -1 && value % 1 == 0 && value < length);
11685 * Checks if the given arguments are from an iteratee call.
11688 * @param {*} value The potential iteratee value argument.
11689 * @param {*} index The potential iteratee index or key argument.
11690 * @param {*} object The potential iteratee object argument.
11691 * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
11694 function isIterateeCall(value, index, object) {
11695 if (!isObject(object)) {
11698 var type = typeof index;
11699 if (type == 'number'
11700 ? (isArrayLike(object) && isIndex(index, object.length))
11701 : (type == 'string' && index in object)
11703 return eq(object[index], value);
11709 * Checks if `value` is a property name and not a property path.
11712 * @param {*} value The value to check.
11713 * @param {Object} [object] The object to query keys on.
11714 * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
11716 function isKey(value, object) {
11717 if (isArray(value)) {
11720 var type = typeof value;
11721 if (type == 'number' || type == 'symbol' || type == 'boolean' ||
11722 value == null || isSymbol(value)) {
11725 return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
11726 (object != null && value in Object(object));
11730 * Checks if `value` is suitable for use as unique object key.
11733 * @param {*} value The value to check.
11734 * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
11736 function isKeyable(value) {
11737 var type = typeof value;
11738 return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
11739 ? (value !== '__proto__')
11740 : (value === null);
11744 * Checks if `func` has a lazy counterpart.
11747 * @param {Function} func The function to check.
11748 * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
11751 function isLaziable(func) {
11752 var funcName = getFuncName(func),
11753 other = lodash[funcName];
11755 if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
11758 if (func === other) {
11761 var data = getData(other);
11762 return !!data && func === data[0];
11766 * Checks if `value` is likely a prototype object.
11769 * @param {*} value The value to check.
11770 * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
11772 function isPrototype(value) {
11773 var Ctor = value && value.constructor,
11774 proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
11776 return value === proto;
11780 * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
11783 * @param {*} value The value to check.
11784 * @returns {boolean} Returns `true` if `value` if suitable for strict
11785 * equality comparisons, else `false`.
11787 function isStrictComparable(value) {
11788 return value === value && !isObject(value);
11792 * A specialized version of `matchesProperty` for source values suitable
11793 * for strict equality comparisons, i.e. `===`.
11796 * @param {string} key The key of the property to get.
11797 * @param {*} srcValue The value to match.
11798 * @returns {Function} Returns the new spec function.
11800 function matchesStrictComparable(key, srcValue) {
11801 return function(object) {
11802 if (object == null) {
11805 return object[key] === srcValue &&
11806 (srcValue !== undefined || (key in Object(object)));
11811 * Merges the function metadata of `source` into `data`.
11813 * Merging metadata reduces the number of wrappers used to invoke a function.
11814 * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
11815 * may be applied regardless of execution order. Methods like `_.ary` and
11816 * `_.rearg` modify function arguments, making the order in which they are
11817 * executed important, preventing the merging of metadata. However, we make
11818 * an exception for a safe combined case where curried functions have `_.ary`
11819 * and or `_.rearg` applied.
11822 * @param {Array} data The destination metadata.
11823 * @param {Array} source The source metadata.
11824 * @returns {Array} Returns `data`.
11826 function mergeData(data, source) {
11827 var bitmask = data[1],
11828 srcBitmask = source[1],
11829 newBitmask = bitmask | srcBitmask,
11830 isCommon = newBitmask < (BIND_FLAG | BIND_KEY_FLAG | ARY_FLAG);
11833 ((srcBitmask == ARY_FLAG) && (bitmask == CURRY_FLAG)) ||
11834 ((srcBitmask == ARY_FLAG) && (bitmask == REARG_FLAG) && (data[7].length <= source[8])) ||
11835 ((srcBitmask == (ARY_FLAG | REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == CURRY_FLAG));
11837 // Exit early if metadata can't be merged.
11838 if (!(isCommon || isCombo)) {
11841 // Use source `thisArg` if available.
11842 if (srcBitmask & BIND_FLAG) {
11843 data[2] = source[2];
11844 // Set when currying a bound function.
11845 newBitmask |= bitmask & BIND_FLAG ? 0 : CURRY_BOUND_FLAG;
11847 // Compose partial arguments.
11848 var value = source[3];
11850 var partials = data[3];
11851 data[3] = partials ? composeArgs(partials, value, source[4]) : value;
11852 data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
11854 // Compose partial right arguments.
11857 partials = data[5];
11858 data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
11859 data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
11861 // Use source `argPos` if available.
11866 // Use source `ary` if it's smaller.
11867 if (srcBitmask & ARY_FLAG) {
11868 data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
11870 // Use source `arity` if one is not provided.
11871 if (data[9] == null) {
11872 data[9] = source[9];
11874 // Use source `func` and merge bitmasks.
11875 data[0] = source[0];
11876 data[1] = newBitmask;
11882 * Gets the parent value at `path` of `object`.
11885 * @param {Object} object The object to query.
11886 * @param {Array} path The path to get the parent value of.
11887 * @returns {*} Returns the parent value.
11889 function parent(object, path) {
11890 return path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
11894 * Reorder `array` according to the specified indexes where the element at
11895 * the first index is assigned as the first element, the element at
11896 * the second index is assigned as the second element, and so on.
11899 * @param {Array} array The array to reorder.
11900 * @param {Array} indexes The arranged array indexes.
11901 * @returns {Array} Returns `array`.
11903 function reorder(array, indexes) {
11904 var arrLength = array.length,
11905 length = nativeMin(indexes.length, arrLength),
11906 oldArray = copyArray(array);
11909 var index = indexes[length];
11910 array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
11916 * Sets metadata for `func`.
11918 * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
11919 * period of time, it will trip its breaker and transition to an identity
11920 * function to avoid garbage collection pauses in V8. See
11921 * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
11922 * for more details.
11925 * @param {Function} func The function to associate metadata with.
11926 * @param {*} data The metadata.
11927 * @returns {Function} Returns `func`.
11929 var setData = (function() {
11933 return function(key, value) {
11935 remaining = HOT_SPAN - (stamp - lastCalled);
11937 lastCalled = stamp;
11938 if (remaining > 0) {
11939 if (++count >= HOT_COUNT) {
11945 return baseSetData(key, value);
11950 * Converts `string` to a property path array.
11953 * @param {string} string The string to convert.
11954 * @returns {Array} Returns the property path array.
11956 var stringToPath = memoize(function(string) {
11958 toString(string).replace(rePropName, function(match, number, quote, string) {
11959 result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
11965 * Converts `value` to a string key if it's not a string or symbol.
11968 * @param {*} value The value to inspect.
11969 * @returns {string|symbol} Returns the key.
11971 function toKey(value) {
11972 if (typeof value == 'string' || isSymbol(value)) {
11975 var result = (value + '');
11976 return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
11980 * Converts `func` to its source code.
11983 * @param {Function} func The function to process.
11984 * @returns {string} Returns the source code.
11986 function toSource(func) {
11987 if (func != null) {
11989 return funcToString.call(func);
11992 return (func + '');
11999 * Creates a clone of `wrapper`.
12002 * @param {Object} wrapper The wrapper to clone.
12003 * @returns {Object} Returns the cloned wrapper.
12005 function wrapperClone(wrapper) {
12006 if (wrapper instanceof LazyWrapper) {
12007 return wrapper.clone();
12009 var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
12010 result.__actions__ = copyArray(wrapper.__actions__);
12011 result.__index__ = wrapper.__index__;
12012 result.__values__ = wrapper.__values__;
12016 /*------------------------------------------------------------------------*/
12019 * Creates an array of elements split into groups the length of `size`.
12020 * If `array` can't be split evenly, the final chunk will be the remaining
12027 * @param {Array} array The array to process.
12028 * @param {number} [size=1] The length of each chunk
12029 * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
12030 * @returns {Array} Returns the new array of chunks.
12033 * _.chunk(['a', 'b', 'c', 'd'], 2);
12034 * // => [['a', 'b'], ['c', 'd']]
12036 * _.chunk(['a', 'b', 'c', 'd'], 3);
12037 * // => [['a', 'b', 'c'], ['d']]
12039 function chunk(array, size, guard) {
12040 if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
12043 size = nativeMax(toInteger(size), 0);
12045 var length = array ? array.length : 0;
12046 if (!length || size < 1) {
12051 result = Array(nativeCeil(length / size));
12053 while (index < length) {
12054 result[resIndex++] = baseSlice(array, index, (index += size));
12060 * Creates an array with all falsey values removed. The values `false`, `null`,
12061 * `0`, `""`, `undefined`, and `NaN` are falsey.
12067 * @param {Array} array The array to compact.
12068 * @returns {Array} Returns the new array of filtered values.
12071 * _.compact([0, 1, false, 2, '', 3]);
12074 function compact(array) {
12076 length = array ? array.length : 0,
12080 while (++index < length) {
12081 var value = array[index];
12083 result[resIndex++] = value;
12090 * Creates an array of unique `array` values not included in the other given
12091 * arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12092 * for equality comparisons. The order of result values is determined by the
12093 * order they occur in the first array.
12099 * @param {Array} array The array to inspect.
12100 * @param {...Array} [values] The values to exclude.
12101 * @returns {Array} Returns the new array of filtered values.
12102 * @see _.without, _.xor
12105 * _.difference([3, 2, 1], [4, 2]);
12108 var difference = rest(function(array, values) {
12109 return isArrayLikeObject(array)
12110 ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
12115 * Flattens `array` a single level deep.
12121 * @param {Array} array The array to flatten.
12122 * @returns {Array} Returns the new flattened array.
12125 * _.flatten([1, [2, [3, [4]], 5]]);
12126 * // => [1, 2, [3, [4]], 5]
12128 function flatten(array) {
12129 var length = array ? array.length : 0;
12130 return length ? baseFlatten(array, 1) : [];
12134 * Gets the first element of `array`.
12141 * @param {Array} array The array to query.
12142 * @returns {*} Returns the first element of `array`.
12145 * _.head([1, 2, 3]);
12151 function head(array) {
12152 return (array && array.length) ? array[0] : undefined;
12156 * Gets the index at which the first occurrence of `value` is found in `array`
12157 * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12158 * for equality comparisons. If `fromIndex` is negative, it's used as the
12159 * offset from the end of `array`.
12165 * @param {Array} array The array to search.
12166 * @param {*} value The value to search for.
12167 * @param {number} [fromIndex=0] The index to search from.
12168 * @returns {number} Returns the index of the matched value, else `-1`.
12171 * _.indexOf([1, 2, 1, 2], 2);
12174 * // Search from the `fromIndex`.
12175 * _.indexOf([1, 2, 1, 2], 2, 2);
12178 function indexOf(array, value, fromIndex) {
12179 var length = array ? array.length : 0;
12183 fromIndex = toInteger(fromIndex);
12184 if (fromIndex < 0) {
12185 fromIndex = nativeMax(length + fromIndex, 0);
12187 return baseIndexOf(array, value, fromIndex);
12191 * Creates an array of unique values that are included in all given arrays
12192 * using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12193 * for equality comparisons. The order of result values is determined by the
12194 * order they occur in the first array.
12200 * @param {...Array} [arrays] The arrays to inspect.
12201 * @returns {Array} Returns the new array of intersecting values.
12204 * _.intersection([2, 1], [4, 2], [1, 2]);
12207 var intersection = rest(function(arrays) {
12208 var mapped = arrayMap(arrays, castArrayLikeObject);
12209 return (mapped.length && mapped[0] === arrays[0])
12210 ? baseIntersection(mapped)
12215 * Gets the last element of `array`.
12221 * @param {Array} array The array to query.
12222 * @returns {*} Returns the last element of `array`.
12225 * _.last([1, 2, 3]);
12228 function last(array) {
12229 var length = array ? array.length : 0;
12230 return length ? array[length - 1] : undefined;
12234 * Reverses `array` so that the first element becomes the last, the second
12235 * element becomes the second to last, and so on.
12237 * **Note:** This method mutates `array` and is based on
12238 * [`Array#reverse`](https://mdn.io/Array/reverse).
12244 * @param {Array} array The array to modify.
12245 * @returns {Array} Returns `array`.
12248 * var array = [1, 2, 3];
12250 * _.reverse(array);
12253 * console.log(array);
12256 function reverse(array) {
12257 return array ? nativeReverse.call(array) : array;
12261 * Creates an array of unique values, in order, from all given arrays using
12262 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12263 * for equality comparisons.
12269 * @param {...Array} [arrays] The arrays to inspect.
12270 * @returns {Array} Returns the new array of combined values.
12273 * _.union([2, 1], [4, 2], [1, 2]);
12276 var union = rest(function(arrays) {
12277 return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
12281 * Creates a duplicate-free version of an array, using
12282 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12283 * for equality comparisons, in which only the first occurrence of each
12290 * @param {Array} array The array to inspect.
12291 * @returns {Array} Returns the new duplicate free array.
12294 * _.uniq([2, 1, 2]);
12297 function uniq(array) {
12298 return (array && array.length)
12304 * Creates an array excluding all given values using
12305 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12306 * for equality comparisons.
12312 * @param {Array} array The array to inspect.
12313 * @param {...*} [values] The values to exclude.
12314 * @returns {Array} Returns the new array of filtered values.
12315 * @see _.difference, _.xor
12318 * _.without([1, 2, 1, 3], 1, 2);
12321 var without = rest(function(array, values) {
12322 return isArrayLikeObject(array)
12323 ? baseDifference(array, values)
12327 /*------------------------------------------------------------------------*/
12330 * Creates a `lodash` wrapper instance that wraps `value` with explicit method
12331 * chain sequences enabled. The result of such sequences must be unwrapped
12338 * @param {*} value The value to wrap.
12339 * @returns {Object} Returns the new `lodash` wrapper instance.
12343 * { 'user': 'barney', 'age': 36 },
12344 * { 'user': 'fred', 'age': 40 },
12345 * { 'user': 'pebbles', 'age': 1 }
12351 * .map(function(o) {
12352 * return o.user + ' is ' + o.age;
12356 * // => 'pebbles is 1'
12358 function chain(value) {
12359 var result = lodash(value);
12360 result.__chain__ = true;
12365 * This method invokes `interceptor` and returns `value`. The interceptor
12366 * is invoked with one argument; (value). The purpose of this method is to
12367 * "tap into" a method chain sequence in order to modify intermediate results.
12373 * @param {*} value The value to provide to `interceptor`.
12374 * @param {Function} interceptor The function to invoke.
12375 * @returns {*} Returns `value`.
12379 * .tap(function(array) {
12380 * // Mutate input array.
12387 function tap(value, interceptor) {
12388 interceptor(value);
12393 * This method is like `_.tap` except that it returns the result of `interceptor`.
12394 * The purpose of this method is to "pass thru" values replacing intermediate
12395 * results in a method chain sequence.
12401 * @param {*} value The value to provide to `interceptor`.
12402 * @param {Function} interceptor The function to invoke.
12403 * @returns {*} Returns the result of `interceptor`.
12409 * .thru(function(value) {
12415 function thru(value, interceptor) {
12416 return interceptor(value);
12420 * This method is the wrapper version of `_.at`.
12426 * @param {...(string|string[])} [paths] The property paths of elements to pick.
12427 * @returns {Object} Returns the new `lodash` wrapper instance.
12430 * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
12432 * _(object).at(['a[0].b.c', 'a[1]']).value();
12435 * _(['a', 'b', 'c']).at(0, 2).value();
12438 var wrapperAt = rest(function(paths) {
12439 paths = baseFlatten(paths, 1);
12440 var length = paths.length,
12441 start = length ? paths[0] : 0,
12442 value = this.__wrapped__,
12443 interceptor = function(object) { return baseAt(object, paths); };
12445 if (length > 1 || this.__actions__.length ||
12446 !(value instanceof LazyWrapper) || !isIndex(start)) {
12447 return this.thru(interceptor);
12449 value = value.slice(start, +start + (length ? 1 : 0));
12450 value.__actions__.push({
12452 'args': [interceptor],
12453 'thisArg': undefined
12455 return new LodashWrapper(value, this.__chain__).thru(function(array) {
12456 if (length && !array.length) {
12457 array.push(undefined);
12464 * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
12470 * @returns {Object} Returns the new `lodash` wrapper instance.
12474 * { 'user': 'barney', 'age': 36 },
12475 * { 'user': 'fred', 'age': 40 }
12478 * // A sequence without explicit chaining.
12480 * // => { 'user': 'barney', 'age': 36 }
12482 * // A sequence with explicit chaining.
12488 * // => { 'user': 'barney' }
12490 function wrapperChain() {
12491 return chain(this);
12495 * Executes the chain sequence and returns the wrapped result.
12501 * @returns {Object} Returns the new `lodash` wrapper instance.
12504 * var array = [1, 2];
12505 * var wrapped = _(array).push(3);
12507 * console.log(array);
12510 * wrapped = wrapped.commit();
12511 * console.log(array);
12517 * console.log(array);
12520 function wrapperCommit() {
12521 return new LodashWrapper(this.value(), this.__chain__);
12525 * Gets the next value on a wrapped object following the
12526 * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
12532 * @returns {Object} Returns the next iterator value.
12535 * var wrapped = _([1, 2]);
12538 * // => { 'done': false, 'value': 1 }
12541 * // => { 'done': false, 'value': 2 }
12544 * // => { 'done': true, 'value': undefined }
12546 function wrapperNext() {
12547 if (this.__values__ === undefined) {
12548 this.__values__ = toArray(this.value());
12550 var done = this.__index__ >= this.__values__.length,
12551 value = done ? undefined : this.__values__[this.__index__++];
12553 return { 'done': done, 'value': value };
12557 * Enables the wrapper to be iterable.
12559 * @name Symbol.iterator
12563 * @returns {Object} Returns the wrapper object.
12566 * var wrapped = _([1, 2]);
12568 * wrapped[Symbol.iterator]() === wrapped;
12571 * Array.from(wrapped);
12574 function wrapperToIterator() {
12579 * Creates a clone of the chain sequence planting `value` as the wrapped value.
12585 * @param {*} value The value to plant.
12586 * @returns {Object} Returns the new `lodash` wrapper instance.
12589 * function square(n) {
12593 * var wrapped = _([1, 2]).map(square);
12594 * var other = wrapped.plant([3, 4]);
12602 function wrapperPlant(value) {
12606 while (parent instanceof baseLodash) {
12607 var clone = wrapperClone(parent);
12608 clone.__index__ = 0;
12609 clone.__values__ = undefined;
12611 previous.__wrapped__ = clone;
12615 var previous = clone;
12616 parent = parent.__wrapped__;
12618 previous.__wrapped__ = value;
12623 * This method is the wrapper version of `_.reverse`.
12625 * **Note:** This method mutates the wrapped array.
12631 * @returns {Object} Returns the new `lodash` wrapper instance.
12634 * var array = [1, 2, 3];
12636 * _(array).reverse().value()
12639 * console.log(array);
12642 function wrapperReverse() {
12643 var value = this.__wrapped__;
12644 if (value instanceof LazyWrapper) {
12645 var wrapped = value;
12646 if (this.__actions__.length) {
12647 wrapped = new LazyWrapper(this);
12649 wrapped = wrapped.reverse();
12650 wrapped.__actions__.push({
12653 'thisArg': undefined
12655 return new LodashWrapper(wrapped, this.__chain__);
12657 return this.thru(reverse);
12661 * Executes the chain sequence to resolve the unwrapped value.
12666 * @alias toJSON, valueOf
12668 * @returns {*} Returns the resolved unwrapped value.
12671 * _([1, 2, 3]).value();
12674 function wrapperValue() {
12675 return baseWrapperValue(this.__wrapped__, this.__actions__);
12678 /*------------------------------------------------------------------------*/
12681 * Checks if `predicate` returns truthy for **all** elements of `collection`.
12682 * Iteration is stopped once `predicate` returns falsey. The predicate is
12683 * invoked with three arguments: (value, index|key, collection).
12688 * @category Collection
12689 * @param {Array|Object} collection The collection to iterate over.
12690 * @param {Array|Function|Object|string} [predicate=_.identity]
12691 * The function invoked per iteration.
12692 * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
12693 * @returns {boolean} Returns `true` if all elements pass the predicate check,
12697 * _.every([true, 1, null, 'yes'], Boolean);
12701 * { 'user': 'barney', 'age': 36, 'active': false },
12702 * { 'user': 'fred', 'age': 40, 'active': false }
12705 * // The `_.matches` iteratee shorthand.
12706 * _.every(users, { 'user': 'barney', 'active': false });
12709 * // The `_.matchesProperty` iteratee shorthand.
12710 * _.every(users, ['active', false]);
12713 * // The `_.property` iteratee shorthand.
12714 * _.every(users, 'active');
12717 function every(collection, predicate, guard) {
12718 var func = isArray(collection) ? arrayEvery : baseEvery;
12719 if (guard && isIterateeCall(collection, predicate, guard)) {
12720 predicate = undefined;
12722 return func(collection, getIteratee(predicate, 3));
12726 * Iterates over elements of `collection`, returning an array of all elements
12727 * `predicate` returns truthy for. The predicate is invoked with three
12728 * arguments: (value, index|key, collection).
12733 * @category Collection
12734 * @param {Array|Object} collection The collection to iterate over.
12735 * @param {Array|Function|Object|string} [predicate=_.identity]
12736 * The function invoked per iteration.
12737 * @returns {Array} Returns the new filtered array.
12742 * { 'user': 'barney', 'age': 36, 'active': true },
12743 * { 'user': 'fred', 'age': 40, 'active': false }
12746 * _.filter(users, function(o) { return !o.active; });
12747 * // => objects for ['fred']
12749 * // The `_.matches` iteratee shorthand.
12750 * _.filter(users, { 'age': 36, 'active': true });
12751 * // => objects for ['barney']
12753 * // The `_.matchesProperty` iteratee shorthand.
12754 * _.filter(users, ['active', false]);
12755 * // => objects for ['fred']
12757 * // The `_.property` iteratee shorthand.
12758 * _.filter(users, 'active');
12759 * // => objects for ['barney']
12761 function filter(collection, predicate) {
12762 var func = isArray(collection) ? arrayFilter : baseFilter;
12763 return func(collection, getIteratee(predicate, 3));
12767 * Iterates over elements of `collection`, returning the first element
12768 * `predicate` returns truthy for. The predicate is invoked with three
12769 * arguments: (value, index|key, collection).
12774 * @category Collection
12775 * @param {Array|Object} collection The collection to search.
12776 * @param {Array|Function|Object|string} [predicate=_.identity]
12777 * The function invoked per iteration.
12778 * @returns {*} Returns the matched element, else `undefined`.
12782 * { 'user': 'barney', 'age': 36, 'active': true },
12783 * { 'user': 'fred', 'age': 40, 'active': false },
12784 * { 'user': 'pebbles', 'age': 1, 'active': true }
12787 * _.find(users, function(o) { return o.age < 40; });
12788 * // => object for 'barney'
12790 * // The `_.matches` iteratee shorthand.
12791 * _.find(users, { 'age': 1, 'active': true });
12792 * // => object for 'pebbles'
12794 * // The `_.matchesProperty` iteratee shorthand.
12795 * _.find(users, ['active', false]);
12796 * // => object for 'fred'
12798 * // The `_.property` iteratee shorthand.
12799 * _.find(users, 'active');
12800 * // => object for 'barney'
12802 function find(collection, predicate) {
12803 predicate = getIteratee(predicate, 3);
12804 if (isArray(collection)) {
12805 var index = baseFindIndex(collection, predicate);
12806 return index > -1 ? collection[index] : undefined;
12808 return baseFind(collection, predicate, baseEach);
12812 * Iterates over elements of `collection` and invokes `iteratee` for each element.
12813 * The iteratee is invoked with three arguments: (value, index|key, collection).
12814 * Iteratee functions may exit iteration early by explicitly returning `false`.
12816 * **Note:** As with other "Collections" methods, objects with a "length"
12817 * property are iterated like arrays. To avoid this behavior use `_.forIn`
12818 * or `_.forOwn` for object iteration.
12824 * @category Collection
12825 * @param {Array|Object} collection The collection to iterate over.
12826 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12827 * @returns {Array|Object} Returns `collection`.
12828 * @see _.forEachRight
12831 * _([1, 2]).forEach(function(value) {
12832 * console.log(value);
12834 * // => Logs `1` then `2`.
12836 * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
12837 * console.log(key);
12839 * // => Logs 'a' then 'b' (iteration order is not guaranteed).
12841 function forEach(collection, iteratee) {
12842 var func = isArray(collection) ? arrayEach : baseEach;
12843 return func(collection, getIteratee(iteratee, 3));
12847 * Creates an object composed of keys generated from the results of running
12848 * each element of `collection` thru `iteratee`. The order of grouped values
12849 * is determined by the order they occur in `collection`. The corresponding
12850 * value of each key is an array of elements responsible for generating the
12851 * key. The iteratee is invoked with one argument: (value).
12856 * @category Collection
12857 * @param {Array|Object} collection The collection to iterate over.
12858 * @param {Array|Function|Object|string} [iteratee=_.identity]
12859 * The iteratee to transform keys.
12860 * @returns {Object} Returns the composed aggregate object.
12863 * _.groupBy([6.1, 4.2, 6.3], Math.floor);
12864 * // => { '4': [4.2], '6': [6.1, 6.3] }
12866 * // The `_.property` iteratee shorthand.
12867 * _.groupBy(['one', 'two', 'three'], 'length');
12868 * // => { '3': ['one', 'two'], '5': ['three'] }
12870 var groupBy = createAggregator(function(result, value, key) {
12871 if (hasOwnProperty.call(result, key)) {
12872 result[key].push(value);
12874 result[key] = [value];
12879 * Checks if `value` is in `collection`. If `collection` is a string, it's
12880 * checked for a substring of `value`, otherwise
12881 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
12882 * is used for equality comparisons. If `fromIndex` is negative, it's used as
12883 * the offset from the end of `collection`.
12888 * @category Collection
12889 * @param {Array|Object|string} collection The collection to search.
12890 * @param {*} value The value to search for.
12891 * @param {number} [fromIndex=0] The index to search from.
12892 * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
12893 * @returns {boolean} Returns `true` if `value` is found, else `false`.
12896 * _.includes([1, 2, 3], 1);
12899 * _.includes([1, 2, 3], 1, 2);
12902 * _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
12905 * _.includes('pebbles', 'eb');
12908 function includes(collection, value, fromIndex, guard) {
12909 collection = isArrayLike(collection) ? collection : values(collection);
12910 fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;
12912 var length = collection.length;
12913 if (fromIndex < 0) {
12914 fromIndex = nativeMax(length + fromIndex, 0);
12916 return isString(collection)
12917 ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
12918 : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
12922 * Creates an array of values by running each element in `collection` thru
12923 * `iteratee`. The iteratee is invoked with three arguments:
12924 * (value, index|key, collection).
12926 * Many lodash methods are guarded to work as iteratees for methods like
12927 * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
12929 * The guarded methods are:
12930 * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
12931 * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
12932 * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
12933 * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
12938 * @category Collection
12939 * @param {Array|Object} collection The collection to iterate over.
12940 * @param {Array|Function|Object|string} [iteratee=_.identity]
12941 * The function invoked per iteration.
12942 * @returns {Array} Returns the new mapped array.
12945 * function square(n) {
12949 * _.map([4, 8], square);
12952 * _.map({ 'a': 4, 'b': 8 }, square);
12953 * // => [16, 64] (iteration order is not guaranteed)
12956 * { 'user': 'barney' },
12957 * { 'user': 'fred' }
12960 * // The `_.property` iteratee shorthand.
12961 * _.map(users, 'user');
12962 * // => ['barney', 'fred']
12964 function map(collection, iteratee) {
12965 var func = isArray(collection) ? arrayMap : baseMap;
12966 return func(collection, getIteratee(iteratee, 3));
12970 * Reduces `collection` to a value which is the accumulated result of running
12971 * each element in `collection` thru `iteratee`, where each successive
12972 * invocation is supplied the return value of the previous. If `accumulator`
12973 * is not given, the first element of `collection` is used as the initial
12974 * value. The iteratee is invoked with four arguments:
12975 * (accumulator, value, index|key, collection).
12977 * Many lodash methods are guarded to work as iteratees for methods like
12978 * `_.reduce`, `_.reduceRight`, and `_.transform`.
12980 * The guarded methods are:
12981 * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
12987 * @category Collection
12988 * @param {Array|Object} collection The collection to iterate over.
12989 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12990 * @param {*} [accumulator] The initial value.
12991 * @returns {*} Returns the accumulated value.
12992 * @see _.reduceRight
12995 * _.reduce([1, 2], function(sum, n) {
13000 * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
13001 * (result[value] || (result[value] = [])).push(key);
13004 * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
13006 function reduce(collection, iteratee, accumulator) {
13007 var func = isArray(collection) ? arrayReduce : baseReduce,
13008 initAccum = arguments.length < 3;
13010 return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
13014 * The opposite of `_.filter`; this method returns the elements of `collection`
13015 * that `predicate` does **not** return truthy for.
13020 * @category Collection
13021 * @param {Array|Object} collection The collection to iterate over.
13022 * @param {Array|Function|Object|string} [predicate=_.identity]
13023 * The function invoked per iteration.
13024 * @returns {Array} Returns the new filtered array.
13029 * { 'user': 'barney', 'age': 36, 'active': false },
13030 * { 'user': 'fred', 'age': 40, 'active': true }
13033 * _.reject(users, function(o) { return !o.active; });
13034 * // => objects for ['fred']
13036 * // The `_.matches` iteratee shorthand.
13037 * _.reject(users, { 'age': 40, 'active': true });
13038 * // => objects for ['barney']
13040 * // The `_.matchesProperty` iteratee shorthand.
13041 * _.reject(users, ['active', false]);
13042 * // => objects for ['fred']
13044 * // The `_.property` iteratee shorthand.
13045 * _.reject(users, 'active');
13046 * // => objects for ['barney']
13048 function reject(collection, predicate) {
13049 var func = isArray(collection) ? arrayFilter : baseFilter;
13050 predicate = getIteratee(predicate, 3);
13051 return func(collection, function(value, index, collection) {
13052 return !predicate(value, index, collection);
13057 * Checks if `predicate` returns truthy for **any** element of `collection`.
13058 * Iteration is stopped once `predicate` returns truthy. The predicate is
13059 * invoked with three arguments: (value, index|key, collection).
13064 * @category Collection
13065 * @param {Array|Object} collection The collection to iterate over.
13066 * @param {Array|Function|Object|string} [predicate=_.identity]
13067 * The function invoked per iteration.
13068 * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
13069 * @returns {boolean} Returns `true` if any element passes the predicate check,
13073 * _.some([null, 0, 'yes', false], Boolean);
13077 * { 'user': 'barney', 'active': true },
13078 * { 'user': 'fred', 'active': false }
13081 * // The `_.matches` iteratee shorthand.
13082 * _.some(users, { 'user': 'barney', 'active': false });
13085 * // The `_.matchesProperty` iteratee shorthand.
13086 * _.some(users, ['active', false]);
13089 * // The `_.property` iteratee shorthand.
13090 * _.some(users, 'active');
13093 function some(collection, predicate, guard) {
13094 var func = isArray(collection) ? arraySome : baseSome;
13095 if (guard && isIterateeCall(collection, predicate, guard)) {
13096 predicate = undefined;
13098 return func(collection, getIteratee(predicate, 3));
13101 /*------------------------------------------------------------------------*/
13104 * Gets the timestamp of the number of milliseconds that have elapsed since
13105 * the Unix epoch (1 January 1970 00:00:00 UTC).
13112 * @returns {number} Returns the timestamp.
13115 * _.defer(function(stamp) {
13116 * console.log(_.now() - stamp);
13118 * // => Logs the number of milliseconds it took for the deferred function to be invoked.
13120 var now = Date.now;
13122 /*------------------------------------------------------------------------*/
13125 * Creates a function that invokes `func` with the `this` binding of `thisArg`
13126 * and `partials` prepended to the arguments it receives.
13128 * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
13129 * may be used as a placeholder for partially applied arguments.
13131 * **Note:** Unlike native `Function#bind` this method doesn't set the "length"
13132 * property of bound functions.
13137 * @category Function
13138 * @param {Function} func The function to bind.
13139 * @param {*} thisArg The `this` binding of `func`.
13140 * @param {...*} [partials] The arguments to be partially applied.
13141 * @returns {Function} Returns the new bound function.
13144 * var greet = function(greeting, punctuation) {
13145 * return greeting + ' ' + this.user + punctuation;
13148 * var object = { 'user': 'fred' };
13150 * var bound = _.bind(greet, object, 'hi');
13154 * // Bound with placeholders.
13155 * var bound = _.bind(greet, object, _, '!');
13159 var bind = rest(function(func, thisArg, partials) {
13160 var bitmask = BIND_FLAG;
13161 if (partials.length) {
13162 var holders = replaceHolders(partials, getHolder(bind));
13163 bitmask |= PARTIAL_FLAG;
13165 return createWrapper(func, bitmask, thisArg, partials, holders);
13169 * Creates a debounced function that delays invoking `func` until after `wait`
13170 * milliseconds have elapsed since the last time the debounced function was
13171 * invoked. The debounced function comes with a `cancel` method to cancel
13172 * delayed `func` invocations and a `flush` method to immediately invoke them.
13173 * Provide an options object to indicate whether `func` should be invoked on
13174 * the leading and/or trailing edge of the `wait` timeout. The `func` is invoked
13175 * with the last arguments provided to the debounced function. Subsequent calls
13176 * to the debounced function return the result of the last `func` invocation.
13178 * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
13179 * on the trailing edge of the timeout only if the debounced function is
13180 * invoked more than once during the `wait` timeout.
13182 * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
13183 * for details over the differences between `_.debounce` and `_.throttle`.
13188 * @category Function
13189 * @param {Function} func The function to debounce.
13190 * @param {number} [wait=0] The number of milliseconds to delay.
13191 * @param {Object} [options={}] The options object.
13192 * @param {boolean} [options.leading=false]
13193 * Specify invoking on the leading edge of the timeout.
13194 * @param {number} [options.maxWait]
13195 * The maximum time `func` is allowed to be delayed before it's invoked.
13196 * @param {boolean} [options.trailing=true]
13197 * Specify invoking on the trailing edge of the timeout.
13198 * @returns {Function} Returns the new debounced function.
13201 * // Avoid costly calculations while the window size is in flux.
13202 * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
13204 * // Invoke `sendMail` when clicked, debouncing subsequent calls.
13205 * jQuery(element).on('click', _.debounce(sendMail, 300, {
13207 * 'trailing': false
13210 * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
13211 * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
13212 * var source = new EventSource('/stream');
13213 * jQuery(source).on('message', debounced);
13215 * // Cancel the trailing debounced invocation.
13216 * jQuery(window).on('popstate', debounced.cancel);
13218 function debounce(func, wait, options) {
13225 lastInvokeTime = 0,
13230 if (typeof func != 'function') {
13231 throw new TypeError(FUNC_ERROR_TEXT);
13233 wait = toNumber(wait) || 0;
13234 if (isObject(options)) {
13235 leading = !!options.leading;
13236 maxing = 'maxWait' in options;
13237 maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
13238 trailing = 'trailing' in options ? !!options.trailing : trailing;
13241 function invokeFunc(time) {
13242 var args = lastArgs,
13243 thisArg = lastThis;
13245 lastArgs = lastThis = undefined;
13246 lastInvokeTime = time;
13247 result = func.apply(thisArg, args);
13251 function leadingEdge(time) {
13252 // Reset any `maxWait` timer.
13253 lastInvokeTime = time;
13254 // Start the timer for the trailing edge.
13255 timerId = setTimeout(timerExpired, wait);
13256 // Invoke the leading edge.
13257 return leading ? invokeFunc(time) : result;
13260 function remainingWait(time) {
13261 var timeSinceLastCall = time - lastCallTime,
13262 timeSinceLastInvoke = time - lastInvokeTime,
13263 result = wait - timeSinceLastCall;
13265 return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
13268 function shouldInvoke(time) {
13269 var timeSinceLastCall = time - lastCallTime,
13270 timeSinceLastInvoke = time - lastInvokeTime;
13272 // Either this is the first call, activity has stopped and we're at the
13273 // trailing edge, the system time has gone backwards and we're treating
13274 // it as the trailing edge, or we've hit the `maxWait` limit.
13275 return (!lastCallTime || (timeSinceLastCall >= wait) ||
13276 (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
13279 function timerExpired() {
13281 if (shouldInvoke(time)) {
13282 return trailingEdge(time);
13284 // Restart the timer.
13285 timerId = setTimeout(timerExpired, remainingWait(time));
13288 function trailingEdge(time) {
13289 clearTimeout(timerId);
13290 timerId = undefined;
13292 // Only invoke if we have `lastArgs` which means `func` has been
13293 // debounced at least once.
13294 if (trailing && lastArgs) {
13295 return invokeFunc(time);
13297 lastArgs = lastThis = undefined;
13301 function cancel() {
13302 if (timerId !== undefined) {
13303 clearTimeout(timerId);
13305 lastCallTime = lastInvokeTime = 0;
13306 lastArgs = lastThis = timerId = undefined;
13310 return timerId === undefined ? result : trailingEdge(now());
13313 function debounced() {
13315 isInvoking = shouldInvoke(time);
13317 lastArgs = arguments;
13319 lastCallTime = time;
13322 if (timerId === undefined) {
13323 return leadingEdge(lastCallTime);
13326 // Handle invocations in a tight loop.
13327 clearTimeout(timerId);
13328 timerId = setTimeout(timerExpired, wait);
13329 return invokeFunc(lastCallTime);
13332 if (timerId === undefined) {
13333 timerId = setTimeout(timerExpired, wait);
13337 debounced.cancel = cancel;
13338 debounced.flush = flush;
13343 * Creates a function that memoizes the result of `func`. If `resolver` is
13344 * provided, it determines the cache key for storing the result based on the
13345 * arguments provided to the memoized function. By default, the first argument
13346 * provided to the memoized function is used as the map cache key. The `func`
13347 * is invoked with the `this` binding of the memoized function.
13349 * **Note:** The cache is exposed as the `cache` property on the memoized
13350 * function. Its creation may be customized by replacing the `_.memoize.Cache`
13351 * constructor with one whose instances implement the
13352 * [`Map`](http://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-map-prototype-object)
13353 * method interface of `delete`, `get`, `has`, and `set`.
13358 * @category Function
13359 * @param {Function} func The function to have its output memoized.
13360 * @param {Function} [resolver] The function to resolve the cache key.
13361 * @returns {Function} Returns the new memoized function.
13364 * var object = { 'a': 1, 'b': 2 };
13365 * var other = { 'c': 3, 'd': 4 };
13367 * var values = _.memoize(_.values);
13378 * // Modify the result cache.
13379 * values.cache.set(object, ['a', 'b']);
13383 * // Replace `_.memoize.Cache`.
13384 * _.memoize.Cache = WeakMap;
13386 function memoize(func, resolver) {
13387 if (typeof func != 'function' || (resolver && typeof resolver != 'function')) {
13388 throw new TypeError(FUNC_ERROR_TEXT);
13390 var memoized = function() {
13391 var args = arguments,
13392 key = resolver ? resolver.apply(this, args) : args[0],
13393 cache = memoized.cache;
13395 if (cache.has(key)) {
13396 return cache.get(key);
13398 var result = func.apply(this, args);
13399 memoized.cache = cache.set(key, result);
13402 memoized.cache = new (memoize.Cache || MapCache);
13406 // Assign cache to `_.memoize`.
13407 memoize.Cache = MapCache;
13410 * Creates a function that invokes `func` with the `this` binding of the
13411 * created function and arguments from `start` and beyond provided as
13414 * **Note:** This method is based on the
13415 * [rest parameter](https://mdn.io/rest_parameters).
13420 * @category Function
13421 * @param {Function} func The function to apply a rest parameter to.
13422 * @param {number} [start=func.length-1] The start position of the rest parameter.
13423 * @returns {Function} Returns the new function.
13426 * var say = _.rest(function(what, names) {
13427 * return what + ' ' + _.initial(names).join(', ') +
13428 * (_.size(names) > 1 ? ', & ' : '') + _.last(names);
13431 * say('hello', 'fred', 'barney', 'pebbles');
13432 * // => 'hello fred, barney, & pebbles'
13434 function rest(func, start) {
13435 if (typeof func != 'function') {
13436 throw new TypeError(FUNC_ERROR_TEXT);
13438 start = nativeMax(start === undefined ? (func.length - 1) : toInteger(start), 0);
13439 return function() {
13440 var args = arguments,
13442 length = nativeMax(args.length - start, 0),
13443 array = Array(length);
13445 while (++index < length) {
13446 array[index] = args[start + index];
13449 case 0: return func.call(this, array);
13450 case 1: return func.call(this, args[0], array);
13451 case 2: return func.call(this, args[0], args[1], array);
13453 var otherArgs = Array(start + 1);
13455 while (++index < start) {
13456 otherArgs[index] = args[index];
13458 otherArgs[start] = array;
13459 return apply(func, this, otherArgs);
13464 * Creates a throttled function that only invokes `func` at most once per
13465 * every `wait` milliseconds. The throttled function comes with a `cancel`
13466 * method to cancel delayed `func` invocations and a `flush` method to
13467 * immediately invoke them. Provide an options object to indicate whether
13468 * `func` should be invoked on the leading and/or trailing edge of the `wait`
13469 * timeout. The `func` is invoked with the last arguments provided to the
13470 * throttled function. Subsequent calls to the throttled function return the
13471 * result of the last `func` invocation.
13473 * **Note:** If `leading` and `trailing` options are `true`, `func` is
13474 * invoked on the trailing edge of the timeout only if the throttled function
13475 * is invoked more than once during the `wait` timeout.
13477 * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
13478 * for details over the differences between `_.throttle` and `_.debounce`.
13483 * @category Function
13484 * @param {Function} func The function to throttle.
13485 * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
13486 * @param {Object} [options={}] The options object.
13487 * @param {boolean} [options.leading=true]
13488 * Specify invoking on the leading edge of the timeout.
13489 * @param {boolean} [options.trailing=true]
13490 * Specify invoking on the trailing edge of the timeout.
13491 * @returns {Function} Returns the new throttled function.
13494 * // Avoid excessively updating the position while scrolling.
13495 * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
13497 * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
13498 * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
13499 * jQuery(element).on('click', throttled);
13501 * // Cancel the trailing throttled invocation.
13502 * jQuery(window).on('popstate', throttled.cancel);
13504 function throttle(func, wait, options) {
13505 var leading = true,
13508 if (typeof func != 'function') {
13509 throw new TypeError(FUNC_ERROR_TEXT);
13511 if (isObject(options)) {
13512 leading = 'leading' in options ? !!options.leading : leading;
13513 trailing = 'trailing' in options ? !!options.trailing : trailing;
13515 return debounce(func, wait, {
13516 'leading': leading,
13518 'trailing': trailing
13522 /*------------------------------------------------------------------------*/
13525 * Creates a shallow clone of `value`.
13527 * **Note:** This method is loosely based on the
13528 * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
13529 * and supports cloning arrays, array buffers, booleans, date objects, maps,
13530 * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
13531 * arrays. The own enumerable properties of `arguments` objects are cloned
13532 * as plain objects. An empty object is returned for uncloneable values such
13533 * as error objects, functions, DOM nodes, and WeakMaps.
13539 * @param {*} value The value to clone.
13540 * @returns {*} Returns the cloned value.
13544 * var objects = [{ 'a': 1 }, { 'b': 2 }];
13546 * var shallow = _.clone(objects);
13547 * console.log(shallow[0] === objects[0]);
13550 function clone(value) {
13551 return baseClone(value, false, true);
13555 * This method is like `_.clone` except that it recursively clones `value`.
13561 * @param {*} value The value to recursively clone.
13562 * @returns {*} Returns the deep cloned value.
13566 * var objects = [{ 'a': 1 }, { 'b': 2 }];
13568 * var deep = _.cloneDeep(objects);
13569 * console.log(deep[0] === objects[0]);
13572 function cloneDeep(value) {
13573 return baseClone(value, true, true);
13578 * [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
13579 * comparison between two values to determine if they are equivalent.
13585 * @param {*} value The value to compare.
13586 * @param {*} other The other value to compare.
13587 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
13590 * var object = { 'user': 'fred' };
13591 * var other = { 'user': 'fred' };
13593 * _.eq(object, object);
13596 * _.eq(object, other);
13602 * _.eq('a', Object('a'));
13608 function eq(value, other) {
13609 return value === other || (value !== value && other !== other);
13613 * Checks if `value` is likely an `arguments` object.
13619 * @param {*} value The value to check.
13620 * @returns {boolean} Returns `true` if `value` is correctly classified,
13624 * _.isArguments(function() { return arguments; }());
13627 * _.isArguments([1, 2, 3]);
13630 function isArguments(value) {
13631 // Safari 8.1 incorrectly makes `arguments.callee` enumerable in strict mode.
13632 return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
13633 (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
13637 * Checks if `value` is classified as an `Array` object.
13644 * @param {*} value The value to check.
13645 * @returns {boolean} Returns `true` if `value` is correctly classified,
13649 * _.isArray([1, 2, 3]);
13652 * _.isArray(document.body.children);
13655 * _.isArray('abc');
13658 * _.isArray(_.noop);
13661 var isArray = Array.isArray;
13664 * Checks if `value` is array-like. A value is considered array-like if it's
13665 * not a function and has a `value.length` that's an integer greater than or
13666 * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
13672 * @param {*} value The value to check.
13673 * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
13676 * _.isArrayLike([1, 2, 3]);
13679 * _.isArrayLike(document.body.children);
13682 * _.isArrayLike('abc');
13685 * _.isArrayLike(_.noop);
13688 function isArrayLike(value) {
13689 return value != null && isLength(getLength(value)) && !isFunction(value);
13693 * This method is like `_.isArrayLike` except that it also checks if `value`
13700 * @param {*} value The value to check.
13701 * @returns {boolean} Returns `true` if `value` is an array-like object,
13705 * _.isArrayLikeObject([1, 2, 3]);
13708 * _.isArrayLikeObject(document.body.children);
13711 * _.isArrayLikeObject('abc');
13714 * _.isArrayLikeObject(_.noop);
13717 function isArrayLikeObject(value) {
13718 return isObjectLike(value) && isArrayLike(value);
13722 * Checks if `value` is a buffer.
13728 * @param {*} value The value to check.
13729 * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
13732 * _.isBuffer(new Buffer(2));
13735 * _.isBuffer(new Uint8Array(2));
13738 var isBuffer = !Buffer ? constant(false) : function(value) {
13739 return value instanceof Buffer;
13743 * Checks if `value` is an empty object, collection, map, or set.
13745 * Objects are considered empty if they have no own enumerable string keyed
13748 * Array-like values such as `arguments` objects, arrays, buffers, strings, or
13749 * jQuery-like collections are considered empty if they have a `length` of `0`.
13750 * Similarly, maps and sets are considered empty if they have a `size` of `0`.
13756 * @param {*} value The value to check.
13757 * @returns {boolean} Returns `true` if `value` is empty, else `false`.
13769 * _.isEmpty([1, 2, 3]);
13772 * _.isEmpty({ 'a': 1 });
13775 function isEmpty(value) {
13776 if (isArrayLike(value) &&
13777 (isArray(value) || isString(value) || isFunction(value.splice) ||
13778 isArguments(value) || isBuffer(value))) {
13779 return !value.length;
13781 if (isObjectLike(value)) {
13782 var tag = getTag(value);
13783 if (tag == mapTag || tag == setTag) {
13784 return !value.size;
13787 for (var key in value) {
13788 if (hasOwnProperty.call(value, key)) {
13792 return !(nonEnumShadows && keys(value).length);
13796 * Performs a deep comparison between two values to determine if they are
13799 * **Note:** This method supports comparing arrays, array buffers, booleans,
13800 * date objects, error objects, maps, numbers, `Object` objects, regexes,
13801 * sets, strings, symbols, and typed arrays. `Object` objects are compared
13802 * by their own, not inherited, enumerable properties. Functions and DOM
13803 * nodes are **not** supported.
13809 * @param {*} value The value to compare.
13810 * @param {*} other The other value to compare.
13811 * @returns {boolean} Returns `true` if the values are equivalent,
13815 * var object = { 'user': 'fred' };
13816 * var other = { 'user': 'fred' };
13818 * _.isEqual(object, other);
13821 * object === other;
13824 function isEqual(value, other) {
13825 return baseIsEqual(value, other);
13829 * Checks if `value` is classified as a `Function` object.
13835 * @param {*} value The value to check.
13836 * @returns {boolean} Returns `true` if `value` is correctly classified,
13843 * _.isFunction(/abc/);
13846 function isFunction(value) {
13847 // The use of `Object#toString` avoids issues with the `typeof` operator
13848 // in Safari 8 which returns 'object' for typed array and weak map constructors,
13849 // and PhantomJS 1.9 which returns 'function' for `NodeList` instances.
13850 var tag = isObject(value) ? objectToString.call(value) : '';
13851 return tag == funcTag || tag == genTag;
13855 * Checks if `value` is a valid array-like length.
13857 * **Note:** This function is loosely based on
13858 * [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
13864 * @param {*} value The value to check.
13865 * @returns {boolean} Returns `true` if `value` is a valid length,
13872 * _.isLength(Number.MIN_VALUE);
13875 * _.isLength(Infinity);
13881 function isLength(value) {
13882 return typeof value == 'number' &&
13883 value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
13887 * Checks if `value` is the
13888 * [language type](http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-language-types)
13889 * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
13895 * @param {*} value The value to check.
13896 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
13902 * _.isObject([1, 2, 3]);
13905 * _.isObject(_.noop);
13908 * _.isObject(null);
13911 function isObject(value) {
13912 var type = typeof value;
13913 return !!value && (type == 'object' || type == 'function');
13917 * Checks if `value` is object-like. A value is object-like if it's not `null`
13918 * and has a `typeof` result of "object".
13924 * @param {*} value The value to check.
13925 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
13928 * _.isObjectLike({});
13931 * _.isObjectLike([1, 2, 3]);
13934 * _.isObjectLike(_.noop);
13937 * _.isObjectLike(null);
13940 function isObjectLike(value) {
13941 return !!value && typeof value == 'object';
13945 * Checks if `value` is a native function.
13951 * @param {*} value The value to check.
13952 * @returns {boolean} Returns `true` if `value` is a native function,
13956 * _.isNative(Array.prototype.push);
13962 function isNative(value) {
13963 if (!isObject(value)) {
13966 var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
13967 return pattern.test(toSource(value));
13971 * Checks if `value` is a plain object, that is, an object created by the
13972 * `Object` constructor or one with a `[[Prototype]]` of `null`.
13978 * @param {*} value The value to check.
13979 * @returns {boolean} Returns `true` if `value` is a plain object,
13987 * _.isPlainObject(new Foo);
13990 * _.isPlainObject([1, 2, 3]);
13993 * _.isPlainObject({ 'x': 0, 'y': 0 });
13996 * _.isPlainObject(Object.create(null));
13999 function isPlainObject(value) {
14000 if (!isObjectLike(value) ||
14001 objectToString.call(value) != objectTag || isHostObject(value)) {
14004 var proto = getPrototype(value);
14005 if (proto === null) {
14008 var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
14009 return (typeof Ctor == 'function' &&
14010 Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);
14014 * Checks if `value` is classified as a `String` primitive or object.
14020 * @param {*} value The value to check.
14021 * @returns {boolean} Returns `true` if `value` is correctly classified,
14025 * _.isString('abc');
14031 function isString(value) {
14032 return typeof value == 'string' ||
14033 (!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag);
14037 * Checks if `value` is classified as a `Symbol` primitive or object.
14043 * @param {*} value The value to check.
14044 * @returns {boolean} Returns `true` if `value` is correctly classified,
14048 * _.isSymbol(Symbol.iterator);
14051 * _.isSymbol('abc');
14054 function isSymbol(value) {
14055 return typeof value == 'symbol' ||
14056 (isObjectLike(value) && objectToString.call(value) == symbolTag);
14060 * Checks if `value` is classified as a typed array.
14066 * @param {*} value The value to check.
14067 * @returns {boolean} Returns `true` if `value` is correctly classified,
14071 * _.isTypedArray(new Uint8Array);
14074 * _.isTypedArray([]);
14077 function isTypedArray(value) {
14078 return isObjectLike(value) &&
14079 isLength(value.length) && !!typedArrayTags[objectToString.call(value)];
14083 * Converts `value` to an array.
14089 * @param {*} value The value to convert.
14090 * @returns {Array} Returns the converted array.
14093 * _.toArray({ 'a': 1, 'b': 2 });
14096 * _.toArray('abc');
14097 * // => ['a', 'b', 'c']
14105 function toArray(value) {
14109 if (isArrayLike(value)) {
14110 return isString(value) ? stringToArray(value) : copyArray(value);
14112 if (iteratorSymbol && value[iteratorSymbol]) {
14113 return iteratorToArray(value[iteratorSymbol]());
14115 var tag = getTag(value),
14116 func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);
14118 return func(value);
14122 * Converts `value` to a finite number.
14128 * @param {*} value The value to convert.
14129 * @returns {number} Returns the converted number.
14135 * _.toFinite(Number.MIN_VALUE);
14138 * _.toFinite(Infinity);
14139 * // => 1.7976931348623157e+308
14141 * _.toFinite('3.2');
14144 function toFinite(value) {
14146 return value === 0 ? value : 0;
14148 value = toNumber(value);
14149 if (value === INFINITY || value === -INFINITY) {
14150 var sign = (value < 0 ? -1 : 1);
14151 return sign * MAX_INTEGER;
14153 return value === value ? value : 0;
14157 * Converts `value` to an integer.
14159 * **Note:** This function is loosely based on
14160 * [`ToInteger`](http://www.ecma-international.org/ecma-262/6.0/#sec-tointeger).
14166 * @param {*} value The value to convert.
14167 * @returns {number} Returns the converted integer.
14170 * _.toInteger(3.2);
14173 * _.toInteger(Number.MIN_VALUE);
14176 * _.toInteger(Infinity);
14177 * // => 1.7976931348623157e+308
14179 * _.toInteger('3.2');
14182 function toInteger(value) {
14183 var result = toFinite(value),
14184 remainder = result % 1;
14186 return result === result ? (remainder ? result - remainder : result) : 0;
14190 * Converts `value` to a number.
14196 * @param {*} value The value to process.
14197 * @returns {number} Returns the number.
14203 * _.toNumber(Number.MIN_VALUE);
14206 * _.toNumber(Infinity);
14209 * _.toNumber('3.2');
14212 function toNumber(value) {
14213 if (typeof value == 'number') {
14216 if (isSymbol(value)) {
14219 if (isObject(value)) {
14220 var other = isFunction(value.valueOf) ? value.valueOf() : value;
14221 value = isObject(other) ? (other + '') : other;
14223 if (typeof value != 'string') {
14224 return value === 0 ? value : +value;
14226 value = value.replace(reTrim, '');
14227 var isBinary = reIsBinary.test(value);
14228 return (isBinary || reIsOctal.test(value))
14229 ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
14230 : (reIsBadHex.test(value) ? NAN : +value);
14234 * Converts `value` to a plain object flattening inherited enumerable string
14235 * keyed properties of `value` to own properties of the plain object.
14241 * @param {*} value The value to convert.
14242 * @returns {Object} Returns the converted plain object.
14249 * Foo.prototype.c = 3;
14251 * _.assign({ 'a': 1 }, new Foo);
14252 * // => { 'a': 1, 'b': 2 }
14254 * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
14255 * // => { 'a': 1, 'b': 2, 'c': 3 }
14257 function toPlainObject(value) {
14258 return copyObject(value, keysIn(value));
14262 * Converts `value` to a string. An empty string is returned for `null`
14263 * and `undefined` values. The sign of `-0` is preserved.
14269 * @param {*} value The value to process.
14270 * @returns {string} Returns the string.
14273 * _.toString(null);
14279 * _.toString([1, 2, 3]);
14282 function toString(value) {
14283 return value == null ? '' : baseToString(value);
14286 /*------------------------------------------------------------------------*/
14289 * Assigns own enumerable string keyed properties of source objects to the
14290 * destination object. Source objects are applied from left to right.
14291 * Subsequent sources overwrite property assignments of previous sources.
14293 * **Note:** This method mutates `object` and is loosely based on
14294 * [`Object.assign`](https://mdn.io/Object/assign).
14300 * @param {Object} object The destination object.
14301 * @param {...Object} [sources] The source objects.
14302 * @returns {Object} Returns `object`.
14314 * Foo.prototype.d = 4;
14315 * Bar.prototype.f = 6;
14317 * _.assign({ 'a': 1 }, new Foo, new Bar);
14318 * // => { 'a': 1, 'c': 3, 'e': 5 }
14320 var assign = createAssigner(function(object, source) {
14321 if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) {
14322 copyObject(source, keys(source), object);
14325 for (var key in source) {
14326 if (hasOwnProperty.call(source, key)) {
14327 assignValue(object, key, source[key]);
14333 * This method is like `_.assign` except that it iterates over own and
14334 * inherited source properties.
14336 * **Note:** This method mutates `object`.
14343 * @param {Object} object The destination object.
14344 * @param {...Object} [sources] The source objects.
14345 * @returns {Object} Returns `object`.
14357 * Foo.prototype.c = 3;
14358 * Bar.prototype.e = 5;
14360 * _.assignIn({ 'a': 1 }, new Foo, new Bar);
14361 * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5 }
14363 var assignIn = createAssigner(function(object, source) {
14364 if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) {
14365 copyObject(source, keysIn(source), object);
14368 for (var key in source) {
14369 assignValue(object, key, source[key]);
14374 * Iterates over own enumerable string keyed properties of an object and
14375 * invokes `iteratee` for each property. The iteratee is invoked with three
14376 * arguments: (value, key, object). Iteratee functions may exit iteration
14377 * early by explicitly returning `false`.
14383 * @param {Object} object The object to iterate over.
14384 * @param {Function} [iteratee=_.identity] The function invoked per iteration.
14385 * @returns {Object} Returns `object`.
14386 * @see _.forOwnRight
14394 * Foo.prototype.c = 3;
14396 * _.forOwn(new Foo, function(value, key) {
14397 * console.log(key);
14399 * // => Logs 'a' then 'b' (iteration order is not guaranteed).
14401 function forOwn(object, iteratee) {
14402 return object && baseForOwn(object, getIteratee(iteratee, 3));
14406 * Gets the value at `path` of `object`. If the resolved value is
14407 * `undefined`, the `defaultValue` is used in its place.
14413 * @param {Object} object The object to query.
14414 * @param {Array|string} path The path of the property to get.
14415 * @param {*} [defaultValue] The value returned for `undefined` resolved values.
14416 * @returns {*} Returns the resolved value.
14419 * var object = { 'a': [{ 'b': { 'c': 3 } }] };
14421 * _.get(object, 'a[0].b.c');
14424 * _.get(object, ['a', '0', 'b', 'c']);
14427 * _.get(object, 'a.b.c', 'default');
14430 function get(object, path, defaultValue) {
14431 var result = object == null ? undefined : baseGet(object, path);
14432 return result === undefined ? defaultValue : result;
14436 * Checks if `path` is a direct or inherited property of `object`.
14442 * @param {Object} object The object to query.
14443 * @param {Array|string} path The path to check.
14444 * @returns {boolean} Returns `true` if `path` exists, else `false`.
14447 * var object = _.create({ 'a': _.create({ 'b': 2 }) });
14449 * _.hasIn(object, 'a');
14452 * _.hasIn(object, 'a.b');
14455 * _.hasIn(object, ['a', 'b']);
14458 * _.hasIn(object, 'b');
14461 function hasIn(object, path) {
14462 return object != null && hasPath(object, path, baseHasIn);
14466 * Creates an array of the own enumerable property names of `object`.
14468 * **Note:** Non-object values are coerced to objects. See the
14469 * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
14470 * for more details.
14476 * @param {Object} object The object to query.
14477 * @returns {Array} Returns the array of property names.
14485 * Foo.prototype.c = 3;
14488 * // => ['a', 'b'] (iteration order is not guaranteed)
14493 function keys(object) {
14494 var isProto = isPrototype(object);
14495 if (!(isProto || isArrayLike(object))) {
14496 return baseKeys(object);
14498 var indexes = indexKeys(object),
14499 skipIndexes = !!indexes,
14500 result = indexes || [],
14501 length = result.length;
14503 for (var key in object) {
14504 if (baseHas(object, key) &&
14505 !(skipIndexes && (key == 'length' || isIndex(key, length))) &&
14506 !(isProto && key == 'constructor')) {
14514 * Creates an array of the own and inherited enumerable property names of `object`.
14516 * **Note:** Non-object values are coerced to objects.
14522 * @param {Object} object The object to query.
14523 * @returns {Array} Returns the array of property names.
14531 * Foo.prototype.c = 3;
14533 * _.keysIn(new Foo);
14534 * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
14536 function keysIn(object) {
14538 isProto = isPrototype(object),
14539 props = baseKeysIn(object),
14540 propsLength = props.length,
14541 indexes = indexKeys(object),
14542 skipIndexes = !!indexes,
14543 result = indexes || [],
14544 length = result.length;
14546 while (++index < propsLength) {
14547 var key = props[index];
14548 if (!(skipIndexes && (key == 'length' || isIndex(key, length))) &&
14549 !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
14557 * This method is like `_.assign` except that it recursively merges own and
14558 * inherited enumerable string keyed properties of source objects into the
14559 * destination object. Source properties that resolve to `undefined` are
14560 * skipped if a destination value exists. Array and plain object properties
14561 * are merged recursively. Other objects and value types are overridden by
14562 * assignment. Source objects are applied from left to right. Subsequent
14563 * sources overwrite property assignments of previous sources.
14565 * **Note:** This method mutates `object`.
14571 * @param {Object} object The destination object.
14572 * @param {...Object} [sources] The source objects.
14573 * @returns {Object} Returns `object`.
14577 * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
14581 * 'data': [{ 'age': 36 }, { 'age': 40 }]
14584 * _.merge(users, ages);
14585 * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
14587 var merge = createAssigner(function(object, source, srcIndex) {
14588 baseMerge(object, source, srcIndex);
14592 * The opposite of `_.pick`; this method creates an object composed of the
14593 * own and inherited enumerable string keyed properties of `object` that are
14600 * @param {Object} object The source object.
14601 * @param {...(string|string[])} [props] The property identifiers to omit.
14602 * @returns {Object} Returns the new object.
14605 * var object = { 'a': 1, 'b': '2', 'c': 3 };
14607 * _.omit(object, ['a', 'c']);
14608 * // => { 'b': '2' }
14610 var omit = rest(function(object, props) {
14611 if (object == null) {
14614 props = arrayMap(baseFlatten(props, 1), toKey);
14615 return basePick(object, baseDifference(getAllKeysIn(object), props));
14619 * Creates an object composed of the picked `object` properties.
14625 * @param {Object} object The source object.
14626 * @param {...(string|string[])} [props] The property identifiers to pick.
14627 * @returns {Object} Returns the new object.
14630 * var object = { 'a': 1, 'b': '2', 'c': 3 };
14632 * _.pick(object, ['a', 'c']);
14633 * // => { 'a': 1, 'c': 3 }
14635 var pick = rest(function(object, props) {
14636 return object == null ? {} : basePick(object, arrayMap(baseFlatten(props, 1), toKey));
14640 * Creates an array of own enumerable string keyed-value pairs for `object`
14641 * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
14642 * entries are returned.
14649 * @param {Object} object The object to query.
14650 * @returns {Array} Returns the key-value pairs.
14658 * Foo.prototype.c = 3;
14660 * _.toPairs(new Foo);
14661 * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
14663 var toPairs = createToPairs(keys);
14666 * Creates an array of the own enumerable string keyed property values of `object`.
14668 * **Note:** Non-object values are coerced to objects.
14674 * @param {Object} object The object to query.
14675 * @returns {Array} Returns the array of property values.
14683 * Foo.prototype.c = 3;
14685 * _.values(new Foo);
14686 * // => [1, 2] (iteration order is not guaranteed)
14691 function values(object) {
14692 return object ? baseValues(object, keys(object)) : [];
14695 /*------------------------------------------------------------------------*/
14698 * Creates a function that returns `value`.
14704 * @param {*} value The value to return from the new function.
14705 * @returns {Function} Returns the new constant function.
14708 * var object = { 'user': 'fred' };
14709 * var getter = _.constant(object);
14711 * getter() === object;
14714 function constant(value) {
14715 return function() {
14721 * This method returns the first argument given to it.
14727 * @param {*} value Any value.
14728 * @returns {*} Returns `value`.
14731 * var object = { 'user': 'fred' };
14733 * _.identity(object) === object;
14736 function identity(value) {
14741 * Creates a function that invokes `func` with the arguments of the created
14742 * function. If `func` is a property name, the created function returns the
14743 * property value for a given element. If `func` is an array or object, the
14744 * created function returns `true` for elements that contain the equivalent
14745 * source properties, otherwise it returns `false`.
14751 * @param {*} [func=_.identity] The value to convert to a callback.
14752 * @returns {Function} Returns the callback.
14756 * { 'user': 'barney', 'age': 36, 'active': true },
14757 * { 'user': 'fred', 'age': 40, 'active': false }
14760 * // The `_.matches` iteratee shorthand.
14761 * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
14762 * // => [{ 'user': 'barney', 'age': 36, 'active': true }]
14764 * // The `_.matchesProperty` iteratee shorthand.
14765 * _.filter(users, _.iteratee(['user', 'fred']));
14766 * // => [{ 'user': 'fred', 'age': 40 }]
14768 * // The `_.property` iteratee shorthand.
14769 * _.map(users, _.iteratee('user'));
14770 * // => ['barney', 'fred']
14772 * // Create custom iteratee shorthands.
14773 * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
14774 * return !_.isRegExp(func) ? iteratee(func) : function(string) {
14775 * return func.test(string);
14779 * _.filter(['abc', 'def'], /ef/);
14782 function iteratee(func) {
14783 return baseIteratee(typeof func == 'function' ? func : baseClone(func, true));
14787 * Adds all own enumerable string keyed function properties of a source
14788 * object to the destination object. If `object` is a function, then methods
14789 * are added to its prototype as well.
14791 * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
14792 * avoid conflicts caused by modifying the original.
14798 * @param {Function|Object} [object=lodash] The destination object.
14799 * @param {Object} source The object of functions to add.
14800 * @param {Object} [options={}] The options object.
14801 * @param {boolean} [options.chain=true] Specify whether mixins are chainable.
14802 * @returns {Function|Object} Returns `object`.
14805 * function vowels(string) {
14806 * return _.filter(string, function(v) {
14807 * return /[aeiou]/i.test(v);
14811 * _.mixin({ 'vowels': vowels });
14812 * _.vowels('fred');
14815 * _('fred').vowels().value();
14818 * _.mixin({ 'vowels': vowels }, { 'chain': false });
14819 * _('fred').vowels();
14822 function mixin(object, source, options) {
14823 var props = keys(source),
14824 methodNames = baseFunctions(source, props);
14826 if (options == null &&
14827 !(isObject(source) && (methodNames.length || !props.length))) {
14831 methodNames = baseFunctions(source, keys(source));
14833 var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
14834 isFunc = isFunction(object);
14836 arrayEach(methodNames, function(methodName) {
14837 var func = source[methodName];
14838 object[methodName] = func;
14840 object.prototype[methodName] = function() {
14841 var chainAll = this.__chain__;
14842 if (chain || chainAll) {
14843 var result = object(this.__wrapped__),
14844 actions = result.__actions__ = copyArray(this.__actions__);
14846 actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
14847 result.__chain__ = chainAll;
14850 return func.apply(object, arrayPush([this.value()], arguments));
14859 * A no-operation function that returns `undefined` regardless of the
14860 * arguments it receives.
14868 * var object = { 'user': 'fred' };
14870 * _.noop(object) === undefined;
14874 // No operation performed.
14878 * Creates a function that returns the value at `path` of a given object.
14884 * @param {Array|string} path The path of the property to get.
14885 * @returns {Function} Returns the new accessor function.
14889 * { 'a': { 'b': 2 } },
14890 * { 'a': { 'b': 1 } }
14893 * _.map(objects, _.property('a.b'));
14896 * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
14899 function property(path) {
14900 return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
14903 /*------------------------------------------------------------------------*/
14905 // Add methods that return wrapped values in chain sequences.
14906 lodash.assign = assign;
14907 lodash.assignIn = assignIn;
14908 lodash.bind = bind;
14909 lodash.chain = chain;
14910 lodash.chunk = chunk;
14911 lodash.compact = compact;
14912 lodash.constant = constant;
14913 lodash.debounce = debounce;
14914 lodash.difference = difference;
14915 lodash.filter = filter;
14916 lodash.flatten = flatten;
14917 lodash.groupBy = groupBy;
14918 lodash.intersection = intersection;
14919 lodash.iteratee = iteratee;
14920 lodash.keys = keys;
14921 lodash.keysIn = keysIn;
14923 lodash.memoize = memoize;
14924 lodash.merge = merge;
14925 lodash.mixin = mixin;
14926 lodash.omit = omit;
14927 lodash.pick = pick;
14928 lodash.property = property;
14929 lodash.reject = reject;
14930 lodash.rest = rest;
14931 lodash.reverse = reverse;
14933 lodash.throttle = throttle;
14934 lodash.thru = thru;
14935 lodash.toArray = toArray;
14936 lodash.toPairs = toPairs;
14937 lodash.toPlainObject = toPlainObject;
14938 lodash.union = union;
14939 lodash.uniq = uniq;
14940 lodash.values = values;
14941 lodash.without = without;
14944 lodash.entries = toPairs;
14945 lodash.extend = assignIn;
14947 // Add methods to `lodash.prototype`.
14948 mixin(lodash, lodash);
14950 /*------------------------------------------------------------------------*/
14952 // Add methods that return unwrapped values in chain sequences.
14953 lodash.clone = clone;
14954 lodash.cloneDeep = cloneDeep;
14956 lodash.every = every;
14957 lodash.find = find;
14958 lodash.forEach = forEach;
14959 lodash.forOwn = forOwn;
14961 lodash.hasIn = hasIn;
14962 lodash.head = head;
14963 lodash.identity = identity;
14964 lodash.includes = includes;
14965 lodash.indexOf = indexOf;
14966 lodash.isArguments = isArguments;
14967 lodash.isArray = isArray;
14968 lodash.isArrayLike = isArrayLike;
14969 lodash.isArrayLikeObject = isArrayLikeObject;
14970 lodash.isBuffer = isBuffer;
14971 lodash.isEmpty = isEmpty;
14972 lodash.isEqual = isEqual;
14973 lodash.isFunction = isFunction;
14974 lodash.isLength = isLength;
14975 lodash.isNative = isNative;
14976 lodash.isObject = isObject;
14977 lodash.isObjectLike = isObjectLike;
14978 lodash.isPlainObject = isPlainObject;
14979 lodash.isString = isString;
14980 lodash.isSymbol = isSymbol;
14981 lodash.isTypedArray = isTypedArray;
14982 lodash.last = last;
14983 lodash.noop = noop;
14985 lodash.reduce = reduce;
14986 lodash.some = some;
14987 lodash.toFinite = toFinite;
14988 lodash.toInteger = toInteger;
14989 lodash.toNumber = toNumber;
14990 lodash.toString = toString;
14993 lodash.each = forEach;
14994 lodash.first = head;
14996 mixin(lodash, (function() {
14998 baseForOwn(lodash, function(func, methodName) {
14999 if (!hasOwnProperty.call(lodash.prototype, methodName)) {
15000 source[methodName] = func;
15004 }()), { 'chain': false });
15006 /*------------------------------------------------------------------------*/
15009 * The semantic version number.
15015 lodash.VERSION = VERSION;
15017 // Assign default placeholders.
15018 bind.placeholder = lodash;
15020 // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
15021 arrayEach(['drop', 'take'], function(methodName, index) {
15022 LazyWrapper.prototype[methodName] = function(n) {
15023 var filtered = this.__filtered__;
15024 if (filtered && !index) {
15025 return new LazyWrapper(this);
15027 n = n === undefined ? 1 : nativeMax(toInteger(n), 0);
15029 var result = this.clone();
15031 result.__takeCount__ = nativeMin(n, result.__takeCount__);
15033 result.__views__.push({
15034 'size': nativeMin(n, MAX_ARRAY_LENGTH),
15035 'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
15041 LazyWrapper.prototype[methodName + 'Right'] = function(n) {
15042 return this.reverse()[methodName](n).reverse();
15046 // Add `LazyWrapper` methods that accept an `iteratee` value.
15047 arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
15048 var type = index + 1,
15049 isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;
15051 LazyWrapper.prototype[methodName] = function(iteratee) {
15052 var result = this.clone();
15053 result.__iteratees__.push({
15054 'iteratee': getIteratee(iteratee, 3),
15057 result.__filtered__ = result.__filtered__ || isFilter;
15062 // Add `LazyWrapper` methods for `_.head` and `_.last`.
15063 arrayEach(['head', 'last'], function(methodName, index) {
15064 var takeName = 'take' + (index ? 'Right' : '');
15066 LazyWrapper.prototype[methodName] = function() {
15067 return this[takeName](1).value()[0];
15071 // Add `LazyWrapper` methods for `_.initial` and `_.tail`.
15072 arrayEach(['initial', 'tail'], function(methodName, index) {
15073 var dropName = 'drop' + (index ? '' : 'Right');
15075 LazyWrapper.prototype[methodName] = function() {
15076 return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
15080 LazyWrapper.prototype.compact = function() {
15081 return this.filter(identity);
15084 LazyWrapper.prototype.find = function(predicate) {
15085 return this.filter(predicate).head();
15088 LazyWrapper.prototype.findLast = function(predicate) {
15089 return this.reverse().find(predicate);
15092 LazyWrapper.prototype.invokeMap = rest(function(path, args) {
15093 if (typeof path == 'function') {
15094 return new LazyWrapper(this);
15096 return this.map(function(value) {
15097 return baseInvoke(value, path, args);
15101 LazyWrapper.prototype.reject = function(predicate) {
15102 predicate = getIteratee(predicate, 3);
15103 return this.filter(function(value) {
15104 return !predicate(value);
15108 LazyWrapper.prototype.slice = function(start, end) {
15109 start = toInteger(start);
15112 if (result.__filtered__ && (start > 0 || end < 0)) {
15113 return new LazyWrapper(result);
15116 result = result.takeRight(-start);
15117 } else if (start) {
15118 result = result.drop(start);
15120 if (end !== undefined) {
15121 end = toInteger(end);
15122 result = end < 0 ? result.dropRight(-end) : result.take(end - start);
15127 LazyWrapper.prototype.takeRightWhile = function(predicate) {
15128 return this.reverse().takeWhile(predicate).reverse();
15131 LazyWrapper.prototype.toArray = function() {
15132 return this.take(MAX_ARRAY_LENGTH);
15135 // Add `LazyWrapper` methods to `lodash.prototype`.
15136 baseForOwn(LazyWrapper.prototype, function(func, methodName) {
15137 var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
15138 isTaker = /^(?:head|last)$/.test(methodName),
15139 lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
15140 retUnwrapped = isTaker || /^find/.test(methodName);
15145 lodash.prototype[methodName] = function() {
15146 var value = this.__wrapped__,
15147 args = isTaker ? [1] : arguments,
15148 isLazy = value instanceof LazyWrapper,
15149 iteratee = args[0],
15150 useLazy = isLazy || isArray(value);
15152 var interceptor = function(value) {
15153 var result = lodashFunc.apply(lodash, arrayPush([value], args));
15154 return (isTaker && chainAll) ? result[0] : result;
15157 if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
15158 // Avoid lazy use if the iteratee has a "length" value other than `1`.
15159 isLazy = useLazy = false;
15161 var chainAll = this.__chain__,
15162 isHybrid = !!this.__actions__.length,
15163 isUnwrapped = retUnwrapped && !chainAll,
15164 onlyLazy = isLazy && !isHybrid;
15166 if (!retUnwrapped && useLazy) {
15167 value = onlyLazy ? value : new LazyWrapper(this);
15168 var result = func.apply(value, args);
15169 result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
15170 return new LodashWrapper(result, chainAll);
15172 if (isUnwrapped && onlyLazy) {
15173 return func.apply(this, args);
15175 result = this.thru(interceptor);
15176 return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
15180 // Add `Array` methods to `lodash.prototype`.
15181 arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
15182 var func = arrayProto[methodName],
15183 chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
15184 retUnwrapped = /^(?:pop|shift)$/.test(methodName);
15186 lodash.prototype[methodName] = function() {
15187 var args = arguments;
15188 if (retUnwrapped && !this.__chain__) {
15189 var value = this.value();
15190 return func.apply(isArray(value) ? value : [], args);
15192 return this[chainName](function(value) {
15193 return func.apply(isArray(value) ? value : [], args);
15198 // Map minified method names to their real names.
15199 baseForOwn(LazyWrapper.prototype, function(func, methodName) {
15200 var lodashFunc = lodash[methodName];
15202 var key = (lodashFunc.name + ''),
15203 names = realNames[key] || (realNames[key] = []);
15205 names.push({ 'name': methodName, 'func': lodashFunc });
15209 realNames[createHybridWrapper(undefined, BIND_KEY_FLAG).name] = [{
15214 // Add methods to `LazyWrapper`.
15215 LazyWrapper.prototype.clone = lazyClone;
15216 LazyWrapper.prototype.reverse = lazyReverse;
15217 LazyWrapper.prototype.value = lazyValue;
15219 // Add chain sequence methods to the `lodash` wrapper.
15220 lodash.prototype.chain = wrapperChain;
15221 lodash.prototype.commit = wrapperCommit;
15222 lodash.prototype.next = wrapperNext;
15223 lodash.prototype.plant = wrapperPlant;
15224 lodash.prototype.reverse = wrapperReverse;
15225 lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
15227 if (iteratorSymbol) {
15228 lodash.prototype[iteratorSymbol] = wrapperToIterator;
15231 /*--------------------------------------------------------------------------*/
15233 // Expose Lodash on the free variable `window` or `self` when available so it's
15234 // globally accessible, even when bundled with Browserify, Webpack, etc. This
15235 // also prevents errors in cases where Lodash is loaded by a script tag in the
15236 // presence of an AMD loader. See http://requirejs.org/docs/errors.html#mismatch
15237 // for more details. Use `_.noConflict` to remove Lodash from the global object.
15238 (freeWindow || freeSelf || {})._ = lodash;
15240 if (freeExports && freeModule) {
15241 // Export for Node.js.
15242 if (moduleExports) {
15243 (freeModule.exports = lodash)._ = lodash;
15245 // Export for CommonJS support.
15246 freeExports._ = lodash;
15249 // Export to the global object.
15253 (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;
15254 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){
15257 var ohauth = require('ohauth'),
15258 xtend = require('xtend'),
15259 store = require('store');
15263 // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
15264 // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
15265 // does not support custom headers, which this uses everywhere.
15266 module.exports = function(o) {
15270 // authenticated users will also have a request token secret, but it's
15271 // not used in transactions with the server
15272 oauth.authenticated = function() {
15273 return !!(token('oauth_token') && token('oauth_token_secret'));
15276 oauth.logout = function() {
15277 token('oauth_token', '');
15278 token('oauth_token_secret', '');
15279 token('oauth_request_token_secret', '');
15283 // TODO: detect lack of click event
15284 oauth.authenticate = function(callback) {
15285 if (oauth.authenticated()) return callback();
15289 // ## Getting a request token
15290 var params = timenonce(getAuth(o)),
15291 url = o.url + '/oauth/request_token',
15294 params.oauth_signature = ohauth.signature(
15295 o.oauth_secret, '',
15296 ohauth.baseString('POST', url, params));
15298 if (!o.singlepage) {
15299 // Create a 600x550 popup window in the center of the screen
15300 var w = 600, h = 550,
15302 ['width', w], ['height', h],
15303 ['left', screen.width / 2 - w / 2],
15304 ['top', screen.height / 2 - h / 2]].map(function(x) {
15305 return x.join('=');
15307 popup = window.open('about:blank', 'oauth_window', settings);
15310 timer = setInterval(function() {
15311 if (popup.closed) {
15313 clearInterval(timer);
15314 callback('not authenticated', null);
15319 // Request a request token. When this is complete, the popup
15320 // window is redirected to OSM's authorization page.
15321 ohauth.xhr('POST', url, params, null, {}, reqTokenDone);
15324 function reqTokenDone(err, xhr) {
15327 if (timer) clearInterval(timer);
15328 return callback(err);
15330 var resp = ohauth.stringQs(xhr.response);
15331 token('oauth_request_token_secret', resp.oauth_token_secret);
15332 var authorize_url = o.url + '/oauth/authorize?' + ohauth.qsString({
15333 oauth_token: resp.oauth_token,
15334 oauth_callback: location.href.replace('index.html', '')
15335 .replace(/#.*/, '') + o.landing
15338 if (o.singlepage) {
15339 location.href = authorize_url;
15341 popup.location = authorize_url;
15345 // Called by a function in a landing page, in the popup window. The
15346 // window closes itself.
15347 window.authComplete = function(token) {
15348 if (timer) clearInterval(timer);
15349 var oauth_token = ohauth.stringQs(token.split('?')[1]);
15350 get_access_token(oauth_token.oauth_token);
15351 delete window.authComplete;
15354 // ## Getting an request token
15356 // At this point we have an `oauth_token`, brought in from a function
15357 // call on a landing page popup.
15358 function get_access_token(oauth_token) {
15359 var url = o.url + '/oauth/access_token',
15360 params = timenonce(getAuth(o)),
15361 request_token_secret = token('oauth_request_token_secret');
15362 params.oauth_token = oauth_token;
15363 params.oauth_signature = ohauth.signature(
15365 request_token_secret,
15366 ohauth.baseString('POST', url, params));
15368 // ## Getting an access token
15370 // The final token required for authentication. At this point
15371 // we have a `request token secret`
15372 ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
15376 function accessTokenDone(err, xhr) {
15378 if (timer) clearInterval(timer);
15379 if (err) return callback(err);
15380 var access_token = ohauth.stringQs(xhr.response);
15381 token('oauth_token', access_token.oauth_token);
15382 token('oauth_token_secret', access_token.oauth_token_secret);
15383 callback(null, oauth);
15387 oauth.bootstrapToken = function(oauth_token, callback) {
15388 // ## Getting an request token
15389 // At this point we have an `oauth_token`, brought in from a function
15390 // call on a landing page popup.
15391 function get_access_token(oauth_token) {
15392 var url = o.url + '/oauth/access_token',
15393 params = timenonce(getAuth(o)),
15394 request_token_secret = token('oauth_request_token_secret');
15395 params.oauth_token = oauth_token;
15396 params.oauth_signature = ohauth.signature(
15398 request_token_secret,
15399 ohauth.baseString('POST', url, params));
15401 // ## Getting an access token
15402 // The final token required for authentication. At this point
15403 // we have a `request token secret`
15404 ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
15408 function accessTokenDone(err, xhr) {
15410 if (err) return callback(err);
15411 var access_token = ohauth.stringQs(xhr.response);
15412 token('oauth_token', access_token.oauth_token);
15413 token('oauth_token_secret', access_token.oauth_token_secret);
15414 callback(null, oauth);
15417 get_access_token(oauth_token);
15422 // A single XMLHttpRequest wrapper that does authenticated calls if the
15423 // user has logged in.
15424 oauth.xhr = function(options, callback) {
15425 if (!oauth.authenticated()) {
15426 if (o.auto) return oauth.authenticate(run);
15427 else return callback('not authenticated', null);
15428 } else return run();
15431 var params = timenonce(getAuth(o)),
15432 url = o.url + options.path,
15433 oauth_token_secret = token('oauth_token_secret');
15435 // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
15436 if ((!options.options || !options.options.header ||
15437 options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') &&
15439 params = xtend(params, ohauth.stringQs(options.content));
15442 params.oauth_token = token('oauth_token');
15443 params.oauth_signature = ohauth.signature(
15445 oauth_token_secret,
15446 ohauth.baseString(options.method, url, params));
15448 ohauth.xhr(options.method,
15449 url, params, options.content, options.options, done);
15452 function done(err, xhr) {
15453 if (err) return callback(err);
15454 else if (xhr.responseXML) return callback(err, xhr.responseXML);
15455 else return callback(err, xhr.response);
15459 // pre-authorize this object, if we can just get a token and token_secret
15461 oauth.preauth = function(c) {
15463 if (c.oauth_token) token('oauth_token', c.oauth_token);
15464 if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
15468 oauth.options = function(_) {
15469 if (!arguments.length) return o;
15473 o.url = o.url || 'http://www.openstreetmap.org';
15474 o.landing = o.landing || 'land.html';
15476 o.singlepage = o.singlepage || false;
15478 // Optional loading and loading-done functions for nice UI feedback.
15479 // by default, no-ops
15480 o.loading = o.loading || function() {};
15481 o.done = o.done || function() {};
15483 return oauth.preauth(o);
15486 // 'stamp' an authentication object from `getAuth()`
15487 // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
15489 function timenonce(o) {
15490 o.oauth_timestamp = ohauth.timestamp();
15491 o.oauth_nonce = ohauth.nonce();
15495 // get/set tokens. These are prefixed with the base URL so that `osm-auth`
15496 // can be used with multiple APIs and the keys in `localStorage`
15500 if (store.enabled) {
15501 token = function (x, y) {
15502 if (arguments.length === 1) return store.get(o.url + x);
15503 else if (arguments.length === 2) return store.set(o.url + x, y);
15507 token = function (x, y) {
15508 if (arguments.length === 1) return storage[o.url + x];
15509 else if (arguments.length === 2) return storage[o.url + x] = y;
15513 // Get an authentication object. If you just add and remove properties
15514 // from a single object, you'll need to use `delete` to make sure that
15515 // it doesn't contain undesired properties for authentication
15516 function getAuth(o) {
15518 oauth_consumer_key: o.oauth_consumer_key,
15519 oauth_signature_method: "HMAC-SHA1"
15523 // potentially pre-authorize
15529 },{"ohauth":2,"store":3,"xtend":4}],3:[function(require,module,exports){
15530 (function(global){;(function(win){
15532 doc = win.document,
15533 localStorageName = 'localStorage',
15536 store.disabled = false
15537 store.set = function(key, value) {}
15538 store.get = function(key) {}
15539 store.remove = function(key) {}
15540 store.clear = function() {}
15541 store.transact = function(key, defaultVal, transactionFn) {
15542 var val = store.get(key)
15543 if (transactionFn == null) {
15544 transactionFn = defaultVal
15547 if (typeof val == 'undefined') { val = defaultVal || {} }
15549 store.set(key, val)
15551 store.getAll = function() {}
15552 store.forEach = function() {}
15554 store.serialize = function(value) {
15555 return JSON.stringify(value)
15557 store.deserialize = function(value) {
15558 if (typeof value != 'string') { return undefined }
15559 try { return JSON.parse(value) }
15560 catch(e) { return value || undefined }
15563 // Functions to encapsulate questionable FireFox 3.6.13 behavior
15564 // when about.config::dom.storage.enabled === false
15565 // See https://github.com/marcuswestin/store.js/issues#issue/13
15566 function isLocalStorageNameSupported() {
15567 try { return (localStorageName in win && win[localStorageName]) }
15568 catch(err) { return false }
15571 if (isLocalStorageNameSupported()) {
15572 storage = win[localStorageName]
15573 store.set = function(key, val) {
15574 if (val === undefined) { return store.remove(key) }
15575 storage.setItem(key, store.serialize(val))
15578 store.get = function(key) { return store.deserialize(storage.getItem(key)) }
15579 store.remove = function(key) { storage.removeItem(key) }
15580 store.clear = function() { storage.clear() }
15581 store.getAll = function() {
15583 store.forEach(function(key, val) {
15588 store.forEach = function(callback) {
15589 for (var i=0; i<storage.length; i++) {
15590 var key = storage.key(i)
15591 callback(key, store.get(key))
15594 } else if (doc.documentElement.addBehavior) {
15597 // Since #userData storage applies only to specific paths, we need to
15598 // somehow link our data to a specific path. We choose /favicon.ico
15599 // as a pretty safe option, since all browsers already make a request to
15600 // this URL anyway and being a 404 will not hurt us here. We wrap an
15601 // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
15602 // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
15603 // since the iframe access rules appear to allow direct access and
15604 // manipulation of the document element, even for a 404 page. This
15605 // document can be used instead of the current document (which would
15606 // have been limited to the current path) to perform #userData storage.
15608 storageContainer = new ActiveXObject('htmlfile')
15609 storageContainer.open()
15610 storageContainer.write('<s' + 'cript>document.w=window</s' + 'cript><iframe src="/favicon.ico"></iframe>')
15611 storageContainer.close()
15612 storageOwner = storageContainer.w.frames[0].document
15613 storage = storageOwner.createElement('div')
15615 // somehow ActiveXObject instantiation failed (perhaps some special
15616 // security settings or otherwse), fall back to per-path storage
15617 storage = doc.createElement('div')
15618 storageOwner = doc.body
15620 function withIEStorage(storeFunction) {
15621 return function() {
15622 var args = Array.prototype.slice.call(arguments, 0)
15623 args.unshift(storage)
15624 // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
15625 // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
15626 storageOwner.appendChild(storage)
15627 storage.addBehavior('#default#userData')
15628 storage.load(localStorageName)
15629 var result = storeFunction.apply(store, args)
15630 storageOwner.removeChild(storage)
15635 // In IE7, keys may not contain special chars. See all of https://github.com/marcuswestin/store.js/issues/40
15636 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g")
15637 function ieKeyFix(key) {
15638 return key.replace(forbiddenCharsRegex, '___')
15640 store.set = withIEStorage(function(storage, key, val) {
15641 key = ieKeyFix(key)
15642 if (val === undefined) { return store.remove(key) }
15643 storage.setAttribute(key, store.serialize(val))
15644 storage.save(localStorageName)
15647 store.get = withIEStorage(function(storage, key) {
15648 key = ieKeyFix(key)
15649 return store.deserialize(storage.getAttribute(key))
15651 store.remove = withIEStorage(function(storage, key) {
15652 key = ieKeyFix(key)
15653 storage.removeAttribute(key)
15654 storage.save(localStorageName)
15656 store.clear = withIEStorage(function(storage) {
15657 var attributes = storage.XMLDocument.documentElement.attributes
15658 storage.load(localStorageName)
15659 for (var i=0, attr; attr=attributes[i]; i++) {
15660 storage.removeAttribute(attr.name)
15662 storage.save(localStorageName)
15664 store.getAll = function(storage) {
15666 store.forEach(function(key, val) {
15671 store.forEach = withIEStorage(function(storage, callback) {
15672 var attributes = storage.XMLDocument.documentElement.attributes
15673 for (var i=0, attr; attr=attributes[i]; ++i) {
15674 callback(attr.name, store.deserialize(storage.getAttribute(attr.name)))
15680 var testKey = '__storejs__'
15681 store.set(testKey, testKey)
15682 if (store.get(testKey) != testKey) { store.disabled = true }
15683 store.remove(testKey)
15685 store.disabled = true
15687 store.enabled = !store.disabled
15689 if (typeof module != 'undefined' && module.exports) { module.exports = store }
15690 else if (typeof define === 'function' && define.amd) { define(store) }
15691 else { win.store = store }
15693 })(this.window || global);
15696 },{}],5:[function(require,module,exports){
15697 module.exports = hasKeys
15699 function hasKeys(source) {
15700 return source !== null &&
15701 (typeof source === "object" ||
15702 typeof source === "function")
15705 },{}],4:[function(require,module,exports){
15706 var Keys = require("object-keys")
15707 var hasKeys = require("./has-keys")
15709 module.exports = extend
15711 function extend() {
15714 for (var i = 0; i < arguments.length; i++) {
15715 var source = arguments[i]
15717 if (!hasKeys(source)) {
15721 var keys = Keys(source)
15723 for (var j = 0; j < keys.length; j++) {
15725 target[name] = source[name]
15732 },{"./has-keys":5,"object-keys":6}],7:[function(require,module,exports){
15733 (function(global){/**
15734 * jsHashes - A fast and independent hashing library pure JavaScript implemented (ES3 compliant) for both server and client side
15737 * @author Tomas Aparicio <tomas@rijndael-project.com>
15738 * @license New BSD (see LICENSE file)
15741 * Algorithms specification:
15743 * MD5 <http://www.ietf.org/rfc/rfc1321.txt>
15744 * RIPEMD-160 <http://homes.esat.kuleuven.be/~bosselae/ripemd160.html>
15745 * SHA1 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
15746 * SHA256 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
15747 * SHA512 <http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf>
15748 * HMAC <http://www.ietf.org/rfc/rfc2104.txt>
15754 // private helper methods
15755 function utf8Encode(str) {
15756 var x, y, output = '', i = -1, l;
15758 if (str && str.length) {
15760 while ((i+=1) < l) {
15761 /* Decode utf-16 surrogate pairs */
15762 x = str.charCodeAt(i);
15763 y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
15764 if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
15765 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
15768 /* Encode output as utf-8 */
15770 output += String.fromCharCode(x);
15771 } else if (x <= 0x7FF) {
15772 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
15773 0x80 | ( x & 0x3F));
15774 } else if (x <= 0xFFFF) {
15775 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
15776 0x80 | ((x >>> 6 ) & 0x3F),
15777 0x80 | ( x & 0x3F));
15778 } else if (x <= 0x1FFFFF) {
15779 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
15780 0x80 | ((x >>> 12) & 0x3F),
15781 0x80 | ((x >>> 6 ) & 0x3F),
15782 0x80 | ( x & 0x3F));
15789 function utf8Decode(str) {
15790 var i, ac, c1, c2, c3, arr = [], l;
15791 i = ac = c1 = c2 = c3 = 0;
15793 if (str && str.length) {
15798 c1 = str.charCodeAt(i);
15801 arr[ac] = String.fromCharCode(c1);
15803 } else if (c1 > 191 && c1 < 224) {
15804 c2 = str.charCodeAt(i + 1);
15805 arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
15808 c2 = str.charCodeAt(i + 1);
15809 c3 = str.charCodeAt(i + 2);
15810 arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
15815 return arr.join('');
15819 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
15820 * to work around bugs in some JS interpreters.
15822 function safe_add(x, y) {
15823 var lsw = (x & 0xFFFF) + (y & 0xFFFF),
15824 msw = (x >> 16) + (y >> 16) + (lsw >> 16);
15825 return (msw << 16) | (lsw & 0xFFFF);
15829 * Bitwise rotate a 32-bit number to the left.
15831 function bit_rol(num, cnt) {
15832 return (num << cnt) | (num >>> (32 - cnt));
15836 * Convert a raw string to a hex string
15838 function rstr2hex(input, hexcase) {
15839 var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
15840 output = '', x, i = 0, l = input.length;
15841 for (; i < l; i+=1) {
15842 x = input.charCodeAt(i);
15843 output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F);
15849 * Encode a string as utf-16
15851 function str2rstr_utf16le(input) {
15852 var i, l = input.length, output = '';
15853 for (i = 0; i < l; i+=1) {
15854 output += String.fromCharCode( input.charCodeAt(i) & 0xFF, (input.charCodeAt(i) >>> 8) & 0xFF);
15859 function str2rstr_utf16be(input) {
15860 var i, l = input.length, output = '';
15861 for (i = 0; i < l; i+=1) {
15862 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, input.charCodeAt(i) & 0xFF);
15868 * Convert an array of big-endian words to a string
15870 function binb2rstr(input) {
15871 var i, l = input.length * 32, output = '';
15872 for (i = 0; i < l; i += 8) {
15873 output += String.fromCharCode((input[i>>5] >>> (24 - i % 32)) & 0xFF);
15879 * Convert an array of little-endian words to a string
15881 function binl2rstr(input) {
15882 var i, l = input.length * 32, output = '';
15883 for (i = 0;i < l; i += 8) {
15884 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
15890 * Convert a raw string to an array of little-endian words
15891 * Characters >255 have their high-byte silently ignored.
15893 function rstr2binl(input) {
15894 var i, l = input.length * 8, output = Array(input.length >> 2), lo = output.length;
15895 for (i = 0; i < lo; i+=1) {
15898 for (i = 0; i < l; i += 8) {
15899 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
15905 * Convert a raw string to an array of big-endian words
15906 * Characters >255 have their high-byte silently ignored.
15908 function rstr2binb(input) {
15909 var i, l = input.length * 8, output = Array(input.length >> 2), lo = output.length;
15910 for (i = 0; i < lo; i+=1) {
15913 for (i = 0; i < l; i += 8) {
15914 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
15920 * Convert a raw string to an arbitrary string encoding
15922 function rstr2any(input, encoding) {
15923 var divisor = encoding.length,
15924 remainders = Array(),
15925 i, q, x, ld, quotient, dividend, output, full_length;
15927 /* Convert to an array of 16-bit big-endian values, forming the dividend */
15928 dividend = Array(Math.ceil(input.length / 2));
15929 ld = dividend.length;
15930 for (i = 0; i < ld; i+=1) {
15931 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
15935 * Repeatedly perform a long division. The binary array forms the dividend,
15936 * the length of the encoding is the divisor. Once computed, the quotient
15937 * forms the dividend for the next step. We stop when the dividend is zerHashes.
15938 * All remainders are stored for later use.
15940 while(dividend.length > 0) {
15941 quotient = Array();
15943 for (i = 0; i < dividend.length; i+=1) {
15944 x = (x << 16) + dividend[i];
15945 q = Math.floor(x / divisor);
15947 if (quotient.length > 0 || q > 0) {
15948 quotient[quotient.length] = q;
15951 remainders[remainders.length] = x;
15952 dividend = quotient;
15955 /* Convert the remainders to the output string */
15957 for (i = remainders.length - 1; i >= 0; i--) {
15958 output += encoding.charAt(remainders[i]);
15961 /* Append leading zero equivalents */
15962 full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
15963 for (i = output.length; i < full_length; i+=1) {
15964 output = encoding[0] + output;
15970 * Convert a raw string to a base-64 string
15972 function rstr2b64(input, b64pad) {
15973 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
15975 len = input.length, i, j, triplet;
15976 b64pad= b64pad || '=';
15977 for (i = 0; i < len; i += 3) {
15978 triplet = (input.charCodeAt(i) << 16)
15979 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
15980 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
15981 for (j = 0; j < 4; j+=1) {
15982 if (i * 8 + j * 6 > input.length * 8) {
15985 output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
15994 * @property {String} version
16003 Base64 : function () {
16004 // private properties
16005 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
16006 pad = '=', // default pad according with the RFC standard
16007 url = false, // URL encoding support @todo
16008 utf8 = true; // by default enable UTF-8 support encoding
16010 // public method for encoding
16011 this.encode = function (input) {
16014 len = input.length;
16017 input = (utf8) ? utf8Encode(input) : input;
16019 for (i = 0; i < len; i += 3) {
16020 triplet = (input.charCodeAt(i) << 16)
16021 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
16022 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
16023 for (j = 0; j < 4; j+=1) {
16024 if (i * 8 + j * 6 > len * 8) {
16027 output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
16034 // public method for decoding
16035 this.decode = function (input) {
16036 // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
16037 var i, o1, o2, o3, h1, h2, h3, h4, bits, ac,
16040 if (!input) { return input; }
16043 input = input.replace(new RegExp('\\'+pad,'gi'),''); // use '='
16046 do { // unpack four hexets into three octets using index points in b64
16047 h1 = tab.indexOf(input.charAt(i+=1));
16048 h2 = tab.indexOf(input.charAt(i+=1));
16049 h3 = tab.indexOf(input.charAt(i+=1));
16050 h4 = tab.indexOf(input.charAt(i+=1));
16052 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
16054 o1 = bits >> 16 & 0xff;
16055 o2 = bits >> 8 & 0xff;
16060 arr[ac] = String.fromCharCode(o1);
16061 } else if (h4 === 64) {
16062 arr[ac] = String.fromCharCode(o1, o2);
16064 arr[ac] = String.fromCharCode(o1, o2, o3);
16066 } while (i < input.length);
16068 dec = arr.join('');
16069 dec = (utf8) ? utf8Decode(dec) : dec;
16074 // set custom pad string
16075 this.setPad = function (str) {
16079 // set custom tab string characters
16080 this.setTab = function (str) {
16084 this.setUTF8 = function (bool) {
16085 if (typeof bool === 'boolean') {
16093 * CRC-32 calculation
16097 * @param {String} str Input String
16100 CRC32 : function (str) {
16101 var crc = 0, x = 0, y = 0, table, i, iTop;
16102 str = utf8Encode(str);
16105 '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ',
16106 '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ',
16107 '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ',
16108 '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ',
16109 'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ',
16110 '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ',
16111 'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ',
16112 '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ',
16113 'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ',
16114 '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ',
16115 'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ',
16116 '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ',
16117 'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ',
16118 '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ',
16119 '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ',
16120 '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ',
16121 '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ',
16122 'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ',
16123 '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ',
16124 'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ',
16125 '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ',
16126 'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ',
16127 '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ',
16128 'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ',
16129 '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ',
16130 'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'
16134 for (i = 0, iTop = str.length; i < iTop; i+=1 ) {
16135 y = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
16136 x = '0x' + table.substr( y * 9, 8 );
16137 crc = ( crc >>> 8 ) ^ x;
16139 // always return a positive number (that's what >>> 0 does)
16140 return (crc ^ (-1)) >>> 0;
16146 * @param {Object} [config]
16148 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
16149 * Digest Algorithm, as defined in RFC 1321.
16150 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
16151 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
16152 * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
16154 MD5 : function (options) {
16156 * Private config properties. You may need to tweak these to be compatible with
16157 * the server-side, but the defaults work in most cases.
16158 * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
16160 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
16161 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
16162 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
16164 // privileged (public) methods
16165 this.hex = function (s) {
16166 return rstr2hex(rstr(s, utf8), hexcase);
16168 this.b64 = function (s) {
16169 return rstr2b64(rstr(s), b64pad);
16171 this.any = function(s, e) {
16172 return rstr2any(rstr(s, utf8), e);
16174 this.hex_hmac = function (k, d) {
16175 return rstr2hex(rstr_hmac(k, d), hexcase);
16177 this.b64_hmac = function (k, d) {
16178 return rstr2b64(rstr_hmac(k,d), b64pad);
16180 this.any_hmac = function (k, d, e) {
16181 return rstr2any(rstr_hmac(k, d), e);
16184 * Perform a simple self-test to see if the VM is working
16185 * @return {String} Hexadecimal hash sample
16187 this.vm_test = function () {
16188 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
16191 * Enable/disable uppercase hexadecimal returned string
16193 * @return {Object} this
16195 this.setUpperCase = function (a) {
16196 if (typeof a === 'boolean' ) {
16202 * Defines a base64 pad string
16203 * @param {String} Pad
16204 * @return {Object} this
16206 this.setPad = function (a) {
16207 b64pad = a || b64pad;
16211 * Defines a base64 pad string
16213 * @return {Object} [this]
16215 this.setUTF8 = function (a) {
16216 if (typeof a === 'boolean') {
16225 * Calculate the MD5 of a raw string
16228 s = (utf8) ? utf8Encode(s): s;
16229 return binl2rstr(binl(rstr2binl(s), s.length * 8));
16233 * Calculate the HMAC-MD5, of a key and some data (raw strings)
16235 function rstr_hmac(key, data) {
16236 var bkey, ipad, opad, hash, i;
16238 key = (utf8) ? utf8Encode(key) : key;
16239 data = (utf8) ? utf8Encode(data) : data;
16240 bkey = rstr2binl(key);
16241 if (bkey.length > 16) {
16242 bkey = binl(bkey, key.length * 8);
16245 ipad = Array(16), opad = Array(16);
16246 for (i = 0; i < 16; i+=1) {
16247 ipad[i] = bkey[i] ^ 0x36363636;
16248 opad[i] = bkey[i] ^ 0x5C5C5C5C;
16250 hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
16251 return binl2rstr(binl(opad.concat(hash), 512 + 128));
16255 * Calculate the MD5 of an array of little-endian words, and a bit length.
16257 function binl(x, len) {
16258 var i, olda, oldb, oldc, oldd,
16264 /* append padding */
16265 x[len >> 5] |= 0x80 << ((len) % 32);
16266 x[(((len + 64) >>> 9) << 4) + 14] = len;
16268 for (i = 0; i < x.length; i += 16) {
16274 a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
16275 d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
16276 c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
16277 b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
16278 a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
16279 d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
16280 c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
16281 b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
16282 a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
16283 d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
16284 c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
16285 b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
16286 a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
16287 d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
16288 c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
16289 b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
16291 a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
16292 d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
16293 c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
16294 b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
16295 a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
16296 d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
16297 c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
16298 b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
16299 a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
16300 d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
16301 c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
16302 b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
16303 a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
16304 d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
16305 c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
16306 b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
16308 a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
16309 d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
16310 c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
16311 b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
16312 a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
16313 d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
16314 c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
16315 b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
16316 a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
16317 d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
16318 c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
16319 b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
16320 a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
16321 d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
16322 c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
16323 b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
16325 a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
16326 d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
16327 c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
16328 b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
16329 a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
16330 d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
16331 c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
16332 b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
16333 a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
16334 d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
16335 c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
16336 b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
16337 a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
16338 d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
16339 c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
16340 b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
16342 a = safe_add(a, olda);
16343 b = safe_add(b, oldb);
16344 c = safe_add(c, oldc);
16345 d = safe_add(d, oldd);
16347 return Array(a, b, c, d);
16351 * These functions implement the four basic operations the algorithm uses.
16353 function md5_cmn(q, a, b, x, s, t) {
16354 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
16356 function md5_ff(a, b, c, d, x, s, t) {
16357 return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
16359 function md5_gg(a, b, c, d, x, s, t) {
16360 return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
16362 function md5_hh(a, b, c, d, x, s, t) {
16363 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
16365 function md5_ii(a, b, c, d, x, s, t) {
16366 return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
16371 * @class Hashes.SHA1
16372 * @param {Object} [config]
16375 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
16376 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
16377 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
16378 * See http://pajhome.org.uk/crypt/md5 for details.
16380 SHA1 : function (options) {
16382 * Private config properties. You may need to tweak these to be compatible with
16383 * the server-side, but the defaults work in most cases.
16384 * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
16386 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
16387 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
16388 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
16391 this.hex = function (s) {
16392 return rstr2hex(rstr(s, utf8), hexcase);
16394 this.b64 = function (s) {
16395 return rstr2b64(rstr(s, utf8), b64pad);
16397 this.any = function (s, e) {
16398 return rstr2any(rstr(s, utf8), e);
16400 this.hex_hmac = function (k, d) {
16401 return rstr2hex(rstr_hmac(k, d));
16403 this.b64_hmac = function (k, d) {
16404 return rstr2b64(rstr_hmac(k, d), b64pad);
16406 this.any_hmac = function (k, d, e) {
16407 return rstr2any(rstr_hmac(k, d), e);
16410 * Perform a simple self-test to see if the VM is working
16411 * @return {String} Hexadecimal hash sample
16414 this.vm_test = function () {
16415 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
16418 * @description Enable/disable uppercase hexadecimal returned string
16420 * @return {Object} this
16423 this.setUpperCase = function (a) {
16424 if (typeof a === 'boolean') {
16430 * @description Defines a base64 pad string
16431 * @param {string} Pad
16432 * @return {Object} this
16435 this.setPad = function (a) {
16436 b64pad = a || b64pad;
16440 * @description Defines a base64 pad string
16442 * @return {Object} this
16445 this.setUTF8 = function (a) {
16446 if (typeof a === 'boolean') {
16455 * Calculate the SHA-512 of a raw string
16458 s = (utf8) ? utf8Encode(s) : s;
16459 return binb2rstr(binb(rstr2binb(s), s.length * 8));
16463 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
16465 function rstr_hmac(key, data) {
16466 var bkey, ipad, opad, i, hash;
16467 key = (utf8) ? utf8Encode(key) : key;
16468 data = (utf8) ? utf8Encode(data) : data;
16469 bkey = rstr2binb(key);
16471 if (bkey.length > 16) {
16472 bkey = binb(bkey, key.length * 8);
16474 ipad = Array(16), opad = Array(16);
16475 for (i = 0; i < 16; i+=1) {
16476 ipad[i] = bkey[i] ^ 0x36363636;
16477 opad[i] = bkey[i] ^ 0x5C5C5C5C;
16479 hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
16480 return binb2rstr(binb(opad.concat(hash), 512 + 160));
16484 * Calculate the SHA-1 of an array of big-endian words, and a bit length
16486 function binb(x, len) {
16487 var i, j, t, olda, oldb, oldc, oldd, olde,
16495 /* append padding */
16496 x[len >> 5] |= 0x80 << (24 - len % 32);
16497 x[((len + 64 >> 9) << 4) + 15] = len;
16499 for (i = 0; i < x.length; i += 16) {
16506 for (j = 0; j < 80; j+=1) {
16510 w[j] = bit_rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
16512 t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
16513 safe_add(safe_add(e, w[j]), sha1_kt(j)));
16516 c = bit_rol(b, 30);
16521 a = safe_add(a, olda);
16522 b = safe_add(b, oldb);
16523 c = safe_add(c, oldc);
16524 d = safe_add(d, oldd);
16525 e = safe_add(e, olde);
16527 return Array(a, b, c, d, e);
16531 * Perform the appropriate triplet combination function for the current
16534 function sha1_ft(t, b, c, d) {
16535 if (t < 20) { return (b & c) | ((~b) & d); }
16536 if (t < 40) { return b ^ c ^ d; }
16537 if (t < 60) { return (b & c) | (b & d) | (c & d); }
16542 * Determine the appropriate additive constant for the current iteration
16544 function sha1_kt(t) {
16545 return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
16546 (t < 60) ? -1894007588 : -899497514;
16550 * @class Hashes.SHA256
16553 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
16554 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
16555 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
16556 * See http://pajhome.org.uk/crypt/md5 for details.
16557 * Also http://anmar.eu.org/projects/jssha2/
16559 SHA256 : function (options) {
16561 * Private properties configuration variables. You may need to tweak these to be compatible with
16562 * the server-side, but the defaults work in most cases.
16563 * @see this.setUpperCase() method
16564 * @see this.setPad() method
16566 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase */
16567 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
16568 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
16571 /* privileged (public) methods */
16572 this.hex = function (s) {
16573 return rstr2hex(rstr(s, utf8));
16575 this.b64 = function (s) {
16576 return rstr2b64(rstr(s, utf8), b64pad);
16578 this.any = function (s, e) {
16579 return rstr2any(rstr(s, utf8), e);
16581 this.hex_hmac = function (k, d) {
16582 return rstr2hex(rstr_hmac(k, d));
16584 this.b64_hmac = function (k, d) {
16585 return rstr2b64(rstr_hmac(k, d), b64pad);
16587 this.any_hmac = function (k, d, e) {
16588 return rstr2any(rstr_hmac(k, d), e);
16591 * Perform a simple self-test to see if the VM is working
16592 * @return {String} Hexadecimal hash sample
16595 this.vm_test = function () {
16596 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
16599 * Enable/disable uppercase hexadecimal returned string
16601 * @return {Object} this
16604 this.setUpperCase = function (a) {
16605 if (typeof a === 'boolean') {
16611 * @description Defines a base64 pad string
16612 * @param {string} Pad
16613 * @return {Object} this
16616 this.setPad = function (a) {
16617 b64pad = a || b64pad;
16621 * Defines a base64 pad string
16623 * @return {Object} this
16626 this.setUTF8 = function (a) {
16627 if (typeof a === 'boolean') {
16636 * Calculate the SHA-512 of a raw string
16638 function rstr(s, utf8) {
16639 s = (utf8) ? utf8Encode(s) : s;
16640 return binb2rstr(binb(rstr2binb(s), s.length * 8));
16644 * Calculate the HMAC-sha256 of a key and some data (raw strings)
16646 function rstr_hmac(key, data) {
16647 key = (utf8) ? utf8Encode(key) : key;
16648 data = (utf8) ? utf8Encode(data) : data;
16650 bkey = rstr2binb(key),
16654 if (bkey.length > 16) { bkey = binb(bkey, key.length * 8); }
16656 for (; i < 16; i+=1) {
16657 ipad[i] = bkey[i] ^ 0x36363636;
16658 opad[i] = bkey[i] ^ 0x5C5C5C5C;
16661 hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
16662 return binb2rstr(binb(opad.concat(hash), 512 + 256));
16666 * Main sha256 function, with its support functions
16668 function sha256_S (X, n) {return ( X >>> n ) | (X << (32 - n));}
16669 function sha256_R (X, n) {return ( X >>> n );}
16670 function sha256_Ch(x, y, z) {return ((x & y) ^ ((~x) & z));}
16671 function sha256_Maj(x, y, z) {return ((x & y) ^ (x & z) ^ (y & z));}
16672 function sha256_Sigma0256(x) {return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));}
16673 function sha256_Sigma1256(x) {return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));}
16674 function sha256_Gamma0256(x) {return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));}
16675 function sha256_Gamma1256(x) {return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));}
16676 function sha256_Sigma0512(x) {return (sha256_S(x, 28) ^ sha256_S(x, 34) ^ sha256_S(x, 39));}
16677 function sha256_Sigma1512(x) {return (sha256_S(x, 14) ^ sha256_S(x, 18) ^ sha256_S(x, 41));}
16678 function sha256_Gamma0512(x) {return (sha256_S(x, 1) ^ sha256_S(x, 8) ^ sha256_R(x, 7));}
16679 function sha256_Gamma1512(x) {return (sha256_S(x, 19) ^ sha256_S(x, 61) ^ sha256_R(x, 6));}
16682 1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993,
16683 -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
16684 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
16685 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986,
16686 -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
16687 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
16688 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885,
16689 -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
16690 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
16691 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872,
16692 -1866530822, -1538233109, -1090935817, -965641998
16695 function binb(m, l) {
16696 var HASH = [1779033703, -1150833019, 1013904242, -1521486534,
16697 1359893119, -1694144372, 528734635, 1541459225];
16698 var W = new Array(64);
16699 var a, b, c, d, e, f, g, h;
16702 /* append padding */
16703 m[l >> 5] |= 0x80 << (24 - l % 32);
16704 m[((l + 64 >> 9) << 4) + 15] = l;
16706 for (i = 0; i < m.length; i += 16)
16717 for (j = 0; j < 64; j+=1)
16722 W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
16723 sha256_Gamma0256(W[j - 15])), W[j - 16]);
16726 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
16727 sha256_K[j]), W[j]);
16728 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
16732 e = safe_add(d, T1);
16736 a = safe_add(T1, T2);
16739 HASH[0] = safe_add(a, HASH[0]);
16740 HASH[1] = safe_add(b, HASH[1]);
16741 HASH[2] = safe_add(c, HASH[2]);
16742 HASH[3] = safe_add(d, HASH[3]);
16743 HASH[4] = safe_add(e, HASH[4]);
16744 HASH[5] = safe_add(f, HASH[5]);
16745 HASH[6] = safe_add(g, HASH[6]);
16746 HASH[7] = safe_add(h, HASH[7]);
16754 * @class Hashes.SHA512
16757 * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
16758 * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
16759 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
16760 * See http://pajhome.org.uk/crypt/md5 for details.
16762 SHA512 : function (options) {
16764 * Private properties configuration variables. You may need to tweak these to be compatible with
16765 * the server-side, but the defaults work in most cases.
16766 * @see this.setUpperCase() method
16767 * @see this.setPad() method
16769 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false , /* hexadecimal output case format. false - lowercase; true - uppercase */
16770 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
16771 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
16774 /* privileged (public) methods */
16775 this.hex = function (s) {
16776 return rstr2hex(rstr(s));
16778 this.b64 = function (s) {
16779 return rstr2b64(rstr(s), b64pad);
16781 this.any = function (s, e) {
16782 return rstr2any(rstr(s), e);
16784 this.hex_hmac = function (k, d) {
16785 return rstr2hex(rstr_hmac(k, d));
16787 this.b64_hmac = function (k, d) {
16788 return rstr2b64(rstr_hmac(k, d), b64pad);
16790 this.any_hmac = function (k, d, e) {
16791 return rstr2any(rstr_hmac(k, d), e);
16794 * Perform a simple self-test to see if the VM is working
16795 * @return {String} Hexadecimal hash sample
16798 this.vm_test = function () {
16799 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
16802 * @description Enable/disable uppercase hexadecimal returned string
16804 * @return {Object} this
16807 this.setUpperCase = function (a) {
16808 if (typeof a === 'boolean') {
16814 * @description Defines a base64 pad string
16815 * @param {string} Pad
16816 * @return {Object} this
16819 this.setPad = function (a) {
16820 b64pad = a || b64pad;
16824 * @description Defines a base64 pad string
16826 * @return {Object} this
16829 this.setUTF8 = function (a) {
16830 if (typeof a === 'boolean') {
16836 /* private methods */
16839 * Calculate the SHA-512 of a raw string
16842 s = (utf8) ? utf8Encode(s) : s;
16843 return binb2rstr(binb(rstr2binb(s), s.length * 8));
16846 * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
16848 function rstr_hmac(key, data) {
16849 key = (utf8) ? utf8Encode(key) : key;
16850 data = (utf8) ? utf8Encode(data) : data;
16853 bkey = rstr2binb(key),
16854 ipad = Array(32), opad = Array(32);
16856 if (bkey.length > 32) { bkey = binb(bkey, key.length * 8); }
16858 for (; i < 32; i+=1) {
16859 ipad[i] = bkey[i] ^ 0x36363636;
16860 opad[i] = bkey[i] ^ 0x5C5C5C5C;
16863 hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
16864 return binb2rstr(binb(opad.concat(hash), 1024 + 512));
16868 * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
16870 function binb(x, len) {
16873 hash = new Array(16),
16874 //Initial hash values
16876 new int64(0x6a09e667, -205731576),
16877 new int64(-1150833019, -2067093701),
16878 new int64(0x3c6ef372, -23791573),
16879 new int64(-1521486534, 0x5f1d36f1),
16880 new int64(0x510e527f, -1377402159),
16881 new int64(-1694144372, 0x2b3e6c1f),
16882 new int64(0x1f83d9ab, -79577749),
16883 new int64(0x5be0cd19, 0x137e2179)
16885 T1 = new int64(0, 0),
16886 T2 = new int64(0, 0),
16887 a = new int64(0,0),
16888 b = new int64(0,0),
16889 c = new int64(0,0),
16890 d = new int64(0,0),
16891 e = new int64(0,0),
16892 f = new int64(0,0),
16893 g = new int64(0,0),
16894 h = new int64(0,0),
16895 //Temporary variables not specified by the document
16896 s0 = new int64(0, 0),
16897 s1 = new int64(0, 0),
16898 Ch = new int64(0, 0),
16899 Maj = new int64(0, 0),
16900 r1 = new int64(0, 0),
16901 r2 = new int64(0, 0),
16902 r3 = new int64(0, 0);
16904 if (sha512_k === undefined) {
16907 new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
16908 new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
16909 new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
16910 new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
16911 new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
16912 new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
16913 new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
16914 new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
16915 new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
16916 new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
16917 new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
16918 new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
16919 new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
16920 new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
16921 new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
16922 new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
16923 new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
16924 new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
16925 new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
16926 new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
16927 new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
16928 new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
16929 new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
16930 new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
16931 new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
16932 new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
16933 new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
16934 new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
16935 new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
16936 new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
16937 new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
16938 new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
16939 new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
16940 new int64(-354779690, -840897762), new int64(-176337025, -294727304),
16941 new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
16942 new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
16943 new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
16944 new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
16945 new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
16946 new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)
16950 for (i=0; i<80; i+=1) {
16951 W[i] = new int64(0, 0);
16954 // append padding to the source string. The format is described in the FIPS.
16955 x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
16956 x[((len + 128 >> 10)<< 5) + 31] = len;
16958 for (i = 0; i<l; i+=32) { //32 dwords is the block size
16959 int64copy(a, H[0]);
16960 int64copy(b, H[1]);
16961 int64copy(c, H[2]);
16962 int64copy(d, H[3]);
16963 int64copy(e, H[4]);
16964 int64copy(f, H[5]);
16965 int64copy(g, H[6]);
16966 int64copy(h, H[7]);
16968 for (j=0; j<16; j+=1) {
16969 W[j].h = x[i + 2*j];
16970 W[j].l = x[i + 2*j + 1];
16973 for (j=16; j<80; j+=1) {
16975 int64rrot(r1, W[j-2], 19);
16976 int64revrrot(r2, W[j-2], 29);
16977 int64shr(r3, W[j-2], 6);
16978 s1.l = r1.l ^ r2.l ^ r3.l;
16979 s1.h = r1.h ^ r2.h ^ r3.h;
16981 int64rrot(r1, W[j-15], 1);
16982 int64rrot(r2, W[j-15], 8);
16983 int64shr(r3, W[j-15], 7);
16984 s0.l = r1.l ^ r2.l ^ r3.l;
16985 s0.h = r1.h ^ r2.h ^ r3.h;
16987 int64add4(W[j], s1, W[j-7], s0, W[j-16]);
16990 for (j = 0; j < 80; j+=1) {
16992 Ch.l = (e.l & f.l) ^ (~e.l & g.l);
16993 Ch.h = (e.h & f.h) ^ (~e.h & g.h);
16996 int64rrot(r1, e, 14);
16997 int64rrot(r2, e, 18);
16998 int64revrrot(r3, e, 9);
16999 s1.l = r1.l ^ r2.l ^ r3.l;
17000 s1.h = r1.h ^ r2.h ^ r3.h;
17003 int64rrot(r1, a, 28);
17004 int64revrrot(r2, a, 2);
17005 int64revrrot(r3, a, 7);
17006 s0.l = r1.l ^ r2.l ^ r3.l;
17007 s0.h = r1.h ^ r2.h ^ r3.h;
17010 Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
17011 Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
17013 int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
17014 int64add(T2, s0, Maj);
17019 int64add(e, d, T1);
17023 int64add(a, T1, T2);
17025 int64add(H[0], H[0], a);
17026 int64add(H[1], H[1], b);
17027 int64add(H[2], H[2], c);
17028 int64add(H[3], H[3], d);
17029 int64add(H[4], H[4], e);
17030 int64add(H[5], H[5], f);
17031 int64add(H[6], H[6], g);
17032 int64add(H[7], H[7], h);
17035 //represent the hash as an array of 32-bit dwords
17036 for (i=0; i<8; i+=1) {
17037 hash[2*i] = H[i].h;
17038 hash[2*i + 1] = H[i].l;
17043 //A constructor for 64-bit numbers
17044 function int64(h, l) {
17047 //this.toString = int64toString;
17050 //Copies src into dst, assuming both are 64-bit numbers
17051 function int64copy(dst, src) {
17056 //Right-rotates a 64-bit number by shift
17057 //Won't handle cases of shift>=32
17058 //The function revrrot() is for that
17059 function int64rrot(dst, x, shift) {
17060 dst.l = (x.l >>> shift) | (x.h << (32-shift));
17061 dst.h = (x.h >>> shift) | (x.l << (32-shift));
17064 //Reverses the dwords of the source and then rotates right by shift.
17065 //This is equivalent to rotation by 32+shift
17066 function int64revrrot(dst, x, shift) {
17067 dst.l = (x.h >>> shift) | (x.l << (32-shift));
17068 dst.h = (x.l >>> shift) | (x.h << (32-shift));
17071 //Bitwise-shifts right a 64-bit number by shift
17072 //Won't handle shift>=32, but it's never needed in SHA512
17073 function int64shr(dst, x, shift) {
17074 dst.l = (x.l >>> shift) | (x.h << (32-shift));
17075 dst.h = (x.h >>> shift);
17078 //Adds two 64-bit numbers
17079 //Like the original implementation, does not rely on 32-bit operations
17080 function int64add(dst, x, y) {
17081 var w0 = (x.l & 0xffff) + (y.l & 0xffff);
17082 var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
17083 var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
17084 var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
17085 dst.l = (w0 & 0xffff) | (w1 << 16);
17086 dst.h = (w2 & 0xffff) | (w3 << 16);
17089 //Same, except with 4 addends. Works faster than adding them one by one.
17090 function int64add4(dst, a, b, c, d) {
17091 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
17092 var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
17093 var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
17094 var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
17095 dst.l = (w0 & 0xffff) | (w1 << 16);
17096 dst.h = (w2 & 0xffff) | (w3 << 16);
17099 //Same, except with 5 addends
17100 function int64add5(dst, a, b, c, d, e) {
17101 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
17102 w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
17103 w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
17104 w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
17105 dst.l = (w0 & 0xffff) | (w1 << 16);
17106 dst.h = (w2 & 0xffff) | (w3 << 16);
17110 * @class Hashes.RMD160
17112 * @param {Object} [config]
17114 * A JavaScript implementation of the RIPEMD-160 Algorithm
17115 * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
17116 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
17117 * See http://pajhome.org.uk/crypt/md5 for details.
17118 * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
17120 RMD160 : function (options) {
17122 * Private properties configuration variables. You may need to tweak these to be compatible with
17123 * the server-side, but the defaults work in most cases.
17124 * @see this.setUpperCase() method
17125 * @see this.setPad() method
17127 var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, /* hexadecimal output case format. false - lowercase; true - uppercase */
17128 b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', /* base-64 pad character. Default '=' for strict RFC compliance */
17129 utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true, /* enable/disable utf8 encoding */
17131 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
17132 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
17133 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
17134 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
17135 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
17138 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
17139 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
17140 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
17141 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
17142 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
17145 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
17146 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
17147 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
17148 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
17149 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
17152 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
17153 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
17154 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
17155 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
17156 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
17159 /* privileged (public) methods */
17160 this.hex = function (s) {
17161 return rstr2hex(rstr(s, utf8));
17163 this.b64 = function (s) {
17164 return rstr2b64(rstr(s, utf8), b64pad);
17166 this.any = function (s, e) {
17167 return rstr2any(rstr(s, utf8), e);
17169 this.hex_hmac = function (k, d) {
17170 return rstr2hex(rstr_hmac(k, d));
17172 this.b64_hmac = function (k, d) {
17173 return rstr2b64(rstr_hmac(k, d), b64pad);
17175 this.any_hmac = function (k, d, e) {
17176 return rstr2any(rstr_hmac(k, d), e);
17179 * Perform a simple self-test to see if the VM is working
17180 * @return {String} Hexadecimal hash sample
17183 this.vm_test = function () {
17184 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
17187 * @description Enable/disable uppercase hexadecimal returned string
17189 * @return {Object} this
17192 this.setUpperCase = function (a) {
17193 if (typeof a === 'boolean' ) { hexcase = a; }
17197 * @description Defines a base64 pad string
17198 * @param {string} Pad
17199 * @return {Object} this
17202 this.setPad = function (a) {
17203 if (typeof a !== 'undefined' ) { b64pad = a; }
17207 * @description Defines a base64 pad string
17209 * @return {Object} this
17212 this.setUTF8 = function (a) {
17213 if (typeof a === 'boolean') { utf8 = a; }
17217 /* private methods */
17220 * Calculate the rmd160 of a raw string
17223 s = (utf8) ? utf8Encode(s) : s;
17224 return binl2rstr(binl(rstr2binl(s), s.length * 8));
17228 * Calculate the HMAC-rmd160 of a key and some data (raw strings)
17230 function rstr_hmac(key, data) {
17231 key = (utf8) ? utf8Encode(key) : key;
17232 data = (utf8) ? utf8Encode(data) : data;
17234 bkey = rstr2binl(key),
17235 ipad = Array(16), opad = Array(16);
17237 if (bkey.length > 16) {
17238 bkey = binl(bkey, key.length * 8);
17241 for (i = 0; i < 16; i+=1) {
17242 ipad[i] = bkey[i] ^ 0x36363636;
17243 opad[i] = bkey[i] ^ 0x5C5C5C5C;
17245 hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
17246 return binl2rstr(binl(opad.concat(hash), 512 + 160));
17250 * Convert an array of little-endian words to a string
17252 function binl2rstr(input) {
17253 var i, output = '', l = input.length * 32;
17254 for (i = 0; i < l; i += 8) {
17255 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
17261 * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
17263 function binl(x, len) {
17270 A1, B1, C1, D1, E1,
17271 A2, B2, C2, D2, E2;
17273 /* append padding */
17274 x[len >> 5] |= 0x80 << (len % 32);
17275 x[(((len + 64) >>> 9) << 4) + 14] = len;
17278 for (i = 0; i < l; i+=16) {
17279 A1 = A2 = h0; B1 = B2 = h1; C1 = C2 = h2; D1 = D2 = h3; E1 = E2 = h4;
17280 for (j = 0; j <= 79; j+=1) {
17281 T = safe_add(A1, rmd160_f(j, B1, C1, D1));
17282 T = safe_add(T, x[i + rmd160_r1[j]]);
17283 T = safe_add(T, rmd160_K1(j));
17284 T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
17285 A1 = E1; E1 = D1; D1 = bit_rol(C1, 10); C1 = B1; B1 = T;
17286 T = safe_add(A2, rmd160_f(79-j, B2, C2, D2));
17287 T = safe_add(T, x[i + rmd160_r2[j]]);
17288 T = safe_add(T, rmd160_K2(j));
17289 T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
17290 A2 = E2; E2 = D2; D2 = bit_rol(C2, 10); C2 = B2; B2 = T;
17293 T = safe_add(h1, safe_add(C1, D2));
17294 h1 = safe_add(h2, safe_add(D1, E2));
17295 h2 = safe_add(h3, safe_add(E1, A2));
17296 h3 = safe_add(h4, safe_add(A1, B2));
17297 h4 = safe_add(h0, safe_add(B1, C2));
17300 return [h0, h1, h2, h3, h4];
17303 // specific algorithm methods
17304 function rmd160_f(j, x, y, z) {
17305 return ( 0 <= j && j <= 15) ? (x ^ y ^ z) :
17306 (16 <= j && j <= 31) ? (x & y) | (~x & z) :
17307 (32 <= j && j <= 47) ? (x | ~y) ^ z :
17308 (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
17309 (64 <= j && j <= 79) ? x ^ (y | ~z) :
17310 'rmd160_f: j out of range';
17313 function rmd160_K1(j) {
17314 return ( 0 <= j && j <= 15) ? 0x00000000 :
17315 (16 <= j && j <= 31) ? 0x5a827999 :
17316 (32 <= j && j <= 47) ? 0x6ed9eba1 :
17317 (48 <= j && j <= 63) ? 0x8f1bbcdc :
17318 (64 <= j && j <= 79) ? 0xa953fd4e :
17319 'rmd160_K1: j out of range';
17322 function rmd160_K2(j){
17323 return ( 0 <= j && j <= 15) ? 0x50a28be6 :
17324 (16 <= j && j <= 31) ? 0x5c4dd124 :
17325 (32 <= j && j <= 47) ? 0x6d703ef3 :
17326 (48 <= j && j <= 63) ? 0x7a6d76e9 :
17327 (64 <= j && j <= 79) ? 0x00000000 :
17328 'rmd160_K2: j out of range';
17334 (function( window, undefined ) {
17335 var freeExports = false;
17336 if (typeof exports === 'object' ) {
17337 freeExports = exports;
17338 if (exports && typeof global === 'object' && global && global === global.global ) { window = global; }
17341 if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
17342 // define as an anonymous module, so, through path mapping, it can be aliased
17343 define(function () { return Hashes; });
17345 else if ( freeExports ) {
17346 // in Node.js or RingoJS v0.8.0+
17347 if ( typeof module === 'object' && module && module.exports === freeExports ) {
17348 module.exports = Hashes;
17350 // in Narwhal or RingoJS v0.7.0-
17352 freeExports.Hashes = Hashes;
17356 // in a browser or Rhino
17357 window.Hashes = Hashes;
17363 },{}],2:[function(require,module,exports){
17366 var hashes = require('jshashes'),
17367 xtend = require('xtend'),
17368 sha1 = new hashes.SHA1();
17372 ohauth.qsString = function(obj) {
17373 return Object.keys(obj).sort().map(function(key) {
17374 return ohauth.percentEncode(key) + '=' +
17375 ohauth.percentEncode(obj[key]);
17379 ohauth.stringQs = function(str) {
17380 return str.split('&').reduce(function(obj, pair){
17381 var parts = pair.split('=');
17382 obj[decodeURIComponent(parts[0])] = (null === parts[1]) ?
17383 '' : decodeURIComponent(parts[1]);
17388 ohauth.rawxhr = function(method, url, data, headers, callback) {
17389 var xhr = new XMLHttpRequest(),
17390 twoHundred = /^20\d$/;
17391 xhr.onreadystatechange = function() {
17392 if (4 == xhr.readyState && 0 !== xhr.status) {
17393 if (twoHundred.test(xhr.status)) callback(null, xhr);
17394 else return callback(xhr, null);
17397 xhr.onerror = function(e) { return callback(e, null); };
17398 xhr.open(method, url, true);
17399 for (var h in headers) xhr.setRequestHeader(h, headers[h]);
17403 ohauth.xhr = function(method, url, auth, data, options, callback) {
17404 var headers = (options && options.header) || {
17405 'Content-Type': 'application/x-www-form-urlencoded'
17407 headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
17408 ohauth.rawxhr(method, url, data, headers, callback);
17411 ohauth.nonce = function() {
17412 for (var o = ''; o.length < 6;) {
17413 o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
17418 ohauth.authHeader = function(obj) {
17419 return Object.keys(obj).sort().map(function(key) {
17420 return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
17424 ohauth.timestamp = function() { return ~~((+new Date()) / 1000); };
17426 ohauth.percentEncode = function(s) {
17427 return encodeURIComponent(s)
17428 .replace(/\!/g, '%21').replace(/\'/g, '%27')
17429 .replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
17432 ohauth.baseString = function(method, url, params) {
17433 if (params.oauth_signature) delete params.oauth_signature;
17436 ohauth.percentEncode(url),
17437 ohauth.percentEncode(ohauth.qsString(params))].join('&');
17440 ohauth.signature = function(oauth_secret, token_secret, baseString) {
17441 return sha1.b64_hmac(
17442 ohauth.percentEncode(oauth_secret) + '&' +
17443 ohauth.percentEncode(token_secret),
17448 * Takes an options object for configuration (consumer_key,
17449 * consumer_secret, version, signature_method, token) and returns a
17450 * function that generates the Authorization header for given data.
17452 * The returned function takes these parameters:
17453 * - method: GET/POST/...
17454 * - uri: full URI with protocol, port, path and query string
17455 * - extra_params: any extra parameters (that are passed in the POST data),
17456 * can be an object or a from-urlencoded string.
17458 * Returned function returns full OAuth header with "OAuth" string in it.
17461 ohauth.headerGenerator = function(options) {
17462 options = options || {};
17463 var consumer_key = options.consumer_key || '',
17464 consumer_secret = options.consumer_secret || '',
17465 signature_method = options.signature_method || 'HMAC-SHA1',
17466 version = options.version || '1.0',
17467 token = options.token || '';
17469 return function(method, uri, extra_params) {
17470 method = method.toUpperCase();
17471 if (typeof extra_params === 'string' && extra_params.length > 0) {
17472 extra_params = ohauth.stringQs(extra_params);
17475 var uri_parts = uri.split('?', 2),
17476 base_uri = uri_parts[0];
17478 var query_params = uri_parts.length === 2 ?
17479 ohauth.stringQs(uri_parts[1]) : {};
17481 var oauth_params = {
17482 oauth_consumer_key: consumer_key,
17483 oauth_signature_method: signature_method,
17484 oauth_version: version,
17485 oauth_timestamp: ohauth.timestamp(),
17486 oauth_nonce: ohauth.nonce()
17489 if (token) oauth_params.oauth_token = token;
17491 var all_params = xtend({}, oauth_params, query_params, extra_params),
17492 base_str = ohauth.baseString(method, base_uri, all_params);
17494 oauth_params.oauth_signature = ohauth.signature(consumer_secret, token, base_str);
17496 return 'OAuth ' + ohauth.authHeader(oauth_params);
17500 module.exports = ohauth;
17502 },{"jshashes":7,"xtend":4}],6:[function(require,module,exports){
17503 module.exports = Object.keys || require('./shim');
17506 },{"./shim":8}],8:[function(require,module,exports){
17510 // modified from https://github.com/kriskowal/es5-shim
17511 var has = Object.prototype.hasOwnProperty,
17512 is = require('is'),
17513 forEach = require('foreach'),
17514 hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
17521 "propertyIsEnumerable",
17526 keysShim = function keys(object) {
17527 if (!is.object(object) && !is.array(object)) {
17528 throw new TypeError("Object.keys called on a non-object");
17531 var name, theKeys = [];
17532 for (name in object) {
17533 if (has.call(object, name)) {
17534 theKeys.push(name);
17538 if (hasDontEnumBug) {
17539 forEach(dontEnums, function (dontEnum) {
17540 if (has.call(object, dontEnum)) {
17541 theKeys.push(dontEnum);
17548 module.exports = keysShim;
17552 },{"is":9,"foreach":10}],9:[function(require,module,exports){
17556 * the definitive JavaScript type testing library
17558 * @copyright 2013 Enrico Marino
17562 var objProto = Object.prototype;
17563 var owns = objProto.hasOwnProperty;
17564 var toString = objProto.toString;
17565 var isActualNaN = function (value) {
17566 return value !== value;
17568 var NON_HOST_TYPES = {
17579 var is = module.exports = {};
17587 * Test if `value` is a type of `type`.
17589 * @param {Mixed} value value to test
17590 * @param {String} type type
17591 * @return {Boolean} true if `value` is a type of `type`, false otherwise
17596 is.type = function (value, type) {
17597 return typeof value === type;
17602 * Test if `value` is defined.
17604 * @param {Mixed} value value to test
17605 * @return {Boolean} true if 'value' is defined, false otherwise
17609 is.defined = function (value) {
17610 return value !== undefined;
17615 * Test if `value` is empty.
17617 * @param {Mixed} value value to test
17618 * @return {Boolean} true if `value` is empty, false otherwise
17622 is.empty = function (value) {
17623 var type = toString.call(value);
17626 if ('[object Array]' === type || '[object Arguments]' === type) {
17627 return value.length === 0;
17630 if ('[object Object]' === type) {
17631 for (key in value) if (owns.call(value, key)) return false;
17635 if ('[object String]' === type) {
17636 return '' === value;
17644 * Test if `value` is equal to `other`.
17646 * @param {Mixed} value value to test
17647 * @param {Mixed} other value to compare with
17648 * @return {Boolean} true if `value` is equal to `other`, false otherwise
17651 is.equal = function (value, other) {
17652 var type = toString.call(value)
17655 if (type !== toString.call(other)) {
17659 if ('[object Object]' === type) {
17660 for (key in value) {
17661 if (!is.equal(value[key], other[key])) {
17668 if ('[object Array]' === type) {
17669 key = value.length;
17670 if (key !== other.length) {
17674 if (!is.equal(value[key], other[key])) {
17681 if ('[object Function]' === type) {
17682 return value.prototype === other.prototype;
17685 if ('[object Date]' === type) {
17686 return value.getTime() === other.getTime();
17689 return value === other;
17694 * Test if `value` is hosted by `host`.
17696 * @param {Mixed} value to test
17697 * @param {Mixed} host host to test with
17698 * @return {Boolean} true if `value` is hosted by `host`, false otherwise
17702 is.hosted = function (value, host) {
17703 var type = typeof host[value];
17704 return type === 'object' ? !!host[value] : !NON_HOST_TYPES[type];
17709 * Test if `value` is an instance of `constructor`.
17711 * @param {Mixed} value value to test
17712 * @return {Boolean} true if `value` is an instance of `constructor`
17716 is.instance = is['instanceof'] = function (value, constructor) {
17717 return value instanceof constructor;
17722 * Test if `value` is null.
17724 * @param {Mixed} value value to test
17725 * @return {Boolean} true if `value` is null, false otherwise
17729 is['null'] = function (value) {
17730 return value === null;
17735 * Test if `value` is undefined.
17737 * @param {Mixed} value value to test
17738 * @return {Boolean} true if `value` is undefined, false otherwise
17742 is.undefined = function (value) {
17743 return value === undefined;
17752 * Test if `value` is an arguments object.
17754 * @param {Mixed} value value to test
17755 * @return {Boolean} true if `value` is an arguments object, false otherwise
17759 is.arguments = function (value) {
17760 var isStandardArguments = '[object Arguments]' === toString.call(value);
17761 var isOldArguments = !is.array(value) && is.arraylike(value) && is.object(value) && is.fn(value.callee);
17762 return isStandardArguments || isOldArguments;
17771 * Test if 'value' is an array.
17773 * @param {Mixed} value value to test
17774 * @return {Boolean} true if `value` is an array, false otherwise
17778 is.array = function (value) {
17779 return '[object Array]' === toString.call(value);
17783 * is.arguments.empty
17784 * Test if `value` is an empty arguments object.
17786 * @param {Mixed} value value to test
17787 * @return {Boolean} true if `value` is an empty arguments object, false otherwise
17790 is.arguments.empty = function (value) {
17791 return is.arguments(value) && value.length === 0;
17796 * Test if `value` is an empty array.
17798 * @param {Mixed} value value to test
17799 * @return {Boolean} true if `value` is an empty array, false otherwise
17802 is.array.empty = function (value) {
17803 return is.array(value) && value.length === 0;
17808 * Test if `value` is an arraylike object.
17810 * @param {Mixed} value value to test
17811 * @return {Boolean} true if `value` is an arguments object, false otherwise
17815 is.arraylike = function (value) {
17816 return !!value && !is.boolean(value)
17817 && owns.call(value, 'length')
17818 && isFinite(value.length)
17819 && is.number(value.length)
17820 && value.length >= 0;
17829 * Test if `value` is a boolean.
17831 * @param {Mixed} value value to test
17832 * @return {Boolean} true if `value` is a boolean, false otherwise
17836 is.boolean = function (value) {
17837 return '[object Boolean]' === toString.call(value);
17842 * Test if `value` is false.
17844 * @param {Mixed} value value to test
17845 * @return {Boolean} true if `value` is false, false otherwise
17849 is['false'] = function (value) {
17850 return is.boolean(value) && (value === false || value.valueOf() === false);
17855 * Test if `value` is true.
17857 * @param {Mixed} value value to test
17858 * @return {Boolean} true if `value` is true, false otherwise
17862 is['true'] = function (value) {
17863 return is.boolean(value) && (value === true || value.valueOf() === true);
17872 * Test if `value` is a date.
17874 * @param {Mixed} value value to test
17875 * @return {Boolean} true if `value` is a date, false otherwise
17879 is.date = function (value) {
17880 return '[object Date]' === toString.call(value);
17889 * Test if `value` is an html element.
17891 * @param {Mixed} value value to test
17892 * @return {Boolean} true if `value` is an HTML Element, false otherwise
17896 is.element = function (value) {
17897 return value !== undefined
17898 && typeof HTMLElement !== 'undefined'
17899 && value instanceof HTMLElement
17900 && value.nodeType === 1;
17909 * Test if `value` is an error object.
17911 * @param {Mixed} value value to test
17912 * @return {Boolean} true if `value` is an error object, false otherwise
17916 is.error = function (value) {
17917 return '[object Error]' === toString.call(value);
17925 * is.fn / is.function (deprecated)
17926 * Test if `value` is a function.
17928 * @param {Mixed} value value to test
17929 * @return {Boolean} true if `value` is a function, false otherwise
17933 is.fn = is['function'] = function (value) {
17934 var isAlert = typeof window !== 'undefined' && value === window.alert;
17935 return isAlert || '[object Function]' === toString.call(value);
17944 * Test if `value` is a number.
17946 * @param {Mixed} value value to test
17947 * @return {Boolean} true if `value` is a number, false otherwise
17951 is.number = function (value) {
17952 return '[object Number]' === toString.call(value);
17957 * Test if `value` is positive or negative infinity.
17959 * @param {Mixed} value value to test
17960 * @return {Boolean} true if `value` is positive or negative Infinity, false otherwise
17963 is.infinite = function (value) {
17964 return value === Infinity || value === -Infinity;
17969 * Test if `value` is a decimal number.
17971 * @param {Mixed} value value to test
17972 * @return {Boolean} true if `value` is a decimal number, false otherwise
17976 is.decimal = function (value) {
17977 return is.number(value) && !isActualNaN(value) && value % 1 !== 0;
17982 * Test if `value` is divisible by `n`.
17984 * @param {Number} value value to test
17985 * @param {Number} n dividend
17986 * @return {Boolean} true if `value` is divisible by `n`, false otherwise
17990 is.divisibleBy = function (value, n) {
17991 var isDividendInfinite = is.infinite(value);
17992 var isDivisorInfinite = is.infinite(n);
17993 var isNonZeroNumber = is.number(value) && !isActualNaN(value) && is.number(n) && !isActualNaN(n) && n !== 0;
17994 return isDividendInfinite || isDivisorInfinite || (isNonZeroNumber && value % n === 0);
17999 * Test if `value` is an integer.
18001 * @param value to test
18002 * @return {Boolean} true if `value` is an integer, false otherwise
18006 is.int = function (value) {
18007 return is.number(value) && !isActualNaN(value) && value % 1 === 0;
18012 * Test if `value` is greater than 'others' values.
18014 * @param {Number} value value to test
18015 * @param {Array} others values to compare with
18016 * @return {Boolean} true if `value` is greater than `others` values
18020 is.maximum = function (value, others) {
18021 if (isActualNaN(value)) {
18022 throw new TypeError('NaN is not a valid value');
18023 } else if (!is.arraylike(others)) {
18024 throw new TypeError('second argument must be array-like');
18026 var len = others.length;
18028 while (--len >= 0) {
18029 if (value < others[len]) {
18039 * Test if `value` is less than `others` values.
18041 * @param {Number} value value to test
18042 * @param {Array} others values to compare with
18043 * @return {Boolean} true if `value` is less than `others` values
18047 is.minimum = function (value, others) {
18048 if (isActualNaN(value)) {
18049 throw new TypeError('NaN is not a valid value');
18050 } else if (!is.arraylike(others)) {
18051 throw new TypeError('second argument must be array-like');
18053 var len = others.length;
18055 while (--len >= 0) {
18056 if (value > others[len]) {
18066 * Test if `value` is not a number.
18068 * @param {Mixed} value value to test
18069 * @return {Boolean} true if `value` is not a number, false otherwise
18073 is.nan = function (value) {
18074 return !is.number(value) || value !== value;
18079 * Test if `value` is an even number.
18081 * @param {Number} value value to test
18082 * @return {Boolean} true if `value` is an even number, false otherwise
18086 is.even = function (value) {
18087 return is.infinite(value) || (is.number(value) && value === value && value % 2 === 0);
18092 * Test if `value` is an odd number.
18094 * @param {Number} value value to test
18095 * @return {Boolean} true if `value` is an odd number, false otherwise
18099 is.odd = function (value) {
18100 return is.infinite(value) || (is.number(value) && value === value && value % 2 !== 0);
18105 * Test if `value` is greater than or equal to `other`.
18107 * @param {Number} value value to test
18108 * @param {Number} other value to compare with
18109 * @return {Boolean}
18113 is.ge = function (value, other) {
18114 if (isActualNaN(value) || isActualNaN(other)) {
18115 throw new TypeError('NaN is not a valid value');
18117 return !is.infinite(value) && !is.infinite(other) && value >= other;
18122 * Test if `value` is greater than `other`.
18124 * @param {Number} value value to test
18125 * @param {Number} other value to compare with
18126 * @return {Boolean}
18130 is.gt = function (value, other) {
18131 if (isActualNaN(value) || isActualNaN(other)) {
18132 throw new TypeError('NaN is not a valid value');
18134 return !is.infinite(value) && !is.infinite(other) && value > other;
18139 * Test if `value` is less than or equal to `other`.
18141 * @param {Number} value value to test
18142 * @param {Number} other value to compare with
18143 * @return {Boolean} if 'value' is less than or equal to 'other'
18147 is.le = function (value, other) {
18148 if (isActualNaN(value) || isActualNaN(other)) {
18149 throw new TypeError('NaN is not a valid value');
18151 return !is.infinite(value) && !is.infinite(other) && value <= other;
18156 * Test if `value` is less than `other`.
18158 * @param {Number} value value to test
18159 * @param {Number} other value to compare with
18160 * @return {Boolean} if `value` is less than `other`
18164 is.lt = function (value, other) {
18165 if (isActualNaN(value) || isActualNaN(other)) {
18166 throw new TypeError('NaN is not a valid value');
18168 return !is.infinite(value) && !is.infinite(other) && value < other;
18173 * Test if `value` is within `start` and `finish`.
18175 * @param {Number} value value to test
18176 * @param {Number} start lower bound
18177 * @param {Number} finish upper bound
18178 * @return {Boolean} true if 'value' is is within 'start' and 'finish'
18181 is.within = function (value, start, finish) {
18182 if (isActualNaN(value) || isActualNaN(start) || isActualNaN(finish)) {
18183 throw new TypeError('NaN is not a valid value');
18184 } else if (!is.number(value) || !is.number(start) || !is.number(finish)) {
18185 throw new TypeError('all arguments must be numbers');
18187 var isAnyInfinite = is.infinite(value) || is.infinite(start) || is.infinite(finish);
18188 return isAnyInfinite || (value >= start && value <= finish);
18197 * Test if `value` is an object.
18199 * @param {Mixed} value value to test
18200 * @return {Boolean} true if `value` is an object, false otherwise
18204 is.object = function (value) {
18205 return value && '[object Object]' === toString.call(value);
18210 * Test if `value` is a hash - a plain object literal.
18212 * @param {Mixed} value value to test
18213 * @return {Boolean} true if `value` is a hash, false otherwise
18217 is.hash = function (value) {
18218 return is.object(value) && value.constructor === Object && !value.nodeType && !value.setInterval;
18227 * Test if `value` is a regular expression.
18229 * @param {Mixed} value value to test
18230 * @return {Boolean} true if `value` is a regexp, false otherwise
18234 is.regexp = function (value) {
18235 return '[object RegExp]' === toString.call(value);
18244 * Test if `value` is a string.
18246 * @param {Mixed} value value to test
18247 * @return {Boolean} true if 'value' is a string, false otherwise
18251 is.string = function (value) {
18252 return '[object String]' === toString.call(value);
18256 },{}],10:[function(require,module,exports){
18258 var hasOwn = Object.prototype.hasOwnProperty;
18259 var toString = Object.prototype.toString;
18261 module.exports = function forEach (obj, fn, ctx) {
18262 if (toString.call(fn) !== '[object Function]') {
18263 throw new TypeError('iterator must be a function');
18265 var l = obj.length;
18267 for (var i = 0; i < l; i++) {
18268 fn.call(ctx, obj[i], i, obj);
18271 for (var k in obj) {
18272 if (hasOwn.call(obj, k)) {
18273 fn.call(ctx, obj[k], k, obj);
18284 (c) 2015, Vladimir Agafonkin
18285 RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles.
18286 https://github.com/mourner/rbush
18292 function rbush(maxEntries, format) {
18294 // jshint newcap: false, validthis: true
18295 if (!(this instanceof rbush)) return new rbush(maxEntries, format);
18297 // max entries in a node is 9 by default; min node fill is 40% for best performance
18298 this._maxEntries = Math.max(4, maxEntries || 9);
18299 this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
18302 this._initFormat(format);
18308 rbush.prototype = {
18311 return this._all(this.data, []);
18314 search: function (bbox) {
18316 var node = this.data,
18318 toBBox = this.toBBox;
18320 if (!intersects(bbox, node.bbox)) return result;
18322 var nodesToSearch = [],
18323 i, len, child, childBBox;
18326 for (i = 0, len = node.children.length; i < len; i++) {
18328 child = node.children[i];
18329 childBBox = node.leaf ? toBBox(child) : child.bbox;
18331 if (intersects(bbox, childBBox)) {
18332 if (node.leaf) result.push(child);
18333 else if (contains(bbox, childBBox)) this._all(child, result);
18334 else nodesToSearch.push(child);
18337 node = nodesToSearch.pop();
18343 collides: function (bbox) {
18345 var node = this.data,
18346 toBBox = this.toBBox;
18348 if (!intersects(bbox, node.bbox)) return false;
18350 var nodesToSearch = [],
18351 i, len, child, childBBox;
18354 for (i = 0, len = node.children.length; i < len; i++) {
18356 child = node.children[i];
18357 childBBox = node.leaf ? toBBox(child) : child.bbox;
18359 if (intersects(bbox, childBBox)) {
18360 if (node.leaf || contains(bbox, childBBox)) return true;
18361 nodesToSearch.push(child);
18364 node = nodesToSearch.pop();
18370 load: function (data) {
18371 if (!(data && data.length)) return this;
18373 if (data.length < this._minEntries) {
18374 for (var i = 0, len = data.length; i < len; i++) {
18375 this.insert(data[i]);
18380 // recursively build the tree with the given data from stratch using OMT algorithm
18381 var node = this._build(data.slice(), 0, data.length - 1, 0);
18383 if (!this.data.children.length) {
18384 // save as is if tree is empty
18387 } else if (this.data.height === node.height) {
18388 // split root if trees have the same height
18389 this._splitRoot(this.data, node);
18392 if (this.data.height < node.height) {
18393 // swap trees if inserted one is bigger
18394 var tmpNode = this.data;
18399 // insert the small tree into the large tree at appropriate level
18400 this._insert(node, this.data.height - node.height - 1, true);
18406 insert: function (item) {
18407 if (item) this._insert(item, this.data.height - 1);
18411 clear: function () {
18421 remove: function (item) {
18422 if (!item) return this;
18424 var node = this.data,
18425 bbox = this.toBBox(item),
18428 i, parent, index, goingUp;
18430 // depth-first iterative tree traversal
18431 while (node || path.length) {
18433 if (!node) { // go up
18435 parent = path[path.length - 1];
18440 if (node.leaf) { // check current node
18441 index = node.children.indexOf(item);
18443 if (index !== -1) {
18444 // item found, remove the item and condense tree upwards
18445 node.children.splice(index, 1);
18447 this._condense(path);
18452 if (!goingUp && !node.leaf && contains(node.bbox, bbox)) { // go down
18457 node = node.children[0];
18459 } else if (parent) { // go right
18461 node = parent.children[i];
18464 } else node = null; // nothing found
18470 toBBox: function (item) { return item; },
18472 compareMinX: function (a, b) { return a[0] - b[0]; },
18473 compareMinY: function (a, b) { return a[1] - b[1]; },
18475 toJSON: function () { return this.data; },
18477 fromJSON: function (data) {
18482 _all: function (node, result) {
18483 var nodesToSearch = [];
18485 if (node.leaf) result.push.apply(result, node.children);
18486 else nodesToSearch.push.apply(nodesToSearch, node.children);
18488 node = nodesToSearch.pop();
18493 _build: function (items, left, right, height) {
18495 var N = right - left + 1,
18496 M = this._maxEntries,
18500 // reached leaf level; return leaf
18502 children: items.slice(left, right + 1),
18507 calcBBox(node, this.toBBox);
18512 // target height of the bulk-loaded tree
18513 height = Math.ceil(Math.log(N) / Math.log(M));
18515 // target number of root entries to maximize storage utilization
18516 M = Math.ceil(N / Math.pow(M, height - 1));
18526 // split the items into M mostly square tiles
18528 var N2 = Math.ceil(N / M),
18529 N1 = N2 * Math.ceil(Math.sqrt(M)),
18530 i, j, right2, right3;
18532 multiSelect(items, left, right, N1, this.compareMinX);
18534 for (i = left; i <= right; i += N1) {
18536 right2 = Math.min(i + N1 - 1, right);
18538 multiSelect(items, i, right2, N2, this.compareMinY);
18540 for (j = i; j <= right2; j += N2) {
18542 right3 = Math.min(j + N2 - 1, right2);
18544 // pack each entry recursively
18545 node.children.push(this._build(items, j, right3, height - 1));
18549 calcBBox(node, this.toBBox);
18554 _chooseSubtree: function (bbox, node, level, path) {
18556 var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
18561 if (node.leaf || path.length - 1 === level) break;
18563 minArea = minEnlargement = Infinity;
18565 for (i = 0, len = node.children.length; i < len; i++) {
18566 child = node.children[i];
18567 area = bboxArea(child.bbox);
18568 enlargement = enlargedArea(bbox, child.bbox) - area;
18570 // choose entry with the least area enlargement
18571 if (enlargement < minEnlargement) {
18572 minEnlargement = enlargement;
18573 minArea = area < minArea ? area : minArea;
18574 targetNode = child;
18576 } else if (enlargement === minEnlargement) {
18577 // otherwise choose one with the smallest area
18578 if (area < minArea) {
18580 targetNode = child;
18591 _insert: function (item, level, isNode) {
18593 var toBBox = this.toBBox,
18594 bbox = isNode ? item.bbox : toBBox(item),
18597 // find the best node for accommodating the item, saving all nodes along the path too
18598 var node = this._chooseSubtree(bbox, this.data, level, insertPath);
18600 // put the item into the node
18601 node.children.push(item);
18602 extend(node.bbox, bbox);
18604 // split on node overflow; propagate upwards if necessary
18605 while (level >= 0) {
18606 if (insertPath[level].children.length > this._maxEntries) {
18607 this._split(insertPath, level);
18612 // adjust bboxes along the insertion path
18613 this._adjustParentBBoxes(bbox, insertPath, level);
18616 // split overflowed node into two
18617 _split: function (insertPath, level) {
18619 var node = insertPath[level],
18620 M = node.children.length,
18621 m = this._minEntries;
18623 this._chooseSplitAxis(node, m, M);
18625 var splitIndex = this._chooseSplitIndex(node, m, M);
18628 children: node.children.splice(splitIndex, node.children.length - splitIndex),
18629 height: node.height,
18634 if (node.leaf) newNode.leaf = true;
18636 calcBBox(node, this.toBBox);
18637 calcBBox(newNode, this.toBBox);
18639 if (level) insertPath[level - 1].children.push(newNode);
18640 else this._splitRoot(node, newNode);
18643 _splitRoot: function (node, newNode) {
18646 children: [node, newNode],
18647 height: node.height + 1,
18651 calcBBox(this.data, this.toBBox);
18654 _chooseSplitIndex: function (node, m, M) {
18656 var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
18658 minOverlap = minArea = Infinity;
18660 for (i = m; i <= M - m; i++) {
18661 bbox1 = distBBox(node, 0, i, this.toBBox);
18662 bbox2 = distBBox(node, i, M, this.toBBox);
18664 overlap = intersectionArea(bbox1, bbox2);
18665 area = bboxArea(bbox1) + bboxArea(bbox2);
18667 // choose distribution with minimum overlap
18668 if (overlap < minOverlap) {
18669 minOverlap = overlap;
18672 minArea = area < minArea ? area : minArea;
18674 } else if (overlap === minOverlap) {
18675 // otherwise choose distribution with minimum area
18676 if (area < minArea) {
18686 // sorts node children by the best axis for split
18687 _chooseSplitAxis: function (node, m, M) {
18689 var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
18690 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
18691 xMargin = this._allDistMargin(node, m, M, compareMinX),
18692 yMargin = this._allDistMargin(node, m, M, compareMinY);
18694 // if total distributions margin value is minimal for x, sort by minX,
18695 // otherwise it's already sorted by minY
18696 if (xMargin < yMargin) node.children.sort(compareMinX);
18699 // total margin of all possible split distributions where each node is at least m full
18700 _allDistMargin: function (node, m, M, compare) {
18702 node.children.sort(compare);
18704 var toBBox = this.toBBox,
18705 leftBBox = distBBox(node, 0, m, toBBox),
18706 rightBBox = distBBox(node, M - m, M, toBBox),
18707 margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
18710 for (i = m; i < M - m; i++) {
18711 child = node.children[i];
18712 extend(leftBBox, node.leaf ? toBBox(child) : child.bbox);
18713 margin += bboxMargin(leftBBox);
18716 for (i = M - m - 1; i >= m; i--) {
18717 child = node.children[i];
18718 extend(rightBBox, node.leaf ? toBBox(child) : child.bbox);
18719 margin += bboxMargin(rightBBox);
18725 _adjustParentBBoxes: function (bbox, path, level) {
18726 // adjust bboxes along the given tree path
18727 for (var i = level; i >= 0; i--) {
18728 extend(path[i].bbox, bbox);
18732 _condense: function (path) {
18733 // go through the path, removing empty nodes and updating bboxes
18734 for (var i = path.length - 1, siblings; i >= 0; i--) {
18735 if (path[i].children.length === 0) {
18737 siblings = path[i - 1].children;
18738 siblings.splice(siblings.indexOf(path[i]), 1);
18740 } else this.clear();
18742 } else calcBBox(path[i], this.toBBox);
18746 _initFormat: function (format) {
18747 // data format (minX, minY, maxX, maxY accessors)
18749 // uses eval-type function compilation instead of just accepting a toBBox function
18750 // because the algorithms are very sensitive to sorting functions performance,
18751 // so they should be dead simple and without inner calls
18753 // jshint evil: true
18755 var compareArr = ['return a', ' - b', ';'];
18757 this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
18758 this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
18760 this.toBBox = new Function('a', 'return [a' + format.join(', a') + '];');
18765 // calculate node's bbox from bboxes of its children
18766 function calcBBox(node, toBBox) {
18767 node.bbox = distBBox(node, 0, node.children.length, toBBox);
18770 // min bounding rectangle of node children from k to p-1
18771 function distBBox(node, k, p, toBBox) {
18772 var bbox = empty();
18774 for (var i = k, child; i < p; i++) {
18775 child = node.children[i];
18776 extend(bbox, node.leaf ? toBBox(child) : child.bbox);
18782 function empty() { return [Infinity, Infinity, -Infinity, -Infinity]; }
18784 function extend(a, b) {
18785 a[0] = Math.min(a[0], b[0]);
18786 a[1] = Math.min(a[1], b[1]);
18787 a[2] = Math.max(a[2], b[2]);
18788 a[3] = Math.max(a[3], b[3]);
18792 function compareNodeMinX(a, b) { return a.bbox[0] - b.bbox[0]; }
18793 function compareNodeMinY(a, b) { return a.bbox[1] - b.bbox[1]; }
18795 function bboxArea(a) { return (a[2] - a[0]) * (a[3] - a[1]); }
18796 function bboxMargin(a) { return (a[2] - a[0]) + (a[3] - a[1]); }
18798 function enlargedArea(a, b) {
18799 return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) *
18800 (Math.max(b[3], a[3]) - Math.min(b[1], a[1]));
18803 function intersectionArea(a, b) {
18804 var minX = Math.max(a[0], b[0]),
18805 minY = Math.max(a[1], b[1]),
18806 maxX = Math.min(a[2], b[2]),
18807 maxY = Math.min(a[3], b[3]);
18809 return Math.max(0, maxX - minX) *
18810 Math.max(0, maxY - minY);
18813 function contains(a, b) {
18814 return a[0] <= b[0] &&
18820 function intersects(a, b) {
18821 return b[0] <= a[2] &&
18827 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
18828 // combines selection algorithm with binary divide & conquer approach
18830 function multiSelect(arr, left, right, n, compare) {
18831 var stack = [left, right],
18834 while (stack.length) {
18835 right = stack.pop();
18836 left = stack.pop();
18838 if (right - left <= n) continue;
18840 mid = left + Math.ceil((right - left) / n / 2) * n;
18841 select(arr, left, right, mid, compare);
18843 stack.push(left, mid, mid, right);
18847 // Floyd-Rivest selection algorithm:
18848 // sort an array between left and right (inclusive) so that the smallest k elements come first (unordered)
18849 function select(arr, left, right, k, compare) {
18850 var n, i, z, s, sd, newLeft, newRight, t, j;
18852 while (right > left) {
18853 if (right - left > 600) {
18854 n = right - left + 1;
18857 s = 0.5 * Math.exp(2 * z / 3);
18858 sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (i - n / 2 < 0 ? -1 : 1);
18859 newLeft = Math.max(left, Math.floor(k - i * s / n + sd));
18860 newRight = Math.min(right, Math.floor(k + (n - i) * s / n + sd));
18861 select(arr, newLeft, newRight, k, compare);
18868 swap(arr, left, k);
18869 if (compare(arr[right], t) > 0) swap(arr, left, right);
18875 while (compare(arr[i], t) < 0) i++;
18876 while (compare(arr[j], t) > 0) j--;
18879 if (compare(arr[left], t) === 0) swap(arr, left, j);
18882 swap(arr, j, right);
18885 if (j <= k) left = j + 1;
18886 if (k <= j) right = j - 1;
18890 function swap(arr, i, j) {
18897 // export as AMD/CommonJS module or global variable
18898 if (typeof define === 'function' && define.amd) define('rbush', function () { return rbush; });
18899 else if (typeof module !== 'undefined') module.exports = rbush;
18900 else if (typeof self !== 'undefined') self.rbush = rbush;
18901 else window.rbush = rbush;
18904 (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;
18905 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){
18906 module.exports = element;
18907 module.exports.pair = pair;
18908 module.exports.format = format;
18909 module.exports.formatPair = formatPair;
18911 function element(x, dims) {
18912 return search(x, dims).val;
18915 function formatPair(x) {
18916 return format(x.lat, 'lat') + ' ' + format(x.lon, 'lon');
18919 // Is 0 North or South?
18920 function format(x, dim) {
18925 dir = dirs[x >= 0 ? 0 : 1],
18927 whole = Math.floor(abs),
18928 fraction = abs - whole,
18929 fractionMinutes = fraction * 60,
18930 minutes = Math.floor(fractionMinutes),
18931 seconds = Math.floor((fractionMinutes - minutes) * 60);
18933 return whole + '° ' +
18934 (minutes ? minutes + "' " : '') +
18935 (seconds ? seconds + '" ' : '') + dir;
18938 function search(x, dims, r) {
18939 if (!dims) dims = 'NSEW';
18940 if (typeof x !== 'string') return { val: null, regex: r };
18941 r = r || /[\s\,]*([\-|\—|\―]?[0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/gi;
18943 if (!m) return { val: null, regex: r };
18944 else if (m[4] && dims.indexOf(m[4]) === -1) return { val: null, regex: r };
18946 val: (((m[1]) ? parseFloat(m[1]) : 0) +
18947 ((m[2] ? parseFloat(m[2]) / 60 : 0)) +
18948 ((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
18949 ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1),
18956 function pair(x, dims) {
18958 var one = search(x, dims);
18959 if (one.val === null) return null;
18960 var two = search(x, dims, one.regex);
18961 if (two.val === null) return null;
18962 // null if one/two are not contiguous.
18963 if (one.raw + two.raw !== x) return null;
18964 if (one.dim) return swapdim(one.val, two.val, one.dim);
18965 else return [one.val, two.val];
18968 function swapdim(a, b, dim) {
18969 if (dim == 'N' || dim == 'S') return [a, b];
18970 if (dim == 'W' || dim == 'E') return [b, a];
18976 ;toGeoJSON = (function() {
18979 var removeSpace = (/\s*/g),
18980 trimSpace = (/^\s*|\s*$/g),
18981 splitSpace = (/\s+/);
18982 // generate a short, numeric hash of a string
18983 function okhash(x) {
18984 if (!x || !x.length) return 0;
18985 for (var i = 0, h = 0; i < x.length; i++) {
18986 h = ((h << 5) - h) + x.charCodeAt(i) | 0;
18989 // all Y children of X
18990 function get(x, y) { return x.getElementsByTagName(y); }
18991 function attr(x, y) { return x.getAttribute(y); }
18992 function attrf(x, y) { return parseFloat(attr(x, y)); }
18993 // one Y child of X, if any, otherwise null
18994 function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
18995 // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
18996 function norm(el) { if (el.normalize) { el.normalize(); } return el; }
18997 // cast array x into numbers
18998 function numarray(x) {
18999 for (var j = 0, o = []; j < x.length; j++) o[j] = parseFloat(x[j]);
19002 function clean(x) {
19004 for (var i in x) if (x[i]) o[i] = x[i];
19007 // get the content of a text node, if any
19008 function nodeVal(x) { if (x) {norm(x);} return x && x.firstChild && x.firstChild.nodeValue; }
19009 // get one coordinate from a coordinate array, if any
19010 function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
19011 // get all coordinates from a coordinate array as [[],[]]
19012 function coord(v) {
19013 var coords = v.replace(trimSpace, '').split(splitSpace),
19015 for (var i = 0; i < coords.length; i++) {
19016 o.push(coord1(coords[i]));
19020 function coordPair(x) { return [attrf(x, 'lon'), attrf(x, 'lat')]; }
19022 // create a new feature collection parent object
19025 type: 'FeatureCollection',
19030 var styleSupport = false;
19031 if (typeof XMLSerializer !== 'undefined') {
19032 var serializer = new XMLSerializer();
19033 styleSupport = true;
19035 function xml2str(str) { return serializer.serializeToString(str); }
19038 kml: function(doc, o) {
19042 // styleindex keeps track of hashed styles in order to match features
19044 // atomic geospatial types supported by KML - MultiGeometry is
19045 // handled separately
19046 geotypes = ['Polygon', 'LineString', 'Point', 'Track'],
19047 // all root placemarks in the file
19048 placemarks = get(doc, 'Placemark'),
19049 styles = get(doc, 'Style');
19051 if (styleSupport) for (var k = 0; k < styles.length; k++) {
19052 styleIndex['#' + attr(styles[k], 'id')] = okhash(xml2str(styles[k])).toString(16);
19054 for (var j = 0; j < placemarks.length; j++) {
19055 gj.features = gj.features.concat(getPlacemark(placemarks[j]));
19057 function gxCoord(v) { return numarray(v.split(' ')); }
19058 function gxCoords(root) {
19059 var elems = get(root, 'coord', 'gx'), coords = [];
19060 for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
19063 function getGeometry(root) {
19064 var geomNode, geomNodes, i, j, k, geoms = [];
19065 if (get1(root, 'MultiGeometry')) return getGeometry(get1(root, 'MultiGeometry'));
19066 if (get1(root, 'MultiTrack')) return getGeometry(get1(root, 'MultiTrack'));
19067 for (i = 0; i < geotypes.length; i++) {
19068 geomNodes = get(root, geotypes[i]);
19070 for (j = 0; j < geomNodes.length; j++) {
19071 geomNode = geomNodes[j];
19072 if (geotypes[i] == 'Point') {
19075 coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
19077 } else if (geotypes[i] == 'LineString') {
19079 type: 'LineString',
19080 coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
19082 } else if (geotypes[i] == 'Polygon') {
19083 var rings = get(geomNode, 'LinearRing'),
19085 for (k = 0; k < rings.length; k++) {
19086 coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
19090 coordinates: coords
19092 } else if (geotypes[i] == 'Track') {
19094 type: 'LineString',
19095 coordinates: gxCoords(geomNode)
19103 function getPlacemark(root) {
19104 var geoms = getGeometry(root), i, properties = {},
19105 name = nodeVal(get1(root, 'name')),
19106 styleUrl = nodeVal(get1(root, 'styleUrl')),
19107 description = nodeVal(get1(root, 'description')),
19108 extendedData = get1(root, 'ExtendedData');
19110 if (!geoms.length) return [];
19111 if (name) properties.name = name;
19112 if (styleUrl && styleIndex[styleUrl]) {
19113 properties.styleUrl = styleUrl;
19114 properties.styleHash = styleIndex[styleUrl];
19116 if (description) properties.description = description;
19117 if (extendedData) {
19118 var datas = get(extendedData, 'Data'),
19119 simpleDatas = get(extendedData, 'SimpleData');
19121 for (i = 0; i < datas.length; i++) {
19122 properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
19124 for (i = 0; i < simpleDatas.length; i++) {
19125 properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
19130 geometry: (geoms.length === 1) ? geoms[0] : {
19131 type: 'GeometryCollection',
19134 properties: properties
19139 gpx: function(doc, o) {
19141 tracks = get(doc, 'trk'),
19142 routes = get(doc, 'rte'),
19143 waypoints = get(doc, 'wpt'),
19144 // a feature collection
19146 for (i = 0; i < tracks.length; i++) {
19147 gj.features.push(getLinestring(tracks[i], 'trkpt'));
19149 for (i = 0; i < routes.length; i++) {
19150 gj.features.push(getLinestring(routes[i], 'rtept'));
19152 for (i = 0; i < waypoints.length; i++) {
19153 gj.features.push(getPoint(waypoints[i]));
19155 function getLinestring(node, pointname) {
19156 var j, pts = get(node, pointname), line = [];
19157 for (j = 0; j < pts.length; j++) {
19158 line.push(coordPair(pts[j]));
19162 properties: getProperties(node),
19164 type: 'LineString',
19169 function getPoint(node) {
19170 var prop = getProperties(node);
19171 prop.ele = nodeVal(get1(node, 'ele'));
19172 prop.sym = nodeVal(get1(node, 'sym'));
19178 coordinates: coordPair(node)
19182 function getProperties(node) {
19183 var meta = ['name', 'desc', 'author', 'copyright', 'link',
19184 'time', 'keywords'],
19187 for (k = 0; k < meta.length; k++) {
19188 prop[meta[k]] = nodeVal(get1(node, meta[k]));
19190 return clean(prop);
19198 if (typeof module !== 'undefined') module.exports = toGeoJSON;
19200 * marked - a markdown parser
19201 * Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
19202 * https://github.com/chjj/marked
19208 * Block-Level Grammar
19213 code: /^( {4}[^\n]+\n*)+/,
19215 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
19216 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
19218 lheading: /^([^\n]+)\n *(=|-){3,} *\n*/,
19219 blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
19220 list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
19221 html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
19222 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
19224 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
19228 block.bullet = /(?:[*+-]|\d+\.)/;
19229 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
19230 block.item = replace(block.item, 'gm')
19231 (/bull/g, block.bullet)
19234 block.list = replace(block.list)
19235 (/bull/g, block.bullet)
19236 ('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
19239 block._tag = '(?!(?:'
19240 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
19241 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
19242 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
19244 block.html = replace(block.html)
19245 ('comment', /<!--[\s\S]*?-->/)
19246 ('closed', /<(tag)[\s\S]+?<\/\1>/)
19247 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
19248 (/tag/g, block._tag)
19251 block.paragraph = replace(block.paragraph)
19253 ('heading', block.heading)
19254 ('lheading', block.lheading)
19255 ('blockquote', block.blockquote)
19256 ('tag', '<' + block._tag)
19261 * Normal Block Grammar
19264 block.normal = merge({}, block);
19267 * GFM Block Grammar
19270 block.gfm = merge({}, block.normal, {
19271 fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
19275 block.gfm.paragraph = replace(block.paragraph)
19276 ('(?!', '(?!' + block.gfm.fences.source.replace('\\1', '\\2') + '|')
19280 * GFM + Tables Block Grammar
19283 block.tables = merge({}, block.gfm, {
19284 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
19285 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
19292 function Lexer(options) {
19294 this.tokens.links = {};
19295 this.options = options || marked.defaults;
19296 this.rules = block.normal;
19298 if (this.options.gfm) {
19299 if (this.options.tables) {
19300 this.rules = block.tables;
19302 this.rules = block.gfm;
19308 * Expose Block Rules
19311 Lexer.rules = block;
19314 * Static Lex Method
19317 Lexer.lex = function(src, options) {
19318 var lexer = new Lexer(options);
19319 return lexer.lex(src);
19326 Lexer.prototype.lex = function(src) {
19328 .replace(/\r\n|\r/g, '\n')
19329 .replace(/\t/g, ' ')
19330 .replace(/\u00a0/g, ' ')
19331 .replace(/\u2424/g, '\n');
19333 return this.token(src, true);
19340 Lexer.prototype.token = function(src, top) {
19341 var src = src.replace(/^ +$/gm, '')
19354 if (cap = this.rules.newline.exec(src)) {
19355 src = src.substring(cap[0].length);
19356 if (cap[0].length > 1) {
19364 if (cap = this.rules.code.exec(src)) {
19365 src = src.substring(cap[0].length);
19366 cap = cap[0].replace(/^ {4}/gm, '');
19369 text: !this.options.pedantic
19370 ? cap.replace(/\n+$/, '')
19377 if (cap = this.rules.fences.exec(src)) {
19378 src = src.substring(cap[0].length);
19388 if (cap = this.rules.heading.exec(src)) {
19389 src = src.substring(cap[0].length);
19392 depth: cap[1].length,
19398 // table no leading pipe (gfm)
19399 if (top && (cap = this.rules.nptable.exec(src))) {
19400 src = src.substring(cap[0].length);
19404 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19405 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19406 cells: cap[3].replace(/\n$/, '').split('\n')
19409 for (i = 0; i < item.align.length; i++) {
19410 if (/^ *-+: *$/.test(item.align[i])) {
19411 item.align[i] = 'right';
19412 } else if (/^ *:-+: *$/.test(item.align[i])) {
19413 item.align[i] = 'center';
19414 } else if (/^ *:-+ *$/.test(item.align[i])) {
19415 item.align[i] = 'left';
19417 item.align[i] = null;
19421 for (i = 0; i < item.cells.length; i++) {
19422 item.cells[i] = item.cells[i].split(/ *\| */);
19425 this.tokens.push(item);
19431 if (cap = this.rules.lheading.exec(src)) {
19432 src = src.substring(cap[0].length);
19435 depth: cap[2] === '=' ? 1 : 2,
19442 if (cap = this.rules.hr.exec(src)) {
19443 src = src.substring(cap[0].length);
19451 if (cap = this.rules.blockquote.exec(src)) {
19452 src = src.substring(cap[0].length);
19455 type: 'blockquote_start'
19458 cap = cap[0].replace(/^ *> ?/gm, '');
19460 // Pass `top` to keep the current
19461 // "toplevel" state. This is exactly
19462 // how markdown.pl works.
19463 this.token(cap, top);
19466 type: 'blockquote_end'
19473 if (cap = this.rules.list.exec(src)) {
19474 src = src.substring(cap[0].length);
19478 type: 'list_start',
19479 ordered: bull.length > 1
19482 // Get each top-level item.
19483 cap = cap[0].match(this.rules.item);
19489 for (; i < l; i++) {
19492 // Remove the list item's bullet
19493 // so it is seen as the next token.
19494 space = item.length;
19495 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
19497 // Outdent whatever the
19498 // list item contains. Hacky.
19499 if (~item.indexOf('\n ')) {
19500 space -= item.length;
19501 item = !this.options.pedantic
19502 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
19503 : item.replace(/^ {1,4}/gm, '');
19506 // Determine whether the next list item belongs here.
19507 // Backpedal if it does not belong in this list.
19508 if (this.options.smartLists && i !== l - 1) {
19509 b = block.bullet.exec(cap[i+1])[0];
19510 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
19511 src = cap.slice(i + 1).join('\n') + src;
19516 // Determine whether item is loose or not.
19517 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
19518 // for discount behavior.
19519 loose = next || /\n\n(?!\s*$)/.test(item);
19521 next = item[item.length-1] === '\n';
19522 if (!loose) loose = next;
19527 ? 'loose_item_start'
19528 : 'list_item_start'
19532 this.token(item, false);
19535 type: 'list_item_end'
19547 if (cap = this.rules.html.exec(src)) {
19548 src = src.substring(cap[0].length);
19550 type: this.options.sanitize
19553 pre: cap[1] === 'pre' || cap[1] === 'script',
19560 if (top && (cap = this.rules.def.exec(src))) {
19561 src = src.substring(cap[0].length);
19562 this.tokens.links[cap[1].toLowerCase()] = {
19570 if (top && (cap = this.rules.table.exec(src))) {
19571 src = src.substring(cap[0].length);
19575 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
19576 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
19577 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
19580 for (i = 0; i < item.align.length; i++) {
19581 if (/^ *-+: *$/.test(item.align[i])) {
19582 item.align[i] = 'right';
19583 } else if (/^ *:-+: *$/.test(item.align[i])) {
19584 item.align[i] = 'center';
19585 } else if (/^ *:-+ *$/.test(item.align[i])) {
19586 item.align[i] = 'left';
19588 item.align[i] = null;
19592 for (i = 0; i < item.cells.length; i++) {
19593 item.cells[i] = item.cells[i]
19594 .replace(/^ *\| *| *\| *$/g, '')
19598 this.tokens.push(item);
19603 // top-level paragraph
19604 if (top && (cap = this.rules.paragraph.exec(src))) {
19605 src = src.substring(cap[0].length);
19608 text: cap[1][cap[1].length-1] === '\n'
19609 ? cap[1].slice(0, -1)
19616 if (cap = this.rules.text.exec(src)) {
19617 // Top-level should never reach here.
19618 src = src.substring(cap[0].length);
19628 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19632 return this.tokens;
19636 * Inline-Level Grammar
19640 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
19641 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
19643 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
19644 link: /^!?\[(inside)\]\(href\)/,
19645 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
19646 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
19647 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
19648 em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
19649 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
19650 br: /^ {2,}\n(?!\s*$)/,
19652 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
19655 inline._inside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
19656 inline._href = /\s*<?([^\s]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
19658 inline.link = replace(inline.link)
19659 ('inside', inline._inside)
19660 ('href', inline._href)
19663 inline.reflink = replace(inline.reflink)
19664 ('inside', inline._inside)
19668 * Normal Inline Grammar
19671 inline.normal = merge({}, inline);
19674 * Pedantic Inline Grammar
19677 inline.pedantic = merge({}, inline.normal, {
19678 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
19679 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
19683 * GFM Inline Grammar
19686 inline.gfm = merge({}, inline.normal, {
19687 escape: replace(inline.escape)('])', '~|])')(),
19688 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
19689 del: /^~~(?=\S)([\s\S]*?\S)~~/,
19690 text: replace(inline.text)
19692 ('|', '|https?://|')
19697 * GFM + Line Breaks Inline Grammar
19700 inline.breaks = merge({}, inline.gfm, {
19701 br: replace(inline.br)('{2,}', '*')(),
19702 text: replace(inline.gfm.text)('{2,}', '*')()
19706 * Inline Lexer & Compiler
19709 function InlineLexer(links, options) {
19710 this.options = options || marked.defaults;
19711 this.links = links;
19712 this.rules = inline.normal;
19716 Error('Tokens array requires a `links` property.');
19719 if (this.options.gfm) {
19720 if (this.options.breaks) {
19721 this.rules = inline.breaks;
19723 this.rules = inline.gfm;
19725 } else if (this.options.pedantic) {
19726 this.rules = inline.pedantic;
19731 * Expose Inline Rules
19734 InlineLexer.rules = inline;
19737 * Static Lexing/Compiling Method
19740 InlineLexer.output = function(src, links, options) {
19741 var inline = new InlineLexer(links, options);
19742 return inline.output(src);
19749 InlineLexer.prototype.output = function(src) {
19758 if (cap = this.rules.escape.exec(src)) {
19759 src = src.substring(cap[0].length);
19765 if (cap = this.rules.autolink.exec(src)) {
19766 src = src.substring(cap[0].length);
19767 if (cap[2] === '@') {
19768 text = cap[1][6] === ':'
19769 ? this.mangle(cap[1].substring(7))
19770 : this.mangle(cap[1]);
19771 href = this.mangle('mailto:') + text;
19773 text = escape(cap[1]);
19785 if (cap = this.rules.url.exec(src)) {
19786 src = src.substring(cap[0].length);
19787 text = escape(cap[1]);
19798 if (cap = this.rules.tag.exec(src)) {
19799 src = src.substring(cap[0].length);
19800 out += this.options.sanitize
19807 if (cap = this.rules.link.exec(src)) {
19808 src = src.substring(cap[0].length);
19809 out += this.outputLink(cap, {
19817 if ((cap = this.rules.reflink.exec(src))
19818 || (cap = this.rules.nolink.exec(src))) {
19819 src = src.substring(cap[0].length);
19820 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
19821 link = this.links[link.toLowerCase()];
19822 if (!link || !link.href) {
19824 src = cap[0].substring(1) + src;
19827 out += this.outputLink(cap, link);
19832 if (cap = this.rules.strong.exec(src)) {
19833 src = src.substring(cap[0].length);
19835 + this.output(cap[2] || cap[1])
19841 if (cap = this.rules.em.exec(src)) {
19842 src = src.substring(cap[0].length);
19844 + this.output(cap[2] || cap[1])
19850 if (cap = this.rules.code.exec(src)) {
19851 src = src.substring(cap[0].length);
19853 + escape(cap[2], true)
19859 if (cap = this.rules.br.exec(src)) {
19860 src = src.substring(cap[0].length);
19866 if (cap = this.rules.del.exec(src)) {
19867 src = src.substring(cap[0].length);
19869 + this.output(cap[1])
19875 if (cap = this.rules.text.exec(src)) {
19876 src = src.substring(cap[0].length);
19877 out += escape(cap[0]);
19883 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19894 InlineLexer.prototype.outputLink = function(cap, link) {
19895 if (cap[0][0] !== '!') {
19897 + escape(link.href)
19901 + escape(link.title)
19905 + this.output(cap[1])
19908 return '<img src="'
19909 + escape(link.href)
19915 + escape(link.title)
19923 * Smartypants Transformations
19926 InlineLexer.prototype.smartypants = function(text) {
19927 if (!this.options.smartypants) return text;
19929 .replace(/--/g, '—')
19930 .replace(/'([^']*)'/g, '‘$1’')
19931 .replace(/"([^"]*)"/g, '“$1”')
19932 .replace(/\.{3}/g, '…');
19939 InlineLexer.prototype.mangle = function(text) {
19945 for (; i < l; i++) {
19946 ch = text.charCodeAt(i);
19947 if (Math.random() > 0.5) {
19948 ch = 'x' + ch.toString(16);
19950 out += '&#' + ch + ';';
19957 * Parsing & Compiling
19960 function Parser(options) {
19963 this.options = options || marked.defaults;
19967 * Static Parse Method
19970 Parser.parse = function(src, options) {
19971 var parser = new Parser(options);
19972 return parser.parse(src);
19979 Parser.prototype.parse = function(src) {
19980 this.inline = new InlineLexer(src.links, this.options);
19981 this.tokens = src.reverse();
19984 while (this.next()) {
19995 Parser.prototype.next = function() {
19996 return this.token = this.tokens.pop();
20000 * Preview Next Token
20003 Parser.prototype.peek = function() {
20004 return this.tokens[this.tokens.length-1] || 0;
20008 * Parse Text Tokens
20011 Parser.prototype.parseText = function() {
20012 var body = this.token.text;
20014 while (this.peek().type === 'text') {
20015 body += '\n' + this.next().text;
20018 return this.inline.output(body);
20022 * Parse Current Token
20025 Parser.prototype.tok = function() {
20026 switch (this.token.type) {
20037 + this.inline.output(this.token.text)
20043 if (this.options.highlight) {
20044 var code = this.options.highlight(this.token.text, this.token.lang);
20045 if (code != null && code !== this.token.text) {
20046 this.token.escaped = true;
20047 this.token.text = code;
20051 if (!this.token.escaped) {
20052 this.token.text = escape(this.token.text, true);
20055 return '<pre><code'
20058 + this.options.langPrefix
20064 + '</code></pre>\n';
20075 body += '<thead>\n<tr>\n';
20076 for (i = 0; i < this.token.header.length; i++) {
20077 heading = this.inline.output(this.token.header[i]);
20078 body += this.token.align[i]
20079 ? '<th align="' + this.token.align[i] + '">' + heading + '</th>\n'
20080 : '<th>' + heading + '</th>\n';
20082 body += '</tr>\n</thead>\n';
20085 body += '<tbody>\n'
20086 for (i = 0; i < this.token.cells.length; i++) {
20087 row = this.token.cells[i];
20089 for (j = 0; j < row.length; j++) {
20090 cell = this.inline.output(row[j]);
20091 body += this.token.align[j]
20092 ? '<td align="' + this.token.align[j] + '">' + cell + '</td>\n'
20093 : '<td>' + cell + '</td>\n';
20097 body += '</tbody>\n';
20103 case 'blockquote_start': {
20106 while (this.next().type !== 'blockquote_end') {
20107 body += this.tok();
20110 return '<blockquote>\n'
20112 + '</blockquote>\n';
20114 case 'list_start': {
20115 var type = this.token.ordered ? 'ol' : 'ul'
20118 while (this.next().type !== 'list_end') {
20119 body += this.tok();
20130 case 'list_item_start': {
20133 while (this.next().type !== 'list_item_end') {
20134 body += this.token.type === 'text'
20143 case 'loose_item_start': {
20146 while (this.next().type !== 'list_item_end') {
20147 body += this.tok();
20155 return !this.token.pre && !this.options.pedantic
20156 ? this.inline.output(this.token.text)
20159 case 'paragraph': {
20161 + this.inline.output(this.token.text)
20176 function escape(html, encode) {
20178 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
20179 .replace(/</g, '<')
20180 .replace(/>/g, '>')
20181 .replace(/"/g, '"')
20182 .replace(/'/g, ''');
20185 function replace(regex, opt) {
20186 regex = regex.source;
20188 return function self(name, val) {
20189 if (!name) return new RegExp(regex, opt);
20190 val = val.source || val;
20191 val = val.replace(/(^|[^\[])\^/g, '$1');
20192 regex = regex.replace(name, val);
20200 function merge(obj) {
20205 for (; i < arguments.length; i++) {
20206 target = arguments[i];
20207 for (key in target) {
20208 if (Object.prototype.hasOwnProperty.call(target, key)) {
20209 obj[key] = target[key];
20221 function marked(src, opt, callback) {
20222 if (callback || typeof opt === 'function') {
20228 if (opt) opt = merge({}, marked.defaults, opt);
20230 var tokens = Lexer.lex(tokens, opt)
20231 , highlight = opt.highlight
20233 , l = tokens.length
20236 if (!highlight || highlight.length < 3) {
20237 return callback(null, Parser.parse(tokens, opt));
20240 var done = function() {
20241 delete opt.highlight;
20242 var out = Parser.parse(tokens, opt);
20243 opt.highlight = highlight;
20244 return callback(null, out);
20247 for (; i < l; i++) {
20249 if (token.type !== 'code') return;
20251 return highlight(token.text, token.lang, function(err, code) {
20252 if (code == null || code === token.text) {
20253 return --pending || done();
20256 token.escaped = true;
20257 --pending || done();
20265 if (opt) opt = merge({}, marked.defaults, opt);
20266 return Parser.parse(Lexer.lex(src, opt), opt);
20268 e.message += '\nPlease report this to https://github.com/chjj/marked.';
20269 if ((opt || marked.defaults).silent) {
20270 return '<p>An error occured:</p><pre>'
20271 + escape(e.message + '', true)
20283 marked.setOptions = function(opt) {
20284 merge(marked.defaults, opt);
20288 marked.defaults = {
20297 langPrefix: 'lang-'
20304 marked.Parser = Parser;
20305 marked.parser = Parser.parse;
20307 marked.Lexer = Lexer;
20308 marked.lexer = Lexer.lex;
20310 marked.InlineLexer = InlineLexer;
20311 marked.inlineLexer = InlineLexer.output;
20313 marked.parse = marked;
20315 if (typeof exports === 'object') {
20316 module.exports = marked;
20317 } else if (typeof define === 'function' && define.amd) {
20318 define(function() { return marked; });
20320 this.marked = marked;
20323 }).call(function() {
20324 return this || (typeof window !== 'undefined' ? window : global);
20328 window.iD = function () {
20329 window.locale.en = iD.data.en;
20330 window.locale.current('en');
20332 var dispatch = d3.dispatch('enter', 'exit', 'change'),
20335 // https://github.com/openstreetmap/iD/issues/772
20336 // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
20338 try { storage = localStorage; } catch (e) {} // eslint-disable-line no-empty
20339 storage = storage || (function() {
20342 getItem: function(k) { return s[k]; },
20343 setItem: function(k, v) { s[k] = v; },
20344 removeItem: function(k) { delete s[k]; }
20348 context.storage = function(k, v) {
20350 if (arguments.length === 1) return storage.getItem(k);
20351 else if (v === null) storage.removeItem(k);
20352 else storage.setItem(k, v);
20354 // localstorage quota exceeded
20355 /* eslint-disable no-console */
20356 if (typeof console !== 'undefined') console.error('localStorage quota exceeded');
20357 /* eslint-enable no-console */
20362 /* Straight accessors. Avoid using these if you can. */
20363 var ui, connection, history;
20364 context.ui = function() { return ui; };
20365 context.connection = function() { return connection; };
20366 context.history = function() { return history; };
20370 function entitiesLoaded(err, result) {
20371 if (!err) history.merge(result.data, result.extent);
20374 context.preauth = function(options) {
20375 connection.switch(options);
20379 context.loadTiles = function(projection, dimensions, callback) {
20380 function done(err, result) {
20381 entitiesLoaded(err, result);
20382 if (callback) callback(err, result);
20384 connection.loadTiles(projection, dimensions, done);
20387 context.loadEntity = function(id, callback) {
20388 function done(err, result) {
20389 entitiesLoaded(err, result);
20390 if (callback) callback(err, result);
20392 connection.loadEntity(id, done);
20395 context.zoomToEntity = function(id, zoomTo) {
20396 if (zoomTo !== false) {
20397 this.loadEntity(id, function(err, result) {
20399 var entity = _.find(result.data, function(e) { return e.id === id; });
20400 if (entity) { map.zoomTo(entity); }
20404 map.on('drawn.zoomToEntity', function() {
20405 if (!context.hasEntity(id)) return;
20406 map.on('drawn.zoomToEntity', null);
20407 context.on('enter.zoomToEntity', null);
20408 context.enter(iD.modes.Select(context, [id]));
20411 context.on('enter.zoomToEntity', function() {
20412 if (mode.id !== 'browse') {
20413 map.on('drawn.zoomToEntity', null);
20414 context.on('enter.zoomToEntity', null);
20419 var minEditableZoom = 16;
20420 context.minEditableZoom = function(_) {
20421 if (!arguments.length) return minEditableZoom;
20422 minEditableZoom = _;
20423 connection.tileZoom(_);
20429 var inIntro = false;
20430 context.inIntro = function(_) {
20431 if (!arguments.length) return inIntro;
20436 context.save = function() {
20437 if (inIntro || (mode && mode.id === 'save') || d3.select('.modal').size()) return;
20439 if (history.hasChanges()) return t('save.unsaved_changes');
20442 context.flush = function() {
20443 context.debouncedSave.cancel();
20444 connection.flush();
20447 _.each(iD.services, function(service) {
20448 var reset = service().reset;
20449 if (reset) reset(context);
20456 context.hasEntity = function(id) {
20457 return history.graph().hasEntity(id);
20459 context.entity = function(id) {
20460 return history.graph().entity(id);
20462 context.childNodes = function(way) {
20463 return history.graph().childNodes(way);
20465 context.geometry = function(id) {
20466 return context.entity(id).geometry(history.graph());
20472 context.mode = function() {
20475 context.enter = function(newMode) {
20478 dispatch.exit(mode);
20483 dispatch.enter(mode);
20486 context.selectedIDs = function() {
20487 if (mode && mode.selectedIDs) {
20488 return mode.selectedIDs();
20496 context.install = function(behavior) {
20497 context.surface().call(behavior);
20499 context.uninstall = function(behavior) {
20500 context.surface().call(behavior.off);
20505 var copyIDs = [], copyGraph;
20506 context.copyGraph = function() { return copyGraph; };
20507 context.copyIDs = function(_) {
20508 if (!arguments.length) return copyIDs;
20510 copyGraph = history.graph();
20517 context.background = function() { return background; };
20522 context.features = function() { return features; };
20523 context.hasHiddenConnections = function(id) {
20524 var graph = history.graph(),
20525 entity = graph.entity(id);
20526 return features.hasHiddenConnections(entity, graph);
20532 context.map = function() { return map; };
20533 context.layers = function() { return map.layers; };
20534 context.surface = function() { return map.surface; };
20535 context.editable = function() { return map.editable(); };
20537 context.surfaceRect = function() {
20538 // Work around a bug in Firefox.
20539 // http://stackoverflow.com/questions/18153989/
20540 // https://bugzilla.mozilla.org/show_bug.cgi?id=530985
20541 return context.surface().node().parentNode.getBoundingClientRect();
20546 var debugTile = false, debugCollision = false;
20547 context.debugTile = function(_) {
20548 if (!arguments.length) return debugTile;
20553 context.debugCollision = function(_) {
20554 if (!arguments.length) return debugCollision;
20555 debugCollision = _;
20563 context.presets = function(_) {
20564 if (!arguments.length) return presets;
20566 iD.areaKeys = presets.areaKeys();
20572 context.imagery = function(_) {
20573 background.load(_);
20579 var container, embed;
20580 context.container = function(_) {
20581 if (!arguments.length) return container;
20583 container.classed('id-container', true);
20586 context.embed = function(_) {
20587 if (!arguments.length) return embed;
20595 context.taginfo = function(_) {
20596 if (!arguments.length) return taginfo;
20603 var assetPath = '';
20604 context.assetPath = function(_) {
20605 if (!arguments.length) return assetPath;
20611 context.assetMap = function(_) {
20612 if (!arguments.length) return assetMap;
20617 context.asset = function(_) {
20618 var filename = assetPath + _;
20619 return assetMap[filename] || filename;
20622 context.imagePath = function(_) {
20623 return context.asset('img/' + _);
20626 var locale, localePath;
20627 context.locale = function(loc, path) {
20631 // Also set iD.detect().locale (unless we detected 'en-us' and openstreetmap wants 'en')..
20632 if (!(loc.toLowerCase() === 'en' && iD.detect().locale.toLowerCase() === 'en-us')) {
20633 iD.detect().locale = loc;
20639 context.loadLocale = function(cb) {
20640 if (locale && locale !== 'en' && iD.data.locales.indexOf(locale) !== -1) {
20641 localePath = localePath || context.asset('locales/' + locale + '.json');
20642 d3.json(localePath, function(err, result) {
20643 window.locale[locale] = result;
20644 window.locale.current(locale);
20655 context.projection = iD.geo.RawMercator();
20657 locale = iD.detect().locale;
20658 if (locale && iD.data.locales.indexOf(locale) === -1) {
20659 locale = locale.split('-')[0];
20662 history = iD.History(context);
20663 context.graph = history.graph;
20664 context.changes = history.changes;
20665 context.intersects = history.intersects;
20667 // Debounce save, since it's a synchronous localStorage write,
20668 // and history changes can happen frequently (e.g. when dragging).
20669 context.debouncedSave = _.debounce(context.save, 350);
20670 function withDebouncedSave(fn) {
20671 return function() {
20672 var result = fn.apply(history, arguments);
20673 context.debouncedSave();
20678 context.perform = withDebouncedSave(history.perform);
20679 context.replace = withDebouncedSave(history.replace);
20680 context.pop = withDebouncedSave(history.pop);
20681 context.overwrite = withDebouncedSave(history.overwrite);
20682 context.undo = withDebouncedSave(history.undo);
20683 context.redo = withDebouncedSave(history.redo);
20685 ui = iD.ui(context);
20687 connection = iD.Connection();
20689 background = iD.Background(context);
20691 features = iD.Features(context);
20693 map = iD.Map(context);
20694 context.mouse = map.mouse;
20695 context.extent = map.extent;
20696 context.pan = map.pan;
20697 context.zoomIn = map.zoomIn;
20698 context.zoomOut = map.zoomOut;
20699 context.zoomInFurther = map.zoomInFurther;
20700 context.zoomOutFurther = map.zoomOutFurther;
20701 context.redrawEnable = map.redrawEnable;
20703 presets = iD.presets();
20705 return d3.rebind(context, dispatch, 'on');
20709 iD.version = '1.9.6';
20714 var ua = navigator.userAgent,
20717 m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
20719 detected.browser = m[1];
20720 detected.version = m[2];
20722 if (!detected.browser) {
20723 m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
20725 detected.browser = 'msie';
20726 detected.version = m[1];
20729 if (!detected.browser) {
20730 m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
20732 detected.browser = 'Opera';
20733 detected.version = m[2];
20736 if (!detected.browser) {
20737 m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
20739 detected.browser = m[1];
20740 detected.version = m[2];
20741 m = ua.match(/version\/([\.\d]+)/i);
20742 if (m !== null) detected.version = m[1];
20745 if (!detected.browser) {
20746 detected.browser = navigator.appName;
20747 detected.version = navigator.appVersion;
20750 // keep major.minor version only..
20751 detected.version = detected.version.split(/\W/).slice(0,2).join('.');
20753 if (detected.browser.toLowerCase() === 'msie') {
20754 detected.ie = true;
20755 detected.browser = 'Internet Explorer';
20756 detected.support = parseFloat(detected.version) >= 11;
20758 detected.ie = false;
20759 detected.support = true;
20762 // Added due to incomplete svg style support. See #715
20763 detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 );
20765 detected.locale = (navigator.languages && navigator.languages.length)
20766 ? navigator.languages[0] : (navigator.language || navigator.userLanguage || 'en-US');
20768 detected.filedrop = (window.FileReader && 'ondrop' in window);
20771 return navigator.userAgent.indexOf(x) !== -1;
20775 detected.os = 'win';
20776 detected.platform = 'Windows';
20778 else if (nav('Mac')) {
20779 detected.os = 'mac';
20780 detected.platform = 'Macintosh';
20782 else if (nav('X11') || nav('Linux')) {
20783 detected.os = 'linux';
20784 detected.platform = 'Linux';
20787 detected.os = 'win';
20788 detected.platform = 'Unknown';
20791 iD.detect = function() { return detected; };
20794 iD.services.mapillary = function() {
20795 var mapillary = {},
20796 dispatch = d3.dispatch('loadedImages', 'loadedSigns'),
20797 apibase = 'https://a.mapillary.com/v2/',
20798 viewercss = 'https://npmcdn.com/mapillary-js@1.3.0/dist/mapillary-js.min.css',
20799 viewerjs = 'https://npmcdn.com/mapillary-js@1.3.0/dist/mapillary-js.min.js',
20800 clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi',
20806 function loadSignStyles(context) {
20807 d3.select('head').selectAll('#traffico')
20811 .attr('id', 'traffico')
20812 .attr('rel', 'stylesheet')
20813 .attr('href', context.asset('traffico/stylesheets/traffico.css'));
20816 function loadSignDefs(context) {
20817 if (iD.services.mapillary.sign_defs) return;
20818 iD.services.mapillary.sign_defs = {};
20820 _.each(['au', 'br', 'ca', 'de', 'us'], function(region) {
20821 d3.json(context.asset('traffico/string-maps/' + region + '-map.json'), function(err, data) {
20823 if (region === 'de') region = 'eu';
20824 iD.services.mapillary.sign_defs[region] = data;
20829 function loadViewer() {
20831 var wrap = d3.select('#content').selectAll('.mapillary-wrap')
20834 var enter = wrap.enter().append('div')
20835 .attr('class', 'mapillary-wrap')
20836 .classed('al', true) // 'al'=left, 'ar'=right
20837 .classed('hidden', true);
20839 enter.append('button')
20840 .attr('class', 'thumb-hide')
20841 .on('click', function () { mapillary.hideViewer(); })
20843 .call(iD.svg.Icon('#icon-close'));
20845 enter.append('div')
20847 .attr('class', 'mly-wrapper')
20848 .classed('active', false);
20850 // mapillary-viewercss
20851 d3.select('head').selectAll('#mapillary-viewercss')
20855 .attr('id', 'mapillary-viewercss')
20856 .attr('rel', 'stylesheet')
20857 .attr('href', viewercss);
20859 // mapillary-viewerjs
20860 d3.select('head').selectAll('#mapillary-viewerjs')
20864 .attr('id', 'mapillary-viewerjs')
20865 .attr('src', viewerjs);
20868 function initViewer(imageKey, context) {
20870 function nodeChanged(d) {
20871 var clicks = iD.services.mapillary.clicks;
20872 var index = clicks.indexOf(d.key);
20873 if (index > -1) { // nodechange initiated from clicking on a marker..
20874 clicks.splice(index, 1);
20875 } else { // nodechange initiated from the Mapillary viewer controls..
20876 var loc = d.apiNavImIm ? [d.apiNavImIm.lon, d.apiNavImIm.lat] : [d.latLon.lon, d.latLon.lat];
20877 context.map().centerEase(loc);
20878 mapillary.setSelectedImage(d.key, false);
20882 if (Mapillary && imageKey) {
20884 baseImageSize: 320,
20893 var viewer = new Mapillary.Viewer('mly', clientId, imageKey, opts);
20894 viewer.on('nodechanged', nodeChanged);
20895 viewer.on('loadingchanged', mapillary.setViewerLoading);
20896 iD.services.mapillary.viewer = viewer;
20900 function abortRequest(i) {
20904 function nearNullIsland(x, y, z) {
20906 var center = Math.pow(2, z - 1),
20907 width = Math.pow(2, z - 6),
20908 min = center - (width / 2),
20909 max = center + (width / 2) - 1;
20910 return x >= min && x <= max && y >= min && y <= max;
20915 function getTiles(projection, dimensions) {
20916 var s = projection.scale() * 2 * Math.PI,
20917 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
20918 ts = 256 * Math.pow(2, z - tileZoom),
20920 s / 2 - projection.translate()[0],
20921 s / 2 - projection.translate()[1]];
20923 return d3.geo.tile()
20924 .scaleExtent([tileZoom, tileZoom])
20927 .translate(projection.translate())()
20928 .map(function(tile) {
20929 var x = tile[0] * ts - origin[0],
20930 y = tile[1] * ts - origin[1];
20933 id: tile.toString(),
20934 extent: iD.geo.Extent(
20935 projection.invert([x, y + ts]),
20936 projection.invert([x + ts, y]))
20942 function loadTiles(which, url, projection, dimensions) {
20943 var tiles = getTiles(projection, dimensions).filter(function(t) {
20944 var xyz = t.id.split(',');
20945 return !nearNullIsland(xyz[0], xyz[1], xyz[2]);
20948 _.filter(which.inflight, function(v, k) {
20949 var wanted = _.find(tiles, function(tile) { return k === (tile.id + ',0'); });
20950 if (!wanted) delete which.inflight[k];
20952 }).map(abortRequest);
20954 tiles.forEach(function(tile) {
20955 loadTilePage(which, url, tile, 0);
20959 function loadTilePage(which, url, tile, page) {
20960 var cache = iD.services.mapillary.cache[which],
20961 id = tile.id + ',' + String(page),
20962 rect = tile.extent.rectangle();
20964 if (cache.loaded[id] || cache.inflight[id]) return;
20966 cache.inflight[id] = d3.json(url +
20971 client_id: clientId,
20976 }), function(err, data) {
20977 cache.loaded[id] = true;
20978 delete cache.inflight[id];
20979 if (err || !data.features || !data.features.length) return;
20982 nextPage = page + 1,
20985 for (var i = 0; i < data.features.length; i++) {
20986 feature = data.features[i];
20987 loc = feature.geometry.coordinates;
20988 d = { key: feature.properties.key, loc: loc };
20989 if (which === 'images') d.ca = feature.properties.ca;
20990 if (which === 'signs') d.signs = feature.properties.rects;
20992 features.push([loc[0], loc[1], loc[0], loc[1], d]);
20995 cache.rtree.load(features);
20997 if (which === 'images') dispatch.loadedImages();
20998 if (which === 'signs') dispatch.loadedSigns();
21000 if (data.features.length === maxResults && nextPage < maxPages) {
21001 loadTilePage(which, url, tile, nextPage);
21007 mapillary.loadImages = function(projection, dimensions) {
21008 var url = apibase + 'search/im/geojson?';
21009 loadTiles('images', url, projection, dimensions);
21012 mapillary.loadSigns = function(context, projection, dimensions) {
21013 var url = apibase + 'search/im/geojson/or?';
21014 loadSignStyles(context);
21015 loadSignDefs(context);
21016 loadTiles('signs', url, projection, dimensions);
21019 mapillary.loadViewer = function() {
21024 // partition viewport into `psize` x `psize` regions
21025 function partitionViewport(psize, projection, dimensions) {
21026 psize = psize || 16;
21027 var cols = d3.range(0, dimensions[0], psize),
21028 rows = d3.range(0, dimensions[1], psize),
21031 rows.forEach(function(y) {
21032 cols.forEach(function(x) {
21033 var min = [x, y + psize],
21034 max = [x + psize, y];
21036 iD.geo.Extent(projection.invert(min), projection.invert(max)));
21043 // no more than `limit` results per partition.
21044 function searchLimited(psize, limit, projection, dimensions, rtree) {
21045 limit = limit || 3;
21047 var partitions = partitionViewport(psize, projection, dimensions);
21048 return _.flatten(_.compact(_.map(partitions, function(extent) {
21049 return rtree.search(extent.rectangle())
21051 .map(function(d) { return d[4]; });
21055 mapillary.images = function(projection, dimensions) {
21056 var psize = 16, limit = 3;
21057 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.images.rtree);
21060 mapillary.signs = function(projection, dimensions) {
21061 var psize = 32, limit = 3;
21062 return searchLimited(psize, limit, projection, dimensions, iD.services.mapillary.cache.signs.rtree);
21065 mapillary.signsSupported = function() {
21066 var detected = iD.detect();
21067 return (!(detected.ie || detected.browser.toLowerCase() === 'safari'));
21070 mapillary.signHTML = function(d) {
21071 if (!iD.services.mapillary.sign_defs) return;
21073 var detectionPackage = d.signs[0].package,
21074 type = d.signs[0].type,
21075 country = detectionPackage.split('_')[1];
21077 return iD.services.mapillary.sign_defs[country][type];
21080 mapillary.showViewer = function() {
21081 d3.select('#content')
21082 .selectAll('.mapillary-wrap')
21083 .classed('hidden', false)
21084 .selectAll('.mly-wrapper')
21085 .classed('active', true);
21090 mapillary.hideViewer = function() {
21091 d3.select('#content')
21092 .selectAll('.mapillary-wrap')
21093 .classed('hidden', true)
21094 .selectAll('.mly-wrapper')
21095 .classed('active', false);
21097 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
21098 .classed('selected', false);
21100 iD.services.mapillary.image = null;
21105 mapillary.setViewerLoading = function(loading) {
21106 var canvas = d3.select('#content')
21107 .selectAll('.mly-wrapper canvas');
21109 if (canvas.empty()) return; // viewer not loaded yet
21111 var cover = d3.select('#content')
21112 .selectAll('.mly-wrapper .Cover');
21114 cover.classed('CoverDone', !loading);
21116 var button = cover.selectAll('.CoverButton')
21117 .data(loading ? [0] : []);
21121 .attr('class', 'CoverButton')
21123 .attr('class', 'uil-ripple-css')
21132 mapillary.updateViewer = function(imageKey, context) {
21133 if (!iD.services.mapillary) return;
21134 if (!imageKey) return;
21136 if (!iD.services.mapillary.viewer) {
21137 initViewer(imageKey, context);
21139 iD.services.mapillary.viewer.moveToKey(imageKey);
21145 mapillary.getSelectedImage = function() {
21146 if (!iD.services.mapillary) return null;
21147 return iD.services.mapillary.image;
21150 mapillary.setSelectedImage = function(imageKey, fromClick) {
21151 if (!iD.services.mapillary) return null;
21153 iD.services.mapillary.image = imageKey;
21155 iD.services.mapillary.clicks.push(imageKey);
21158 d3.selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
21159 .classed('selected', function(d) { return d.key === imageKey; });
21164 mapillary.reset = function() {
21165 var cache = iD.services.mapillary.cache;
21168 _.forEach(cache.images.inflight, abortRequest);
21169 _.forEach(cache.signs.inflight, abortRequest);
21172 iD.services.mapillary.cache = {
21173 images: { inflight: {}, loaded: {}, rtree: rbush() },
21174 signs: { inflight: {}, loaded: {}, rtree: rbush() }
21177 iD.services.mapillary.image = null;
21178 iD.services.mapillary.clicks = [];
21184 if (!iD.services.mapillary.cache) {
21188 return d3.rebind(mapillary, dispatch, 'on');
21190 iD.services.nominatim = function() {
21191 var nominatim = {},
21192 endpoint = 'https://nominatim.openstreetmap.org/reverse?';
21195 nominatim.countryCode = function(location, callback) {
21196 var cache = iD.services.nominatim.cache,
21197 countryCodes = cache.search([location[0], location[1], location[0], location[1]]);
21199 if (countryCodes.length > 0)
21200 return callback(null, countryCodes[0][4]);
21208 }), function(err, result) {
21210 return callback(err);
21211 else if (result && result.error)
21212 return callback(result.error);
21214 var extent = iD.geo.Extent(location).padByMeters(1000);
21216 cache.insert(extent.rectangle().concat(result.address.country_code));
21218 callback(null, result.address.country_code);
21222 nominatim.reset = function() {
21223 iD.services.nominatim.cache = rbush();
21228 if (!iD.services.nominatim.cache) {
21234 iD.services.taginfo = function() {
21236 endpoint = 'https://taginfo.openstreetmap.org/api/4/',
21238 point: 'count_nodes',
21239 vertex: 'count_nodes',
21240 area: 'count_ways',
21251 function sets(parameters, n, o) {
21252 if (parameters.geometry && o[parameters.geometry]) {
21253 parameters[n] = o[parameters.geometry];
21258 function setFilter(parameters) {
21259 return sets(parameters, 'filter', tag_filters);
21262 function setSort(parameters) {
21263 return sets(parameters, 'sortname', tag_sorts);
21266 function clean(parameters) {
21267 return _.omit(parameters, 'geometry', 'debounce');
21270 function filterKeys(type) {
21271 var count_type = type ? 'count_' + type : 'count_all';
21272 return function(d) {
21273 return parseFloat(d[count_type]) > 2500 || d.in_wiki;
21277 function filterMultikeys() {
21278 return function(d) {
21279 return (d.key.match(/:/g) || []).length === 1; // exactly one ':'
21283 function filterValues() {
21284 return function(d) {
21285 if (d.value.match(/[A-Z*;,]/) !== null) return false; // exclude some punctuation, uppercase letters
21286 return parseFloat(d.fraction) > 0.0 || d.in_wiki;
21290 function valKey(d) {
21297 function valKeyDescription(d) {
21300 title: d.description || d.value
21304 // sort keys with ':' lower than keys without ':'
21305 function sortKeys(a, b) {
21306 return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
21307 : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
21311 var debounced = _.debounce(d3.json, 100, true);
21313 function request(url, debounce, callback) {
21314 var cache = iD.services.taginfo.cache;
21317 callback(null, cache[url]);
21318 } else if (debounce) {
21319 debounced(url, done);
21321 d3.json(url, done);
21324 function done(err, data) {
21325 if (!err) cache[url] = data;
21326 callback(err, data);
21330 taginfo.keys = function(parameters, callback) {
21331 var debounce = parameters.debounce;
21332 parameters = clean(setSort(parameters));
21333 request(endpoint + 'keys/all?' +
21334 iD.util.qsString(_.extend({
21336 sortname: 'count_all',
21339 }, parameters)), debounce, function(err, d) {
21340 if (err) return callback(err);
21341 var f = filterKeys(parameters.filter);
21342 callback(null, d.data.filter(f).sort(sortKeys).map(valKey));
21346 taginfo.multikeys = function(parameters, callback) {
21347 var debounce = parameters.debounce;
21348 parameters = clean(setSort(parameters));
21349 request(endpoint + 'keys/all?' +
21350 iD.util.qsString(_.extend({
21352 sortname: 'count_all',
21355 }, parameters)), debounce, function(err, d) {
21356 if (err) return callback(err);
21357 var f = filterMultikeys();
21358 callback(null, d.data.filter(f).map(valKey));
21362 taginfo.values = function(parameters, callback) {
21363 var debounce = parameters.debounce;
21364 parameters = clean(setSort(setFilter(parameters)));
21365 request(endpoint + 'key/values?' +
21366 iD.util.qsString(_.extend({
21368 sortname: 'count_all',
21371 }, parameters)), debounce, function(err, d) {
21372 if (err) return callback(err);
21373 var f = filterValues();
21374 callback(null, d.data.filter(f).map(valKeyDescription));
21378 taginfo.docs = function(parameters, callback) {
21379 var debounce = parameters.debounce;
21380 parameters = clean(setSort(parameters));
21382 var path = 'key/wiki_pages?';
21383 if (parameters.value) path = 'tag/wiki_pages?';
21384 else if (parameters.rtype) path = 'relation/wiki_pages?';
21386 request(endpoint + path + iD.util.qsString(parameters), debounce, function(err, d) {
21387 if (err) return callback(err);
21388 callback(null, d.data);
21392 taginfo.endpoint = function(_) {
21393 if (!arguments.length) return endpoint;
21398 taginfo.reset = function() {
21399 iD.services.taginfo.cache = {};
21404 if (!iD.services.taginfo.cache) {
21410 iD.services.wikidata = function() {
21412 endpoint = 'https://www.wikidata.org/w/api.php?';
21414 // Given a Wikipedia language and article title, return an array of
21415 // corresponding Wikidata entities.
21416 wiki.itemsByTitle = function(lang, title, callback) {
21417 lang = lang || 'en';
21418 d3.jsonp(endpoint + iD.util.qsString({
21419 action: 'wbgetentities',
21421 sites: lang.replace(/-/g, '_') + 'wiki',
21423 languages: 'en', // shrink response by filtering to one language
21424 callback: '{callback}'
21425 }), function(data) {
21426 callback(title, data.entities || {});
21432 iD.services.wikipedia = function() {
21434 endpoint = 'https://en.wikipedia.org/w/api.php?';
21436 wiki.search = function(lang, query, callback) {
21437 lang = lang || 'en';
21438 d3.jsonp(endpoint.replace('en', lang) +
21443 srinfo: 'suggestion',
21445 callback: '{callback}',
21447 }), function(data) {
21448 if (!data.query) return;
21449 callback(query, data.query.search.map(function(d) {
21455 wiki.suggestions = function(lang, query, callback) {
21456 lang = lang || 'en';
21457 d3.jsonp(endpoint.replace('en', lang) +
21459 action: 'opensearch',
21463 callback: '{callback}',
21466 callback(d[0], d[1]);
21470 wiki.translations = function(lang, title, callback) {
21471 d3.jsonp(endpoint.replace('en', lang) +
21476 callback: '{callback}',
21480 var list = d.query.pages[Object.keys(d.query.pages)[0]],
21482 if (list && list.langlinks) {
21483 list.langlinks.forEach(function(d) {
21484 translations[d.lang] = d['*'];
21486 callback(translations);
21495 iD.util.tagText = function(entity) {
21496 return d3.entries(entity.tags).map(function(e) {
21497 return e.key + '=' + e.value;
21501 iD.util.entitySelector = function(ids) {
21502 return ids.length ? '.' + ids.join(',.') : 'nothing';
21505 iD.util.entityOrMemberSelector = function(ids, graph) {
21506 var s = iD.util.entitySelector(ids);
21508 ids.forEach(function(id) {
21509 var entity = graph.hasEntity(id);
21510 if (entity && entity.type === 'relation') {
21511 entity.members.forEach(function(member) {
21512 s += ',.' + member.id;
21520 iD.util.displayName = function(entity) {
21521 var localeName = 'name:' + iD.detect().locale.toLowerCase().split('-')[0];
21522 return entity.tags[localeName] || entity.tags.name || entity.tags.ref;
21525 iD.util.displayType = function(id) {
21527 n: t('inspector.node'),
21528 w: t('inspector.way'),
21529 r: t('inspector.relation')
21533 iD.util.stringQs = function(str) {
21534 return str.split('&').reduce(function(obj, pair){
21535 var parts = pair.split('=');
21536 if (parts.length === 2) {
21537 obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
21543 iD.util.qsString = function(obj, noencode) {
21544 function softEncode(s) {
21545 // encode everything except special characters used in certain hash parameters:
21546 // "/" in map states, ":", ",", {" and "}" in background
21547 return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
21549 return Object.keys(obj).sort().map(function(key) {
21550 return encodeURIComponent(key) + '=' + (
21551 noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
21555 iD.util.prefixDOMProperty = function(property) {
21556 var prefixes = ['webkit', 'ms', 'moz', 'o'],
21558 n = prefixes.length,
21564 property = property.substr(0, 1).toUpperCase() + property.substr(1);
21567 if (prefixes[i] + property in s)
21568 return prefixes[i] + property;
21573 iD.util.prefixCSSProperty = function(property) {
21574 var prefixes = ['webkit', 'ms', 'Moz', 'O'],
21576 n = prefixes.length,
21577 s = document.body.style;
21579 if (property.toLowerCase() in s)
21580 return property.toLowerCase();
21583 if (prefixes[i] + property in s)
21584 return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
21590 iD.util.setTransform = function(el, x, y, scale) {
21591 var prop = iD.util.transformProperty = iD.util.transformProperty || iD.util.prefixCSSProperty('Transform'),
21592 translate = iD.detect().opera ?
21593 'translate(' + x + 'px,' + y + 'px)' :
21594 'translate3d(' + x + 'px,' + y + 'px,0)';
21595 return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
21598 iD.util.getStyle = function(selector) {
21599 for (var i = 0; i < document.styleSheets.length; i++) {
21600 var rules = document.styleSheets[i].rules || document.styleSheets[i].cssRules || [];
21601 for (var k = 0; k < rules.length; k++) {
21602 var selectorText = rules[k].selectorText && rules[k].selectorText.split(', ');
21603 if (_.includes(selectorText, selector)) {
21610 iD.util.editDistance = function(a, b) {
21611 if (a.length === 0) return b.length;
21612 if (b.length === 0) return a.length;
21614 for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
21615 for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
21616 for (i = 1; i <= b.length; i++) {
21617 for (j = 1; j <= a.length; j++) {
21618 if (b.charAt(i-1) === a.charAt(j-1)) {
21619 matrix[i][j] = matrix[i-1][j-1];
21621 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
21622 Math.min(matrix[i][j-1] + 1, // insertion
21623 matrix[i-1][j] + 1)); // deletion
21627 return matrix[b.length][a.length];
21630 // a d3.mouse-alike which
21631 // 1. Only works on HTML elements, not SVG
21632 // 2. Does not cause style recalculation
21633 iD.util.fastMouse = function(container) {
21634 var rect = container.getBoundingClientRect(),
21635 rectLeft = rect.left,
21636 rectTop = rect.top,
21637 clientLeft = +container.clientLeft,
21638 clientTop = +container.clientTop;
21639 return function(e) {
21641 e.clientX - rectLeft - clientLeft,
21642 e.clientY - rectTop - clientTop];
21646 /* eslint-disable no-proto */
21647 iD.util.getPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
21648 /* eslint-enable no-proto */
21650 iD.util.asyncMap = function(inputs, func, callback) {
21651 var remaining = inputs.length,
21655 inputs.forEach(function(d, i) {
21656 func(d, function done(err, data) {
21660 if (!remaining) callback(errors, results);
21665 // wraps an index to an interval [0..length-1]
21666 iD.util.wrap = function(index, length) {
21668 index += Math.ceil(-index/length)*length;
21669 return index % length;
21671 // A per-domain session mutex backed by a cookie and dead man's
21672 // switch. If the session crashes, the mutex will auto-release
21673 // after 5 seconds.
21675 iD.util.SessionMutex = function(name) {
21680 var expires = new Date();
21681 expires.setSeconds(expires.getSeconds() + 5);
21682 document.cookie = name + '=1; expires=' + expires.toUTCString();
21685 mutex.lock = function() {
21686 if (intervalID) return true;
21687 var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
21688 if (cookie) return false;
21690 intervalID = window.setInterval(renew, 4000);
21694 mutex.unlock = function() {
21695 if (!intervalID) return;
21696 document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
21697 clearInterval(intervalID);
21701 mutex.locked = function() {
21702 return !!intervalID;
21707 iD.util.SuggestNames = function(preset, suggestions) {
21708 preset = preset.id.split('/', 2);
21712 return function(value, callback) {
21714 if (value && value.length > 2) {
21715 if (suggestions[k] && suggestions[k][v]) {
21716 for (var sugg in suggestions[k][v]) {
21717 var dist = iD.util.editDistance(value, sugg.substring(0, value.length));
21727 result.sort(function(a, b) {
21728 return a.dist - b.dist;
21731 result = result.slice(0,3);
21737 iD.geo.roundCoords = function(c) {
21738 return [Math.floor(c[0]), Math.floor(c[1])];
21741 iD.geo.interp = function(p1, p2, t) {
21742 return [p1[0] + (p2[0] - p1[0]) * t,
21743 p1[1] + (p2[1] - p1[1]) * t];
21746 // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
21747 // Returns a positive value, if OAB makes a counter-clockwise turn,
21748 // negative for clockwise turn, and zero if the points are collinear.
21749 iD.geo.cross = function(o, a, b) {
21750 return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
21753 // http://jsperf.com/id-dist-optimization
21754 iD.geo.euclideanDistance = function(a, b) {
21755 var x = a[0] - b[0], y = a[1] - b[1];
21756 return Math.sqrt((x * x) + (y * y));
21759 // using WGS84 polar radius (6356752.314245179 m)
21760 // const = 2 * PI * r / 360
21761 iD.geo.latToMeters = function(dLat) {
21762 return dLat * 110946.257617;
21765 // using WGS84 equatorial radius (6378137.0 m)
21766 // const = 2 * PI * r / 360
21767 iD.geo.lonToMeters = function(dLon, atLat) {
21768 return Math.abs(atLat) >= 90 ? 0 :
21769 dLon * 111319.490793 * Math.abs(Math.cos(atLat * (Math.PI/180)));
21772 // using WGS84 polar radius (6356752.314245179 m)
21773 // const = 2 * PI * r / 360
21774 iD.geo.metersToLat = function(m) {
21775 return m / 110946.257617;
21778 // using WGS84 equatorial radius (6378137.0 m)
21779 // const = 2 * PI * r / 360
21780 iD.geo.metersToLon = function(m, atLat) {
21781 return Math.abs(atLat) >= 90 ? 0 :
21782 m / 111319.490793 / Math.abs(Math.cos(atLat * (Math.PI/180)));
21785 iD.geo.offsetToMeters = function(offset) {
21786 var equatRadius = 6356752.314245179,
21787 polarRadius = 6378137.0,
21791 offset[0] * 2 * Math.PI * equatRadius / tileSize,
21792 -offset[1] * 2 * Math.PI * polarRadius / tileSize
21796 iD.geo.metersToOffset = function(meters) {
21797 var equatRadius = 6356752.314245179,
21798 polarRadius = 6378137.0,
21802 meters[0] * tileSize / (2 * Math.PI * equatRadius),
21803 -meters[1] * tileSize / (2 * Math.PI * polarRadius)
21807 // Equirectangular approximation of spherical distances on Earth
21808 iD.geo.sphericalDistance = function(a, b) {
21809 var x = iD.geo.lonToMeters(a[0] - b[0], (a[1] + b[1]) / 2),
21810 y = iD.geo.latToMeters(a[1] - b[1]);
21811 return Math.sqrt((x * x) + (y * y));
21814 iD.geo.edgeEqual = function(a, b) {
21815 return (a[0] === b[0] && a[1] === b[1]) ||
21816 (a[0] === b[1] && a[1] === b[0]);
21819 // Return the counterclockwise angle in the range (-pi, pi)
21820 // between the positive X axis and the line intersecting a and b.
21821 iD.geo.angle = function(a, b, projection) {
21822 a = projection(a.loc);
21823 b = projection(b.loc);
21824 return Math.atan2(b[1] - a[1], b[0] - a[0]);
21827 // Choose the edge with the minimal distance from `point` to its orthogonal
21828 // projection onto that edge, if such a projection exists, or the distance to
21829 // the closest vertex on that edge. Returns an object with the `index` of the
21830 // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
21831 iD.geo.chooseEdge = function(nodes, point, projection) {
21832 var dist = iD.geo.euclideanDistance,
21833 points = nodes.map(function(n) { return projection(n.loc); }),
21837 function dot(p, q) {
21838 return p[0] * q[0] + p[1] * q[1];
21841 for (var i = 0; i < points.length - 1; i++) {
21843 s = [points[i + 1][0] - o[0],
21844 points[i + 1][1] - o[1]],
21845 v = [point[0] - o[0],
21847 proj = dot(v, s) / dot(s, s),
21852 } else if (proj > 1) {
21855 p = [o[0] + proj * s[0], o[1] + proj * s[1]];
21858 var d = dist(p, point);
21862 loc = projection.invert(p);
21873 // Return the intersection point of 2 line segments.
21874 // From https://github.com/pgkelley4/line-segments-intersect
21875 // This uses the vector cross product approach described below:
21876 // http://stackoverflow.com/a/565282/786339
21877 iD.geo.lineIntersection = function(a, b) {
21878 function subtractPoints(point1, point2) {
21879 return [point1[0] - point2[0], point1[1] - point2[1]];
21881 function crossProduct(point1, point2) {
21882 return point1[0] * point2[1] - point1[1] * point2[0];
21885 var p = [a[0][0], a[0][1]],
21886 p2 = [a[1][0], a[1][1]],
21887 q = [b[0][0], b[0][1]],
21888 q2 = [b[1][0], b[1][1]],
21889 r = subtractPoints(p2, p),
21890 s = subtractPoints(q2, q),
21891 uNumerator = crossProduct(subtractPoints(q, p), r),
21892 denominator = crossProduct(r, s);
21894 if (uNumerator && denominator) {
21895 var u = uNumerator / denominator,
21896 t = crossProduct(subtractPoints(q, p), s) / denominator;
21898 if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
21899 return iD.geo.interp(p, p2, t);
21906 iD.geo.pathIntersections = function(path1, path2) {
21907 var intersections = [];
21908 for (var i = 0; i < path1.length - 1; i++) {
21909 for (var j = 0; j < path2.length - 1; j++) {
21910 var a = [ path1[i], path1[i+1] ],
21911 b = [ path2[j], path2[j+1] ],
21912 hit = iD.geo.lineIntersection(a, b);
21913 if (hit) intersections.push(hit);
21916 return intersections;
21919 // Return whether point is contained in polygon.
21921 // `point` should be a 2-item array of coordinates.
21922 // `polygon` should be an array of 2-item arrays of coordinates.
21924 // From https://github.com/substack/point-in-polygon.
21925 // ray-casting algorithm based on
21926 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
21928 iD.geo.pointInPolygon = function(point, polygon) {
21933 for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
21934 var xi = polygon[i][0], yi = polygon[i][1];
21935 var xj = polygon[j][0], yj = polygon[j][1];
21937 var intersect = ((yi > y) !== (yj > y)) &&
21938 (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
21939 if (intersect) inside = !inside;
21945 iD.geo.polygonContainsPolygon = function(outer, inner) {
21946 return _.every(inner, function(point) {
21947 return iD.geo.pointInPolygon(point, outer);
21951 iD.geo.polygonIntersectsPolygon = function(outer, inner, checkSegments) {
21952 function testSegments(outer, inner) {
21953 for (var i = 0; i < outer.length - 1; i++) {
21954 for (var j = 0; j < inner.length - 1; j++) {
21955 var a = [ outer[i], outer[i+1] ],
21956 b = [ inner[j], inner[j+1] ];
21957 if (iD.geo.lineIntersection(a, b)) return true;
21963 function testPoints(outer, inner) {
21964 return _.some(inner, function(point) {
21965 return iD.geo.pointInPolygon(point, outer);
21969 return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
21972 iD.geo.pathLength = function(path) {
21975 for (var i = 0; i < path.length - 1; i++) {
21976 dx = path[i][0] - path[i + 1][0];
21977 dy = path[i][1] - path[i + 1][1];
21978 length += Math.sqrt(dx * dx + dy * dy);
21982 iD.geo.Extent = function geoExtent(min, max) {
21983 if (!(this instanceof iD.geo.Extent)) return new iD.geo.Extent(min, max);
21984 if (min instanceof iD.geo.Extent) {
21986 } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
21990 this[0] = min || [ Infinity, Infinity];
21991 this[1] = max || min || [-Infinity, -Infinity];
21995 iD.geo.Extent.prototype = new Array(2);
21997 _.extend(iD.geo.Extent.prototype, {
21998 equals: function (obj) {
21999 return this[0][0] === obj[0][0] &&
22000 this[0][1] === obj[0][1] &&
22001 this[1][0] === obj[1][0] &&
22002 this[1][1] === obj[1][1];
22005 extend: function(obj) {
22006 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
22007 return iD.geo.Extent([Math.min(obj[0][0], this[0][0]),
22008 Math.min(obj[0][1], this[0][1])],
22009 [Math.max(obj[1][0], this[1][0]),
22010 Math.max(obj[1][1], this[1][1])]);
22013 _extend: function(extent) {
22014 this[0][0] = Math.min(extent[0][0], this[0][0]);
22015 this[0][1] = Math.min(extent[0][1], this[0][1]);
22016 this[1][0] = Math.max(extent[1][0], this[1][0]);
22017 this[1][1] = Math.max(extent[1][1], this[1][1]);
22021 return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
22024 center: function() {
22025 return [(this[0][0] + this[1][0]) / 2,
22026 (this[0][1] + this[1][1]) / 2];
22029 rectangle: function() {
22030 return [this[0][0], this[0][1], this[1][0], this[1][1]];
22033 polygon: function() {
22035 [this[0][0], this[0][1]],
22036 [this[0][0], this[1][1]],
22037 [this[1][0], this[1][1]],
22038 [this[1][0], this[0][1]],
22039 [this[0][0], this[0][1]]
22043 contains: function(obj) {
22044 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
22045 return obj[0][0] >= this[0][0] &&
22046 obj[0][1] >= this[0][1] &&
22047 obj[1][0] <= this[1][0] &&
22048 obj[1][1] <= this[1][1];
22051 intersects: function(obj) {
22052 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
22053 return obj[0][0] <= this[1][0] &&
22054 obj[0][1] <= this[1][1] &&
22055 obj[1][0] >= this[0][0] &&
22056 obj[1][1] >= this[0][1];
22059 intersection: function(obj) {
22060 if (!this.intersects(obj)) return new iD.geo.Extent();
22061 return new iD.geo.Extent([Math.max(obj[0][0], this[0][0]),
22062 Math.max(obj[0][1], this[0][1])],
22063 [Math.min(obj[1][0], this[1][0]),
22064 Math.min(obj[1][1], this[1][1])]);
22067 percentContainedIn: function(obj) {
22068 if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
22069 var a1 = this.intersection(obj).area(),
22072 if (a1 === Infinity || a2 === Infinity || a1 === 0 || a2 === 0) {
22079 padByMeters: function(meters) {
22080 var dLat = iD.geo.metersToLat(meters),
22081 dLon = iD.geo.metersToLon(meters, this.center()[1]);
22082 return iD.geo.Extent(
22083 [this[0][0] - dLon, this[0][1] - dLat],
22084 [this[1][0] + dLon, this[1][1] + dLat]);
22087 toParam: function() {
22088 return this.rectangle().join(',');
22092 iD.geo.Turn = function(turn) {
22093 if (!(this instanceof iD.geo.Turn))
22094 return new iD.geo.Turn(turn);
22095 _.extend(this, turn);
22098 iD.geo.Intersection = function(graph, vertexId) {
22099 var vertex = graph.entity(vertexId),
22100 parentWays = graph.parentWays(vertex),
22104 function addHighway(way, adjacentNodeId) {
22105 if (highways[adjacentNodeId]) {
22106 coincident.push(adjacentNodeId);
22108 highways[adjacentNodeId] = way;
22112 // Pre-split ways that would need to be split in
22113 // order to add a restriction. The real split will
22114 // happen when the restriction is added.
22115 parentWays.forEach(function(way) {
22116 if (!way.tags.highway || way.isArea() || way.isDegenerate())
22119 var isFirst = (vertexId === way.first()),
22120 isLast = (vertexId === way.last()),
22121 isAffix = (isFirst || isLast),
22122 isClosingNode = (isFirst && isLast);
22124 if (isAffix && !isClosingNode) {
22125 var index = (isFirst ? 1 : way.nodes.length - 2);
22126 addHighway(way, way.nodes[index]);
22129 var splitIndex, wayA, wayB, indexA, indexB;
22130 if (isClosingNode) {
22131 splitIndex = Math.ceil(way.nodes.length / 2); // split at midpoint
22132 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
22133 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
22135 indexB = way.nodes.length - 2;
22137 splitIndex = _.indexOf(way.nodes, vertex.id, 1); // split at vertexid
22138 wayA = iD.Way({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
22139 wayB = iD.Way({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
22140 indexA = splitIndex - 1;
22141 indexB = splitIndex + 1;
22143 graph = graph.replace(wayA).replace(wayB);
22144 addHighway(wayA, way.nodes[indexA]);
22145 addHighway(wayB, way.nodes[indexB]);
22149 // remove any ways from this intersection that are coincident
22150 // (i.e. any adjacent node used by more than one intersecting way)
22151 coincident.forEach(function (n) {
22152 delete highways[n];
22156 var intersection = {
22157 highways: highways,
22158 ways: _.values(highways),
22162 intersection.adjacentNodeId = function(fromWayId) {
22163 return _.find(_.keys(highways), function(k) {
22164 return highways[k].id === fromWayId;
22168 intersection.turns = function(fromNodeId) {
22169 var start = highways[fromNodeId];
22173 if (start.first() === vertex.id && start.tags.oneway === 'yes')
22175 if (start.last() === vertex.id && start.tags.oneway === '-1')
22178 function withRestriction(turn) {
22179 graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
22180 if (relation.tags.type !== 'restriction')
22183 var f = relation.memberByRole('from'),
22184 t = relation.memberByRole('to'),
22185 v = relation.memberByRole('via');
22187 if (f && f.id === turn.from.way &&
22188 v && v.id === turn.via.node &&
22189 t && t.id === turn.to.way) {
22190 turn.restriction = relation.id;
22191 } else if (/^only_/.test(relation.tags.restriction) &&
22192 f && f.id === turn.from.way &&
22193 v && v.id === turn.via.node &&
22194 t && t.id !== turn.to.way) {
22195 turn.restriction = relation.id;
22196 turn.indirect_restriction = true;
22200 return iD.geo.Turn(turn);
22205 way: start.id.split(/-(a|b)/)[0]
22207 via = { node: vertex.id },
22210 _.each(highways, function(end, adjacentNodeId) {
22215 if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
22216 turns.push(withRestriction({
22220 node: adjacentNodeId,
22221 way: end.id.split(/-(a|b)/)[0]
22227 if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
22228 turns.push(withRestriction({
22232 node: adjacentNodeId,
22233 way: end.id.split(/-(a|b)/)[0]
22241 if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
22242 turns.push(withRestriction({
22253 return intersection;
22257 iD.geo.inferRestriction = function(graph, from, via, to, projection) {
22258 var fromWay = graph.entity(from.way),
22259 fromNode = graph.entity(from.node),
22260 toWay = graph.entity(to.way),
22261 toNode = graph.entity(to.node),
22262 viaNode = graph.entity(via.node),
22263 fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
22264 (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
22265 toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
22266 (toWay.tags.oneway === '-1' && toWay.last() === via.node),
22267 angle = iD.geo.angle(viaNode, fromNode, projection) -
22268 iD.geo.angle(viaNode, toNode, projection);
22270 angle = angle * 180 / Math.PI;
22275 if (fromNode === toNode)
22276 return 'no_u_turn';
22277 if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
22278 return 'no_u_turn';
22280 return 'no_right_turn';
22282 return 'no_left_turn';
22284 return 'no_straight_on';
22286 // For fixing up rendering of multipolygons with tags on the outer member.
22287 // https://github.com/openstreetmap/iD/issues/613
22288 iD.geo.isSimpleMultipolygonOuterMember = function(entity, graph) {
22289 if (entity.type !== 'way')
22292 var parents = graph.parentRelations(entity);
22293 if (parents.length !== 1)
22296 var parent = parents[0];
22297 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
22300 var members = parent.members, member;
22301 for (var i = 0; i < members.length; i++) {
22302 member = members[i];
22303 if (member.id === entity.id && member.role && member.role !== 'outer')
22304 return false; // Not outer member
22305 if (member.id !== entity.id && (!member.role || member.role === 'outer'))
22306 return false; // Not a simple multipolygon
22312 iD.geo.simpleMultipolygonOuterMember = function(entity, graph) {
22313 if (entity.type !== 'way')
22316 var parents = graph.parentRelations(entity);
22317 if (parents.length !== 1)
22320 var parent = parents[0];
22321 if (!parent.isMultipolygon() || Object.keys(parent.tags).length > 1)
22324 var members = parent.members, member, outerMember;
22325 for (var i = 0; i < members.length; i++) {
22326 member = members[i];
22327 if (!member.role || member.role === 'outer') {
22329 return false; // Not a simple multipolygon
22330 outerMember = member;
22334 return outerMember && graph.hasEntity(outerMember.id);
22337 // Join `array` into sequences of connecting ways.
22339 // Segments which share identical start/end nodes will, as much as possible,
22340 // be connected with each other.
22342 // The return value is a nested array. Each constituent array contains elements
22343 // of `array` which have been determined to connect. Each consitituent array
22344 // also has a `nodes` property whose value is an ordered array of member nodes,
22345 // with appropriate order reversal and start/end coordinate de-duplication.
22347 // Members of `array` must have, at minimum, `type` and `id` properties.
22348 // Thus either an array of `iD.Way`s or a relation member array may be
22351 // If an member has a `tags` property, its tags will be reversed via
22352 // `iD.actions.Reverse` in the output.
22354 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
22355 // false) and non-way members are ignored.
22357 iD.geo.joinWays = function(array, graph) {
22358 var joined = [], member, current, nodes, first, last, i, how, what;
22360 array = array.filter(function(member) {
22361 return member.type === 'way' && graph.hasEntity(member.id);
22364 function resolve(member) {
22365 return graph.childNodes(graph.entity(member.id));
22368 function reverse(member) {
22369 return member.tags ? iD.actions.Reverse(member.id, {reverseOneway: true})(graph).entity(member.id) : member;
22372 while (array.length) {
22373 member = array.shift();
22374 current = [member];
22375 current.nodes = nodes = resolve(member).slice();
22376 joined.push(current);
22378 while (array.length && _.first(nodes) !== _.last(nodes)) {
22379 first = _.first(nodes);
22380 last = _.last(nodes);
22382 for (i = 0; i < array.length; i++) {
22384 what = resolve(member);
22386 if (last === _.first(what)) {
22388 what = what.slice(1);
22390 } else if (last === _.last(what)) {
22392 what = what.slice(0, -1).reverse();
22393 member = reverse(member);
22395 } else if (first === _.last(what)) {
22396 how = nodes.unshift;
22397 what = what.slice(0, -1);
22399 } else if (first === _.first(what)) {
22400 how = nodes.unshift;
22401 what = what.slice(1).reverse();
22402 member = reverse(member);
22410 break; // No more joinable ways.
22412 how.apply(current, [member]);
22413 how.apply(nodes, what);
22415 array.splice(i, 1);
22422 Bypasses features of D3's default projection stream pipeline that are unnecessary:
22423 * Antimeridian clipping
22424 * Spherical rotation
22427 iD.geo.RawMercator = function () {
22428 var project = d3.geo.mercator.raw,
22429 k = 512 / Math.PI, // scale
22430 x = 0, y = 0, // translate
22431 clipExtent = [[0, 0], [0, 0]];
22433 function projection(point) {
22434 point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
22435 return [point[0] * k + x, y - point[1] * k];
22438 projection.invert = function(point) {
22439 point = project.invert((point[0] - x) / k, (y - point[1]) / k);
22440 return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
22443 projection.scale = function(_) {
22444 if (!arguments.length) return k;
22449 projection.translate = function(_) {
22450 if (!arguments.length) return [x, y];
22456 projection.clipExtent = function(_) {
22457 if (!arguments.length) return clipExtent;
22462 projection.stream = d3.geo.transform({
22463 point: function(x, y) {
22464 x = projection([x, y]);
22465 this.stream.point(x[0], x[1]);
22472 iD.actions.AddEntity = function(way) {
22473 return function(graph) {
22474 return graph.replace(way);
22477 iD.actions.AddMember = function(relationId, member, memberIndex) {
22478 return function(graph) {
22479 var relation = graph.entity(relationId);
22481 if (isNaN(memberIndex) && member.type === 'way') {
22482 var members = relation.indexedMembers();
22483 members.push(member);
22485 var joined = iD.geo.joinWays(members, graph);
22486 for (var i = 0; i < joined.length; i++) {
22487 var segment = joined[i];
22488 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
22489 if (segment[j] !== member)
22493 memberIndex = segment[j + 1].index;
22494 } else if (j === segment.length - 1) {
22495 memberIndex = segment[j - 1].index + 1;
22497 memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
22503 return graph.replace(relation.addMember(member, memberIndex));
22506 iD.actions.AddMidpoint = function(midpoint, node) {
22507 return function(graph) {
22508 graph = graph.replace(node.move(midpoint.loc));
22510 var parents = _.intersection(
22511 graph.parentWays(graph.entity(midpoint.edge[0])),
22512 graph.parentWays(graph.entity(midpoint.edge[1])));
22514 parents.forEach(function(way) {
22515 for (var i = 0; i < way.nodes.length - 1; i++) {
22516 if (iD.geo.edgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
22517 graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
22519 // Add only one midpoint on doubled-back segments,
22520 // turning them into self-intersections.
22529 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
22530 iD.actions.AddVertex = function(wayId, nodeId, index) {
22531 return function(graph) {
22532 return graph.replace(graph.entity(wayId).addNode(nodeId, index));
22535 iD.actions.ChangeMember = function(relationId, member, memberIndex) {
22536 return function(graph) {
22537 return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
22540 iD.actions.ChangePreset = function(entityId, oldPreset, newPreset) {
22541 return function(graph) {
22542 var entity = graph.entity(entityId),
22543 geometry = entity.geometry(graph),
22544 tags = entity.tags;
22546 if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
22547 if (newPreset) tags = newPreset.applyTags(tags, geometry);
22549 return graph.replace(entity.update({tags: tags}));
22552 iD.actions.ChangeTags = function(entityId, tags) {
22553 return function(graph) {
22554 var entity = graph.entity(entityId);
22555 return graph.replace(entity.update({tags: tags}));
22558 iD.actions.Circularize = function(wayId, projection, maxAngle) {
22559 maxAngle = (maxAngle || 20) * Math.PI / 180;
22561 var action = function(graph) {
22562 var way = graph.entity(wayId);
22564 if (!way.isConvex(graph)) {
22565 graph = action.makeConvex(graph);
22568 var nodes = _.uniq(graph.childNodes(way)),
22569 keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
22570 points = nodes.map(function(n) { return projection(n.loc); }),
22571 keyPoints = keyNodes.map(function(n) { return projection(n.loc); }),
22572 centroid = (points.length === 2) ? iD.geo.interp(points[0], points[1], 0.5) : d3.geom.polygon(points).centroid(),
22573 radius = d3.median(points, function(p) { return iD.geo.euclideanDistance(centroid, p); }),
22574 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
22577 // we need atleast two key nodes for the algorithm to work
22578 if (!keyNodes.length) {
22579 keyNodes = [nodes[0]];
22580 keyPoints = [points[0]];
22583 if (keyNodes.length === 1) {
22584 var index = nodes.indexOf(keyNodes[0]),
22585 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
22587 keyNodes.push(nodes[oppositeIndex]);
22588 keyPoints.push(points[oppositeIndex]);
22591 // key points and nodes are those connected to the ways,
22592 // they are projected onto the circle, inbetween nodes are moved
22593 // to constant intervals between key nodes, extra inbetween nodes are
22594 // added if necessary.
22595 for (var i = 0; i < keyPoints.length; i++) {
22596 var nextKeyNodeIndex = (i + 1) % keyNodes.length,
22597 startNode = keyNodes[i],
22598 endNode = keyNodes[nextKeyNodeIndex],
22599 startNodeIndex = nodes.indexOf(startNode),
22600 endNodeIndex = nodes.indexOf(endNode),
22601 numberNewPoints = -1,
22602 indexRange = endNodeIndex - startNodeIndex,
22603 distance, totalAngle, eachAngle, startAngle, endAngle,
22604 angle, loc, node, j,
22605 inBetweenNodes = [];
22607 if (indexRange < 0) {
22608 indexRange += nodes.length;
22611 // position this key node
22612 distance = iD.geo.euclideanDistance(centroid, keyPoints[i]);
22613 if (distance === 0) { distance = 1e-4; }
22615 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius,
22616 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
22617 graph = graph.replace(keyNodes[i].move(projection.invert(keyPoints[i])));
22619 // figure out the between delta angle we want to match to
22620 startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
22621 endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
22622 totalAngle = endAngle - startAngle;
22624 // detects looping around -pi/pi
22625 if (totalAngle * sign > 0) {
22626 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
22631 eachAngle = totalAngle / (indexRange + numberNewPoints);
22632 } while (Math.abs(eachAngle) > maxAngle);
22634 // move existing points
22635 for (j = 1; j < indexRange; j++) {
22636 angle = startAngle + j * eachAngle;
22637 loc = projection.invert([
22638 centroid[0] + Math.cos(angle)*radius,
22639 centroid[1] + Math.sin(angle)*radius]);
22641 node = nodes[(j + startNodeIndex) % nodes.length].move(loc);
22642 graph = graph.replace(node);
22645 // add new inbetween nodes if necessary
22646 for (j = 0; j < numberNewPoints; j++) {
22647 angle = startAngle + (indexRange + j) * eachAngle;
22648 loc = projection.invert([
22649 centroid[0] + Math.cos(angle) * radius,
22650 centroid[1] + Math.sin(angle) * radius]);
22652 node = iD.Node({loc: loc});
22653 graph = graph.replace(node);
22655 nodes.splice(endNodeIndex + j, 0, node);
22656 inBetweenNodes.push(node.id);
22659 // Check for other ways that share these keyNodes..
22660 // If keyNodes are adjacent in both ways,
22661 // we can add inBetween nodes to that shared way too..
22662 if (indexRange === 1 && inBetweenNodes.length) {
22663 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
22664 endIndex1 = way.nodes.lastIndexOf(endNode.id),
22665 wayDirection1 = (endIndex1 - startIndex1);
22666 if (wayDirection1 < -1) { wayDirection1 = 1; }
22668 /* eslint-disable no-loop-func */
22669 _.each(_.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
22670 if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
22671 var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
22672 endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
22673 wayDirection2 = (endIndex2 - startIndex2),
22674 insertAt = endIndex2;
22675 if (wayDirection2 < -1) { wayDirection2 = 1; }
22677 if (wayDirection1 !== wayDirection2) {
22678 inBetweenNodes.reverse();
22679 insertAt = startIndex2;
22681 for (j = 0; j < inBetweenNodes.length; j++) {
22682 sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
22684 graph = graph.replace(sharedWay);
22687 /* eslint-enable no-loop-func */
22692 // update the way to have all the new nodes
22693 ids = nodes.map(function(n) { return n.id; });
22696 way = way.update({nodes: ids});
22697 graph = graph.replace(way);
22702 action.makeConvex = function(graph) {
22703 var way = graph.entity(wayId),
22704 nodes = _.uniq(graph.childNodes(way)),
22705 points = nodes.map(function(n) { return projection(n.loc); }),
22706 sign = d3.geom.polygon(points).area() > 0 ? 1 : -1,
22707 hull = d3.geom.hull(points);
22709 // D3 convex hulls go counterclockwise..
22715 for (var i = 0; i < hull.length - 1; i++) {
22716 var startIndex = points.indexOf(hull[i]),
22717 endIndex = points.indexOf(hull[i+1]),
22718 indexRange = (endIndex - startIndex);
22720 if (indexRange < 0) {
22721 indexRange += nodes.length;
22724 // move interior nodes to the surface of the convex hull..
22725 for (var j = 1; j < indexRange; j++) {
22726 var point = iD.geo.interp(hull[i], hull[i+1], j / indexRange),
22727 node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
22728 graph = graph.replace(node);
22734 action.disabled = function(graph) {
22735 if (!graph.entity(wayId).isClosed())
22736 return 'not_closed';
22741 // Connect the ways at the given nodes.
22743 // The last node will survive. All other nodes will be replaced with
22744 // the surviving node in parent ways, and then removed.
22746 // Tags and relation memberships of of non-surviving nodes are merged
22747 // to the survivor.
22749 // This is the inverse of `iD.actions.Disconnect`.
22752 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
22753 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
22755 iD.actions.Connect = function(nodeIds) {
22756 return function(graph) {
22757 var survivor = graph.entity(_.last(nodeIds));
22759 for (var i = 0; i < nodeIds.length - 1; i++) {
22760 var node = graph.entity(nodeIds[i]);
22762 /* eslint-disable no-loop-func */
22763 graph.parentWays(node).forEach(function(parent) {
22764 if (!parent.areAdjacent(node.id, survivor.id)) {
22765 graph = graph.replace(parent.replaceNode(node.id, survivor.id));
22769 graph.parentRelations(node).forEach(function(parent) {
22770 graph = graph.replace(parent.replaceMember(node, survivor));
22772 /* eslint-enable no-loop-func */
22774 survivor = survivor.mergeTags(node.tags);
22775 graph = iD.actions.DeleteNode(node.id)(graph);
22778 graph = graph.replace(survivor);
22783 iD.actions.CopyEntities = function(ids, fromGraph) {
22786 var action = function(graph) {
22787 ids.forEach(function(id) {
22788 fromGraph.entity(id).copy(fromGraph, copies);
22791 for (var id in copies) {
22792 graph = graph.replace(copies[id]);
22798 action.copies = function() {
22804 iD.actions.DeleteMember = function(relationId, memberIndex) {
22805 return function(graph) {
22806 var relation = graph.entity(relationId)
22807 .removeMember(memberIndex);
22809 graph = graph.replace(relation);
22811 if (relation.isDegenerate())
22812 graph = iD.actions.DeleteRelation(relation.id)(graph);
22817 iD.actions.DeleteMultiple = function(ids) {
22819 way: iD.actions.DeleteWay,
22820 node: iD.actions.DeleteNode,
22821 relation: iD.actions.DeleteRelation
22824 var action = function(graph) {
22825 ids.forEach(function(id) {
22826 if (graph.hasEntity(id)) { // It may have been deleted aready.
22827 graph = actions[graph.entity(id).type](id)(graph);
22834 action.disabled = function(graph) {
22835 for (var i = 0; i < ids.length; i++) {
22837 disabled = actions[graph.entity(id).type](id).disabled(graph);
22838 if (disabled) return disabled;
22844 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
22845 iD.actions.DeleteNode = function(nodeId) {
22846 var action = function(graph) {
22847 var node = graph.entity(nodeId);
22849 graph.parentWays(node)
22850 .forEach(function(parent) {
22851 parent = parent.removeNode(nodeId);
22852 graph = graph.replace(parent);
22854 if (parent.isDegenerate()) {
22855 graph = iD.actions.DeleteWay(parent.id)(graph);
22859 graph.parentRelations(node)
22860 .forEach(function(parent) {
22861 parent = parent.removeMembersWithID(nodeId);
22862 graph = graph.replace(parent);
22864 if (parent.isDegenerate()) {
22865 graph = iD.actions.DeleteRelation(parent.id)(graph);
22869 return graph.remove(node);
22872 action.disabled = function() {
22878 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
22879 iD.actions.DeleteRelation = function(relationId) {
22880 function deleteEntity(entity, graph) {
22881 return !graph.parentWays(entity).length &&
22882 !graph.parentRelations(entity).length &&
22883 !entity.hasInterestingTags();
22886 var action = function(graph) {
22887 var relation = graph.entity(relationId);
22889 graph.parentRelations(relation)
22890 .forEach(function(parent) {
22891 parent = parent.removeMembersWithID(relationId);
22892 graph = graph.replace(parent);
22894 if (parent.isDegenerate()) {
22895 graph = iD.actions.DeleteRelation(parent.id)(graph);
22899 _.uniq(_.map(relation.members, 'id')).forEach(function(memberId) {
22900 graph = graph.replace(relation.removeMembersWithID(memberId));
22902 var entity = graph.entity(memberId);
22903 if (deleteEntity(entity, graph)) {
22904 graph = iD.actions.DeleteMultiple([memberId])(graph);
22908 return graph.remove(relation);
22911 action.disabled = function(graph) {
22912 if (!graph.entity(relationId).isComplete(graph))
22913 return 'incomplete_relation';
22918 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
22919 iD.actions.DeleteWay = function(wayId) {
22920 function deleteNode(node, graph) {
22921 return !graph.parentWays(node).length &&
22922 !graph.parentRelations(node).length &&
22923 !node.hasInterestingTags();
22926 var action = function(graph) {
22927 var way = graph.entity(wayId);
22929 graph.parentRelations(way)
22930 .forEach(function(parent) {
22931 parent = parent.removeMembersWithID(wayId);
22932 graph = graph.replace(parent);
22934 if (parent.isDegenerate()) {
22935 graph = iD.actions.DeleteRelation(parent.id)(graph);
22939 _.uniq(way.nodes).forEach(function(nodeId) {
22940 graph = graph.replace(way.removeNode(nodeId));
22942 var node = graph.entity(nodeId);
22943 if (deleteNode(node, graph)) {
22944 graph = graph.remove(node);
22948 return graph.remove(way);
22951 action.disabled = function(graph) {
22952 var disabled = false;
22954 graph.parentRelations(graph.entity(wayId)).forEach(function(parent) {
22955 var type = parent.tags.type,
22956 role = parent.memberById(wayId).role || 'outer';
22957 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
22958 disabled = 'part_of_relation';
22967 iD.actions.DeprecateTags = function(entityId) {
22968 return function(graph) {
22969 var entity = graph.entity(entityId),
22970 newtags = _.clone(entity.tags),
22974 // This handles deprecated tags with a single condition
22975 for (var i = 0; i < iD.data.deprecated.length; i++) {
22977 rule = iD.data.deprecated[i];
22978 var match = _.toPairs(rule.old)[0],
22979 replacements = rule.replace ? _.toPairs(rule.replace) : null;
22981 if (entity.tags[match[0]] && match[1] === '*') {
22983 var value = entity.tags[match[0]];
22984 if (replacements && !newtags[replacements[0][0]]) {
22985 newtags[replacements[0][0]] = value;
22987 delete newtags[match[0]];
22990 } else if (entity.tags[match[0]] === match[1]) {
22991 newtags = _.assign({}, rule.replace || {}, _.omit(newtags, match[0]));
22997 return graph.replace(entity.update({tags: newtags}));
23003 iD.actions.DiscardTags = function(difference) {
23004 return function(graph) {
23005 function discardTags(entity) {
23006 if (!_.isEmpty(entity.tags)) {
23008 _.each(entity.tags, function(v, k) {
23009 if (v) tags[k] = v;
23012 graph = graph.replace(entity.update({
23013 tags: _.omit(tags, iD.data.discarded)
23018 difference.modified().forEach(discardTags);
23019 difference.created().forEach(discardTags);
23024 // Disconect the ways at the given node.
23026 // Optionally, disconnect only the given ways.
23028 // For testing convenience, accepts an ID to assign to the (first) new node.
23029 // Normally, this will be undefined and the way will automatically
23030 // be assigned a new ID.
23032 // This is the inverse of `iD.actions.Connect`.
23035 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
23036 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
23038 iD.actions.Disconnect = function(nodeId, newNodeId) {
23041 var action = function(graph) {
23042 var node = graph.entity(nodeId),
23043 connections = action.connections(graph);
23045 connections.forEach(function(connection) {
23046 var way = graph.entity(connection.wayID),
23047 newNode = iD.Node({id: newNodeId, loc: node.loc, tags: node.tags});
23049 graph = graph.replace(newNode);
23050 if (connection.index === 0 && way.isArea()) {
23051 // replace shared node with shared node..
23052 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
23054 // replace shared node with multiple new nodes..
23055 graph = graph.replace(way.updateNode(newNode.id, connection.index));
23062 action.connections = function(graph) {
23063 var candidates = [],
23065 parentWays = graph.parentWays(graph.entity(nodeId));
23067 parentWays.forEach(function(way) {
23068 if (wayIds && wayIds.indexOf(way.id) === -1) {
23072 if (way.isArea() && (way.nodes[0] === nodeId)) {
23073 candidates.push({wayID: way.id, index: 0});
23075 way.nodes.forEach(function(waynode, index) {
23076 if (waynode === nodeId) {
23077 candidates.push({wayID: way.id, index: index});
23083 return keeping ? candidates : candidates.slice(1);
23086 action.disabled = function(graph) {
23087 var connections = action.connections(graph);
23088 if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
23089 return 'not_connected';
23091 var parentWays = graph.parentWays(graph.entity(nodeId)),
23092 seenRelationIds = {},
23095 parentWays.forEach(function(way) {
23096 if (wayIds && wayIds.indexOf(way.id) === -1)
23099 var relations = graph.parentRelations(way);
23100 relations.forEach(function(relation) {
23101 if (relation.id in seenRelationIds) {
23102 sharedRelation = relation;
23104 seenRelationIds[relation.id] = true;
23109 if (sharedRelation)
23113 action.limitWays = function(_) {
23114 if (!arguments.length) return wayIds;
23121 // Join ways at the end node they share.
23123 // This is the inverse of `iD.actions.Split`.
23126 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
23127 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
23129 iD.actions.Join = function(ids) {
23131 function groupEntitiesByGeometry(graph) {
23132 var entities = ids.map(function(id) { return graph.entity(id); });
23133 return _.extend({line: []}, _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
23136 var action = function(graph) {
23137 var ways = ids.map(graph.entity, graph),
23138 survivor = ways[0];
23140 // Prefer to keep an existing way.
23141 for (var i = 0; i < ways.length; i++) {
23142 if (!ways[i].isNew()) {
23143 survivor = ways[i];
23148 var joined = iD.geo.joinWays(ways, graph)[0];
23150 survivor = survivor.update({nodes: _.map(joined.nodes, 'id')});
23151 graph = graph.replace(survivor);
23153 joined.forEach(function(way) {
23154 if (way.id === survivor.id)
23157 graph.parentRelations(way).forEach(function(parent) {
23158 graph = graph.replace(parent.replaceMember(way, survivor));
23161 survivor = survivor.mergeTags(way.tags);
23163 graph = graph.replace(survivor);
23164 graph = iD.actions.DeleteWay(way.id)(graph);
23170 action.disabled = function(graph) {
23171 var geometries = groupEntitiesByGeometry(graph);
23172 if (ids.length < 2 || ids.length !== geometries.line.length)
23173 return 'not_eligible';
23175 var joined = iD.geo.joinWays(ids.map(graph.entity, graph), graph);
23176 if (joined.length > 1)
23177 return 'not_adjacent';
23179 var nodeIds = _.map(joined[0].nodes, 'id').slice(1, -1),
23182 conflicting = false;
23184 joined[0].forEach(function(way) {
23185 var parents = graph.parentRelations(way);
23186 parents.forEach(function(parent) {
23187 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
23191 for (var k in way.tags) {
23192 if (!(k in tags)) {
23193 tags[k] = way.tags[k];
23194 } else if (tags[k] && iD.interestingTag(k) && tags[k] !== way.tags[k]) {
23195 conflicting = true;
23201 return 'restriction';
23204 return 'conflicting_tags';
23209 iD.actions.Merge = function(ids) {
23210 function groupEntitiesByGeometry(graph) {
23211 var entities = ids.map(function(id) { return graph.entity(id); });
23212 return _.extend({point: [], area: [], line: [], relation: []},
23213 _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
23216 var action = function(graph) {
23217 var geometries = groupEntitiesByGeometry(graph),
23218 target = geometries.area[0] || geometries.line[0],
23219 points = geometries.point;
23221 points.forEach(function(point) {
23222 target = target.mergeTags(point.tags);
23224 graph.parentRelations(point).forEach(function(parent) {
23225 graph = graph.replace(parent.replaceMember(point, target));
23228 graph = graph.remove(point);
23231 graph = graph.replace(target);
23236 action.disabled = function(graph) {
23237 var geometries = groupEntitiesByGeometry(graph);
23238 if (geometries.point.length === 0 ||
23239 (geometries.area.length + geometries.line.length) !== 1 ||
23240 geometries.relation.length !== 0)
23241 return 'not_eligible';
23246 iD.actions.MergePolygon = function(ids, newRelationId) {
23248 function groupEntities(graph) {
23249 var entities = ids.map(function (id) { return graph.entity(id); });
23254 }, _.groupBy(entities, function(entity) {
23255 if (entity.type === 'way' && entity.isClosed()) {
23256 return 'closedWay';
23257 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
23258 return 'multipolygon';
23265 var action = function(graph) {
23266 var entities = groupEntities(graph);
23268 // An array representing all the polygons that are part of the multipolygon.
23270 // Each element is itself an array of objects with an id property, and has a
23271 // locs property which is an array of the locations forming the polygon.
23272 var polygons = entities.multipolygon.reduce(function(polygons, m) {
23273 return polygons.concat(iD.geo.joinWays(m.members, graph));
23274 }, []).concat(entities.closedWay.map(function(d) {
23275 var member = [{id: d.id}];
23276 member.nodes = graph.childNodes(d);
23280 // contained is an array of arrays of boolean values,
23281 // where contained[j][k] is true iff the jth way is
23282 // contained by the kth way.
23283 var contained = polygons.map(function(w, i) {
23284 return polygons.map(function(d, n) {
23285 if (i === n) return null;
23286 return iD.geo.polygonContainsPolygon(
23287 _.map(d.nodes, 'loc'),
23288 _.map(w.nodes, 'loc'));
23292 // Sort all polygons as either outer or inner ways
23296 while (polygons.length) {
23297 extractUncontained(polygons);
23298 polygons = polygons.filter(isContained);
23299 contained = contained.filter(isContained).map(filterContained);
23302 function isContained(d, i) {
23303 return _.some(contained[i]);
23306 function filterContained(d) {
23307 return d.filter(isContained);
23310 function extractUncontained(polygons) {
23311 polygons.forEach(function(d, i) {
23312 if (!isContained(d, i)) {
23313 d.forEach(function(member) {
23317 role: outer ? 'outer' : 'inner'
23325 // Move all tags to one relation
23326 var relation = entities.multipolygon[0] ||
23327 iD.Relation({ id: newRelationId, tags: { type: 'multipolygon' }});
23329 entities.multipolygon.slice(1).forEach(function(m) {
23330 relation = relation.mergeTags(m.tags);
23331 graph = graph.remove(m);
23334 entities.closedWay.forEach(function(way) {
23335 function isThisOuter(m) {
23336 return m.id === way.id && m.role !== 'inner';
23338 if (members.some(isThisOuter)) {
23339 relation = relation.mergeTags(way.tags);
23340 graph = graph.replace(way.update({ tags: {} }));
23344 return graph.replace(relation.update({
23346 tags: _.omit(relation.tags, 'area')
23350 action.disabled = function(graph) {
23351 var entities = groupEntities(graph);
23352 if (entities.other.length > 0 ||
23353 entities.closedWay.length + entities.multipolygon.length < 2)
23354 return 'not_eligible';
23355 if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
23356 return 'incomplete_relation';
23361 iD.actions.MergeRemoteChanges = function(id, localGraph, remoteGraph, formatUser) {
23362 var option = 'safe', // 'safe', 'force_local', 'force_remote'
23366 return _.isFunction(formatUser) ? formatUser(d) : d;
23370 function mergeLocation(remote, target) {
23371 function pointEqual(a, b) {
23372 var epsilon = 1e-6;
23373 return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
23376 if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
23379 if (option === 'force_remote') {
23380 return target.update({loc: remote.loc});
23383 conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
23388 function mergeNodes(base, remote, target) {
23389 if (option === 'force_local' || _.isEqual(target.nodes, remote.nodes)) {
23392 if (option === 'force_remote') {
23393 return target.update({nodes: remote.nodes});
23396 var ccount = conflicts.length,
23397 o = base.nodes || [],
23398 a = target.nodes || [],
23399 b = remote.nodes || [],
23401 hunks = Diff3.diff3_merge(a, o, b, true);
23403 for (var i = 0; i < hunks.length; i++) {
23404 var hunk = hunks[i];
23406 nodes.push.apply(nodes, hunk.ok);
23408 // for all conflicts, we can assume c.a !== c.b
23409 // because `diff3_merge` called with `true` option to exclude false conflicts..
23410 var c = hunk.conflict;
23411 if (_.isEqual(c.o, c.a)) { // only changed remotely
23412 nodes.push.apply(nodes, c.b);
23413 } else if (_.isEqual(c.o, c.b)) { // only changed locally
23414 nodes.push.apply(nodes, c.a);
23415 } else { // changed both locally and remotely
23416 conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
23422 return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
23426 function mergeChildren(targetWay, children, updates, graph) {
23427 function isUsed(node, targetWay) {
23428 var parentWays = _.map(graph.parentWays(node), 'id');
23429 return node.hasInterestingTags() ||
23430 _.without(parentWays, targetWay.id).length > 0 ||
23431 graph.parentRelations(node).length > 0;
23434 var ccount = conflicts.length;
23436 for (var i = 0; i < children.length; i++) {
23437 var id = children[i],
23438 node = graph.hasEntity(id);
23440 // remove unused childNodes..
23441 if (targetWay.nodes.indexOf(id) === -1) {
23442 if (node && !isUsed(node, targetWay)) {
23443 updates.removeIds.push(id);
23448 // restore used childNodes..
23449 var local = localGraph.hasEntity(id),
23450 remote = remoteGraph.hasEntity(id),
23453 if (option === 'force_remote' && remote && remote.visible) {
23454 updates.replacements.push(remote);
23456 } else if (option === 'force_local' && local) {
23457 target = iD.Entity(local);
23459 target = target.update({ version: remote.version });
23461 updates.replacements.push(target);
23463 } else if (option === 'safe' && local && remote && local.version !== remote.version) {
23464 target = iD.Entity(local, { version: remote.version });
23465 if (remote.visible) {
23466 target = mergeLocation(remote, target);
23468 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
23471 if (conflicts.length !== ccount) break;
23472 updates.replacements.push(target);
23480 function updateChildren(updates, graph) {
23481 for (var i = 0; i < updates.replacements.length; i++) {
23482 graph = graph.replace(updates.replacements[i]);
23484 if (updates.removeIds.length) {
23485 graph = iD.actions.DeleteMultiple(updates.removeIds)(graph);
23491 function mergeMembers(remote, target) {
23492 if (option === 'force_local' || _.isEqual(target.members, remote.members)) {
23495 if (option === 'force_remote') {
23496 return target.update({members: remote.members});
23499 conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
23504 function mergeTags(base, remote, target) {
23505 function ignoreKey(k) {
23506 return _.includes(iD.data.discarded, k);
23509 if (option === 'force_local' || _.isEqual(target.tags, remote.tags)) {
23512 if (option === 'force_remote') {
23513 return target.update({tags: remote.tags});
23516 var ccount = conflicts.length,
23517 o = base.tags || {},
23518 a = target.tags || {},
23519 b = remote.tags || {},
23520 keys = _.reject(_.union(_.keys(o), _.keys(a), _.keys(b)), ignoreKey),
23524 for (var i = 0; i < keys.length; i++) {
23527 if (o[k] !== b[k] && a[k] !== b[k]) { // changed remotely..
23528 if (o[k] !== a[k]) { // changed locally..
23529 conflicts.push(t('merge_remote_changes.conflict.tags',
23530 { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
23532 } else { // unchanged locally, accept remote change..
23533 if (b.hasOwnProperty(k)) {
23543 return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
23547 // `graph.base()` is the common ancestor of the two graphs.
23548 // `localGraph` contains user's edits up to saving
23549 // `remoteGraph` contains remote edits to modified nodes
23550 // `graph` must be a descendent of `localGraph` and may include
23551 // some conflict resolution actions performed on it.
23553 // --- ... --- `localGraph` -- ... -- `graph`
23555 // `graph.base()` --- ... --- `remoteGraph`
23557 var action = function(graph) {
23558 var updates = { replacements: [], removeIds: [] },
23559 base = graph.base().entities[id],
23560 local = localGraph.entity(id),
23561 remote = remoteGraph.entity(id),
23562 target = iD.Entity(local, { version: remote.version });
23565 if (!remote.visible) {
23566 if (option === 'force_remote') {
23567 return iD.actions.DeleteMultiple([id])(graph);
23569 } else if (option === 'force_local') {
23570 if (target.type === 'way') {
23571 target = mergeChildren(target, _.uniq(local.nodes), updates, graph);
23572 graph = updateChildren(updates, graph);
23574 return graph.replace(target);
23577 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
23578 return graph; // do nothing
23583 if (target.type === 'node') {
23584 target = mergeLocation(remote, target);
23586 } else if (target.type === 'way') {
23587 // pull in any child nodes that may not be present locally..
23588 graph.rebase(remoteGraph.childNodes(remote), [graph], false);
23589 target = mergeNodes(base, remote, target);
23590 target = mergeChildren(target, _.union(local.nodes, remote.nodes), updates, graph);
23592 } else if (target.type === 'relation') {
23593 target = mergeMembers(remote, target);
23596 target = mergeTags(base, remote, target);
23598 if (!conflicts.length) {
23599 graph = updateChildren(updates, graph).replace(target);
23605 action.withOption = function(opt) {
23610 action.conflicts = function() {
23616 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
23617 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
23618 iD.actions.Move = function(moveIds, tryDelta, projection, cache) {
23619 var delta = tryDelta;
23621 function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
23622 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
23624 function setupCache(graph) {
23625 function canMove(nodeId) {
23626 var parents = _.map(graph.parentWays(graph.entity(nodeId)), 'id');
23627 if (parents.length < 3) return true;
23629 // Don't move a vertex where >2 ways meet, unless all parentWays are moving too..
23630 var parentsMoving = _.all(parents, function(id) { return cache.moving[id]; });
23631 if (!parentsMoving) delete cache.moving[nodeId];
23633 return parentsMoving;
23636 function cacheEntities(ids) {
23637 _.each(ids, function(id) {
23638 if (cache.moving[id]) return;
23639 cache.moving[id] = true;
23641 var entity = graph.hasEntity(id);
23642 if (!entity) return;
23644 if (entity.type === 'node') {
23645 cache.nodes.push(id);
23646 cache.startLoc[id] = entity.loc;
23647 } else if (entity.type === 'way') {
23648 cache.ways.push(id);
23649 cacheEntities(entity.nodes);
23651 cacheEntities(_.map(entity.members, 'id'));
23656 function cacheIntersections(ids) {
23657 function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
23659 _.each(ids, function(id) {
23660 // consider only intersections with 1 moved and 1 unmoved way.
23661 _.each(graph.childNodes(graph.entity(id)), function(node) {
23662 var parents = graph.parentWays(node);
23663 if (parents.length !== 2) return;
23665 var moved = graph.entity(id),
23666 unmoved = _.find(parents, function(way) { return !cache.moving[way.id]; });
23667 if (!unmoved) return;
23669 // exclude ways that are overly connected..
23670 if (_.intersection(moved.nodes, unmoved.nodes).length > 2) return;
23672 if (moved.isArea() || unmoved.isArea()) return;
23674 cache.intersection[node.id] = {
23677 unmovedId: unmoved.id,
23678 movedIsEP: isEndpoint(moved, node.id),
23679 unmovedIsEP: isEndpoint(unmoved, node.id)
23691 cache.intersection = {};
23692 cache.replacedVertex = {};
23693 cache.startLoc = {};
23697 cacheEntities(moveIds);
23698 cacheIntersections(cache.ways);
23699 cache.nodes = _.filter(cache.nodes, canMove);
23706 // Place a vertex where the moved vertex used to be, to preserve way shape..
23707 function replaceMovedVertex(nodeId, wayId, graph, delta) {
23708 var way = graph.entity(wayId),
23709 moved = graph.entity(nodeId),
23710 movedIndex = way.nodes.indexOf(nodeId),
23711 len, prevIndex, nextIndex;
23713 if (way.isClosed()) {
23714 len = way.nodes.length - 1;
23715 prevIndex = (movedIndex + len - 1) % len;
23716 nextIndex = (movedIndex + len + 1) % len;
23718 len = way.nodes.length;
23719 prevIndex = movedIndex - 1;
23720 nextIndex = movedIndex + 1;
23723 var prev = graph.hasEntity(way.nodes[prevIndex]),
23724 next = graph.hasEntity(way.nodes[nextIndex]);
23726 // Don't add orig vertex at endpoint..
23727 if (!prev || !next) return graph;
23729 var key = wayId + '_' + nodeId,
23730 orig = cache.replacedVertex[key];
23733 cache.replacedVertex[key] = orig;
23734 cache.startLoc[orig.id] = cache.startLoc[nodeId];
23739 start = projection(cache.startLoc[nodeId]);
23740 end = projection.invert(vecAdd(start, delta));
23742 end = cache.startLoc[nodeId];
23744 orig = orig.move(end);
23746 var angle = Math.abs(iD.geo.angle(orig, prev, projection) -
23747 iD.geo.angle(orig, next, projection)) * 180 / Math.PI;
23749 // Don't add orig vertex if it would just make a straight line..
23750 if (angle > 175 && angle < 185) return graph;
23752 // Don't add orig vertex if another point is already nearby (within 10m)
23753 if (iD.geo.sphericalDistance(prev.loc, orig.loc) < 10 ||
23754 iD.geo.sphericalDistance(orig.loc, next.loc) < 10) return graph;
23756 // moving forward or backward along way?
23757 var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
23758 p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
23759 d1 = iD.geo.pathLength(p1),
23760 d2 = iD.geo.pathLength(p2),
23761 insertAt = (d1 < d2) ? movedIndex : nextIndex;
23763 // moving around closed loop?
23764 if (way.isClosed() && insertAt === 0) insertAt = len;
23766 way = way.addNode(orig.id, insertAt);
23767 return graph.replace(orig).replace(way);
23770 // Reorder nodes around intersections that have moved..
23771 function unZorroIntersection(intersection, graph) {
23772 var vertex = graph.entity(intersection.nodeId),
23773 way1 = graph.entity(intersection.movedId),
23774 way2 = graph.entity(intersection.unmovedId),
23775 isEP1 = intersection.movedIsEP,
23776 isEP2 = intersection.unmovedIsEP;
23778 // don't move the vertex if it is the endpoint of both ways.
23779 if (isEP1 && isEP2) return graph;
23781 var nodes1 = _.without(graph.childNodes(way1), vertex),
23782 nodes2 = _.without(graph.childNodes(way2), vertex);
23784 if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
23785 if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
23787 var edge1 = !isEP1 && iD.geo.chooseEdge(nodes1, projection(vertex.loc), projection),
23788 edge2 = !isEP2 && iD.geo.chooseEdge(nodes2, projection(vertex.loc), projection),
23791 // snap vertex to nearest edge (or some point between them)..
23792 if (!isEP1 && !isEP2) {
23793 var epsilon = 1e-4, maxIter = 10;
23794 for (var i = 0; i < maxIter; i++) {
23795 loc = iD.geo.interp(edge1.loc, edge2.loc, 0.5);
23796 edge1 = iD.geo.chooseEdge(nodes1, projection(loc), projection);
23797 edge2 = iD.geo.chooseEdge(nodes2, projection(loc), projection);
23798 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
23800 } else if (!isEP1) {
23806 graph = graph.replace(vertex.move(loc));
23808 // if zorro happened, reorder nodes..
23809 if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
23810 way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
23811 graph = graph.replace(way1);
23813 if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
23814 way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
23815 graph = graph.replace(way2);
23822 function cleanupIntersections(graph) {
23823 _.each(cache.intersection, function(obj) {
23824 graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
23825 graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
23826 graph = unZorroIntersection(obj, graph);
23832 // check if moving way endpoint can cross an unmoved way, if so limit delta..
23833 function limitDelta(graph) {
23834 _.each(cache.intersection, function(obj) {
23835 if (!obj.movedIsEP) return;
23837 var node = graph.entity(obj.nodeId),
23838 start = projection(node.loc),
23839 end = vecAdd(start, delta),
23840 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
23841 movedPath = _.map(_.map(movedNodes, 'loc'),
23842 function(loc) { return vecAdd(projection(loc), delta); }),
23843 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
23844 unmovedPath = _.map(_.map(unmovedNodes, 'loc'), projection),
23845 hits = iD.geo.pathIntersections(movedPath, unmovedPath);
23847 for (var i = 0; i < hits.length; i++) {
23848 if (_.isEqual(hits[i], end)) continue;
23849 var edge = iD.geo.chooseEdge(unmovedNodes, end, projection);
23850 delta = vecSub(projection(edge.loc), start);
23856 var action = function(graph) {
23857 if (delta[0] === 0 && delta[1] === 0) return graph;
23861 if (!_.isEmpty(cache.intersection)) {
23865 _.each(cache.nodes, function(id) {
23866 var node = graph.entity(id),
23867 start = projection(node.loc),
23868 end = vecAdd(start, delta);
23869 graph = graph.replace(node.move(projection.invert(end)));
23872 if (!_.isEmpty(cache.intersection)) {
23873 graph = cleanupIntersections(graph);
23879 action.disabled = function(graph) {
23880 function incompleteRelation(id) {
23881 var entity = graph.entity(id);
23882 return entity.type === 'relation' && !entity.isComplete(graph);
23885 if (_.some(moveIds, incompleteRelation))
23886 return 'incomplete_relation';
23889 action.delta = function() {
23895 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
23896 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
23897 iD.actions.MoveNode = function(nodeId, loc) {
23898 return function(graph) {
23899 return graph.replace(graph.entity(nodeId).move(loc));
23902 iD.actions.Noop = function() {
23903 return function(graph) {
23908 * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
23911 iD.actions.Orthogonalize = function(wayId, projection) {
23912 var threshold = 12, // degrees within right or straight to alter
23913 lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
23914 upperThreshold = Math.cos(threshold * Math.PI / 180);
23916 var action = function(graph) {
23917 var way = graph.entity(wayId),
23918 nodes = graph.childNodes(way),
23919 points = _.uniq(nodes).map(function(n) { return projection(n.loc); }),
23920 corner = {i: 0, dotp: 1},
23922 i, j, score, motions;
23924 if (nodes.length === 4) {
23925 for (i = 0; i < 1000; i++) {
23926 motions = points.map(calcMotion);
23927 points[corner.i] = addPoints(points[corner.i],motions[corner.i]);
23928 score = corner.dotp;
23929 if (score < epsilon) {
23934 graph = graph.replace(graph.entity(nodes[corner.i].id)
23935 .move(projection.invert(points[corner.i])));
23938 originalPoints = _.clone(points);
23941 for (i = 0; i < 1000; i++) {
23942 motions = points.map(calcMotion);
23943 for (j = 0; j < motions.length; j++) {
23944 points[j] = addPoints(points[j],motions[j]);
23946 var newScore = squareness(points);
23947 if (newScore < score) {
23948 best = _.clone(points);
23951 if (score < epsilon) {
23958 for (i = 0; i < points.length; i++) {
23959 // only move the points that actually moved
23960 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
23961 graph = graph.replace(graph.entity(nodes[i].id)
23962 .move(projection.invert(points[i])));
23966 // remove empty nodes on straight sections
23967 for (i = 0; i < points.length; i++) {
23968 var node = nodes[i];
23970 if (graph.parentWays(node).length > 1 ||
23971 graph.parentRelations(node).length ||
23972 node.hasInterestingTags()) {
23977 var dotp = normalizedDotProduct(i, points);
23978 if (dotp < -1 + epsilon) {
23979 graph = iD.actions.DeleteNode(nodes[i].id)(graph);
23986 function calcMotion(b, i, array) {
23987 var a = array[(i - 1 + array.length) % array.length],
23988 c = array[(i + 1) % array.length],
23989 p = subtractPoints(a, b),
23990 q = subtractPoints(c, b),
23993 scale = 2 * Math.min(iD.geo.euclideanDistance(p, [0, 0]), iD.geo.euclideanDistance(q, [0, 0]));
23994 p = normalizePoint(p, 1.0);
23995 q = normalizePoint(q, 1.0);
23997 dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
23999 // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
24000 if (array.length > 3) {
24001 if (dotp < -0.707106781186547) {
24004 } else if (dotp && Math.abs(dotp) < corner.dotp) {
24006 corner.dotp = Math.abs(dotp);
24009 return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
24013 function squareness(points) {
24014 return points.reduce(function(sum, val, i, array) {
24015 var dotp = normalizedDotProduct(i, array);
24017 dotp = filterDotProduct(dotp);
24018 return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
24022 function normalizedDotProduct(i, points) {
24023 var a = points[(i - 1 + points.length) % points.length],
24025 c = points[(i + 1) % points.length],
24026 p = subtractPoints(a, b),
24027 q = subtractPoints(c, b);
24029 p = normalizePoint(p, 1.0);
24030 q = normalizePoint(q, 1.0);
24032 return p[0] * q[0] + p[1] * q[1];
24035 function subtractPoints(a, b) {
24036 return [a[0] - b[0], a[1] - b[1]];
24039 function addPoints(a, b) {
24040 return [a[0] + b[0], a[1] + b[1]];
24043 function normalizePoint(point, scale) {
24044 var vector = [0, 0];
24045 var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
24046 if (length !== 0) {
24047 vector[0] = point[0] / length;
24048 vector[1] = point[1] / length;
24051 vector[0] *= scale;
24052 vector[1] *= scale;
24057 function filterDotProduct(dotp) {
24058 if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
24065 action.disabled = function(graph) {
24066 var way = graph.entity(wayId),
24067 nodes = graph.childNodes(way),
24068 points = _.uniq(nodes).map(function(n) { return projection(n.loc); });
24070 if (squareness(points)) {
24074 return 'not_squarish';
24079 // Create a restriction relation for `turn`, which must have the following structure:
24082 // from: { node: <node ID>, way: <way ID> },
24083 // via: { node: <node ID> },
24084 // to: { node: <node ID>, way: <way ID> },
24085 // restriction: <'no_right_turn', 'no_left_turn', etc.>
24088 // This specifies a restriction of type `restriction` when traveling from
24089 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
24090 // (The action does not check that these entities form a valid intersection.)
24092 // If `restriction` is not provided, it is automatically determined by
24093 // iD.geo.inferRestriction.
24095 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
24096 // and `to.node` are used to determine which portion of the split ways become
24097 // members of the restriction.
24099 // For testing convenience, accepts an ID to assign to the new relation.
24100 // Normally, this will be undefined and the relation will automatically
24101 // be assigned a new ID.
24103 iD.actions.RestrictTurn = function(turn, projection, restrictionId) {
24104 return function(graph) {
24105 var from = graph.entity(turn.from.way),
24106 via = graph.entity(turn.via.node),
24107 to = graph.entity(turn.to.way);
24109 function isClosingNode(way, nodeId) {
24110 return nodeId === way.first() && nodeId === way.last();
24113 function split(toOrFrom) {
24114 var newID = toOrFrom.newID || iD.Way().id;
24115 graph = iD.actions.Split(via.id, [newID])
24116 .limitWays([toOrFrom.way])(graph);
24118 var a = graph.entity(newID),
24119 b = graph.entity(toOrFrom.way);
24121 if (a.nodes.indexOf(toOrFrom.node) !== -1) {
24128 if (!from.affix(via.id) || isClosingNode(from, via.id)) {
24129 if (turn.from.node === turn.to.node) {
24131 from = to = split(turn.from)[0];
24132 } else if (turn.from.way === turn.to.way) {
24133 // Straight-on or circular
24134 var s = split(turn.from);
24139 from = split(turn.from)[0];
24143 if (!to.affix(via.id) || isClosingNode(to, via.id)) {
24144 to = split(turn.to)[0];
24147 return graph.replace(iD.Relation({
24150 type: 'restriction',
24151 restriction: turn.restriction ||
24152 iD.geo.inferRestriction(
24160 {id: from.id, type: 'way', role: 'from'},
24161 {id: via.id, type: 'node', role: 'via'},
24162 {id: to.id, type: 'way', role: 'to'}
24168 Order the nodes of a way in reverse order and reverse any direction dependent tags
24169 other than `oneway`. (We assume that correcting a backwards oneway is the primary
24170 reason for reversing a way.)
24172 The following transforms are performed:
24175 *:right=* ⟺ *:left=*
24176 *:forward=* ⟺ *:backward=*
24177 direction=up ⟺ direction=down
24178 incline=up ⟺ incline=down
24182 role=forward ⟺ role=backward
24183 role=north ⟺ role=south
24184 role=east ⟺ role=west
24186 In addition, numeric-valued `incline` tags are negated.
24188 The JOSM implementation was used as a guide, but transformations that were of unclear benefit
24189 or adjusted tags that don't seem to be used in practice were omitted.
24192 http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
24193 http://wiki.openstreetmap.org/wiki/Key:direction#Steps
24194 http://wiki.openstreetmap.org/wiki/Key:incline
24195 http://wiki.openstreetmap.org/wiki/Route#Members
24196 http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
24198 iD.actions.Reverse = function(wayId, options) {
24199 var replacements = [
24200 [/:right$/, ':left'], [/:left$/, ':right'],
24201 [/:forward$/, ':backward'], [/:backward$/, ':forward']
24203 numeric = /^([+\-]?)(?=[\d.])/,
24205 forward: 'backward',
24206 backward: 'forward',
24213 function reverseKey(key) {
24214 for (var i = 0; i < replacements.length; ++i) {
24215 var replacement = replacements[i];
24216 if (replacement[0].test(key)) {
24217 return key.replace(replacement[0], replacement[1]);
24223 function reverseValue(key, value) {
24224 if (key === 'incline' && numeric.test(value)) {
24225 return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
24226 } else if (key === 'incline' || key === 'direction') {
24227 return {up: 'down', down: 'up'}[value] || value;
24228 } else if (options && options.reverseOneway && key === 'oneway') {
24229 return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
24231 return {left: 'right', right: 'left'}[value] || value;
24235 return function(graph) {
24236 var way = graph.entity(wayId),
24237 nodes = way.nodes.slice().reverse(),
24238 tags = {}, key, role;
24240 for (key in way.tags) {
24241 tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
24244 graph.parentRelations(way).forEach(function(relation) {
24245 relation.members.forEach(function(member, index) {
24246 if (member.id === way.id && (role = roleReversals[member.role])) {
24247 relation = relation.updateMember({role: role}, index);
24248 graph = graph.replace(relation);
24253 return graph.replace(way.update({nodes: nodes, tags: tags}));
24256 iD.actions.Revert = function(id) {
24258 var action = function(graph) {
24259 var entity = graph.hasEntity(id),
24260 base = graph.base().entities[id];
24262 if (entity && !base) { // entity will be removed..
24263 if (entity.type === 'node') {
24264 graph.parentWays(entity)
24265 .forEach(function(parent) {
24266 parent = parent.removeNode(id);
24267 graph = graph.replace(parent);
24269 if (parent.isDegenerate()) {
24270 graph = iD.actions.DeleteWay(parent.id)(graph);
24275 graph.parentRelations(entity)
24276 .forEach(function(parent) {
24277 parent = parent.removeMembersWithID(id);
24278 graph = graph.replace(parent);
24280 if (parent.isDegenerate()) {
24281 graph = iD.actions.DeleteRelation(parent.id)(graph);
24286 return graph.revert(id);
24291 iD.actions.RotateWay = function(wayId, pivot, angle, projection) {
24292 return function(graph) {
24293 return graph.update(function(graph) {
24294 var way = graph.entity(wayId);
24296 _.uniq(way.nodes).forEach(function(id) {
24298 var node = graph.entity(id),
24299 point = projection(node.loc),
24302 radial[0] = point[0] - pivot[0];
24303 radial[1] = point[1] - pivot[1];
24306 radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + pivot[0],
24307 radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + pivot[1]
24310 graph = graph.replace(node.move(projection.invert(point)));
24317 // Split a way at the given node.
24319 // Optionally, split only the given ways, if multiple ways share
24322 // This is the inverse of `iD.actions.Join`.
24324 // For testing convenience, accepts an ID to assign to the new way.
24325 // Normally, this will be undefined and the way will automatically
24326 // be assigned a new ID.
24329 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
24331 iD.actions.Split = function(nodeId, newWayIds) {
24334 // if the way is closed, we need to search for a partner node
24335 // to split the way at.
24337 // The following looks for a node that is both far away from
24338 // the initial node in terms of way segment length and nearby
24339 // in terms of beeline-distance. This assures that areas get
24340 // split on the most "natural" points (independent of the number
24342 // For example: bone-shaped areas get split across their waist
24343 // line, circles across the diameter.
24344 function splitArea(nodes, idxA, graph) {
24345 var lengths = new Array(nodes.length),
24351 function wrap(index) {
24352 return iD.util.wrap(index, nodes.length);
24355 function dist(nA, nB) {
24356 return iD.geo.sphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
24359 // calculate lengths
24361 for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
24362 length += dist(nodes[i], nodes[wrap(i-1)]);
24363 lengths[i] = length;
24367 for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
24368 length += dist(nodes[i], nodes[wrap(i+1)]);
24369 if (length < lengths[i])
24370 lengths[i] = length;
24373 // determine best opposite node to split
24374 for (i = 0; i < nodes.length; i++) {
24375 var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
24385 function split(graph, wayA, newWayId) {
24386 var wayB = iD.Way({id: newWayId, tags: wayA.tags}),
24389 isArea = wayA.isArea(),
24390 isOuter = iD.geo.isSimpleMultipolygonOuterMember(wayA, graph);
24392 if (wayA.isClosed()) {
24393 var nodes = wayA.nodes.slice(0, -1),
24394 idxA = _.indexOf(nodes, nodeId),
24395 idxB = splitArea(nodes, idxA, graph);
24398 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
24399 nodesB = nodes.slice(idxB, idxA + 1);
24401 nodesA = nodes.slice(idxA, idxB + 1);
24402 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
24405 var idx = _.indexOf(wayA.nodes, nodeId, 1);
24406 nodesA = wayA.nodes.slice(0, idx + 1);
24407 nodesB = wayA.nodes.slice(idx);
24410 wayA = wayA.update({nodes: nodesA});
24411 wayB = wayB.update({nodes: nodesB});
24413 graph = graph.replace(wayA);
24414 graph = graph.replace(wayB);
24416 graph.parentRelations(wayA).forEach(function(relation) {
24417 if (relation.isRestriction()) {
24418 var via = relation.memberByRole('via');
24419 if (via && wayB.contains(via.id)) {
24420 relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
24421 graph = graph.replace(relation);
24424 if (relation === isOuter) {
24425 graph = graph.replace(relation.mergeTags(wayA.tags));
24426 graph = graph.replace(wayA.update({tags: {}}));
24427 graph = graph.replace(wayB.update({tags: {}}));
24433 role: relation.memberById(wayA.id).role
24436 graph = iD.actions.AddMember(relation.id, member)(graph);
24440 if (!isOuter && isArea) {
24441 var multipolygon = iD.Relation({
24442 tags: _.extend({}, wayA.tags, {type: 'multipolygon'}),
24444 {id: wayA.id, role: 'outer', type: 'way'},
24445 {id: wayB.id, role: 'outer', type: 'way'}
24448 graph = graph.replace(multipolygon);
24449 graph = graph.replace(wayA.update({tags: {}}));
24450 graph = graph.replace(wayB.update({tags: {}}));
24456 var action = function(graph) {
24457 var candidates = action.ways(graph);
24458 for (var i = 0; i < candidates.length; i++) {
24459 graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
24464 action.ways = function(graph) {
24465 var node = graph.entity(nodeId),
24466 parents = graph.parentWays(node),
24467 hasLines = _.some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
24469 return parents.filter(function(parent) {
24470 if (wayIds && wayIds.indexOf(parent.id) === -1)
24473 if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
24476 if (parent.isClosed()) {
24480 for (var i = 1; i < parent.nodes.length - 1; i++) {
24481 if (parent.nodes[i] === nodeId) {
24490 action.disabled = function(graph) {
24491 var candidates = action.ways(graph);
24492 if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
24493 return 'not_eligible';
24496 action.limitWays = function(_) {
24497 if (!arguments.length) return wayIds;
24505 * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
24508 iD.actions.Straighten = function(wayId, projection) {
24509 function positionAlongWay(n, s, e) {
24510 return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1]))/
24511 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
24514 var action = function(graph) {
24515 var way = graph.entity(wayId),
24516 nodes = graph.childNodes(way),
24517 points = nodes.map(function(n) { return projection(n.loc); }),
24518 startPoint = points[0],
24519 endPoint = points[points.length-1],
24523 for (i = 1; i < points.length-1; i++) {
24524 var node = nodes[i],
24527 if (graph.parentWays(node).length > 1 ||
24528 graph.parentRelations(node).length ||
24529 node.hasInterestingTags()) {
24531 var u = positionAlongWay(point, startPoint, endPoint),
24532 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
24533 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]);
24535 graph = graph.replace(graph.entity(node.id)
24536 .move(projection.invert([p0, p1])));
24539 if (toDelete.indexOf(node) === -1) {
24540 toDelete.push(node);
24545 for (i = 0; i < toDelete.length; i++) {
24546 graph = iD.actions.DeleteNode(toDelete[i].id)(graph);
24552 action.disabled = function(graph) {
24553 // check way isn't too bendy
24554 var way = graph.entity(wayId),
24555 nodes = graph.childNodes(way),
24556 points = nodes.map(function(n) { return projection(n.loc); }),
24557 startPoint = points[0],
24558 endPoint = points[points.length-1],
24559 threshold = 0.2 * Math.sqrt(Math.pow(startPoint[0] - endPoint[0], 2) + Math.pow(startPoint[1] - endPoint[1], 2)),
24562 if (threshold === 0) {
24563 return 'too_bendy';
24566 for (i = 1; i < points.length-1; i++) {
24567 var point = points[i],
24568 u = positionAlongWay(point, startPoint, endPoint),
24569 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
24570 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
24571 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
24573 // to bendy if point is off by 20% of total start/end distance in projected space
24574 if (isNaN(dist) || dist > threshold) {
24575 return 'too_bendy';
24582 // Remove the effects of `turn.restriction` on `turn`, which must have the
24583 // following structure:
24586 // from: { node: <node ID>, way: <way ID> },
24587 // via: { node: <node ID> },
24588 // to: { node: <node ID>, way: <way ID> },
24589 // restriction: <relation ID>
24592 // In the simple case, `restriction` is a reference to a `no_*` restriction
24593 // on the turn itself. In this case, it is simply deleted.
24595 // The more complex case is where `restriction` references an `only_*`
24596 // restriction on a different turn in the same intersection. In that case,
24597 // that restriction is also deleted, but at the same time restrictions on
24598 // the turns other than the first two are created.
24600 iD.actions.UnrestrictTurn = function(turn) {
24601 return function(graph) {
24602 return iD.actions.DeleteRelation(turn.restriction)(graph);
24606 iD.behavior.AddWay = function(context) {
24607 var event = d3.dispatch('start', 'startFromWay', 'startFromNode'),
24608 draw = iD.behavior.Draw(context);
24610 var addWay = function(surface) {
24611 draw.on('click', event.start)
24612 .on('clickWay', event.startFromWay)
24613 .on('clickNode', event.startFromNode)
24614 .on('cancel', addWay.cancel)
24615 .on('finish', addWay.cancel);
24618 .dblclickEnable(false);
24620 surface.call(draw);
24623 addWay.off = function(surface) {
24624 surface.call(draw.off);
24627 addWay.cancel = function() {
24628 window.setTimeout(function() {
24629 context.map().dblclickEnable(true);
24632 context.enter(iD.modes.Browse(context));
24635 addWay.tail = function(text) {
24640 return d3.rebind(addWay, event, 'on');
24642 iD.behavior.Breathe = function() {
24643 var duration = 800,
24644 selector = '.selected.shadow, .selected .shadow',
24645 selected = d3.select(null),
24650 function reset(selection) {
24652 .style('stroke-opacity', null)
24653 .style('stroke-width', null)
24654 .style('fill-opacity', null)
24658 function setAnimationParams(transition, fromTo) {
24660 .style('stroke-opacity', function(d) { return params[d.id][fromTo].opacity; })
24661 .style('stroke-width', function(d) { return params[d.id][fromTo].width; })
24662 .style('fill-opacity', function(d) { return params[d.id][fromTo].opacity; })
24663 .style('r', function(d) { return params[d.id][fromTo].width; });
24666 function calcAnimationParams(selection) {
24669 .each(function(d) {
24670 var s = d3.select(this),
24671 tag = s.node().tagName,
24672 p = {'from': {}, 'to': {}},
24675 // determine base opacity and width
24676 if (tag === 'circle') {
24677 opacity = parseFloat(s.style('fill-opacity') || 0.5);
24678 width = parseFloat(s.style('r') || 15.5);
24680 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
24681 width = parseFloat(s.style('stroke-width') || 10);
24684 // calculate from/to interpolation params..
24686 p.from.opacity = opacity * 0.6;
24687 p.to.opacity = opacity * 1.25;
24688 p.from.width = width * 0.9;
24689 p.to.width = width * (tag === 'circle' ? 1.5 : 1.25);
24694 function run(surface, fromTo) {
24695 var toFrom = (fromTo === 'from' ? 'to': 'from'),
24696 currSelected = surface.selectAll(selector),
24697 currClassed = surface.attr('class'),
24700 if (done || currSelected.empty()) {
24701 selected.call(reset);
24705 if (!_.isEqual(currSelected, selected) || currClassed !== classed) {
24706 selected.call(reset);
24707 classed = currClassed;
24708 selected = currSelected.call(calcAnimationParams);
24713 .call(setAnimationParams, fromTo)
24714 .duration(duration)
24715 .each(function() { ++n; })
24716 .each('end', function() {
24717 if (!--n) { // call once
24718 surface.call(run, toFrom);
24723 var breathe = function(surface) {
24725 d3.timer(function() {
24726 if (done) return true;
24728 var currSelected = surface.selectAll(selector);
24729 if (currSelected.empty()) return false;
24731 surface.call(run, 'from');
24736 breathe.off = function() {
24747 iD.behavior.Copy = function(context) {
24748 var keybinding = d3.keybinding('copy');
24750 function groupEntities(ids, graph) {
24751 var entities = ids.map(function (id) { return graph.entity(id); });
24752 return _.extend({relation: [], way: [], node: []},
24753 _.groupBy(entities, function(entity) { return entity.type; }));
24756 function getDescendants(id, graph, descendants) {
24757 var entity = graph.entity(id),
24760 descendants = descendants || {};
24762 if (entity.type === 'relation') {
24763 children = _.map(entity.members, 'id');
24764 } else if (entity.type === 'way') {
24765 children = entity.nodes;
24770 for (i = 0; i < children.length; i++) {
24771 if (!descendants[children[i]]) {
24772 descendants[children[i]] = true;
24773 descendants = getDescendants(children[i], graph, descendants);
24777 return descendants;
24780 function doCopy() {
24781 d3.event.preventDefault();
24782 if (context.inIntro()) return;
24784 var graph = context.graph(),
24785 selected = groupEntities(context.selectedIDs(), graph),
24790 for (i = 0; i < selected.relation.length; i++) {
24791 entity = selected.relation[i];
24792 if (!skip[entity.id] && entity.isComplete(graph)) {
24793 canCopy.push(entity.id);
24794 skip = getDescendants(entity.id, graph, skip);
24797 for (i = 0; i < selected.way.length; i++) {
24798 entity = selected.way[i];
24799 if (!skip[entity.id]) {
24800 canCopy.push(entity.id);
24801 skip = getDescendants(entity.id, graph, skip);
24804 for (i = 0; i < selected.node.length; i++) {
24805 entity = selected.node[i];
24806 if (!skip[entity.id]) {
24807 canCopy.push(entity.id);
24811 context.copyIDs(canCopy);
24815 keybinding.on(iD.ui.cmd('⌘C'), doCopy);
24816 d3.select(document).call(keybinding);
24820 copy.off = function() {
24821 d3.select(document).call(keybinding.off);
24827 `iD.behavior.drag` is like `d3.behavior.drag`, with the following differences:
24829 * The `origin` function is expected to return an [x, y] tuple rather than an
24831 * The events are `start`, `move`, and `end`.
24832 (https://github.com/mbostock/d3/issues/563)
24833 * The `start` event is not dispatched until the first cursor movement occurs.
24834 (https://github.com/mbostock/d3/pull/368)
24835 * The `move` event has a `point` and `delta` [x, y] tuple properties rather
24836 than `x`, `y`, `dx`, and `dy` properties.
24837 * The `end` event is not dispatched if no movement occurs.
24838 * An `off` function is available that unbinds the drag's internal event handlers.
24839 * Delegation is supported via the `delegate` function.
24842 iD.behavior.drag = function() {
24843 function d3_eventCancel() {
24844 d3.event.stopPropagation();
24845 d3.event.preventDefault();
24848 var event = d3.dispatch('start', 'move', 'end'),
24852 event_, target, surface;
24854 event.of = function(thiz, argumentz) {
24855 return function(e1) {
24856 var e0 = e1.sourceEvent = d3.event;
24860 event[e1.type].apply(thiz, argumentz);
24867 var d3_event_userSelectProperty = iD.util.prefixCSSProperty('UserSelect'),
24868 d3_event_userSelectSuppress = d3_event_userSelectProperty ?
24870 var selection = d3.selection(),
24871 select = selection.style(d3_event_userSelectProperty);
24872 selection.style(d3_event_userSelectProperty, 'none');
24873 return function () {
24874 selection.style(d3_event_userSelectProperty, select);
24878 var w = d3.select(window).on('selectstart.' + type, d3_eventCancel);
24879 return function () {
24880 w.on('selectstart.' + type, null);
24884 function mousedown() {
24886 event_ = event.of(target, arguments);
24887 var eventTarget = d3.event.target,
24888 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
24892 selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
24894 var w = d3.select(window)
24895 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
24896 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
24899 offset = origin.apply(target, arguments);
24900 offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
24905 if (touchId === null) d3.event.stopPropagation();
24908 var p = target.parentNode || surface;
24909 return touchId !== null ? d3.touches(p).filter(function(p) {
24910 return p.identifier === touchId;
24911 })[0] : d3.mouse(p);
24914 function dragmove() {
24917 dx = p[0] - origin_[0],
24918 dy = p[1] - origin_[1];
24920 if (dx === 0 && dy === 0)
24935 point: [p[0] + offset[0], p[1] + offset[1]],
24940 function dragend() {
24947 if (d3.event.target === eventTarget) w.on('click.drag', click, true);
24950 w.on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
24951 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
24957 w.on('click.drag', null);
24961 function drag(selection) {
24962 var matchesSelector = iD.util.prefixDOMProperty('matchesSelector'),
24963 delegate = mousedown;
24966 delegate = function() {
24968 target = d3.event.target;
24969 for (; target && target !== root; target = target.parentNode) {
24970 if (target[matchesSelector](selector) &&
24971 (!filter || filter(target.__data__))) {
24972 return mousedown.call(target, target.__data__);
24978 selection.on('mousedown.drag' + selector, delegate)
24979 .on('touchstart.drag' + selector, delegate);
24982 drag.off = function(selection) {
24983 selection.on('mousedown.drag' + selector, null)
24984 .on('touchstart.drag' + selector, null);
24987 drag.delegate = function(_) {
24988 if (!arguments.length) return selector;
24993 drag.filter = function(_) {
24994 if (!arguments.length) return origin;
24999 drag.origin = function (_) {
25000 if (!arguments.length) return origin;
25005 drag.cancel = function() {
25007 .on('mousemove.drag', null)
25008 .on('mouseup.drag', null);
25012 drag.target = function() {
25013 if (!arguments.length) return target;
25014 target = arguments[0];
25015 event_ = event.of(target, Array.prototype.slice.call(arguments, 1));
25019 drag.surface = function() {
25020 if (!arguments.length) return surface;
25021 surface = arguments[0];
25025 return d3.rebind(drag, event, 'on');
25027 iD.behavior.Draw = function(context) {
25028 var event = d3.dispatch('move', 'click', 'clickWay',
25029 'clickNode', 'undo', 'cancel', 'finish'),
25030 keybinding = d3.keybinding('draw'),
25031 hover = iD.behavior.Hover(context)
25033 .on('hover', context.ui().sidebar.hover),
25034 tail = iD.behavior.Tail(),
25035 edit = iD.behavior.Edit(context),
25036 closeTolerance = 4,
25038 mouseLeave = false,
25040 cached = iD.behavior.Draw;
25043 if (d3.event.altKey) return {};
25045 if (d3.event.type === 'keydown') {
25046 return (lastMouse && lastMouse.target.__data__) || {};
25048 return d3.event.target.__data__ || {};
25052 function mousedown() {
25055 var p = context.container().node();
25056 return touchId !== null ? d3.touches(p).filter(function(p) {
25057 return p.identifier === touchId;
25058 })[0] : d3.mouse(p);
25061 var element = d3.select(this),
25062 touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
25066 element.on('mousemove.draw', null);
25068 d3.select(window).on('mouseup.draw', function() {
25069 var t2 = +new Date(),
25071 dist = iD.geo.euclideanDistance(p1, p2);
25073 element.on('mousemove.draw', mousemove);
25074 d3.select(window).on('mouseup.draw', null);
25076 if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
25077 // Prevent a quick second click
25078 d3.select(window).on('click.draw-block', function() {
25079 d3.event.stopPropagation();
25082 context.map().dblclickEnable(false);
25084 window.setTimeout(function() {
25085 context.map().dblclickEnable(true);
25086 d3.select(window).on('click.draw-block', null);
25094 function mousemove() {
25095 lastMouse = d3.event;
25096 event.move(datum());
25099 function mouseenter() {
25100 mouseLeave = false;
25103 function mouseleave() {
25109 if (d.type === 'way') {
25110 var dims = context.map().dimensions(),
25111 mouse = context.mouse(),
25113 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
25114 mouse[1] > pad && mouse[1] < dims[1] - pad;
25117 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection),
25118 edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
25119 event.clickWay(choice.loc, edge);
25121 event.click(context.map().mouseCoordinates());
25124 } else if (d.type === 'node') {
25125 event.clickNode(d);
25128 event.click(context.map().mouseCoordinates());
25133 var currSpace = context.mouse();
25134 if (cached.disableSpace && cached.lastSpace) {
25135 var dist = iD.geo.euclideanDistance(cached.lastSpace, currSpace);
25136 if (dist > tolerance) {
25137 cached.disableSpace = false;
25141 if (cached.disableSpace || mouseLeave || !lastMouse) return;
25143 // user must move mouse or release space bar to allow another click
25144 cached.lastSpace = currSpace;
25145 cached.disableSpace = true;
25147 d3.select(window).on('keyup.space-block', function() {
25148 cached.disableSpace = false;
25149 d3.select(window).on('keyup.space-block', null);
25152 d3.event.preventDefault();
25156 function backspace() {
25157 d3.event.preventDefault();
25162 d3.event.preventDefault();
25167 d3.event.preventDefault();
25171 function draw(selection) {
25172 context.install(hover);
25173 context.install(edit);
25175 if (!context.inIntro() && !cached.usedTails[tail.text()]) {
25176 context.install(tail);
25180 .on('⌫', backspace)
25184 .on('space', space)
25185 .on('⌥space', space);
25188 .on('mouseenter.draw', mouseenter)
25189 .on('mouseleave.draw', mouseleave)
25190 .on('mousedown.draw', mousedown)
25191 .on('mousemove.draw', mousemove);
25193 d3.select(document)
25199 draw.off = function(selection) {
25200 context.ui().sidebar.hover.cancel();
25201 context.uninstall(hover);
25202 context.uninstall(edit);
25204 if (!context.inIntro() && !cached.usedTails[tail.text()]) {
25205 context.uninstall(tail);
25206 cached.usedTails[tail.text()] = true;
25210 .on('mouseenter.draw', null)
25211 .on('mouseleave.draw', null)
25212 .on('mousedown.draw', null)
25213 .on('mousemove.draw', null);
25216 .on('mouseup.draw', null);
25217 // note: keyup.space-block, click.draw-block should remain
25219 d3.select(document)
25220 .call(keybinding.off);
25223 draw.tail = function(_) {
25228 return d3.rebind(draw, event, 'on');
25231 iD.behavior.Draw.usedTails = {};
25232 iD.behavior.Draw.disableSpace = false;
25233 iD.behavior.Draw.lastSpace = null;
25234 iD.behavior.DrawWay = function(context, wayId, index, mode, baseGraph) {
25235 var way = context.entity(wayId),
25236 isArea = context.geometry(wayId) === 'area',
25238 annotation = t((way.isDegenerate() ?
25239 'operations.start.annotation.' :
25240 'operations.continue.annotation.') + context.geometry(wayId)),
25241 draw = iD.behavior.Draw(context);
25243 var startIndex = typeof index === 'undefined' ? way.nodes.length - 1 : 0,
25244 start = iD.Node({loc: context.graph().entity(way.nodes[startIndex]).loc}),
25245 end = iD.Node({loc: context.map().mouseCoordinates()}),
25247 nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
25248 tags: _.clone(way.tags)
25251 var f = context[way.isDegenerate() ? 'replace' : 'perform'];
25253 f(iD.actions.AddEntity(end),
25254 iD.actions.AddVertex(wayId, end.id, index));
25256 f(iD.actions.AddEntity(start),
25257 iD.actions.AddEntity(end),
25258 iD.actions.AddEntity(segment));
25261 function move(datum) {
25264 if (datum.type === 'node' && datum.id !== end.id) {
25267 } else if (datum.type === 'way' && datum.id !== segment.id) {
25268 var dims = context.map().dimensions(),
25269 mouse = context.mouse(),
25271 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
25272 mouse[1] > pad && mouse[1] < dims[1] - pad;
25275 loc = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
25280 loc = context.map().mouseCoordinates();
25283 context.replace(iD.actions.MoveNode(end.id, loc));
25286 function undone() {
25288 context.enter(iD.modes.Browse(context));
25291 function setActiveElements() {
25292 var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
25293 context.surface().selectAll(iD.util.entitySelector(active))
25294 .classed('active', true);
25297 var drawWay = function(surface) {
25298 draw.on('move', move)
25299 .on('click', drawWay.add)
25300 .on('clickWay', drawWay.addWay)
25301 .on('clickNode', drawWay.addNode)
25302 .on('undo', context.undo)
25303 .on('cancel', drawWay.cancel)
25304 .on('finish', drawWay.finish);
25307 .dblclickEnable(false)
25308 .on('drawn.draw', setActiveElements);
25310 setActiveElements();
25312 surface.call(draw);
25315 .on('undone.draw', undone);
25318 drawWay.off = function(surface) {
25323 .on('drawn.draw', null);
25325 surface.call(draw.off)
25326 .selectAll('.active')
25327 .classed('active', false);
25330 .on('undone.draw', null);
25333 function ReplaceTemporaryNode(newNode) {
25334 return function(graph) {
25337 .replace(way.addNode(newNode.id, index))
25342 .replace(graph.entity(wayId).addNode(newNode.id, index))
25350 // Accept the current position of the temporary node and continue drawing.
25351 drawWay.add = function(loc) {
25353 // prevent duplicate nodes
25354 var last = context.hasEntity(way.nodes[way.nodes.length - (isArea ? 2 : 1)]);
25355 if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
25357 var newNode = iD.Node({loc: loc});
25360 iD.actions.AddEntity(newNode),
25361 ReplaceTemporaryNode(newNode),
25365 context.enter(mode);
25368 // Connect the way to an existing way.
25369 drawWay.addWay = function(loc, edge) {
25370 var previousEdge = startIndex ?
25371 [way.nodes[startIndex], way.nodes[startIndex - 1]] :
25372 [way.nodes[0], way.nodes[1]];
25374 // Avoid creating duplicate segments
25375 if (!isArea && iD.geo.edgeEqual(edge, previousEdge))
25378 var newNode = iD.Node({ loc: loc });
25381 iD.actions.AddMidpoint({ loc: loc, edge: edge}, newNode),
25382 ReplaceTemporaryNode(newNode),
25386 context.enter(mode);
25389 // Connect the way to an existing node and continue drawing.
25390 drawWay.addNode = function(node) {
25392 // Avoid creating duplicate segments
25393 if (way.areAdjacent(node.id, way.nodes[way.nodes.length - 1])) return;
25396 ReplaceTemporaryNode(node),
25400 context.enter(mode);
25403 // Finish the draw operation, removing the temporary node. If the way has enough
25404 // nodes to be valid, it's selected. Otherwise, return to browse mode.
25405 drawWay.finish = function() {
25409 window.setTimeout(function() {
25410 context.map().dblclickEnable(true);
25413 if (context.hasEntity(wayId)) {
25415 iD.modes.Select(context, [wayId])
25416 .suppressMenu(true)
25417 .newFeature(true));
25419 context.enter(iD.modes.Browse(context));
25423 // Cancel the draw operation and return to browse, deleting everything drawn.
25424 drawWay.cancel = function() {
25426 d3.functor(baseGraph),
25427 t('operations.cancel_draw.annotation'));
25429 window.setTimeout(function() {
25430 context.map().dblclickEnable(true);
25434 context.enter(iD.modes.Browse(context));
25437 drawWay.tail = function(text) {
25444 iD.behavior.Edit = function(context) {
25447 .minzoom(context.minEditableZoom());
25450 edit.off = function() {
25457 iD.behavior.Hash = function(context) {
25458 var s0 = null, // cached location.hash
25459 lat = 90 - 1e-8; // allowable latitude range
25461 var parser = function(map, s) {
25462 var q = iD.util.stringQs(s);
25463 var args = (q.map || '').split('/').map(Number);
25464 if (args.length < 3 || args.some(isNaN)) {
25465 return true; // replace bogus hash
25466 } else if (s !== formatter(map).slice(1)) {
25467 map.centerZoom([args[1],
25468 Math.min(lat, Math.max(-lat, args[2]))], args[0]);
25472 var formatter = function(map) {
25473 var mode = context.mode(),
25474 center = map.center(),
25476 precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)),
25477 q = _.omit(iD.util.stringQs(location.hash.substring(1)), 'comment'),
25480 if (mode && mode.id === 'browse') {
25483 var selected = context.selectedIDs().filter(function(id) {
25484 return !context.entity(id).isNew();
25486 if (selected.length) {
25487 newParams.id = selected.join(',');
25491 newParams.map = zoom.toFixed(2) +
25492 '/' + center[0].toFixed(precision) +
25493 '/' + center[1].toFixed(precision);
25495 return '#' + iD.util.qsString(_.assign(q, newParams), true);
25498 function update() {
25499 if (context.inIntro()) return;
25500 var s1 = formatter(context.map());
25501 if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map!
25504 var throttledUpdate = _.throttle(update, 500);
25506 function hashchange() {
25507 if (location.hash === s0) return; // ignore spurious hashchange events
25508 if (parser(context.map(), (s0 = location.hash).substring(1))) {
25509 update(); // replace bogus hash
25515 .on('move.hash', throttledUpdate);
25518 .on('enter.hash', throttledUpdate);
25521 .on('hashchange.hash', hashchange);
25523 if (location.hash) {
25524 var q = iD.util.stringQs(location.hash.substring(1));
25525 if (q.id) context.zoomToEntity(q.id.split(',')[0], !q.map);
25526 if (q.comment) context.storage('comment', q.comment);
25528 if (q.map) hash.hadHash = true;
25532 hash.off = function() {
25533 throttledUpdate.cancel();
25536 .on('move.hash', null);
25539 .on('enter.hash', null);
25542 .on('hashchange.hash', null);
25544 location.hash = '';
25550 The hover behavior adds the `.hover` class on mouseover to all elements to which
25551 the identical datum is bound, and removes it on mouseout.
25553 The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
25554 representation may consist of several elements scattered throughout the DOM hierarchy.
25555 Only one of these elements can have the :hover pseudo-class, but all of them will
25556 have the .hover class.
25558 iD.behavior.Hover = function() {
25559 var dispatch = d3.dispatch('hover'),
25564 function keydown() {
25565 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
25566 dispatch.hover(null);
25567 selection.selectAll('.hover')
25568 .classed('hover-suppressed', true)
25569 .classed('hover', false);
25574 if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
25575 dispatch.hover(target ? target.id : null);
25576 selection.selectAll('.hover-suppressed')
25577 .classed('hover-suppressed', false)
25578 .classed('hover', true);
25582 var hover = function(__) {
25585 function enter(d) {
25586 if (d === target) return;
25590 selection.selectAll('.hover')
25591 .classed('hover', false);
25592 selection.selectAll('.hover-suppressed')
25593 .classed('hover-suppressed', false);
25595 if (target instanceof iD.Entity) {
25596 var selector = '.' + target.id;
25598 if (target.type === 'relation') {
25599 target.members.forEach(function(member) {
25600 selector += ', .' + member.id;
25604 var suppressed = altDisables && d3.event && d3.event.altKey;
25606 selection.selectAll(selector)
25607 .classed(suppressed ? 'hover-suppressed' : 'hover', true);
25609 dispatch.hover(target.id);
25611 dispatch.hover(null);
25617 function mouseover() {
25619 var target = d3.event.target;
25620 enter(target ? target.__data__ : null);
25623 function mouseout() {
25625 var target = d3.event.relatedTarget;
25626 enter(target ? target.__data__ : null);
25629 function mousedown() {
25632 .on('mouseup.hover', mouseup);
25635 function mouseup() {
25640 .on('mouseover.hover', mouseover)
25641 .on('mouseout.hover', mouseout)
25642 .on('mousedown.hover', mousedown)
25643 .on('mouseup.hover', mouseup);
25646 .on('keydown.hover', keydown)
25647 .on('keyup.hover', keyup);
25650 hover.off = function(selection) {
25651 selection.selectAll('.hover')
25652 .classed('hover', false);
25653 selection.selectAll('.hover-suppressed')
25654 .classed('hover-suppressed', false);
25657 .on('mouseover.hover', null)
25658 .on('mouseout.hover', null)
25659 .on('mousedown.hover', null)
25660 .on('mouseup.hover', null);
25663 .on('keydown.hover', null)
25664 .on('keyup.hover', null)
25665 .on('mouseup.hover', null);
25668 hover.altDisables = function(_) {
25669 if (!arguments.length) return altDisables;
25674 return d3.rebind(hover, dispatch, 'on');
25676 iD.behavior.Lasso = function(context) {
25678 var behavior = function(selection) {
25681 function mousedown() {
25682 var button = 0; // left
25683 if (d3.event.button === button && d3.event.shiftKey === true) {
25687 .on('mousemove.lasso', mousemove)
25688 .on('mouseup.lasso', mouseup);
25690 d3.event.stopPropagation();
25694 function mousemove() {
25696 lasso = iD.ui.Lasso(context);
25697 context.surface().call(lasso);
25700 lasso.p(context.mouse());
25703 function normalize(a, b) {
25705 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
25706 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
25709 function lassoed() {
25710 if (!lasso) return [];
25712 var graph = context.graph(),
25713 bounds = lasso.extent().map(context.projection.invert),
25714 extent = iD.geo.Extent(normalize(bounds[0], bounds[1]));
25716 return _.map(context.intersects(extent).filter(function(entity) {
25717 return entity.type === 'node' &&
25718 iD.geo.pointInPolygon(context.projection(entity.loc), lasso.coordinates) &&
25719 !context.features().isHidden(entity, graph, entity.geometry(graph));
25723 function mouseup() {
25725 .on('mousemove.lasso', null)
25726 .on('mouseup.lasso', null);
25728 if (!lasso) return;
25730 var ids = lassoed();
25734 context.enter(iD.modes.Select(context, ids));
25739 .on('mousedown.lasso', mousedown);
25742 behavior.off = function(selection) {
25743 selection.on('mousedown.lasso', null);
25748 iD.behavior.Paste = function(context) {
25749 var keybinding = d3.keybinding('paste');
25751 function omitTag(v, k) {
25759 k === 'description' ||
25760 k.indexOf('name') !== -1 ||
25761 k.indexOf('wiki') === 0 ||
25762 k.indexOf('addr:') === 0 ||
25763 k.indexOf('contact:') === 0
25767 function doPaste() {
25768 d3.event.preventDefault();
25769 if (context.inIntro()) return;
25771 var baseGraph = context.graph(),
25772 mouse = context.mouse(),
25773 projection = context.projection,
25774 viewport = iD.geo.Extent(projection.clipExtent()).polygon();
25776 if (!iD.geo.pointInPolygon(mouse, viewport)) return;
25778 var extent = iD.geo.Extent(),
25779 oldIDs = context.copyIDs(),
25780 oldGraph = context.copyGraph(),
25783 if (!oldIDs.length) return;
25785 var action = iD.actions.CopyEntities(oldIDs, oldGraph);
25786 context.perform(action);
25788 var copies = action.copies();
25789 for (var id in copies) {
25790 var oldEntity = oldGraph.entity(id),
25791 newEntity = copies[id];
25793 extent._extend(oldEntity.extent(oldGraph));
25794 newIDs.push(newEntity.id);
25795 context.perform(iD.actions.ChangeTags(newEntity.id, _.omit(newEntity.tags, omitTag)));
25798 // Put pasted objects where mouse pointer is..
25799 var center = projection(extent.center()),
25800 delta = [ mouse[0] - center[0], mouse[1] - center[1] ];
25802 context.perform(iD.actions.Move(newIDs, delta, projection));
25803 context.enter(iD.modes.Move(context, newIDs, baseGraph));
25807 keybinding.on(iD.ui.cmd('⌘V'), doPaste);
25808 d3.select(document).call(keybinding);
25812 paste.off = function() {
25813 d3.select(document).call(keybinding.off);
25818 iD.behavior.Select = function(context) {
25819 function keydown() {
25820 if (d3.event && d3.event.shiftKey) {
25822 .classed('behavior-multiselect', true);
25827 if (!d3.event || !d3.event.shiftKey) {
25829 .classed('behavior-multiselect', false);
25834 var datum = d3.event.target.__data__,
25835 lasso = d3.select('#surface .lasso').node(),
25836 mode = context.mode();
25838 if (!(datum instanceof iD.Entity)) {
25839 if (!d3.event.shiftKey && !lasso && mode.id !== 'browse')
25840 context.enter(iD.modes.Browse(context));
25842 } else if (!d3.event.shiftKey && !lasso) {
25843 // Avoid re-entering Select mode with same entity.
25844 if (context.selectedIDs().length !== 1 || context.selectedIDs()[0] !== datum.id) {
25845 context.enter(iD.modes.Select(context, [datum.id]));
25847 mode.suppressMenu(false).reselect();
25849 } else if (context.selectedIDs().indexOf(datum.id) >= 0) {
25850 var selectedIDs = _.without(context.selectedIDs(), datum.id);
25851 context.enter(selectedIDs.length ?
25852 iD.modes.Select(context, selectedIDs) :
25853 iD.modes.Browse(context));
25856 context.enter(iD.modes.Select(context, context.selectedIDs().concat([datum.id])));
25860 var behavior = function(selection) {
25862 .on('keydown.select', keydown)
25863 .on('keyup.select', keyup);
25865 selection.on('click.select', click);
25870 behavior.off = function(selection) {
25872 .on('keydown.select', null)
25873 .on('keyup.select', null);
25875 selection.on('click.select', null);
25882 iD.behavior.Tail = function() {
25886 tooltipSize = [0, 0],
25887 selectionSize = [0, 0];
25889 function tail(selection) {
25893 .on('resize.tail', function() { selectionSize = selection.dimensions(); });
25896 container.style('display', 'block');
25897 tooltipSize = container.dimensions();
25900 function mousemove() {
25901 if (container.style('display') === 'none') show();
25902 var xoffset = ((d3.event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
25903 -tooltipSize[0] - xmargin : xmargin;
25904 container.classed('left', xoffset > 0);
25905 iD.util.setTransform(container, d3.event.clientX + xoffset, d3.event.clientY);
25908 function mouseleave() {
25909 if (d3.event.relatedTarget !== container.node()) {
25910 container.style('display', 'none');
25914 function mouseenter() {
25915 if (d3.event.relatedTarget !== container.node()) {
25920 container = d3.select(document.body)
25922 .style('display', 'none')
25923 .attr('class', 'tail tooltip-inner');
25925 container.append('div')
25929 .on('mousemove.tail', mousemove)
25930 .on('mouseenter.tail', mouseenter)
25931 .on('mouseleave.tail', mouseleave);
25934 .on('mousemove.tail', mousemove);
25936 tooltipSize = container.dimensions();
25937 selectionSize = selection.dimensions();
25940 tail.off = function(selection) {
25944 .on('mousemove.tail', null)
25948 .on('mousemove.tail', null)
25949 .on('mouseenter.tail', null)
25950 .on('mouseleave.tail', null);
25953 .on('resize.tail', null);
25956 tail.text = function(_) {
25957 if (!arguments.length) return text;
25965 iD.modes.AddArea = function(context) {
25969 title: t('modes.add_area.title'),
25970 description: t('modes.add_area.description'),
25974 var behavior = iD.behavior.AddWay(context)
25975 .tail(t('modes.add_area.tail'))
25976 .on('start', start)
25977 .on('startFromWay', startFromWay)
25978 .on('startFromNode', startFromNode),
25979 defaultTags = {area: 'yes'};
25981 function start(loc) {
25982 var graph = context.graph(),
25983 node = iD.Node({loc: loc}),
25984 way = iD.Way({tags: defaultTags});
25987 iD.actions.AddEntity(node),
25988 iD.actions.AddEntity(way),
25989 iD.actions.AddVertex(way.id, node.id),
25990 iD.actions.AddVertex(way.id, node.id));
25992 context.enter(iD.modes.DrawArea(context, way.id, graph));
25995 function startFromWay(loc, edge) {
25996 var graph = context.graph(),
25997 node = iD.Node({loc: loc}),
25998 way = iD.Way({tags: defaultTags});
26001 iD.actions.AddEntity(node),
26002 iD.actions.AddEntity(way),
26003 iD.actions.AddVertex(way.id, node.id),
26004 iD.actions.AddVertex(way.id, node.id),
26005 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
26007 context.enter(iD.modes.DrawArea(context, way.id, graph));
26010 function startFromNode(node) {
26011 var graph = context.graph(),
26012 way = iD.Way({tags: defaultTags});
26015 iD.actions.AddEntity(way),
26016 iD.actions.AddVertex(way.id, node.id),
26017 iD.actions.AddVertex(way.id, node.id));
26019 context.enter(iD.modes.DrawArea(context, way.id, graph));
26022 mode.enter = function() {
26023 context.install(behavior);
26026 mode.exit = function() {
26027 context.uninstall(behavior);
26032 iD.modes.AddLine = function(context) {
26036 title: t('modes.add_line.title'),
26037 description: t('modes.add_line.description'),
26041 var behavior = iD.behavior.AddWay(context)
26042 .tail(t('modes.add_line.tail'))
26043 .on('start', start)
26044 .on('startFromWay', startFromWay)
26045 .on('startFromNode', startFromNode);
26047 function start(loc) {
26048 var baseGraph = context.graph(),
26049 node = iD.Node({loc: loc}),
26053 iD.actions.AddEntity(node),
26054 iD.actions.AddEntity(way),
26055 iD.actions.AddVertex(way.id, node.id));
26057 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
26060 function startFromWay(loc, edge) {
26061 var baseGraph = context.graph(),
26062 node = iD.Node({loc: loc}),
26066 iD.actions.AddEntity(node),
26067 iD.actions.AddEntity(way),
26068 iD.actions.AddVertex(way.id, node.id),
26069 iD.actions.AddMidpoint({ loc: loc, edge: edge }, node));
26071 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
26074 function startFromNode(node) {
26075 var baseGraph = context.graph(),
26079 iD.actions.AddEntity(way),
26080 iD.actions.AddVertex(way.id, node.id));
26082 context.enter(iD.modes.DrawLine(context, way.id, baseGraph));
26085 mode.enter = function() {
26086 context.install(behavior);
26089 mode.exit = function() {
26090 context.uninstall(behavior);
26095 iD.modes.AddPoint = function(context) {
26099 title: t('modes.add_point.title'),
26100 description: t('modes.add_point.description'),
26104 var behavior = iD.behavior.Draw(context)
26105 .tail(t('modes.add_point.tail'))
26107 .on('clickWay', addWay)
26108 .on('clickNode', addNode)
26109 .on('cancel', cancel)
26110 .on('finish', cancel);
26112 function add(loc) {
26113 var node = iD.Node({loc: loc});
26116 iD.actions.AddEntity(node),
26117 t('operations.add.annotation.point'));
26120 iD.modes.Select(context, [node.id])
26121 .suppressMenu(true)
26122 .newFeature(true));
26125 function addWay(loc) {
26129 function addNode(node) {
26133 function cancel() {
26134 context.enter(iD.modes.Browse(context));
26137 mode.enter = function() {
26138 context.install(behavior);
26141 mode.exit = function() {
26142 context.uninstall(behavior);
26147 iD.modes.Browse = function(context) {
26151 title: t('modes.browse.title'),
26152 description: t('modes.browse.description')
26156 iD.behavior.Paste(context),
26157 iD.behavior.Hover(context)
26158 .on('hover', context.ui().sidebar.hover),
26159 iD.behavior.Select(context),
26160 iD.behavior.Lasso(context),
26161 iD.modes.DragNode(context).behavior];
26163 mode.enter = function() {
26164 behaviors.forEach(function(behavior) {
26165 context.install(behavior);
26168 // Get focus on the body.
26169 if (document.activeElement && document.activeElement.blur) {
26170 document.activeElement.blur();
26174 context.ui().sidebar.show(sidebar);
26176 context.ui().sidebar.select(null);
26180 mode.exit = function() {
26181 context.ui().sidebar.hover.cancel();
26182 behaviors.forEach(function(behavior) {
26183 context.uninstall(behavior);
26187 context.ui().sidebar.hide();
26191 mode.sidebar = function(_) {
26192 if (!arguments.length) return sidebar;
26199 iD.modes.DragNode = function(context) {
26210 hover = iD.behavior.Hover(context)
26212 .on('hover', context.ui().sidebar.hover),
26213 edit = iD.behavior.Edit(context);
26215 function edge(point, size) {
26216 var pad = [30, 100, 30, 100];
26217 if (point[0] > size[0] - pad[0]) return [-10, 0];
26218 else if (point[0] < pad[2]) return [10, 0];
26219 else if (point[1] > size[1] - pad[1]) return [0, -10];
26220 else if (point[1] < pad[3]) return [0, 10];
26224 function startNudge(nudge) {
26225 if (nudgeInterval) window.clearInterval(nudgeInterval);
26226 nudgeInterval = window.setInterval(function() {
26227 context.pan(nudge);
26231 function stopNudge() {
26232 if (nudgeInterval) window.clearInterval(nudgeInterval);
26233 nudgeInterval = null;
26236 function moveAnnotation(entity) {
26237 return t('operations.move.annotation.' + entity.geometry(context.graph()));
26240 function connectAnnotation(entity) {
26241 return t('operations.connect.annotation.' + entity.geometry(context.graph()));
26244 function origin(entity) {
26245 return context.projection(entity.loc);
26248 function start(entity) {
26249 cancelled = d3.event.sourceEvent.shiftKey ||
26250 context.features().hasHiddenConnections(entity, context.graph());
26252 if (cancelled) return behavior.cancel();
26254 wasMidpoint = entity.type === 'midpoint';
26256 var midpoint = entity;
26257 entity = iD.Node();
26258 context.perform(iD.actions.AddMidpoint(midpoint, entity));
26260 var vertex = context.surface()
26261 .selectAll('.' + entity.id);
26262 behavior.target(vertex.node(), entity);
26266 iD.actions.Noop());
26269 activeIDs = _.map(context.graph().parentWays(entity), 'id');
26270 activeIDs.push(entity.id);
26272 context.enter(mode);
26276 if (d3.event.sourceEvent.altKey) {
26280 return d3.event.sourceEvent.target.__data__ || {};
26283 // via https://gist.github.com/shawnbot/4166283
26284 function childOf(p, c) {
26285 if (p === c) return false;
26286 while (c && c !== p) c = c.parentNode;
26290 function move(entity) {
26291 if (cancelled) return;
26292 d3.event.sourceEvent.stopPropagation();
26294 var nudge = childOf(context.container().node(),
26295 d3.event.sourceEvent.toElement) &&
26296 edge(d3.event.point, context.map().dimensions());
26298 if (nudge) startNudge(nudge);
26301 var loc = context.projection.invert(d3.event.point);
26304 if (d.type === 'node' && d.id !== entity.id) {
26306 } else if (d.type === 'way' && !d3.select(d3.event.sourceEvent.target).classed('fill')) {
26307 loc = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
26311 iD.actions.MoveNode(entity.id, loc),
26312 moveAnnotation(entity));
26315 function end(entity) {
26316 if (cancelled) return;
26320 if (d.type === 'way') {
26321 var choice = iD.geo.chooseEdge(context.childNodes(d), context.mouse(), context.projection);
26323 iD.actions.AddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
26324 connectAnnotation(d));
26326 } else if (d.type === 'node' && d.id !== entity.id) {
26328 iD.actions.Connect([d.id, entity.id]),
26329 connectAnnotation(d));
26331 } else if (wasMidpoint) {
26334 t('operations.add.annotation.vertex'));
26339 moveAnnotation(entity));
26342 var reselection = selectedIDs.filter(function(id) {
26343 return context.graph().hasEntity(id);
26346 if (reselection.length) {
26348 iD.modes.Select(context, reselection)
26349 .suppressMenu(true));
26351 context.enter(iD.modes.Browse(context));
26355 function cancel() {
26357 context.enter(iD.modes.Browse(context));
26360 function setActiveElements() {
26361 context.surface().selectAll(iD.util.entitySelector(activeIDs))
26362 .classed('active', true);
26365 var behavior = iD.behavior.drag()
26366 .delegate('g.node, g.point, g.midpoint')
26367 .surface(context.surface().node())
26369 .on('start', start)
26373 mode.enter = function() {
26374 context.install(hover);
26375 context.install(edit);
26378 .on('undone.drag-node', cancel);
26381 .on('drawn.drag-node', setActiveElements);
26383 setActiveElements();
26386 mode.exit = function() {
26387 context.ui().sidebar.hover.cancel();
26388 context.uninstall(hover);
26389 context.uninstall(edit);
26392 .on('undone.drag-node', null);
26395 .on('drawn.drag-node', null);
26398 .selectAll('.active')
26399 .classed('active', false);
26404 mode.selectedIDs = function(_) {
26405 if (!arguments.length) return selectedIDs;
26410 mode.behavior = behavior;
26414 iD.modes.DrawArea = function(context, wayId, baseGraph) {
26422 mode.enter = function() {
26423 var way = context.entity(wayId),
26424 headId = way.nodes[way.nodes.length - 2],
26425 tailId = way.first();
26427 behavior = iD.behavior.DrawWay(context, wayId, -1, mode, baseGraph)
26428 .tail(t('modes.draw_area.tail'));
26430 var addNode = behavior.addNode;
26432 behavior.addNode = function(node) {
26433 if (node.id === headId || node.id === tailId) {
26440 context.install(behavior);
26443 mode.exit = function() {
26444 context.uninstall(behavior);
26447 mode.selectedIDs = function() {
26453 iD.modes.DrawLine = function(context, wayId, baseGraph, affix) {
26461 mode.enter = function() {
26462 var way = context.entity(wayId),
26463 index = (affix === 'prefix') ? 0 : undefined,
26464 headId = (affix === 'prefix') ? way.first() : way.last();
26466 behavior = iD.behavior.DrawWay(context, wayId, index, mode, baseGraph)
26467 .tail(t('modes.draw_line.tail'));
26469 var addNode = behavior.addNode;
26471 behavior.addNode = function(node) {
26472 if (node.id === headId) {
26479 context.install(behavior);
26482 mode.exit = function() {
26483 context.uninstall(behavior);
26486 mode.selectedIDs = function() {
26492 iD.modes.Move = function(context, entityIDs, baseGraph) {
26498 var keybinding = d3.keybinding('move'),
26499 edit = iD.behavior.Edit(context),
26500 annotation = entityIDs.length === 1 ?
26501 t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
26502 t('operations.move.annotation.multiple'),
26507 function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
26509 function edge(point, size) {
26510 var pad = [30, 100, 30, 100];
26511 if (point[0] > size[0] - pad[0]) return [-10, 0];
26512 else if (point[0] < pad[2]) return [10, 0];
26513 else if (point[1] > size[1] - pad[1]) return [0, -10];
26514 else if (point[1] < pad[3]) return [0, 10];
26518 function startNudge(nudge) {
26519 if (nudgeInterval) window.clearInterval(nudgeInterval);
26520 nudgeInterval = window.setInterval(function() {
26521 context.pan(nudge);
26523 var currMouse = context.mouse(),
26524 origMouse = context.projection(origin),
26525 delta = vecSub(vecSub(currMouse, origMouse), nudge),
26526 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
26528 context.overwrite(action, annotation);
26533 function stopNudge() {
26534 if (nudgeInterval) window.clearInterval(nudgeInterval);
26535 nudgeInterval = null;
26539 var currMouse = context.mouse(),
26540 origMouse = context.projection(origin),
26541 delta = vecSub(currMouse, origMouse),
26542 action = iD.actions.Move(entityIDs, delta, context.projection, cache);
26544 context.overwrite(action, annotation);
26546 var nudge = edge(currMouse, context.map().dimensions());
26547 if (nudge) startNudge(nudge);
26551 function finish() {
26552 d3.event.stopPropagation();
26553 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
26557 function cancel() {
26559 while (context.graph() !== baseGraph) context.pop();
26560 context.enter(iD.modes.Browse(context));
26563 context.enter(iD.modes.Select(context, entityIDs).suppressMenu(true));
26568 function undone() {
26569 context.enter(iD.modes.Browse(context));
26572 mode.enter = function() {
26573 origin = context.map().mouseCoordinates();
26576 context.install(edit);
26583 .on('mousemove.move', move)
26584 .on('click.move', finish);
26587 .on('undone.move', undone);
26593 d3.select(document)
26597 mode.exit = function() {
26600 context.uninstall(edit);
26603 .on('mousemove.move', null)
26604 .on('click.move', null);
26607 .on('undone.move', null);
26614 iD.modes.RotateWay = function(context, wayId) {
26620 var keybinding = d3.keybinding('rotate-way'),
26621 edit = iD.behavior.Edit(context);
26623 mode.enter = function() {
26624 context.install(edit);
26626 var annotation = t('operations.rotate.annotation.' + context.geometry(wayId)),
26627 way = context.graph().entity(wayId),
26628 nodes = _.uniq(context.graph().childNodes(way)),
26629 points = nodes.map(function(n) { return context.projection(n.loc); }),
26630 pivot = d3.geom.polygon(points).centroid(),
26637 function rotate() {
26639 var mousePoint = context.mouse(),
26640 newAngle = Math.atan2(mousePoint[1] - pivot[1], mousePoint[0] - pivot[0]);
26642 if (typeof angle === 'undefined') angle = newAngle;
26645 iD.actions.RotateWay(wayId, pivot, newAngle - angle, context.projection),
26651 function finish() {
26652 d3.event.stopPropagation();
26653 context.enter(iD.modes.Select(context, [wayId])
26654 .suppressMenu(true));
26657 function cancel() {
26659 context.enter(iD.modes.Select(context, [wayId])
26660 .suppressMenu(true));
26663 function undone() {
26664 context.enter(iD.modes.Browse(context));
26668 .on('mousemove.rotate-way', rotate)
26669 .on('click.rotate-way', finish);
26672 .on('undone.rotate-way', undone);
26678 d3.select(document)
26682 mode.exit = function() {
26683 context.uninstall(edit);
26686 .on('mousemove.rotate-way', null)
26687 .on('click.rotate-way', null);
26690 .on('undone.rotate-way', null);
26697 iD.modes.Save = function(context) {
26698 var ui = iD.ui.Commit(context)
26699 .on('cancel', cancel)
26702 function cancel() {
26703 context.enter(iD.modes.Browse(context));
26706 function save(e, tryAgain) {
26707 function withChildNodes(ids, graph) {
26708 return _.uniq(_.reduce(ids, function(result, id) {
26709 var e = graph.entity(id);
26710 if (e.type === 'way') {
26712 var cn = graph.childNodes(e);
26713 result.push.apply(result, _.map(_.filter(cn, 'version'), 'id'));
26715 /* eslint-disable no-console */
26716 if (typeof console !== 'undefined') console.error(err);
26717 /* eslint-enable no-console */
26724 var loading = iD.ui.Loading(context).message(t('save.uploading')).blocking(true),
26725 history = context.history(),
26726 origChanges = history.changes(iD.actions.DiscardTags(history.difference())),
26727 localGraph = context.graph(),
26728 remoteGraph = iD.Graph(history.base(), true),
26729 modified = _.filter(history.difference().summary(), {changeType: 'modified'}),
26730 toCheck = _.map(_.map(modified, 'entity'), 'id'),
26731 toLoad = withChildNodes(toCheck, localGraph),
26735 if (!tryAgain) history.perform(iD.actions.Noop()); // checkpoint
26736 context.container().call(loading);
26738 if (toCheck.length) {
26739 context.connection().loadMultiple(toLoad, loaded);
26745 // Reload modified entities into an alternate graph and check for conflicts..
26746 function loaded(err, result) {
26747 if (errors.length) return;
26751 msg: err.responseText,
26752 details: [ t('save.status_code', { code: err.status }) ]
26758 _.each(result.data, function(entity) {
26759 remoteGraph.replace(entity);
26760 toLoad = _.without(toLoad, entity.id);
26762 // Because loadMultiple doesn't download /full like loadEntity,
26763 // need to also load children that aren't already being checked..
26764 if (!entity.visible) return;
26765 if (entity.type === 'way') {
26766 loadMore.push.apply(loadMore,
26767 _.difference(entity.nodes, toCheck, toLoad, loadMore));
26768 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
26769 loadMore.push.apply(loadMore,
26770 _.difference(_.map(entity.members, 'id'), toCheck, toLoad, loadMore));
26774 if (loadMore.length) {
26775 toLoad.push.apply(toLoad, loadMore);
26776 context.connection().loadMultiple(loadMore, loaded);
26779 if (!toLoad.length) {
26786 function checkConflicts() {
26787 function choice(id, text, action) {
26788 return { id: id, text: text, action: function() { history.replace(action); } };
26790 function formatUser(d) {
26791 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
26793 function entityName(entity) {
26794 return iD.util.displayName(entity) || (iD.util.displayType(entity.id) + ' ' + entity.id);
26797 function compareVersions(local, remote) {
26798 if (local.version !== remote.version) return false;
26800 if (local.type === 'way') {
26801 var children = _.union(local.nodes, remote.nodes);
26803 for (var i = 0; i < children.length; i++) {
26804 var a = localGraph.hasEntity(children[i]),
26805 b = remoteGraph.hasEntity(children[i]);
26807 if (a && b && a.version !== b.version) return false;
26814 _.each(toCheck, function(id) {
26815 var local = localGraph.entity(id),
26816 remote = remoteGraph.entity(id);
26818 if (compareVersions(local, remote)) return;
26820 var action = iD.actions.MergeRemoteChanges,
26821 merge = action(id, localGraph, remoteGraph, formatUser);
26823 history.replace(merge);
26825 var mergeConflicts = merge.conflicts();
26826 if (!mergeConflicts.length) return; // merged safely
26828 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
26829 forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
26830 keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
26831 keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
26835 name: entityName(local),
26836 details: mergeConflicts,
26839 choice(id, keepMine, forceLocal),
26840 choice(id, keepTheirs, forceRemote)
26849 function finalize() {
26850 if (conflicts.length) {
26851 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
26853 } else if (errors.length) {
26856 var changes = history.changes(iD.actions.DiscardTags(history.difference()));
26857 if (changes.modified.length || changes.created.length || changes.deleted.length) {
26858 context.connection().putChangeset(
26861 history.imageryUsed(),
26862 function(err, changeset_id) {
26865 msg: err.responseText,
26866 details: [ t('save.status_code', { code: err.status }) ]
26870 history.clearSaved();
26871 success(e, changeset_id);
26872 // Add delay to allow for postgres replication #1646 #2678
26873 window.setTimeout(function() {
26879 } else { // changes were insignificant or reverted by user
26888 function showConflicts() {
26889 var selection = context.container()
26890 .select('#sidebar')
26892 .attr('class','sidebar-component');
26896 selection.call(iD.ui.Conflicts(context)
26898 .on('download', function() {
26899 var data = JXON.stringify(context.connection().osmChangeJXON('CHANGEME', origChanges)),
26900 win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
26903 .on('cancel', function() {
26905 selection.remove();
26907 .on('save', function() {
26908 for (var i = 0; i < conflicts.length; i++) {
26909 if (conflicts[i].chosen === 1) { // user chose "keep theirs"
26910 var entity = context.hasEntity(conflicts[i].id);
26911 if (entity && entity.type === 'way') {
26912 var children = _.uniq(entity.nodes);
26913 for (var j = 0; j < children.length; j++) {
26914 history.replace(iD.actions.Revert(children[j]));
26917 history.replace(iD.actions.Revert(conflicts[i].id));
26921 selection.remove();
26928 function showErrors() {
26929 var selection = iD.ui.confirm(context.container());
26935 .select('.modal-section.header')
26937 .text(t('save.error'));
26939 addErrors(selection, errors);
26940 selection.okButton();
26944 function addErrors(selection, data) {
26945 var message = selection
26946 .select('.modal-section.message-text');
26948 var items = message
26949 .selectAll('.error-container')
26952 var enter = items.enter()
26954 .attr('class', 'error-container');
26958 .attr('class', 'error-description')
26960 .classed('hide-toggle', true)
26961 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
26962 .on('click', function() {
26963 var error = d3.select(this),
26964 detail = d3.select(this.nextElementSibling),
26965 exp = error.classed('expanded');
26967 detail.style('display', exp ? 'none' : 'block');
26968 error.classed('expanded', !exp);
26970 d3.event.preventDefault();
26973 var details = enter
26975 .attr('class', 'error-detail-container')
26976 .style('display', 'none');
26980 .attr('class', 'error-detail-list')
26982 .data(function(d) { return d.details || []; })
26985 .attr('class', 'error-detail-item')
26986 .text(function(d) { return d; });
26995 function success(e, changeset_id) {
26996 context.enter(iD.modes.Browse(context)
26997 .sidebar(iD.ui.Success(context)
27002 .on('cancel', function() {
27003 context.ui().sidebar.hide();
27011 mode.enter = function() {
27012 context.connection().authenticate(function(err) {
27016 context.ui().sidebar.show(ui);
27021 mode.exit = function() {
27022 context.ui().sidebar.hide();
27027 iD.modes.Select = function(context, selectedIDs) {
27033 var keybinding = d3.keybinding('select'),
27036 iD.behavior.Copy(context),
27037 iD.behavior.Paste(context),
27038 iD.behavior.Breathe(context),
27039 iD.behavior.Hover(context),
27040 iD.behavior.Select(context),
27041 iD.behavior.Lasso(context),
27042 iD.modes.DragNode(context)
27043 .selectedIDs(selectedIDs)
27047 newFeature = false,
27048 suppressMenu = false;
27050 var wrap = context.container()
27051 .select('.inspector-wrap');
27054 function singular() {
27055 if (selectedIDs.length === 1) {
27056 return context.hasEntity(selectedIDs[0]);
27060 function closeMenu() {
27062 context.surface().call(radialMenu.close);
27066 function positionMenu() {
27067 if (suppressMenu || !radialMenu) { return; }
27069 var entity = singular();
27070 if (entity && context.geometry(entity.id) === 'relation') {
27071 suppressMenu = true;
27072 } else if (entity && entity.type === 'node') {
27073 radialMenu.center(context.projection(entity.loc));
27075 var point = context.mouse(),
27076 viewport = iD.geo.Extent(context.projection.clipExtent()).polygon();
27077 if (iD.geo.pointInPolygon(point, viewport)) {
27078 radialMenu.center(point);
27080 suppressMenu = true;
27085 function showMenu() {
27087 if (!suppressMenu && radialMenu) {
27088 context.surface().call(radialMenu);
27092 function toggleMenu() {
27093 if (d3.select('.radial-menu').empty()) {
27100 mode.selectedIDs = function() {
27101 return selectedIDs;
27104 mode.reselect = function() {
27105 var surfaceNode = context.surface().node();
27106 if (surfaceNode.focus) { // FF doesn't support it
27107 surfaceNode.focus();
27114 mode.newFeature = function(_) {
27115 if (!arguments.length) return newFeature;
27120 mode.suppressMenu = function(_) {
27121 if (!arguments.length) return suppressMenu;
27126 mode.enter = function() {
27127 function update() {
27129 if (_.some(selectedIDs, function(id) { return !context.hasEntity(id); })) {
27130 // Exit mode if selected entity gets undone
27131 context.enter(iD.modes.Browse(context));
27135 function dblclick() {
27136 var target = d3.select(d3.event.target),
27137 datum = target.datum();
27139 if (datum instanceof iD.Way && !target.classed('fill')) {
27140 var choice = iD.geo.chooseEdge(context.childNodes(datum), context.mouse(), context.projection),
27143 var prev = datum.nodes[choice.index - 1],
27144 next = datum.nodes[choice.index];
27147 iD.actions.AddMidpoint({loc: choice.loc, edge: [prev, next]}, node),
27148 t('operations.add.annotation.vertex'));
27150 d3.event.preventDefault();
27151 d3.event.stopPropagation();
27155 function selectElements(drawn) {
27156 var entity = singular();
27157 if (entity && context.geometry(entity.id) === 'relation') {
27158 suppressMenu = true;
27162 var selection = context.surface()
27163 .selectAll(iD.util.entityOrMemberSelector(selectedIDs, context.graph()));
27165 if (selection.empty()) {
27166 if (drawn) { // Exit mode if selected DOM elements have disappeared..
27167 context.enter(iD.modes.Browse(context));
27171 .classed('selected', true);
27176 if (!context.inIntro()) {
27177 context.enter(iD.modes.Browse(context));
27182 behaviors.forEach(function(behavior) {
27183 context.install(behavior);
27186 var operations = _.without(d3.values(iD.operations), iD.operations.Delete)
27187 .map(function(o) { return o(selectedIDs, context); })
27188 .filter(function(o) { return o.available(); });
27190 operations.unshift(iD.operations.Delete(selectedIDs, context));
27193 .on('⎋', esc, true)
27194 .on('space', toggleMenu);
27196 operations.forEach(function(operation) {
27197 operation.keys.forEach(function(key) {
27198 keybinding.on(key, function() {
27199 if (!(context.inIntro() || operation.disabled())) {
27206 d3.select(document)
27209 radialMenu = iD.ui.RadialMenu(context, operations);
27211 context.ui().sidebar
27212 .select(singular() ? singular().id : null, newFeature);
27215 .on('undone.select', update)
27216 .on('redone.select', update);
27219 .on('move.select', closeMenu)
27220 .on('drawn.select', selectElements);
27224 var show = d3.event && !suppressMenu;
27230 timeout = window.setTimeout(function() {
27236 .on('dblclick.select', dblclick);
27239 if (selectedIDs.length > 1) {
27240 var entities = iD.ui.SelectionList(context, selectedIDs);
27241 context.ui().sidebar.show(entities);
27245 mode.exit = function() {
27246 if (timeout) window.clearTimeout(timeout);
27248 if (inspector) wrap.call(inspector.close);
27250 behaviors.forEach(function(behavior) {
27251 context.uninstall(behavior);
27256 radialMenu = undefined;
27259 .on('undone.select', null)
27260 .on('redone.select', null);
27263 .on('dblclick.select', null)
27264 .selectAll('.selected')
27265 .classed('selected', false);
27267 context.map().on('drawn.select', null);
27268 context.ui().sidebar.hide();
27273 iD.operations = {};
27274 iD.operations.Circularize = function(selectedIDs, context) {
27275 var entityId = selectedIDs[0],
27276 entity = context.entity(entityId),
27277 extent = entity.extent(context.graph()),
27278 geometry = context.geometry(entityId),
27279 action = iD.actions.Circularize(entityId, context.projection);
27281 var operation = function() {
27282 var annotation = t('operations.circularize.annotation.' + geometry);
27283 context.perform(action, annotation);
27286 operation.available = function() {
27287 return selectedIDs.length === 1 &&
27288 entity.type === 'way' &&
27289 _.uniq(entity.nodes).length > 1;
27292 operation.disabled = function() {
27294 if (extent.percentContainedIn(context.extent()) < 0.8) {
27295 reason = 'too_large';
27296 } else if (context.hasHiddenConnections(entityId)) {
27297 reason = 'connected_to_hidden';
27299 return action.disabled(context.graph()) || reason;
27302 operation.tooltip = function() {
27303 var disable = operation.disabled();
27305 t('operations.circularize.' + disable) :
27306 t('operations.circularize.description.' + geometry);
27309 operation.id = 'circularize';
27310 operation.keys = [t('operations.circularize.key')];
27311 operation.title = t('operations.circularize.title');
27315 iD.operations.Continue = function(selectedIDs, context) {
27316 var graph = context.graph(),
27317 entities = selectedIDs.map(function(id) { return graph.entity(id); }),
27318 geometries = _.extend({line: [], vertex: []},
27319 _.groupBy(entities, function(entity) { return entity.geometry(graph); })),
27320 vertex = geometries.vertex[0];
27322 function candidateWays() {
27323 return graph.parentWays(vertex).filter(function(parent) {
27324 return parent.geometry(graph) === 'line' &&
27325 parent.affix(vertex.id) &&
27326 (geometries.line.length === 0 || geometries.line[0] === parent);
27330 var operation = function() {
27331 var candidate = candidateWays()[0];
27332 context.enter(iD.modes.DrawLine(
27336 candidate.affix(vertex.id)));
27339 operation.available = function() {
27340 return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
27341 !context.features().hasHiddenConnections(vertex, context.graph());
27344 operation.disabled = function() {
27345 var candidates = candidateWays();
27346 if (candidates.length === 0)
27347 return 'not_eligible';
27348 if (candidates.length > 1)
27352 operation.tooltip = function() {
27353 var disable = operation.disabled();
27355 t('operations.continue.' + disable) :
27356 t('operations.continue.description');
27359 operation.id = 'continue';
27360 operation.keys = [t('operations.continue.key')];
27361 operation.title = t('operations.continue.title');
27365 iD.operations.Delete = function(selectedIDs, context) {
27366 var action = iD.actions.DeleteMultiple(selectedIDs);
27368 var operation = function() {
27372 if (selectedIDs.length > 1) {
27373 annotation = t('operations.delete.annotation.multiple', {n: selectedIDs.length});
27376 var id = selectedIDs[0],
27377 entity = context.entity(id),
27378 geometry = context.geometry(id),
27379 parents = context.graph().parentWays(entity),
27380 parent = parents[0];
27382 annotation = t('operations.delete.annotation.' + geometry);
27384 // Select the next closest node in the way.
27385 if (geometry === 'vertex' && parents.length === 1 && parent.nodes.length > 2) {
27386 var nodes = parent.nodes,
27387 i = nodes.indexOf(id);
27391 } else if (i === nodes.length - 1) {
27394 var a = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
27395 b = iD.geo.sphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
27396 i = a < b ? i - 1 : i + 1;
27399 nextSelectedID = nodes[i];
27403 if (nextSelectedID && context.hasEntity(nextSelectedID)) {
27404 context.enter(iD.modes.Select(context, [nextSelectedID]));
27406 context.enter(iD.modes.Browse(context));
27414 operation.available = function() {
27418 operation.disabled = function() {
27420 if (_.some(selectedIDs, context.hasHiddenConnections)) {
27421 reason = 'connected_to_hidden';
27423 return action.disabled(context.graph()) || reason;
27426 operation.tooltip = function() {
27427 var disable = operation.disabled();
27429 t('operations.delete.' + disable) :
27430 t('operations.delete.description');
27433 operation.id = 'delete';
27434 operation.keys = [iD.ui.cmd('⌘⌫'), iD.ui.cmd('⌘⌦')];
27435 operation.title = t('operations.delete.title');
27439 iD.operations.Disconnect = function(selectedIDs, context) {
27440 var vertices = _.filter(selectedIDs, function vertex(entityId) {
27441 return context.geometry(entityId) === 'vertex';
27444 var entityId = vertices[0],
27445 action = iD.actions.Disconnect(entityId);
27447 if (selectedIDs.length > 1) {
27448 action.limitWays(_.without(selectedIDs, entityId));
27451 var operation = function() {
27452 context.perform(action, t('operations.disconnect.annotation'));
27455 operation.available = function() {
27456 return vertices.length === 1;
27459 operation.disabled = function() {
27461 if (_.some(selectedIDs, context.hasHiddenConnections)) {
27462 reason = 'connected_to_hidden';
27464 return action.disabled(context.graph()) || reason;
27467 operation.tooltip = function() {
27468 var disable = operation.disabled();
27470 t('operations.disconnect.' + disable) :
27471 t('operations.disconnect.description');
27474 operation.id = 'disconnect';
27475 operation.keys = [t('operations.disconnect.key')];
27476 operation.title = t('operations.disconnect.title');
27480 iD.operations.Merge = function(selectedIDs, context) {
27481 var join = iD.actions.Join(selectedIDs),
27482 merge = iD.actions.Merge(selectedIDs),
27483 mergePolygon = iD.actions.MergePolygon(selectedIDs);
27485 var operation = function() {
27486 var annotation = t('operations.merge.annotation', {n: selectedIDs.length}),
27489 if (!join.disabled(context.graph())) {
27491 } else if (!merge.disabled(context.graph())) {
27494 action = mergePolygon;
27497 context.perform(action, annotation);
27498 context.enter(iD.modes.Select(context, selectedIDs.filter(function(id) { return context.hasEntity(id); }))
27499 .suppressMenu(true));
27502 operation.available = function() {
27503 return selectedIDs.length >= 2;
27506 operation.disabled = function() {
27507 return join.disabled(context.graph()) &&
27508 merge.disabled(context.graph()) &&
27509 mergePolygon.disabled(context.graph());
27512 operation.tooltip = function() {
27513 var j = join.disabled(context.graph()),
27514 m = merge.disabled(context.graph()),
27515 p = mergePolygon.disabled(context.graph());
27517 if (j === 'restriction' && m && p)
27518 return t('operations.merge.restriction', {relation: context.presets().item('type/restriction').name()});
27520 if (p === 'incomplete_relation' && j && m)
27521 return t('operations.merge.incomplete_relation');
27524 return t('operations.merge.' + j);
27526 return t('operations.merge.description');
27529 operation.id = 'merge';
27530 operation.keys = [t('operations.merge.key')];
27531 operation.title = t('operations.merge.title');
27535 iD.operations.Move = function(selectedIDs, context) {
27536 var extent = selectedIDs.reduce(function(extent, id) {
27537 return extent.extend(context.entity(id).extent(context.graph()));
27538 }, iD.geo.Extent());
27540 var operation = function() {
27541 context.enter(iD.modes.Move(context, selectedIDs));
27544 operation.available = function() {
27545 return selectedIDs.length > 1 ||
27546 context.entity(selectedIDs[0]).type !== 'node';
27549 operation.disabled = function() {
27551 if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
27552 reason = 'too_large';
27553 } else if (_.some(selectedIDs, context.hasHiddenConnections)) {
27554 reason = 'connected_to_hidden';
27556 return iD.actions.Move(selectedIDs).disabled(context.graph()) || reason;
27559 operation.tooltip = function() {
27560 var disable = operation.disabled();
27562 t('operations.move.' + disable) :
27563 t('operations.move.description');
27566 operation.id = 'move';
27567 operation.keys = [t('operations.move.key')];
27568 operation.title = t('operations.move.title');
27572 iD.operations.Orthogonalize = function(selectedIDs, context) {
27573 var entityId = selectedIDs[0],
27574 entity = context.entity(entityId),
27575 extent = entity.extent(context.graph()),
27576 geometry = context.geometry(entityId),
27577 action = iD.actions.Orthogonalize(entityId, context.projection);
27579 var operation = function() {
27580 var annotation = t('operations.orthogonalize.annotation.' + geometry);
27581 context.perform(action, annotation);
27584 operation.available = function() {
27585 return selectedIDs.length === 1 &&
27586 entity.type === 'way' &&
27587 entity.isClosed() &&
27588 _.uniq(entity.nodes).length > 2;
27591 operation.disabled = function() {
27593 if (extent.percentContainedIn(context.extent()) < 0.8) {
27594 reason = 'too_large';
27595 } else if (context.hasHiddenConnections(entityId)) {
27596 reason = 'connected_to_hidden';
27598 return action.disabled(context.graph()) || reason;
27601 operation.tooltip = function() {
27602 var disable = operation.disabled();
27604 t('operations.orthogonalize.' + disable) :
27605 t('operations.orthogonalize.description.' + geometry);
27608 operation.id = 'orthogonalize';
27609 operation.keys = [t('operations.orthogonalize.key')];
27610 operation.title = t('operations.orthogonalize.title');
27614 iD.operations.Reverse = function(selectedIDs, context) {
27615 var entityId = selectedIDs[0];
27617 var operation = function() {
27619 iD.actions.Reverse(entityId),
27620 t('operations.reverse.annotation'));
27623 operation.available = function() {
27624 return selectedIDs.length === 1 &&
27625 context.geometry(entityId) === 'line';
27628 operation.disabled = function() {
27632 operation.tooltip = function() {
27633 return t('operations.reverse.description');
27636 operation.id = 'reverse';
27637 operation.keys = [t('operations.reverse.key')];
27638 operation.title = t('operations.reverse.title');
27642 iD.operations.Rotate = function(selectedIDs, context) {
27643 var entityId = selectedIDs[0],
27644 entity = context.entity(entityId),
27645 extent = entity.extent(context.graph()),
27646 geometry = context.geometry(entityId);
27648 var operation = function() {
27649 context.enter(iD.modes.RotateWay(context, entityId));
27652 operation.available = function() {
27653 if (selectedIDs.length !== 1 || entity.type !== 'way')
27655 if (geometry === 'area')
27657 if (entity.isClosed() &&
27658 context.graph().parentRelations(entity).some(function(r) { return r.isMultipolygon(); }))
27663 operation.disabled = function() {
27664 if (extent.percentContainedIn(context.extent()) < 0.8) {
27665 return 'too_large';
27666 } else if (context.hasHiddenConnections(entityId)) {
27667 return 'connected_to_hidden';
27673 operation.tooltip = function() {
27674 var disable = operation.disabled();
27676 t('operations.rotate.' + disable) :
27677 t('operations.rotate.description');
27680 operation.id = 'rotate';
27681 operation.keys = [t('operations.rotate.key')];
27682 operation.title = t('operations.rotate.title');
27686 iD.operations.Split = function(selectedIDs, context) {
27687 var vertices = _.filter(selectedIDs, function vertex(entityId) {
27688 return context.geometry(entityId) === 'vertex';
27691 var entityId = vertices[0],
27692 action = iD.actions.Split(entityId);
27694 if (selectedIDs.length > 1) {
27695 action.limitWays(_.without(selectedIDs, entityId));
27698 var operation = function() {
27701 var ways = action.ways(context.graph());
27702 if (ways.length === 1) {
27703 annotation = t('operations.split.annotation.' + context.geometry(ways[0].id));
27705 annotation = t('operations.split.annotation.multiple', {n: ways.length});
27708 var difference = context.perform(action, annotation);
27709 context.enter(iD.modes.Select(context, difference.extantIDs()));
27712 operation.available = function() {
27713 return vertices.length === 1;
27716 operation.disabled = function() {
27718 if (_.some(selectedIDs, context.hasHiddenConnections)) {
27719 reason = 'connected_to_hidden';
27721 return action.disabled(context.graph()) || reason;
27724 operation.tooltip = function() {
27725 var disable = operation.disabled();
27727 return t('operations.split.' + disable);
27730 var ways = action.ways(context.graph());
27731 if (ways.length === 1) {
27732 return t('operations.split.description.' + context.geometry(ways[0].id));
27734 return t('operations.split.description.multiple');
27738 operation.id = 'split';
27739 operation.keys = [t('operations.split.key')];
27740 operation.title = t('operations.split.title');
27744 iD.operations.Straighten = function(selectedIDs, context) {
27745 var entityId = selectedIDs[0],
27746 action = iD.actions.Straighten(entityId, context.projection);
27748 function operation() {
27749 var annotation = t('operations.straighten.annotation');
27750 context.perform(action, annotation);
27753 operation.available = function() {
27754 var entity = context.entity(entityId);
27755 return selectedIDs.length === 1 &&
27756 entity.type === 'way' &&
27757 !entity.isClosed() &&
27758 _.uniq(entity.nodes).length > 2;
27761 operation.disabled = function() {
27763 if (context.hasHiddenConnections(entityId)) {
27764 reason = 'connected_to_hidden';
27766 return action.disabled(context.graph()) || reason;
27769 operation.tooltip = function() {
27770 var disable = operation.disabled();
27772 t('operations.straighten.' + disable) :
27773 t('operations.straighten.description');
27776 operation.id = 'straighten';
27777 operation.keys = [t('operations.straighten.key')];
27778 operation.title = t('operations.straighten.title');
27782 iD.Connection = function(useHttps) {
27783 if (typeof useHttps !== 'boolean') {
27784 useHttps = window.location.protocol === 'https:';
27787 var event = d3.dispatch('authenticating', 'authenticated', 'auth', 'loading', 'loaded'),
27788 protocol = useHttps ? 'https:' : 'http:',
27789 url = protocol + '//www.openstreetmap.org',
27795 url: protocol + '//www.openstreetmap.org',
27796 oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
27797 oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
27798 loading: authenticating,
27799 done: authenticated
27803 memberStr = 'member',
27806 relationStr = 'relation',
27811 connection.changesetURL = function(changesetId) {
27812 return url + '/changeset/' + changesetId;
27815 connection.changesetsURL = function(center, zoom) {
27816 var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
27817 return url + '/history#map=' +
27818 Math.floor(zoom) + '/' +
27819 center[1].toFixed(precision) + '/' +
27820 center[0].toFixed(precision);
27823 connection.entityURL = function(entity) {
27824 return url + '/' + entity.type + '/' + entity.osmId();
27827 connection.userURL = function(username) {
27828 return url + '/user/' + username;
27831 connection.loadFromURL = function(url, callback) {
27832 function done(err, dom) {
27833 return callback(err, parse(dom));
27835 return d3.xml(url).get(done);
27838 connection.loadEntity = function(id, callback) {
27839 var type = iD.Entity.id.type(id),
27840 osmID = iD.Entity.id.toOSM(id);
27842 connection.loadFromURL(
27843 url + '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
27844 function(err, entities) {
27845 if (callback) callback(err, {data: entities});
27849 connection.loadEntityVersion = function(id, version, callback) {
27850 var type = iD.Entity.id.type(id),
27851 osmID = iD.Entity.id.toOSM(id);
27853 connection.loadFromURL(
27854 url + '/api/0.6/' + type + '/' + osmID + '/' + version,
27855 function(err, entities) {
27856 if (callback) callback(err, {data: entities});
27860 connection.loadMultiple = function(ids, callback) {
27861 _.each(_.groupBy(_.uniq(ids), iD.Entity.id.type), function(v, k) {
27862 var type = k + 's',
27863 osmIDs = _.map(v, iD.Entity.id.toOSM);
27865 _.each(_.chunk(osmIDs, 150), function(arr) {
27866 connection.loadFromURL(
27867 url + '/api/0.6/' + type + '?' + type + '=' + arr.join(),
27868 function(err, entities) {
27869 if (callback) callback(err, {data: entities});
27875 function authenticating() {
27876 event.authenticating();
27879 function authenticated() {
27880 event.authenticated();
27883 function getLoc(attrs) {
27884 var lon = attrs.lon && attrs.lon.value,
27885 lat = attrs.lat && attrs.lat.value;
27886 return [parseFloat(lon), parseFloat(lat)];
27889 function getNodes(obj) {
27890 var elems = obj.getElementsByTagName(ndStr),
27891 nodes = new Array(elems.length);
27892 for (var i = 0, l = elems.length; i < l; i++) {
27893 nodes[i] = 'n' + elems[i].attributes.ref.value;
27898 function getTags(obj) {
27899 var elems = obj.getElementsByTagName(tagStr),
27901 for (var i = 0, l = elems.length; i < l; i++) {
27902 var attrs = elems[i].attributes;
27903 tags[attrs.k.value] = attrs.v.value;
27908 function getMembers(obj) {
27909 var elems = obj.getElementsByTagName(memberStr),
27910 members = new Array(elems.length);
27911 for (var i = 0, l = elems.length; i < l; i++) {
27912 var attrs = elems[i].attributes;
27914 id: attrs.type.value[0] + attrs.ref.value,
27915 type: attrs.type.value,
27916 role: attrs.role.value
27922 function getVisible(attrs) {
27923 return (!attrs.visible || attrs.visible.value !== 'false');
27927 node: function nodeData(obj) {
27928 var attrs = obj.attributes;
27929 return new iD.Node({
27930 id: iD.Entity.id.fromOSM(nodeStr, attrs.id.value),
27931 loc: getLoc(attrs),
27932 version: attrs.version.value,
27933 user: attrs.user && attrs.user.value,
27934 tags: getTags(obj),
27935 visible: getVisible(attrs)
27939 way: function wayData(obj) {
27940 var attrs = obj.attributes;
27941 return new iD.Way({
27942 id: iD.Entity.id.fromOSM(wayStr, attrs.id.value),
27943 version: attrs.version.value,
27944 user: attrs.user && attrs.user.value,
27945 tags: getTags(obj),
27946 nodes: getNodes(obj),
27947 visible: getVisible(attrs)
27951 relation: function relationData(obj) {
27952 var attrs = obj.attributes;
27953 return new iD.Relation({
27954 id: iD.Entity.id.fromOSM(relationStr, attrs.id.value),
27955 version: attrs.version.value,
27956 user: attrs.user && attrs.user.value,
27957 tags: getTags(obj),
27958 members: getMembers(obj),
27959 visible: getVisible(attrs)
27964 function parse(dom) {
27965 if (!dom || !dom.childNodes) return;
27967 var root = dom.childNodes[0],
27968 children = root.childNodes,
27971 for (var i = 0, l = children.length; i < l; i++) {
27972 var child = children[i],
27973 parser = parsers[child.nodeName];
27975 entities.push(parser(child));
27982 connection.authenticated = function() {
27983 return oauth.authenticated();
27986 // Generate Changeset XML. Returns a string.
27987 connection.changesetJXON = function(tags) {
27991 tag: _.map(tags, function(value, key) {
27992 return { '@k': key, '@v': value };
28001 // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
28002 // XML. Returns a string.
28003 connection.osmChangeJXON = function(changeset_id, changes) {
28004 function nest(x, order) {
28006 for (var i = 0; i < x.length; i++) {
28007 var tagName = Object.keys(x[i])[0];
28008 if (!groups[tagName]) groups[tagName] = [];
28009 groups[tagName].push(x[i][tagName]);
28012 order.forEach(function(o) {
28013 if (groups[o]) ordered[o] = groups[o];
28018 function rep(entity) {
28019 return entity.asJXON(changeset_id);
28025 '@generator': 'iD',
28026 'create': nest(changes.created.map(rep), ['node', 'way', 'relation']),
28027 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
28028 'delete': _.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {'@if-unused': true})
28033 connection.changesetTags = function(comment, imageryUsed) {
28034 var detected = iD.detect(),
28036 created_by: 'iD ' + iD.version,
28037 imagery_used: imageryUsed.join(';').substr(0, 255),
28038 host: (window.location.origin + window.location.pathname).substr(0, 255),
28039 locale: detected.locale
28043 tags.comment = comment.substr(0, 255);
28049 connection.putChangeset = function(changes, comment, imageryUsed, callback) {
28052 path: '/api/0.6/changeset/create',
28053 options: { header: { 'Content-Type': 'text/xml' } },
28054 content: JXON.stringify(connection.changesetJXON(connection.changesetTags(comment, imageryUsed)))
28055 }, function(err, changeset_id) {
28056 if (err) return callback(err);
28059 path: '/api/0.6/changeset/' + changeset_id + '/upload',
28060 options: { header: { 'Content-Type': 'text/xml' } },
28061 content: JXON.stringify(connection.osmChangeJXON(changeset_id, changes))
28063 if (err) return callback(err);
28064 // POST was successful, safe to call the callback.
28065 // Still attempt to close changeset, but ignore response because #2667
28066 // Add delay to allow for postgres replication #1646 #2678
28067 window.setTimeout(function() { callback(null, changeset_id); }, 2500);
28070 path: '/api/0.6/changeset/' + changeset_id + '/close',
28071 options: { header: { 'Content-Type': 'text/xml' } }
28072 }, d3.functor(true));
28077 connection.userDetails = function(callback) {
28079 callback(undefined, userDetails);
28083 function done(err, user_details) {
28084 if (err) return callback(err);
28086 var u = user_details.getElementsByTagName('user')[0],
28087 img = u.getElementsByTagName('img'),
28090 if (img && img[0] && img[0].getAttribute('href')) {
28091 image_url = img[0].getAttribute('href');
28095 display_name: u.attributes.display_name.value,
28096 image_url: image_url,
28097 id: u.attributes.id.value
28100 callback(undefined, userDetails);
28103 oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
28106 connection.userChangesets = function(callback) {
28107 connection.userDetails(function(err, user) {
28108 if (err) return callback(err);
28110 function done(changesets) {
28111 callback(undefined, Array.prototype.map.call(changesets.getElementsByTagName('changeset'),
28112 function (changeset) {
28113 return { tags: getTags(changeset) };
28117 d3.xml(url + '/api/0.6/changesets?user=' + user.id).get()
28119 .on('error', callback);
28123 connection.status = function(callback) {
28124 function done(capabilities) {
28125 var apiStatus = capabilities.getElementsByTagName('status');
28126 callback(undefined, apiStatus[0].getAttribute('api'));
28128 d3.xml(url + '/api/capabilities').get()
28130 .on('error', callback);
28133 function abortRequest(i) { i.abort(); }
28135 connection.tileZoom = function(_) {
28136 if (!arguments.length) return tileZoom;
28141 connection.loadTiles = function(projection, dimensions, callback) {
28145 var s = projection.scale() * 2 * Math.PI,
28146 z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
28147 ts = 256 * Math.pow(2, z - tileZoom),
28149 s / 2 - projection.translate()[0],
28150 s / 2 - projection.translate()[1]];
28152 var tiles = d3.geo.tile()
28153 .scaleExtent([tileZoom, tileZoom])
28156 .translate(projection.translate())()
28157 .map(function(tile) {
28158 var x = tile[0] * ts - origin[0],
28159 y = tile[1] * ts - origin[1];
28162 id: tile.toString(),
28163 extent: iD.geo.Extent(
28164 projection.invert([x, y + ts]),
28165 projection.invert([x + ts, y]))
28169 function bboxUrl(tile) {
28170 return url + '/api/0.6/map?bbox=' + tile.extent.toParam();
28173 _.filter(inflight, function(v, i) {
28174 var wanted = _.find(tiles, function(tile) {
28175 return i === tile.id;
28177 if (!wanted) delete inflight[i];
28179 }).map(abortRequest);
28181 tiles.forEach(function(tile) {
28184 if (loadedTiles[id] || inflight[id]) return;
28186 if (_.isEmpty(inflight)) {
28190 inflight[id] = connection.loadFromURL(bboxUrl(tile), function(err, parsed) {
28191 loadedTiles[id] = true;
28192 delete inflight[id];
28194 if (callback) callback(err, _.extend({data: parsed}, tile));
28196 if (_.isEmpty(inflight)) {
28203 connection.switch = function(options) {
28205 oauth.options(_.extend({
28206 loading: authenticating,
28207 done: authenticated
28210 connection.flush();
28214 connection.toggle = function(_) {
28219 connection.flush = function() {
28220 userDetails = undefined;
28221 _.forEach(inflight, abortRequest);
28227 connection.loadedTiles = function(_) {
28228 if (!arguments.length) return loadedTiles;
28233 connection.logout = function() {
28234 userDetails = undefined;
28240 connection.authenticate = function(callback) {
28241 userDetails = undefined;
28242 function done(err, res) {
28244 if (callback) callback(err, res);
28246 return oauth.authenticate(done);
28249 return d3.rebind(connection, event, 'on');
28252 iD.Difference represents the difference between two graphs.
28253 It knows how to calculate the set of entities that were
28254 created, modified, or deleted, and also contains the logic
28255 for recursively extending a difference to the complete set
28256 of entities that will require a redraw, taking into account
28257 child and parent relationships.
28259 iD.Difference = function(base, head) {
28260 var changes = {}, length = 0;
28262 function changed(h, b) {
28263 return h !== b && !_.isEqual(_.omit(h, 'v'), _.omit(b, 'v'));
28266 _.each(head.entities, function(h, id) {
28267 var b = base.entities[id];
28268 if (changed(h, b)) {
28269 changes[id] = {base: b, head: h};
28274 _.each(base.entities, function(b, id) {
28275 var h = head.entities[id];
28276 if (!changes[id] && changed(h, b)) {
28277 changes[id] = {base: b, head: h};
28282 function addParents(parents, result) {
28283 for (var i = 0; i < parents.length; i++) {
28284 var parent = parents[i];
28286 if (parent.id in result)
28289 result[parent.id] = parent;
28290 addParents(head.parentRelations(parent), result);
28294 var difference = {};
28296 difference.length = function() {
28300 difference.changes = function() {
28304 difference.extantIDs = function() {
28306 _.each(changes, function(change, id) {
28307 if (change.head) result.push(id);
28312 difference.modified = function() {
28314 _.each(changes, function(change) {
28315 if (change.base && change.head) result.push(change.head);
28320 difference.created = function() {
28322 _.each(changes, function(change) {
28323 if (!change.base && change.head) result.push(change.head);
28328 difference.deleted = function() {
28330 _.each(changes, function(change) {
28331 if (change.base && !change.head) result.push(change.base);
28336 difference.summary = function() {
28339 function addEntity(entity, graph, changeType) {
28340 relevant[entity.id] = {
28343 changeType: changeType
28347 function addParents(entity) {
28348 var parents = head.parentWays(entity);
28349 for (var j = parents.length - 1; j >= 0; j--) {
28350 var parent = parents[j];
28351 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
28355 _.each(changes, function(change) {
28356 if (change.head && change.head.geometry(head) !== 'vertex') {
28357 addEntity(change.head, head, change.base ? 'modified' : 'created');
28359 } else if (change.base && change.base.geometry(base) !== 'vertex') {
28360 addEntity(change.base, base, 'deleted');
28362 } else if (change.base && change.head) { // modified vertex
28363 var moved = !_.isEqual(change.base.loc, change.head.loc),
28364 retagged = !_.isEqual(change.base.tags, change.head.tags);
28367 addParents(change.head);
28370 if (retagged || (moved && change.head.hasInterestingTags())) {
28371 addEntity(change.head, head, 'modified');
28374 } else if (change.head && change.head.hasInterestingTags()) { // created vertex
28375 addEntity(change.head, head, 'created');
28377 } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
28378 addEntity(change.base, base, 'deleted');
28382 return d3.values(relevant);
28385 difference.complete = function(extent) {
28386 var result = {}, id, change;
28388 for (id in changes) {
28389 change = changes[id];
28391 var h = change.head,
28396 (!h || !h.intersects(extent, head)) &&
28397 (!b || !b.intersects(extent, base)))
28402 if (entity.type === 'way') {
28403 var nh = h ? h.nodes : [],
28404 nb = b ? b.nodes : [],
28407 diff = _.difference(nh, nb);
28408 for (i = 0; i < diff.length; i++) {
28409 result[diff[i]] = head.hasEntity(diff[i]);
28412 diff = _.difference(nb, nh);
28413 for (i = 0; i < diff.length; i++) {
28414 result[diff[i]] = head.hasEntity(diff[i]);
28418 addParents(head.parentWays(entity), result);
28419 addParents(head.parentRelations(entity), result);
28427 iD.Entity = function(attrs) {
28428 // For prototypal inheritance.
28429 if (this instanceof iD.Entity) return;
28431 // Create the appropriate subtype.
28432 if (attrs && attrs.type) {
28433 return iD.Entity[attrs.type].apply(this, arguments);
28434 } else if (attrs && attrs.id) {
28435 return iD.Entity[iD.Entity.id.type(attrs.id)].apply(this, arguments);
28438 // Initialize a generic Entity (used only in tests).
28439 return (new iD.Entity()).initialize(arguments);
28442 iD.Entity.id = function(type) {
28443 return iD.Entity.id.fromOSM(type, iD.Entity.id.next[type]--);
28446 iD.Entity.id.next = {node: -1, way: -1, relation: -1};
28448 iD.Entity.id.fromOSM = function(type, id) {
28449 return type[0] + id;
28452 iD.Entity.id.toOSM = function(id) {
28453 return id.slice(1);
28456 iD.Entity.id.type = function(id) {
28457 return {'n': 'node', 'w': 'way', 'r': 'relation'}[id[0]];
28460 // A function suitable for use as the second argument to d3.selection#data().
28461 iD.Entity.key = function(entity) {
28462 return entity.id + 'v' + (entity.v || 0);
28465 iD.Entity.prototype = {
28468 initialize: function(sources) {
28469 for (var i = 0; i < sources.length; ++i) {
28470 var source = sources[i];
28471 for (var prop in source) {
28472 if (Object.prototype.hasOwnProperty.call(source, prop)) {
28473 if (source[prop] === undefined) {
28476 this[prop] = source[prop];
28482 if (!this.id && this.type) {
28483 this.id = iD.Entity.id(this.type);
28485 if (!this.hasOwnProperty('visible')) {
28486 this.visible = true;
28490 Object.freeze(this);
28491 Object.freeze(this.tags);
28493 if (this.loc) Object.freeze(this.loc);
28494 if (this.nodes) Object.freeze(this.nodes);
28495 if (this.members) Object.freeze(this.members);
28501 copy: function(resolver, copies) {
28502 if (copies[this.id])
28503 return copies[this.id];
28505 var copy = iD.Entity(this, {id: undefined, user: undefined, version: undefined});
28506 copies[this.id] = copy;
28511 osmId: function() {
28512 return iD.Entity.id.toOSM(this.id);
28515 isNew: function() {
28516 return this.osmId() < 0;
28519 update: function(attrs) {
28520 return iD.Entity(this, attrs, {v: 1 + (this.v || 0)});
28523 mergeTags: function(tags) {
28524 var merged = _.clone(this.tags), changed = false;
28525 for (var k in tags) {
28526 var t1 = merged[k],
28531 } else if (t1 !== t2) {
28533 merged[k] = _.union(t1.split(/;\s*/), t2.split(/;\s*/)).join(';');
28536 return changed ? this.update({tags: merged}) : this;
28539 intersects: function(extent, resolver) {
28540 return this.extent(resolver).intersects(extent);
28543 isUsed: function(resolver) {
28544 return _.without(Object.keys(this.tags), 'area').length > 0 ||
28545 resolver.parentRelations(this).length > 0;
28548 hasInterestingTags: function() {
28549 return _.keys(this.tags).some(iD.interestingTag);
28552 isHighwayIntersection: function() {
28556 deprecatedTags: function() {
28557 var tags = _.toPairs(this.tags);
28558 var deprecated = {};
28560 iD.data.deprecated.forEach(function(d) {
28561 var match = _.toPairs(d.old)[0];
28562 tags.forEach(function(t) {
28563 if (t[0] === match[0] &&
28564 (t[1] === match[1] || match[1] === '*')) {
28565 deprecated[t[0]] = t[1];
28573 iD.Graph = function(other, mutable) {
28574 if (!(this instanceof iD.Graph)) return new iD.Graph(other, mutable);
28576 if (other instanceof iD.Graph) {
28577 var base = other.base();
28578 this.entities = _.assign(Object.create(base.entities), other.entities);
28579 this._parentWays = _.assign(Object.create(base.parentWays), other._parentWays);
28580 this._parentRels = _.assign(Object.create(base.parentRels), other._parentRels);
28583 this.entities = Object.create({});
28584 this._parentWays = Object.create({});
28585 this._parentRels = Object.create({});
28586 this.rebase(other || [], [this]);
28589 this.transients = {};
28590 this._childNodes = {};
28591 this.frozen = !mutable;
28594 iD.Graph.prototype = {
28595 hasEntity: function(id) {
28596 return this.entities[id];
28599 entity: function(id) {
28600 var entity = this.entities[id];
28602 throw new Error('entity ' + id + ' not found');
28607 transient: function(entity, key, fn) {
28608 var id = entity.id,
28609 transients = this.transients[id] ||
28610 (this.transients[id] = {});
28612 if (transients[key] !== undefined) {
28613 return transients[key];
28616 transients[key] = fn.call(entity);
28618 return transients[key];
28621 parentWays: function(entity) {
28622 var parents = this._parentWays[entity.id],
28626 for (var i = 0; i < parents.length; i++) {
28627 result.push(this.entity(parents[i]));
28633 isPoi: function(entity) {
28634 var parentWays = this._parentWays[entity.id];
28635 return !parentWays || parentWays.length === 0;
28638 isShared: function(entity) {
28639 var parentWays = this._parentWays[entity.id];
28640 return parentWays && parentWays.length > 1;
28643 parentRelations: function(entity) {
28644 var parents = this._parentRels[entity.id],
28648 for (var i = 0; i < parents.length; i++) {
28649 result.push(this.entity(parents[i]));
28655 childNodes: function(entity) {
28656 if (this._childNodes[entity.id]) return this._childNodes[entity.id];
28657 if (!entity.nodes) return [];
28660 for (var i = 0; i < entity.nodes.length; i++) {
28661 nodes[i] = this.entity(entity.nodes[i]);
28664 if (iD.debug) Object.freeze(nodes);
28666 this._childNodes[entity.id] = nodes;
28667 return this._childNodes[entity.id];
28672 'entities': iD.util.getPrototypeOf(this.entities),
28673 'parentWays': iD.util.getPrototypeOf(this._parentWays),
28674 'parentRels': iD.util.getPrototypeOf(this._parentRels)
28678 // Unlike other graph methods, rebase mutates in place. This is because it
28679 // is used only during the history operation that merges newly downloaded
28680 // data into each state. To external consumers, it should appear as if the
28681 // graph always contained the newly downloaded data.
28682 rebase: function(entities, stack, force) {
28683 var base = this.base(),
28686 for (i = 0; i < entities.length; i++) {
28687 var entity = entities[i];
28689 if (!entity.visible || (!force && base.entities[entity.id]))
28692 // Merging data into the base graph
28693 base.entities[entity.id] = entity;
28694 this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
28696 // Restore provisionally-deleted nodes that are discovered to have an extant parent
28697 if (entity.type === 'way') {
28698 for (j = 0; j < entity.nodes.length; j++) {
28699 id = entity.nodes[j];
28700 for (k = 1; k < stack.length; k++) {
28701 var ents = stack[k].entities;
28702 if (ents.hasOwnProperty(id) && ents[id] === undefined) {
28710 for (i = 0; i < stack.length; i++) {
28711 stack[i]._updateRebased();
28715 _updateRebased: function() {
28716 var base = this.base(),
28717 i, k, child, id, keys;
28719 keys = Object.keys(this._parentWays);
28720 for (i = 0; i < keys.length; i++) {
28722 if (base.parentWays[child]) {
28723 for (k = 0; k < base.parentWays[child].length; k++) {
28724 id = base.parentWays[child][k];
28725 if (!this.entities.hasOwnProperty(id) && !_.includes(this._parentWays[child], id)) {
28726 this._parentWays[child].push(id);
28732 keys = Object.keys(this._parentRels);
28733 for (i = 0; i < keys.length; i++) {
28735 if (base.parentRels[child]) {
28736 for (k = 0; k < base.parentRels[child].length; k++) {
28737 id = base.parentRels[child][k];
28738 if (!this.entities.hasOwnProperty(id) && !_.includes(this._parentRels[child], id)) {
28739 this._parentRels[child].push(id);
28745 this.transients = {};
28747 // this._childNodes is not updated, under the assumption that
28748 // ways are always downloaded with their child nodes.
28751 // Updates calculated properties (parentWays, parentRels) for the specified change
28752 _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
28754 parentWays = parentWays || this._parentWays;
28755 parentRels = parentRels || this._parentRels;
28757 var type = entity && entity.type || oldentity && oldentity.type,
28758 removed, added, ways, rels, i;
28761 if (type === 'way') {
28763 // Update parentWays
28764 if (oldentity && entity) {
28765 removed = _.difference(oldentity.nodes, entity.nodes);
28766 added = _.difference(entity.nodes, oldentity.nodes);
28767 } else if (oldentity) {
28768 removed = oldentity.nodes;
28770 } else if (entity) {
28772 added = entity.nodes;
28774 for (i = 0; i < removed.length; i++) {
28775 parentWays[removed[i]] = _.without(parentWays[removed[i]], oldentity.id);
28777 for (i = 0; i < added.length; i++) {
28778 ways = _.without(parentWays[added[i]], entity.id);
28779 ways.push(entity.id);
28780 parentWays[added[i]] = ways;
28783 } else if (type === 'relation') {
28785 // Update parentRels
28786 if (oldentity && entity) {
28787 removed = _.difference(oldentity.members, entity.members);
28788 added = _.difference(entity.members, oldentity);
28789 } else if (oldentity) {
28790 removed = oldentity.members;
28792 } else if (entity) {
28794 added = entity.members;
28796 for (i = 0; i < removed.length; i++) {
28797 parentRels[removed[i].id] = _.without(parentRels[removed[i].id], oldentity.id);
28799 for (i = 0; i < added.length; i++) {
28800 rels = _.without(parentRels[added[i].id], entity.id);
28801 rels.push(entity.id);
28802 parentRels[added[i].id] = rels;
28807 replace: function(entity) {
28808 if (this.entities[entity.id] === entity)
28811 return this.update(function() {
28812 this._updateCalculated(this.entities[entity.id], entity);
28813 this.entities[entity.id] = entity;
28817 remove: function(entity) {
28818 return this.update(function() {
28819 this._updateCalculated(entity, undefined);
28820 this.entities[entity.id] = undefined;
28824 revert: function(id) {
28825 var baseEntity = this.base().entities[id],
28826 headEntity = this.entities[id];
28828 if (headEntity === baseEntity)
28831 return this.update(function() {
28832 this._updateCalculated(headEntity, baseEntity);
28833 delete this.entities[id];
28837 update: function() {
28838 var graph = this.frozen ? iD.Graph(this, true) : this;
28840 for (var i = 0; i < arguments.length; i++) {
28841 arguments[i].call(graph, graph);
28844 if (this.frozen) graph.frozen = true;
28849 // Obliterates any existing entities
28850 load: function(entities) {
28851 var base = this.base();
28852 this.entities = Object.create(base.entities);
28854 for (var i in entities) {
28855 this.entities[i] = entities[i];
28856 this._updateCalculated(base.entities[i], this.entities[i]);
28862 iD.History = function(context) {
28863 var stack, index, tree,
28864 imageryUsed = ['Bing'],
28865 dispatch = d3.dispatch('change', 'undone', 'redone'),
28866 lock = iD.util.SessionMutex('lock');
28868 function perform(actions) {
28869 actions = Array.prototype.slice.call(actions);
28873 if (!_.isFunction(_.last(actions))) {
28874 annotation = actions.pop();
28877 var graph = stack[index].graph;
28878 for (var i = 0; i < actions.length; i++) {
28879 graph = actions[i](graph);
28884 annotation: annotation,
28885 imageryUsed: imageryUsed
28889 function change(previous) {
28890 var difference = iD.Difference(previous, history.graph());
28891 dispatch.change(difference);
28895 // iD uses namespaced keys so multiple installations do not conflict
28896 function getKey(n) {
28897 return 'iD_' + window.location.origin + '_' + n;
28901 graph: function() {
28902 return stack[index].graph;
28906 return stack[0].graph;
28909 merge: function(entities, extent) {
28910 stack[0].graph.rebase(entities, _.map(stack, 'graph'), false);
28911 tree.rebase(entities, false);
28913 dispatch.change(undefined, extent);
28916 perform: function() {
28917 var previous = stack[index].graph;
28919 stack = stack.slice(0, index + 1);
28920 stack.push(perform(arguments));
28923 return change(previous);
28926 replace: function() {
28927 var previous = stack[index].graph;
28929 // assert(index == stack.length - 1)
28930 stack[index] = perform(arguments);
28932 return change(previous);
28936 var previous = stack[index].graph;
28941 return change(previous);
28945 // Same as calling pop and then perform
28946 overwrite: function() {
28947 var previous = stack[index].graph;
28953 stack = stack.slice(0, index + 1);
28954 stack.push(perform(arguments));
28957 return change(previous);
28961 var previous = stack[index].graph;
28963 // Pop to the next annotated state.
28964 while (index > 0) {
28966 if (stack[index].annotation) break;
28970 return change(previous);
28974 var previous = stack[index].graph;
28976 while (index < stack.length - 1) {
28978 if (stack[index].annotation) break;
28982 return change(previous);
28985 undoAnnotation: function() {
28988 if (stack[i].annotation) return stack[i].annotation;
28993 redoAnnotation: function() {
28995 while (i <= stack.length - 1) {
28996 if (stack[i].annotation) return stack[i].annotation;
29001 intersects: function(extent) {
29002 return tree.intersects(extent, stack[index].graph);
29005 difference: function() {
29006 var base = stack[0].graph,
29007 head = stack[index].graph;
29008 return iD.Difference(base, head);
29011 changes: function(action) {
29012 var base = stack[0].graph,
29013 head = stack[index].graph;
29016 head = action(head);
29019 var difference = iD.Difference(base, head);
29022 modified: difference.modified(),
29023 created: difference.created(),
29024 deleted: difference.deleted()
29028 validate: function(changes) {
29029 return _(iD.validations)
29030 .map(function(fn) { return fn()(changes, stack[index].graph); })
29035 hasChanges: function() {
29036 return this.difference().length() > 0;
29039 imageryUsed: function(sources) {
29041 imageryUsed = sources;
29044 return _(stack.slice(1, index + 1))
29045 .map('imageryUsed')
29048 .without(undefined, 'Custom')
29053 reset: function() {
29054 stack = [{graph: iD.Graph()}];
29056 tree = iD.Tree(stack[0].graph);
29061 toJSON: function() {
29062 if (!this.hasChanges()) return;
29064 var allEntities = {},
29068 var s = stack.map(function(i) {
29069 var modified = [], deleted = [];
29071 _.forEach(i.graph.entities, function(entity, id) {
29073 var key = iD.Entity.key(entity);
29074 allEntities[key] = entity;
29075 modified.push(key);
29080 // make sure that the originals of changed or deleted entities get merged
29081 // into the base of the stack after restoring the data from JSON.
29082 if (id in base.graph.entities) {
29083 baseEntities[id] = base.graph.entities[id];
29085 // get originals of parent entities too
29086 _.forEach(base.graph._parentWays[id], function(parentId) {
29087 if (parentId in base.graph.entities) {
29088 baseEntities[parentId] = base.graph.entities[parentId];
29095 if (modified.length) x.modified = modified;
29096 if (deleted.length) x.deleted = deleted;
29097 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
29098 if (i.annotation) x.annotation = i.annotation;
29103 return JSON.stringify({
29105 entities: _.values(allEntities),
29106 baseEntities: _.values(baseEntities),
29108 nextIDs: iD.Entity.id.next,
29113 fromJSON: function(json, loadChildNodes) {
29114 var h = JSON.parse(json),
29115 loadComplete = true;
29117 iD.Entity.id.next = h.nextIDs;
29120 if (h.version === 2 || h.version === 3) {
29121 var allEntities = {};
29123 h.entities.forEach(function(entity) {
29124 allEntities[iD.Entity.key(entity)] = iD.Entity(entity);
29127 if (h.version === 3) {
29128 // This merges originals for changed entities into the base of
29129 // the stack even if the current stack doesn't have them (for
29130 // example when iD has been restarted in a different region)
29131 var baseEntities = h.baseEntities.map(function(d) { return iD.Entity(d); });
29132 stack[0].graph.rebase(baseEntities, _.map(stack, 'graph'), true);
29133 tree.rebase(baseEntities, true);
29135 // When we restore a modified way, we also need to fetch any missing
29136 // childnodes that would normally have been downloaded with it.. #2142
29137 if (loadChildNodes) {
29138 var missing = _(baseEntities)
29139 .filter({ type: 'way' })
29143 .reject(function(n) { return stack[0].graph.hasEntity(n); })
29146 if (!_.isEmpty(missing)) {
29147 loadComplete = false;
29148 context.redrawEnable(false);
29150 var loading = iD.ui.Loading(context).blocking(true);
29151 context.container().call(loading);
29153 var childNodesLoaded = function(err, result) {
29155 var visible = _.groupBy(result.data, 'visible');
29156 if (!_.isEmpty(visible.true)) {
29157 missing = _.difference(missing, _.map(visible.true, 'id'));
29158 stack[0].graph.rebase(visible.true, _.map(stack, 'graph'), true);
29159 tree.rebase(visible.true, true);
29162 // fetch older versions of nodes that were deleted..
29163 _.each(visible.false, function(entity) {
29164 context.connection()
29165 .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
29169 if (err || _.isEmpty(missing)) {
29171 context.redrawEnable(true);
29176 context.connection().loadMultiple(missing, childNodesLoaded);
29181 stack = h.stack.map(function(d) {
29182 var entities = {}, entity;
29185 d.modified.forEach(function(key) {
29186 entity = allEntities[key];
29187 entities[entity.id] = entity;
29192 d.deleted.forEach(function(id) {
29193 entities[id] = undefined;
29198 graph: iD.Graph(stack[0].graph).load(entities),
29199 annotation: d.annotation,
29200 imageryUsed: d.imageryUsed
29204 } else { // original version
29205 stack = h.stack.map(function(d) {
29208 for (var i in d.entities) {
29209 var entity = d.entities[i];
29210 entities[i] = entity === 'undefined' ? undefined : iD.Entity(entity);
29213 d.graph = iD.Graph(stack[0].graph).load(entities);
29218 if (loadComplete) {
29226 if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
29230 clearSaved: function() {
29231 context.debouncedSave.cancel();
29232 if (lock.locked()) context.storage(getKey('saved_history'), null);
29237 return lock.lock();
29240 unlock: function() {
29244 // is iD not open in another window and it detects that
29245 // there's a history stored in localStorage that's recoverable?
29246 restorableChanges: function() {
29247 return lock.locked() && !!context.storage(getKey('saved_history'));
29250 // load history from a version stored in localStorage
29251 restore: function() {
29252 if (!lock.locked()) return;
29254 var json = context.storage(getKey('saved_history'));
29255 if (json) history.fromJSON(json, true);
29264 return d3.rebind(history, dispatch, 'on');
29266 iD.Node = iD.Entity.node = function iD_Node() {
29267 if (!(this instanceof iD_Node)) {
29268 return (new iD_Node()).initialize(arguments);
29269 } else if (arguments.length) {
29270 this.initialize(arguments);
29274 iD.Node.prototype = Object.create(iD.Entity.prototype);
29276 _.extend(iD.Node.prototype, {
29279 extent: function() {
29280 return new iD.geo.Extent(this.loc);
29283 geometry: function(graph) {
29284 return graph.transient(this, 'geometry', function() {
29285 return graph.isPoi(this) ? 'point' : 'vertex';
29289 move: function(loc) {
29290 return this.update({loc: loc});
29293 isIntersection: function(resolver) {
29294 return resolver.transient(this, 'isIntersection', function() {
29295 return resolver.parentWays(this).filter(function(parent) {
29296 return (parent.tags.highway ||
29297 parent.tags.waterway ||
29298 parent.tags.railway ||
29299 parent.tags.aeroway) &&
29300 parent.geometry(resolver) === 'line';
29305 isHighwayIntersection: function(resolver) {
29306 return resolver.transient(this, 'isHighwayIntersection', function() {
29307 return resolver.parentWays(this).filter(function(parent) {
29308 return parent.tags.highway && parent.geometry(resolver) === 'line';
29313 asJXON: function(changeset_id) {
29316 '@id': this.osmId(),
29317 '@lon': this.loc[0],
29318 '@lat': this.loc[1],
29319 '@version': (this.version || 0),
29320 tag: _.map(this.tags, function(v, k) {
29321 return { keyAttributes: { k: k, v: v } };
29325 if (changeset_id) r.node['@changeset'] = changeset_id;
29329 asGeoJSON: function() {
29332 coordinates: this.loc
29336 iD.Relation = iD.Entity.relation = function iD_Relation() {
29337 if (!(this instanceof iD_Relation)) {
29338 return (new iD_Relation()).initialize(arguments);
29339 } else if (arguments.length) {
29340 this.initialize(arguments);
29344 iD.Relation.prototype = Object.create(iD.Entity.prototype);
29346 iD.Relation.creationOrder = function(a, b) {
29347 var aId = parseInt(iD.Entity.id.toOSM(a.id), 10);
29348 var bId = parseInt(iD.Entity.id.toOSM(b.id), 10);
29350 if (aId < 0 || bId < 0) return aId - bId;
29354 _.extend(iD.Relation.prototype, {
29358 copy: function(resolver, copies) {
29359 if (copies[this.id])
29360 return copies[this.id];
29362 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
29364 var members = this.members.map(function(member) {
29365 return _.extend({}, member, {id: resolver.entity(member.id).copy(resolver, copies).id});
29368 copy = copy.update({members: members});
29369 copies[this.id] = copy;
29374 extent: function(resolver, memo) {
29375 return resolver.transient(this, 'extent', function() {
29376 if (memo && memo[this.id]) return iD.geo.Extent();
29378 memo[this.id] = true;
29380 var extent = iD.geo.Extent();
29381 for (var i = 0; i < this.members.length; i++) {
29382 var member = resolver.hasEntity(this.members[i].id);
29384 extent._extend(member.extent(resolver, memo));
29391 geometry: function(graph) {
29392 return graph.transient(this, 'geometry', function() {
29393 return this.isMultipolygon() ? 'area' : 'relation';
29397 isDegenerate: function() {
29398 return this.members.length === 0;
29401 // Return an array of members, each extended with an 'index' property whose value
29402 // is the member index.
29403 indexedMembers: function() {
29404 var result = new Array(this.members.length);
29405 for (var i = 0; i < this.members.length; i++) {
29406 result[i] = _.extend({}, this.members[i], {index: i});
29411 // Return the first member with the given role. A copy of the member object
29412 // is returned, extended with an 'index' property whose value is the member index.
29413 memberByRole: function(role) {
29414 for (var i = 0; i < this.members.length; i++) {
29415 if (this.members[i].role === role) {
29416 return _.extend({}, this.members[i], {index: i});
29421 // Return the first member with the given id. A copy of the member object
29422 // is returned, extended with an 'index' property whose value is the member index.
29423 memberById: function(id) {
29424 for (var i = 0; i < this.members.length; i++) {
29425 if (this.members[i].id === id) {
29426 return _.extend({}, this.members[i], {index: i});
29431 // Return the first member with the given id and role. A copy of the member object
29432 // is returned, extended with an 'index' property whose value is the member index.
29433 memberByIdAndRole: function(id, role) {
29434 for (var i = 0; i < this.members.length; i++) {
29435 if (this.members[i].id === id && this.members[i].role === role) {
29436 return _.extend({}, this.members[i], {index: i});
29441 addMember: function(member, index) {
29442 var members = this.members.slice();
29443 members.splice(index === undefined ? members.length : index, 0, member);
29444 return this.update({members: members});
29447 updateMember: function(member, index) {
29448 var members = this.members.slice();
29449 members.splice(index, 1, _.extend({}, members[index], member));
29450 return this.update({members: members});
29453 removeMember: function(index) {
29454 var members = this.members.slice();
29455 members.splice(index, 1);
29456 return this.update({members: members});
29459 removeMembersWithID: function(id) {
29460 var members = _.reject(this.members, function(m) { return m.id === id; });
29461 return this.update({members: members});
29464 // Wherever a member appears with id `needle.id`, replace it with a member
29465 // with id `replacement.id`, type `replacement.type`, and the original role,
29466 // unless a member already exists with that id and role. Return an updated
29468 replaceMember: function(needle, replacement) {
29469 if (!this.memberById(needle.id))
29474 for (var i = 0; i < this.members.length; i++) {
29475 var member = this.members[i];
29476 if (member.id !== needle.id) {
29477 members.push(member);
29478 } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
29479 members.push({id: replacement.id, type: replacement.type, role: member.role});
29483 return this.update({members: members});
29486 asJXON: function(changeset_id) {
29489 '@id': this.osmId(),
29490 '@version': this.version || 0,
29491 member: _.map(this.members, function(member) {
29492 return { keyAttributes: { type: member.type, role: member.role, ref: iD.Entity.id.toOSM(member.id) } };
29494 tag: _.map(this.tags, function(v, k) {
29495 return { keyAttributes: { k: k, v: v } };
29499 if (changeset_id) r.relation['@changeset'] = changeset_id;
29503 asGeoJSON: function(resolver) {
29504 return resolver.transient(this, 'GeoJSON', function () {
29505 if (this.isMultipolygon()) {
29507 type: 'MultiPolygon',
29508 coordinates: this.multipolygon(resolver)
29512 type: 'FeatureCollection',
29513 properties: this.tags,
29514 features: this.members.map(function (member) {
29515 return _.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
29522 area: function(resolver) {
29523 return resolver.transient(this, 'area', function() {
29524 return d3.geo.area(this.asGeoJSON(resolver));
29528 isMultipolygon: function() {
29529 return this.tags.type === 'multipolygon';
29532 isComplete: function(resolver) {
29533 for (var i = 0; i < this.members.length; i++) {
29534 if (!resolver.hasEntity(this.members[i].id)) {
29541 isRestriction: function() {
29542 return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
29545 // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
29546 // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
29548 // This corresponds to the structure needed for rendering a multipolygon path using a
29549 // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
29551 // In the case of invalid geometries, this function will still return a result which
29552 // includes the nodes of all way members, but some Nds may be unclosed and some inner
29553 // rings not matched with the intended outer ring.
29555 multipolygon: function(resolver) {
29556 var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
29557 inners = this.members.filter(function(m) { return 'inner' === m.role; });
29559 outers = iD.geo.joinWays(outers, resolver);
29560 inners = iD.geo.joinWays(inners, resolver);
29562 outers = outers.map(function(outer) { return _.map(outer.nodes, 'loc'); });
29563 inners = inners.map(function(inner) { return _.map(inner.nodes, 'loc'); });
29565 var result = outers.map(function(o) {
29566 // Heuristic for detecting counterclockwise winding order. Assumes
29567 // that OpenStreetMap polygons are not hemisphere-spanning.
29568 return [d3.geo.area({type: 'Polygon', coordinates: [o]}) > 2 * Math.PI ? o.reverse() : o];
29571 function findOuter(inner) {
29574 for (o = 0; o < outers.length; o++) {
29576 if (iD.geo.polygonContainsPolygon(outer, inner))
29580 for (o = 0; o < outers.length; o++) {
29582 if (iD.geo.polygonIntersectsPolygon(outer, inner))
29587 for (var i = 0; i < inners.length; i++) {
29588 var inner = inners[i];
29590 if (d3.geo.area({type: 'Polygon', coordinates: [inner]}) < 2 * Math.PI) {
29591 inner = inner.reverse();
29594 var o = findOuter(inners[i]);
29595 if (o !== undefined)
29596 result[o].push(inners[i]);
29598 result.push([inners[i]]); // Invalid geometry
29606 'chair_lift': true,
29607 'mixed_lift': true,
29612 'magic_carpet': true,
29617 'motorway_link': true
29623 'piste:halfpipe': true
29647 iD.interestingTag = function (key) {
29648 return key !== 'attribution' &&
29649 key !== 'created_by' &&
29650 key !== 'source' &&
29652 key.indexOf('tiger:') !== 0;
29655 iD.Tree = function(head) {
29656 var rtree = rbush(),
29659 function entityRectangle(entity) {
29660 var rect = entity.extent(head).rectangle();
29661 rect.id = entity.id;
29662 rectangles[entity.id] = rect;
29666 function updateParents(entity, insertions, memo) {
29667 head.parentWays(entity).forEach(function(way) {
29668 if (rectangles[way.id]) {
29669 rtree.remove(rectangles[way.id]);
29670 insertions[way.id] = way;
29672 updateParents(way, insertions, memo);
29675 head.parentRelations(entity).forEach(function(relation) {
29676 if (memo[entity.id]) return;
29677 memo[entity.id] = true;
29678 if (rectangles[relation.id]) {
29679 rtree.remove(rectangles[relation.id]);
29680 insertions[relation.id] = relation;
29682 updateParents(relation, insertions, memo);
29688 tree.rebase = function(entities, force) {
29689 var insertions = {};
29691 for (var i = 0; i < entities.length; i++) {
29692 var entity = entities[i];
29694 if (!entity.visible)
29697 if (head.entities.hasOwnProperty(entity.id) || rectangles[entity.id]) {
29700 } else if (rectangles[entity.id]) {
29701 rtree.remove(rectangles[entity.id]);
29705 insertions[entity.id] = entity;
29706 updateParents(entity, insertions, {});
29709 rtree.load(_.map(insertions, entityRectangle));
29714 tree.intersects = function(extent, graph) {
29715 if (graph !== head) {
29716 var diff = iD.Difference(head, graph),
29721 diff.deleted().forEach(function(entity) {
29722 rtree.remove(rectangles[entity.id]);
29723 delete rectangles[entity.id];
29726 diff.modified().forEach(function(entity) {
29727 rtree.remove(rectangles[entity.id]);
29728 insertions[entity.id] = entity;
29729 updateParents(entity, insertions, {});
29732 diff.created().forEach(function(entity) {
29733 insertions[entity.id] = entity;
29736 rtree.load(_.map(insertions, entityRectangle));
29739 return rtree.search(extent.rectangle()).map(function(rect) {
29740 return head.entity(rect.id);
29746 iD.Way = iD.Entity.way = function iD_Way() {
29747 if (!(this instanceof iD_Way)) {
29748 return (new iD_Way()).initialize(arguments);
29749 } else if (arguments.length) {
29750 this.initialize(arguments);
29754 iD.Way.prototype = Object.create(iD.Entity.prototype);
29756 _.extend(iD.Way.prototype, {
29760 copy: function(resolver, copies) {
29761 if (copies[this.id])
29762 return copies[this.id];
29764 var copy = iD.Entity.prototype.copy.call(this, resolver, copies);
29766 var nodes = this.nodes.map(function(id) {
29767 return resolver.entity(id).copy(resolver, copies).id;
29770 copy = copy.update({nodes: nodes});
29771 copies[this.id] = copy;
29776 extent: function(resolver) {
29777 return resolver.transient(this, 'extent', function() {
29778 var extent = iD.geo.Extent();
29779 for (var i = 0; i < this.nodes.length; i++) {
29780 var node = resolver.hasEntity(this.nodes[i]);
29782 extent._extend(node.extent());
29789 first: function() {
29790 return this.nodes[0];
29794 return this.nodes[this.nodes.length - 1];
29797 contains: function(node) {
29798 return this.nodes.indexOf(node) >= 0;
29801 affix: function(node) {
29802 if (this.nodes[0] === node) return 'prefix';
29803 if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
29806 layer: function() {
29807 // explicit layer tag, clamp between -10, 10..
29808 if (this.tags.layer !== undefined) {
29809 return Math.max(-10, Math.min(+(this.tags.layer), 10));
29812 // implied layer tag..
29813 if (this.tags.location === 'overground') return 1;
29814 if (this.tags.location === 'underground') return -1;
29815 if (this.tags.location === 'underwater') return -10;
29817 if (this.tags.power === 'line') return 10;
29818 if (this.tags.power === 'minor_line') return 10;
29819 if (this.tags.aerialway) return 10;
29820 if (this.tags.bridge) return 1;
29821 if (this.tags.cutting) return -1;
29822 if (this.tags.tunnel) return -1;
29823 if (this.tags.waterway) return -1;
29824 if (this.tags.man_made === 'pipeline') return -10;
29825 if (this.tags.boundary) return -10;
29829 isOneWay: function() {
29830 // explicit oneway tag..
29831 if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
29832 if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
29834 // implied oneway tag..
29835 for (var key in this.tags) {
29836 if (key in iD.oneWayTags && (this.tags[key] in iD.oneWayTags[key]))
29842 isClosed: function() {
29843 return this.nodes.length > 0 && this.first() === this.last();
29846 isConvex: function(resolver) {
29847 if (!this.isClosed() || this.isDegenerate()) return null;
29849 var nodes = _.uniq(resolver.childNodes(this)),
29850 coords = _.map(nodes, 'loc'),
29851 curr = 0, prev = 0;
29853 for (var i = 0; i < coords.length; i++) {
29854 var o = coords[(i+1) % coords.length],
29856 b = coords[(i+2) % coords.length],
29857 res = iD.geo.cross(o, a, b);
29859 curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
29862 } else if (prev && curr !== prev) {
29870 isArea: function() {
29871 if (this.tags.area === 'yes')
29873 if (!this.isClosed() || this.tags.area === 'no')
29875 for (var key in this.tags)
29876 if (key in iD.areaKeys && !(this.tags[key] in iD.areaKeys[key]))
29881 isDegenerate: function() {
29882 return _.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
29885 areAdjacent: function(n1, n2) {
29886 for (var i = 0; i < this.nodes.length; i++) {
29887 if (this.nodes[i] === n1) {
29888 if (this.nodes[i - 1] === n2) return true;
29889 if (this.nodes[i + 1] === n2) return true;
29895 geometry: function(graph) {
29896 return graph.transient(this, 'geometry', function() {
29897 return this.isArea() ? 'area' : 'line';
29901 addNode: function(id, index) {
29902 var nodes = this.nodes.slice();
29903 nodes.splice(index === undefined ? nodes.length : index, 0, id);
29904 return this.update({nodes: nodes});
29907 updateNode: function(id, index) {
29908 var nodes = this.nodes.slice();
29909 nodes.splice(index, 1, id);
29910 return this.update({nodes: nodes});
29913 replaceNode: function(needle, replacement) {
29914 if (this.nodes.indexOf(needle) < 0)
29917 var nodes = this.nodes.slice();
29918 for (var i = 0; i < nodes.length; i++) {
29919 if (nodes[i] === needle) {
29920 nodes[i] = replacement;
29923 return this.update({nodes: nodes});
29926 removeNode: function(id) {
29929 for (var i = 0; i < this.nodes.length; i++) {
29930 var node = this.nodes[i];
29931 if (node !== id && nodes[nodes.length - 1] !== node) {
29936 // Preserve circularity
29937 if (this.nodes.length > 1 && this.first() === id && this.last() === id && nodes[nodes.length - 1] !== nodes[0]) {
29938 nodes.push(nodes[0]);
29941 return this.update({nodes: nodes});
29944 asJXON: function(changeset_id) {
29947 '@id': this.osmId(),
29948 '@version': this.version || 0,
29949 nd: _.map(this.nodes, function(id) {
29950 return { keyAttributes: { ref: iD.Entity.id.toOSM(id) } };
29952 tag: _.map(this.tags, function(v, k) {
29953 return { keyAttributes: { k: k, v: v } };
29957 if (changeset_id) r.way['@changeset'] = changeset_id;
29961 asGeoJSON: function(resolver) {
29962 return resolver.transient(this, 'GeoJSON', function() {
29963 var coordinates = _.map(resolver.childNodes(this), 'loc');
29964 if (this.isArea() && this.isClosed()) {
29967 coordinates: [coordinates]
29971 type: 'LineString',
29972 coordinates: coordinates
29978 area: function(resolver) {
29979 return resolver.transient(this, 'area', function() {
29980 var nodes = resolver.childNodes(this);
29984 coordinates: [_.map(nodes, 'loc')]
29987 if (!this.isClosed() && nodes.length) {
29988 json.coordinates[0].push(nodes[0].loc);
29991 var area = d3.geo.area(json);
29993 // Heuristic for detecting counterclockwise winding order. Assumes
29994 // that OpenStreetMap polygons are not hemisphere-spanning.
29995 if (area > 2 * Math.PI) {
29996 json.coordinates[0] = json.coordinates[0].reverse();
29997 area = d3.geo.area(json);
30000 return isNaN(area) ? 0 : area;
30004 iD.Background = function(context) {
30005 var dispatch = d3.dispatch('change'),
30006 baseLayer = iD.TileLayer(context).projection(context.projection),
30007 overlayLayers = [],
30011 function findSource(id) {
30012 return _.find(backgroundSources, function(d) {
30013 return d.id && d.id === id;
30018 function background(selection) {
30019 var base = selection.selectAll('.layer-background')
30023 .insert('div', '.layer-data')
30024 .attr('class', 'layer layer-background');
30026 base.call(baseLayer);
30028 var overlays = selection.selectAll('.layer-overlay')
30029 .data(overlayLayers, function(d) { return d.source().name(); });
30032 .insert('div', '.layer-data')
30033 .attr('class', 'layer layer-overlay');
30035 overlays.each(function(layer) {
30036 d3.select(this).call(layer);
30044 background.updateImagery = function() {
30045 var b = background.baseLayerSource(),
30046 o = overlayLayers.map(function (d) { return d.source().id; }).join(','),
30047 meters = iD.geo.offsetToMeters(b.offset()),
30049 x = +meters[0].toFixed(2),
30050 y = +meters[1].toFixed(2),
30051 q = iD.util.stringQs(location.hash.substring(1));
30054 if (id === 'custom') {
30055 id = 'custom:' + b.template;
30061 delete q.background;
30070 if (Math.abs(x) > epsilon || Math.abs(y) > epsilon) {
30071 q.offset = x + ',' + y;
30076 location.replace('#' + iD.util.qsString(q, true));
30078 var imageryUsed = [b.imageryUsed()];
30080 overlayLayers.forEach(function (d) {
30081 var source = d.source();
30082 if (!source.isLocatorOverlay()) {
30083 imageryUsed.push(source.imageryUsed());
30087 var gpx = context.layers().layer('gpx');
30088 if (gpx && gpx.enabled() && gpx.hasGpx()) {
30089 imageryUsed.push('Local GPX');
30092 var mapillary_images = context.layers().layer('mapillary-images');
30093 if (mapillary_images && mapillary_images.enabled()) {
30094 imageryUsed.push('Mapillary Images');
30097 var mapillary_signs = context.layers().layer('mapillary-signs');
30098 if (mapillary_signs && mapillary_signs.enabled()) {
30099 imageryUsed.push('Mapillary Signs');
30102 context.history().imageryUsed(imageryUsed);
30105 background.sources = function(extent) {
30106 return backgroundSources.filter(function(source) {
30107 return source.intersects(extent);
30111 background.dimensions = function(_) {
30112 baseLayer.dimensions(_);
30114 overlayLayers.forEach(function(layer) {
30115 layer.dimensions(_);
30119 background.baseLayerSource = function(d) {
30120 if (!arguments.length) return baseLayer.source();
30121 baseLayer.source(d);
30123 background.updateImagery();
30127 background.bing = function() {
30128 background.baseLayerSource(findSource('Bing'));
30131 background.showsLayer = function(d) {
30132 return d === baseLayer.source() ||
30133 (d.id === 'custom' && baseLayer.source().id === 'custom') ||
30134 overlayLayers.some(function(l) { return l.source() === d; });
30137 background.overlayLayerSources = function() {
30138 return overlayLayers.map(function (l) { return l.source(); });
30141 background.toggleOverlayLayer = function(d) {
30144 for (var i = 0; i < overlayLayers.length; i++) {
30145 layer = overlayLayers[i];
30146 if (layer.source() === d) {
30147 overlayLayers.splice(i, 1);
30149 background.updateImagery();
30154 layer = iD.TileLayer(context)
30156 .projection(context.projection)
30157 .dimensions(baseLayer.dimensions());
30159 overlayLayers.push(layer);
30161 background.updateImagery();
30164 background.nudge = function(d, zoom) {
30165 baseLayer.source().nudge(d, zoom);
30167 background.updateImagery();
30171 background.offset = function(d) {
30172 if (!arguments.length) return baseLayer.source().offset();
30173 baseLayer.source().offset(d);
30175 background.updateImagery();
30179 background.load = function(imagery) {
30180 function parseMap(qmap) {
30181 if (!qmap) return false;
30182 var args = qmap.split('/').map(Number);
30183 if (args.length < 3 || args.some(isNaN)) return false;
30184 return iD.geo.Extent([args[1], args[2]]);
30187 var q = iD.util.stringQs(location.hash.substring(1)),
30188 chosen = q.background || q.layer,
30189 extent = parseMap(q.map),
30192 backgroundSources = imagery.map(function(source) {
30193 if (source.type === 'bing') {
30194 return iD.BackgroundSource.Bing(source, dispatch);
30196 return iD.BackgroundSource(source);
30200 backgroundSources.unshift(iD.BackgroundSource.None());
30202 if (!chosen && extent) {
30203 best = _.find(this.sources(extent), function(s) { return s.best(); });
30206 if (chosen && chosen.indexOf('custom:') === 0) {
30207 background.baseLayerSource(iD.BackgroundSource.Custom(chosen.replace(/^custom:/, '')));
30209 background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
30212 var locator = _.find(backgroundSources, function(d) {
30213 return d.overlay && d.default;
30217 background.toggleOverlayLayer(locator);
30220 var overlays = (q.overlays || '').split(',');
30221 overlays.forEach(function(overlay) {
30222 overlay = findSource(overlay);
30224 background.toggleOverlayLayer(overlay);
30229 var gpx = context.layers().layer('gpx');
30236 var offset = q.offset.replace(/;/g, ',').split(',').map(function(n) {
30237 return !isNaN(n) && n;
30240 if (offset.length === 2) {
30241 background.offset(iD.geo.metersToOffset(offset));
30246 return d3.rebind(background, dispatch, 'on');
30248 iD.BackgroundSource = function(data) {
30249 var source = _.clone(data),
30251 name = source.name,
30252 best = !!source.best;
30254 source.scaleExtent = data.scaleExtent || [0, 20];
30255 source.overzoom = data.overzoom !== false;
30257 source.offset = function(_) {
30258 if (!arguments.length) return offset;
30263 source.nudge = function(_, zoomlevel) {
30264 offset[0] += _[0] / Math.pow(2, zoomlevel);
30265 offset[1] += _[1] / Math.pow(2, zoomlevel);
30269 source.name = function() {
30273 source.best = function() {
30277 source.area = function() {
30278 if (!data.polygon) return Number.MAX_VALUE; // worldwide
30279 var area = d3.geo.area({ type: 'MultiPolygon', coordinates: [ data.polygon ] });
30280 return isNaN(area) ? 0 : area;
30283 source.imageryUsed = function() {
30284 return source.id || name;
30287 source.url = function(coord) {
30288 return data.template
30289 .replace('{x}', coord[0])
30290 .replace('{y}', coord[1])
30291 // TMS-flipped y coordinate
30292 .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
30293 .replace(/\{z(oom)?\}/, coord[2])
30294 .replace(/\{switch:([^}]+)\}/, function(s, r) {
30295 var subdomains = r.split(',');
30296 return subdomains[(coord[0] + coord[1]) % subdomains.length];
30298 .replace('{u}', function() {
30300 for (var zoom = coord[2]; zoom > 0; zoom--) {
30302 var mask = 1 << (zoom - 1);
30303 if ((coord[0] & mask) !== 0) b++;
30304 if ((coord[1] & mask) !== 0) b += 2;
30311 source.intersects = function(extent) {
30312 extent = extent.polygon();
30313 return !data.polygon || data.polygon.some(function(polygon) {
30314 return iD.geo.polygonIntersectsPolygon(polygon, extent, true);
30318 source.validZoom = function(z) {
30319 return source.scaleExtent[0] <= z &&
30320 (source.overzoom || source.scaleExtent[1] > z);
30323 source.isLocatorOverlay = function() {
30324 return name === 'Locator Overlay';
30327 source.copyrightNotices = function() {};
30332 iD.BackgroundSource.Bing = function(data, dispatch) {
30333 // http://msdn.microsoft.com/en-us/library/ff701716.aspx
30334 // http://msdn.microsoft.com/en-us/library/ff701701.aspx
30336 data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
30338 var bing = iD.BackgroundSource(data),
30339 key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
30340 url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
30341 key + '&jsonp={callback}',
30344 d3.jsonp(url, function(json) {
30345 providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
30347 attribution: provider.attribution,
30348 areas: provider.coverageAreas.map(function(area) {
30350 zoom: [area.zoomMin, area.zoomMax],
30351 extent: iD.geo.Extent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
30359 bing.copyrightNotices = function(zoom, extent) {
30360 zoom = Math.min(zoom, 21);
30361 return providers.filter(function(provider) {
30362 return _.some(provider.areas, function(area) {
30363 return extent.intersects(area.extent) &&
30364 area.zoom[0] <= zoom &&
30365 area.zoom[1] >= zoom;
30367 }).map(function(provider) {
30368 return provider.attribution;
30372 bing.logo = 'bing_maps.png';
30373 bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
30378 iD.BackgroundSource.None = function() {
30379 var source = iD.BackgroundSource({id: 'none', template: ''});
30381 source.name = function() {
30382 return t('background.none');
30385 source.imageryUsed = function() {
30389 source.area = function() {
30396 iD.BackgroundSource.Custom = function(template) {
30397 var source = iD.BackgroundSource({id: 'custom', template: template});
30399 source.name = function() {
30400 return t('background.custom');
30403 source.imageryUsed = function() {
30404 return 'Custom (' + template + ')';
30407 source.area = function() {
30413 iD.Features = function(context) {
30414 var traffic_roads = {
30416 'motorway_link': true,
30418 'trunk_link': true,
30420 'primary_link': true,
30422 'secondary_link': true,
30424 'tertiary_link': true,
30425 'residential': true,
30426 'unclassified': true,
30427 'living_street': true
30430 var service_roads = {
30442 'pedestrian': true,
30446 var past_futures = {
30448 'construction': true,
30450 'dismantled': true,
30453 'demolished': true,
30454 'obliterated': true
30457 var dispatch = d3.dispatch('change', 'redraw'),
30465 function update() {
30466 _hidden = features.hidden();
30471 function defineFeature(k, filter, max) {
30475 enabled: true, // whether the user wants it enabled..
30477 currentMax: (max || Infinity),
30478 defaultMax: (max || Infinity),
30479 enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
30480 disable: function() { this.enabled = false; this.currentMax = 0; },
30481 hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
30482 autoHidden: function() { return this.hidden() && this.currentMax > 0; }
30487 defineFeature('points', function isPoint(entity, resolver, geometry) {
30488 return geometry === 'point';
30491 defineFeature('traffic_roads', function isTrafficRoad(entity) {
30492 return traffic_roads[entity.tags.highway];
30495 defineFeature('service_roads', function isServiceRoad(entity) {
30496 return service_roads[entity.tags.highway];
30499 defineFeature('paths', function isPath(entity) {
30500 return paths[entity.tags.highway];
30503 defineFeature('buildings', function isBuilding(entity) {
30505 !!entity.tags['building:part'] ||
30506 (!!entity.tags.building && entity.tags.building !== 'no') ||
30507 entity.tags.amenity === 'shelter' ||
30508 entity.tags.parking === 'multi-storey' ||
30509 entity.tags.parking === 'sheds' ||
30510 entity.tags.parking === 'carports' ||
30511 entity.tags.parking === 'garage_boxes'
30515 defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
30516 return geometry === 'area' &&
30517 !_features.buildings.filter(entity) &&
30518 !_features.water.filter(entity);
30521 defineFeature('boundaries', function isBoundary(entity) {
30522 return !!entity.tags.boundary;
30525 defineFeature('water', function isWater(entity) {
30527 !!entity.tags.waterway ||
30528 entity.tags.natural === 'water' ||
30529 entity.tags.natural === 'coastline' ||
30530 entity.tags.natural === 'bay' ||
30531 entity.tags.landuse === 'pond' ||
30532 entity.tags.landuse === 'basin' ||
30533 entity.tags.landuse === 'reservoir' ||
30534 entity.tags.landuse === 'salt_pond'
30538 defineFeature('rail', function isRail(entity) {
30540 !!entity.tags.railway ||
30541 entity.tags.landuse === 'railway'
30543 traffic_roads[entity.tags.highway] ||
30544 service_roads[entity.tags.highway] ||
30545 paths[entity.tags.highway]
30549 defineFeature('power', function isPower(entity) {
30550 return !!entity.tags.power;
30553 // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
30554 defineFeature('past_future', function isPastFuture(entity) {
30556 traffic_roads[entity.tags.highway] ||
30557 service_roads[entity.tags.highway] ||
30558 paths[entity.tags.highway]
30559 ) { return false; }
30561 var strings = Object.keys(entity.tags);
30563 for (var i = 0; i < strings.length; i++) {
30564 var s = strings[i];
30565 if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
30570 // Lines or areas that don't match another feature filter.
30571 // IMPORTANT: The 'others' feature must be the last one defined,
30572 // so that code in getMatches can skip this test if `hasMatch = true`
30573 defineFeature('others', function isOther(entity, resolver, geometry) {
30574 return (geometry === 'line' || geometry === 'area');
30578 function features() {}
30580 features.features = function() {
30584 features.keys = function() {
30588 features.enabled = function(k) {
30589 if (!arguments.length) {
30590 return _.filter(_keys, function(k) { return _features[k].enabled; });
30592 return _features[k] && _features[k].enabled;
30595 features.disabled = function(k) {
30596 if (!arguments.length) {
30597 return _.reject(_keys, function(k) { return _features[k].enabled; });
30599 return _features[k] && !_features[k].enabled;
30602 features.hidden = function(k) {
30603 if (!arguments.length) {
30604 return _.filter(_keys, function(k) { return _features[k].hidden(); });
30606 return _features[k] && _features[k].hidden();
30609 features.autoHidden = function(k) {
30610 if (!arguments.length) {
30611 return _.filter(_keys, function(k) { return _features[k].autoHidden(); });
30613 return _features[k] && _features[k].autoHidden();
30616 features.enable = function(k) {
30617 if (_features[k] && !_features[k].enabled) {
30618 _features[k].enable();
30623 features.disable = function(k) {
30624 if (_features[k] && _features[k].enabled) {
30625 _features[k].disable();
30630 features.toggle = function(k) {
30631 if (_features[k]) {
30632 (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
30637 features.resetStats = function() {
30638 _.each(_features, function(f) { f.count = 0; });
30642 features.gatherStats = function(d, resolver, dimensions) {
30643 var needsRedraw = false,
30644 type = _.groupBy(d, function(ent) { return ent.type; }),
30645 entities = [].concat(type.relation || [], type.way || [], type.node || []),
30646 currHidden, geometry, matches;
30648 _.each(_features, function(f) { f.count = 0; });
30650 // adjust the threshold for point/building culling based on viewport size..
30651 // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
30652 _cullFactor = dimensions[0] * dimensions[1] / 1000000;
30654 for (var i = 0; i < entities.length; i++) {
30655 geometry = entities[i].geometry(resolver);
30656 if (!(geometry === 'vertex' || geometry === 'relation')) {
30657 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
30658 for (var j = 0; j < matches.length; j++) {
30659 _features[matches[j]].count++;
30664 currHidden = features.hidden();
30665 if (currHidden !== _hidden) {
30666 _hidden = currHidden;
30667 needsRedraw = true;
30671 return needsRedraw;
30674 features.stats = function() {
30675 _.each(_keys, function(k) { _stats[k] = _features[k].count; });
30679 features.clear = function(d) {
30680 for (var i = 0; i < d.length; i++) {
30681 features.clearEntity(d[i]);
30685 features.clearEntity = function(entity) {
30686 delete _cache[iD.Entity.key(entity)];
30689 features.reset = function() {
30693 features.getMatches = function(entity, resolver, geometry) {
30694 if (geometry === 'vertex' || geometry === 'relation') return {};
30696 var ent = iD.Entity.key(entity);
30697 if (!_cache[ent]) {
30701 if (!_cache[ent].matches) {
30705 for (var i = 0; i < _keys.length; i++) {
30706 if (_keys[i] === 'others') {
30707 if (hasMatch) continue;
30709 // Multipolygon members:
30711 // 1. is a way that hasn't matched other "interesting" feature rules,
30712 // 2. and it belongs to a single parent multipolygon relation
30713 // ...then match whatever feature rules the parent multipolygon has matched.
30714 // see #2548, #2887
30717 // For this to work, getMatches must be called on relations before ways.
30719 if (entity.type === 'way') {
30720 var parents = features.getParents(entity, resolver, geometry);
30721 if (parents.length === 1 && parents[0].isMultipolygon()) {
30722 var pkey = iD.Entity.key(parents[0]);
30723 if (_cache[pkey] && _cache[pkey].matches) {
30724 matches = _.clone(_cache[pkey].matches);
30731 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
30732 matches[_keys[i]] = hasMatch = true;
30735 _cache[ent].matches = matches;
30738 return _cache[ent].matches;
30741 features.getParents = function(entity, resolver, geometry) {
30742 if (geometry === 'point') return [];
30744 var ent = iD.Entity.key(entity);
30745 if (!_cache[ent]) {
30749 if (!_cache[ent].parents) {
30751 if (geometry === 'vertex') {
30752 parents = resolver.parentWays(entity);
30753 } else { // 'line', 'area', 'relation'
30754 parents = resolver.parentRelations(entity);
30756 _cache[ent].parents = parents;
30758 return _cache[ent].parents;
30761 features.isHiddenFeature = function(entity, resolver, geometry) {
30762 if (!_hidden.length) return false;
30763 if (!entity.version) return false;
30765 var matches = features.getMatches(entity, resolver, geometry);
30767 for (var i = 0; i < _hidden.length; i++) {
30768 if (matches[_hidden[i]]) return true;
30773 features.isHiddenChild = function(entity, resolver, geometry) {
30774 if (!_hidden.length) return false;
30775 if (!entity.version || geometry === 'point') return false;
30777 var parents = features.getParents(entity, resolver, geometry);
30778 if (!parents.length) return false;
30780 for (var i = 0; i < parents.length; i++) {
30781 if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
30788 features.hasHiddenConnections = function(entity, resolver) {
30789 if (!_hidden.length) return false;
30790 var childNodes, connections;
30792 if (entity.type === 'midpoint') {
30793 childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
30796 childNodes = entity.nodes ? resolver.childNodes(entity) : [];
30797 connections = features.getParents(entity, resolver, entity.geometry(resolver));
30800 // gather ways connected to child nodes..
30801 connections = _.reduce(childNodes, function(result, e) {
30802 return resolver.isShared(e) ? _.union(result, resolver.parentWays(e)) : result;
30805 return connections.length ? _.some(connections, function(e) {
30806 return features.isHidden(e, resolver, e.geometry(resolver));
30810 features.isHidden = function(entity, resolver, geometry) {
30811 if (!_hidden.length) return false;
30812 if (!entity.version) return false;
30814 var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
30815 return fn(entity, resolver, geometry);
30818 features.filter = function(d, resolver) {
30819 if (!_hidden.length) return d;
30822 for (var i = 0; i < d.length; i++) {
30824 if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
30825 result.push(entity);
30831 return d3.rebind(features, dispatch, 'on');
30833 iD.Map = function(context) {
30834 var dimensions = [1, 1],
30835 dispatch = d3.dispatch('move', 'drawn'),
30836 projection = context.projection,
30837 zoom = d3.behavior.zoom()
30838 .translate(projection.translate())
30839 .scale(projection.scale() * 2 * Math.PI)
30840 .scaleExtent([1024, 256 * Math.pow(2, 24)])
30841 .on('zoom', zoomPan),
30842 dblclickEnabled = true,
30843 redrawEnabled = true,
30845 transformed = false,
30848 drawLayers = iD.svg.Layers(projection, context),
30849 drawPoints = iD.svg.Points(projection, context),
30850 drawVertices = iD.svg.Vertices(projection, context),
30851 drawLines = iD.svg.Lines(projection),
30852 drawAreas = iD.svg.Areas(projection),
30853 drawMidpoints = iD.svg.Midpoints(projection, context),
30854 drawLabels = iD.svg.Labels(projection, context),
30861 function map(selection) {
30863 .on('change.map', redraw);
30865 .on('change.map', redraw);
30866 context.background()
30867 .on('change.map', redraw);
30869 .on('redraw.map', redraw);
30871 .on('change.map', function() {
30872 context.background().updateImagery();
30877 .on('dblclick.map', dblClick)
30880 supersurface = selection.append('div')
30881 .attr('id', 'supersurface')
30882 .call(iD.util.setTransform, 0, 0);
30884 // Need a wrapper div because Opera can't cope with an absolutely positioned
30885 // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
30886 wrapper = supersurface
30888 .attr('class', 'layer layer-data');
30890 map.surface = surface = wrapper
30892 .selectAll('.surface')
30893 .attr('id', 'surface');
30896 .on('mousedown.zoom', function() {
30897 if (d3.event.button === 2) {
30898 d3.event.stopPropagation();
30901 .on('mouseup.zoom', function() {
30902 if (resetTransform()) redraw();
30904 .on('mousemove.map', function() {
30905 mousemove = d3.event;
30907 .on('mouseover.vertices', function() {
30908 if (map.editable() && !transformed) {
30909 var hover = d3.event.target.__data__;
30910 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
30911 dispatch.drawn({full: false});
30914 .on('mouseout.vertices', function() {
30915 if (map.editable() && !transformed) {
30916 var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__;
30917 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
30918 dispatch.drawn({full: false});
30924 .call(context.background());
30927 context.on('enter.map', function() {
30928 if (map.editable() && !transformed) {
30929 var all = context.intersects(map.extent()),
30930 filter = d3.functor(true),
30931 graph = context.graph();
30933 all = context.features().filter(all, graph);
30935 .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
30936 .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
30937 dispatch.drawn({full: false});
30941 map.dimensions(selection.dimensions());
30943 drawLabels.supersurface(supersurface);
30946 function pxCenter() {
30947 return [dimensions[0] / 2, dimensions[1] / 2];
30950 function drawVector(difference, extent) {
30951 var graph = context.graph(),
30952 features = context.features(),
30953 all = context.intersects(map.extent()),
30957 var complete = difference.complete(map.extent());
30958 data = _.compact(_.values(complete));
30959 filter = function(d) { return d.id in complete; };
30960 features.clear(data);
30963 // force a full redraw if gatherStats detects that a feature
30964 // should be auto-hidden (e.g. points or buildings)..
30965 if (features.gatherStats(all, graph, dimensions)) {
30966 extent = undefined;
30970 data = context.intersects(map.extent().intersection(extent));
30971 var set = d3.set(_.map(data, 'id'));
30972 filter = function(d) { return set.has(d.id); };
30976 filter = d3.functor(true);
30980 data = features.filter(data, graph);
30983 .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
30984 .call(drawLines, graph, data, filter)
30985 .call(drawAreas, graph, data, filter)
30986 .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
30987 .call(drawLabels, graph, data, filter, dimensions, !difference && !extent)
30988 .call(drawPoints, graph, data, filter);
30990 dispatch.drawn({full: true});
30993 function editOff() {
30994 context.features().resetStats();
30995 surface.selectAll('.layer-osm *').remove();
30996 dispatch.drawn({full: true});
30999 function dblClick() {
31000 if (!dblclickEnabled) {
31001 d3.event.preventDefault();
31002 d3.event.stopImmediatePropagation();
31006 function zoomPan() {
31007 if (Math.log(d3.event.scale) / Math.LN2 - 8 < minzoom) {
31008 surface.interrupt();
31009 iD.ui.flash(context.container())
31010 .select('.content')
31011 .text(t('cannot_zoom'));
31012 setZoom(context.minEditableZoom(), true);
31014 dispatch.move(map);
31019 .translate(d3.event.translate)
31020 .scale(d3.event.scale / (2 * Math.PI));
31022 var scale = d3.event.scale / transformStart[0],
31023 tX = (d3.event.translate[0] / scale - transformStart[1][0]) * scale,
31024 tY = (d3.event.translate[1] / scale - transformStart[1][1]) * scale;
31026 transformed = true;
31027 iD.util.setTransform(supersurface, tX, tY, scale);
31030 dispatch.move(map);
31033 function resetTransform() {
31034 if (!transformed) return false;
31036 surface.selectAll('.radial-menu').interrupt().remove();
31037 iD.util.setTransform(supersurface, 0, 0);
31038 transformed = false;
31042 function redraw(difference, extent) {
31043 if (!surface || !redrawEnabled) return;
31045 clearTimeout(timeoutId);
31047 // If we are in the middle of a zoom/pan, we can't do differenced redraws.
31048 // It would result in artifacts where differenced entities are redrawn with
31049 // one transform and unchanged entities with another.
31050 if (resetTransform()) {
31051 difference = extent = undefined;
31054 var zoom = String(~~map.zoom());
31055 if (surface.attr('data-zoom') !== zoom) {
31056 surface.attr('data-zoom', zoom)
31057 .classed('low-zoom', zoom <= 16);
31061 supersurface.call(context.background());
31065 if (map.editable()) {
31066 context.loadTiles(projection, dimensions);
31067 drawVector(difference, extent);
31076 projection.scale() * 2 * Math.PI,
31077 projection.translate().slice()];
31083 function queueRedraw() {
31084 timeoutId = setTimeout(function() { redraw(); }, 750);
31087 function pointLocation(p) {
31088 var translate = projection.translate(),
31089 scale = projection.scale() * 2 * Math.PI;
31090 return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
31093 function locationPoint(l) {
31094 var translate = projection.translate(),
31095 scale = projection.scale() * 2 * Math.PI;
31096 return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
31099 map.mouse = function() {
31100 var e = mousemove || d3.event, s;
31101 while ((s = e.sourceEvent)) e = s;
31105 map.mouseCoordinates = function() {
31106 return projection.invert(map.mouse());
31109 map.dblclickEnable = function(_) {
31110 if (!arguments.length) return dblclickEnabled;
31111 dblclickEnabled = _;
31115 map.redrawEnable = function(_) {
31116 if (!arguments.length) return redrawEnabled;
31121 function interpolateZoom(_) {
31122 var k = projection.scale(),
31123 t = projection.translate();
31125 surface.node().__chart__ = {
31132 projection.scale(k).translate(t); // undo setZoom projection changes
31134 zoom.event(surface.transition());
31137 function setZoom(_, force) {
31138 if (_ === map.zoom() && !force)
31140 var scale = 256 * Math.pow(2, _),
31141 center = pxCenter(),
31142 l = pointLocation(center);
31143 scale = Math.max(1024, Math.min(256 * Math.pow(2, 24), scale));
31144 projection.scale(scale / (2 * Math.PI));
31146 var t = projection.translate();
31147 l = locationPoint(l);
31148 t[0] += center[0] - l[0];
31149 t[1] += center[1] - l[1];
31150 projection.translate(t);
31151 zoom.translate(projection.translate());
31155 function setCenter(_) {
31156 var c = map.center();
31157 if (_[0] === c[0] && _[1] === c[1])
31159 var t = projection.translate(),
31161 ll = projection(_);
31162 projection.translate([
31163 t[0] - ll[0] + pxC[0],
31164 t[1] - ll[1] + pxC[1]]);
31165 zoom.translate(projection.translate());
31169 map.pan = function(d) {
31170 var t = projection.translate();
31173 projection.translate(t);
31174 zoom.translate(projection.translate());
31175 dispatch.move(map);
31179 map.dimensions = function(_) {
31180 if (!arguments.length) return dimensions;
31181 var center = map.center();
31183 drawLayers.dimensions(dimensions);
31184 context.background().dimensions(dimensions);
31185 projection.clipExtent([[0, 0], dimensions]);
31186 mouse = iD.util.fastMouse(supersurface.node());
31191 function zoomIn(integer) {
31192 interpolateZoom(~~map.zoom() + integer);
31195 function zoomOut(integer) {
31196 interpolateZoom(~~map.zoom() - integer);
31199 map.zoomIn = function() { zoomIn(1); };
31200 map.zoomInFurther = function() { zoomIn(4); };
31202 map.zoomOut = function() { zoomOut(1); };
31203 map.zoomOutFurther = function() { zoomOut(4); };
31205 map.center = function(loc) {
31206 if (!arguments.length) {
31207 return projection.invert(pxCenter());
31210 if (setCenter(loc)) {
31211 dispatch.move(map);
31217 map.zoom = function(z) {
31218 if (!arguments.length) {
31219 return Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.LN2 - 8, 0);
31223 surface.interrupt();
31224 iD.ui.flash(context.container())
31225 .select('.content')
31226 .text(t('cannot_zoom'));
31227 z = context.minEditableZoom();
31231 dispatch.move(map);
31237 map.zoomTo = function(entity, zoomLimits) {
31238 var extent = entity.extent(context.graph());
31239 if (!isFinite(extent.area())) return;
31241 var zoom = map.trimmedExtentZoom(extent);
31242 zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
31243 map.centerZoom(extent.center(), Math.min(Math.max(zoom, zoomLimits[0]), zoomLimits[1]));
31246 map.centerZoom = function(loc, z) {
31247 var centered = setCenter(loc),
31248 zoomed = setZoom(z);
31250 if (centered || zoomed) {
31251 dispatch.move(map);
31257 map.centerEase = function(loc2, duration) {
31258 duration = duration || 250;
31260 surface.one('mousedown.ease', function() {
31268 var t1 = Date.now(),
31269 t2 = t1 + duration,
31270 loc1 = map.center(),
31271 ease = d3.ease('cubic-in-out');
31275 d3.timer(function() {
31276 if (!easing) return true; // cancelled ease
31278 var tNow = Date.now();
31284 var locNow = iD.geo.interp(loc1, loc2, ease((tNow - t1) / duration));
31288 scale: zoom.scale(),
31289 translate: zoom.translate()
31299 map.cancelEase = function() {
31305 map.extent = function(_) {
31306 if (!arguments.length) {
31307 return new iD.geo.Extent(projection.invert([0, dimensions[1]]),
31308 projection.invert([dimensions[0], 0]));
31310 var extent = iD.geo.Extent(_);
31311 map.centerZoom(extent.center(), map.extentZoom(extent));
31315 map.trimmedExtent = function(_) {
31316 if (!arguments.length) {
31317 var headerY = 60, footerY = 30, pad = 10;
31318 return new iD.geo.Extent(projection.invert([pad, dimensions[1] - footerY - pad]),
31319 projection.invert([dimensions[0] - pad, headerY + pad]));
31321 var extent = iD.geo.Extent(_);
31322 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
31326 function calcZoom(extent, dim) {
31327 var tl = projection([extent[0][0], extent[1][1]]),
31328 br = projection([extent[1][0], extent[0][1]]);
31330 // Calculate maximum zoom that fits extent
31331 var hFactor = (br[0] - tl[0]) / dim[0],
31332 vFactor = (br[1] - tl[1]) / dim[1],
31333 hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
31334 vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
31335 newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
31340 map.extentZoom = function(_) {
31341 return calcZoom(iD.geo.Extent(_), dimensions);
31344 map.trimmedExtentZoom = function(_) {
31345 var trimY = 120, trimX = 40,
31346 trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
31347 return calcZoom(iD.geo.Extent(_), trimmed);
31350 map.editable = function() {
31351 return map.zoom() >= context.minEditableZoom();
31354 map.minzoom = function(_) {
31355 if (!arguments.length) return minzoom;
31360 map.layers = drawLayers;
31362 return d3.rebind(map, dispatch, 'on');
31364 iD.TileLayer = function(context) {
31365 var tileSize = 256,
31366 tile = d3.geo.tile(),
31371 transformProp = iD.util.prefixCSSProperty('Transform'),
31372 source = d3.functor('');
31375 // blacklist overlay tiles around Null Island..
31376 function nearNullIsland(x, y, z) {
31378 var center = Math.pow(2, z - 1),
31379 width = Math.pow(2, z - 6),
31380 min = center - (width / 2),
31381 max = center + (width / 2) - 1;
31382 return x >= min && x <= max && y >= min && y <= max;
31387 function tileSizeAtZoom(d, z) {
31388 var epsilon = 0.002;
31389 return ((tileSize * Math.pow(2, z - d[2])) / tileSize) + epsilon;
31392 function atZoom(t, distance) {
31393 var power = Math.pow(2, distance);
31395 Math.floor(t[0] * power),
31396 Math.floor(t[1] * power),
31400 function lookUp(d) {
31401 for (var up = -1; up > -d[2]; up--) {
31402 var tile = atZoom(d, up);
31403 if (cache[source.url(tile)] !== false) {
31409 function uniqueBy(a, n) {
31410 var o = [], seen = {};
31411 for (var i = 0; i < a.length; i++) {
31412 if (seen[a[i][n]] === undefined) {
31414 seen[a[i][n]] = true;
31420 function addSource(d) {
31421 d.push(source.url(d));
31425 // Update tiles based on current state of `projection`.
31426 function background(selection) {
31427 tile.scale(projection.scale() * 2 * Math.PI)
31428 .translate(projection.translate());
31431 projection.scale() * Math.PI - projection.translate()[0],
31432 projection.scale() * Math.PI - projection.translate()[1]];
31434 z = Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
31439 // Derive the tiles onscreen, remove those offscreen and position them.
31440 // Important that this part not depend on `projection` because it's
31441 // rentered when tiles load/error (see #644).
31442 function render(selection) {
31444 var showDebug = context.debugTile() && !source.overlay;
31446 if (source.validZoom(z)) {
31447 tile().forEach(function(d) {
31449 if (d[3] === '') return;
31450 if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
31452 if (cache[d[3]] === false && lookUp(d)) {
31453 requests.push(addSource(lookUp(d)));
31457 requests = uniqueBy(requests, 3).filter(function(r) {
31458 if (!!source.overlay && nearNullIsland(r[0], r[1], r[2])) {
31461 // don't re-request tiles which have failed in the past
31462 return cache[r[3]] !== false;
31466 var pixelOffset = [
31467 source.offset()[0] * Math.pow(2, z),
31468 source.offset()[1] * Math.pow(2, z)
31472 cache[d[3]] = true;
31476 .classed('tile-loaded', true);
31480 function error(d) {
31481 cache[d[3]] = false;
31489 function imageTransform(d) {
31490 var _ts = tileSize * Math.pow(2, z - d[2]);
31491 var scale = tileSizeAtZoom(d, z);
31492 return 'translate(' +
31493 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
31494 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
31495 'scale(' + scale + ',' + scale + ')';
31498 function debugTransform(d) {
31499 var _ts = tileSize * Math.pow(2, z - d[2]);
31500 var scale = tileSizeAtZoom(d, z);
31501 return 'translate(' +
31502 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0] + scale * (tileSize / 4)) + 'px,' +
31503 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1] + scale * (tileSize / 2)) + 'px)';
31506 var image = selection
31508 .data(requests, function(d) { return d[3]; });
31511 .style(transformProp, imageTransform)
31512 .classed('tile-removing', true)
31514 var tile = d3.select(this);
31515 window.setTimeout(function() {
31516 if (tile.classed('tile-removing')) {
31522 image.enter().append('img')
31523 .attr('class', 'tile')
31524 .attr('src', function(d) { return d[3]; })
31525 .on('error', error)
31529 .style(transformProp, imageTransform)
31530 .classed('tile-debug', showDebug)
31531 .classed('tile-removing', false);
31534 var debug = selection.selectAll('.tile-label-debug')
31535 .data(showDebug ? requests : [], function(d) { return d[3]; });
31542 .attr('class', 'tile-label-debug');
31545 .text(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; })
31546 .style(transformProp, debugTransform);
31549 background.projection = function(_) {
31550 if (!arguments.length) return projection;
31555 background.dimensions = function(_) {
31556 if (!arguments.length) return tile.size();
31561 background.source = function(_) {
31562 if (!arguments.length) return source;
31565 tile.scaleExtent(source.scaleExtent);
31572 PointTransform: function(projection) {
31573 return function(entity) {
31574 // http://jsperf.com/short-array-join
31575 var pt = projection(entity.loc);
31576 return 'translate(' + pt[0] + ',' + pt[1] + ')';
31580 Path: function(projection, graph, polygon) {
31582 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
31583 project = projection.stream,
31584 path = d3.geo.path()
31585 .projection({stream: function(output) { return polygon ? project(output) : project(clip(output)); }});
31587 return function(entity) {
31588 if (entity.id in cache) {
31589 return cache[entity.id];
31591 return cache[entity.id] = path(entity.asGeoJSON(graph));
31596 OneWaySegments: function(projection, graph, dt) {
31597 return function(entity) {
31603 clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream,
31604 coordinates = graph.childNodes(entity).map(function(n) {
31608 if (entity.tags.oneway === '-1') coordinates.reverse();
31611 type: 'LineString',
31612 coordinates: coordinates
31613 }, projection.stream(clip({
31614 lineStart: function() {},
31615 lineEnd: function() {
31618 point: function(x, y) {
31622 var span = iD.geo.euclideanDistance(a, b) - offset;
31625 var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
31626 dx = dt * Math.cos(angle),
31627 dy = dt * Math.sin(angle),
31628 p = [a[0] + offset * Math.cos(angle),
31629 a[1] + offset * Math.sin(angle)];
31631 var segment = 'M' + a[0] + ',' + a[1] +
31632 'L' + p[0] + ',' + p[1];
31634 for (span -= dt; span >= 0; span -= dt) {
31637 segment += 'L' + p[0] + ',' + p[1];
31640 segment += 'L' + b[0] + ',' + b[1];
31641 segments.push({id: entity.id, index: i, d: segment});
31656 RelationMemberTags: function(graph) {
31657 return function(entity) {
31658 var tags = entity.tags;
31659 graph.parentRelations(entity).forEach(function(relation) {
31660 var type = relation.tags.type;
31661 if (type === 'multipolygon' || type === 'boundary') {
31662 tags = _.extend({}, relation.tags, tags);
31669 iD.svg.Areas = function(projection) {
31670 // Patterns only work in Firefox when set directly on element.
31671 // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
31673 wetland: 'wetland',
31676 construction: 'construction',
31677 military: 'construction',
31678 cemetery: 'cemetery',
31679 grave_yard: 'cemetery',
31682 farmland: 'farmland',
31686 var patternKeys = ['landuse', 'natural', 'amenity'];
31688 function setPattern(d) {
31689 for (var i = 0; i < patternKeys.length; i++) {
31690 if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
31691 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
31695 this.style.fill = this.style.stroke = '';
31698 return function drawAreas(surface, graph, entities, filter) {
31699 var path = iD.svg.Path(projection, graph, true),
31703 for (var i = 0; i < entities.length; i++) {
31704 var entity = entities[i];
31705 if (entity.geometry(graph) !== 'area') continue;
31707 multipolygon = iD.geo.isSimpleMultipolygonOuterMember(entity, graph);
31708 if (multipolygon) {
31709 areas[multipolygon.id] = {
31710 entity: multipolygon.mergeTags(entity.tags),
31711 area: Math.abs(entity.area(graph))
31713 } else if (!areas[entity.id]) {
31714 areas[entity.id] = {
31716 area: Math.abs(entity.area(graph))
31721 areas = d3.values(areas).filter(function hasPath(a) { return path(a.entity); });
31722 areas.sort(function areaSort(a, b) { return b.area - a.area; });
31723 areas = _.map(areas, 'entity');
31725 var strokes = areas.filter(function(area) {
31726 return area.type === 'way';
31736 var clipPaths = surface.selectAll('defs').selectAll('.clipPath')
31738 .data(data.clip, iD.Entity.key);
31741 .append('clipPath')
31742 .attr('class', 'clipPath')
31743 .attr('id', function(entity) { return entity.id + '-clippath'; })
31746 clipPaths.selectAll('path')
31752 var areagroup = surface
31753 .selectAll('.layer-areas')
31754 .selectAll('g.areagroup')
31755 .data(['fill', 'shadow', 'stroke']);
31759 .attr('class', function(d) { return 'layer areagroup area-' + d; });
31761 var paths = areagroup
31764 .data(function(layer) { return data[layer]; }, iD.Entity.key);
31766 // Remove exiting areas first, so they aren't included in the `fills`
31767 // array used for sorting below (https://github.com/openstreetmap/iD/issues/1903).
31771 var fills = surface.selectAll('.area-fill path.area')[0];
31773 var bisect = d3.bisector(function(node) {
31774 return -node.__data__.area(graph);
31777 function sortedByArea(entity) {
31778 if (this.__data__ === 'fill') {
31779 return fills[bisect(fills, -entity.area(graph))];
31784 .insert('path', sortedByArea)
31785 .each(function(entity) {
31786 var layer = this.parentNode.__data__;
31788 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
31790 if (layer === 'fill') {
31791 this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
31792 setPattern.apply(this, arguments);
31795 .call(iD.svg.TagClasses());
31802 A standalone SVG element that contains only a `defs` sub-element. To be
31803 used once globally, since defs IDs must be unique within a document.
31805 iD.svg.Defs = function(context) {
31807 function SVGSpriteDefinition(id, href) {
31808 return function(defs) {
31809 d3.xml(href, 'image/svg+xml', function(err, svg) {
31811 defs.node().appendChild(
31812 d3.select(svg.documentElement).attr('id', id).node()
31818 return function drawDefs(selection) {
31819 var defs = selection.append('defs');
31822 defs.append('marker')
31824 id: 'oneway-marker',
31825 viewBox: '0 0 10 10',
31830 markerUnits: 'strokeWidth',
31834 .attr('class', 'oneway')
31835 .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')
31836 .attr('stroke', 'none')
31837 .attr('fill', '#000')
31838 .attr('opacity', '0.5');
31841 var patterns = defs.selectAll('pattern')
31843 // pattern name, pattern image name
31844 ['wetland', 'wetland'],
31845 ['construction', 'construction'],
31846 ['cemetery', 'cemetery'],
31847 ['orchard', 'orchard'],
31848 ['farmland', 'farmland'],
31857 return 'pattern-' + d[0];
31861 patternUnits: 'userSpaceOnUse'
31864 patterns.append('rect')
31870 'class': function (d) {
31871 return 'pattern-color-' + d[0];
31875 patterns.append('image')
31882 .attr('xlink:href', function (d) {
31883 return context.imagePath('pattern/' + d[1] + '.png');
31888 .data([12, 18, 20, 32, 45])
31889 .enter().append('clipPath')
31890 .attr('id', function (d) {
31891 return 'clip-square-' + d;
31896 .attr('width', function (d) {
31899 .attr('height', function (d) {
31903 defs.call(SVGSpriteDefinition(
31905 context.imagePath('iD-sprite.svg')));
31907 defs.call(SVGSpriteDefinition(
31909 context.imagePath('maki-sprite.svg')));
31912 iD.svg.Gpx = function(projection, context, dispatch) {
31913 var showLabels = true,
31917 if (iD.svg.Gpx.initialized) return; // run once
31919 iD.svg.Gpx.geojson = {};
31920 iD.svg.Gpx.enabled = true;
31923 d3.event.stopPropagation();
31924 d3.event.preventDefault();
31925 d3.event.dataTransfer.dropEffect = 'copy';
31929 .attr('dropzone', 'copy')
31930 .on('drop.localgpx', function() {
31931 d3.event.stopPropagation();
31932 d3.event.preventDefault();
31933 if (!iD.detect().filedrop) return;
31934 drawGpx.files(d3.event.dataTransfer.files);
31936 .on('dragenter.localgpx', over)
31937 .on('dragexit.localgpx', over)
31938 .on('dragover.localgpx', over);
31940 iD.svg.Gpx.initialized = true;
31944 function drawGpx(surface) {
31945 var geojson = iD.svg.Gpx.geojson,
31946 enabled = iD.svg.Gpx.enabled;
31948 layer = surface.selectAll('.layer-gpx')
31949 .data(enabled ? [0] : []);
31953 .attr('class', 'layer-gpx');
31965 .attr('class', 'gpx');
31970 var path = d3.geo.path()
31971 .projection(projection);
31977 var labels = layer.selectAll('text')
31978 .data(showLabels && geojson.features ? geojson.features : []);
31982 .attr('class', 'gpx');
31988 .text(function(d) {
31989 return d.properties.desc || d.properties.name;
31991 .attr('x', function(d) {
31992 var centroid = path.centroid(d);
31993 return centroid[0] + 7;
31995 .attr('y', function(d) {
31996 var centroid = path.centroid(d);
31997 return centroid[1];
32002 function toDom(x) {
32003 return (new DOMParser()).parseFromString(x, 'text/xml');
32006 drawGpx.showLabels = function(_) {
32007 if (!arguments.length) return showLabels;
32012 drawGpx.enabled = function(_) {
32013 if (!arguments.length) return iD.svg.Gpx.enabled;
32014 iD.svg.Gpx.enabled = _;
32019 drawGpx.hasGpx = function() {
32020 var geojson = iD.svg.Gpx.geojson;
32021 return (!(_.isEmpty(geojson) || _.isEmpty(geojson.features)));
32024 drawGpx.geojson = function(gj) {
32025 if (!arguments.length) return iD.svg.Gpx.geojson;
32026 if (_.isEmpty(gj) || _.isEmpty(gj.features)) return this;
32027 iD.svg.Gpx.geojson = gj;
32032 drawGpx.url = function(url) {
32033 d3.text(url, function(err, data) {
32035 drawGpx.geojson(toGeoJSON.gpx(toDom(data)));
32041 drawGpx.files = function(fileList) {
32042 if (!fileList.length) return this;
32043 var f = fileList[0],
32044 reader = new FileReader();
32046 reader.onload = function(e) {
32047 drawGpx.geojson(toGeoJSON.gpx(toDom(e.target.result))).fitZoom();
32050 reader.readAsText(f);
32054 drawGpx.fitZoom = function() {
32055 if (!this.hasGpx()) return this;
32056 var geojson = iD.svg.Gpx.geojson;
32058 var map = context.map(),
32059 viewport = map.trimmedExtent().polygon(),
32060 coords = _.reduce(geojson.features, function(coords, feature) {
32061 var c = feature.geometry.coordinates;
32062 return _.union(coords, feature.geometry.type === 'Point' ? [c] : c);
32065 if (!iD.geo.polygonIntersectsPolygon(viewport, coords, true)) {
32066 var extent = iD.geo.Extent(d3.geo.bounds(geojson));
32067 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
32076 iD.svg.Icon = function(name, svgklass, useklass) {
32077 return function drawIcon(selection) {
32078 selection.selectAll('svg')
32082 .attr('class', 'icon ' + (svgklass || ''))
32084 .attr('xlink:href', name)
32085 .attr('class', useklass);
32088 iD.svg.Labels = function(projection, context) {
32089 var path = d3.geo.path().projection(projection);
32091 // Replace with dict and iterate over entities tags instead?
32092 var label_stack = [
32093 ['line', 'aeroway'],
32094 ['line', 'highway'],
32095 ['line', 'railway'],
32096 ['line', 'waterway'],
32097 ['area', 'aeroway'],
32098 ['area', 'amenity'],
32099 ['area', 'building'],
32100 ['area', 'historic'],
32101 ['area', 'leisure'],
32102 ['area', 'man_made'],
32103 ['area', 'natural'],
32105 ['area', 'tourism'],
32106 ['point', 'aeroway'],
32107 ['point', 'amenity'],
32108 ['point', 'building'],
32109 ['point', 'historic'],
32110 ['point', 'leisure'],
32111 ['point', 'man_made'],
32112 ['point', 'natural'],
32114 ['point', 'tourism'],
32120 var default_size = 12;
32122 var font_sizes = label_stack.map(function(d) {
32123 var style = iD.util.getStyle('text.' + d[0] + '.tag-' + d[1]),
32124 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
32125 if (m) return parseInt(m[1], 10);
32127 style = iD.util.getStyle('text.' + d[0]);
32128 m = style && style.cssText.match('font-size: ([0-9]{1,2})px;');
32129 if (m) return parseInt(m[1], 10);
32131 return default_size;
32136 var pointOffsets = [
32137 [15, -11, 'start'], // right
32138 [10, -11, 'start'], // unused right now
32142 var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25,
32143 75, 20, 80, 15, 95, 10, 90, 5, 95];
32146 var noIcons = ['building', 'landuse', 'natural'];
32147 function blacklisted(preset) {
32148 return _.some(noIcons, function(s) {
32149 return preset.id.indexOf(s) >= 0;
32153 function get(array, prop) {
32154 return function(d, i) { return array[i][prop]; };
32157 var textWidthCache = {};
32159 function textWidth(text, size, elem) {
32160 var c = textWidthCache[size];
32161 if (!c) c = textWidthCache[size] = {};
32167 c[text] = elem.getComputedTextLength();
32171 var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
32172 if (str === null) {
32173 return size / 3 * 2 * text.length;
32175 return size / 3 * (2 * text.length + str.length);
32180 function drawLineLabels(group, entities, filter, classes, labels) {
32181 var texts = group.selectAll('text.' + classes)
32183 .data(entities, iD.Entity.key);
32187 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
32188 .append('textPath')
32189 .attr('class', 'textpath');
32192 texts.selectAll('.textpath')
32194 .data(entities, iD.Entity.key)
32196 'startOffset': '50%',
32197 'xlink:href': function(d) { return '#labelpath-' + d.id; }
32199 .text(iD.util.displayName);
32201 texts.exit().remove();
32204 function drawLinePaths(group, entities, filter, classes, labels) {
32205 var halos = group.selectAll('path')
32207 .data(entities, iD.Entity.key);
32211 .style('stroke-width', get(labels, 'font-size'))
32212 .attr('id', function(d) { return 'labelpath-' + d.id; })
32213 .attr('class', classes);
32215 halos.attr('d', get(labels, 'lineString'));
32217 halos.exit().remove();
32220 function drawPointLabels(group, entities, filter, classes, labels) {
32221 var texts = group.selectAll('text.' + classes)
32223 .data(entities, iD.Entity.key);
32227 .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; });
32229 texts.attr('x', get(labels, 'x'))
32230 .attr('y', get(labels, 'y'))
32231 .style('text-anchor', get(labels, 'textAnchor'))
32232 .text(iD.util.displayName)
32233 .each(function(d, i) { textWidth(iD.util.displayName(d), labels[i].height, this); });
32235 texts.exit().remove();
32239 function drawAreaLabels(group, entities, filter, classes, labels) {
32240 entities = entities.filter(hasText);
32241 labels = labels.filter(hasText);
32242 return drawPointLabels(group, entities, filter, classes, labels);
32244 function hasText(d, i) {
32245 return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
32249 function drawAreaIcons(group, entities, filter, classes, labels) {
32250 var icons = group.selectAll('use')
32252 .data(entities, iD.Entity.key);
32256 .attr('class', 'icon areaicon')
32257 .attr('width', '18px')
32258 .attr('height', '18px');
32260 icons.attr('transform', get(labels, 'transform'))
32261 .attr('xlink:href', function(d) {
32262 var icon = context.presets().match(d, context.graph()).icon;
32263 return '#' + icon + (icon === 'hairdresser' ? '-24': '-18'); // workaround: maki hairdresser-18 broken?
32267 icons.exit().remove();
32270 function reverse(p) {
32271 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
32272 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
32275 function lineString(nodes) {
32276 return 'M' + nodes.join('L');
32279 function subpath(nodes, from, to) {
32280 function segmentLength(i) {
32281 var dx = nodes[i][0] - nodes[i + 1][0];
32282 var dy = nodes[i][1] - nodes[i + 1][1];
32283 return Math.sqrt(dx * dx + dy * dy);
32287 start, end, i0, i1;
32288 for (var i = 0; i < nodes.length - 1; i++) {
32289 var current = segmentLength(i);
32291 if (!start && sofar + current >= from) {
32292 portion = (from - sofar) / current;
32294 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
32295 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
32299 if (!end && sofar + current >= to) {
32300 portion = (to - sofar) / current;
32302 nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
32303 nodes[i][1] + portion * (nodes[i + 1][1] - nodes[i][1])
32310 var ret = nodes.slice(i0, i1);
32311 ret.unshift(start);
32317 function hideOnMouseover() {
32318 var layers = d3.select(this)
32319 .selectAll('.layer-label, .layer-halo');
32321 layers.selectAll('.proximate')
32322 .classed('proximate', false);
32324 var mouse = context.mouse(),
32326 rect = [mouse[0] - pad, mouse[1] - pad, mouse[0] + pad, mouse[1] + pad],
32327 ids = _.map(rtree.search(rect), 'id');
32329 if (!ids.length) return;
32330 layers.selectAll('.' + ids.join(', .'))
32331 .classed('proximate', true);
32334 var rtree = rbush(),
32337 function drawLabels(surface, graph, entities, filter, dimensions, fullRedraw) {
32338 var hidePoints = !surface.selectAll('.node.point').node();
32340 var labelable = [], i, k, entity;
32341 for (i = 0; i < label_stack.length; i++) labelable.push([]);
32347 for (i = 0; i < entities.length; i++) {
32348 rtree.remove(rectangles[entities[i].id]);
32352 // Split entities into groups specified by label_stack
32353 for (i = 0; i < entities.length; i++) {
32354 entity = entities[i];
32355 var geometry = entity.geometry(graph);
32357 if (geometry === 'vertex')
32359 if (hidePoints && geometry === 'point')
32362 var preset = geometry === 'area' && context.presets().match(entity, graph),
32363 icon = preset && !blacklisted(preset) && preset.icon;
32365 if (!icon && !iD.util.displayName(entity))
32368 for (k = 0; k < label_stack.length; k++) {
32369 if (geometry === label_stack[k][0] && entity.tags[label_stack[k][1]]) {
32370 labelable[k].push(entity);
32388 // Try and find a valid label for labellable entities
32389 for (k = 0; k < labelable.length; k++) {
32390 var font_size = font_sizes[k];
32391 for (i = 0; i < labelable[k].length; i++) {
32392 entity = labelable[k][i];
32393 var name = iD.util.displayName(entity),
32394 width = name && textWidth(name, font_size),
32396 if (entity.geometry(graph) === 'point') {
32397 p = getPointLabel(entity, width, font_size);
32398 } else if (entity.geometry(graph) === 'line') {
32399 p = getLineLabel(entity, width, font_size);
32400 } else if (entity.geometry(graph) === 'area') {
32401 p = getAreaLabel(entity, width, font_size);
32404 p.classes = entity.geometry(graph) + ' tag-' + label_stack[k][1];
32405 positions[entity.geometry(graph)].push(p);
32406 labelled[entity.geometry(graph)].push(entity);
32411 function getPointLabel(entity, width, height) {
32412 var coord = projection(entity.loc),
32414 offset = pointOffsets[0],
32418 x: coord[0] + offset[0],
32419 y: coord[1] + offset[1],
32420 textAnchor: offset[2]
32422 var rect = [p.x - m, p.y - m, p.x + width + m, p.y + height + m];
32423 if (tryInsert(rect, entity.id)) return p;
32427 function getLineLabel(entity, width, height) {
32428 var nodes = _.map(graph.childNodes(entity), 'loc').map(projection),
32429 length = iD.geo.pathLength(nodes);
32430 if (length < width + 20) return;
32432 for (var i = 0; i < lineOffsets.length; i++) {
32433 var offset = lineOffsets[i],
32434 middle = offset / 100 * length,
32435 start = middle - width/2;
32436 if (start < 0 || start + width > length) continue;
32437 var sub = subpath(nodes, start, start + width),
32438 rev = reverse(sub),
32440 Math.min(sub[0][0], sub[sub.length - 1][0]) - 10,
32441 Math.min(sub[0][1], sub[sub.length - 1][1]) - 10,
32442 Math.max(sub[0][0], sub[sub.length - 1][0]) + 20,
32443 Math.max(sub[0][1], sub[sub.length - 1][1]) + 30
32445 if (rev) sub = sub.reverse();
32446 if (tryInsert(rect, entity.id)) return {
32447 'font-size': height + 2,
32448 lineString: lineString(sub),
32449 startOffset: offset + '%'
32454 function getAreaLabel(entity, width, height) {
32455 var centroid = path.centroid(entity.asGeoJSON(graph, true)),
32456 extent = entity.extent(graph),
32457 entitywidth = projection(extent[1])[0] - projection(extent[0])[0],
32460 if (isNaN(centroid[0]) || entitywidth < 20) return;
32462 var iconX = centroid[0] - (iconSize/2),
32463 iconY = centroid[1] - (iconSize/2),
32464 textOffset = iconSize + 5;
32467 transform: 'translate(' + iconX + ',' + iconY + ')'
32470 if (width && entitywidth >= width + 20) {
32472 p.y = centroid[1] + textOffset;
32473 p.textAnchor = 'middle';
32475 rect = [p.x - width/2, p.y, p.x + width/2, p.y + height + textOffset];
32477 rect = [iconX, iconY, iconX + iconSize, iconY + iconSize];
32480 if (tryInsert(rect, entity.id)) return p;
32484 function tryInsert(rect, id) {
32485 // Check that label is visible
32486 if (rect[0] < 0 || rect[1] < 0 || rect[2] > dimensions[0] ||
32487 rect[3] > dimensions[1]) return false;
32488 var v = rtree.search(rect).length === 0;
32491 rtree.insert(rect);
32492 rectangles[id] = rect;
32497 var label = surface.selectAll('.layer-label'),
32498 halo = surface.selectAll('.layer-halo');
32501 drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
32502 drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
32505 drawLinePaths(halo, labelled.line, filter, '', positions.line);
32506 drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
32507 drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
32510 drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
32511 drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
32512 drawAreaIcons(label, labelled.area, filter, 'arealabel-icon', positions.area);
32515 var showDebug = context.debugCollision();
32516 var debug = label.selectAll('.layer-label-debug')
32517 .data(showDebug ? [true] : []);
32521 .attr('class', 'layer-label-debug');
32527 var gj = rtree.all().map(function(d) {
32528 return { type: 'Polygon', coordinates: [[
32537 var debugboxes = debug.selectAll('.bbox').data(gj);
32541 .attr('class', 'bbox');
32547 .attr('d', d3.geo.path().projection(null));
32551 drawLabels.supersurface = function(supersurface) {
32553 .on('mousemove.hidelabels', hideOnMouseover)
32554 .on('mousedown.hidelabels', function () {
32555 supersurface.on('mousemove.hidelabels', null);
32557 .on('mouseup.hidelabels', function () {
32558 supersurface.on('mousemove.hidelabels', hideOnMouseover);
32564 iD.svg.Layers = function(projection, context) {
32565 var dispatch = d3.dispatch('change'),
32566 svg = d3.select(null),
32568 { id: 'osm', layer: iD.svg.Osm(projection, context, dispatch) },
32569 { id: 'gpx', layer: iD.svg.Gpx(projection, context, dispatch) },
32570 { id: 'mapillary-images', layer: iD.svg.MapillaryImages(projection, context, dispatch) },
32571 { id: 'mapillary-signs', layer: iD.svg.MapillarySigns(projection, context, dispatch) }
32575 function drawLayers(selection) {
32576 svg = selection.selectAll('.surface')
32581 .attr('class', 'surface')
32584 var groups = svg.selectAll('.data-layer')
32589 .attr('class', function(d) { return 'data-layer data-layer-' + d.id; });
32592 .each(function(d) { d3.select(this).call(d.layer); });
32598 drawLayers.all = function() {
32602 drawLayers.layer = function(id) {
32603 var obj = _.find(layers, function(o) {return o.id === id;});
32604 return obj && obj.layer;
32607 drawLayers.only = function(what) {
32608 var arr = [].concat(what);
32609 drawLayers.remove(_.difference(_.map(layers, 'id'), arr));
32613 drawLayers.remove = function(what) {
32614 var arr = [].concat(what);
32615 arr.forEach(function(id) {
32616 layers = _.reject(layers, function(o) {return o.id === id;});
32622 drawLayers.add = function(what) {
32623 var arr = [].concat(what);
32624 arr.forEach(function(obj) {
32625 if ('id' in obj && 'layer' in obj) {
32633 drawLayers.dimensions = function(_) {
32634 if (!arguments.length) return svg.dimensions();
32636 layers.forEach(function(obj) {
32637 if (obj.layer.dimensions) {
32638 obj.layer.dimensions(_);
32645 return d3.rebind(drawLayers, dispatch, 'on');
32647 iD.svg.Lines = function(projection) {
32649 var highway_stack = {
32664 function waystack(a, b) {
32665 var as = 0, bs = 0;
32667 if (a.tags.highway) { as -= highway_stack[a.tags.highway]; }
32668 if (b.tags.highway) { bs -= highway_stack[b.tags.highway]; }
32672 return function drawLines(surface, graph, entities, filter) {
32673 var ways = [], pathdata = {}, onewaydata = {},
32674 getPath = iD.svg.Path(projection, graph);
32676 for (var i = 0; i < entities.length; i++) {
32677 var entity = entities[i],
32678 outer = iD.geo.simpleMultipolygonOuterMember(entity, graph);
32680 ways.push(entity.mergeTags(outer.tags));
32681 } else if (entity.geometry(graph) === 'line') {
32686 ways = ways.filter(getPath);
32688 pathdata = _.groupBy(ways, function(way) { return way.layer(); });
32690 _.forOwn(pathdata, function(v, k) {
32691 onewaydata[k] = _(v)
32692 .filter(function(d) { return d.isOneWay(); })
32693 .map(iD.svg.OneWaySegments(projection, graph, 35))
32698 var layergroup = surface
32699 .selectAll('.layer-lines')
32700 .selectAll('g.layergroup')
32701 .data(d3.range(-10, 11));
32705 .attr('class', function(d) { return 'layer layergroup layer' + String(d); });
32708 var linegroup = layergroup
32709 .selectAll('g.linegroup')
32710 .data(['shadow', 'casing', 'stroke']);
32714 .attr('class', function(d) { return 'layer linegroup line-' + d; });
32717 var lines = linegroup
32721 function() { return pathdata[this.parentNode.parentNode.__data__] || []; },
32725 // Optimization: call simple TagClasses only on enter selection. This
32726 // works because iD.Entity.key is defined to include the entity v attribute.
32729 .attr('class', function(d) { return 'way line ' + this.parentNode.__data__ + ' ' + d.id; })
32730 .call(iD.svg.TagClasses());
32734 .attr('d', getPath)
32735 .call(iD.svg.TagClasses().tags(iD.svg.RelationMemberTags(graph)));
32741 var onewaygroup = layergroup
32742 .selectAll('g.onewaygroup')
32745 onewaygroup.enter()
32747 .attr('class', 'layer onewaygroup');
32750 var oneways = onewaygroup
32754 function() { return onewaydata[this.parentNode.parentNode.__data__] || []; },
32755 function(d) { return [d.id, d.index]; }
32760 .attr('class', 'oneway')
32761 .attr('marker-mid', 'url(#oneway-marker)');
32764 .attr('d', function(d) { return d.d; });
32766 if (iD.detect().ie) {
32767 oneways.each(function() { this.parentNode.insertBefore(this, this); });
32775 iD.svg.MapillaryImages = function(projection, context, dispatch) {
32776 var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000),
32778 layer = d3.select(null),
32783 if (iD.svg.MapillaryImages.initialized) return; // run once
32784 iD.svg.MapillaryImages.enabled = false;
32785 iD.svg.MapillaryImages.initialized = true;
32788 function getMapillary() {
32789 if (iD.services.mapillary && !_mapillary) {
32790 _mapillary = iD.services.mapillary();
32791 _mapillary.on('loadedImages', debouncedRedraw);
32792 } else if (!iD.services.mapillary && _mapillary) {
32799 function showLayer() {
32800 var mapillary = getMapillary();
32801 if (!mapillary) return;
32803 mapillary.loadViewer();
32807 .style('opacity', 0)
32810 .style('opacity', 1)
32811 .each('end', debouncedRedraw);
32814 function hideLayer() {
32815 var mapillary = getMapillary();
32817 mapillary.hideViewer();
32820 debouncedRedraw.cancel();
32825 .style('opacity', 0)
32826 .each('end', editOff);
32829 function editOn() {
32830 layer.style('display', 'block');
32833 function editOff() {
32834 layer.selectAll('.viewfield-group').remove();
32835 layer.style('display', 'none');
32838 function click(d) {
32839 var mapillary = getMapillary();
32840 if (!mapillary) return;
32842 context.map().centerEase(d.loc);
32845 .setSelectedImage(d.key, true)
32846 .updateViewer(d.key, context)
32850 function transform(d) {
32851 var t = iD.svg.PointTransform(projection)(d);
32852 if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
32856 function update() {
32857 var mapillary = getMapillary(),
32858 data = (mapillary ? mapillary.images(projection, layer.dimensions()) : []),
32859 imageKey = mapillary ? mapillary.getSelectedImage() : null;
32861 var markers = layer.selectAll('.viewfield-group')
32862 .data(data, function(d) { return d.key; });
32865 var enter = markers.enter()
32867 .attr('class', 'viewfield-group')
32868 .classed('selected', function(d) { return d.key === imageKey; })
32869 .on('click', click);
32871 enter.append('path')
32872 .attr('class', 'viewfield')
32873 .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
32874 .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');
32876 enter.append('circle')
32887 .attr('transform', transform);
32890 function drawImages(selection) {
32891 var enabled = iD.svg.MapillaryImages.enabled,
32892 mapillary = getMapillary();
32894 layer = selection.selectAll('.layer-mapillary-images')
32895 .data(mapillary ? [0] : []);
32899 .attr('class', 'layer-mapillary-images')
32900 .style('display', enabled ? 'block' : 'none');
32906 if (mapillary && ~~context.map().zoom() >= minZoom) {
32909 mapillary.loadImages(projection, layer.dimensions());
32916 drawImages.enabled = function(_) {
32917 if (!arguments.length) return iD.svg.MapillaryImages.enabled;
32918 iD.svg.MapillaryImages.enabled = _;
32919 if (iD.svg.MapillaryImages.enabled) {
32928 drawImages.supported = function() {
32929 return !!getMapillary();
32932 drawImages.dimensions = function(_) {
32933 if (!arguments.length) return layer.dimensions();
32934 layer.dimensions(_);
32941 iD.svg.MapillarySigns = function(projection, context, dispatch) {
32942 var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000),
32944 layer = d3.select(null),
32949 if (iD.svg.MapillarySigns.initialized) return; // run once
32950 iD.svg.MapillarySigns.enabled = false;
32951 iD.svg.MapillarySigns.initialized = true;
32954 function getMapillary() {
32955 if (iD.services.mapillary && !_mapillary) {
32956 _mapillary = iD.services.mapillary().on('loadedSigns', debouncedRedraw);
32957 } else if (!iD.services.mapillary && _mapillary) {
32963 function showLayer() {
32968 function hideLayer() {
32969 debouncedRedraw.cancel();
32973 function editOn() {
32974 layer.style('display', 'block');
32977 function editOff() {
32978 layer.selectAll('.icon-sign').remove();
32979 layer.style('display', 'none');
32982 function click(d) {
32983 var mapillary = getMapillary();
32984 if (!mapillary) return;
32986 context.map().centerEase(d.loc);
32989 .setSelectedImage(d.key, true)
32990 .updateViewer(d.key, context)
32994 function update() {
32995 var mapillary = getMapillary(),
32996 data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []),
32997 imageKey = mapillary ? mapillary.getSelectedImage() : null;
32999 var signs = layer.selectAll('.icon-sign')
33000 .data(data, function(d) { return d.key; });
33003 var enter = signs.enter()
33004 .append('foreignObject')
33005 .attr('class', 'icon-sign')
33006 .attr('width', '32px') // for Firefox
33007 .attr('height', '32px') // for Firefox
33008 .classed('selected', function(d) { return d.key === imageKey; })
33009 .on('click', click);
33012 .append('xhtml:body')
33013 .html(mapillary.signHTML);
33021 .attr('transform', iD.svg.PointTransform(projection));
33024 function drawSigns(selection) {
33025 var enabled = iD.svg.MapillarySigns.enabled,
33026 mapillary = getMapillary();
33028 layer = selection.selectAll('.layer-mapillary-signs')
33029 .data(mapillary ? [0] : []);
33033 .attr('class', 'layer-mapillary-signs')
33034 .style('display', enabled ? 'block' : 'none')
33035 .attr('transform', 'translate(-16, -16)'); // center signs on loc
33041 if (mapillary && ~~context.map().zoom() >= minZoom) {
33044 mapillary.loadSigns(context, projection, layer.dimensions());
33051 drawSigns.enabled = function(_) {
33052 if (!arguments.length) return iD.svg.MapillarySigns.enabled;
33053 iD.svg.MapillarySigns.enabled = _;
33054 if (iD.svg.MapillarySigns.enabled) {
33063 drawSigns.supported = function() {
33064 var mapillary = getMapillary();
33065 return (mapillary && mapillary.signsSupported());
33068 drawSigns.dimensions = function(_) {
33069 if (!arguments.length) return layer.dimensions();
33070 layer.dimensions(_);
33077 iD.svg.Midpoints = function(projection, context) {
33078 return function drawMidpoints(surface, graph, entities, filter, extent) {
33079 var poly = extent.polygon(),
33082 for (var i = 0; i < entities.length; i++) {
33083 var entity = entities[i];
33085 if (entity.type !== 'way')
33087 if (!filter(entity))
33089 if (context.selectedIDs().indexOf(entity.id) < 0)
33092 var nodes = graph.childNodes(entity);
33093 for (var j = 0; j < nodes.length - 1; j++) {
33097 id = [a.id, b.id].sort().join('-');
33099 if (midpoints[id]) {
33100 midpoints[id].parents.push(entity);
33102 if (iD.geo.euclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
33103 var point = iD.geo.interp(a.loc, b.loc, 0.5),
33106 if (extent.intersects(point)) {
33109 for (var k = 0; k < 4; k++) {
33110 point = iD.geo.lineIntersection([a.loc, b.loc], [poly[k], poly[k+1]]);
33112 iD.geo.euclideanDistance(projection(a.loc), projection(point)) > 20 &&
33113 iD.geo.euclideanDistance(projection(b.loc), projection(point)) > 20)
33126 edge: [a.id, b.id],
33135 function midpointFilter(d) {
33136 if (midpoints[d.id])
33139 for (var i = 0; i < d.parents.length; i++)
33140 if (filter(d.parents[i]))
33146 var groups = surface.selectAll('.layer-hit').selectAll('g.midpoint')
33147 .filter(midpointFilter)
33148 .data(_.values(midpoints), function(d) { return d.id; });
33150 var enter = groups.enter()
33151 .insert('g', ':first-child')
33152 .attr('class', 'midpoint');
33154 enter.append('polygon')
33155 .attr('points', '-6,8 10,0 -6,-8')
33156 .attr('class', 'shadow');
33158 enter.append('polygon')
33159 .attr('points', '-3,4 5,0 -3,-4')
33160 .attr('class', 'fill');
33163 .attr('transform', function(d) {
33164 var translate = iD.svg.PointTransform(projection),
33165 a = context.entity(d.edge[0]),
33166 b = context.entity(d.edge[1]),
33167 angle = Math.round(iD.geo.angle(a, b, projection) * (180 / Math.PI));
33168 return translate(d) + ' rotate(' + angle + ')';
33170 .call(iD.svg.TagClasses().tags(
33171 function(d) { return d.parents[0].tags; }
33174 // Propagate data bindings.
33175 groups.select('polygon.shadow');
33176 groups.select('polygon.fill');
33182 iD.svg.Osm = function() {
33183 return function drawOsm(selection) {
33184 var layers = selection.selectAll('.layer-osm')
33185 .data(['areas', 'lines', 'hit', 'halo', 'label']);
33187 layers.enter().append('g')
33188 .attr('class', function(d) { return 'layer-osm layer-' + d; });
33191 iD.svg.Points = function(projection, context) {
33192 function markerPath(selection, klass) {
33194 .attr('class', klass)
33195 .attr('transform', 'translate(-8, -23)')
33196 .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');
33199 function sortY(a, b) {
33200 return b.loc[1] - a.loc[1];
33203 return function drawPoints(surface, graph, entities, filter) {
33204 var wireframe = surface.classed('fill-wireframe'),
33205 points = wireframe ? [] : _.filter(entities, function(e) {
33206 return e.geometry(graph) === 'point';
33209 points.sort(sortY);
33211 var groups = surface.selectAll('.layer-hit').selectAll('g.point')
33213 .data(points, iD.Entity.key);
33215 var group = groups.enter()
33217 .attr('class', function(d) { return 'node point ' + d.id; })
33220 group.append('path')
33221 .call(markerPath, 'shadow');
33223 group.append('path')
33224 .call(markerPath, 'stroke');
33226 group.append('use')
33227 .attr('transform', 'translate(-6, -20)')
33228 .attr('class', 'icon')
33229 .attr('width', '12px')
33230 .attr('height', '12px');
33232 groups.attr('transform', iD.svg.PointTransform(projection))
33233 .call(iD.svg.TagClasses());
33235 // Selecting the following implicitly
33236 // sets the data (point entity) on the element
33237 groups.select('.shadow');
33238 groups.select('.stroke');
33239 groups.select('.icon')
33240 .attr('xlink:href', function(entity) {
33241 var preset = context.presets().match(entity, graph);
33242 return preset.icon ? '#' + preset.icon + '-12' : '';
33249 iD.svg.TagClasses = function() {
33251 'building', 'highway', 'railway', 'waterway', 'aeroway',
33252 'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
33256 'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
33257 'razed', 'demolished', 'obliterated'
33260 'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
33261 'surface', 'tracktype', 'crossing'
33263 tagClassRe = /^tag-/,
33264 tags = function(entity) { return entity.tags; };
33267 var tagClasses = function(selection) {
33268 selection.each(function tagClassesEach(entity) {
33269 var value = this.className,
33270 classes, primary, status;
33272 if (value.baseVal !== undefined) value = value.baseVal;
33274 classes = value.trim().split(/\s+/).filter(function(name) {
33275 return name.length && !tagClassRe.test(name);
33278 var t = tags(entity), i, k, v;
33280 // pick at most one primary classification tag..
33281 for (i = 0; i < primaries.length; i++) {
33284 if (!v || v === 'no') continue;
33287 if (statuses.indexOf(v) !== -1) { // e.g. `railway=abandoned`
33289 classes += ' tag-' + k;
33291 classes += ' tag-' + k + ' tag-' + k + '-' + v;
33297 // add at most one status tag, only if relates to primary tag..
33299 for (i = 0; i < statuses.length; i++) {
33302 if (!v || v === 'no') continue;
33304 if (v === 'yes') { // e.g. `railway=rail + abandoned=yes`
33307 else if (primary && primary === v) { // e.g. `railway=rail + abandoned=railway`
33309 } else if (!primary && primaries.indexOf(v) !== -1) { // e.g. `abandoned=railway`
33312 classes += ' tag-' + v;
33313 } // else ignore e.g. `highway=path + abandoned=railway`
33320 classes += ' tag-status tag-status-' + status;
33323 // add any secondary (structure) tags
33324 for (i = 0; i < secondaries.length; i++) {
33325 k = secondaries[i];
33327 if (!v || v === 'no') continue;
33328 classes += ' tag-' + k + ' tag-' + k + '-' + v;
33331 // For highways, look for surface tagging..
33332 if (primary === 'highway') {
33333 var paved = (t.highway !== 'track');
33336 if (k in iD.pavedTags) {
33337 paved = !!iD.pavedTags[k][v];
33342 classes += ' tag-unpaved';
33346 classes = classes.trim();
33348 if (classes !== value) {
33349 d3.select(this).attr('class', classes);
33354 tagClasses.tags = function(_) {
33355 if (!arguments.length) return tags;
33362 iD.svg.Turns = function(projection) {
33363 return function drawTurns(surface, graph, turns) {
33364 function key(turn) {
33365 return [turn.from.node + turn.via.node + turn.to.node].join('-');
33368 function icon(turn) {
33369 var u = turn.u ? '-u' : '';
33370 if (!turn.restriction)
33371 return '#turn-yes' + u;
33372 var restriction = graph.entity(turn.restriction).tags.restriction;
33374 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
33377 var groups = surface.selectAll('.layer-hit').selectAll('g.turn')
33381 var enter = groups.enter().append('g')
33382 .attr('class', 'turn');
33384 var nEnter = enter.filter(function (turn) { return !turn.u; });
33386 nEnter.append('rect')
33387 .attr('transform', 'translate(-22, -12)')
33388 .attr('width', '44')
33389 .attr('height', '24');
33391 nEnter.append('use')
33392 .attr('transform', 'translate(-22, -12)')
33393 .attr('width', '44')
33394 .attr('height', '24');
33397 var uEnter = enter.filter(function (turn) { return turn.u; });
33399 uEnter.append('circle')
33402 uEnter.append('use')
33403 .attr('transform', 'translate(-16, -16)')
33404 .attr('width', '32')
33405 .attr('height', '32');
33410 .attr('transform', function (turn) {
33411 var v = graph.entity(turn.via.node),
33412 t = graph.entity(turn.to.node),
33413 a = iD.geo.angle(v, t, projection),
33414 p = projection(v.loc),
33415 r = turn.u ? 0 : 60;
33417 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
33418 'rotate(' + a * 180 / Math.PI + ')';
33421 groups.select('use')
33422 .attr('xlink:href', icon);
33424 groups.select('rect');
33425 groups.select('circle');
33435 iD.svg.Vertices = function(projection, context) {
33437 // z16-, z17, z18+, tagged
33438 shadow: [6, 7.5, 7.5, 11.5],
33439 stroke: [2.5, 3.5, 3.5, 7],
33440 fill: [1, 1.5, 1.5, 1.5]
33445 function siblingAndChildVertices(ids, graph, extent) {
33448 function addChildVertices(entity) {
33449 if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
33451 if (entity.type === 'way') {
33452 for (i = 0; i < entity.nodes.length; i++) {
33453 addChildVertices(graph.entity(entity.nodes[i]));
33455 } else if (entity.type === 'relation') {
33456 for (i = 0; i < entity.members.length; i++) {
33457 var member = context.hasEntity(entity.members[i].id);
33459 addChildVertices(member);
33462 } else if (entity.intersects(extent, graph)) {
33463 vertices[entity.id] = entity;
33468 ids.forEach(function(id) {
33469 var entity = context.hasEntity(id);
33470 if (entity && entity.type === 'node') {
33471 vertices[entity.id] = entity;
33472 context.graph().parentWays(entity).forEach(function(entity) {
33473 addChildVertices(entity);
33475 } else if (entity) {
33476 addChildVertices(entity);
33483 function draw(selection, vertices, klass, graph, zoom) {
33485 z = (zoom < 17 ? 0 : zoom < 18 ? 1 : 2);
33487 var groups = selection
33488 .data(vertices, iD.Entity.key);
33490 function icon(entity) {
33491 if (entity.id in icons) return icons[entity.id];
33493 entity.hasInterestingTags() &&
33494 context.presets().match(entity, graph).icon;
33495 return icons[entity.id];
33498 function setClass(klass) {
33499 return function(entity) {
33500 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
33504 function setAttributes(selection) {
33505 ['shadow','stroke','fill'].forEach(function(klass) {
33506 var rads = radiuses[klass];
33507 selection.selectAll('.' + klass)
33508 .each(function(entity) {
33509 var i = z && icon(entity),
33511 r = rads[i ? 3 : z];
33512 this.setAttribute('cx', c);
33513 this.setAttribute('cy', -c);
33514 this.setAttribute('r', r);
33515 if (i && klass === 'fill') {
33516 this.setAttribute('visibility', 'hidden');
33518 this.removeAttribute('visibility');
33523 selection.selectAll('use')
33526 this.removeAttribute('visibility');
33528 this.setAttribute('visibility', 'hidden');
33533 var enter = groups.enter()
33535 .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
33537 enter.append('circle')
33538 .each(setClass('shadow'));
33540 enter.append('circle')
33541 .each(setClass('stroke'));
33543 // Vertices with icons get a `use`.
33544 enter.filter(function(d) { return icon(d); })
33546 .attr('transform', 'translate(-6, -6)')
33547 .attr('xlink:href', function(d) { return '#' + icon(d) + '-12'; })
33548 .attr('width', '12px')
33549 .attr('height', '12px')
33550 .each(setClass('icon'));
33552 // Vertices with tags get a fill.
33553 enter.filter(function(d) { return d.hasInterestingTags(); })
33555 .each(setClass('fill'));
33558 .attr('transform', iD.svg.PointTransform(projection))
33559 .classed('shared', function(entity) { return graph.isShared(entity); })
33560 .call(setAttributes);
33566 function drawVertices(surface, graph, entities, filter, extent, zoom) {
33567 var selected = siblingAndChildVertices(context.selectedIDs(), graph, extent),
33568 wireframe = surface.classed('fill-wireframe'),
33571 for (var i = 0; i < entities.length; i++) {
33572 var entity = entities[i],
33573 geometry = entity.geometry(graph);
33575 if (wireframe && geometry === 'point') {
33576 vertices.push(entity);
33580 if (geometry !== 'vertex')
33583 if (entity.id in selected ||
33584 entity.hasInterestingTags() ||
33585 entity.isIntersection(graph)) {
33586 vertices.push(entity);
33590 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-persistent')
33592 .call(draw, vertices, 'vertex-persistent', graph, zoom);
33594 drawHover(surface, graph, extent, zoom);
33597 function drawHover(surface, graph, extent, zoom) {
33598 var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent) : {};
33600 surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-hover')
33601 .call(draw, d3.values(hovered), 'vertex-hover', graph, zoom);
33604 drawVertices.drawHover = function(surface, graph, target, extent, zoom) {
33605 if (target === hover) return;
33607 drawHover(surface, graph, extent, zoom);
33610 return drawVertices;
33612 iD.ui = function(context) {
33613 function render(container) {
33614 var map = context.map();
33616 if (iD.detect().opera) container.classed('opera', true);
33618 var hash = iD.behavior.Hash(context);
33622 if (!hash.hadHash) {
33623 map.centerZoom([0, 0], 2);
33626 container.append('svg')
33627 .attr('id', 'defs')
33628 .call(iD.svg.Defs(context));
33630 container.append('div')
33631 .attr('id', 'sidebar')
33632 .attr('class', 'col4')
33635 var content = container.append('div')
33636 .attr('id', 'content');
33638 var bar = content.append('div')
33640 .attr('class', 'fillD');
33642 content.append('div')
33647 .call(iD.ui.MapInMap(context));
33649 content.append('div')
33650 .call(iD.ui.Info(context));
33653 .attr('class', 'spacer col4');
33655 var limiter = bar.append('div')
33656 .attr('class', 'limiter');
33658 limiter.append('div')
33659 .attr('class', 'button-wrap joined col3')
33660 .call(iD.ui.Modes(context), limiter);
33662 limiter.append('div')
33663 .attr('class', 'button-wrap joined col1')
33664 .call(iD.ui.UndoRedo(context));
33666 limiter.append('div')
33667 .attr('class', 'button-wrap col1')
33668 .call(iD.ui.Save(context));
33671 .attr('class', 'full-screen')
33672 .call(iD.ui.FullScreen(context));
33675 .attr('class', 'spinner')
33676 .call(iD.ui.Spinner(context));
33678 var controls = bar.append('div')
33679 .attr('class', 'map-controls');
33681 controls.append('div')
33682 .attr('class', 'map-control zoombuttons')
33683 .call(iD.ui.Zoom(context));
33685 controls.append('div')
33686 .attr('class', 'map-control geolocate-control')
33687 .call(iD.ui.Geolocate(context));
33689 controls.append('div')
33690 .attr('class', 'map-control background-control')
33691 .call(iD.ui.Background(context));
33693 controls.append('div')
33694 .attr('class', 'map-control map-data-control')
33695 .call(iD.ui.MapData(context));
33697 controls.append('div')
33698 .attr('class', 'map-control help-control')
33699 .call(iD.ui.Help(context));
33701 var about = content.append('div')
33702 .attr('id', 'about');
33704 about.append('div')
33705 .attr('id', 'attrib')
33706 .call(iD.ui.Attribution(context));
33708 var footer = about.append('div')
33709 .attr('id', 'footer')
33710 .attr('class', 'fillD');
33712 footer.append('div')
33713 .attr('class', 'api-status')
33714 .call(iD.ui.Status(context));
33716 footer.append('div')
33717 .attr('id', 'scale-block')
33718 .call(iD.ui.Scale(context));
33720 var aboutList = footer.append('div')
33721 .attr('id', 'info-block')
33723 .attr('id', 'about-list');
33725 if (!context.embed()) {
33726 aboutList.call(iD.ui.Account(context));
33729 aboutList.append('li')
33731 .attr('target', '_blank')
33732 .attr('tabindex', -1)
33733 .attr('href', 'https://github.com/openstreetmap/iD')
33736 var issueLinks = aboutList.append('li');
33738 issueLinks.append('a')
33739 .attr('target', '_blank')
33740 .attr('tabindex', -1)
33741 .attr('href', 'https://github.com/openstreetmap/iD/issues')
33742 .call(iD.svg.Icon('#icon-bug', 'light'))
33743 .call(bootstrap.tooltip()
33744 .title(t('report_a_bug'))
33748 issueLinks.append('a')
33749 .attr('target', '_blank')
33750 .attr('tabindex', -1)
33751 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
33752 .call(iD.svg.Icon('#icon-translate', 'light'))
33753 .call(bootstrap.tooltip()
33754 .title(t('help_translate'))
33758 aboutList.append('li')
33759 .attr('class', 'feature-warning')
33760 .attr('tabindex', -1)
33761 .call(iD.ui.FeatureInfo(context));
33763 aboutList.append('li')
33764 .attr('class', 'user-list')
33765 .attr('tabindex', -1)
33766 .call(iD.ui.Contributors(context));
33768 window.onbeforeunload = function() {
33769 return context.save();
33772 window.onunload = function() {
33773 context.history().unlock();
33776 var mapDimensions = map.dimensions();
33778 d3.select(window).on('resize.editor', function() {
33779 mapDimensions = content.dimensions(null);
33780 map.dimensions(mapDimensions);
33784 return function() {
33785 d3.event.preventDefault();
33786 if (!context.inIntro()) context.pan(d);
33793 var keybinding = d3.keybinding('main')
33794 .on('⌫', function() { d3.event.preventDefault(); })
33795 .on('←', pan([pa, 0]))
33796 .on('↑', pan([0, pa]))
33797 .on('→', pan([-pa, 0]))
33798 .on('↓', pan([0, -pa]))
33799 .on('⇧←', pan([mapDimensions[0], 0]))
33800 .on('⇧↑', pan([0, mapDimensions[1]]))
33801 .on('⇧→', pan([-mapDimensions[0], 0]))
33802 .on('⇧↓', pan([0, -mapDimensions[1]]))
33803 .on(iD.ui.cmd('⌘←'), pan([mapDimensions[0], 0]))
33804 .on(iD.ui.cmd('⌘↑'), pan([0, mapDimensions[1]]))
33805 .on(iD.ui.cmd('⌘→'), pan([-mapDimensions[0], 0]))
33806 .on(iD.ui.cmd('⌘↓'), pan([0, -mapDimensions[1]]));
33808 d3.select(document)
33811 context.enter(iD.modes.Browse(context));
33813 context.container()
33814 .call(iD.ui.Splash(context))
33815 .call(iD.ui.Restore(context));
33817 var authenticating = iD.ui.Loading(context)
33818 .message(t('loading_auth'));
33820 context.connection()
33821 .on('authenticating.ui', function() {
33822 context.container()
33823 .call(authenticating);
33825 .on('authenticated.ui', function() {
33826 authenticating.close();
33830 function ui(container) {
33831 context.container(container);
33832 context.loadLocale(function() {
33837 ui.sidebar = iD.ui.Sidebar(context);
33842 iD.ui.tooltipHtml = function(text, key) {
33843 var s = '<span>' + text + '</span>';
33845 s += '<div class="keyhint-wrap">' +
33846 '<span> ' + (t('tooltip_keyhint')) + ' </span>' +
33847 '<span class="keyhint"> ' + key + '</span></div>';
33851 iD.ui.Account = function(context) {
33852 var connection = context.connection();
33854 function update(selection) {
33855 if (!connection.authenticated()) {
33856 selection.selectAll('#userLink, #logoutLink')
33857 .classed('hide', true);
33861 connection.userDetails(function(err, details) {
33862 var userLink = selection.select('#userLink'),
33863 logoutLink = selection.select('#logoutLink');
33866 logoutLink.html('');
33870 selection.selectAll('#userLink, #logoutLink')
33871 .classed('hide', false);
33874 userLink.append('a')
33875 .attr('href', connection.userURL(details.display_name))
33876 .attr('target', '_blank');
33878 // Add thumbnail or dont
33879 if (details.image_url) {
33880 userLink.append('img')
33881 .attr('class', 'icon pre-text user-icon')
33882 .attr('src', details.image_url);
33885 .call(iD.svg.Icon('#icon-avatar', 'pre-text light'));
33889 userLink.append('span')
33890 .attr('class', 'label')
33891 .text(details.display_name);
33893 logoutLink.append('a')
33894 .attr('class', 'logout')
33897 .on('click.logout', function() {
33898 d3.event.preventDefault();
33899 connection.logout();
33904 return function(selection) {
33905 selection.append('li')
33906 .attr('id', 'logoutLink')
33907 .classed('hide', true);
33909 selection.append('li')
33910 .attr('id', 'userLink')
33911 .classed('hide', true);
33913 connection.on('auth.account', function() { update(selection); });
33917 iD.ui.Attribution = function(context) {
33920 function attribution(data, klass) {
33921 var div = selection.selectAll('.' + klass)
33926 .attr('class', klass);
33928 var background = div.selectAll('.attribution')
33929 .data(data, function(d) { return d.name(); });
33933 .attr('class', 'attribution')
33934 .each(function(d) {
33935 if (d.terms_html) {
33937 .html(d.terms_html);
33941 var source = d.terms_text || d.id || d.name();
33944 source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
33950 .attr('href', d.terms_url)
33951 .attr('target', '_blank')
33962 var copyright = background.selectAll('.copyright-notice')
33963 .data(function(d) {
33964 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
33965 return notice ? [notice] : [];
33970 .attr('class', 'copyright-notice');
33972 copyright.text(String);
33978 function update() {
33979 attribution([context.background().baseLayerSource()], 'base-layer-attribution');
33980 attribution(context.background().overlayLayerSources().filter(function (s) {
33981 return s.validZoom(context.map().zoom());
33982 }), 'overlay-layer-attribution');
33985 return function(select) {
33986 selection = select;
33988 context.background()
33989 .on('change.attribution', update);
33992 .on('move.attribution', _.throttle(update, 400, {leading: false}));
33997 iD.ui.Background = function(context) {
33999 opacities = [1, 0.75, 0.5, 0.25],
34001 ['right', [0.5, 0]],
34002 ['top', [0, -0.5]],
34003 ['left', [-0.5, 0]],
34004 ['bottom', [0, 0.5]]],
34005 opacityDefault = (context.storage('background-opacity') !== null) ?
34006 (+context.storage('background-opacity')) : 1.0,
34007 customTemplate = context.storage('background-custom-template') || '',
34010 // Can be 0 from <1.3.0 use or due to issue #1923.
34011 if (opacityDefault === 0) opacityDefault = 1.0;
34014 function background(selection) {
34016 function sortSources(a, b) {
34017 return a.best() && !b.best() ? -1
34018 : b.best() && !a.best() ? 1
34019 : d3.descending(a.area(), b.area()) || d3.ascending(a.name(), b.name()) || 0;
34022 function setOpacity(d) {
34023 var bg = context.container().selectAll('.layer-background')
34025 .style('opacity', d)
34026 .attr('data-opacity', d);
34028 if (!iD.detect().opera) {
34029 iD.util.setTransform(bg, 0, 0);
34032 opacityList.selectAll('li')
34033 .classed('active', function(_) { return _ === d; });
34035 context.storage('background-opacity', d);
34038 function setTooltips(selection) {
34039 selection.each(function(d) {
34040 var item = d3.select(this);
34041 if (d === previous) {
34042 item.call(bootstrap.tooltip()
34044 .title(function() {
34045 var tip = '<div>' + t('background.switch') + '</div>';
34046 return iD.ui.tooltipHtml(tip, iD.ui.cmd('⌘B'));
34050 } else if (d.description) {
34051 item.call(bootstrap.tooltip()
34052 .title(d.description)
34056 item.call(bootstrap.tooltip().destroy);
34061 function selectLayer() {
34062 function active(d) {
34063 return context.background().showsLayer(d);
34066 content.selectAll('.layer, .custom_layer')
34067 .classed('active', active)
34068 .classed('switch', function(d) { return d === previous; })
34070 .selectAll('input')
34071 .property('checked', active);
34074 function clickSetSource(d) {
34075 previous = context.background().baseLayerSource();
34076 d3.event.preventDefault();
34077 context.background().baseLayerSource(d);
34079 document.activeElement.blur();
34082 function editCustom() {
34083 d3.event.preventDefault();
34084 var template = window.prompt(t('background.custom_prompt'), customTemplate);
34086 template.indexOf('google.com') !== -1 ||
34087 template.indexOf('googleapis.com') !== -1 ||
34088 template.indexOf('google.ru') !== -1) {
34092 setCustom(template);
34095 function setCustom(template) {
34096 context.background().baseLayerSource(iD.BackgroundSource.Custom(template));
34098 context.storage('background-custom-template', template);
34101 function clickSetOverlay(d) {
34102 d3.event.preventDefault();
34103 context.background().toggleOverlayLayer(d);
34105 document.activeElement.blur();
34108 function drawList(layerList, type, change, filter) {
34109 var sources = context.background()
34110 .sources(context.map().extent())
34113 var layerLinks = layerList.selectAll('li.layer')
34114 .data(sources, function(d) { return d.name(); });
34116 var enter = layerLinks.enter()
34117 .insert('li', '.custom_layer')
34118 .attr('class', 'layer')
34119 .classed('best', function(d) { return d.best(); });
34121 enter.filter(function(d) { return d.best(); })
34123 .attr('class', 'best')
34124 .call(bootstrap.tooltip()
34125 .title(t('background.best_imagery'))
34126 .placement('left'))
34130 var label = enter.append('label');
34132 label.append('input')
34133 .attr('type', type)
34134 .attr('name', 'layers')
34135 .on('change', change);
34137 label.append('span')
34138 .text(function(d) { return d.name(); });
34144 layerList.selectAll('li.layer')
34146 .style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
34149 function update() {
34150 backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
34151 overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
34155 var source = context.background().baseLayerSource();
34156 if (source.id === 'custom') {
34157 customTemplate = source.template;
34163 function updateOffsetVal() {
34164 var meters = iD.geo.offsetToMeters(context.background().offset()),
34165 x = +meters[0].toFixed(2),
34166 y = +meters[1].toFixed(2);
34168 d3.selectAll('.nudge-inner-rect')
34170 .classed('error', false)
34171 .property('value', x + ', ' + y);
34173 d3.selectAll('.nudge-reset')
34174 .classed('disabled', function() {
34175 return (x === 0 && y === 0);
34179 function resetOffset() {
34180 context.background().offset([0, 0]);
34184 function nudge(d) {
34185 context.background().nudge(d, context.map().zoom());
34189 function buttonOffset(d) {
34190 var timeout = window.setTimeout(function() {
34191 interval = window.setInterval(nudge.bind(null, d), 100);
34195 d3.select(window).on('mouseup', function() {
34196 window.clearInterval(interval);
34197 window.clearTimeout(timeout);
34198 d3.select(window).on('mouseup', null);
34204 function inputOffset() {
34205 var input = d3.select(this);
34206 var d = input.node().value;
34208 if (d === '') return resetOffset();
34210 d = d.replace(/;/g, ',').split(',').map(function(n) {
34211 // if n is NaN, it will always get mapped to false.
34212 return !isNaN(n) && n;
34215 if (d.length !== 2 || !d[0] || !d[1]) {
34216 input.classed('error', true);
34220 context.background().offset(iD.geo.metersToOffset(d));
34224 function dragOffset() {
34225 var origin = [d3.event.clientX, d3.event.clientY];
34227 context.container()
34229 .attr('class', 'nudge-surface');
34232 .on('mousemove.offset', function() {
34233 var latest = [d3.event.clientX, d3.event.clientY];
34235 -(origin[0] - latest[0]) / 4,
34236 -(origin[1] - latest[1]) / 4
34242 .on('mouseup.offset', function() {
34243 d3.selectAll('.nudge-surface')
34247 .on('mousemove.offset', null)
34248 .on('mouseup.offset', null);
34251 d3.event.preventDefault();
34258 function toggle() {
34259 if (d3.event) d3.event.preventDefault();
34260 tooltip.hide(button);
34261 setVisible(!button.classed('active'));
34264 function quickSwitch() {
34266 clickSetSource(previous);
34270 function setVisible(show) {
34271 if (show !== shown) {
34272 button.classed('active', show);
34276 selection.on('mousedown.background-inside', function() {
34277 return d3.event.stopPropagation();
34279 content.style('display', 'block')
34280 .style('right', '-300px')
34283 .style('right', '0px');
34285 content.style('display', 'block')
34286 .style('right', '0px')
34289 .style('right', '-300px')
34290 .each('end', function() {
34291 d3.select(this).style('display', 'none');
34293 selection.on('mousedown.background-inside', null);
34299 var content = selection.append('div')
34300 .attr('class', 'fillL map-overlay col3 content hide'),
34301 tooltip = bootstrap.tooltip()
34304 .title(iD.ui.tooltipHtml(t('background.description'), key)),
34305 button = selection.append('button')
34306 .attr('tabindex', -1)
34307 .on('click', toggle)
34308 .call(iD.svg.Icon('#icon-layers', 'light'))
34313 /* opacity switcher */
34315 var opa = content.append('div')
34316 .attr('class', 'opacity-options-wrapper');
34319 .text(t('background.title'));
34321 var opacityList = opa.append('ul')
34322 .attr('class', 'opacity-options');
34324 opacityList.selectAll('div.opacity')
34328 .attr('data-original-title', function(d) {
34329 return t('background.percent_brightness', { opacity: (d * 100) });
34331 .on('click.set-opacity', setOpacity)
34332 .html('<div class="select-box"></div>')
34333 .call(bootstrap.tooltip()
34334 .placement('left'))
34336 .attr('class', 'opacity')
34337 .style('opacity', function(d) { return 1.25 - d; });
34340 /* background switcher */
34342 var backgroundList = content.append('ul')
34343 .attr('class', 'layer-list');
34345 var custom = backgroundList.append('li')
34346 .attr('class', 'custom_layer')
34347 .datum(iD.BackgroundSource.Custom());
34349 custom.append('button')
34350 .attr('class', 'layer-browse')
34351 .call(bootstrap.tooltip()
34352 .title(t('background.custom_button'))
34353 .placement('left'))
34354 .on('click', editCustom)
34355 .call(iD.svg.Icon('#icon-search'));
34357 var label = custom.append('label');
34359 label.append('input')
34360 .attr('type', 'radio')
34361 .attr('name', 'layers')
34362 .on('change', function () {
34363 if (customTemplate) {
34364 setCustom(customTemplate);
34370 label.append('span')
34371 .text(t('background.custom'));
34373 content.append('div')
34374 .attr('class', 'imagery-faq')
34376 .attr('target', '_blank')
34377 .attr('tabindex', -1)
34378 .call(iD.svg.Icon('#icon-out-link', 'inline'))
34379 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
34381 .text(t('background.imagery_source_faq'));
34383 var overlayList = content.append('ul')
34384 .attr('class', 'layer-list');
34386 var controls = content.append('div')
34387 .attr('class', 'controls-list');
34390 /* minimap toggle */
34392 var minimapLabel = controls
34394 .call(bootstrap.tooltip()
34396 .title(iD.ui.tooltipHtml(t('background.minimap.tooltip'), '/'))
34400 minimapLabel.classed('minimap-toggle', true)
34402 .attr('type', 'checkbox')
34403 .on('change', function() {
34404 iD.ui.MapInMap.toggle();
34405 d3.event.preventDefault();
34408 minimapLabel.append('span')
34409 .text(t('background.minimap.description'));
34412 /* imagery offset controls */
34414 var adjustments = content.append('div')
34415 .attr('class', 'adjustments');
34417 adjustments.append('a')
34418 .text(t('background.fix_misalignment'))
34420 .classed('hide-toggle', true)
34421 .classed('expanded', false)
34422 .on('click', function() {
34423 var exp = d3.select(this).classed('expanded');
34424 nudgeContainer.style('display', exp ? 'none' : 'block');
34425 d3.select(this).classed('expanded', !exp);
34426 d3.event.preventDefault();
34429 var nudgeContainer = adjustments.append('div')
34430 .attr('class', 'nudge-container cf')
34431 .style('display', 'none');
34433 nudgeContainer.append('div')
34434 .attr('class', 'nudge-instructions')
34435 .text(t('background.offset'));
34437 var nudgeRect = nudgeContainer.append('div')
34438 .attr('class', 'nudge-outer-rect')
34439 .on('mousedown', dragOffset);
34441 nudgeRect.append('div')
34442 .attr('class', 'nudge-inner-rect')
34444 .on('change', inputOffset)
34445 .on('mousedown', function() {
34446 d3.event.stopPropagation();
34449 nudgeContainer.append('div')
34450 .selectAll('button')
34451 .data(directions).enter()
34453 .attr('class', function(d) { return d[0] + ' nudge'; })
34454 .on('mousedown', function(d) {
34455 buttonOffset(d[1]);
34458 nudgeContainer.append('button')
34459 .attr('title', t('background.reset'))
34460 .attr('class', 'nudge-reset disabled')
34461 .on('click', resetOffset)
34462 .call(iD.svg.Icon('#icon-undo'));
34465 .on('move.background-update', _.debounce(update, 1000));
34467 context.background()
34468 .on('change.background-update', update);
34472 setOpacity(opacityDefault);
34474 var keybinding = d3.keybinding('background')
34476 .on(iD.ui.cmd('⌘B'), quickSwitch)
34480 d3.select(document)
34483 context.surface().on('mousedown.background-outside', hide);
34484 context.container().on('mousedown.background-outside', hide);
34489 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
34490 // For example, ⌘Z -> Ctrl+Z
34491 iD.ui.cmd = function(code) {
34492 if (iD.detect().os === 'mac') {
34496 if (iD.detect().os === 'win') {
34497 if (code === '⌘⇧Z') return 'Ctrl+Y';
34509 for (var i = 0; i < code.length; i++) {
34510 if (code[i] in replacements) {
34511 result += replacements[code[i]] + '+';
34519 iD.ui.Commit = function(context) {
34520 var dispatch = d3.dispatch('cancel', 'save');
34522 function commit(selection) {
34523 var changes = context.history().changes(),
34524 summary = context.history().difference().summary();
34526 function zoomToEntity(change) {
34527 var entity = change.entity;
34528 if (change.changeType !== 'deleted' &&
34529 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
34530 context.map().zoomTo(entity);
34531 context.surface().selectAll(
34532 iD.util.entityOrMemberSelector([entity.id], context.graph()))
34533 .classed('hover', true);
34537 var header = selection.append('div')
34538 .attr('class', 'header fillL');
34540 header.append('h3')
34541 .text(t('commit.title'));
34543 var body = selection.append('div')
34544 .attr('class', 'body');
34548 var commentSection = body.append('div')
34549 .attr('class', 'modal-section form-field commit-form');
34551 commentSection.append('label')
34552 .attr('class', 'form-label')
34553 .text(t('commit.message_label'));
34555 var commentField = commentSection.append('textarea')
34556 .attr('placeholder', t('commit.description_placeholder'))
34557 .attr('maxlength', 255)
34558 .property('value', context.storage('comment') || '')
34559 .on('input.save', checkComment)
34560 .on('change.save', checkComment)
34561 .on('blur.save', function() {
34562 context.storage('comment', this.value);
34565 function checkComment() {
34566 d3.selectAll('.save-section .save-button')
34567 .attr('disabled', (this.value.length ? null : true));
34569 var googleWarning = clippyArea
34572 .data(this.value.match(/google/i) ? [true] : []);
34574 googleWarning.exit().remove();
34576 googleWarning.enter()
34578 .attr('target', '_blank')
34579 .attr('tabindex', -1)
34580 .call(iD.svg.Icon('#icon-alert', 'inline'))
34581 .attr('href', t('commit.google_warning_link'))
34583 .text(t('commit.google_warning'));
34586 commentField.node().select();
34588 context.connection().userChangesets(function (err, changesets) {
34593 for (var i = 0; i < changesets.length; i++) {
34594 if (changesets[i].tags.comment) {
34596 title: changesets[i].tags.comment,
34597 value: changesets[i].tags.comment
34602 commentField.call(d3.combobox().caseSensitive(true).data(comments));
34605 var clippyArea = commentSection.append('div')
34606 .attr('class', 'clippy-area');
34609 var changeSetInfo = commentSection.append('div')
34610 .attr('class', 'changeset-info');
34612 changeSetInfo.append('a')
34613 .attr('target', '_blank')
34614 .attr('tabindex', -1)
34615 .call(iD.svg.Icon('#icon-out-link', 'inline'))
34616 .attr('href', t('commit.about_changeset_comments_link'))
34618 .text(t('commit.about_changeset_comments'));
34621 var warnings = body.selectAll('div.warning-section')
34622 .data([context.history().validate(changes)])
34625 .attr('class', 'modal-section warning-section fillL2')
34626 .style('display', function(d) { return _.isEmpty(d) ? 'none' : null; })
34627 .style('background', '#ffb');
34629 warnings.append('h3')
34630 .text(t('commit.warnings'));
34632 var warningLi = warnings.append('ul')
34633 .attr('class', 'changeset-list')
34635 .data(function(d) { return d; })
34639 .on('mouseover', mouseover)
34640 .on('mouseout', mouseout)
34641 .on('click', warningClick);
34644 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
34647 .append('strong').text(function(d) {
34651 warningLi.filter(function(d) { return d.tooltip; })
34652 .call(bootstrap.tooltip()
34653 .title(function(d) { return d.tooltip; })
34658 // Upload Explanation
34659 var saveSection = body.append('div')
34660 .attr('class','modal-section save-section fillL cf');
34662 var prose = saveSection.append('p')
34663 .attr('class', 'commit-info')
34664 .html(t('commit.upload_explanation'));
34666 context.connection().userDetails(function(err, user) {
34669 var userLink = d3.select(document.createElement('div'));
34671 if (user.image_url) {
34672 userLink.append('img')
34673 .attr('src', user.image_url)
34674 .attr('class', 'icon pre-text user-icon');
34677 userLink.append('a')
34678 .attr('class','user-info')
34679 .text(user.display_name)
34680 .attr('href', context.connection().userURL(user.display_name))
34681 .attr('tabindex', -1)
34682 .attr('target', '_blank');
34684 prose.html(t('commit.upload_explanation_with_user', {user: userLink.html()}));
34689 var buttonSection = saveSection.append('div')
34690 .attr('class','buttons fillL cf');
34692 var cancelButton = buttonSection.append('button')
34693 .attr('class', 'secondary-action col5 button cancel-button')
34694 .on('click.cancel', function() { dispatch.cancel(); });
34696 cancelButton.append('span')
34697 .attr('class', 'label')
34698 .text(t('commit.cancel'));
34700 var saveButton = buttonSection.append('button')
34701 .attr('class', 'action col5 button save-button')
34702 .attr('disabled', function() {
34703 var n = d3.select('.commit-form textarea').node();
34704 return (n && n.value.length) ? null : true;
34706 .on('click.save', function() {
34708 comment: commentField.node().value
34712 saveButton.append('span')
34713 .attr('class', 'label')
34714 .text(t('commit.save'));
34718 var changeSection = body.selectAll('div.commit-section')
34722 .attr('class', 'commit-section modal-section fillL2');
34724 changeSection.append('h3')
34725 .text(t('commit.changes', {count: summary.length}));
34727 var li = changeSection.append('ul')
34728 .attr('class', 'changeset-list')
34733 .on('mouseover', mouseover)
34734 .on('mouseout', mouseout)
34735 .on('click', zoomToEntity);
34737 li.each(function(d) {
34739 .call(iD.svg.Icon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
34743 .attr('class', 'change-type')
34744 .text(function(d) {
34745 return t('commit.' + d.changeType) + ' ';
34748 li.append('strong')
34749 .attr('class', 'entity-type')
34750 .text(function(d) {
34751 return context.presets().match(d.entity, d.graph).name();
34755 .attr('class', 'entity-name')
34756 .text(function(d) {
34757 var name = iD.util.displayName(d.entity) || '',
34759 if (name !== '') string += ':';
34760 return string += ' ' + name;
34763 li.style('opacity', 0)
34765 .style('opacity', 1);
34768 function mouseover(d) {
34770 context.surface().selectAll(
34771 iD.util.entityOrMemberSelector([d.entity.id], context.graph())
34772 ).classed('hover', true);
34776 function mouseout() {
34777 context.surface().selectAll('.hover')
34778 .classed('hover', false);
34781 function warningClick(d) {
34783 context.map().zoomTo(d.entity);
34785 iD.modes.Select(context, [d.entity.id])
34786 .suppressMenu(true));
34790 // Call checkComment off the bat, in case a changeset
34791 // comment is recovered from localStorage
34792 commentField.trigger('input');
34795 return d3.rebind(commit, dispatch, 'on');
34797 iD.ui.confirm = function(selection) {
34798 var modal = iD.ui.modal(selection);
34800 modal.select('.modal')
34801 .classed('modal-alert', true);
34803 var section = modal.select('.content');
34805 section.append('div')
34806 .attr('class', 'modal-section header');
34808 section.append('div')
34809 .attr('class', 'modal-section message-text');
34811 var buttons = section.append('div')
34812 .attr('class', 'modal-section buttons cf');
34814 modal.okButton = function() {
34817 .attr('class', 'action col4')
34818 .on('click.confirm', function() {
34821 .text(t('confirm.okay'));
34828 iD.ui.Conflicts = function(context) {
34829 var dispatch = d3.dispatch('download', 'cancel', 'save'),
34832 function conflicts(selection) {
34833 var header = selection
34835 .attr('class', 'header fillL');
34839 .attr('class', 'fr')
34840 .on('click', function() { dispatch.cancel(); })
34841 .call(iD.svg.Icon('#icon-close'));
34845 .text(t('save.conflict.header'));
34847 var body = selection
34849 .attr('class', 'body fillL');
34853 .attr('class', 'conflicts-help')
34854 .text(t('save.conflict.help'))
34856 .attr('class', 'conflicts-download')
34857 .text(t('save.conflict.download_changes'))
34858 .on('click.download', function() { dispatch.download(); });
34862 .attr('class', 'conflict-container fillL3')
34863 .call(showConflict, 0);
34867 .attr('class', 'conflicts-done')
34868 .attr('opacity', 0)
34869 .style('display', 'none')
34870 .text(t('save.conflict.done'));
34874 .attr('class','buttons col12 joined conflicts-buttons');
34878 .attr('disabled', list.length > 1)
34879 .attr('class', 'action conflicts-button col6')
34880 .text(t('save.title'))
34881 .on('click.try_again', function() { dispatch.save(); });
34885 .attr('class', 'secondary-action conflicts-button col6')
34886 .text(t('confirm.cancel'))
34887 .on('click.cancel', function() { dispatch.cancel(); });
34891 function showConflict(selection, index) {
34892 if (index < 0 || index >= list.length) return;
34894 var parent = d3.select(selection.node().parentNode);
34896 // enable save button if this is the last conflict being reviewed..
34897 if (index === list.length - 1) {
34898 window.setTimeout(function() {
34899 parent.select('.conflicts-button')
34900 .attr('disabled', null);
34902 parent.select('.conflicts-done')
34904 .attr('opacity', 1)
34905 .style('display', 'block');
34909 var item = selection
34910 .selectAll('.conflict')
34911 .data([list[index]]);
34913 var enter = item.enter()
34915 .attr('class', 'conflict');
34919 .attr('class', 'conflict-count')
34920 .text(t('save.conflict.count', { num: index + 1, total: list.length }));
34924 .attr('class', 'conflict-description')
34926 .text(function(d) { return d.name; })
34927 .on('click', function(d) {
34928 zoomToEntity(d.id);
34929 d3.event.preventDefault();
34932 var details = enter
34934 .attr('class', 'conflict-detail-container');
34938 .attr('class', 'conflict-detail-list')
34940 .data(function(d) { return d.details || []; })
34943 .attr('class', 'conflict-detail-item')
34944 .html(function(d) { return d; });
34948 .attr('class', 'conflict-choices')
34953 .attr('class', 'conflict-nav-buttons joined cf')
34954 .selectAll('button')
34955 .data(['previous', 'next'])
34958 .text(function(d) { return t('save.conflict.' + d); })
34959 .attr('class', 'conflict-nav-button action col6')
34960 .attr('disabled', function(d, i) {
34961 return (i === 0 && index === 0) ||
34962 (i === 1 && index === list.length - 1) || null;
34964 .on('click', function(d, i) {
34965 var container = parent.select('.conflict-container'),
34966 sign = (i === 0 ? -1 : 1);
34969 .selectAll('.conflict')
34973 .call(showConflict, index + sign);
34975 d3.event.preventDefault();
34983 function addChoices(selection) {
34984 var choices = selection
34986 .attr('class', 'layer-list')
34988 .data(function(d) { return d.choices || []; });
34990 var enter = choices.enter()
34992 .attr('class', 'layer');
34999 .attr('type', 'radio')
35000 .attr('name', function(d) { return d.id; })
35001 .on('change', function(d, i) {
35002 var ul = this.parentNode.parentNode.parentNode;
35003 ul.__data__.chosen = i;
35009 .text(function(d) { return d.text; });
35012 .each(function(d, i) {
35013 var ul = this.parentNode;
35014 if (ul.__data__.chosen === i) choose(ul, d);
35018 function choose(ul, datum) {
35019 if (d3.event) d3.event.preventDefault();
35023 .classed('active', function(d) { return d === datum; })
35024 .selectAll('input')
35025 .property('checked', function(d) { return d === datum; });
35027 var extent = iD.geo.Extent(),
35030 entity = context.graph().hasEntity(datum.id);
35031 if (entity) extent._extend(entity.extent(context.graph()));
35035 entity = context.graph().hasEntity(datum.id);
35036 if (entity) extent._extend(entity.extent(context.graph()));
35038 zoomToEntity(datum.id, extent);
35041 function zoomToEntity(id, extent) {
35042 context.surface().selectAll('.hover')
35043 .classed('hover', false);
35045 var entity = context.graph().hasEntity(id);
35048 context.map().trimmedExtent(extent);
35050 context.map().zoomTo(entity);
35052 context.surface().selectAll(
35053 iD.util.entityOrMemberSelector([entity.id], context.graph()))
35054 .classed('hover', true);
35059 // The conflict list should be an array of objects like:
35062 // name: entityName(local),
35063 // details: merge.conflicts(),
35066 // choice(id, keepMine, forceLocal),
35067 // choice(id, keepTheirs, forceRemote)
35070 conflicts.list = function(_) {
35071 if (!arguments.length) return list;
35076 return d3.rebind(conflicts, dispatch, 'on');
35078 iD.ui.Contributors = function(context) {
35079 var debouncedUpdate = _.debounce(function() { update(); }, 1000),
35082 wrap = d3.select(null);
35084 function update() {
35086 entities = context.intersects(context.map().extent());
35088 entities.forEach(function(entity) {
35089 if (entity && entity.user) users[entity.user] = true;
35092 var u = Object.keys(users),
35093 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
35096 .call(iD.svg.Icon('#icon-nearby', 'pre-text light'));
35098 var userList = d3.select(document.createElement('span'));
35100 userList.selectAll()
35104 .attr('class', 'user-link')
35105 .attr('href', function(d) { return context.connection().userURL(d); })
35106 .attr('target', '_blank')
35107 .attr('tabindex', -1)
35110 if (u.length > limit) {
35111 var count = d3.select(document.createElement('span'));
35114 .attr('target', '_blank')
35115 .attr('tabindex', -1)
35116 .attr('href', function() {
35117 return context.connection().changesetsURL(context.map().center(), context.map().zoom());
35119 .text(u.length - limit + 1);
35121 wrap.append('span')
35122 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
35125 wrap.append('span')
35126 .html(t('contributors.list', { users: userList.html() }));
35133 .style('opacity', 0);
35135 } else if (hidden) {
35138 .style('opacity', 1);
35142 return function(selection) {
35146 context.connection().on('loaded.contributors', debouncedUpdate);
35147 context.map().on('move.contributors', debouncedUpdate);
35150 iD.ui.Disclosure = function() {
35151 var dispatch = d3.dispatch('toggled'),
35154 content = function () {};
35156 var disclosure = function(selection) {
35157 var $link = selection.selectAll('.hide-toggle')
35160 $link.enter().append('a')
35162 .attr('class', 'hide-toggle');
35165 .on('click', toggle)
35166 .classed('expanded', expanded);
35168 var $body = selection.selectAll('div')
35171 $body.enter().append('div');
35173 $body.classed('hide', !expanded)
35176 function toggle() {
35177 expanded = !expanded;
35178 $link.classed('expanded', expanded);
35179 $body.call(iD.ui.Toggle(expanded));
35180 dispatch.toggled(expanded);
35184 disclosure.title = function(_) {
35185 if (!arguments.length) return title;
35190 disclosure.expanded = function(_) {
35191 if (!arguments.length) return expanded;
35196 disclosure.content = function(_) {
35197 if (!arguments.length) return content;
35202 return d3.rebind(disclosure, dispatch, 'on');
35204 iD.ui.EntityEditor = function(context) {
35205 var dispatch = d3.dispatch('choose'),
35207 coalesceChanges = false,
35214 var presetEditor = iD.ui.preset(context)
35215 .on('change', changeTags);
35216 var rawTagEditor = iD.ui.RawTagEditor(context)
35217 .on('change', changeTags);
35219 function entityEditor(selection) {
35220 var entity = context.entity(id),
35221 tags = _.clone(entity.tags);
35223 var $header = selection.selectAll('.header')
35227 var $enter = $header.enter().append('div')
35228 .attr('class', 'header fillL cf');
35230 $enter.append('button')
35231 .attr('class', 'fl preset-reset preset-choose')
35235 $enter.append('button')
35236 .attr('class', 'fr preset-close')
35237 .call(iD.svg.Icon(modified ? '#icon-apply' : '#icon-close'));
35239 $enter.append('h3');
35242 $header.select('h3')
35243 .text(t('inspector.edit'));
35245 $header.select('.preset-close')
35246 .on('click', function() {
35247 context.enter(iD.modes.Browse(context));
35250 var $body = selection.selectAll('.inspector-body')
35254 $enter = $body.enter().append('div')
35255 .attr('class', 'inspector-body');
35257 $enter.append('div')
35258 .attr('class', 'preset-list-item inspector-inner')
35260 .attr('class', 'preset-list-button-wrap')
35262 .attr('class', 'preset-list-button preset-reset')
35263 .call(bootstrap.tooltip()
35264 .title(t('inspector.back_tooltip'))
35265 .placement('bottom'))
35267 .attr('class', 'label');
35269 $body.select('.preset-list-button-wrap')
35270 .call(reference.button);
35272 $body.select('.preset-list-item')
35273 .call(reference.body);
35275 $enter.append('div')
35276 .attr('class', 'inspector-border inspector-preset');
35278 $enter.append('div')
35279 .attr('class', 'inspector-border raw-tag-editor inspector-inner');
35281 $enter.append('div')
35282 .attr('class', 'inspector-border raw-member-editor inspector-inner');
35284 $enter.append('div')
35285 .attr('class', 'raw-membership-editor inspector-inner');
35287 selection.selectAll('.preset-reset')
35288 .on('click', function() {
35289 dispatch.choose(preset);
35293 $body.select('.preset-list-item button')
35294 .call(iD.ui.PresetIcon()
35295 .geometry(context.geometry(id))
35298 $body.select('.preset-list-item .label')
35299 .text(preset.name());
35301 $body.select('.inspector-preset')
35308 $body.select('.raw-tag-editor')
35315 if (entity.type === 'relation') {
35316 $body.select('.raw-member-editor')
35317 .style('display', 'block')
35318 .call(iD.ui.RawMemberEditor(context)
35321 $body.select('.raw-member-editor')
35322 .style('display', 'none');
35325 $body.select('.raw-membership-editor')
35326 .call(iD.ui.RawMembershipEditor(context)
35329 function historyChanged() {
35330 if (state === 'hide') return;
35332 var entity = context.hasEntity(id),
35333 graph = context.graph();
35334 if (!entity) return;
35336 entityEditor.preset(context.presets().match(entity, graph));
35337 entityEditor.modified(base !== graph);
35338 entityEditor(selection);
35342 .on('change.entity-editor', historyChanged);
35345 function clean(o) {
35347 function cleanVal(k, v) {
35348 function keepSpaces(k) {
35349 var whitelist = ['opening_hours', 'service_times', 'collection_times',
35350 'operating_times', 'smoking_hours', 'happy_hours'];
35351 return _.some(whitelist, function(s) { return k.indexOf(s) !== -1; });
35354 var blacklist = ['description', 'note', 'fixme'];
35355 if (_.some(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
35357 var cleaned = v.split(';')
35358 .map(function(s) { return s.trim(); })
35359 .join(keepSpaces(k) ? '; ' : ';');
35361 // The code below is not intended to validate websites and emails.
35362 // It is only intended to prevent obvious copy-paste errors. (#2323)
35364 // clean website- and email-like tags
35365 if (k.indexOf('website') !== -1 ||
35366 k.indexOf('email') !== -1 ||
35367 cleaned.indexOf('http') === 0) {
35369 .replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
35376 var out = {}, k, v;
35378 if (k && (v = o[k]) !== undefined) {
35379 out[k] = cleanVal(k, v);
35385 // Tag changes that fire on input can all get coalesced into a single
35386 // history operation when the user leaves the field. #2342
35387 function changeTags(changed, onInput) {
35388 var entity = context.entity(id),
35389 annotation = t('operations.change_tags.annotation'),
35390 tags = _.extend({}, entity.tags, changed);
35393 tags = clean(tags);
35395 if (!_.isEqual(entity.tags, tags)) {
35396 if (coalesceChanges) {
35397 context.overwrite(iD.actions.ChangeTags(id, tags), annotation);
35399 context.perform(iD.actions.ChangeTags(id, tags), annotation);
35400 coalesceChanges = !!onInput;
35405 entityEditor.modified = function(_) {
35406 if (!arguments.length) return modified;
35408 d3.selectAll('button.preset-close use')
35409 .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
35412 entityEditor.state = function(_) {
35413 if (!arguments.length) return state;
35415 return entityEditor;
35418 entityEditor.entityID = function(_) {
35419 if (!arguments.length) return id;
35421 base = context.graph();
35422 entityEditor.preset(context.presets().match(context.entity(id), base));
35423 entityEditor.modified(false);
35424 coalesceChanges = false;
35425 return entityEditor;
35428 entityEditor.preset = function(_) {
35429 if (!arguments.length) return preset;
35430 if (_ !== preset) {
35432 reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context)
35435 return entityEditor;
35438 return d3.rebind(entityEditor, dispatch, 'on');
35440 iD.ui.FeatureInfo = function(context) {
35441 function update(selection) {
35442 var features = context.features(),
35443 stats = features.stats(),
35445 hiddenList = _.compact(_.map(features.hidden(), function(k) {
35448 return String(stats[k]) + ' ' + t('feature.' + k + '.description');
35452 selection.html('');
35454 if (hiddenList.length) {
35455 var tooltip = bootstrap.tooltip()
35458 .title(function() {
35459 return iD.ui.tooltipHtml(hiddenList.join('<br/>'));
35462 var warning = selection.append('a')
35464 .attr('tabindex', -1)
35465 .html(t('feature_info.hidden_warning', { count: count }))
35467 .on('click', function() {
35468 tooltip.hide(warning);
35469 // open map data panel?
35470 d3.event.preventDefault();
35475 .classed('hide', !hiddenList.length);
35478 return function(selection) {
35481 context.features().on('change.feature_info', function() {
35486 iD.ui.FeatureList = function(context) {
35487 var geocodeResults;
35489 function featureList(selection) {
35490 var header = selection.append('div')
35491 .attr('class', 'header fillL cf');
35493 header.append('h3')
35494 .text(t('inspector.feature_list'));
35496 function keypress() {
35497 var q = search.property('value'),
35498 items = list.selectAll('.feature-list-item');
35499 if (d3.event.keyCode === 13 && q.length && items.size()) {
35500 click(items.datum());
35504 function inputevent() {
35505 geocodeResults = undefined;
35509 var searchWrap = selection.append('div')
35510 .attr('class', 'search-header');
35512 var search = searchWrap.append('input')
35513 .attr('placeholder', t('inspector.search'))
35514 .attr('type', 'search')
35515 .on('keypress', keypress)
35516 .on('input', inputevent);
35519 .call(iD.svg.Icon('#icon-search', 'pre-text'));
35521 var listWrap = selection.append('div')
35522 .attr('class', 'inspector-body');
35524 var list = listWrap.append('div')
35525 .attr('class', 'feature-list cf');
35528 .on('exit.feature-list', clearSearch);
35530 .on('drawn.feature-list', mapDrawn);
35532 function clearSearch() {
35533 search.property('value', '');
35537 function mapDrawn(e) {
35543 function features() {
35546 graph = context.graph(),
35547 q = search.property('value').toLowerCase();
35549 if (!q) return result;
35551 var idMatch = q.match(/^([nwr])([0-9]+)$/);
35556 geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
35557 type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
35562 var locationMatch = sexagesimal.pair(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
35564 if (locationMatch) {
35565 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
35569 type: t('inspector.location'),
35570 name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
35575 function addEntity(entity) {
35576 if (entity.id in entities || result.length > 200)
35579 entities[entity.id] = true;
35581 var name = iD.util.displayName(entity) || '';
35582 if (name.toLowerCase().indexOf(q) >= 0) {
35586 geometry: context.geometry(entity.id),
35587 type: context.presets().match(entity, graph).name(),
35592 graph.parentRelations(entity).forEach(function(parent) {
35597 var visible = context.surface().selectAll('.point, .line, .area')[0];
35598 for (var i = 0; i < visible.length && result.length <= 200; i++) {
35599 addEntity(visible[i].__data__);
35602 (geocodeResults || []).forEach(function(d) {
35603 // https://github.com/openstreetmap/iD/issues/1890
35604 if (d.osm_type && d.osm_id) {
35606 id: iD.Entity.id.fromOSM(d.osm_type, d.osm_id),
35607 geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
35608 type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
35609 : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
35610 name: d.display_name,
35611 extent: new iD.geo.Extent(
35612 [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
35613 [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
35621 function drawList() {
35622 var value = search.property('value'),
35623 results = features();
35625 list.classed('filtered', value.length);
35627 var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
35629 var resultsIndicator = list.selectAll('.no-results-item')
35631 .enter().append('button')
35632 .property('disabled', true)
35633 .attr('class', 'no-results-item')
35634 .call(iD.svg.Icon('#icon-alert', 'pre-text'));
35636 resultsIndicator.append('span')
35637 .attr('class', 'entity-name');
35639 list.selectAll('.no-results-item .entity-name')
35640 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
35642 list.selectAll('.geocode-item')
35644 .enter().append('button')
35645 .attr('class', 'geocode-item')
35646 .on('click', geocode)
35648 .attr('class', 'label')
35650 .attr('class', 'entity-name')
35651 .text(t('geocoder.search'));
35653 list.selectAll('.no-results-item')
35654 .style('display', (value.length && !results.length) ? 'block' : 'none');
35656 list.selectAll('.geocode-item')
35657 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
35659 list.selectAll('.feature-list-item')
35663 var items = list.selectAll('.feature-list-item')
35664 .data(results, function(d) { return d.id; });
35666 var enter = items.enter()
35667 .insert('button', '.geocode-item')
35668 .attr('class', 'feature-list-item')
35669 .on('mouseover', mouseover)
35670 .on('mouseout', mouseout)
35671 .on('click', click);
35675 .attr('class', 'label');
35677 label.each(function(d) {
35679 .call(iD.svg.Icon('#icon-' + d.geometry, 'pre-text'));
35682 label.append('span')
35683 .attr('class', 'entity-type')
35684 .text(function(d) { return d.type; });
35686 label.append('span')
35687 .attr('class', 'entity-name')
35688 .text(function(d) { return d.name; });
35690 enter.style('opacity', 0)
35692 .style('opacity', 1);
35700 function mouseover(d) {
35701 if (d.id === -1) return;
35703 context.surface().selectAll(iD.util.entityOrMemberSelector([d.id], context.graph()))
35704 .classed('hover', true);
35707 function mouseout() {
35708 context.surface().selectAll('.hover')
35709 .classed('hover', false);
35712 function click(d) {
35713 d3.event.preventDefault();
35715 context.map().centerZoom([d.location[1], d.location[0]], 20);
35717 else if (d.entity) {
35718 if (d.entity.type === 'node') {
35719 context.map().center(d.entity.loc);
35720 } else if (d.entity.type === 'way') {
35721 var center = context.projection(context.map().center()),
35722 edge = iD.geo.chooseEdge(context.childNodes(d.entity), center, context.projection);
35723 context.map().center(edge.loc);
35725 context.enter(iD.modes.Select(context, [d.entity.id]).suppressMenu(true));
35727 context.zoomToEntity(d.id);
35731 function geocode() {
35732 var searchVal = encodeURIComponent(search.property('value'));
35733 d3.json('https://nominatim.openstreetmap.org/search/' + searchVal + '?limit=10&format=json', function(err, resp) {
35734 geocodeResults = resp || [];
35740 return featureList;
35742 iD.ui.flash = function(selection) {
35743 var modal = iD.ui.modal(selection);
35745 modal.select('.modal').classed('modal-flash', true);
35747 modal.select('.content')
35748 .classed('modal-section', true)
35750 .attr('class', 'description');
35752 modal.on('click.flash', function() { modal.remove(); });
35754 setTimeout(function() {
35761 iD.ui.FullScreen = function(context) {
35762 var element = context.container().node(),
35763 keybinding = d3.keybinding('full-screen');
35766 function getFullScreenFn() {
35767 if (element.requestFullscreen) {
35768 return element.requestFullscreen;
35769 } else if (element.msRequestFullscreen) {
35770 return element.msRequestFullscreen;
35771 } else if (element.mozRequestFullScreen) {
35772 return element.mozRequestFullScreen;
35773 } else if (element.webkitRequestFullscreen) {
35774 return element.webkitRequestFullscreen;
35778 function getExitFullScreenFn() {
35779 if (document.exitFullscreen) {
35780 return document.exitFullscreen;
35781 } else if (document.msExitFullscreen) {
35782 return document.msExitFullscreen;
35783 } else if (document.mozCancelFullScreen) {
35784 return document.mozCancelFullScreen;
35785 } else if (document.webkitExitFullscreen) {
35786 return document.webkitExitFullscreen;
35790 function isFullScreen() {
35791 return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement ||
35792 document.msFullscreenElement;
35795 function isSupported() {
35796 return !!getFullScreenFn();
35799 function fullScreen() {
35800 d3.event.preventDefault();
35801 if (!isFullScreen()) {
35802 // button.classed('active', true);
35803 getFullScreenFn().apply(element);
35805 // button.classed('active', false);
35806 getExitFullScreenFn().apply(document);
35810 return function() { // selection) {
35811 if (!isSupported())
35814 // var tooltip = bootstrap.tooltip()
35815 // .placement('left');
35817 // button = selection.append('button')
35818 // .attr('title', t('full_screen'))
35819 // .attr('tabindex', -1)
35820 // .on('click', fullScreen)
35823 // button.append('span')
35824 // .attr('class', 'icon full-screen');
35827 .on('f11', fullScreen)
35828 .on(iD.ui.cmd('⌘⇧F'), fullScreen);
35830 d3.select(document)
35834 iD.ui.Geolocate = function(context) {
35835 var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
35836 locating = iD.ui.Loading(context).message(t('geolocate.locating')).blocking(true),
35840 context.enter(iD.modes.Browse(context));
35841 context.container().call(locating);
35842 navigator.geolocation.getCurrentPosition(success, error, geoOptions);
35844 // This timeout ensures that we still call finish() even if
35845 // the user declines to share their location in Firefox
35846 timeoutId = setTimeout(finish, 10000 /* 10sec */ );
35849 function success(position) {
35850 var map = context.map(),
35851 extent = iD.geo.Extent([position.coords.longitude, position.coords.latitude])
35852 .padByMeters(position.coords.accuracy);
35854 map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
35862 function finish() {
35863 locating.close(); // unblock ui
35864 if (timeoutId) { clearTimeout(timeoutId); }
35865 timeoutId = undefined;
35868 return function(selection) {
35869 if (!navigator.geolocation) return;
35871 selection.append('button')
35872 .attr('tabindex', -1)
35873 .attr('title', t('geolocate.title'))
35874 .on('click', click)
35875 .call(iD.svg.Icon('#icon-geolocate', 'light'))
35876 .call(bootstrap.tooltip()
35877 .placement('left'));
35880 iD.ui.Help = function(context) {
35885 'help.editing_saving',
35894 var docs = docKeys.map(function(key) {
35897 title: text.split('\n')[0].replace('#', '').trim(),
35898 html: marked(text.split('\n').slice(1).join('\n'))
35902 function help(selection) {
35908 function toggle() {
35909 if (d3.event) d3.event.preventDefault();
35910 tooltip.hide(button);
35911 setVisible(!button.classed('active'));
35914 function setVisible(show) {
35915 if (show !== shown) {
35916 button.classed('active', show);
35920 selection.on('mousedown.help-inside', function() {
35921 return d3.event.stopPropagation();
35923 pane.style('display', 'block')
35924 .style('right', '-500px')
35927 .style('right', '0px');
35929 pane.style('right', '0px')
35932 .style('right', '-500px')
35933 .each('end', function() {
35934 d3.select(this).style('display', 'none');
35936 selection.on('mousedown.help-inside', null);
35941 function clickHelp(d, i) {
35942 pane.property('scrollTop', 0);
35943 doctitle.html(d.title);
35945 body.selectAll('a')
35946 .attr('target', '_blank');
35947 menuItems.classed('selected', function(m) {
35948 return m.title === d.title;
35954 var prevLink = nav.append('a')
35955 .attr('class', 'previous')
35956 .on('click', function() {
35957 clickHelp(docs[i - 1], i - 1);
35959 prevLink.append('span').html('◄ ' + docs[i - 1].title);
35961 if (i < docs.length - 1) {
35962 var nextLink = nav.append('a')
35963 .attr('class', 'next')
35964 .on('click', function() {
35965 clickHelp(docs[i + 1], i + 1);
35967 nextLink.append('span').html(docs[i + 1].title + ' ►');
35971 function clickWalkthrough() {
35972 d3.select(document.body).call(iD.ui.intro(context));
35977 var pane = selection.append('div')
35978 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
35979 tooltip = bootstrap.tooltip()
35982 .title(iD.ui.tooltipHtml(t('help.title'), key)),
35983 button = selection.append('button')
35984 .attr('tabindex', -1)
35985 .on('click', toggle)
35986 .call(iD.svg.Icon('#icon-help', 'light'))
35991 var toc = pane.append('ul')
35992 .attr('class', 'toc');
35994 var menuItems = toc.selectAll('li')
35999 .html(function(d) { return d.title; })
36000 .on('click', clickHelp);
36003 .attr('class','walkthrough')
36005 .text(t('splash.walkthrough'))
36006 .on('click', clickWalkthrough);
36008 var content = pane.append('div')
36009 .attr('class', 'left-content');
36011 var doctitle = content.append('h2')
36012 .text(t('help.title'));
36014 var body = content.append('div')
36015 .attr('class', 'body');
36017 var nav = content.append('div')
36018 .attr('class', 'nav');
36020 clickHelp(docs[0], 0);
36022 var keybinding = d3.keybinding('help')
36027 d3.select(document)
36030 context.surface().on('mousedown.help-outside', hide);
36031 context.container().on('mousedown.help-outside', hide);
36036 iD.ui.Info = function(context) {
36037 var key = iD.ui.cmd('⌘I'),
36038 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
36041 function info(selection) {
36042 function radiansToMeters(r) {
36043 // using WGS84 authalic radius (6371007.1809 m)
36044 return r * 6371007.1809;
36047 function steradiansToSqmeters(r) {
36048 // http://gis.stackexchange.com/a/124857/40446
36049 return r / 12.56637 * 510065621724000;
36052 function toLineString(feature) {
36053 if (feature.type === 'LineString') return feature;
36055 var result = { type: 'LineString', coordinates: [] };
36056 if (feature.type === 'Polygon') {
36057 result.coordinates = feature.coordinates[0];
36058 } else if (feature.type === 'MultiPolygon') {
36059 result.coordinates = feature.coordinates[0][0];
36065 function displayLength(m) {
36066 var d = m * (imperial ? 3.28084 : 1),
36085 // drop unnecessary precision
36086 p = d > 1000 ? 0 : d > 100 ? 1 : 2;
36088 return String(d.toFixed(p)) + ' ' + unit;
36091 function displayArea(m2) {
36092 var d = m2 * (imperial ? 10.7639111056 : 1),
36093 d1, d2, p1, p2, unit1, unit2;
36096 if (d >= 6969600) { // > 0.25mi² show mi²
36104 if (d > 4356 && d < 43560000) { // 0.1 - 1000 acres
36110 if (d >= 250000) { // > 0.25km² show km²
36118 if (d > 1000 && d < 10000000) { // 0.1 - 1000 hectares
36124 // drop unnecessary precision
36125 p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
36126 p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
36128 return String(d1.toFixed(p1)) + ' ' + unit1 +
36129 (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
36133 function redraw() {
36134 if (hidden) return;
36136 var resolver = context.graph(),
36137 selected = _.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
36138 singular = selected.length === 1 ? selected[0] : null,
36139 extent = iD.geo.Extent(),
36144 .attr('class', 'infobox-heading fillD')
36145 .text(singular || t('infobox.selected', { n: selected.length }));
36147 if (!selected.length) return;
36150 for (var i = 0; i < selected.length; i++) {
36151 entity = context.entity(selected[i]);
36152 extent._extend(entity.extent(resolver));
36154 center = extent.center();
36157 var list = wrap.append('ul');
36159 // multiple wrap, just display extent center..
36162 .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
36166 // single wrap, display details..
36167 if (!entity) return;
36168 var geometry = entity.geometry(resolver);
36170 if (geometry === 'line' || geometry === 'area') {
36171 var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
36172 feature = entity.asGeoJSON(resolver),
36173 length = radiansToMeters(d3.geo.length(toLineString(feature))),
36174 lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')),
36175 centroid = d3.geo.centroid(feature);
36178 .text(t('infobox.geometry') + ': ' +
36179 (closed ? t('infobox.closed') + ' ' : '') + t('geometry.' + geometry) );
36182 var area = steradiansToSqmeters(entity.area(resolver));
36184 .text(t('infobox.area') + ': ' + displayArea(area));
36188 .text(lengthLabel + ': ' + displayLength(length));
36191 .text(t('infobox.centroid') + ': ' + centroid[0].toFixed(5) + ', ' + centroid[1].toFixed(5));
36194 var toggle = imperial ? 'imperial' : 'metric';
36196 .text(t('infobox.' + toggle))
36198 .attr('class', 'button')
36199 .on('click', function() {
36200 d3.event.preventDefault();
36201 imperial = !imperial;
36206 var centerLabel = t('infobox.' + (entity.type === 'node' ? 'location' : 'center'));
36209 .text(t('infobox.geometry') + ': ' + t('geometry.' + geometry));
36212 .text(centerLabel + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
36217 function toggle() {
36218 if (d3.event) d3.event.preventDefault();
36224 .style('display', 'block')
36225 .style('opacity', 1)
36228 .style('opacity', 0)
36229 .each('end', function() {
36230 d3.select(this).style('display', 'none');
36234 .style('display', 'block')
36235 .style('opacity', 0)
36238 .style('opacity', 1);
36245 var wrap = selection.selectAll('.infobox')
36250 .attr('class', 'infobox fillD2')
36251 .style('display', (hidden ? 'none' : 'block'));
36254 .on('drawn.info', redraw);
36258 var keybinding = d3.keybinding('info')
36261 d3.select(document)
36267 iD.ui.Inspector = function(context) {
36268 var presetList = iD.ui.PresetList(context),
36269 entityEditor = iD.ui.EntityEditor(context),
36272 newFeature = false;
36274 function inspector(selection) {
36276 .entityID(entityID)
36277 .autofocus(newFeature)
36278 .on('choose', setPreset);
36282 .entityID(entityID)
36283 .on('choose', showList);
36285 var $wrap = selection.selectAll('.panewrap')
36288 var $enter = $wrap.enter().append('div')
36289 .attr('class', 'panewrap');
36291 $enter.append('div')
36292 .attr('class', 'preset-list-pane pane');
36294 $enter.append('div')
36295 .attr('class', 'entity-editor-pane pane');
36297 var $presetPane = $wrap.select('.preset-list-pane');
36298 var $editorPane = $wrap.select('.entity-editor-pane');
36300 var graph = context.graph(),
36301 entity = context.entity(entityID),
36302 showEditor = state === 'hover' ||
36303 entity.isUsed(graph) ||
36304 entity.isHighwayIntersection(graph);
36307 $wrap.style('right', '0%');
36308 $editorPane.call(entityEditor);
36310 $wrap.style('right', '-100%');
36311 $presetPane.call(presetList);
36314 var $footer = selection.selectAll('.footer')
36317 $footer.enter().append('div')
36318 .attr('class', 'footer');
36320 selection.select('.footer')
36321 .call(iD.ui.ViewOnOSM(context)
36322 .entityID(entityID));
36324 function showList(preset) {
36326 .styleTween('right', function() { return d3.interpolate('0%', '-100%'); });
36328 $presetPane.call(presetList
36333 function setPreset(preset) {
36335 .styleTween('right', function() { return d3.interpolate('-100%', '0%'); });
36337 $editorPane.call(entityEditor
36342 inspector.state = function(_) {
36343 if (!arguments.length) return state;
36345 entityEditor.state(state);
36349 inspector.entityID = function(_) {
36350 if (!arguments.length) return entityID;
36355 inspector.newFeature = function(_) {
36356 if (!arguments.length) return newFeature;
36363 iD.ui.intro = function(context) {
36366 function intro(selection) {
36368 function localizedName(id) {
36370 n2140018997: 'city_hall',
36371 n367813436: 'fire_department',
36372 w203988286: 'memory_isle_park',
36373 w203972937: 'riverwalk_trail',
36374 w203972938: 'riverwalk_trail',
36375 w203972940: 'riverwalk_trail',
36376 w41785752: 'w_michigan_ave',
36377 w134150789: 'w_michigan_ave',
36378 w134150795: 'w_michigan_ave',
36379 w134150800: 'w_michigan_ave',
36380 w134150811: 'w_michigan_ave',
36381 w134150802: 'e_michigan_ave',
36382 w134150836: 'e_michigan_ave',
36383 w41074896: 'e_michigan_ave',
36384 w17965834: 'spring_st',
36385 w203986457: 'scidmore_park',
36386 w203049587: 'petting_zoo',
36387 w17967397: 'n_andrews_st',
36388 w17967315: 's_andrews_st',
36389 w17967326: 'n_constantine_st',
36390 w17966400: 's_constantine_st',
36391 w170848823: 'rocky_river',
36392 w170848824: 'rocky_river',
36393 w170848331: 'rocky_river',
36394 w17967752: 'railroad_dr',
36395 w17965998: 'conrail_rr',
36396 w134150845: 'conrail_rr',
36397 w170989131: 'st_joseph_river',
36398 w143497377: 'n_main_st',
36399 w134150801: 's_main_st',
36400 w134150830: 's_main_st',
36401 w17966462: 's_main_st',
36402 w17967734: 'water_st',
36403 w17964996: 'foster_st',
36404 w170848330: 'portage_river',
36405 w17965351: 'flower_st',
36406 w17965502: 'elm_st',
36407 w17965402: 'walnut_st',
36408 w17964793: 'morris_ave',
36409 w17967444: 'east_st',
36410 w17966984: 'portage_ave'
36412 return features[id] && t('intro.graph.' + features[id]);
36415 context.enter(iD.modes.Browse(context));
36417 // Save current map state
36418 var history = context.history().toJSON(),
36419 hash = window.location.hash,
36420 center = context.map().center(),
36421 zoom = context.map().zoom(),
36422 background = context.background().baseLayerSource(),
36423 opacity = d3.selectAll('#map .layer-background').style('opacity'),
36424 loadedTiles = context.connection().loadedTiles(),
36425 baseEntities = context.history().graph().base().entities,
36429 context.inIntro(true);
36431 // Load semi-real data used in intro
36432 context.connection().toggle(false).flush();
36433 context.history().reset();
36435 introGraph = JSON.parse(iD.introGraph);
36436 for (var key in introGraph) {
36437 introGraph[key] = iD.Entity(introGraph[key]);
36438 name = localizedName(key);
36440 introGraph[key].tags.name = name;
36443 context.history().merge(d3.values(iD.Graph().load(introGraph).entities));
36444 context.background().bing();
36446 d3.selectAll('#map .layer-background').style('opacity', 1);
36448 var curtain = d3.curtain();
36449 selection.call(curtain);
36451 function reveal(box, text, options) {
36452 options = options || {};
36453 if (text) curtain.reveal(box, text, options.tooltipClass, options.duration);
36454 else curtain.reveal(box, '', '', options.duration);
36457 var steps = ['navigation', 'point', 'area', 'line', 'startEditing'].map(function(step, i) {
36458 var s = iD.ui.intro[step](context, reveal)
36459 .on('done', function() {
36460 entered.filter(function(d) {
36461 return d.title === s.title;
36462 }).classed('finished', true);
36463 enter(steps[i + 1]);
36468 steps[steps.length - 1].on('startEditing', function() {
36471 d3.selectAll('#map .layer-background').style('opacity', opacity);
36472 context.connection().toggle(true).flush().loadedTiles(loadedTiles);
36473 context.history().reset().merge(d3.values(baseEntities));
36474 context.background().baseLayerSource(background);
36475 if (history) context.history().fromJSON(history, false);
36476 context.map().centerZoom(center, zoom);
36477 window.location.replace(hash);
36478 context.inIntro(false);
36481 var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
36483 var buttonwrap = navwrap.append('div')
36484 .attr('class', 'joined')
36485 .selectAll('button.step');
36487 var entered = buttonwrap
36491 .attr('class', 'step')
36492 .on('click', enter);
36495 .call(iD.svg.Icon('#icon-apply', 'pre-text'));
36499 .text(function(d) { return t(d.title); });
36503 function enter (newStep) {
36504 if (step) { step.exit(); }
36506 context.enter(iD.modes.Browse(context));
36511 entered.classed('active', function(d) {
36512 return d.title === step.title;
36520 iD.ui.intro.pointBox = function(point, context) {
36521 var rect = context.surfaceRect();
36522 point = context.projection(point);
36524 left: point[0] + rect.left - 30,
36525 top: point[1] + rect.top - 50,
36531 iD.ui.intro.pad = function(box, padding, context) {
36532 if (box instanceof Array) {
36533 var rect = context.surfaceRect();
36534 box = context.projection(box);
36536 left: box[0] + rect.left,
36537 top: box[1] + rect.top
36541 left: box.left - padding,
36542 top: box.top - padding,
36543 width: (box.width || 0) + 2 * padding,
36544 height: (box.width || 0) + 2 * padding
36548 iD.ui.intro.icon = function(name, svgklass) {
36549 return '<svg class="icon ' + (svgklass || '') + '">' +
36550 '<use xlink:href="' + name + '"></use></svg>';
36552 iD.ui.Lasso = function(context) {
36553 var group, polygon;
36555 lasso.coordinates = [];
36557 function lasso(selection) {
36559 context.container().classed('lasso', true);
36561 group = selection.append('g')
36562 .attr('class', 'lasso hide');
36564 polygon = group.append('path')
36565 .attr('class', 'lasso-path');
36567 group.call(iD.ui.Toggle(true));
36573 polygon.data([lasso.coordinates])
36574 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
36578 lasso.extent = function () {
36579 return lasso.coordinates.reduce(function(extent, point) {
36580 return extent.extend(iD.geo.Extent(point));
36581 }, iD.geo.Extent());
36584 lasso.p = function(_) {
36585 if (!arguments.length) return lasso;
36586 lasso.coordinates.push(_);
36591 lasso.close = function() {
36593 group.call(iD.ui.Toggle(false, function() {
36594 d3.select(this).remove();
36597 context.container().classed('lasso', false);
36602 iD.ui.Loading = function(context) {
36607 var loading = function(selection) {
36608 modal = iD.ui.modal(selection, blocking);
36610 var loadertext = modal.select('.content')
36611 .classed('loading-modal', true)
36613 .attr('class', 'modal-section fillL');
36615 loadertext.append('img')
36616 .attr('class', 'loader')
36617 .attr('src', context.imagePath('loader-white.gif'));
36619 loadertext.append('h3')
36622 modal.select('button.close')
36623 .attr('class', 'hide');
36628 loading.message = function(_) {
36629 if (!arguments.length) return message;
36634 loading.blocking = function(_) {
36635 if (!arguments.length) return blocking;
36640 loading.close = function() {
36646 iD.ui.MapData = function(context) {
36648 features = context.features().keys(),
36649 layers = context.layers(),
36650 fills = ['wireframe', 'partial', 'full'],
36651 fillDefault = context.storage('area-fill') || 'partial',
36652 fillSelected = fillDefault;
36655 function map_data(selection) {
36657 function showsFeature(d) {
36658 return context.features().enabled(d);
36661 function autoHiddenFeature(d) {
36662 return context.features().autoHidden(d);
36665 function clickFeature(d) {
36666 context.features().toggle(d);
36670 function showsFill(d) {
36671 return fillSelected === d;
36674 function setFill(d) {
36675 _.each(fills, function(opt) {
36676 context.surface().classed('fill-' + opt, Boolean(opt === d));
36680 if (d !== 'wireframe') {
36682 context.storage('area-fill', d);
36687 function showsLayer(which) {
36688 var layer = layers.layer(which);
36690 return layer.enabled();
36695 function setLayer(which, enabled) {
36696 var layer = layers.layer(which);
36698 layer.enabled(enabled);
36703 function toggleLayer(which) {
36704 setLayer(which, !showsLayer(which));
36707 function clickGpx() {
36708 toggleLayer('gpx');
36711 function clickMapillaryImages() {
36712 toggleLayer('mapillary-images');
36713 if (!showsLayer('mapillary-images')) {
36714 setLayer('mapillary-signs', false);
36718 function clickMapillarySigns() {
36719 toggleLayer('mapillary-signs');
36723 function drawMapillaryItems(selection) {
36724 var mapillaryImages = layers.layer('mapillary-images'),
36725 mapillarySigns = layers.layer('mapillary-signs'),
36726 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
36727 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
36728 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
36729 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
36731 var mapillaryList = selection
36732 .selectAll('.layer-list-mapillary')
36739 .attr('class', 'layer-list layer-list-mapillary');
36741 var mapillaryImageLayerItem = mapillaryList
36742 .selectAll('.list-item-mapillary-images')
36743 .data(supportsMapillaryImages ? [0] : []);
36745 var enterImages = mapillaryImageLayerItem.enter()
36747 .attr('class', 'list-item-mapillary-images');
36749 var labelImages = enterImages.append('label')
36750 .call(bootstrap.tooltip()
36751 .title(t('mapillary_images.tooltip'))
36752 .placement('top'));
36754 labelImages.append('input')
36755 .attr('type', 'checkbox')
36756 .on('change', clickMapillaryImages);
36758 labelImages.append('span')
36759 .text(t('mapillary_images.title'));
36762 var mapillarySignLayerItem = mapillaryList
36763 .selectAll('.list-item-mapillary-signs')
36764 .data(supportsMapillarySigns ? [0] : []);
36766 var enterSigns = mapillarySignLayerItem.enter()
36768 .attr('class', 'list-item-mapillary-signs');
36770 var labelSigns = enterSigns.append('label')
36771 .call(bootstrap.tooltip()
36772 .title(t('mapillary_signs.tooltip'))
36773 .placement('top'));
36775 labelSigns.append('input')
36776 .attr('type', 'checkbox')
36777 .on('change', clickMapillarySigns);
36779 labelSigns.append('span')
36780 .text(t('mapillary_signs.title'));
36783 mapillaryImageLayerItem
36784 .classed('active', showsMapillaryImages)
36785 .selectAll('input')
36786 .property('checked', showsMapillaryImages);
36788 mapillarySignLayerItem
36789 .classed('active', showsMapillarySigns)
36790 .selectAll('input')
36791 .property('disabled', !showsMapillaryImages)
36792 .property('checked', showsMapillarySigns);
36794 mapillarySignLayerItem
36795 .selectAll('label')
36796 .classed('deemphasize', !showsMapillaryImages);
36799 mapillaryImageLayerItem.exit()
36801 mapillarySignLayerItem.exit()
36806 function drawGpxItem(selection) {
36807 var gpx = layers.layer('gpx'),
36808 hasGpx = gpx && gpx.hasGpx(),
36809 showsGpx = hasGpx && gpx.enabled();
36811 var gpxLayerItem = selection
36812 .selectAll('.layer-list-gpx')
36813 .data(gpx ? [0] : []);
36816 var enter = gpxLayerItem.enter()
36818 .attr('class', 'layer-list layer-list-gpx')
36820 .classed('list-item-gpx', true);
36822 enter.append('button')
36823 .attr('class', 'list-item-gpx-extent')
36824 .call(bootstrap.tooltip()
36825 .title(t('gpx.zoom'))
36826 .placement('left'))
36827 .on('click', function() {
36828 d3.event.preventDefault();
36829 d3.event.stopPropagation();
36832 .call(iD.svg.Icon('#icon-search'));
36834 enter.append('button')
36835 .attr('class', 'list-item-gpx-browse')
36836 .call(bootstrap.tooltip()
36837 .title(t('gpx.browse'))
36838 .placement('left'))
36839 .on('click', function() {
36840 d3.select(document.createElement('input'))
36841 .attr('type', 'file')
36842 .on('change', function() {
36843 gpx.files(d3.event.target.files);
36847 .call(iD.svg.Icon('#icon-geolocate'));
36849 var labelGpx = enter.append('label')
36850 .call(bootstrap.tooltip()
36851 .title(t('gpx.drag_drop'))
36852 .placement('top'));
36854 labelGpx.append('input')
36855 .attr('type', 'checkbox')
36856 .on('change', clickGpx);
36858 labelGpx.append('span')
36859 .text(t('gpx.local_layer'));
36863 .classed('active', showsGpx)
36864 .selectAll('input')
36865 .property('disabled', !hasGpx)
36866 .property('checked', showsGpx);
36869 .selectAll('label')
36870 .classed('deemphasize', !hasGpx);
36873 gpxLayerItem.exit()
36878 function drawList(selection, data, type, name, change, active) {
36879 var items = selection.selectAll('li')
36883 var enter = items.enter()
36885 .attr('class', 'layer')
36886 .call(bootstrap.tooltip()
36888 .title(function(d) {
36889 var tip = t(name + '.' + d + '.tooltip'),
36890 key = (d === 'wireframe' ? 'W' : null);
36892 if (name === 'feature' && autoHiddenFeature(d)) {
36893 tip += '<div>' + t('map_data.autohidden') + '</div>';
36895 return iD.ui.tooltipHtml(tip, key);
36900 var label = enter.append('label');
36902 label.append('input')
36903 .attr('type', type)
36904 .attr('name', name)
36905 .on('change', change);
36907 label.append('span')
36908 .text(function(d) { return t(name + '.' + d + '.description'); });
36912 .classed('active', active)
36913 .selectAll('input')
36914 .property('checked', active)
36915 .property('indeterminate', function(d) {
36916 return (name === 'feature' && autoHiddenFeature(d));
36925 function update() {
36926 dataLayerContainer.call(drawMapillaryItems);
36927 dataLayerContainer.call(drawGpxItem);
36929 fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
36931 featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
36934 function hidePanel() {
36938 function togglePanel() {
36939 if (d3.event) d3.event.preventDefault();
36940 tooltip.hide(button);
36941 setVisible(!button.classed('active'));
36944 function toggleWireframe() {
36946 d3.event.preventDefault();
36947 d3.event.stopPropagation();
36949 setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
36950 context.map().pan([0,0]); // trigger a redraw
36953 function setVisible(show) {
36954 if (show !== shown) {
36955 button.classed('active', show);
36960 selection.on('mousedown.map_data-inside', function() {
36961 return d3.event.stopPropagation();
36963 content.style('display', 'block')
36964 .style('right', '-300px')
36967 .style('right', '0px');
36969 content.style('display', 'block')
36970 .style('right', '0px')
36973 .style('right', '-300px')
36974 .each('end', function() {
36975 d3.select(this).style('display', 'none');
36977 selection.on('mousedown.map_data-inside', null);
36983 var content = selection.append('div')
36984 .attr('class', 'fillL map-overlay col3 content hide'),
36985 tooltip = bootstrap.tooltip()
36988 .title(iD.ui.tooltipHtml(t('map_data.description'), key)),
36989 button = selection.append('button')
36990 .attr('tabindex', -1)
36991 .on('click', togglePanel)
36992 .call(iD.svg.Icon('#icon-data', 'light'))
36996 content.append('h4')
36997 .text(t('map_data.title'));
37001 content.append('a')
37002 .text(t('map_data.data_layers'))
37004 .classed('hide-toggle', true)
37005 .classed('expanded', true)
37006 .on('click', function() {
37007 var exp = d3.select(this).classed('expanded');
37008 dataLayerContainer.style('display', exp ? 'none' : 'block');
37009 d3.select(this).classed('expanded', !exp);
37010 d3.event.preventDefault();
37013 var dataLayerContainer = content.append('div')
37014 .attr('class', 'data-data-layers')
37015 .style('display', 'block');
37019 content.append('a')
37020 .text(t('map_data.fill_area'))
37022 .classed('hide-toggle', true)
37023 .classed('expanded', false)
37024 .on('click', function() {
37025 var exp = d3.select(this).classed('expanded');
37026 fillContainer.style('display', exp ? 'none' : 'block');
37027 d3.select(this).classed('expanded', !exp);
37028 d3.event.preventDefault();
37031 var fillContainer = content.append('div')
37032 .attr('class', 'data-area-fills')
37033 .style('display', 'none');
37035 var fillList = fillContainer.append('ul')
37036 .attr('class', 'layer-list layer-fill-list');
37040 content.append('a')
37041 .text(t('map_data.map_features'))
37043 .classed('hide-toggle', true)
37044 .classed('expanded', false)
37045 .on('click', function() {
37046 var exp = d3.select(this).classed('expanded');
37047 featureContainer.style('display', exp ? 'none' : 'block');
37048 d3.select(this).classed('expanded', !exp);
37049 d3.event.preventDefault();
37052 var featureContainer = content.append('div')
37053 .attr('class', 'data-feature-filters')
37054 .style('display', 'none');
37056 var featureList = featureContainer.append('ul')
37057 .attr('class', 'layer-list layer-feature-list');
37061 .on('change.map_data-update', update);
37063 setFill(fillDefault);
37065 var keybinding = d3.keybinding('features')
37066 .on(key, togglePanel)
37067 .on('W', toggleWireframe)
37068 .on('B', hidePanel)
37069 .on('H', hidePanel);
37071 d3.select(document)
37074 context.surface().on('mousedown.map_data-outside', hidePanel);
37075 context.container().on('mousedown.map_data-outside', hidePanel);
37080 iD.ui.MapInMap = function(context) {
37083 function map_in_map(selection) {
37084 var backgroundLayer = iD.TileLayer(context),
37085 overlayLayers = {},
37086 projection = iD.geo.RawMercator(),
37087 gpxLayer = iD.svg.Gpx(projection, context).showLabels(false),
37088 zoom = d3.behavior.zoom()
37089 .scaleExtent([ztok(0.5), ztok(24)])
37090 .on('zoom', zoomPan),
37091 transformed = false,
37094 zDiff = 6, // by default, minimap renders at (main zoom - 6)
37095 tStart, tLast, tCurr, kLast, kCurr, tiles, svg, timeoutId;
37097 function ztok(z) { return 256 * Math.pow(2, z); }
37098 function ktoz(k) { return Math.log(k) / Math.LN2 - 8; }
37101 function startMouse() {
37102 context.surface().on('mouseup.map-in-map-outside', endMouse);
37103 context.container().on('mouseup.map-in-map-outside', endMouse);
37105 tStart = tLast = tCurr = projection.translate();
37110 function zoomPan() {
37111 var e = d3.event.sourceEvent,
37112 t = d3.event.translate,
37113 k = d3.event.scale,
37114 zMain = ktoz(context.projection.scale() * 2 * Math.PI),
37117 // restrict minimap zoom to < (main zoom - 3)
37118 if (zMini > zMain - 3) {
37120 zoom.scale(kCurr).translate(tCurr); // restore last good values
37126 zDiff = zMain - zMini;
37128 var scale = kCurr / kLast,
37129 tX = (tCurr[0] / scale - tLast[0]) * scale,
37130 tY = (tCurr[1] / scale - tLast[1]) * scale;
37132 iD.util.setTransform(tiles, tX, tY, scale);
37133 iD.util.setTransform(svg, 0, 0, scale);
37134 transformed = true;
37138 e.preventDefault();
37139 e.stopPropagation();
37143 function endMouse() {
37144 context.surface().on('mouseup.map-in-map-outside', null);
37145 context.container().on('mouseup.map-in-map-outside', null);
37147 updateProjection();
37150 if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) {
37151 var dMini = wrap.dimensions(),
37152 cMini = [ dMini[0] / 2, dMini[1] / 2 ];
37154 context.map().center(projection.invert(cMini));
37159 function updateProjection() {
37160 var loc = context.map().center(),
37161 dMini = wrap.dimensions(),
37162 cMini = [ dMini[0] / 2, dMini[1] / 2 ],
37163 tMain = context.projection.translate(),
37164 kMain = context.projection.scale(),
37165 zMain = ktoz(kMain * 2 * Math.PI),
37166 zMini = Math.max(zMain - zDiff, 0.5),
37167 kMini = ztok(zMini);
37171 .scale(kMini / (2 * Math.PI));
37173 var s = projection(loc),
37174 mouse = panning ? [ tCurr[0] - tStart[0], tCurr[1] - tStart[1] ] : [0, 0],
37176 cMini[0] - s[0] + tMain[0] + mouse[0],
37177 cMini[1] - s[1] + tMain[1] + mouse[1]
37182 .clipExtent([[0, 0], dMini]);
37189 tLast = tCurr = tMini;
37190 kLast = kCurr = kMini;
37193 iD.util.setTransform(tiles, 0, 0);
37194 iD.util.setTransform(svg, 0, 0);
37195 transformed = false;
37200 function redraw() {
37201 if (hidden) return;
37203 updateProjection();
37205 var dMini = wrap.dimensions(),
37206 zMini = ktoz(projection.scale() * 2 * Math.PI);
37208 // setup tile container
37210 .selectAll('.map-in-map-tiles')
37216 .attr('class', 'map-in-map-tiles');
37218 // redraw background
37220 .source(context.background().baseLayerSource())
37221 .projection(projection)
37222 .dimensions(dMini);
37224 var background = tiles
37225 .selectAll('.map-in-map-background')
37230 .attr('class', 'map-in-map-background');
37233 .call(backgroundLayer);
37237 var overlaySources = context.background().overlayLayerSources();
37238 var activeOverlayLayers = [];
37239 for (var i = 0; i < overlaySources.length; i++) {
37240 if (overlaySources[i].validZoom(zMini)) {
37241 if (!overlayLayers[i]) overlayLayers[i] = iD.TileLayer(context);
37242 activeOverlayLayers.push(overlayLayers[i]
37243 .source(overlaySources[i])
37244 .projection(projection)
37245 .dimensions(dMini));
37249 var overlay = tiles
37250 .selectAll('.map-in-map-overlay')
37255 .attr('class', 'map-in-map-overlay');
37257 var overlays = overlay
37259 .data(activeOverlayLayers, function(d) { return d.source().name(); });
37261 overlays.enter().append('div');
37262 overlays.each(function(layer) {
37263 d3.select(this).call(layer);
37271 .selectAll('.map-in-map-gpx')
37272 .data(gpxLayer.enabled() ? [0] : []);
37276 .attr('class', 'map-in-map-gpx');
37281 gpx.call(gpxLayer);
37284 // redraw bounding box
37286 var getPath = d3.geo.path().projection(projection),
37287 bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
37289 svg = wrap.selectAll('.map-in-map-svg')
37294 .attr('class', 'map-in-map-svg');
37296 var path = svg.selectAll('.map-in-map-bbox')
37301 .attr('class', 'map-in-map-bbox');
37304 .attr('d', getPath)
37305 .classed('thick', function(d) { return getPath.area(d) < 30; });
37310 function queueRedraw() {
37311 clearTimeout(timeoutId);
37312 timeoutId = setTimeout(function() { redraw(); }, 300);
37316 function toggle() {
37317 if (d3.event) d3.event.preventDefault();
37321 var label = d3.select('.minimap-toggle');
37322 label.classed('active', !hidden)
37323 .select('input').property('checked', !hidden);
37327 .style('display', 'block')
37328 .style('opacity', 1)
37331 .style('opacity', 0)
37332 .each('end', function() {
37333 d3.select(this).style('display', 'none');
37337 .style('display', 'block')
37338 .style('opacity', 0)
37341 .style('opacity', 1);
37347 iD.ui.MapInMap.toggle = toggle;
37349 var wrap = selection.selectAll('.map-in-map')
37354 .attr('class', 'map-in-map')
37355 .style('display', (hidden ? 'none' : 'block'))
37356 .on('mousedown.map-in-map', startMouse)
37357 .on('mouseup.map-in-map', endMouse)
37359 .on('dblclick.zoom', null);
37362 .on('drawn.map-in-map', function(drawn) {
37363 if (drawn.full === true) redraw();
37368 var keybinding = d3.keybinding('map-in-map')
37371 d3.select(document)
37377 iD.ui.modal = function(selection, blocking) {
37378 var keybinding = d3.keybinding('modal');
37379 var previous = selection.select('div.modal');
37380 var animate = previous.empty();
37382 previous.transition()
37384 .style('opacity', 0)
37387 var shaded = selection
37389 .attr('class', 'shaded')
37390 .style('opacity', 0);
37392 shaded.close = function() {
37396 .style('opacity',0)
37401 .style('top','0px');
37407 var modal = shaded.append('div')
37408 .attr('class', 'modal fillL col6');
37411 shaded.on('click.remove-modal', function() {
37412 if (d3.event.target === this) {
37417 modal.append('button')
37418 .attr('class', 'close')
37419 .on('click', shaded.close)
37420 .call(iD.svg.Icon('#icon-close'));
37423 .on('⌫', shaded.close)
37424 .on('⎋', shaded.close);
37426 d3.select(document).call(keybinding);
37429 modal.append('div')
37430 .attr('class', 'content');
37433 shaded.transition().style('opacity', 1);
37435 shaded.style('opacity', 1);
37440 iD.ui.Modes = function(context) {
37442 iD.modes.AddPoint(context),
37443 iD.modes.AddLine(context),
37444 iD.modes.AddArea(context)];
37446 function editable() {
37447 return context.editable() && context.mode().id !== 'save';
37450 return function(selection) {
37451 var buttons = selection.selectAll('button.add-button')
37454 buttons.enter().append('button')
37455 .attr('tabindex', -1)
37456 .attr('class', function(mode) { return mode.id + ' add-button col4'; })
37457 .on('click.mode-buttons', function(mode) {
37458 if (mode.id === context.mode().id) {
37459 context.enter(iD.modes.Browse(context));
37461 context.enter(mode);
37464 .call(bootstrap.tooltip()
37465 .placement('bottom')
37467 .title(function(mode) {
37468 return iD.ui.tooltipHtml(mode.description, mode.key);
37472 .on('move.modes', _.debounce(update, 500));
37475 .on('enter.modes', update);
37477 buttons.each(function(d) {
37479 .call(iD.svg.Icon('#icon-' + d.button, 'pre-text'));
37482 buttons.append('span')
37483 .attr('class', 'label')
37484 .text(function(mode) { return mode.title; });
37486 context.on('enter.editor', function(entered) {
37487 buttons.classed('active', function(mode) { return entered.button === mode.button; });
37488 context.container()
37489 .classed('mode-' + entered.id, true);
37492 context.on('exit.editor', function(exited) {
37493 context.container()
37494 .classed('mode-' + exited.id, false);
37497 var keybinding = d3.keybinding('mode-buttons');
37499 modes.forEach(function(m) {
37500 keybinding.on(m.key, function() { if (editable()) context.enter(m); });
37503 d3.select(document)
37506 function update() {
37507 buttons.property('disabled', !editable());
37511 iD.ui.Notice = function(context) {
37512 return function(selection) {
37513 var div = selection.append('div')
37514 .attr('class', 'notice');
37516 var button = div.append('button')
37517 .attr('class', 'zoom-to notice')
37518 .on('click', function() { context.map().zoom(context.minEditableZoom()); });
37521 .call(iD.svg.Icon('#icon-plus', 'pre-text'))
37523 .attr('class', 'label')
37524 .text(t('zoom_in_edit'));
37526 function disableTooHigh() {
37527 div.style('display', context.editable() ? 'none' : 'block');
37531 .on('move.notice', _.debounce(disableTooHigh, 500));
37536 iD.ui.PresetIcon = function() {
37537 var preset, geometry;
37539 function presetIcon(selection) {
37540 selection.each(render);
37543 function render() {
37544 var selection = d3.select(this),
37545 p = preset.apply(this, arguments),
37546 geom = geometry.apply(this, arguments),
37547 icon = p.icon || (geom === 'line' ? 'other-line' : 'marker-stroked'),
37548 maki = iD.data.featureIcons.hasOwnProperty(icon + '-24');
37550 if (icon === 'dentist') maki = true; // workaround for dentist icon missing in `maki-sprite.json`
37552 function tag_classes(p) {
37554 for (var i in p.tags) {
37556 if (p.tags[i] !== '*') {
37557 s += ' tag-' + i + '-' + p.tags[i];
37563 var $fill = selection.selectAll('.preset-icon-fill')
37566 $fill.enter().append('div');
37568 $fill.attr('class', function() {
37569 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
37572 var $frame = selection.selectAll('.preset-icon-frame')
37577 .call(iD.svg.Icon('#preset-icon-frame'));
37579 $frame.attr('class', function() {
37580 return 'preset-icon-frame ' + (geom === 'area' ? '' : 'hide');
37584 var $icon = selection.selectAll('.preset-icon')
37589 .attr('class', 'preset-icon')
37590 .call(iD.svg.Icon(''));
37593 .attr('class', 'preset-icon preset-icon-' + (maki ? '32' : (geom === 'area' ? '44' : '60')));
37595 $icon.selectAll('svg')
37596 .attr('class', function() {
37597 return 'icon ' + icon + tag_classes(p);
37600 $icon.selectAll('use') // workaround: maki parking-24 broken?
37601 .attr('href', '#' + icon + (maki ? ( icon === 'parking' ? '-18' : '-24') : ''));
37604 presetIcon.preset = function(_) {
37605 if (!arguments.length) return preset;
37606 preset = d3.functor(_);
37610 presetIcon.geometry = function(_) {
37611 if (!arguments.length) return geometry;
37612 geometry = d3.functor(_);
37618 iD.ui.preset = function(context) {
37619 var event = d3.dispatch('change'),
37626 function UIField(field, entity, show) {
37627 field = _.clone(field);
37629 field.input = iD.ui.preset[field.type](field, context)
37630 .on('change', event.change);
37632 if (field.input.entity) field.input.entity(entity);
37634 field.keys = field.keys || [field.key];
37638 field.shown = function() {
37639 return field.id === 'name' || field.show || _.some(field.keys, function(key) { return !!tags[key]; });
37642 field.modified = function() {
37643 var original = context.graph().base().entities[entity.id];
37644 return _.some(field.keys, function(key) {
37645 return original ? tags[key] !== original.tags[key] : tags[key];
37649 field.revert = function() {
37650 var original = context.graph().base().entities[entity.id],
37652 field.keys.forEach(function(key) {
37653 t[key] = original ? original.tags[key] : undefined;
37658 field.present = function() {
37659 return _.some(field.keys, function(key) {
37664 field.remove = function() {
37666 field.keys.forEach(function(key) {
37667 t[key] = undefined;
37675 function fieldKey(field) {
37679 function presets(selection) {
37680 selection.call(iD.ui.Disclosure()
37681 .title(t('inspector.all_fields'))
37682 .expanded(context.storage('preset_fields.expanded') !== 'false')
37683 .on('toggled', toggled)
37684 .content(content));
37686 function toggled(expanded) {
37687 context.storage('preset_fields.expanded', expanded);
37691 function content(selection) {
37693 var entity = context.entity(id),
37694 geometry = context.geometry(id);
37696 fields = [UIField(context.presets().field('name'), entity)];
37698 preset.fields.forEach(function(field) {
37699 if (field.matchGeometry(geometry)) {
37700 fields.push(UIField(field, entity, true));
37704 if (entity.isHighwayIntersection(context.graph())) {
37705 fields.push(UIField(context.presets().field('restrictions'), entity, true));
37708 context.presets().universal().forEach(function(field) {
37709 if (preset.fields.indexOf(field) < 0) {
37710 fields.push(UIField(field, entity));
37715 var shown = fields.filter(function(field) { return field.shown(); }),
37716 notShown = fields.filter(function(field) { return !field.shown(); });
37718 var $form = selection.selectAll('.preset-form')
37721 $form.enter().append('div')
37722 .attr('class', 'preset-form inspector-inner fillL3');
37724 var $fields = $form.selectAll('.form-field')
37725 .data(shown, fieldKey);
37729 var $enter = $fields.enter()
37731 .attr('class', function(field) {
37732 return 'form-field form-field-' + field.id;
37735 var $label = $enter.append('label')
37736 .attr('class', 'form-label')
37737 .attr('for', function(field) { return 'preset-input-' + field.id; })
37738 .text(function(field) { return field.label(); });
37740 var wrap = $label.append('div')
37741 .attr('class', 'form-label-button-wrap');
37743 wrap.append('button')
37744 .attr('class', 'remove-icon')
37745 .attr('tabindex', -1)
37746 .call(iD.svg.Icon('#operation-delete'));
37748 wrap.append('button')
37749 .attr('class', 'modified-icon')
37750 .attr('tabindex', -1)
37751 .call(iD.svg.Icon('#icon-undo'));
37755 $fields.select('.form-label-button-wrap .remove-icon')
37756 .on('click', remove);
37758 $fields.select('.modified-icon')
37759 .on('click', revert);
37763 .classed('modified', function(field) {
37764 return field.modified();
37766 .classed('present', function(field) {
37767 return field.present();
37769 .each(function(field) {
37770 var reference = iD.ui.TagReference(field.reference || {key: field.key}, context);
37772 if (state === 'hover') {
37773 reference.showing(false);
37778 .selectAll('input')
37779 .on('keydown', function() {
37780 // if user presses enter, and combobox is not active, accept edits..
37781 if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) {
37782 context.enter(iD.modes.Browse(context));
37785 .call(reference.body)
37786 .select('.form-label-button-wrap')
37787 .call(reference.button);
37789 field.input.tags(tags);
37795 notShown = notShown.map(function(field) {
37797 title: field.label(),
37798 value: field.label(),
37803 var $more = selection.selectAll('.more-fields')
37804 .data((notShown.length > 0) ? [0] : []);
37806 $more.enter().append('div')
37807 .attr('class', 'more-fields')
37809 .text(t('inspector.add_fields'));
37811 var $input = $more.selectAll('.value')
37814 $input.enter().append('input')
37815 .attr('class', 'value')
37816 .attr('type', 'text');
37819 .attr('placeholder', function() {
37820 var placeholder = [];
37821 for (var field in notShown) {
37822 placeholder.push(notShown[field].title);
37824 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
37826 .call(d3.combobox().data(notShown)
37828 .on('accept', show));
37836 function show(field) {
37837 field = field.field;
37839 content(selection);
37840 field.input.focus();
37843 function revert(field) {
37844 d3.event.stopPropagation();
37845 d3.event.preventDefault();
37846 event.change(field.revert());
37849 function remove(field) {
37850 d3.event.stopPropagation();
37851 d3.event.preventDefault();
37852 event.change(field.remove());
37856 presets.preset = function(_) {
37857 if (!arguments.length) return preset;
37858 if (preset && preset.id === _.id) return presets;
37864 presets.state = function(_) {
37865 if (!arguments.length) return state;
37870 presets.tags = function(_) {
37871 if (!arguments.length) return tags;
37873 // Don't reset fields here.
37877 presets.entityID = function(_) {
37878 if (!arguments.length) return id;
37879 if (id === _) return presets;
37885 return d3.rebind(presets, event, 'on');
37887 iD.ui.PresetList = function(context) {
37888 var event = d3.dispatch('choose'),
37893 function presetList(selection) {
37894 var geometry = context.geometry(id),
37895 presets = context.presets().matchGeometry(geometry);
37897 selection.html('');
37899 var messagewrap = selection.append('div')
37900 .attr('class', 'header fillL cf');
37902 var message = messagewrap.append('h3')
37903 .text(t('inspector.choose'));
37905 if (context.entity(id).isUsed(context.graph())) {
37906 messagewrap.append('button')
37907 .attr('class', 'preset-choose')
37908 .on('click', function() { event.choose(currentPreset); })
37912 messagewrap.append('button')
37913 .attr('class', 'close')
37914 .on('click', function() {
37915 context.enter(iD.modes.Browse(context));
37917 .call(iD.svg.Icon('#icon-close'));
37920 function keydown() {
37921 // hack to let delete shortcut work when search is autofocused
37922 if (search.property('value').length === 0 &&
37923 (d3.event.keyCode === d3.keybinding.keyCodes['⌫'] ||
37924 d3.event.keyCode === d3.keybinding.keyCodes['⌦'])) {
37925 d3.event.preventDefault();
37926 d3.event.stopPropagation();
37927 iD.operations.Delete([id], context)();
37928 } else if (search.property('value').length === 0 &&
37929 (d3.event.ctrlKey || d3.event.metaKey) &&
37930 d3.event.keyCode === d3.keybinding.keyCodes.z) {
37931 d3.event.preventDefault();
37932 d3.event.stopPropagation();
37934 } else if (!d3.event.ctrlKey && !d3.event.metaKey) {
37935 d3.select(this).on('keydown', null);
37939 function keypress() {
37941 var value = search.property('value');
37942 if (d3.event.keyCode === 13 && value.length) {
37943 list.selectAll('.preset-list-item:first-child').datum().choose();
37947 function inputevent() {
37948 var value = search.property('value');
37949 list.classed('filtered', value.length);
37950 if (value.length) {
37951 var results = presets.search(value, geometry);
37952 message.text(t('inspector.results', {
37953 n: results.collection.length,
37956 list.call(drawList, results);
37958 list.call(drawList, context.presets().defaults(geometry, 36));
37959 message.text(t('inspector.choose'));
37963 var searchWrap = selection.append('div')
37964 .attr('class', 'search-header');
37966 var search = searchWrap.append('input')
37967 .attr('class', 'preset-search-input')
37968 .attr('placeholder', t('inspector.search'))
37969 .attr('type', 'search')
37970 .on('keydown', keydown)
37971 .on('keypress', keypress)
37972 .on('input', inputevent);
37975 .call(iD.svg.Icon('#icon-search', 'pre-text'));
37978 search.node().focus();
37981 var listWrap = selection.append('div')
37982 .attr('class', 'inspector-body');
37984 var list = listWrap.append('div')
37985 .attr('class', 'preset-list fillL cf')
37986 .call(drawList, context.presets().defaults(geometry, 36));
37989 function drawList(list, presets) {
37990 var collection = presets.collection.map(function(preset) {
37991 return preset.members ? CategoryItem(preset) : PresetItem(preset);
37994 var items = list.selectAll('.preset-list-item')
37995 .data(collection, function(d) { return d.preset.id; });
37997 items.enter().append('div')
37998 .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
37999 .classed('current', function(item) { return item.preset === currentPreset; })
38000 .each(function(item) {
38001 d3.select(this).call(item);
38003 .style('opacity', 0)
38005 .style('opacity', 1);
38013 function CategoryItem(preset) {
38014 var box, sublist, shown = false;
38016 function item(selection) {
38017 var wrap = selection.append('div')
38018 .attr('class', 'preset-list-button-wrap category col12');
38020 wrap.append('button')
38021 .attr('class', 'preset-list-button')
38022 .classed('expanded', false)
38023 .call(iD.ui.PresetIcon()
38024 .geometry(context.geometry(id))
38026 .on('click', function() {
38027 var isExpanded = d3.select(this).classed('expanded');
38028 var triangle = isExpanded ? '▶ ' : '▼ ';
38029 d3.select(this).classed('expanded', !isExpanded);
38030 d3.select(this).selectAll('.label').text(triangle + preset.name());
38034 .attr('class', 'label')
38036 return '▶ ' + preset.name();
38039 box = selection.append('div')
38040 .attr('class', 'subgrid col12')
38041 .style('max-height', '0px')
38042 .style('opacity', 0);
38045 .attr('class', 'arrow');
38047 sublist = box.append('div')
38048 .attr('class', 'preset-list fillL3 cf fl');
38051 item.choose = function() {
38052 if (!box || !sublist) return;
38058 .style('opacity', '0')
38059 .style('max-height', '0px')
38060 .style('padding-bottom', '0px');
38063 sublist.call(drawList, preset.members);
38066 .style('opacity', '1')
38067 .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
38068 .style('padding-bottom', '20px');
38072 item.preset = preset;
38077 function PresetItem(preset) {
38078 function item(selection) {
38079 var wrap = selection.append('div')
38080 .attr('class', 'preset-list-button-wrap col12');
38082 wrap.append('button')
38083 .attr('class', 'preset-list-button')
38084 .call(iD.ui.PresetIcon()
38085 .geometry(context.geometry(id))
38087 .on('click', item.choose)
38089 .attr('class', 'label')
38090 .text(preset.name());
38092 wrap.call(item.reference.button);
38093 selection.call(item.reference.body);
38096 item.choose = function() {
38097 context.presets().choose(preset);
38100 iD.actions.ChangePreset(id, currentPreset, preset),
38101 t('operations.change_tags.annotation'));
38103 event.choose(preset);
38106 item.help = function() {
38107 d3.event.stopPropagation();
38108 item.reference.toggle();
38111 item.preset = preset;
38112 item.reference = iD.ui.TagReference(preset.reference(context.geometry(id)), context);
38117 presetList.autofocus = function(_) {
38118 if (!arguments.length) return autofocus;
38123 presetList.entityID = function(_) {
38124 if (!arguments.length) return id;
38126 presetList.preset(context.presets().match(context.entity(id), context.graph()));
38130 presetList.preset = function(_) {
38131 if (!arguments.length) return currentPreset;
38136 return d3.rebind(presetList, event, 'on');
38138 iD.ui.RadialMenu = function(context, operations) {
38143 var radialMenu = function(selection) {
38144 if (!operations.length)
38147 selection.node().parentNode.focus();
38149 function click(operation) {
38150 d3.event.stopPropagation();
38151 if (operation.disabled())
38154 radialMenu.close();
38157 menu = selection.append('g')
38158 .attr('class', 'radial-menu')
38159 .attr('transform', 'translate(' + center + ')')
38160 .attr('opacity', 0);
38163 .attr('opacity', 1);
38168 a1 = a0 + (operations.length - 1) * a;
38170 menu.append('path')
38171 .attr('class', 'radial-menu-background')
38172 .attr('d', 'M' + r * Math.sin(a0) + ',' +
38174 ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
38175 (r * Math.sin(a1) + 1e-3) + ',' +
38176 (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
38177 .attr('stroke-width', 50)
38178 .attr('stroke-linecap', 'round');
38180 var button = menu.selectAll()
38184 .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
38185 .classed('disabled', function(d) { return d.disabled(); })
38186 .attr('transform', function(d, i) {
38187 return 'translate(' + iD.geo.roundCoords([
38188 r * Math.sin(a0 + i * a),
38189 r * Math.cos(a0 + i * a)]).join(',') + ')';
38192 button.append('circle')
38194 .on('click', click)
38195 .on('mousedown', mousedown)
38196 .on('mouseover', mouseover)
38197 .on('mouseout', mouseout);
38199 button.append('use')
38200 .attr('transform', 'translate(-10,-10)')
38201 .attr('width', '20')
38202 .attr('height', '20')
38203 .attr('xlink:href', function(d) { return '#operation-' + d.id; });
38205 tooltip = d3.select(document.body)
38207 .attr('class', 'tooltip-inner radial-menu-tooltip');
38209 function mousedown() {
38210 d3.event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
38213 function mouseover(d, i) {
38214 var rect = context.surfaceRect(),
38215 angle = a0 + i * a,
38216 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
38217 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
38218 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
38219 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
38222 .style('top', null)
38223 .style('left', null)
38224 .style('bottom', null)
38225 .style('right', null)
38226 .style('display', 'block')
38227 .html(iD.ui.tooltipHtml(d.tooltip(), d.keys[0]));
38231 .style('right', right)
38232 .style('top', top);
38233 } else if (i >= 4) {
38235 .style('left', left)
38236 .style('bottom', bottom);
38239 .style('left', left)
38240 .style('top', top);
38244 function mouseout() {
38245 tooltip.style('display', 'none');
38249 radialMenu.close = function() {
38252 .style('pointer-events', 'none')
38254 .attr('opacity', 0)
38263 radialMenu.center = function(_) {
38264 if (!arguments.length) return center;
38271 iD.ui.RawMemberEditor = function(context) {
38274 function selectMember(d) {
38275 d3.event.preventDefault();
38276 context.enter(iD.modes.Select(context, [d.id]));
38279 function changeRole(d) {
38280 var role = d3.select(this).property('value');
38281 var member = {id: d.id, type: d.type, role: role};
38283 iD.actions.ChangeMember(d.relation.id, member, d.index),
38284 t('operations.change_role.annotation'));
38287 function deleteMember(d) {
38289 iD.actions.DeleteMember(d.relation.id, d.index),
38290 t('operations.delete_member.annotation'));
38292 if (!context.hasEntity(d.relation.id)) {
38293 context.enter(iD.modes.Browse(context));
38297 function rawMemberEditor(selection) {
38298 var entity = context.entity(id),
38301 entity.members.forEach(function(member, index) {
38308 member: context.hasEntity(member.id)
38312 selection.call(iD.ui.Disclosure()
38313 .title(t('inspector.all_members') + ' (' + memberships.length + ')')
38315 .on('toggled', toggled)
38316 .content(content));
38318 function toggled(expanded) {
38320 selection.node().parentNode.scrollTop += 200;
38324 function content($wrap) {
38325 var $list = $wrap.selectAll('.member-list')
38328 $list.enter().append('ul')
38329 .attr('class', 'member-list');
38331 var $items = $list.selectAll('li')
38332 .data(memberships, function(d) {
38333 return iD.Entity.key(d.relation) + ',' + d.index + ',' +
38334 (d.member ? iD.Entity.key(d.member) : 'incomplete');
38337 var $enter = $items.enter().append('li')
38338 .attr('class', 'member-row form-field')
38339 .classed('member-incomplete', function(d) { return !d.member; });
38341 $enter.each(function(d) {
38343 var $label = d3.select(this).append('label')
38344 .attr('class', 'form-label')
38347 .on('click', selectMember);
38349 $label.append('span')
38350 .attr('class', 'member-entity-type')
38351 .text(function(d) { return context.presets().match(d.member, context.graph()).name(); });
38353 $label.append('span')
38354 .attr('class', 'member-entity-name')
38355 .text(function(d) { return iD.util.displayName(d.member); });
38358 d3.select(this).append('label')
38359 .attr('class', 'form-label')
38360 .text(t('inspector.incomplete'));
38364 $enter.append('input')
38365 .attr('class', 'member-role')
38366 .property('type', 'text')
38367 .attr('maxlength', 255)
38368 .attr('placeholder', t('inspector.role'))
38369 .property('value', function(d) { return d.role; })
38370 .on('change', changeRole);
38372 $enter.append('button')
38373 .attr('tabindex', -1)
38374 .attr('class', 'remove button-input-action member-delete minor')
38375 .on('click', deleteMember)
38376 .call(iD.svg.Icon('#operation-delete'));
38383 rawMemberEditor.entityID = function(_) {
38384 if (!arguments.length) return id;
38386 return rawMemberEditor;
38389 return rawMemberEditor;
38391 iD.ui.RawMembershipEditor = function(context) {
38394 function selectRelation(d) {
38395 d3.event.preventDefault();
38396 context.enter(iD.modes.Select(context, [d.relation.id]));
38399 function changeRole(d) {
38400 var role = d3.select(this).property('value');
38402 iD.actions.ChangeMember(d.relation.id, _.extend({}, d.member, {role: role}), d.index),
38403 t('operations.change_role.annotation'));
38406 function addMembership(d, role) {
38411 iD.actions.AddMember(d.relation.id, {id: id, type: context.entity(id).type, role: role}),
38412 t('operations.add_member.annotation'));
38415 var relation = iD.Relation();
38418 iD.actions.AddEntity(relation),
38419 iD.actions.AddMember(relation.id, {id: id, type: context.entity(id).type, role: role}),
38420 t('operations.add.annotation.relation'));
38422 context.enter(iD.modes.Select(context, [relation.id]));
38426 function deleteMembership(d) {
38428 iD.actions.DeleteMember(d.relation.id, d.index),
38429 t('operations.delete_member.annotation'));
38432 function relations(q) {
38433 var newRelation = {
38435 value: t('inspector.new_relation')
38438 graph = context.graph();
38440 context.intersects(context.extent()).forEach(function(entity) {
38441 if (entity.type !== 'relation' || entity.id === id)
38444 var presetName = context.presets().match(entity, graph).name(),
38445 entityName = iD.util.displayName(entity) || '';
38447 var value = presetName + ' ' + entityName;
38448 if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
38457 result.sort(function(a, b) {
38458 return iD.Relation.creationOrder(a.relation, b.relation);
38461 // Dedupe identical names by appending relation id - see #2891
38462 var dupeGroups = _(result)
38464 .filter(function(v) { return v.length > 1; })
38467 dupeGroups.forEach(function(group) {
38468 group.forEach(function(obj) {
38469 obj.value += ' ' + obj.relation.id;
38473 result.unshift(newRelation);
38478 function rawMembershipEditor(selection) {
38479 var entity = context.entity(id),
38482 context.graph().parentRelations(entity).forEach(function(relation) {
38483 relation.members.forEach(function(member, index) {
38484 if (member.id === entity.id) {
38485 memberships.push({relation: relation, member: member, index: index});
38490 selection.call(iD.ui.Disclosure()
38491 .title(t('inspector.all_relations') + ' (' + memberships.length + ')')
38493 .on('toggled', toggled)
38494 .content(content));
38496 function toggled(expanded) {
38498 selection.node().parentNode.scrollTop += 200;
38502 function content($wrap) {
38503 var $list = $wrap.selectAll('.member-list')
38506 $list.enter().append('ul')
38507 .attr('class', 'member-list');
38509 var $items = $list.selectAll('li.member-row-normal')
38510 .data(memberships, function(d) { return iD.Entity.key(d.relation) + ',' + d.index; });
38512 var $enter = $items.enter().append('li')
38513 .attr('class', 'member-row member-row-normal form-field');
38515 var $label = $enter.append('label')
38516 .attr('class', 'form-label')
38519 .on('click', selectRelation);
38521 $label.append('span')
38522 .attr('class', 'member-entity-type')
38523 .text(function(d) { return context.presets().match(d.relation, context.graph()).name(); });
38525 $label.append('span')
38526 .attr('class', 'member-entity-name')
38527 .text(function(d) { return iD.util.displayName(d.relation); });
38529 $enter.append('input')
38530 .attr('class', 'member-role')
38531 .property('type', 'text')
38532 .attr('maxlength', 255)
38533 .attr('placeholder', t('inspector.role'))
38534 .property('value', function(d) { return d.member.role; })
38535 .on('change', changeRole);
38537 $enter.append('button')
38538 .attr('tabindex', -1)
38539 .attr('class', 'remove button-input-action member-delete minor')
38540 .on('click', deleteMembership)
38541 .call(iD.svg.Icon('#operation-delete'));
38547 var $new = $list.selectAll('.member-row-new')
38550 $enter = $new.enter().append('li')
38551 .attr('class', 'member-row member-row-new form-field');
38553 $enter.append('input')
38554 .attr('type', 'text')
38555 .attr('class', 'member-entity-input')
38556 .call(d3.combobox()
38558 .fetcher(function(value, callback) {
38559 callback(relations(value));
38561 .on('accept', function(d) {
38562 addMembership(d, $new.select('.member-role').property('value'));
38565 $enter.append('input')
38566 .attr('class', 'member-role')
38567 .property('type', 'text')
38568 .attr('maxlength', 255)
38569 .attr('placeholder', t('inspector.role'))
38570 .on('change', changeRole);
38572 $enter.append('button')
38573 .attr('tabindex', -1)
38574 .attr('class', 'remove button-input-action member-delete minor')
38575 .on('click', deleteMembership)
38576 .call(iD.svg.Icon('#operation-delete'));
38579 $list.selectAll('.member-row-new')
38583 var $add = $wrap.selectAll('.add-relation')
38588 .attr('class', 'add-relation')
38589 .call(iD.svg.Icon('#icon-plus', 'light'));
38591 $wrap.selectAll('.add-relation')
38592 .on('click', function() {
38595 $list.selectAll('.member-entity-input').node().focus();
38600 rawMembershipEditor.entityID = function(_) {
38601 if (!arguments.length) return id;
38603 return rawMembershipEditor;
38606 return rawMembershipEditor;
38608 iD.ui.RawTagEditor = function(context) {
38609 var event = d3.dispatch('change'),
38616 function rawTagEditor(selection) {
38617 var count = Object.keys(tags).filter(function(d) { return d; }).length;
38619 selection.call(iD.ui.Disclosure()
38620 .title(t('inspector.all_tags') + ' (' + count + ')')
38621 .expanded(context.storage('raw_tag_editor.expanded') === 'true' || preset.isFallback())
38622 .on('toggled', toggled)
38623 .content(content));
38625 function toggled(expanded) {
38626 context.storage('raw_tag_editor.expanded', expanded);
38628 selection.node().parentNode.scrollTop += 200;
38633 function content($wrap) {
38634 var entries = d3.entries(tags);
38636 if (!entries.length || showBlank) {
38638 entries.push({key: '', value: ''});
38641 var $list = $wrap.selectAll('.tag-list')
38644 $list.enter().append('ul')
38645 .attr('class', 'tag-list');
38647 var $newTag = $wrap.selectAll('.add-tag')
38652 .attr('class', 'add-tag')
38653 .call(iD.svg.Icon('#icon-plus', 'light'));
38655 $newTag.on('click', addTag);
38657 var $items = $list.selectAll('li')
38658 .data(entries, function(d) { return d.key; });
38662 var $enter = $items.enter().append('li')
38663 .attr('class', 'tag-row cf');
38665 $enter.append('div')
38666 .attr('class', 'key-wrap')
38668 .property('type', 'text')
38669 .attr('class', 'key')
38670 .attr('maxlength', 255);
38672 $enter.append('div')
38673 .attr('class', 'input-wrap-position')
38675 .property('type', 'text')
38676 .attr('class', 'value')
38677 .attr('maxlength', 255);
38679 $enter.append('button')
38680 .attr('tabindex', -1)
38681 .attr('class', 'remove minor')
38682 .call(iD.svg.Icon('#operation-delete'));
38684 if (context.taginfo()) {
38685 $enter.each(bindTypeahead);
38692 $items.each(function(tag) {
38693 var isRelation = (context.entity(id).type === 'relation'),
38695 if (isRelation && tag.key === 'type')
38696 reference = iD.ui.TagReference({rtype: tag.value}, context);
38698 reference = iD.ui.TagReference({key: tag.key, value: tag.value}, context);
38700 if (state === 'hover') {
38701 reference.showing(false);
38705 .call(reference.button)
38706 .call(reference.body);
38709 $items.select('input.key')
38710 .attr('title', function(d) { return d.key; })
38711 .value(function(d) { return d.key; })
38712 .on('blur', keyChange)
38713 .on('change', keyChange);
38715 $items.select('input.value')
38716 .attr('title', function(d) { return d.value; })
38717 .value(function(d) { return d.value; })
38718 .on('blur', valueChange)
38719 .on('change', valueChange)
38720 .on('keydown.push-more', pushMore);
38722 $items.select('button.remove')
38723 .on('click', removeTag);
38729 function pushMore() {
38730 if (d3.event.keyCode === 9 && !d3.event.shiftKey &&
38731 $list.selectAll('li:last-child input.value').node() === this) {
38736 function bindTypeahead() {
38737 var row = d3.select(this),
38738 key = row.selectAll('input.key'),
38739 value = row.selectAll('input.value');
38741 function sort(value, data) {
38742 var sameletter = [],
38744 for (var i = 0; i < data.length; i++) {
38745 if (data[i].value.substring(0, value.length) === value) {
38746 sameletter.push(data[i]);
38748 other.push(data[i]);
38751 return sameletter.concat(other);
38754 key.call(d3.combobox()
38755 .fetcher(function(value, callback) {
38756 context.taginfo().keys({
38758 geometry: context.geometry(id),
38760 }, function(err, data) {
38761 if (!err) callback(sort(value, data));
38765 value.call(d3.combobox()
38766 .fetcher(function(value, callback) {
38767 context.taginfo().values({
38770 geometry: context.geometry(id),
38772 }, function(err, data) {
38773 if (!err) callback(sort(value, data));
38778 function unbind() {
38779 var row = d3.select(this);
38781 row.selectAll('input.key')
38782 .call(d3.combobox.off);
38784 row.selectAll('input.value')
38785 .call(d3.combobox.off);
38788 function keyChange(d) {
38790 kNew = this.value.trim(),
38793 if (kNew && kNew !== kOld) {
38794 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
38796 suffix = +(match[2] || 1);
38797 while (tags[kNew]) { // rename key if already in use
38798 kNew = base + '_' + suffix++;
38801 tag[kOld] = undefined;
38802 tag[kNew] = d.value;
38803 d.key = kNew; // Maintain DOM identity through the subsequent update.
38808 function valueChange(d) {
38810 tag[d.key] = this.value;
38814 function removeTag(d) {
38816 tag[d.key] = undefined;
38818 d3.select(this.parentNode).remove();
38821 function addTag() {
38822 // Wrapped in a setTimeout in case it's being called from a blur
38823 // handler. Without the setTimeout, the call to `content` would
38824 // wipe out the pending value change.
38825 setTimeout(function() {
38828 $list.selectAll('li:last-child input.key').node().focus();
38833 rawTagEditor.state = function(_) {
38834 if (!arguments.length) return state;
38836 return rawTagEditor;
38839 rawTagEditor.preset = function(_) {
38840 if (!arguments.length) return preset;
38842 return rawTagEditor;
38845 rawTagEditor.tags = function(_) {
38846 if (!arguments.length) return tags;
38848 return rawTagEditor;
38851 rawTagEditor.entityID = function(_) {
38852 if (!arguments.length) return id;
38854 return rawTagEditor;
38857 return d3.rebind(rawTagEditor, event, 'on');
38859 iD.ui.Restore = function(context) {
38860 return function(selection) {
38861 if (!context.history().lock() || !context.history().restorableChanges())
38864 var modal = iD.ui.modal(selection, true);
38866 modal.select('.modal')
38867 .attr('class', 'modal fillL col6');
38869 var introModal = modal.select('.content');
38871 introModal.attr('class','cf');
38873 introModal.append('div')
38874 .attr('class', 'modal-section')
38876 .text(t('restore.heading'));
38878 introModal.append('div')
38879 .attr('class','modal-section')
38881 .text(t('restore.description'));
38883 var buttonWrap = introModal.append('div')
38884 .attr('class', 'modal-actions cf');
38886 var restore = buttonWrap.append('button')
38887 .attr('class', 'restore col6')
38888 .text(t('restore.restore'))
38889 .on('click', function() {
38890 context.history().restore();
38894 buttonWrap.append('button')
38895 .attr('class', 'reset col6')
38896 .text(t('restore.reset'))
38897 .on('click', function() {
38898 context.history().clearSaved();
38902 restore.node().focus();
38905 iD.ui.Save = function(context) {
38906 var history = context.history(),
38907 key = iD.ui.cmd('⌘S');
38910 function saving() {
38911 return context.mode().id === 'save';
38915 d3.event.preventDefault();
38916 if (!context.inIntro() && !saving() && history.hasChanges()) {
38917 context.enter(iD.modes.Save(context));
38921 function getBackground(numChanges) {
38923 if (numChanges === 0) {
38925 } else if (numChanges <= 50) {
38926 step = numChanges / 50;
38927 return d3.interpolateRgb('#fff', '#ff8')(step); // white -> yellow
38929 step = Math.min((numChanges - 50) / 50, 1.0);
38930 return d3.interpolateRgb('#ff8', '#f88')(step); // yellow -> red
38934 return function(selection) {
38935 var tooltip = bootstrap.tooltip()
38936 .placement('bottom')
38938 .title(iD.ui.tooltipHtml(t('save.no_changes'), key));
38940 var button = selection.append('button')
38941 .attr('class', 'save col12 disabled')
38942 .attr('tabindex', -1)
38946 button.append('span')
38947 .attr('class', 'label')
38948 .text(t('save.title'));
38950 button.append('span')
38951 .attr('class', 'count')
38954 var keybinding = d3.keybinding('undo-redo')
38955 .on(key, save, true);
38957 d3.select(document)
38960 var numChanges = 0;
38962 context.history().on('change.save', function() {
38963 var _ = history.difference().summary().length;
38964 if (_ === numChanges)
38968 tooltip.title(iD.ui.tooltipHtml(t(numChanges > 0 ?
38969 'save.help' : 'save.no_changes'), key));
38971 var background = getBackground(numChanges);
38974 .classed('disabled', numChanges === 0)
38975 .classed('has-count', numChanges > 0)
38976 .style('background', background);
38978 button.select('span.count')
38980 .style('background', background)
38981 .style('border-color', background);
38984 context.on('enter.save', function() {
38985 button.property('disabled', saving());
38986 if (saving()) button.call(tooltip.hide);
38990 iD.ui.Scale = function(context) {
38991 var projection = context.projection,
38992 imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
38996 function scaleDefs(loc1, loc2) {
38997 var lat = (loc2[1] + loc1[1]) / 2,
38998 conversion = (imperial ? 3.28084 : 1),
38999 dist = iD.geo.lonToMeters(loc2[0] - loc1[0], lat) * conversion,
39000 scale = { dist: 0, px: 0, text: '' },
39001 buckets, i, val, dLon;
39004 buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
39006 buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
39009 // determine a user-friendly endpoint for the scale
39010 for (i = 0; i < buckets.length; i++) {
39013 scale.dist = Math.floor(dist / val) * val;
39018 dLon = iD.geo.metersToLon(scale.dist / conversion, lat);
39019 scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
39022 if (scale.dist >= 5280) {
39023 scale.dist /= 5280;
39024 scale.text = String(scale.dist) + ' mi';
39026 scale.text = String(scale.dist) + ' ft';
39029 if (scale.dist >= 1000) {
39030 scale.dist /= 1000;
39031 scale.text = String(scale.dist) + ' km';
39033 scale.text = String(scale.dist) + ' m';
39040 function update(selection) {
39041 // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
39042 var dims = context.map().dimensions(),
39043 loc1 = projection.invert([0, dims[1]]),
39044 loc2 = projection.invert([maxLength, dims[1]]),
39045 scale = scaleDefs(loc1, loc2);
39047 selection.select('#scalepath')
39048 .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
39050 selection.select('#scaletext')
39051 .attr('x', scale.px + 8)
39052 .attr('y', tickHeight)
39057 return function(selection) {
39058 function switchUnits() {
39059 imperial = !imperial;
39060 selection.call(update);
39063 var g = selection.append('svg')
39064 .attr('id', 'scale')
39065 .on('click', switchUnits)
39067 .attr('transform', 'translate(10,11)');
39069 g.append('path').attr('id', 'scalepath');
39070 g.append('text').attr('id', 'scaletext');
39072 selection.call(update);
39074 context.map().on('move.scale', function() {
39079 iD.ui.SelectionList = function(context, selectedIDs) {
39081 function selectEntity(entity) {
39082 context.enter(iD.modes.Select(context, [entity.id]).suppressMenu(true));
39086 function selectionList(selection) {
39087 selection.classed('selection-list-pane', true);
39089 var header = selection.append('div')
39090 .attr('class', 'header fillL cf');
39092 header.append('h3')
39093 .text(t('inspector.multiselect'));
39095 var listWrap = selection.append('div')
39096 .attr('class', 'inspector-body');
39098 var list = listWrap.append('div')
39099 .attr('class', 'feature-list cf');
39101 context.history().on('change.selection-list', drawList);
39104 function drawList() {
39105 var entities = selectedIDs
39106 .map(function(id) { return context.hasEntity(id); })
39107 .filter(function(entity) { return entity; });
39109 var items = list.selectAll('.feature-list-item')
39110 .data(entities, iD.Entity.key);
39112 var enter = items.enter().append('button')
39113 .attr('class', 'feature-list-item')
39114 .on('click', selectEntity);
39117 var label = enter.append('div')
39118 .attr('class', 'label')
39119 .call(iD.svg.Icon('', 'pre-text'));
39121 label.append('span')
39122 .attr('class', 'entity-type');
39124 label.append('span')
39125 .attr('class', 'entity-name');
39128 items.selectAll('use')
39129 .attr('href', function() {
39130 var entity = this.parentNode.parentNode.__data__;
39131 return '#icon-' + context.geometry(entity.id);
39134 items.selectAll('.entity-type')
39135 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
39137 items.selectAll('.entity-name')
39138 .text(function(entity) { return iD.util.displayName(entity); });
39146 return selectionList;
39149 iD.ui.Sidebar = function(context) {
39150 var inspector = iD.ui.Inspector(context),
39153 function sidebar(selection) {
39154 var featureListWrap = selection.append('div')
39155 .attr('class', 'feature-list-pane')
39156 .call(iD.ui.FeatureList(context));
39158 selection.call(iD.ui.Notice(context));
39160 var inspectorWrap = selection.append('div')
39161 .attr('class', 'inspector-hidden inspector-wrap fr');
39163 function hover(id) {
39164 if (!current && context.hasEntity(id)) {
39165 featureListWrap.classed('inspector-hidden', true);
39166 inspectorWrap.classed('inspector-hidden', false)
39167 .classed('inspector-hover', true);
39169 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
39174 inspectorWrap.call(inspector);
39176 } else if (!current) {
39177 featureListWrap.classed('inspector-hidden', false);
39178 inspectorWrap.classed('inspector-hidden', true);
39179 inspector.state('hide');
39183 sidebar.hover = _.throttle(hover, 200);
39185 sidebar.select = function(id, newFeature) {
39186 if (!current && id) {
39187 featureListWrap.classed('inspector-hidden', true);
39188 inspectorWrap.classed('inspector-hidden', false)
39189 .classed('inspector-hover', false);
39191 if (inspector.entityID() !== id || inspector.state() !== 'select') {
39195 .newFeature(newFeature);
39197 inspectorWrap.call(inspector);
39199 } else if (!current) {
39200 featureListWrap.classed('inspector-hidden', false);
39201 inspectorWrap.classed('inspector-hidden', true);
39202 inspector.state('hide');
39206 sidebar.show = function(component) {
39207 featureListWrap.classed('inspector-hidden', true);
39208 inspectorWrap.classed('inspector-hidden', true);
39209 if (current) current.remove();
39210 current = selection.append('div')
39211 .attr('class', 'sidebar-component')
39215 sidebar.hide = function() {
39216 featureListWrap.classed('inspector-hidden', false);
39217 inspectorWrap.classed('inspector-hidden', true);
39218 if (current) current.remove();
39223 sidebar.hover = function() {};
39224 sidebar.hover.cancel = function() {};
39225 sidebar.select = function() {};
39226 sidebar.show = function() {};
39227 sidebar.hide = function() {};
39231 iD.ui.SourceSwitch = function(context) {
39235 d3.event.preventDefault();
39237 if (context.history().hasChanges() &&
39238 !window.confirm(t('source_switch.lose_changes'))) return;
39240 var live = d3.select(this)
39243 context.connection()
39244 .switch(live ? keys[1] : keys[0]);
39246 context.enter(iD.modes.Browse(context));
39250 .text(live ? t('source_switch.dev') : t('source_switch.live'))
39251 .classed('live', !live);
39254 var sourceSwitch = function(selection) {
39255 selection.append('a')
39257 .text(t('source_switch.live'))
39258 .classed('live', true)
39259 .attr('tabindex', -1)
39260 .on('click', click);
39263 sourceSwitch.keys = function(_) {
39264 if (!arguments.length) return keys;
39266 return sourceSwitch;
39269 return sourceSwitch;
39271 iD.ui.Spinner = function(context) {
39272 var connection = context.connection();
39274 return function(selection) {
39275 var img = selection.append('img')
39276 .attr('src', context.imagePath('loader-black.gif'))
39277 .style('opacity', 0);
39279 connection.on('loading.spinner', function() {
39281 .style('opacity', 1);
39284 connection.on('loaded.spinner', function() {
39286 .style('opacity', 0);
39290 iD.ui.Splash = function(context) {
39291 return function(selection) {
39292 if (context.storage('sawSplash'))
39295 context.storage('sawSplash', true);
39297 var modal = iD.ui.modal(selection);
39299 modal.select('.modal')
39300 .attr('class', 'modal-splash modal col6');
39302 var introModal = modal.select('.content')
39304 .attr('class', 'fillL');
39306 introModal.append('div')
39307 .attr('class','modal-section cf')
39308 .append('h3').text(t('splash.welcome'));
39310 introModal.append('div')
39311 .attr('class','modal-section')
39313 .html(t('splash.text', {
39314 version: iD.version,
39315 website: '<a href="http://ideditor.com/">ideditor.com</a>',
39316 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
39319 var buttons = introModal.append('div').attr('class', 'modal-actions cf');
39321 buttons.append('button')
39322 .attr('class', 'col6 walkthrough')
39323 .text(t('splash.walkthrough'))
39324 .on('click', function() {
39325 d3.select(document.body).call(iD.ui.intro(context));
39329 buttons.append('button')
39330 .attr('class', 'col6 start')
39331 .text(t('splash.start'))
39332 .on('click', modal.close);
39334 modal.select('button.close').attr('class','hide');
39338 iD.ui.Status = function(context) {
39339 var connection = context.connection(),
39342 return function(selection) {
39344 function update() {
39346 connection.status(function(err, apiStatus) {
39348 selection.html('');
39350 if (err && errCount++ < 2) return;
39353 selection.text(t('status.error'));
39355 } else if (apiStatus === 'readonly') {
39356 selection.text(t('status.readonly'));
39358 } else if (apiStatus === 'offline') {
39359 selection.text(t('status.offline'));
39362 selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
39363 if (!err) errCount = 0;
39368 connection.on('auth', function() { update(selection); });
39369 window.setInterval(update, 90000);
39373 iD.ui.Success = function(context) {
39374 var dispatch = d3.dispatch('cancel'),
39377 function success(selection) {
39378 var message = (changeset.comment || t('success.edited_osm')).substring(0, 130) +
39379 ' ' + context.connection().changesetURL(changeset.id);
39381 var header = selection.append('div')
39382 .attr('class', 'header fillL');
39384 header.append('button')
39385 .attr('class', 'fr')
39386 .on('click', function() { dispatch.cancel(); })
39387 .call(iD.svg.Icon('#icon-close'));
39389 header.append('h3')
39390 .text(t('success.just_edited'));
39392 var body = selection.append('div')
39393 .attr('class', 'body save-success fillL');
39396 .html(t('success.help_html'));
39399 .attr('class', 'details')
39400 .attr('target', '_blank')
39401 .attr('tabindex', -1)
39402 .call(iD.svg.Icon('#icon-out-link', 'inline'))
39403 .attr('href', t('success.help_link_url'))
39405 .text(t('success.help_link_text'));
39407 var changesetURL = context.connection().changesetURL(changeset.id);
39410 .attr('class', 'button col12 osm')
39411 .attr('target', '_blank')
39412 .attr('href', changesetURL)
39413 .text(t('success.view_on_osm'));
39416 facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
39417 twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
39418 google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
39421 body.selectAll('.button.social')
39422 .data(d3.entries(sharing))
39425 .attr('class', 'button social col4')
39426 .attr('target', '_blank')
39427 .attr('href', function(d) { return d.value; })
39428 .call(bootstrap.tooltip()
39429 .title(function(d) { return t('success.' + d.key); })
39430 .placement('bottom'))
39431 .each(function(d) { d3.select(this).call(iD.svg.Icon('#logo-' + d.key, 'social')); });
39434 success.changeset = function(_) {
39435 if (!arguments.length) return changeset;
39440 return d3.rebind(success, dispatch, 'on');
39442 iD.ui.TagReference = function(tag, context) {
39443 var tagReference = {},
39449 function findLocal(data) {
39450 var locale = iD.detect().locale.toLowerCase(),
39453 localized = _.find(data, function(d) {
39454 return d.lang.toLowerCase() === locale;
39456 if (localized) return localized;
39458 // try the non-regional version of a language, like
39459 // 'en' if the language is 'en-US'
39460 if (locale.indexOf('-') !== -1) {
39461 var first = locale.split('-')[0];
39462 localized = _.find(data, function(d) {
39463 return d.lang.toLowerCase() === first;
39465 if (localized) return localized;
39468 // finally fall back to english
39469 return _.find(data, function(d) {
39470 return d.lang.toLowerCase() === 'en';
39474 function load(param) {
39475 button.classed('tag-reference-loading', true);
39477 context.taginfo().docs(param, function show(err, data) {
39479 if (!err && data) {
39480 docs = findLocal(data);
39485 if (!docs || !docs.description) {
39486 if (param.hasOwnProperty('value')) {
39487 load(_.omit(param, 'value')); // retry with key only
39489 body.append('p').text(t('inspector.no_documentation_key'));
39495 if (docs.image && docs.image.thumb_url_prefix) {
39498 .attr('class', 'wiki-image')
39499 .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
39500 .on('load', function() { done(); })
39501 .on('error', function() { d3.select(this).remove(); done(); });
39508 .text(docs.description);
39512 .attr('target', '_blank')
39513 .attr('tabindex', -1)
39514 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
39515 .call(iD.svg.Icon('#icon-out-link', 'inline'))
39517 .text(t('inspector.reference'));
39524 button.classed('tag-reference-loading', false);
39528 .style('max-height', '200px')
39529 .style('opacity', '1');
39534 function hide(selection) {
39535 selection = selection || body.transition().duration(200);
39538 .style('max-height', '0px')
39539 .style('opacity', '0');
39544 tagReference.button = function(selection) {
39545 button = selection.selectAll('.tag-reference-button')
39550 .attr('class', 'tag-reference-button')
39551 .attr('tabindex', -1)
39552 .call(iD.svg.Icon('#icon-inspect'));
39554 button.on('click', function () {
39555 d3.event.stopPropagation();
39556 d3.event.preventDefault();
39559 } else if (loaded) {
39562 if (context.taginfo()) {
39569 tagReference.body = function(selection) {
39570 body = selection.selectAll('.tag-reference-body')
39573 body.enter().append('div')
39574 .attr('class', 'tag-reference-body cf')
39575 .style('max-height', '0')
39576 .style('opacity', '0');
39578 if (showing === false) {
39583 tagReference.showing = function(_) {
39584 if (!arguments.length) return showing;
39586 return tagReference;
39589 return tagReference;
39591 // toggles the visibility of ui elements, using a combination of the
39592 // hide class, which sets display=none, and a d3 transition for opacity.
39593 // this will cause blinking when called repeatedly, so check that the
39594 // value actually changes between calls.
39595 iD.ui.Toggle = function(show, callback) {
39596 return function(selection) {
39598 .style('opacity', show ? 0 : 1)
39599 .classed('hide', false)
39601 .style('opacity', show ? 1 : 0)
39602 .each('end', function() {
39604 .classed('hide', !show)
39605 .style('opacity', null);
39606 if (callback) callback.apply(this);
39610 iD.ui.UndoRedo = function(context) {
39613 cmd: iD.ui.cmd('⌘Z'),
39614 action: function() { if (!(context.inIntro() || saving())) context.undo(); },
39615 annotation: function() { return context.history().undoAnnotation(); }
39618 cmd: iD.ui.cmd('⌘⇧Z'),
39619 action: function() {if (!(context.inIntro() || saving())) context.redo(); },
39620 annotation: function() { return context.history().redoAnnotation(); }
39623 function saving() {
39624 return context.mode().id === 'save';
39627 return function(selection) {
39628 var tooltip = bootstrap.tooltip()
39629 .placement('bottom')
39631 .title(function (d) {
39632 return iD.ui.tooltipHtml(d.annotation() ?
39633 t(d.id + '.tooltip', {action: d.annotation()}) :
39634 t(d.id + '.nothing'), d.cmd);
39637 var buttons = selection.selectAll('button')
39639 .enter().append('button')
39640 .attr('class', 'col6 disabled')
39641 .on('click', function(d) { return d.action(); })
39644 buttons.each(function(d) {
39646 .call(iD.svg.Icon('#icon-' + d.id));
39649 var keybinding = d3.keybinding('undo')
39650 .on(commands[0].cmd, function() { d3.event.preventDefault(); commands[0].action(); })
39651 .on(commands[1].cmd, function() { d3.event.preventDefault(); commands[1].action(); });
39653 d3.select(document)
39657 .on('change.undo_redo', update);
39660 .on('enter.undo_redo', update);
39662 function update() {
39664 .property('disabled', saving())
39665 .classed('disabled', function(d) { return !d.annotation(); })
39667 var selection = d3.select(this);
39668 if (selection.property('tooltipVisible')) {
39669 selection.call(tooltip.show);
39675 iD.ui.ViewOnOSM = function(context) {
39678 function viewOnOSM(selection) {
39679 var entity = context.entity(id);
39681 selection.style('display', entity.isNew() ? 'none' : null);
39683 var $link = selection.selectAll('.view-on-osm')
39688 .attr('class', 'view-on-osm')
39689 .attr('target', '_blank')
39690 .call(iD.svg.Icon('#icon-out-link', 'inline'))
39692 .text(t('inspector.view_on_osm'));
39695 .attr('href', context.connection().entityURL(entity));
39698 viewOnOSM.entityID = function(_) {
39699 if (!arguments.length) return id;
39706 iD.ui.Zoom = function(context) {
39710 title: t('zoom.in'),
39711 action: context.zoomIn,
39716 title: t('zoom.out'),
39717 action: context.zoomOut,
39721 function zoomIn() {
39722 d3.event.preventDefault();
39723 if (!context.inIntro()) context.zoomIn();
39726 function zoomOut() {
39727 d3.event.preventDefault();
39728 if (!context.inIntro()) context.zoomOut();
39731 function zoomInFurther() {
39732 d3.event.preventDefault();
39733 if (!context.inIntro()) context.zoomInFurther();
39736 function zoomOutFurther() {
39737 d3.event.preventDefault();
39738 if (!context.inIntro()) context.zoomOutFurther();
39742 return function(selection) {
39743 var button = selection.selectAll('button')
39745 .enter().append('button')
39746 .attr('tabindex', -1)
39747 .attr('class', function(d) { return d.id; })
39748 .on('click.editor', function(d) { d.action(); })
39749 .call(bootstrap.tooltip()
39752 .title(function(d) {
39753 return iD.ui.tooltipHtml(d.title, d.key);
39756 button.each(function(d) {
39758 .call(iD.svg.Icon('#icon-' + d.icon, 'light'));
39761 var keybinding = d3.keybinding('zoom');
39763 _.each(['=','ffequals','plus','ffplus'], function(key) {
39764 keybinding.on(key, zoomIn);
39765 keybinding.on('⇧' + key, zoomIn);
39766 keybinding.on(iD.ui.cmd('⌘' + key), zoomInFurther);
39767 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomInFurther);
39769 _.each(['-','ffminus','_','dash'], function(key) {
39770 keybinding.on(key, zoomOut);
39771 keybinding.on('⇧' + key, zoomOut);
39772 keybinding.on(iD.ui.cmd('⌘' + key), zoomOutFurther);
39773 keybinding.on(iD.ui.cmd('⌘⇧' + key), zoomOutFurther);
39776 d3.select(document)
39780 iD.ui.preset.access = function(field) {
39781 var dispatch = d3.dispatch('change'),
39784 function access(selection) {
39785 var wrap = selection.selectAll('.preset-input-wrap')
39788 wrap.enter().append('div')
39789 .attr('class', 'cf preset-input-wrap')
39792 items = wrap.select('ul').selectAll('li')
39797 var enter = items.enter().append('li')
39798 .attr('class', function(d) { return 'cf preset-access-' + d; });
39800 enter.append('span')
39801 .attr('class', 'col6 label preset-label-access')
39802 .attr('for', function(d) { return 'preset-input-access-' + d; })
39803 .text(function(d) { return field.t('types.' + d); });
39805 enter.append('div')
39806 .attr('class', 'col6 preset-input-access-wrap')
39808 .attr('type', 'text')
39809 .attr('class', 'preset-input-access')
39810 .attr('id', function(d) { return 'preset-input-access-' + d; })
39811 .each(function(d) {
39813 .call(d3.combobox()
39814 .data(access.options(d)));
39819 wrap.selectAll('.preset-input-access')
39820 .on('change', change)
39821 .on('blur', change);
39824 function change(d) {
39826 tag[d] = d3.select(this).value() || undefined;
39827 dispatch.change(tag);
39830 access.options = function(type) {
39831 var options = ['no', 'permissive', 'private', 'destination'];
39833 if (type !== 'access') {
39834 options.unshift('yes');
39835 options.push('designated');
39837 if (type === 'bicycle') {
39838 options.push('dismount');
39842 return options.map(function(option) {
39844 title: field.t('options.' + option + '.description'),
39850 var placeholders = {
39852 foot: 'designated',
39853 motor_vehicle: 'no'
39857 motor_vehicle: 'no',
39863 motor_vehicle: 'no'
39866 motor_vehicle: 'no',
39867 bicycle: 'designated'
39870 motor_vehicle: 'no',
39871 horse: 'designated'
39875 motor_vehicle: 'no',
39881 motor_vehicle: 'yes',
39886 motor_vehicle: 'yes'
39890 motor_vehicle: 'yes',
39896 motor_vehicle: 'yes',
39902 motor_vehicle: 'yes',
39908 motor_vehicle: 'yes',
39914 motor_vehicle: 'yes',
39920 motor_vehicle: 'yes',
39926 motor_vehicle: 'yes',
39931 motor_vehicle: 'yes'
39935 motor_vehicle: 'yes',
39941 motor_vehicle: 'yes',
39947 motor_vehicle: 'yes',
39953 access.tags = function(tags) {
39954 items.selectAll('.preset-input-access')
39955 .value(function(d) { return tags[d] || ''; })
39956 .attr('placeholder', function() {
39957 return tags.access ? tags.access : field.placeholder();
39960 // items.selectAll('#preset-input-access-access')
39961 // .attr('placeholder', 'yes');
39963 _.forEach(placeholders[tags.highway], function(v, k) {
39964 items.selectAll('#preset-input-access-' + k)
39965 .attr('placeholder', function() { return (tags.access || v); });
39969 access.focus = function() {
39970 items.selectAll('.preset-input-access')
39974 return d3.rebind(access, dispatch, 'on');
39976 iD.ui.preset.address = function(field, context) {
39977 var dispatch = d3.dispatch('init', 'change'),
39990 function getStreets() {
39991 var extent = entity.extent(context.graph()),
39992 l = extent.center(),
39993 box = iD.geo.Extent(l).padByMeters(200);
39995 return context.intersects(box)
39996 .filter(isAddressable)
39998 var loc = context.projection([
39999 (extent[0][0] + extent[1][0]) / 2,
40000 (extent[0][1] + extent[1][1]) / 2]),
40001 choice = iD.geo.chooseEdge(context.childNodes(d), loc, context.projection);
40003 title: d.tags.name,
40004 value: d.tags.name,
40005 dist: choice.distance
40007 }).sort(function(a, b) {
40008 return a.dist - b.dist;
40011 function isAddressable(d) {
40012 return d.tags.highway && d.tags.name && d.type === 'way';
40016 function getCities() {
40017 var extent = entity.extent(context.graph()),
40018 l = extent.center(),
40019 box = iD.geo.Extent(l).padByMeters(200);
40021 return context.intersects(box)
40022 .filter(isAddressable)
40025 title: d.tags['addr:city'] || d.tags.name,
40026 value: d.tags['addr:city'] || d.tags.name,
40027 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
40029 }).sort(function(a, b) {
40030 return a.dist - b.dist;
40033 function isAddressable(d) {
40035 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
40038 if (d.tags.place && d.tags.name && (
40039 d.tags.place === 'city' ||
40040 d.tags.place === 'town' ||
40041 d.tags.place === 'village'))
40044 if (d.tags['addr:city']) return true;
40050 function getPostCodes() {
40051 var extent = entity.extent(context.graph()),
40052 l = extent.center(),
40053 box = iD.geo.Extent(l).padByMeters(200);
40055 return context.intersects(box)
40056 .filter(isAddressable)
40059 title: d.tags['addr:postcode'],
40060 value: d.tags['addr:postcode'],
40061 dist: iD.geo.sphericalDistance(d.extent(context.graph()).center(), l)
40063 }).sort(function(a, b) {
40064 return a.dist - b.dist;
40067 function isAddressable(d) {
40068 return d.tags['addr:postcode'];
40072 function address(selection) {
40073 isInitialized = false;
40075 wrap = selection.selectAll('.preset-input-wrap')
40082 .attr('class', 'preset-input-wrap');
40084 var center = entity.extent(context.graph()).center(),
40087 iD.services.nominatim().countryCode(center, function (err, countryCode) {
40088 addressFormat = _.find(iD.data.addressFormats, function (a) {
40089 return a && a.countryCodes && _.includes(a.countryCodes, countryCode);
40090 }) || _.first(iD.data.addressFormats);
40093 // Normalize widths.
40094 var total = _.reduce(r, function(sum, field) {
40095 return sum + (widths[field] || 0.5);
40098 return r.map(function (field) {
40101 width: (widths[field] || 0.5) / total
40106 wrap.selectAll('div')
40107 .data(addressFormat.format)
40110 .attr('class', 'addr-row')
40111 .selectAll('input')
40115 .property('type', 'text')
40116 .attr('placeholder', function (d) { return field.t('placeholders.' + d.id); })
40117 .attr('class', function (d) { return 'addr-' + d.id; })
40118 .style('width', function (d) { return d.width * 100 + '%'; });
40122 wrap.selectAll('.addr-street')
40123 .call(d3.combobox()
40124 .fetcher(function(value, callback) {
40125 callback(getStreets());
40128 wrap.selectAll('.addr-city')
40129 .call(d3.combobox()
40130 .fetcher(function(value, callback) {
40131 callback(getCities());
40134 wrap.selectAll('.addr-postcode')
40135 .call(d3.combobox()
40136 .fetcher(function(value, callback) {
40137 callback(getPostCodes());
40140 wrap.selectAll('input')
40141 .on('blur', change())
40142 .on('change', change());
40144 wrap.selectAll('input:not(.combobox-input)')
40145 .on('input', change(true));
40148 isInitialized = true;
40152 function change(onInput) {
40153 return function() {
40156 wrap.selectAll('input')
40157 .each(function (field) {
40158 tags['addr:' + field.id] = this.value || undefined;
40161 dispatch.change(tags, onInput);
40165 function updateTags(tags) {
40166 wrap.selectAll('input')
40167 .value(function (field) {
40168 return tags['addr:' + field.id] || '';
40172 address.entity = function(_) {
40173 if (!arguments.length) return entity;
40178 address.tags = function(tags) {
40179 if (isInitialized) {
40182 dispatch.on('init', function () {
40188 address.focus = function() {
40189 var node = wrap.selectAll('input').node();
40190 if (node) node.focus();
40193 return d3.rebind(address, dispatch, 'on');
40195 iD.ui.preset.check =
40196 iD.ui.preset.defaultcheck = function(field) {
40197 var dispatch = d3.dispatch('change'),
40198 options = field.strings && field.strings.options,
40201 entity, value, box, text, label;
40204 for (var k in options) {
40205 values.push(k === 'undefined' ? undefined : k);
40206 texts.push(field.t('options.' + k, { 'default': options[k] }));
40209 values = [undefined, 'yes'];
40210 texts = [t('inspector.unknown'), t('inspector.check.yes')];
40211 if (field.type === 'check') {
40213 texts.push(t('inspector.check.no'));
40217 var check = function(selection) {
40218 // hack: pretend oneway field is a oneway_yes field
40219 // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
40220 if (field.id === 'oneway') {
40221 for (var key in entity.tags) {
40222 if (key in iD.oneWayTags && (entity.tags[key] in iD.oneWayTags[key])) {
40223 texts[0] = t('presets.fields.oneway_yes.options.undefined');
40229 selection.classed('checkselect', 'true');
40231 label = selection.selectAll('.preset-input-wrap')
40234 var enter = label.enter().append('label')
40235 .attr('class', 'preset-input-wrap');
40237 enter.append('input')
40238 .property('indeterminate', field.type === 'check')
40239 .attr('type', 'checkbox')
40240 .attr('id', 'preset-input-' + field.id);
40242 enter.append('span')
40244 .attr('class', 'value');
40246 box = label.select('input')
40247 .on('click', function() {
40249 t[field.key] = values[(values.indexOf(value) + 1) % values.length];
40250 dispatch.change(t);
40251 d3.event.stopPropagation();
40254 text = label.select('span.value');
40257 check.entity = function(_) {
40258 if (!arguments.length) return entity;
40263 check.tags = function(tags) {
40264 value = tags[field.key];
40265 box.property('indeterminate', field.type === 'check' && !value);
40266 box.property('checked', value === 'yes');
40267 text.text(texts[values.indexOf(value)]);
40268 label.classed('set', !!value);
40271 check.focus = function() {
40272 box.node().focus();
40275 return d3.rebind(check, dispatch, 'on');
40277 iD.ui.preset.combo =
40278 iD.ui.preset.typeCombo =
40279 iD.ui.preset.multiCombo = function(field, context) {
40280 var dispatch = d3.dispatch('change'),
40281 isMulti = (field.type === 'multiCombo'),
40282 optstrings = field.strings && field.strings.options,
40283 optarray = field.options,
40284 snake_case = (field.snake_case || (field.snake_case === undefined)),
40285 combobox = d3.combobox().minItems(isMulti ? 1 : 2),
40292 // ensure multiCombo field.key ends with a ':'
40293 if (isMulti && field.key.match(/:$/) === null) {
40298 function snake(s) {
40299 return s.replace(/\s+/g, '_');
40302 function unsnake(s) {
40303 return s.replace(/_+/g, ' ');
40306 function clean(s) {
40307 return s.split(';')
40308 .map(function(s) { return s.trim(); })
40313 // returns the tag value for a display value
40314 // (for multiCombo, dval should be the key suffix, not the entire key)
40315 function tagValue(dval) {
40316 dval = clean(dval || '');
40319 var match = _.find(comboData, function(o) {
40320 return o.key && clean(o.value) === dval;
40327 if (field.type === 'typeCombo' && !dval) {
40331 return (snake_case ? snake(dval) : dval) || undefined;
40335 // returns the display value for a tag value
40336 // (for multiCombo, tval should be the key suffix, not the entire key)
40337 function displayValue(tval) {
40341 var match = _.find(comboData, function(o) { return o.key === tval && o.value; });
40343 return match.value;
40347 if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
40351 return snake_case ? unsnake(tval) : tval;
40355 function objectDifference(a, b) {
40356 return _.reject(a, function(d1) {
40357 return _.some(b, function(d2) { return d1.value === d2.value; });
40362 function initCombo(selection, attachTo) {
40364 selection.attr('readonly', 'readonly');
40365 selection.call(combobox, attachTo);
40366 setStaticValues(setPlaceholder);
40368 } else if (optarray) {
40369 selection.call(combobox, attachTo);
40370 setStaticValues(setPlaceholder);
40372 } else if (context.taginfo()) {
40373 selection.call(combobox.fetcher(setTaginfoValues), attachTo);
40374 setTaginfoValues('', setPlaceholder);
40379 function setStaticValues(callback) {
40380 if (!(optstrings || optarray)) return;
40383 comboData = Object.keys(optstrings).map(function(k) {
40384 var v = field.t('options.' + k, { 'default': optstrings[k] });
40392 } else if (optarray) {
40393 comboData = optarray.map(function(k) {
40394 var v = snake_case ? unsnake(k) : k;
40403 combobox.data(objectDifference(comboData, multiData));
40404 if (callback) callback(comboData);
40408 function setTaginfoValues(q, callback) {
40409 var fn = isMulti ? 'multikeys' : 'values';
40410 context.taginfo()[fn]({
40413 geometry: context.geometry(entity.id),
40414 query: (isMulti ? field.key : '') + q
40415 }, function(err, data) {
40417 comboData = _.map(data, 'value').map(function(k) {
40418 if (isMulti) k = k.replace(field.key, '');
40419 var v = snake_case ? unsnake(k) : k;
40426 comboData = objectDifference(comboData, multiData);
40427 if (callback) callback(comboData);
40432 function setPlaceholder(d) {
40435 ph = field.placeholder() || t('inspector.add');
40437 var vals = _.map(d, 'value').filter(function(s) { return s.length < 20; }),
40438 placeholders = vals.length > 1 ? vals : _.map(d, 'key');
40439 ph = field.placeholder() || placeholders.slice(0, 3).join(', ');
40442 input.attr('placeholder', ph + '…');
40446 function change() {
40447 var val = tagValue(input.value()),
40452 container.classed('active', false);
40454 field.keys.push(field.key + val);
40455 t[field.key + val] = 'yes';
40456 window.setTimeout(function() { input.node().focus(); }, 10);
40459 t[field.key] = val;
40462 dispatch.change(t);
40466 function removeMultikey(d) {
40467 d3.event.stopPropagation();
40469 t[d.key] = undefined;
40470 dispatch.change(t);
40474 function combo(selection) {
40476 container = selection.selectAll('ul').data([0]);
40480 .attr('class', 'form-field-multicombo')
40481 .on('click', function() {
40482 window.setTimeout(function() { input.node().focus(); }, 10);
40486 container = selection;
40489 input = container.selectAll('input')
40494 .attr('type', 'text')
40495 .attr('id', 'preset-input-' + field.id)
40496 .call(initCombo, selection);
40499 .on('change', change)
40500 .on('blur', change);
40504 .on('accept', function() {
40505 input.node().blur();
40506 input.node().focus();
40510 .on('focus', function() { container.classed('active', true); });
40515 combo.tags = function(tags) {
40519 // Build multiData array containing keys already set..
40520 Object.keys(tags).forEach(function(key) {
40521 if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return;
40523 var suffix = key.substring(field.key.length);
40526 value: displayValue(suffix)
40530 // Set keys for form-field modified (needed for undo and reset buttons)..
40531 field.keys = _.map(multiData, 'key');
40533 // Exclude existing multikeys from combo options..
40534 var available = objectDifference(comboData, multiData);
40535 combobox.data(available);
40537 // Hide "Add" button if this field uses fixed set of
40538 // translateable optstrings and they're all currently used..
40539 container.selectAll('.combobox-input, .combobox-caret')
40540 .classed('hide', optstrings && !available.length);
40544 var chips = container.selectAll('.chips').data(multiData);
40546 var enter = chips.enter()
40547 .insert('li', 'input')
40548 .attr('class', 'chips');
40550 enter.append('span');
40553 chips.select('span')
40554 .text(function(d) { return d.value; });
40557 .on('click', removeMultikey)
40558 .attr('class', 'remove')
40565 input.value(displayValue(tags[field.key]));
40570 combo.focus = function() {
40571 input.node().focus();
40575 combo.entity = function(_) {
40576 if (!arguments.length) return entity;
40582 return d3.rebind(combo, dispatch, 'on');
40584 iD.ui.preset.cycleway = function(field) {
40585 var dispatch = d3.dispatch('change'),
40588 function cycleway(selection) {
40589 var wrap = selection.selectAll('.preset-input-wrap')
40592 wrap.enter().append('div')
40593 .attr('class', 'cf preset-input-wrap')
40596 items = wrap.select('ul').selectAll('li')
40601 var enter = items.enter().append('li')
40602 .attr('class', function(d) { return 'cf preset-cycleway-' + d; });
40604 enter.append('span')
40605 .attr('class', 'col6 label preset-label-cycleway')
40606 .attr('for', function(d) { return 'preset-input-cycleway-' + d; })
40607 .text(function(d) { return field.t('types.' + d); });
40609 enter.append('div')
40610 .attr('class', 'col6 preset-input-cycleway-wrap')
40612 .attr('type', 'text')
40613 .attr('class', 'preset-input-cycleway')
40614 .attr('id', function(d) { return 'preset-input-cycleway-' + d; })
40615 .each(function(d) {
40617 .call(d3.combobox()
40618 .data(cycleway.options(d)));
40623 wrap.selectAll('.preset-input-cycleway')
40624 .on('change', change)
40625 .on('blur', change);
40628 function change() {
40629 var inputs = d3.selectAll('.preset-input-cycleway')[0],
40630 left = d3.select(inputs[0]).value(),
40631 right = d3.select(inputs[1]).value(),
40633 if (left === 'none' || left === '') { left = undefined; }
40634 if (right === 'none' || right === '') { right = undefined; }
40636 // Always set both left and right as changing one can affect the other
40638 cycleway: undefined,
40639 'cycleway:left': left,
40640 'cycleway:right': right
40643 // If the left and right tags match, use the cycleway tag to tag both
40644 // sides the same way
40645 if (left === right) {
40648 'cycleway:left': undefined,
40649 'cycleway:right': undefined
40653 dispatch.change(tag);
40656 cycleway.options = function() {
40657 return d3.keys(field.strings.options).map(function(option) {
40659 title: field.t('options.' + option + '.description'),
40665 cycleway.tags = function(tags) {
40666 items.selectAll('.preset-input-cycleway')
40667 .value(function(d) {
40668 // If cycleway is set, always return that
40669 if (tags.cycleway) {
40670 return tags.cycleway;
40672 return tags[d] || '';
40674 .attr('placeholder', field.placeholder());
40677 cycleway.focus = function() {
40678 items.selectAll('.preset-input-cycleway')
40682 return d3.rebind(cycleway, dispatch, 'on');
40684 iD.ui.preset.text =
40685 iD.ui.preset.number =
40687 iD.ui.preset.email =
40688 iD.ui.preset.url = function(field, context) {
40690 var dispatch = d3.dispatch('change'),
40694 function i(selection) {
40695 var fieldId = 'preset-input-' + field.id;
40697 input = selection.selectAll('input')
40700 input.enter().append('input')
40701 .attr('type', field.type)
40702 .attr('id', fieldId)
40703 .attr('placeholder', field.placeholder() || t('inspector.unknown'));
40706 .on('input', change(true))
40707 .on('blur', change())
40708 .on('change', change());
40710 if (field.type === 'tel') {
40711 var center = entity.extent(context.graph()).center();
40712 iD.services.nominatim().countryCode(center, function (err, countryCode) {
40713 if (err || !iD.data.phoneFormats[countryCode]) return;
40714 selection.selectAll('#' + fieldId)
40715 .attr('placeholder', iD.data.phoneFormats[countryCode]);
40718 } else if (field.type === 'number') {
40719 input.attr('type', 'text');
40721 var spinControl = selection.selectAll('.spin-control')
40724 var enter = spinControl.enter().append('div')
40725 .attr('class', 'spin-control');
40727 enter.append('button')
40729 .attr('class', 'increment')
40730 .attr('tabindex', -1);
40732 enter.append('button')
40734 .attr('class', 'decrement')
40735 .attr('tabindex', -1);
40737 spinControl.selectAll('button')
40738 .on('click', function(d) {
40739 d3.event.preventDefault();
40740 var num = parseInt(input.node().value || 0, 10);
40741 if (!isNaN(num)) input.node().value = num + d;
40747 function change(onInput) {
40748 return function() {
40750 t[field.key] = input.value() || undefined;
40751 dispatch.change(t, onInput);
40755 i.entity = function(_) {
40756 if (!arguments.length) return entity;
40761 i.tags = function(tags) {
40762 input.value(tags[field.key] || '');
40765 i.focus = function() {
40766 var node = input.node();
40767 if (node) node.focus();
40770 return d3.rebind(i, dispatch, 'on');
40772 iD.ui.preset.localized = function(field, context) {
40773 var dispatch = d3.dispatch('change', 'input'),
40774 wikipedia = iD.services.wikipedia(),
40775 input, localizedInputs, wikiTitles,
40778 function localized(selection) {
40779 input = selection.selectAll('.localized-main')
40782 input.enter().append('input')
40783 .attr('type', 'text')
40784 .attr('id', 'preset-input-' + field.id)
40785 .attr('class', 'localized-main')
40786 .attr('placeholder', field.placeholder());
40788 if (field.id === 'name') {
40789 var preset = context.presets().match(entity, context.graph());
40790 input.call(d3.combobox().fetcher(
40791 iD.util.SuggestNames(preset, iD.data.suggestions)
40796 .on('input', change(true))
40797 .on('blur', change())
40798 .on('change', change());
40800 var translateButton = selection.selectAll('.localized-add')
40803 translateButton.enter()
40805 .attr('class', 'button-input-action localized-add minor')
40806 .attr('tabindex', -1)
40807 .call(iD.svg.Icon('#icon-plus'))
40808 .call(bootstrap.tooltip()
40809 .title(t('translate.translate'))
40810 .placement('left'));
40813 .on('click', addNew);
40815 localizedInputs = selection.selectAll('.localized-wrap')
40818 localizedInputs.enter().append('div')
40819 .attr('class', 'localized-wrap');
40822 function addNew() {
40823 d3.event.preventDefault();
40824 var data = localizedInputs.selectAll('div.entry').data();
40825 var defaultLang = iD.detect().locale.toLowerCase().split('-')[0];
40826 var langExists = _.find(data, function(datum) { return datum.lang === defaultLang;});
40827 var isLangEn = defaultLang.indexOf('en') > -1;
40828 if (isLangEn || langExists) {
40831 data.push({ lang: defaultLang, value: '' });
40832 localizedInputs.call(render, data);
40835 function change(onInput) {
40836 return function() {
40838 t[field.key] = d3.select(this).value() || undefined;
40839 dispatch.change(t, onInput);
40843 function key(lang) { return field.key + ':' + lang; }
40845 function changeLang(d) {
40846 var lang = d3.select(this).value(),
40848 language = _.find(iD.data.wikipedia, function(d) {
40849 return d[0].toLowerCase() === lang.toLowerCase() ||
40850 d[1].toLowerCase() === lang.toLowerCase();
40853 if (language) lang = language[2];
40855 if (d.lang && d.lang !== lang) {
40856 t[key(d.lang)] = undefined;
40859 var value = d3.select(this.parentNode)
40860 .selectAll('.localized-value')
40863 if (lang && value) {
40864 t[key(lang)] = value;
40865 } else if (lang && wikiTitles && wikiTitles[d.lang]) {
40866 t[key(lang)] = wikiTitles[d.lang];
40870 dispatch.change(t);
40873 function changeValue(d) {
40874 if (!d.lang) return;
40876 t[key(d.lang)] = d3.select(this).value() || undefined;
40877 dispatch.change(t);
40880 function fetcher(value, cb) {
40881 var v = value.toLowerCase();
40883 cb(iD.data.wikipedia.filter(function(d) {
40884 return d[0].toLowerCase().indexOf(v) >= 0 ||
40885 d[1].toLowerCase().indexOf(v) >= 0 ||
40886 d[2].toLowerCase().indexOf(v) >= 0;
40887 }).map(function(d) {
40888 return { value: d[1] };
40892 function render(selection, data) {
40893 var wraps = selection.selectAll('div.entry').
40894 data(data, function(d) { return d.lang; });
40896 var innerWrap = wraps.enter()
40897 .insert('div', ':first-child');
40899 innerWrap.attr('class', 'entry')
40901 var wrap = d3.select(this);
40902 var langcombo = d3.combobox().fetcher(fetcher).minItems(0);
40904 var label = wrap.append('label')
40905 .attr('class','form-label')
40906 .text(t('translate.localized_translation_label'))
40907 .attr('for','localized-lang');
40909 label.append('button')
40910 .attr('class', 'minor remove')
40911 .on('click', function(d){
40912 d3.event.preventDefault();
40914 t[key(d.lang)] = undefined;
40915 dispatch.change(t);
40916 d3.select(this.parentNode.parentNode)
40918 .style('max-height','240px')
40920 .style('opacity', '0')
40921 .style('max-height','0px')
40924 .call(iD.svg.Icon('#operation-delete'));
40926 wrap.append('input')
40927 .attr('class', 'localized-lang')
40928 .attr('type', 'text')
40929 .attr('placeholder',t('translate.localized_translation_language'))
40930 .on('blur', changeLang)
40931 .on('change', changeLang)
40934 wrap.append('input')
40935 .on('blur', changeValue)
40936 .on('change', changeValue)
40937 .attr('type', 'text')
40938 .attr('placeholder', t('translate.localized_translation_name'))
40939 .attr('class', 'localized-value');
40943 .style('margin-top', '0px')
40944 .style('max-height', '0px')
40945 .style('opacity', '0')
40948 .style('margin-top', '10px')
40949 .style('max-height', '240px')
40950 .style('opacity', '1')
40951 .each('end', function() {
40953 .style('max-height', '')
40954 .style('overflow', 'visible');
40960 .style('max-height','0px')
40961 .style('opacity', '0')
40962 .style('top','-10px')
40965 var entry = selection.selectAll('.entry');
40967 entry.select('.localized-lang')
40968 .value(function(d) {
40969 var lang = _.find(iD.data.wikipedia, function(lang) { return lang[2] === d.lang; });
40970 return lang ? lang[1] : d.lang;
40973 entry.select('.localized-value')
40974 .value(function(d) { return d.value; });
40977 localized.tags = function(tags) {
40978 // Fetch translations from wikipedia
40979 if (tags.wikipedia && !wikiTitles) {
40981 var wm = tags.wikipedia.match(/([^:]+):(.+)/);
40982 if (wm && wm[0] && wm[1]) {
40983 wikipedia.translations(wm[1], wm[2], function(d) {
40989 input.value(tags[field.key] || '');
40991 var postfixed = [], k, m;
40993 m = k.match(/^(.*):([a-zA-Z_-]+)$/);
40994 if (m && m[1] === field.key && m[2]) {
40995 postfixed.push({ lang: m[2], value: tags[k] });
40999 localizedInputs.call(render, postfixed.reverse());
41002 localized.focus = function() {
41003 input.node().focus();
41006 localized.entity = function(_) {
41007 if (!arguments.length) return entity;
41012 return d3.rebind(localized, dispatch, 'on');
41014 iD.ui.preset.maxspeed = function(field, context) {
41015 var dispatch = d3.dispatch('change'),
41022 var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
41023 imperialValues = [20, 25, 30, 35, 40, 45, 50, 55, 65, 70];
41025 function maxspeed(selection) {
41026 combobox = d3.combobox();
41027 var unitCombobox = d3.combobox().data(['km/h', 'mph'].map(comboValues));
41029 input = selection.selectAll('#preset-input-' + field.id)
41032 input.enter().append('input')
41033 .attr('type', 'text')
41034 .attr('id', 'preset-input-' + field.id)
41035 .attr('placeholder', field.placeholder());
41039 .on('change', change)
41040 .on('blur', change);
41042 var childNodes = context.graph().childNodes(context.entity(entity.id)),
41043 loc = childNodes[~~(childNodes.length/2)].loc;
41045 imperial = _.some(iD.data.imperial.features, function(f) {
41046 return _.some(f.geometry.coordinates, function(d) {
41047 return iD.geo.pointInPolygon(loc, d[0]);
41051 unitInput = selection.selectAll('input.maxspeed-unit')
41054 unitInput.enter().append('input')
41055 .attr('type', 'text')
41056 .attr('class', 'maxspeed-unit');
41059 .on('blur', changeUnits)
41060 .on('change', changeUnits)
41061 .call(unitCombobox);
41063 function changeUnits() {
41064 imperial = unitInput.value() === 'mph';
41065 unitInput.value(imperial ? 'mph' : 'km/h');
41072 function setSuggestions() {
41073 combobox.data((imperial ? imperialValues : metricValues).map(comboValues));
41074 unitInput.value(imperial ? 'mph' : 'km/h');
41077 function comboValues(d) {
41079 value: d.toString(),
41080 title: d.toString()
41084 function change() {
41086 value = input.value();
41089 tag[field.key] = undefined;
41090 } else if (isNaN(value) || !imperial) {
41091 tag[field.key] = value;
41093 tag[field.key] = value + ' mph';
41096 dispatch.change(tag);
41099 maxspeed.tags = function(tags) {
41100 var value = tags[field.key];
41102 if (value && value.indexOf('mph') >= 0) {
41103 value = parseInt(value, 10);
41105 } else if (value) {
41111 input.value(value || '');
41114 maxspeed.focus = function() {
41115 input.node().focus();
41118 maxspeed.entity = function(_) {
41122 return d3.rebind(maxspeed, dispatch, 'on');
41124 iD.ui.preset.radio = function(field) {
41125 var dispatch = d3.dispatch('change'),
41126 labels, radios, placeholder;
41128 function radio(selection) {
41129 selection.classed('preset-radio', true);
41131 var wrap = selection.selectAll('.preset-input-wrap')
41134 var buttonWrap = wrap.enter().append('div')
41135 .attr('class', 'preset-input-wrap toggle-list');
41137 buttonWrap.append('span')
41138 .attr('class', 'placeholder');
41140 placeholder = selection.selectAll('.placeholder');
41142 labels = wrap.selectAll('label')
41143 .data(field.options || field.keys);
41145 var enter = labels.enter().append('label');
41147 enter.append('input')
41148 .attr('type', 'radio')
41149 .attr('name', field.id)
41150 .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
41151 .attr('checked', false);
41153 enter.append('span')
41154 .text(function(d) { return field.t('options.' + d, { 'default': d }); });
41156 radios = labels.selectAll('input')
41157 .on('change', change);
41160 function change() {
41162 if (field.key) t[field.key] = undefined;
41163 radios.each(function(d) {
41164 var active = d3.select(this).property('checked');
41166 if (active) t[field.key] = d;
41168 t[d] = active ? 'yes' : undefined;
41171 dispatch.change(t);
41174 radio.tags = function(tags) {
41175 function checked(d) {
41177 return tags[field.key] === d;
41179 return !!(tags[d] && tags[d] !== 'no');
41183 labels.classed('active', checked);
41184 radios.property('checked', checked);
41185 var selection = radios.filter(function() { return this.checked; });
41186 if (selection.empty()) {
41187 placeholder.text(t('inspector.none'));
41189 placeholder.text(selection.attr('value'));
41193 radio.focus = function() {
41194 radios.node().focus();
41197 return d3.rebind(radio, dispatch, 'on');
41199 iD.ui.preset.restrictions = function(field, context) {
41200 var dispatch = d3.dispatch('change'),
41201 hover = iD.behavior.Hover(context),
41206 function restrictions(selection) {
41207 // if form field is hidden or has detached from dom, clean up.
41208 if (!d3.select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
41209 selection.call(restrictions.off);
41213 var wrap = selection.selectAll('.preset-input-wrap')
41216 var enter = wrap.enter()
41218 .attr('class', 'preset-input-wrap');
41222 .attr('class', 'restriction-help');
41225 var intersection = iD.geo.Intersection(context.graph(), vertexID),
41226 graph = intersection.graph,
41227 vertex = graph.entity(vertexID),
41228 filter = d3.functor(true),
41229 extent = iD.geo.Extent(),
41230 projection = iD.geo.RawMercator();
41232 var d = wrap.dimensions(),
41233 c = [d[0] / 2, d[1] / 2],
41237 .scale(256 * Math.pow(2, z) / (2 * Math.PI));
41239 var s = projection(vertex.loc);
41242 .translate([c[0] - s[0], c[1] - s[1]])
41243 .clipExtent([[0, 0], d]);
41245 var drawLayers = iD.svg.Layers(projection, context).only('osm').dimensions(d),
41246 drawVertices = iD.svg.Vertices(projection, context),
41247 drawLines = iD.svg.Lines(projection, context),
41248 drawTurns = iD.svg.Turns(projection, context);
41252 .selectAll('.surface')
41256 var surface = wrap.selectAll('.surface');
41260 .call(drawVertices, graph, [vertex], filter, extent, z)
41261 .call(drawLines, graph, intersection.ways, filter)
41262 .call(drawTurns, graph, intersection.turns(fromNodeID));
41265 .on('click.restrictions', click)
41266 .on('mouseover.restrictions', mouseover)
41267 .on('mouseout.restrictions', mouseout);
41270 .selectAll('.selected')
41271 .classed('selected', false);
41275 .selectAll('.' + intersection.highways[fromNodeID].id)
41276 .classed('selected', true);
41282 .on('change.restrictions', render);
41285 .on('resize.restrictions', function() {
41286 wrap.dimensions(null);
41291 var datum = d3.event.target.__data__;
41292 if (datum instanceof iD.Entity) {
41293 fromNodeID = intersection.adjacentNodeId(datum.id);
41295 } else if (datum instanceof iD.geo.Turn) {
41296 if (datum.restriction) {
41298 iD.actions.UnrestrictTurn(datum, projection),
41299 t('operations.restriction.annotation.delete'));
41302 iD.actions.RestrictTurn(datum, projection),
41303 t('operations.restriction.annotation.create'));
41308 function mouseover() {
41309 var datum = d3.event.target.__data__;
41310 if (datum instanceof iD.geo.Turn) {
41311 var graph = context.graph(),
41312 presets = context.presets(),
41315 if (datum.restriction) {
41316 preset = presets.match(graph.entity(datum.restriction), graph);
41318 preset = presets.item('type/restriction/' +
41319 iD.geo.inferRestriction(
41327 wrap.selectAll('.restriction-help')
41328 .text(t('operations.restriction.help.' +
41329 (datum.restriction ? 'toggle_off' : 'toggle_on'),
41330 {restriction: preset.name()}));
41334 function mouseout() {
41335 wrap.selectAll('.restriction-help')
41336 .text(t('operations.restriction.help.' +
41337 (fromNodeID ? 'toggle' : 'select')));
41340 function render() {
41341 if (context.hasEntity(vertexID)) {
41342 restrictions(selection);
41347 restrictions.entity = function(_) {
41348 if (!vertexID || vertexID !== _.id) {
41354 restrictions.tags = function() {};
41355 restrictions.focus = function() {};
41357 restrictions.off = function(selection) {
41358 selection.selectAll('.surface')
41360 .on('click.restrictions', null)
41361 .on('mouseover.restrictions', null)
41362 .on('mouseout.restrictions', null);
41365 .on('change.restrictions', null);
41368 .on('resize.restrictions', null);
41371 return d3.rebind(restrictions, dispatch, 'on');
41373 iD.ui.preset.textarea = function(field) {
41374 var dispatch = d3.dispatch('change'),
41377 function textarea(selection) {
41378 input = selection.selectAll('textarea')
41381 input.enter().append('textarea')
41382 .attr('id', 'preset-input-' + field.id)
41383 .attr('placeholder', field.placeholder() || t('inspector.unknown'))
41384 .attr('maxlength', 255);
41387 .on('input', change(true))
41388 .on('blur', change())
41389 .on('change', change());
41392 function change(onInput) {
41393 return function() {
41395 t[field.key] = input.value() || undefined;
41396 dispatch.change(t, onInput);
41400 textarea.tags = function(tags) {
41401 input.value(tags[field.key] || '');
41404 textarea.focus = function() {
41405 input.node().focus();
41408 return d3.rebind(textarea, dispatch, 'on');
41410 iD.ui.preset.wikipedia = function(field, context) {
41411 var dispatch = d3.dispatch('change'),
41412 wikipedia = iD.services.wikipedia(),
41413 wikidata = iD.services.wikidata(),
41414 link, entity, lang, title;
41416 function wiki(selection) {
41417 var langcombo = d3.combobox()
41418 .fetcher(function(value, cb) {
41419 var v = value.toLowerCase();
41421 cb(iD.data.wikipedia.filter(function(d) {
41422 return d[0].toLowerCase().indexOf(v) >= 0 ||
41423 d[1].toLowerCase().indexOf(v) >= 0 ||
41424 d[2].toLowerCase().indexOf(v) >= 0;
41425 }).map(function(d) {
41426 return { value: d[1] };
41430 var titlecombo = d3.combobox()
41431 .fetcher(function(value, cb) {
41433 if (!value) value = context.entity(entity.id).tags.name || '';
41434 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
41436 searchfn(language()[2], value, function(query, data) {
41437 cb(data.map(function(d) {
41438 return { value: d };
41443 lang = selection.selectAll('input.wiki-lang')
41446 lang.enter().append('input')
41447 .attr('type', 'text')
41448 .attr('class', 'wiki-lang')
41449 .attr('placeholder', t('translate.localized_translation_language'))
41454 .on('blur', changeLang)
41455 .on('change', changeLang);
41457 title = selection.selectAll('input.wiki-title')
41460 title.enter().append('input')
41461 .attr('type', 'text')
41462 .attr('class', 'wiki-title')
41463 .attr('id', 'preset-input-' + field.id);
41468 .on('change', change);
41470 link = selection.selectAll('a.wiki-link')
41473 link.enter().append('a')
41474 .attr('class', 'wiki-link button-input-action minor')
41475 .attr('tabindex', -1)
41476 .attr('target', '_blank')
41477 .call(iD.svg.Icon('#icon-out-link', 'inline'));
41480 function language() {
41481 var value = lang.value().toLowerCase();
41482 var locale = iD.detect().locale.toLowerCase();
41483 var localeLanguage;
41484 return _.find(iD.data.wikipedia, function(d) {
41485 if (d[2] === locale) localeLanguage = d;
41486 return d[0].toLowerCase() === value ||
41487 d[1].toLowerCase() === value ||
41489 }) || localeLanguage || ['English', 'English', 'en'];
41492 function changeLang() {
41493 lang.value(language()[1]);
41501 function change(skipWikidata) {
41502 var value = title.value(),
41503 m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
41504 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
41509 // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
41510 value = decodeURIComponent(m[2]).replace(/_/g, ' ');
41513 // Best-effort `anchordecode:` implementation
41514 anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
41516 anchor = decodeURIComponent(m[3]);
41518 value += '#' + anchor.replace(/_/g, ' ');
41520 value = value.slice(0, 1).toUpperCase() + value.slice(1);
41522 title.value(value);
41525 syncTags.wikipedia = value ? language()[2] + ':' + value : undefined;
41526 if (!skipWikidata) {
41527 syncTags.wikidata = undefined;
41530 dispatch.change(syncTags);
41533 if (skipWikidata || !value || !language()[2]) return;
41535 // attempt asynchronous update of wikidata tag..
41536 var initEntityId = entity.id,
41537 initWikipedia = context.entity(initEntityId).tags.wikipedia;
41539 wikidata.itemsByTitle(language()[2], value, function (title, data) {
41540 // 1. most recent change was a tag change
41541 var annotation = t('operations.change_tags.annotation'),
41542 currAnnotation = context.history().undoAnnotation();
41543 if (currAnnotation !== annotation) return;
41545 // 2. same entity exists and still selected
41546 var selectedIds = context.selectedIDs(),
41547 currEntityId = selectedIds.length > 0 && selectedIds[0];
41548 if (currEntityId !== initEntityId) return;
41550 // 3. wikipedia value has not changed
41551 var currTags = _.clone(context.entity(currEntityId).tags),
41552 qids = data && Object.keys(data);
41553 if (initWikipedia !== currTags.wikipedia) return;
41555 // ok to coalesce the update of wikidata tag into the previous tag change
41556 currTags.wikidata = qids && _.find(qids, function (id) {
41557 return id.match(/^Q\d+$/);
41560 context.overwrite(iD.actions.ChangeTags(currEntityId, currTags), annotation);
41561 dispatch.change(currTags);
41565 wiki.tags = function(tags) {
41566 var value = tags[field.key] || '',
41567 m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
41568 l = m && _.find(iD.data.wikipedia, function(d) { return m[1] === d[2]; }),
41569 anchor = m && m[3];
41571 // value in correct format
41574 title.value(m[2] + (anchor ? ('#' + anchor) : ''));
41577 // Best-effort `anchorencode:` implementation
41578 anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
41580 anchor = anchor.replace(/ /g, '_');
41583 link.attr('href', 'https://' + m[1] + '.wikipedia.org/wiki/' +
41584 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : ''));
41586 // unrecognized value format
41588 title.value(value);
41589 if (value && value !== '') {
41592 link.attr('href', 'https://en.wikipedia.org/wiki/Special:Search?search=' + value);
41596 wiki.entity = function(_) {
41597 if (!arguments.length) return entity;
41602 wiki.focus = function() {
41603 title.node().focus();
41606 return d3.rebind(wiki, dispatch, 'on');
41608 iD.ui.intro.area = function(context, reveal) {
41609 var event = d3.dispatch('done'),
41613 title: 'intro.areas.title'
41616 step.enter = function() {
41617 var playground = [-85.63552, 41.94159],
41618 corner = [-85.63565411045074, 41.9417715536927];
41619 context.map().centerZoom(playground, 19);
41620 reveal('button.add-area',
41621 t('intro.areas.add', { button: iD.ui.intro.icon('#icon-area', 'pre-text') }),
41622 { tooltipClass: 'intro-areas-add' });
41624 context.on('enter.intro', addArea);
41626 function addArea(mode) {
41627 if (mode.id !== 'add-area') return;
41628 context.on('enter.intro', drawArea);
41630 var padding = 120 * Math.pow(2, context.map().zoom() - 19);
41631 var pointBox = iD.ui.intro.pad(corner, padding, context);
41632 reveal(pointBox, t('intro.areas.corner'));
41634 context.map().on('move.intro', function() {
41635 padding = 120 * Math.pow(2, context.map().zoom() - 19);
41636 pointBox = iD.ui.intro.pad(corner, padding, context);
41637 reveal(pointBox, t('intro.areas.corner'), {duration: 0});
41641 function drawArea(mode) {
41642 if (mode.id !== 'draw-area') return;
41643 context.on('enter.intro', enterSelect);
41645 var padding = 150 * Math.pow(2, context.map().zoom() - 19);
41646 var pointBox = iD.ui.intro.pad(playground, padding, context);
41647 reveal(pointBox, t('intro.areas.place'));
41649 context.map().on('move.intro', function() {
41650 padding = 150 * Math.pow(2, context.map().zoom() - 19);
41651 pointBox = iD.ui.intro.pad(playground, padding, context);
41652 reveal(pointBox, t('intro.areas.place'), {duration: 0});
41656 function enterSelect(mode) {
41657 if (mode.id !== 'select') return;
41658 context.map().on('move.intro', null);
41659 context.on('enter.intro', null);
41661 timeout = setTimeout(function() {
41662 reveal('.preset-search-input',
41663 t('intro.areas.search',
41664 { name: context.presets().item('leisure/playground').name() }));
41665 d3.select('.preset-search-input').on('keyup.intro', keySearch);
41669 function keySearch() {
41670 var first = d3.select('.preset-list-item:first-child');
41671 if (first.classed('preset-leisure-playground')) {
41672 reveal(first.select('.preset-list-button').node(), t('intro.areas.choose'));
41673 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
41674 d3.select('.preset-search-input').on('keyup.intro', null);
41678 function selectedPreset() {
41680 t('intro.areas.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
41681 context.on('exit.intro', event.done);
41685 step.exit = function() {
41686 window.clearTimeout(timeout);
41687 context.on('enter.intro', null);
41688 context.on('exit.intro', null);
41689 context.history().on('change.intro', null);
41690 context.map().on('move.intro', null);
41691 d3.select('.preset-search-input').on('keyup.intro', null);
41694 return d3.rebind(step, event, 'on');
41696 iD.ui.intro.line = function(context, reveal) {
41697 var event = d3.dispatch('done'),
41701 title: 'intro.lines.title'
41704 function timeout(f, t) {
41705 timeouts.push(window.setTimeout(f, t));
41708 function eventCancel() {
41709 d3.event.stopPropagation();
41710 d3.event.preventDefault();
41713 step.enter = function() {
41714 var centroid = [-85.62830, 41.95699];
41715 var midpoint = [-85.62975395449628, 41.95787501510204];
41716 var start = [-85.6297754121684, 41.95805253325314];
41717 var intersection = [-85.62974496187628, 41.95742515554585];
41719 context.map().centerZoom(start, 18);
41720 reveal('button.add-line',
41721 t('intro.lines.add', { button: iD.ui.intro.icon('#icon-line', 'pre-text') }),
41722 { tooltipClass: 'intro-lines-add' });
41724 context.on('enter.intro', addLine);
41726 function addLine(mode) {
41727 if (mode.id !== 'add-line') return;
41728 context.on('enter.intro', drawLine);
41730 var padding = 150 * Math.pow(2, context.map().zoom() - 18);
41731 var pointBox = iD.ui.intro.pad(start, padding, context);
41732 reveal(pointBox, t('intro.lines.start'));
41734 context.map().on('move.intro', function() {
41735 padding = 150 * Math.pow(2, context.map().zoom() - 18);
41736 pointBox = iD.ui.intro.pad(start, padding, context);
41737 reveal(pointBox, t('intro.lines.start'), {duration: 0});
41741 function drawLine(mode) {
41742 if (mode.id !== 'draw-line') return;
41743 context.history().on('change.intro', addIntersection);
41744 context.on('enter.intro', retry);
41746 var padding = 300 * Math.pow(2, context.map().zoom() - 19);
41747 var pointBox = iD.ui.intro.pad(midpoint, padding, context);
41748 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}));
41750 context.map().on('move.intro', function() {
41751 padding = 300 * Math.pow(2, context.map().zoom() - 19);
41752 pointBox = iD.ui.intro.pad(midpoint, padding, context);
41753 reveal(pointBox, t('intro.lines.intersect', {name: t('intro.graph.flower_st')}), {duration: 0});
41757 // ended line before creating intersection
41758 function retry(mode) {
41759 if (mode.id !== 'select') return;
41760 var pointBox = iD.ui.intro.pad(intersection, 30, context),
41761 ids = mode.selectedIDs();
41762 reveal(pointBox, t('intro.lines.restart', {name: t('intro.graph.flower_st')}));
41763 d3.select(window).on('mousedown.intro', eventCancel, true);
41765 timeout(function() {
41766 context.replace(iD.actions.DeleteMultiple(ids));
41772 function addIntersection(changes) {
41773 if ( _.some(changes.created(), function(d) {
41774 return d.type === 'node' && context.graph().parentWays(d).length > 1;
41776 context.history().on('change.intro', null);
41777 context.on('enter.intro', enterSelect);
41779 var padding = 900 * Math.pow(2, context.map().zoom() - 19);
41780 var pointBox = iD.ui.intro.pad(centroid, padding, context);
41781 reveal(pointBox, t('intro.lines.finish'));
41783 context.map().on('move.intro', function() {
41784 padding = 900 * Math.pow(2, context.map().zoom() - 19);
41785 pointBox = iD.ui.intro.pad(centroid, padding, context);
41786 reveal(pointBox, t('intro.lines.finish'), {duration: 0});
41791 function enterSelect(mode) {
41792 if (mode.id !== 'select') return;
41793 context.map().on('move.intro', null);
41794 context.on('enter.intro', null);
41795 d3.select('#curtain').style('pointer-events', 'all');
41800 function presetCategory() {
41801 timeout(function() {
41802 d3.select('#curtain').style('pointer-events', 'none');
41803 var road = d3.select('.preset-category-road .preset-list-button');
41804 reveal(road.node(), t('intro.lines.road'));
41805 road.one('click.intro', roadCategory);
41809 function roadCategory() {
41810 timeout(function() {
41811 var grid = d3.select('.subgrid');
41812 reveal(grid.node(), t('intro.lines.residential'));
41813 grid.selectAll(':not(.preset-highway-residential) .preset-list-button')
41814 .one('click.intro', retryPreset);
41815 grid.selectAll('.preset-highway-residential .preset-list-button')
41816 .one('click.intro', roadDetails);
41820 // selected wrong road type
41821 function retryPreset() {
41822 timeout(function() {
41823 var preset = d3.select('.entity-editor-pane .preset-list-button');
41824 reveal(preset.node(), t('intro.lines.wrong_preset'));
41825 preset.one('click.intro', presetCategory);
41829 function roadDetails() {
41831 t('intro.lines.describe', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
41832 context.on('exit.intro', event.done);
41837 step.exit = function() {
41838 d3.select(window).on('mousedown.intro', null, true);
41839 d3.select('#curtain').style('pointer-events', 'none');
41840 timeouts.forEach(window.clearTimeout);
41841 context.on('enter.intro', null);
41842 context.on('exit.intro', null);
41843 context.map().on('move.intro', null);
41844 context.history().on('change.intro', null);
41847 return d3.rebind(step, event, 'on');
41849 iD.ui.intro.navigation = function(context, reveal) {
41850 var event = d3.dispatch('done'),
41854 title: 'intro.navigation.title'
41857 function set(f, t) {
41858 timeouts.push(window.setTimeout(f, t));
41861 function eventCancel() {
41862 d3.event.stopPropagation();
41863 d3.event.preventDefault();
41866 step.enter = function() {
41867 var rect = context.surfaceRect(),
41869 left: rect.left + 10,
41870 top: rect.top + 70,
41871 width: rect.width - 70,
41872 height: rect.height - 170
41875 context.map().centerZoom([-85.63591, 41.94285], 19);
41877 reveal(map, t('intro.navigation.drag'));
41879 context.map().on('move.intro', _.debounce(function() {
41880 context.map().on('move.intro', null);
41882 context.on('enter.intro', inspectTownHall);
41885 function townhall() {
41886 var hall = [-85.63645945147184, 41.942986488012565];
41888 var point = context.projection(hall);
41889 if (point[0] < 0 || point[0] > rect.width ||
41890 point[1] < 0 || point[1] > rect.height) {
41891 context.map().center(hall);
41894 var box = iD.ui.intro.pointBox(hall, context);
41895 reveal(box, t('intro.navigation.select'));
41897 context.map().on('move.intro', function() {
41898 var box = iD.ui.intro.pointBox(hall, context);
41899 reveal(box, t('intro.navigation.select'), {duration: 0});
41903 function inspectTownHall(mode) {
41904 if (mode.id !== 'select') return;
41905 context.on('enter.intro', null);
41906 context.map().on('move.intro', null);
41908 reveal('.entity-editor-pane',
41909 t('intro.navigation.pane', { button: iD.ui.intro.icon('#icon-close', 'pre-text') }));
41910 context.on('exit.intro', streetSearch);
41914 function streetSearch() {
41915 context.on('exit.intro', null);
41916 reveal('.search-header input',
41917 t('intro.navigation.search', { name: t('intro.graph.spring_st') }));
41918 d3.select('.search-header input').on('keyup.intro', searchResult);
41921 function searchResult() {
41922 var first = d3.select('.feature-list-item:nth-child(0n+2)'), // skip No Results item
41923 firstName = first.select('.entity-name'),
41924 name = t('intro.graph.spring_st');
41926 if (!firstName.empty() && firstName.text() === name) {
41927 reveal(first.node(), t('intro.navigation.choose', { name: name }));
41928 context.on('exit.intro', selectedStreet);
41929 d3.select('.search-header input')
41930 .on('keydown.intro', eventCancel, true)
41931 .on('keyup.intro', null);
41935 function selectedStreet() {
41936 var springSt = [-85.63585099140167, 41.942506848938926];
41937 context.map().center(springSt);
41938 context.on('exit.intro', event.done);
41940 reveal('.entity-editor-pane',
41941 t('intro.navigation.chosen', {
41942 name: t('intro.graph.spring_st'),
41943 button: iD.ui.intro.icon('#icon-close', 'pre-text')
41949 step.exit = function() {
41950 timeouts.forEach(window.clearTimeout);
41951 context.map().on('move.intro', null);
41952 context.on('enter.intro', null);
41953 context.on('exit.intro', null);
41954 d3.select('.search-header input')
41955 .on('keydown.intro', null)
41956 .on('keyup.intro', null);
41959 return d3.rebind(step, event, 'on');
41961 iD.ui.intro.point = function(context, reveal) {
41962 var event = d3.dispatch('done'),
41966 title: 'intro.points.title'
41969 function setTimeout(f, t) {
41970 timeouts.push(window.setTimeout(f, t));
41973 function eventCancel() {
41974 d3.event.stopPropagation();
41975 d3.event.preventDefault();
41978 step.enter = function() {
41979 context.map().centerZoom([-85.63279, 41.94394], 19);
41980 reveal('button.add-point',
41981 t('intro.points.add', { button: iD.ui.intro.icon('#icon-point', 'pre-text') }),
41982 { tooltipClass: 'intro-points-add' });
41984 var corner = [-85.632481,41.944094];
41986 context.on('enter.intro', addPoint);
41988 function addPoint(mode) {
41989 if (mode.id !== 'add-point') return;
41990 context.on('enter.intro', enterSelect);
41992 var pointBox = iD.ui.intro.pad(corner, 150, context);
41993 reveal(pointBox, t('intro.points.place'));
41995 context.map().on('move.intro', function() {
41996 pointBox = iD.ui.intro.pad(corner, 150, context);
41997 reveal(pointBox, t('intro.points.place'), {duration: 0});
42001 function enterSelect(mode) {
42002 if (mode.id !== 'select') return;
42003 context.map().on('move.intro', null);
42004 context.on('enter.intro', null);
42006 setTimeout(function() {
42007 reveal('.preset-search-input',
42008 t('intro.points.search', {name: context.presets().item('amenity/cafe').name()}));
42009 d3.select('.preset-search-input').on('keyup.intro', keySearch);
42013 function keySearch() {
42014 var first = d3.select('.preset-list-item:first-child');
42015 if (first.classed('preset-amenity-cafe')) {
42016 reveal(first.select('.preset-list-button').node(), t('intro.points.choose'));
42017 d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
42018 d3.select('.preset-search-input')
42019 .on('keydown.intro', eventCancel, true)
42020 .on('keyup.intro', null);
42024 function selectedPreset() {
42025 setTimeout(function() {
42026 reveal('.entity-editor-pane', t('intro.points.describe'), {tooltipClass: 'intro-points-describe'});
42027 context.history().on('change.intro', closeEditor);
42028 context.on('exit.intro', selectPoint);
42032 function closeEditor() {
42033 d3.select('.preset-search-input').on('keydown.intro', null);
42034 context.history().on('change.intro', null);
42035 reveal('.entity-editor-pane',
42036 t('intro.points.close', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
42039 function selectPoint() {
42040 context.on('exit.intro', null);
42041 context.history().on('change.intro', null);
42042 context.on('enter.intro', enterReselect);
42044 var pointBox = iD.ui.intro.pad(corner, 150, context);
42045 reveal(pointBox, t('intro.points.reselect'));
42047 context.map().on('move.intro', function() {
42048 pointBox = iD.ui.intro.pad(corner, 150, context);
42049 reveal(pointBox, t('intro.points.reselect'), {duration: 0});
42053 function enterReselect(mode) {
42054 if (mode.id !== 'select') return;
42055 context.map().on('move.intro', null);
42056 context.on('enter.intro', null);
42058 setTimeout(function() {
42059 reveal('.entity-editor-pane',
42060 t('intro.points.fixname', { button: iD.ui.intro.icon('#icon-apply', 'pre-text') }));
42061 context.on('exit.intro', deletePoint);
42065 function deletePoint() {
42066 context.on('exit.intro', null);
42067 context.on('enter.intro', enterDelete);
42069 var pointBox = iD.ui.intro.pad(corner, 150, context);
42070 reveal(pointBox, t('intro.points.reselect_delete'));
42072 context.map().on('move.intro', function() {
42073 pointBox = iD.ui.intro.pad(corner, 150, context);
42074 reveal(pointBox, t('intro.points.reselect_delete'), {duration: 0});
42078 function enterDelete(mode) {
42079 if (mode.id !== 'select') return;
42080 context.map().on('move.intro', null);
42081 context.on('enter.intro', null);
42082 context.on('exit.intro', deletePoint);
42083 context.map().on('move.intro', deletePoint);
42084 context.history().on('change.intro', deleted);
42086 setTimeout(function() {
42087 var node = d3.select('.radial-menu-item-delete').node();
42088 var pointBox = iD.ui.intro.pad(node.getBoundingClientRect(), 50, context);
42090 t('intro.points.delete', { button: iD.ui.intro.icon('#operation-delete', 'pre-text') }));
42094 function deleted(changed) {
42095 if (changed.deleted().length) event.done();
42100 step.exit = function() {
42101 timeouts.forEach(window.clearTimeout);
42102 context.on('exit.intro', null);
42103 context.on('enter.intro', null);
42104 context.map().on('move.intro', null);
42105 context.history().on('change.intro', null);
42106 d3.select('.preset-search-input')
42107 .on('keyup.intro', null)
42108 .on('keydown.intro', null);
42111 return d3.rebind(step, event, 'on');
42113 iD.ui.intro.startEditing = function(context, reveal) {
42114 var event = d3.dispatch('done', 'startEditing'),
42119 title: 'intro.startediting.title'
42122 function timeout(f, t) {
42123 timeouts.push(window.setTimeout(f, t));
42126 step.enter = function() {
42127 reveal('.map-control.help-control',
42128 t('intro.startediting.help', { button: iD.ui.intro.icon('#icon-help', 'pre-text') }));
42130 timeout(function() {
42131 reveal('#bar button.save', t('intro.startediting.save'));
42134 timeout(function() {
42135 reveal('#surface');
42138 timeout(function() {
42139 modal = iD.ui.modal(context.container());
42141 modal.select('.modal')
42142 .attr('class', 'modal-splash modal col6');
42144 modal.selectAll('.close').remove();
42146 var startbutton = modal.select('.content')
42147 .attr('class', 'fillL')
42149 .attr('class', 'modal-section huge-modal-button')
42150 .on('click', function() {
42154 startbutton.append('div')
42155 .attr('class','illustration');
42156 startbutton.append('h2')
42157 .text(t('intro.startediting.start'));
42159 event.startEditing();
42163 step.exit = function() {
42164 if (modal) modal.remove();
42165 timeouts.forEach(window.clearTimeout);
42168 return d3.rebind(step, event, 'on');
42170 iD.presets = function() {
42172 // an iD.presets.Collection with methods for
42173 // loading new data and returning defaults
42175 var all = iD.presets.Collection([]),
42176 defaults = { area: all, line: all, point: all, vertex: all, relation: all },
42179 recent = iD.presets.Collection([]);
42181 // Index of presets by (geometry, tag key).
42190 all.match = function(entity, resolver) {
42191 var geometry = entity.geometry(resolver),
42192 geometryMatches = index[geometry],
42196 for (var k in entity.tags) {
42197 var keyMatches = geometryMatches[k];
42198 if (!keyMatches) continue;
42200 for (var i = 0; i < keyMatches.length; i++) {
42201 var score = keyMatches[i].matchScore(entity);
42202 if (score > best) {
42204 match = keyMatches[i];
42209 return match || all.item(geometry);
42212 // Because of the open nature of tagging, iD will never have a complete
42213 // list of tags used in OSM, so we want it to have logic like "assume
42214 // that a closed way with an amenity tag is an area, unless the amenity
42215 // is one of these specific types". This function computes a structure
42216 // that allows testing of such conditions, based on the presets designated
42217 // as as supporting (or not supporting) the area geometry.
42219 // The returned object L is a whitelist/blacklist of tags. A closed way
42220 // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
42221 // (see `iD.Way#isArea()`). In other words, the keys of L form the whitelist,
42222 // and the subkeys form the blacklist.
42223 all.areaKeys = function() {
42225 ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],
42226 presets = _.reject(all.collection, 'suggestion');
42229 presets.forEach(function(d) {
42230 for (var key in d.tags) break;
42232 if (ignore.indexOf(key) !== -1) return;
42234 if (d.geometry.indexOf('area') !== -1) {
42235 areaKeys[key] = areaKeys[key] || {};
42240 presets.forEach(function(d) {
42241 for (var key in d.tags) break;
42243 if (ignore.indexOf(key) !== -1) return;
42245 var value = d.tags[key];
42246 if (d.geometry.indexOf('area') === -1 &&
42247 d.geometry.indexOf('line') !== -1 &&
42248 key in areaKeys && value !== '*') {
42249 areaKeys[key][value] = true;
42256 all.load = function(d) {
42259 _.forEach(d.fields, function(d, id) {
42260 fields[id] = iD.presets.Field(id, d);
42261 if (d.universal) universal.push(fields[id]);
42266 _.forEach(d.presets, function(d, id) {
42267 all.collection.push(iD.presets.Preset(id, d, fields));
42271 if (d.categories) {
42272 _.forEach(d.categories, function(d, id) {
42273 all.collection.push(iD.presets.Category(id, d, all));
42278 var getItem = _.bind(all.item, all);
42280 area: iD.presets.Collection(d.defaults.area.map(getItem)),
42281 line: iD.presets.Collection(d.defaults.line.map(getItem)),
42282 point: iD.presets.Collection(d.defaults.point.map(getItem)),
42283 vertex: iD.presets.Collection(d.defaults.vertex.map(getItem)),
42284 relation: iD.presets.Collection(d.defaults.relation.map(getItem))
42288 for (var i = 0; i < all.collection.length; i++) {
42289 var preset = all.collection[i],
42290 geometry = preset.geometry;
42292 for (var j = 0; j < geometry.length; j++) {
42293 var g = index[geometry[j]];
42294 for (var k in preset.tags) {
42295 (g[k] = g[k] || []).push(preset);
42303 all.field = function(id) {
42307 all.universal = function() {
42311 all.defaults = function(geometry, n) {
42312 var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
42313 def = _.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
42314 return iD.presets.Collection(_.uniq(rec.concat(def).concat(all.item(geometry))));
42317 all.choose = function(preset) {
42318 if (!preset.isFallback()) {
42319 recent = iD.presets.Collection(_.uniq([preset].concat(recent.collection)));
42326 iD.presets.Category = function(id, category, all) {
42327 category = _.clone(category);
42331 category.members = iD.presets.Collection(category.members.map(function(id) {
42332 return all.item(id);
42335 category.matchGeometry = function(geometry) {
42336 return category.geometry.indexOf(geometry) >= 0;
42339 category.matchScore = function() { return -1; };
42341 category.name = function() {
42342 return t('presets.categories.' + id + '.name', {'default': id});
42345 category.terms = function() {
42351 iD.presets.Collection = function(collection) {
42353 var maxSearchResults = 50,
42354 maxSuggestionResults = 10;
42358 collection: collection,
42360 item: function(id) {
42361 return _.find(collection, function(d) {
42362 return d.id === id;
42366 matchGeometry: function(geometry) {
42367 return iD.presets.Collection(collection.filter(function(d) {
42368 return d.matchGeometry(geometry);
42372 search: function(value, geometry) {
42373 if (!value) return this;
42375 value = value.toLowerCase();
42377 var searchable = _.filter(collection, function(a) {
42378 return a.searchable !== false && a.suggestion !== true;
42380 suggestions = _.filter(collection, function(a) {
42381 return a.suggestion === true;
42384 function leading(a) {
42385 var index = a.indexOf(value);
42386 return index === 0 || a[index - 1] === ' ';
42389 // matches value to preset.name
42390 var leading_name = _.filter(searchable, function(a) {
42391 return leading(a.name().toLowerCase());
42392 }).sort(function(a, b) {
42393 var i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
42394 if (i === 0) return a.name().length - b.name().length;
42398 // matches value to preset.terms values
42399 var leading_terms = _.filter(searchable, function(a) {
42400 return _.some(a.terms() || [], leading);
42403 // matches value to preset.tags values
42404 var leading_tag_values = _.filter(searchable, function(a) {
42405 return _.some(_.without(_.values(a.tags || {}), '*'), leading);
42409 // finds close matches to value in preset.name
42410 var levenstein_name = searchable.map(function(a) {
42413 dist: iD.util.editDistance(value, a.name().toLowerCase())
42415 }).filter(function(a) {
42416 return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
42417 }).sort(function(a, b) {
42418 return a.dist - b.dist;
42419 }).map(function(a) {
42423 // finds close matches to value in preset.terms
42424 var leventstein_terms = _.filter(searchable, function(a) {
42425 return _.some(a.terms() || [], function(b) {
42426 return iD.util.editDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
42430 function suggestionName(name) {
42431 var nameArray = name.split(' - ');
42432 if (nameArray.length > 1) {
42433 name = nameArray.slice(0, nameArray.length-1).join(' - ');
42435 return name.toLowerCase();
42438 var leading_suggestions = _.filter(suggestions, function(a) {
42439 return leading(suggestionName(a.name()));
42440 }).sort(function(a, b) {
42441 a = suggestionName(a.name());
42442 b = suggestionName(b.name());
42443 var i = a.indexOf(value) - b.indexOf(value);
42444 if (i === 0) return a.length - b.length;
42448 var leven_suggestions = suggestions.map(function(a) {
42451 dist: iD.util.editDistance(value, suggestionName(a.name()))
42453 }).filter(function(a) {
42454 return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
42455 }).sort(function(a, b) {
42456 return a.dist - b.dist;
42457 }).map(function(a) {
42461 var other = presets.item(geometry);
42463 var results = leading_name.concat(
42465 leading_tag_values,
42466 leading_suggestions.slice(0, maxSuggestionResults+5),
42469 leven_suggestions.slice(0, maxSuggestionResults)
42470 ).slice(0, maxSearchResults-1);
42472 return iD.presets.Collection(_.uniq(
42473 results.concat(other)
42480 iD.presets.Field = function(id, field) {
42481 field = _.clone(field);
42485 field.matchGeometry = function(geometry) {
42486 return !field.geometry || field.geometry === geometry;
42489 field.t = function(scope, options) {
42490 return t('presets.fields.' + id + '.' + scope, options);
42493 field.label = function() {
42494 return field.t('label', {'default': id});
42497 var placeholder = field.placeholder;
42498 field.placeholder = function() {
42499 return field.t('placeholder', {'default': placeholder});
42504 iD.presets.Preset = function(id, preset, fields) {
42505 preset = _.clone(preset);
42508 preset.fields = (preset.fields || []).map(getFields);
42509 preset.geometry = (preset.geometry || []);
42511 function getFields(f) {
42515 preset.matchGeometry = function(geometry) {
42516 return preset.geometry.indexOf(geometry) >= 0;
42519 var matchScore = preset.matchScore || 1;
42520 preset.matchScore = function(entity) {
42521 var tags = preset.tags,
42524 for (var t in tags) {
42525 if (entity.tags[t] === tags[t]) {
42526 score += matchScore;
42527 } else if (tags[t] === '*' && t in entity.tags) {
42528 score += matchScore / 2;
42537 preset.t = function(scope, options) {
42538 return t('presets.presets.' + id + '.' + scope, options);
42541 var name = preset.name;
42542 preset.name = function() {
42543 if (preset.suggestion) {
42544 id = id.split('/');
42545 id = id[0] + '/' + id[1];
42546 return name + ' - ' + t('presets.presets.' + id + '.name');
42548 return preset.t('name', {'default': name});
42551 preset.terms = function() {
42552 return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
42555 preset.isFallback = function() {
42556 var tagCount = Object.keys(preset.tags).length;
42557 return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
42560 preset.reference = function(geometry) {
42561 var key = Object.keys(preset.tags)[0],
42562 value = preset.tags[key];
42564 if (geometry === 'relation' && key === 'type') {
42565 return { rtype: value };
42566 } else if (value === '*') {
42567 return { key: key };
42569 return { key: key, value: value };
42573 var removeTags = preset.removeTags || preset.tags;
42574 preset.removeTags = function(tags, geometry) {
42575 tags = _.omit(tags, _.keys(removeTags));
42577 for (var f in preset.fields) {
42578 var field = preset.fields[f];
42579 if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
42580 delete tags[field.key];
42588 var applyTags = preset.addTags || preset.tags;
42589 preset.applyTags = function(tags, geometry) {
42592 tags = _.clone(tags);
42594 for (k in applyTags) {
42595 if (applyTags[k] === '*') {
42598 tags[k] = applyTags[k];
42602 // Add area=yes if necessary.
42603 // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
42604 // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
42605 // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
42606 if (geometry === 'area') {
42607 var needsAreaTag = true;
42608 if (preset.geometry.indexOf('line') === -1) {
42609 for (k in applyTags) {
42610 if (k in iD.areaKeys) {
42611 needsAreaTag = false;
42616 if (needsAreaTag) {
42621 for (var f in preset.fields) {
42622 var field = preset.fields[f];
42623 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
42624 tags[field.key] = field.default;
42633 iD.validations = {};
42634 iD.validations.DeprecatedTag = function() {
42636 var validation = function(changes) {
42638 for (var i = 0; i < changes.created.length; i++) {
42639 var change = changes.created[i],
42640 deprecatedTags = change.deprecatedTags();
42642 if (!_.isEmpty(deprecatedTags)) {
42643 var tags = iD.util.tagText({ tags: deprecatedTags });
42645 id: 'deprecated_tags',
42646 message: t('validations.deprecated_tags', { tags: tags }),
42656 iD.validations.ManyDeletions = function() {
42657 var threshold = 100;
42659 var validation = function(changes) {
42661 if (changes.deleted.length > threshold) {
42663 id: 'many_deletions',
42664 message: t('validations.many_deletions', { n: changes.deleted.length })
42672 iD.validations.MissingTag = function() {
42674 // Slightly stricter check than Entity#isUsed (#3091)
42675 function hasTags(entity, graph) {
42676 return _.without(Object.keys(entity.tags), 'area', 'name').length > 0 ||
42677 graph.parentRelations(entity).length > 0;
42680 var validation = function(changes, graph) {
42682 for (var i = 0; i < changes.created.length; i++) {
42683 var change = changes.created[i],
42684 geometry = change.geometry(graph);
42686 if ((geometry === 'point' || geometry === 'line' || geometry === 'area') && !hasTags(change, graph)) {
42689 message: t('validations.untagged_' + geometry),
42690 tooltip: t('validations.untagged_' + geometry + '_tooltip'),
42700 iD.validations.TagSuggestsArea = function() {
42702 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
42703 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
42704 function tagSuggestsArea(tags) {
42705 if (_.isEmpty(tags)) return false;
42707 var presence = ['landuse', 'amenities', 'tourism', 'shop'];
42708 for (var i = 0; i < presence.length; i++) {
42709 if (tags[presence[i]] !== undefined) {
42710 return presence[i] + '=' + tags[presence[i]];
42714 if (tags.building && tags.building === 'yes') return 'building=yes';
42717 var validation = function(changes, graph) {
42719 for (var i = 0; i < changes.created.length; i++) {
42720 var change = changes.created[i],
42721 geometry = change.geometry(graph),
42722 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
42726 id: 'tag_suggests_area',
42727 message: t('validations.tag_suggests_area', { tag: suggestion }),
42738 window.locale = { _current: 'en' };
42740 locale.current = function(_) {
42741 if (!arguments.length) return locale._current;
42742 if (locale[_] !== undefined) locale._current = _;
42743 else if (locale[_.split('-')[0]]) locale._current = _.split('-')[0];
42747 function t(s, o, loc) {
42748 loc = loc || locale._current;
42750 var path = s.split(".").reverse(),
42753 while (rep !== undefined && path.length) rep = rep[path.pop()];
42755 if (rep !== undefined) {
42756 if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
42760 if (loc !== 'en') {
42761 return t(s, o, 'en');
42764 if (o && 'default' in o) {
42765 return o['default'];
42768 var missing = 'Missing ' + loc + ' translation: ' + s;
42769 if (typeof console !== "undefined") console.error(missing);
42773 iD.introGraph = '{"n185954700":{"id":"n185954700","loc":[-85.642244,41.939081]},"n185964961":{"id":"n185964961","loc":[-85.6406588,41.942601]},"n185964962":{"id":"n185964962","loc":[-85.6394548,41.94261]},"n185970607":{"id":"n185970607","loc":[-85.641094,41.94006]},"n185970614":{"id":"n185970614","loc":[-85.641825,41.941316]},"n185970616":{"id":"n185970616","loc":[-85.641838,41.941556]},"n185973650":{"id":"n185973650","loc":[-85.639918,41.940064]},"n185973660":{"id":"n185973660","loc":[-85.640645,41.941339]},"n185973659":{"id":"n185973659","loc":[-85.6406115,41.9400658]},"n185974479":{"id":"n185974479","loc":[-85.639402,41.941344]},"n185974481":{"id":"n185974481","loc":[-85.643071,41.941288]},"n185976259":{"id":"n185976259","loc":[-85.642213,41.940043]},"n185976261":{"id":"n185976261","loc":[-85.643056,41.94001]},"n185964959":{"id":"n185964959","loc":[-85.6431031,41.9425754]},"n185964960":{"id":"n185964960","loc":[-85.6418749,41.9425864]},"n185981481":{"id":"n185981481","loc":[-85.6386827,41.9400828]},"n185981482":{"id":"n185981482","loc":[-85.6393664,41.9400854]},"n2138493844":{"id":"n2138493844","loc":[-85.6427969,41.940522]},"n2138493845":{"id":"n2138493845","loc":[-85.6425891,41.9405228]},"n2138493846":{"id":"n2138493846","loc":[-85.6425868,41.9402875]},"n2138493847":{"id":"n2138493847","loc":[-85.6427969,41.9402858]},"n2138493848":{"id":"n2138493848","loc":[-85.6425708,41.9405234]},"n2138493849":{"id":"n2138493849","loc":[-85.642568,41.9402855]},"n2138493850":{"id":"n2138493850","loc":[-85.6423157,41.9402886]},"n2138493851":{"id":"n2138493851","loc":[-85.6423212,41.9404362]},"n2138493852":{"id":"n2138493852","loc":[-85.6422923,41.9404578]},"n2138493853":{"id":"n2138493853","loc":[-85.6422868,41.9404834]},"n2138493854":{"id":"n2138493854","loc":[-85.6423226,41.9405091]},"n2138493855":{"id":"n2138493855","loc":[-85.6423847,41.9405111]},"n2138493856":{"id":"n2138493856","loc":[-85.6424081,41.9405265]},"n2140155811":{"id":"n2140155811","loc":[-85.6419547,41.9410956]},"n2140155814":{"id":"n2140155814","loc":[-85.6427577,41.9410884]},"n2140155816":{"id":"n2140155816","loc":[-85.6427545,41.9410052]},"n2140155818":{"id":"n2140155818","loc":[-85.6428057,41.9410028]},"n2140155821":{"id":"n2140155821","loc":[-85.6427993,41.9407339]},"n2140155823":{"id":"n2140155823","loc":[-85.6427385,41.9407339]},"n2140155825":{"id":"n2140155825","loc":[-85.6427417,41.9406435]},"n2140155827":{"id":"n2140155827","loc":[-85.6419515,41.9406482]},"n2140155828":{"id":"n2140155828","loc":[-85.6429368,41.9412407]},"n2140155829":{"id":"n2140155829","loc":[-85.6417756,41.9412526]},"n2140155830":{"id":"n2140155830","loc":[-85.641766,41.9405983]},"n2140155831":{"id":"n2140155831","loc":[-85.6419803,41.9405983]},"n2140155832":{"id":"n2140155832","loc":[-85.6419611,41.9401366]},"n2140155833":{"id":"n2140155833","loc":[-85.6429336,41.94012]},"n2140155834":{"id":"n2140155834","loc":[-85.6430697,41.9411732]},"n2140155835":{"id":"n2140155835","loc":[-85.6428411,41.9409974]},"n2140155837":{"id":"n2140155837","loc":[-85.6428388,41.9407211]},"n2140155839":{"id":"n2140155839","loc":[-85.6430624,41.9405521]},"n2140155840":{"id":"n2140155840","loc":[-85.6427323,41.9412396]},"n2140155842":{"id":"n2140155842","loc":[-85.6418147,41.9412457]},"n2140155844":{"id":"n2140155844","loc":[-85.641813,41.9411319]},"n2140155845":{"id":"n2140155845","loc":[-85.6418394,41.9411111]},"n2140155847":{"id":"n2140155847","loc":[-85.6418838,41.9410977]},"n2140155849":{"id":"n2140155849","loc":[-85.6427324,41.9410921]},"n2140155851":{"id":"n2140155851","loc":[-85.6427798,41.9412945]},"n2140155852":{"id":"n2140155852","loc":[-85.6427701,41.9411777]},"n2140155854":{"id":"n2140155854","loc":[-85.6427323,41.9411572]},"n2140155856":{"id":"n2140155856","loc":[-85.6418478,41.9411666]},"n2165942818":{"id":"n2165942818","loc":[-85.6437533,41.9415029]},"n2165942819":{"id":"n2165942819","loc":[-85.6437623,41.9421195]},"n2168510551":{"id":"n2168510551","loc":[-85.6423795,41.9422615]},"n2168510552":{"id":"n2168510552","loc":[-85.6423744,41.9419439]},"n2168510553":{"id":"n2168510553","loc":[-85.642518,41.9419427]},"n2168510554":{"id":"n2168510554","loc":[-85.6425186,41.9419801]},"n2168510555":{"id":"n2168510555","loc":[-85.6428314,41.9419773]},"n2168510556":{"id":"n2168510556","loc":[-85.6428368,41.9423116]},"n2168510557":{"id":"n2168510557","loc":[-85.6424947,41.9423146]},"n2168510558":{"id":"n2168510558","loc":[-85.6424938,41.9422605]},"n2189046007":{"id":"n2189046007","loc":[-85.6410866,41.9424327]},"n2189046009":{"id":"n2189046009","loc":[-85.6410805,41.9420061]},"n2189046011":{"id":"n2189046011","loc":[-85.6412443,41.9420048]},"n2189046012":{"id":"n2189046012","loc":[-85.6412505,41.9424314]},"n2189046014":{"id":"n2189046014","loc":[-85.6413311,41.942968]},"n2189046016":{"id":"n2189046016","loc":[-85.6413281,41.942713]},"n2189046018":{"id":"n2189046018","loc":[-85.641521,41.9427117]},"n2189046021":{"id":"n2189046021","loc":[-85.6415234,41.9429236]},"n2189046022":{"id":"n2189046022","loc":[-85.6415045,41.9429238]},"n2189046025":{"id":"n2189046025","loc":[-85.641505,41.9429668]},"n2189046053":{"id":"n2189046053","loc":[-85.6385988,41.942412]},"n2189046054":{"id":"n2189046054","loc":[-85.6385985,41.9423311]},"n2189046055":{"id":"n2189046055","loc":[-85.6387617,41.9423308]},"n2189046056":{"id":"n2189046056","loc":[-85.6387616,41.9423026]},"n2189046058":{"id":"n2189046058","loc":[-85.6388215,41.9423025]},"n2189046059":{"id":"n2189046059","loc":[-85.6388219,41.9424115]},"n2189046060":{"id":"n2189046060","loc":[-85.6391096,41.9424486]},"n2189046061":{"id":"n2189046061","loc":[-85.6391105,41.9423673]},"n2189046063":{"id":"n2189046063","loc":[-85.6392911,41.9423684]},"n2189046065":{"id":"n2189046065","loc":[-85.6392903,41.9424497]},"n2189046067":{"id":"n2189046067","loc":[-85.6397927,41.9423876]},"n2189046069":{"id":"n2189046069","loc":[-85.6397897,41.9422981]},"n2189046070":{"id":"n2189046070","loc":[-85.6399702,41.9422947]},"n2189046072":{"id":"n2189046072","loc":[-85.6399732,41.9423843]},"n2189046074":{"id":"n2189046074","loc":[-85.6396331,41.9430227]},"n2189046075":{"id":"n2189046075","loc":[-85.6398673,41.9430189]},"n2189046077":{"id":"n2189046077","loc":[-85.6398656,41.9429637]},"n2189046079":{"id":"n2189046079","loc":[-85.6398885,41.9429633]},"n2189046082":{"id":"n2189046082","loc":[-85.6398832,41.942779]},"n2189046083":{"id":"n2189046083","loc":[-85.6398513,41.9427796]},"n2189046085":{"id":"n2189046085","loc":[-85.6398502,41.9427401]},"n2189046087":{"id":"n2189046087","loc":[-85.6397889,41.9427411]},"n2189046089":{"id":"n2189046089","loc":[-85.6397892,41.942753]},"n2189046090":{"id":"n2189046090","loc":[-85.6396983,41.9427544]},"n2189046092":{"id":"n2189046092","loc":[-85.6396993,41.9427882]},"n2189046094":{"id":"n2189046094","loc":[-85.6396746,41.9427886]},"n2189046096":{"id":"n2189046096","loc":[-85.6396758,41.9428296]},"n2189046097":{"id":"n2189046097","loc":[-85.6397007,41.9428292]},"n2189046099":{"id":"n2189046099","loc":[-85.6397018,41.9428686]},"n2189046103":{"id":"n2189046103","loc":[-85.6396289,41.9428697]},"n2189046112":{"id":"n2189046112","loc":[-85.6435683,41.9429457]},"n2189046113":{"id":"n2189046113","loc":[-85.643568,41.9427766]},"n2189046115":{"id":"n2189046115","loc":[-85.6434011,41.9427767]},"n2189046116":{"id":"n2189046116","loc":[-85.6434012,41.9428631]},"n2189046117":{"id":"n2189046117","loc":[-85.643448,41.9428631]},"n2189046118":{"id":"n2189046118","loc":[-85.6434481,41.9429457]},"n2189046119":{"id":"n2189046119","loc":[-85.6428363,41.9429809]},"n2189046120":{"id":"n2189046120","loc":[-85.6429171,41.9429791]},"n2189046121":{"id":"n2189046121","loc":[-85.642914,41.9429041]},"n2189046122":{"id":"n2189046122","loc":[-85.6429385,41.9429035]},"n2189046123":{"id":"n2189046123","loc":[-85.6429348,41.9428126]},"n2189046124":{"id":"n2189046124","loc":[-85.6427746,41.9428163]},"n2189046125":{"id":"n2189046125","loc":[-85.6427783,41.942906]},"n2189046126":{"id":"n2189046126","loc":[-85.6428332,41.9429047]},"n2189046127":{"id":"n2189046127","loc":[-85.6423018,41.9428859]},"n2189046128":{"id":"n2189046128","loc":[-85.6422987,41.9427208]},"n2189046130":{"id":"n2189046130","loc":[-85.6424218,41.9427195]},"n2189046131":{"id":"n2189046131","loc":[-85.6424246,41.9428684]},"n2189046132":{"id":"n2189046132","loc":[-85.6423845,41.9428689]},"n2189046133":{"id":"n2189046133","loc":[-85.6423848,41.942885]},"n2189046134":{"id":"n2189046134","loc":[-85.641533,41.9429392]},"n2189046135":{"id":"n2189046135","loc":[-85.6416096,41.9428768]},"n2189046137":{"id":"n2189046137","loc":[-85.6416763,41.9429221]},"n2189046138":{"id":"n2189046138","loc":[-85.6415997,41.9429845]},"n2189046139":{"id":"n2189046139","loc":[-85.6420598,41.9428016]},"n2189046140":{"id":"n2189046140","loc":[-85.6420593,41.9427415]},"n2189046141":{"id":"n2189046141","loc":[-85.6421957,41.9427409]},"n2189046142":{"id":"n2189046142","loc":[-85.6421963,41.9428182]},"n2189046143":{"id":"n2189046143","loc":[-85.6421281,41.9428185]},"n2189046144":{"id":"n2189046144","loc":[-85.6421279,41.9428013]},"n2189046145":{"id":"n2189046145","loc":[-85.6409429,41.9429345]},"n2189046146":{"id":"n2189046146","loc":[-85.6410354,41.9429334]},"n2189046147":{"id":"n2189046147","loc":[-85.6410325,41.9427972]},"n2189046148":{"id":"n2189046148","loc":[-85.640997,41.9427976]},"n2189046149":{"id":"n2189046149","loc":[-85.6409963,41.9427643]},"n2189046150":{"id":"n2189046150","loc":[-85.6408605,41.9427659]},"n2189046152":{"id":"n2189046152","loc":[-85.6408623,41.9428482]},"n2189046153":{"id":"n2189046153","loc":[-85.640941,41.9428473]},"n2189152992":{"id":"n2189152992","loc":[-85.6437661,41.9422257]},"n2189152993":{"id":"n2189152993","loc":[-85.643768,41.9424067]},"n2189152994":{"id":"n2189152994","loc":[-85.6432176,41.9417705]},"n2189152995":{"id":"n2189152995","loc":[-85.6432097,41.941327]},"n2189152996":{"id":"n2189152996","loc":[-85.6436493,41.9413226]},"n2189152997":{"id":"n2189152997","loc":[-85.6436563,41.9417164]},"n2189152998":{"id":"n2189152998","loc":[-85.6435796,41.9417171]},"n2189152999":{"id":"n2189152999","loc":[-85.6435805,41.9417669]},"n2189153000":{"id":"n2189153000","loc":[-85.6438202,41.9414953]},"n2189153001":{"id":"n2189153001","loc":[-85.6438173,41.9413175]},"n2189153004":{"id":"n2189153004","loc":[-85.6432535,41.9418466]},"n2189153005":{"id":"n2189153005","loc":[-85.6433935,41.9418599]},"n2189153006":{"id":"n2189153006","loc":[-85.6434831,41.9418986]},"n2189153007":{"id":"n2189153007","loc":[-85.6435678,41.9419774]},"n2189153008":{"id":"n2189153008","loc":[-85.6435987,41.9420282]},"n2189153009":{"id":"n2189153009","loc":[-85.643438,41.9419573]},"n2189153010":{"id":"n2189153010","loc":[-85.6435284,41.9424676]},"n2189153011":{"id":"n2189153011","loc":[-85.6436207,41.9423631]},"n2189153012":{"id":"n2189153012","loc":[-85.6434957,41.9422973]},"n2189153013":{"id":"n2189153013","loc":[-85.6434457,41.9422458]},"n2189153014":{"id":"n2189153014","loc":[-85.6433976,41.9421772]},"n2189153015":{"id":"n2189153015","loc":[-85.6433861,41.9420785]},"n2189153016":{"id":"n2189153016","loc":[-85.6433765,41.9420313]},"n2189153017":{"id":"n2189153017","loc":[-85.6432207,41.9420284]},"n2189153018":{"id":"n2189153018","loc":[-85.6432245,41.9422759]},"n2189153019":{"id":"n2189153019","loc":[-85.6432649,41.9423474]},"n2189153020":{"id":"n2189153020","loc":[-85.6433226,41.9424132]},"n2189153021":{"id":"n2189153021","loc":[-85.6434111,41.9424704]},"n2189153022":{"id":"n2189153022","loc":[-85.6434591,41.9424347]},"n2189153025":{"id":"n2189153025","loc":[-85.6437669,41.9423073]},"n2189153026":{"id":"n2189153026","loc":[-85.6436611,41.942293]},"n2189153027":{"id":"n2189153027","loc":[-85.6435784,41.9422473]},"n2189153028":{"id":"n2189153028","loc":[-85.6435245,41.9421443]},"n2189153029":{"id":"n2189153029","loc":[-85.6435149,41.9420613]},"n2189153030":{"id":"n2189153030","loc":[-85.6433528,41.9419269]},"n2189153031":{"id":"n2189153031","loc":[-85.6432535,41.9419191]},"n2189153032":{"id":"n2189153032","loc":[-85.6430868,41.9419198]},"n2189153033":{"id":"n2189153033","loc":[-85.6434894,41.9420033]},"n2189153034":{"id":"n2189153034","loc":[-85.6432974,41.9419225]},"n2189153035":{"id":"n2189153035","loc":[-85.6433055,41.9421632]},"n2189153036":{"id":"n2189153036","loc":[-85.6433538,41.9422849]},"n2189153037":{"id":"n2189153037","loc":[-85.6434718,41.9423887]},"n2189153038":{"id":"n2189153038","loc":[-85.6436134,41.9422667]},"n2189153040":{"id":"n2189153040","loc":[-85.6438759,41.9414017]},"n2189153041":{"id":"n2189153041","loc":[-85.6438181,41.9413687]},"n2189153042":{"id":"n2189153042","loc":[-85.6436821,41.9413044]},"n2189153043":{"id":"n2189153043","loc":[-85.6435899,41.9412862]},"n2189153044":{"id":"n2189153044","loc":[-85.6433169,41.9417268]},"n2189153045":{"id":"n2189153045","loc":[-85.643301,41.9412859]},"n2189153046":{"id":"n2189153046","loc":[-85.6435531,41.9416981]},"n2189153047":{"id":"n2189153047","loc":[-85.6435427,41.9412863]},"n185948706":{"id":"n185948706","loc":[-85.6369439,41.940122]},"n185949348":{"id":"n185949348","loc":[-85.640039,41.931135]},"n185949870":{"id":"n185949870","loc":[-85.643195,41.949261]},"n185954680":{"id":"n185954680","loc":[-85.6337802,41.9401143]},"n185954784":{"id":"n185954784","loc":[-85.6487485,41.942527]},"n185958670":{"id":"n185958670","loc":[-85.637255,41.940104]},"n185958672":{"id":"n185958672","loc":[-85.636996,41.941355]},"n185960207":{"id":"n185960207","loc":[-85.634992,41.940118]},"n185963163":{"id":"n185963163","loc":[-85.638831,41.93398]},"n185963165":{"id":"n185963165","loc":[-85.640073,41.933968]},"n185963167":{"id":"n185963167","loc":[-85.641225,41.933972]},"n185963168":{"id":"n185963168","loc":[-85.642386,41.933952]},"n185964695":{"id":"n185964695","loc":[-85.6443608,41.9425645]},"n185964697":{"id":"n185964697","loc":[-85.644384,41.939941]},"n185964963":{"id":"n185964963","loc":[-85.6382347,41.9426146]},"n185964965":{"id":"n185964965","loc":[-85.637022,41.942622]},"n185964967":{"id":"n185964967","loc":[-85.6363706,41.9426606]},"n185964968":{"id":"n185964968","loc":[-85.6357988,41.9427748]},"n185964969":{"id":"n185964969","loc":[-85.6355409,41.9428465]},"n185964970":{"id":"n185964970","loc":[-85.6348729,41.9430443]},"n185966958":{"id":"n185966958","loc":[-85.641946,41.946413]},"n185966960":{"id":"n185966960","loc":[-85.643148,41.946389]},"n185967774":{"id":"n185967774","loc":[-85.641889,41.943852]},"n185967775":{"id":"n185967775","loc":[-85.641922,41.945121]},"n185967776":{"id":"n185967776","loc":[-85.641927,41.947544]},"n185967777":{"id":"n185967777","loc":[-85.641982,41.947622]},"n185969289":{"id":"n185969289","loc":[-85.63928,41.929221]},"n185969704":{"id":"n185969704","loc":[-85.6388186,41.9350099]},"n185969706":{"id":"n185969706","loc":[-85.6400709,41.9349957]},"n185969708":{"id":"n185969708","loc":[-85.6412214,41.9349827]},"n185969710":{"id":"n185969710","loc":[-85.6423509,41.934974]},"n185970602":{"id":"n185970602","loc":[-85.641293,41.931817]},"n185970604":{"id":"n185970604","loc":[-85.641258,41.932705]},"n185970605":{"id":"n185970605","loc":[-85.641148,41.936984]},"n185970606":{"id":"n185970606","loc":[-85.641112,41.938169]},"n185970906":{"id":"n185970906","loc":[-85.639454,41.943871]},"n185970908":{"id":"n185970908","loc":[-85.6394635,41.9450504]},"n185970909":{"id":"n185970909","loc":[-85.6394914,41.9451911]},"n185971368":{"id":"n185971368","loc":[-85.635769,41.940122]},"n185971978":{"id":"n185971978","loc":[-85.640003,41.936988]},"n185971980":{"id":"n185971980","loc":[-85.642299,41.936988]},"n185973633":{"id":"n185973633","loc":[-85.639023,41.92861]},"n185973635":{"id":"n185973635","loc":[-85.639153,41.928969]},"n185973637":{"id":"n185973637","loc":[-85.639213,41.929088]},"n185973639":{"id":"n185973639","loc":[-85.63935,41.929396]},"n185973641":{"id":"n185973641","loc":[-85.640143,41.931462]},"n185973644":{"id":"n185973644","loc":[-85.64019,41.931788]},"n185973646":{"id":"n185973646","loc":[-85.6401365,41.9327199]},"n185973648":{"id":"n185973648","loc":[-85.639983,41.938174]},"n185974477":{"id":"n185974477","loc":[-85.638206,41.941331]},"n185975928":{"id":"n185975928","loc":[-85.640683,41.94513]},"n185975930":{"id":"n185975930","loc":[-85.643102,41.945103]},"n185976255":{"id":"n185976255","loc":[-85.642424,41.931817]},"n185976257":{"id":"n185976257","loc":[-85.64242,41.932699]},"n185976258":{"id":"n185976258","loc":[-85.6422621,41.9381489]},"n185977452":{"id":"n185977452","loc":[-85.6457497,41.9398834]},"n185978772":{"id":"n185978772","loc":[-85.646656,41.939869]},"n185981472":{"id":"n185981472","loc":[-85.6388962,41.9321266]},"n185981474":{"id":"n185981474","loc":[-85.6388769,41.9327334]},"n185981476":{"id":"n185981476","loc":[-85.638829,41.934116]},"n185981478":{"id":"n185981478","loc":[-85.63876,41.937002]},"n185981480":{"id":"n185981480","loc":[-85.638682,41.93819]},"n185981999":{"id":"n185981999","loc":[-85.638194,41.9400866]},"n185982001":{"id":"n185982001","loc":[-85.646302,41.93988]},"n185982877":{"id":"n185982877","loc":[-85.640676,41.943867]},"n185982879":{"id":"n185982879","loc":[-85.640734,41.945887]},"n185985823":{"id":"n185985823","loc":[-85.643106,41.943841]},"n185985824":{"id":"n185985824","loc":[-85.643145,41.947641]},"n185985825":{"id":"n185985825","loc":[-85.643219,41.950829]},"n1475301385":{"id":"n1475301385","loc":[-85.6360612,41.9427042]},"n1475301397":{"id":"n1475301397","loc":[-85.6366651,41.9426328]},"n2139795811":{"id":"n2139795811","loc":[-85.6469154,41.9425427]},"n2139795830":{"id":"n2139795830","loc":[-85.6443194,41.9399444]},"n2139795834":{"id":"n2139795834","loc":[-85.6453506,41.9399002]},"n2139795837":{"id":"n2139795837","loc":[-85.645806,41.9398831]},"n2139858932":{"id":"n2139858932","loc":[-85.6351721,41.9429557]},"n2140019000":{"id":"n2140019000","loc":[-85.6359935,41.9427224]},"n2165942817":{"id":"n2165942817","loc":[-85.6442017,41.9414993]},"n2165942820":{"id":"n2165942820","loc":[-85.6442107,41.9421159]},"n2189152990":{"id":"n2189152990","loc":[-85.6442328,41.942404]},"n2189152991":{"id":"n2189152991","loc":[-85.6442309,41.9422229]},"n2189153002":{"id":"n2189153002","loc":[-85.6441329,41.9413147]},"n2189153003":{"id":"n2189153003","loc":[-85.6441357,41.9414925]},"n2189153023":{"id":"n2189153023","loc":[-85.6443453,41.9423074]},"n2189153024":{"id":"n2189153024","loc":[-85.6442318,41.9423045]},"n2189153039":{"id":"n2189153039","loc":[-85.6441343,41.9414025]},"w208643102":{"id":"w208643102","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153034","n2189153035","n2189153036","n2189153037","n2189153038"]},"w17966942":{"id":"w17966942","tags":{"highway":"residential","name":"Millard St"},"nodes":["n185954680","n185960207","n185971368","n185948706","n185958670","n185981999","n185981481","n185981482","n185973650","n185973659","n185970607","n185976259","n185976261","n2139795830","n185964697","n2139795834","n185977452","n2139795837","n185982001","n185978772"]},"w208643105":{"id":"w208643105","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153046","n2189153047"]},"w208631637":{"id":"w208631637","tags":{"area":"yes","building":"yes"},"nodes":["n2189046014","n2189046016","n2189046018","n2189046021","n2189046022","n2189046025","n2189046014"]},"w208643096":{"id":"w208643096","tags":{"amenity":"parking","area":"yes","fee":"no"},"nodes":["n2189152990","n2189153024","n2189152991","n2189152992","n2189153025","n2189152993","n2189152990"]},"w208631656":{"id":"w208631656","tags":{"area":"yes","building":"yes"},"nodes":["n2189046134","n2189046135","n2189046137","n2189046138","n2189046134"]},"w204003417":{"id":"w204003417","tags":{"area":"yes","building":"school"},"nodes":["n2140155811","n2140155814","n2140155816","n2140155818","n2140155821","n2140155823","n2140155825","n2140155827","n2140155811"]},"w208631654":{"id":"w208631654","tags":{"area":"yes","building":"yes"},"nodes":["n2189046127","n2189046128","n2189046130","n2189046131","n2189046132","n2189046133","n2189046127"]},"w17966327":{"id":"w17966327","tags":{"highway":"residential","name":"S Douglas Ave"},"nodes":["n185976261","n2140155839","n2140155834","n185974481","n2189153032","n185964959"]},"w41785752":{"id":"w41785752","tags":{"highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60","access":"yes"},"nodes":["n185954784","n2139795811","n185964695","n185964959","n185964960","n185964961","n185964962","n185964963","n185964965","n1475301397","n185964967","n1475301385","n2140019000","n185964968","n185964969","n2139858932","n185964970"]},"w203841842":{"id":"w203841842","tags":{"area":"yes","leisure":"playground"},"nodes":["n2138493848","n2138493849","n2138493850","n2138493851","n2138493852","n2138493853","n2138493854","n2138493855","n2138493856","n2138493848"]},"w208643103":{"id":"w208643103","tags":{"highway":"service"},"nodes":["n2189153039","n2189153040","n2189153041","n2189153042","n2189153043","n2189153047","n2189153045","n185974481"]},"w208643098":{"id":"w208643098","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153000","n2189153041","n2189153001","n2189153002","n2189153039","n2189153003","n2189153000"]},"w208631646":{"id":"w208631646","tags":{"area":"yes","building":"yes"},"nodes":["n2189046067","n2189046069","n2189046070","n2189046072","n2189046067"]},"w208631653":{"id":"w208631653","tags":{"area":"yes","building":"yes"},"nodes":["n2189046119","n2189046120","n2189046121","n2189046122","n2189046123","n2189046124","n2189046125","n2189046126","n2189046119"]},"w17966041":{"id":"w17966041","tags":{"highway":"residential","name":"S Lincoln Ave"},"nodes":["n185973659","n185973660","n185964961"]},"w208631645":{"id":"w208631645","tags":{"area":"yes","building":"yes"},"nodes":["n2189046060","n2189046061","n2189046063","n2189046065","n2189046060"]},"w206803397":{"id":"w206803397","tags":{"area":"yes","building":"yes"},"nodes":["n2168510551","n2168510552","n2168510553","n2168510554","n2168510555","n2168510556","n2168510557","n2168510558","n2168510551"]},"w17965792":{"id":"w17965792","tags":{"highway":"residential","name":"N Hooker Ave"},"nodes":["n185964962","n185970906","n185970908","n185970909"]},"w208631651":{"id":"w208631651","tags":{"area":"yes","building":"yes"},"nodes":["n2189046112","n2189046113","n2189046115","n2189046116","n2189046117","n2189046118","n2189046112"]},"w208631643":{"id":"w208631643","tags":{"area":"yes","building":"yes"},"nodes":["n2189046053","n2189046054","n2189046055","n2189046056","n2189046058","n2189046059","n2189046053"]},"w17966878":{"id":"w17966878","tags":{"highway":"residential","name":"S Hooker Ave"},"nodes":["n185981472","n185981474","n185963163","n185981476","n185969704","n185981478","n185981480","n185981481"]},"w17966102":{"id":"w17966102","tags":{"highway":"residential","name":"South St"},"nodes":["n185958672","n185974477","n185974479","n185973660","n185970614"]},"w208631660":{"id":"w208631660","tags":{"area":"yes","building":"yes"},"nodes":["n2189046145","n2189046146","n2189046147","n2189046148","n2189046149","n2189046150","n2189046152","n2189046153","n2189046145"]},"w208643101":{"id":"w208643101","tags":{"highway":"service"},"nodes":["n2189153023","n2189153024","n2189153025","n2189153026","n2189153038","n2189153027","n2189153028","n2189153029","n2189153033","n2189153009","n2189153030","n2189153034","n2189153031","n2189153032"]},"w204000205":{"id":"w204000205","tags":{"highway":"residential","name":"South St","oneway":"yes"},"nodes":["n185974481","n2140155851","n185970614"]},"w203841841":{"id":"w203841841","tags":{"area":"yes","leisure":"pitch","pitch":"basketball"},"nodes":["n2138493844","n2138493845","n2138493846","n2138493847","n2138493844"]},"w17965444":{"id":"w17965444","tags":{"highway":"residential","name":"N Grant Ave"},"nodes":["n185964960","n185967774","n185967775","n185966958","n185967776","n185967777"]},"w208631648":{"id":"w208631648","tags":{"area":"yes","building":"yes"},"nodes":["n2189046074","n2189046075","n2189046077","n2189046079","n2189046082","n2189046083","n2189046085","n2189046087","n2189046089","n2189046090","n2189046092","n2189046094","n2189046096","n2189046097","n2189046099","n2189046103","n2189046074"]},"w208643100":{"id":"w208643100","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153010","n2189153011","n2189153012","n2189153013","n2189153014","n2189153015","n2189153016","n2189153017","n2189153018","n2189153019","n2189153020","n2189153021","n2189153022","n2189153010"]},"w17965749":{"id":"w17965749","tags":{"highway":"residential","name":"S Grant Ave"},"nodes":["n185970614","n185970616","n185964960"]},"w206574482":{"id":"w206574482","tags":{"amenity":"library","area":"yes","building":"yes","name":"Three Rivers Public Library"},"nodes":["n2165942817","n2165942818","n2165942819","n2165942820","n2165942817"]},"w208643097":{"id":"w208643097","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189152994","n2189152995","n2189152996","n2189152997","n2189152998","n2189152999","n2189152994"]},"w17966879":{"id":"w17966879","tags":{"highway":"residential","name":"S Hooker Ave"},"nodes":["n185981482","n185974479","n185964962"]},"w17966325":{"id":"w17966325","tags":{"highway":"residential","name":"S Douglas Ave"},"nodes":["n185976255","n185976257","n185963168","n185969710","n185971980","n185976258","n185954700","n185976259"]},"w17967390":{"id":"w17967390","tags":{"highway":"residential","name":"N Douglas Ave"},"nodes":["n185964959","n185985823","n185975930","n185966960","n185985824","n185949870","n185985825"]},"w208631635":{"id":"w208631635","tags":{"area":"yes","building":"yes"},"nodes":["n2189046007","n2189046009","n2189046011","n2189046012","n2189046007"]},"w208643099":{"id":"w208643099","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153031","n2189153004","n2189153005","n2189153006","n2189153007","n2189153008","n2189153029","n2189153033","n2189153009","n2189153030","n2189153031"]},"w208631658":{"id":"w208631658","tags":{"area":"yes","building":"yes"},"nodes":["n2189046139","n2189046140","n2189046141","n2189046142","n2189046143","n2189046144","n2189046139"]},"w208643104":{"id":"w208643104","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153044","n2189153045"]},"w17966039":{"id":"w17966039","tags":{"highway":"residential","name":"S Lincoln Ave"},"nodes":["n185973633","n185973635","n185973637","n185969289","n185973639","n185949348","n185973641","n185973644","n185973646","n185963165","n185969706","n185971978","n185973648","n185973650"]},"w204003420":{"id":"w204003420","tags":{"amenity":"parking","area":"yes"},"nodes":["n2140155840","n2140155842","n2140155844","n2140155845","n2140155847","n2140155849","n2140155854","n2140155840"]},"w204003419":{"id":"w204003419","tags":{"highway":"service"},"nodes":["n2140155834","n2140155835","n2140155837","n2140155839"]},"w204003418":{"id":"w204003418","tags":{"amenity":"school","area":"yes","name":"Andrews Elementary School"},"nodes":["n2140155828","n2140155829","n2140155830","n2140155831","n2140155832","n2140155833","n2140155828"]},"w17965747":{"id":"w17965747","tags":{"highway":"residential","name":"S Grant Ave"},"nodes":["n185970602","n185970604","n185963167","n185969708","n185970605","n185970606","n185970607"]},"w17967073":{"id":"w17967073","tags":{"highway":"residential","name":"N Lincoln Ave"},"nodes":["n185964961","n185982877","n185975928","n185982879"]},"w204003421":{"id":"w204003421","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2140155851","n2140155852","n2140155854","n2140155856"]},"r1943857":{"id":"r1943857","tags":{"modifier":"Business","name":"US 131 Business (Three Rivers, MI)","network":"US:US","ref":"131","route":"road","type":"route"},"members":[{"id":"w17966509","type":"way","role":"forward"},{"id":"w143497377","type":"way","role":""},{"id":"w134150811","type":"way","role":""},{"id":"w134150800","type":"way","role":""},{"id":"w134150789","type":"way","role":""},{"id":"w134150795","type":"way","role":""},{"id":"w41785752","type":"way","role":""},{"id":"w17965146","type":"way","role":"forward"},{"id":"w17964031","type":"way","role":"forward"}]},"r270277":{"id":"r270277","tags":{"network":"US:MI","ref":"60","route":"road","state_id":"MI","type":"route","url":"http://en.wikipedia.org/wiki/M-60_%28Michigan_highway%29"},"members":[{"id":"w17751087","type":"way","role":"east"},{"id":"w117148312","type":"way","role":"east"},{"id":"w40942155","type":"way","role":"west"},{"id":"w17751017","type":"way","role":""},{"id":"w17751083","type":"way","role":""},{"id":"w17747780","type":"way","role":""},{"id":"w41068082","type":"way","role":""},{"id":"w197025212","type":"way","role":""},{"id":"w17743874","type":"way","role":""},{"id":"w17751044","type":"way","role":""},{"id":"w17752167","type":"way","role":""},{"id":"w17751089","type":"way","role":""},{"id":"w17743879","type":"way","role":""},{"id":"w17751064","type":"way","role":""},{"id":"w197057073","type":"way","role":""},{"id":"w167699963","type":"way","role":""},{"id":"w167699972","type":"way","role":""},{"id":"w17967584","type":"way","role":""},{"id":"w167699964","type":"way","role":""},{"id":"w17967582","type":"way","role":"west"},{"id":"w41260270","type":"way","role":"west"},{"id":"w17965146","type":"way","role":"west"},{"id":"w41785752","type":"way","role":""},{"id":"w134150795","type":"way","role":""},{"id":"w134150789","type":"way","role":""},{"id":"w134150800","type":"way","role":""},{"id":"w134150811","type":"way","role":""},{"id":"w134150836","type":"way","role":""},{"id":"w134150802","type":"way","role":""},{"id":"w41074896","type":"way","role":""},{"id":"w17966773","type":"way","role":""},{"id":"w17967415","type":"way","role":""},{"id":"w41074899","type":"way","role":""},{"id":"w17967581","type":"way","role":""},{"id":"w41074902","type":"way","role":""},{"id":"w41074906","type":"way","role":""},{"id":"w209707997","type":"way","role":""},{"id":"w209707998","type":"way","role":""},{"id":"w17964798","type":"way","role":""},{"id":"w17966034","type":"way","role":""},{"id":"w17967593","type":"way","role":""},{"id":"w41074888","type":"way","role":""},{"id":"w17733772","type":"way","role":""},{"id":"w41074813","type":"way","role":""},{"id":"w17742213","type":"way","role":""},{"id":"w17746863","type":"way","role":""},{"id":"w17745772","type":"way","role":""},{"id":"w17742222","type":"way","role":""},{"id":"w17745922","type":"way","role":""},{"id":"w17742198","type":"way","role":""},{"id":"w17747675","type":"way","role":""},{"id":"w17739927","type":"way","role":""},{"id":"w17745708","type":"way","role":""},{"id":"w41006323","type":"way","role":""},{"id":"w17744233","type":"way","role":""},{"id":"w17739436","type":"way","role":""},{"id":"w17742201","type":"way","role":""},{"id":"w151418616","type":"way","role":""},{"id":"w17750062","type":"way","role":""},{"id":"w17742227","type":"way","role":"east"},{"id":"w41006348","type":"way","role":"east"},{"id":"w41260984","type":"way","role":""},{"id":"w17832427","type":"way","role":""},{"id":"w17838408","type":"way","role":""},{"id":"w17835846","type":"way","role":""},{"id":"w17832923","type":"way","role":""},{"id":"w17839388","type":"way","role":""},{"id":"w17838390","type":"way","role":""},{"id":"w17831272","type":"way","role":""},{"id":"w17828581","type":"way","role":""},{"id":"w38240686","type":"way","role":""},{"id":"w17838405","type":"way","role":"east"},{"id":"w123323711","type":"way","role":"east"},{"id":"w17830167","type":"way","role":"east"},{"id":"w99011909","type":"way","role":"east"},{"id":"w41911361","type":"way","role":"east"},{"id":"w41911355","type":"way","role":"east"},{"id":"w41911356","type":"way","role":"east"},{"id":"w117148326","type":"way","role":"west"},{"id":"w41911352","type":"way","role":"west"},{"id":"w41911353","type":"way","role":"west"},{"id":"w41911354","type":"way","role":"west"},{"id":"w41911360","type":"way","role":"west"},{"id":"w38240676","type":"way","role":"west"},{"id":"w123323710","type":"way","role":"west"},{"id":"w41260271","type":"way","role":"east"},{"id":"w41260273","type":"way","role":"east"},{"id":"w17964031","type":"way","role":"east"},{"id":"w41006344","type":"way","role":"west"},{"id":"w41006351","type":"way","role":"west"}]},"n367813436":{"id":"n367813436","loc":[-85.63605205663384,41.94305506683346],"tags":{"amenity":"fire_station","name":"Three Rivers Fire Department"}},"n185948708":{"id":"n185948708","loc":[-85.6369828,41.9408789]},"n185948710":{"id":"n185948710","loc":[-85.6370184,41.9411346]},"n185954691":{"id":"n185954691","loc":[-85.634476,41.941475]},"n185954692":{"id":"n185954692","loc":[-85.635008,41.941846]},"n185954693":{"id":"n185954693","loc":[-85.635362,41.941962]},"n185954695":{"id":"n185954695","loc":[-85.63578,41.941978]},"n185972903":{"id":"n185972903","loc":[-85.63295,41.9430062]},"n185964971":{"id":"n185964971","loc":[-85.6346811,41.9431023]},"n1819805854":{"id":"n1819805854","loc":[-85.6331275,41.9404837]},"n1819805918":{"id":"n1819805918","loc":[-85.6331168,41.942798]},"n1819805762":{"id":"n1819805762","loc":[-85.6333034,41.9424123]},"n1819805907":{"id":"n1819805907","loc":[-85.6334819,41.9419121]},"n1819805915":{"id":"n1819805915","loc":[-85.6334554,41.9413588]},"n1819848888":{"id":"n1819848888","loc":[-85.6331625,41.942679]},"n1819848930":{"id":"n1819848930","loc":[-85.6338684,41.9431252]},"n1819858505":{"id":"n1819858505","loc":[-85.6346782,41.9429092]},"n1819858507":{"id":"n1819858507","loc":[-85.6339003,41.9414534]},"n1819858508":{"id":"n1819858508","loc":[-85.6345709,41.9427742]},"n1819858509":{"id":"n1819858509","loc":[-85.63419,41.9417322]},"n1819858511":{"id":"n1819858511","loc":[-85.6340666,41.9415652]},"n1819858512":{"id":"n1819858512","loc":[-85.6343295,41.9423027]},"n1819858514":{"id":"n1819858514","loc":[-85.6343241,41.942207]},"n1819858521":{"id":"n1819858521","loc":[-85.633391,41.941231]},"n1819858528":{"id":"n1819858528","loc":[-85.6343027,41.9419716]},"n185954683":{"id":"n185954683","loc":[-85.6335412,41.940147]},"n185954685":{"id":"n185954685","loc":[-85.6334296,41.9403023]},"n185954687":{"id":"n185954687","loc":[-85.6333988,41.9404704]},"n185954689":{"id":"n185954689","loc":[-85.6335511,41.9410225]},"n185954690":{"id":"n185954690","loc":[-85.6336721,41.9411669]},"n1820938802":{"id":"n1820938802","loc":[-85.6330671,41.941845]},"n1821006702":{"id":"n1821006702","loc":[-85.6344047,41.9395496]},"n2130304133":{"id":"n2130304133","loc":[-85.6349025,41.9427659]},"n2130304136":{"id":"n2130304136","loc":[-85.6346027,41.9422017]},"n2130304138":{"id":"n2130304138","loc":[-85.6348577,41.9421517]},"n2130304140":{"id":"n2130304140","loc":[-85.6348419,41.9422694]},"n2130304142":{"id":"n2130304142","loc":[-85.6349071,41.9423135]},"n2130304144":{"id":"n2130304144","loc":[-85.6350495,41.9423312]},"n2130304146":{"id":"n2130304146","loc":[-85.6351009,41.9422812]},"n2130304147":{"id":"n2130304147","loc":[-85.6351227,41.9421532]},"n2130304148":{"id":"n2130304148","loc":[-85.635526,41.9421547]},"n2130304149":{"id":"n2130304149","loc":[-85.6355339,41.9425768]},"n2130304150":{"id":"n2130304150","loc":[-85.6351582,41.9426562]},"n2130304151":{"id":"n2130304151","loc":[-85.6351207,41.9427032]},"n2138493807":{"id":"n2138493807","loc":[-85.6350923,41.9415216]},"n2138493808":{"id":"n2138493808","loc":[-85.6353603,41.9411061]},"n2138493809":{"id":"n2138493809","loc":[-85.6354421,41.9410942]},"n2138493810":{"id":"n2138493810","loc":[-85.6355079,41.9411044]},"n2138493811":{"id":"n2138493811","loc":[-85.6355693,41.9411246]},"n2138493812":{"id":"n2138493812","loc":[-85.6355829,41.9411061]},"n2138493813":{"id":"n2138493813","loc":[-85.6355624,41.9409777]},"n2138493814":{"id":"n2138493814","loc":[-85.6355011,41.9409152]},"n2138493815":{"id":"n2138493815","loc":[-85.635383,41.9409219]},"n2138493816":{"id":"n2138493816","loc":[-85.635299,41.9409658]},"n2138493817":{"id":"n2138493817","loc":[-85.6351695,41.941204]},"n2138493818":{"id":"n2138493818","loc":[-85.6348879,41.9415166]},"n2138493819":{"id":"n2138493819","loc":[-85.634897,41.9415757]},"n2138493820":{"id":"n2138493820","loc":[-85.6349606,41.9416399]},"n2138493821":{"id":"n2138493821","loc":[-85.6350219,41.9416669]},"n2138493822":{"id":"n2138493822","loc":[-85.6351241,41.9416314]},"n2138493823":{"id":"n2138493823","loc":[-85.6350855,41.9415622]},"n2138493824":{"id":"n2138493824","loc":[-85.6350401,41.9413603]},"n2138493825":{"id":"n2138493825","loc":[-85.6352206,41.9410765]},"n2138493826":{"id":"n2138493826","loc":[-85.6343865,41.9415594]},"n2138493827":{"id":"n2138493827","loc":[-85.6343506,41.9415873]},"n2138493828":{"id":"n2138493828","loc":[-85.6344158,41.9417557]},"n2138493829":{"id":"n2138493829","loc":[-85.6344614,41.9417968]},"n2138493830":{"id":"n2138493830","loc":[-85.6345005,41.9418186]},"n2138493831":{"id":"n2138493831","loc":[-85.6345965,41.9418162]},"n2138493832":{"id":"n2138493832","loc":[-85.6347317,41.9417242]},"n2138493833":{"id":"n2138493833","loc":[-85.6346722,41.941775]},"n2139858909":{"id":"n2139858909","loc":[-85.633403,41.9391006]},"n2139858910":{"id":"n2139858910","loc":[-85.6332973,41.9393967]},"n2139858911":{"id":"n2139858911","loc":[-85.633205,41.9396742]},"n2139858912":{"id":"n2139858912","loc":[-85.6332203,41.9397772]},"n2139858913":{"id":"n2139858913","loc":[-85.6333453,41.939936]},"n2139858914":{"id":"n2139858914","loc":[-85.6333761,41.9400018]},"n2139858915":{"id":"n2139858915","loc":[-85.63328,41.9402249]},"n2139858916":{"id":"n2139858916","loc":[-85.6332357,41.9403523]},"n2139858917":{"id":"n2139858917","loc":[-85.6332838,41.9405831]},"n2139858918":{"id":"n2139858918","loc":[-85.6333643,41.9408744]},"n2139858919":{"id":"n2139858919","loc":[-85.6334394,41.9410519]},"n2139858920":{"id":"n2139858920","loc":[-85.6335815,41.9411717]},"n2139858921":{"id":"n2139858921","loc":[-85.6337478,41.9412734]},"n2139858922":{"id":"n2139858922","loc":[-85.6343174,41.9415268]},"n2139858923":{"id":"n2139858923","loc":[-85.6343886,41.9417397]},"n2139858924":{"id":"n2139858924","loc":[-85.6344407,41.9418015]},"n2139858925":{"id":"n2139858925","loc":[-85.6345139,41.9418366]},"n2139858926":{"id":"n2139858926","loc":[-85.6344846,41.942005]},"n2139858927":{"id":"n2139858927","loc":[-85.6345775,41.9422218]},"n2139858928":{"id":"n2139858928","loc":[-85.6348771,41.9427814]},"n2139858929":{"id":"n2139858929","loc":[-85.6349487,41.9427995]},"n2139858930":{"id":"n2139858930","loc":[-85.6350415,41.9427874]},"n2139858931":{"id":"n2139858931","loc":[-85.6351246,41.9428589]},"n2139858978":{"id":"n2139858978","loc":[-85.6349658,41.9431481]},"n2139858979":{"id":"n2139858979","loc":[-85.6350081,41.9431287]},"n2139858980":{"id":"n2139858980","loc":[-85.6349967,41.9430997]},"n2139858981":{"id":"n2139858981","loc":[-85.6352158,41.9430352]},"n2139858982":{"id":"n2139858982","loc":[-85.6348174,41.94267]},"n2139858983":{"id":"n2139858983","loc":[-85.6346142,41.9425989]},"n2139858984":{"id":"n2139858984","loc":[-85.6344938,41.9423809]},"n2139858985":{"id":"n2139858985","loc":[-85.6344856,41.9422997]},"n2139870380":{"id":"n2139870380","loc":[-85.6346707,41.9417955]},"n2139870381":{"id":"n2139870381","loc":[-85.6345949,41.9418311]},"n2139870382":{"id":"n2139870382","loc":[-85.6343322,41.9418659]},"n2139870383":{"id":"n2139870383","loc":[-85.6342072,41.941885]},"n2139870384":{"id":"n2139870384","loc":[-85.6341325,41.9418919]},"n2139870385":{"id":"n2139870385","loc":[-85.6341314,41.9422028]},"n2139870386":{"id":"n2139870386","loc":[-85.6340472,41.9423271]},"n2139870387":{"id":"n2139870387","loc":[-85.6342185,41.9427933]},"n2139870388":{"id":"n2139870388","loc":[-85.6340605,41.9423924]},"n2139870389":{"id":"n2139870389","loc":[-85.6339889,41.9424069]},"n2139870390":{"id":"n2139870390","loc":[-85.633971,41.942356]},"n2139870391":{"id":"n2139870391","loc":[-85.63361,41.9424235]},"n2139870392":{"id":"n2139870392","loc":[-85.6337137,41.9426819]},"n2139870393":{"id":"n2139870393","loc":[-85.6336977,41.9428632]},"n2139870394":{"id":"n2139870394","loc":[-85.6338823,41.9428647]},"n2139870395":{"id":"n2139870395","loc":[-85.6339412,41.9430069]},"n2139870396":{"id":"n2139870396","loc":[-85.6338873,41.9430353]},"n2139870397":{"id":"n2139870397","loc":[-85.6337676,41.942815]},"n2139870398":{"id":"n2139870398","loc":[-85.6336822,41.9423505]},"n2139870399":{"id":"n2139870399","loc":[-85.634037,41.9422725]},"n2139870400":{"id":"n2139870400","loc":[-85.6340294,41.9422518]},"n2139870401":{"id":"n2139870401","loc":[-85.6336726,41.9423312]},"n2139870402":{"id":"n2139870402","loc":[-85.6342188,41.9425715]},"n2139870403":{"id":"n2139870403","loc":[-85.6342524,41.942565]},"n2139870404":{"id":"n2139870404","loc":[-85.6341438,41.942299]},"n2139870405":{"id":"n2139870405","loc":[-85.6341149,41.9423061]},"n2139870407":{"id":"n2139870407","loc":[-85.6340846,41.9431458]},"n2139870408":{"id":"n2139870408","loc":[-85.6339436,41.9429032]},"n2139870409":{"id":"n2139870409","loc":[-85.6343143,41.9428207]},"n2139870410":{"id":"n2139870410","loc":[-85.6343507,41.94277]},"n2139870411":{"id":"n2139870411","loc":[-85.6341527,41.942254]},"n2139870412":{"id":"n2139870412","loc":[-85.6340925,41.9422199]},"n2139870413":{"id":"n2139870413","loc":[-85.6335435,41.9423433]},"n2139870414":{"id":"n2139870414","loc":[-85.6335023,41.9423975]},"n2139870415":{"id":"n2139870415","loc":[-85.6335086,41.9424552]},"n2139870416":{"id":"n2139870416","loc":[-85.6336296,41.942665]},"n2139870417":{"id":"n2139870417","loc":[-85.6341396,41.9428596]},"n2139870418":{"id":"n2139870418","loc":[-85.6339701,41.9424487]},"n2139870419":{"id":"n2139870419","loc":[-85.6335514,41.9425294]},"n2139870420":{"id":"n2139870420","loc":[-85.6337406,41.9424929]},"n2139870421":{"id":"n2139870421","loc":[-85.6338939,41.9428687]},"n2139870422":{"id":"n2139870422","loc":[-85.6341323,41.9419538]},"n2139870423":{"id":"n2139870423","loc":[-85.6340321,41.9420376]},"n2139870424":{"id":"n2139870424","loc":[-85.6337648,41.942238]},"n2139870425":{"id":"n2139870425","loc":[-85.6337604,41.9422685]},"n2139870426":{"id":"n2139870426","loc":[-85.6337682,41.9422928]},"n2139870427":{"id":"n2139870427","loc":[-85.6338086,41.9423862]},"n2139870428":{"id":"n2139870428","loc":[-85.6349465,41.9416631]},"n2139870429":{"id":"n2139870429","loc":[-85.6351097,41.9416973]},"n2139870430":{"id":"n2139870430","loc":[-85.6353371,41.9416798]},"n2139870431":{"id":"n2139870431","loc":[-85.6349627,41.9422506]},"n2139870432":{"id":"n2139870432","loc":[-85.634979,41.9421815]},"n2139870433":{"id":"n2139870433","loc":[-85.634885,41.9421679]},"n2139870434":{"id":"n2139870434","loc":[-85.6348689,41.9422377]},"n2139870435":{"id":"n2139870435","loc":[-85.6349779,41.9419486]},"n2139870436":{"id":"n2139870436","loc":[-85.6349505,41.9418933]},"n2139870437":{"id":"n2139870437","loc":[-85.6347327,41.9419505]},"n2139870438":{"id":"n2139870438","loc":[-85.6347614,41.9420087]},"n2139870439":{"id":"n2139870439","loc":[-85.6351889,41.9416912]},"n2139870440":{"id":"n2139870440","loc":[-85.6351092,41.9418426]},"n2139870441":{"id":"n2139870441","loc":[-85.635086,41.9419659]},"n2139870442":{"id":"n2139870442","loc":[-85.6350584,41.9421466]},"n2139870443":{"id":"n2139870443","loc":[-85.6350993,41.9421606]},"n2139870444":{"id":"n2139870444","loc":[-85.6350993,41.9422132]},"n2139870445":{"id":"n2139870445","loc":[-85.6350794,41.9422855]},"n2139870446":{"id":"n2139870446","loc":[-85.6350474,41.9423159]},"n2139870447":{"id":"n2139870447","loc":[-85.6349251,41.9422998]},"n2139870448":{"id":"n2139870448","loc":[-85.634911,41.9422755]},"n2139870449":{"id":"n2139870449","loc":[-85.6349157,41.9422553]},"n2139870450":{"id":"n2139870450","loc":[-85.6347213,41.9419324]},"n2139870451":{"id":"n2139870451","loc":[-85.6349535,41.9418771]},"n2139870452":{"id":"n2139870452","loc":[-85.6350135,41.9419421]},"n2139870453":{"id":"n2139870453","loc":[-85.6348584,41.9418997]},"n2139870454":{"id":"n2139870454","loc":[-85.6348113,41.9418101]},"n2139870455":{"id":"n2139870455","loc":[-85.6347306,41.9417449]},"n2139870456":{"id":"n2139870456","loc":[-85.6349123,41.941776]},"n2139870457":{"id":"n2139870457","loc":[-85.6349423,41.9421448]},"n2139870458":{"id":"n2139870458","loc":[-85.6349436,41.9420652]},"n2139870459":{"id":"n2139870459","loc":[-85.6349136,41.9419963]},"n2139870460":{"id":"n2139870460","loc":[-85.6349814,41.9419789]},"n2139989328":{"id":"n2139989328","loc":[-85.6334188,41.9421725]},"n2139989330":{"id":"n2139989330","loc":[-85.6335087,41.9416308]},"n2139989335":{"id":"n2139989335","loc":[-85.6336856,41.9429371]},"n2139989337":{"id":"n2139989337","loc":[-85.6333713,41.9427217]},"n2139989339":{"id":"n2139989339","loc":[-85.6332912,41.9425383]},"n2139989341":{"id":"n2139989341","loc":[-85.6339369,41.9409198]},"n2139989344":{"id":"n2139989344","loc":[-85.634097,41.9409469]},"n2139989346":{"id":"n2139989346","loc":[-85.634137,41.9412852]},"n2139989348":{"id":"n2139989348","loc":[-85.6344536,41.9414151]},"n2139989350":{"id":"n2139989350","loc":[-85.6350794,41.9412392]},"n2139989351":{"id":"n2139989351","loc":[-85.6352541,41.9409387]},"n2139989353":{"id":"n2139989353","loc":[-85.6357198,41.9408007]},"n2139989355":{"id":"n2139989355","loc":[-85.6357235,41.9427088]},"n2139989357":{"id":"n2139989357","loc":[-85.6337119,41.9421256]},"n2139989359":{"id":"n2139989359","loc":[-85.6336913,41.9420655]},"n2139989360":{"id":"n2139989360","loc":[-85.633582,41.9420867]},"n2139989362":{"id":"n2139989362","loc":[-85.6336058,41.9421491]},"n2139989364":{"id":"n2139989364","loc":[-85.6339685,41.9410995]},"n2139989366":{"id":"n2139989366","loc":[-85.6339067,41.9411383]},"n2139989368":{"id":"n2139989368","loc":[-85.6339685,41.9411972]},"n2139989370":{"id":"n2139989370","loc":[-85.6340398,41.9411619]},"n2139870379":{"id":"n2139870379","loc":[-85.6348391,41.9416651]},"n2140006363":{"id":"n2140006363","loc":[-85.6353144,41.9430345]},"n2140006364":{"id":"n2140006364","loc":[-85.6349191,41.9431422]},"n2140018997":{"id":"n2140018997","loc":[-85.63645945147184,41.942986488012565],"tags":{"amenity":"townhall","name":"Three Rivers City Hall"}},"n2140018998":{"id":"n2140018998","loc":[-85.6370319,41.9427919]},"n2140018999":{"id":"n2140018999","loc":[-85.6360687,41.9427808]},"n2199856288":{"id":"n2199856288","loc":[-85.6344968,41.9407307]},"n2199856289":{"id":"n2199856289","loc":[-85.634492,41.9406036]},"n2199856290":{"id":"n2199856290","loc":[-85.634891,41.9406001]},"n2199856291":{"id":"n2199856291","loc":[-85.6348894,41.9405288]},"n2199856292":{"id":"n2199856292","loc":[-85.6349166,41.94053]},"n2199856293":{"id":"n2199856293","loc":[-85.6349166,41.9404956]},"n2199856294":{"id":"n2199856294","loc":[-85.6350219,41.9404956]},"n2199856295":{"id":"n2199856295","loc":[-85.6350251,41.94053]},"n2199856296":{"id":"n2199856296","loc":[-85.6350538,41.9405288]},"n2199856297":{"id":"n2199856297","loc":[-85.6350602,41.94079]},"n2199856298":{"id":"n2199856298","loc":[-85.6351703,41.9407912]},"n2199856299":{"id":"n2199856299","loc":[-85.6351688,41.9409171]},"n2199856300":{"id":"n2199856300","loc":[-85.6347889,41.9409135]},"n2199856301":{"id":"n2199856301","loc":[-85.6347921,41.94079]},"n2199856302":{"id":"n2199856302","loc":[-85.6348942,41.9407888]},"n2199856303":{"id":"n2199856303","loc":[-85.6348926,41.9407283]},"n185951869":{"id":"n185951869","loc":[-85.6387639,41.957288]},"n185958643":{"id":"n185958643","loc":[-85.636746,41.929221]},"n185958645":{"id":"n185958645","loc":[-85.636791,41.929363]},"n185958647":{"id":"n185958647","loc":[-85.6375975,41.9314987]},"n185958649":{"id":"n185958649","loc":[-85.637669,41.931667]},"n185958651":{"id":"n185958651","loc":[-85.637728,41.931901]},"n185958653":{"id":"n185958653","loc":[-85.637724,41.932187]},"n185958656":{"id":"n185958656","loc":[-85.637732,41.932761]},"n185958658":{"id":"n185958658","loc":[-85.637688,41.93398]},"n185958660":{"id":"n185958660","loc":[-85.637685,41.934223]},"n185958662":{"id":"n185958662","loc":[-85.6376468,41.9350232]},"n185958664":{"id":"n185958664","loc":[-85.637564,41.937028]},"n185958666":{"id":"n185958666","loc":[-85.637458,41.938197]},"n185958668":{"id":"n185958668","loc":[-85.637424,41.938692]},"n185964972":{"id":"n185964972","loc":[-85.6341901,41.9432732]},"n185971361":{"id":"n185971361","loc":[-85.635762,41.938208]},"n185971364":{"id":"n185971364","loc":[-85.635732,41.9384]},"n185971366":{"id":"n185971366","loc":[-85.635736,41.938697]},"n185972775":{"id":"n185972775","loc":[-85.635638,42.070357]},"n185972777":{"id":"n185972777","loc":[-85.635724,42.069929]},"n185972779":{"id":"n185972779","loc":[-85.635804,42.069248]},"n185972781":{"id":"n185972781","loc":[-85.635869,42.068361]},"n185972783":{"id":"n185972783","loc":[-85.635883,42.067582]},"n185972785":{"id":"n185972785","loc":[-85.635875,42.067114]},"n185972787":{"id":"n185972787","loc":[-85.635778,42.065359]},"n185972788":{"id":"n185972788","loc":[-85.635728,42.063416]},"n185972789":{"id":"n185972789","loc":[-85.635665,42.062491]},"n185972790":{"id":"n185972790","loc":[-85.635617,42.061928]},"n185972791":{"id":"n185972791","loc":[-85.635614,42.061898]},"n185972793":{"id":"n185972793","loc":[-85.635379,42.060288]},"n185972795":{"id":"n185972795","loc":[-85.635092,42.05799]},"n185972797":{"id":"n185972797","loc":[-85.634843,42.055781]},"n185972798":{"id":"n185972798","loc":[-85.634817,42.055549]},"n185972800":{"id":"n185972800","loc":[-85.634708,42.053942]},"n185972802":{"id":"n185972802","loc":[-85.634447,42.051809]},"n185972805":{"id":"n185972805","loc":[-85.634241,42.04946]},"n185972807":{"id":"n185972807","loc":[-85.633787,42.045926]},"n185972809":{"id":"n185972809","loc":[-85.633811,42.045645]},"n185972811":{"id":"n185972811","loc":[-85.63373,42.043626]},"n185972813":{"id":"n185972813","loc":[-85.633698,42.042184]},"n185972814":{"id":"n185972814","loc":[-85.63369,42.04181]},"n185972815":{"id":"n185972815","loc":[-85.633681,42.040714]},"n185972816":{"id":"n185972816","loc":[-85.633571,42.036322]},"n185972817":{"id":"n185972817","loc":[-85.633537,42.034044]},"n185972819":{"id":"n185972819","loc":[-85.633481,42.030785]},"n185972821":{"id":"n185972821","loc":[-85.633452,42.027538]},"n185972824":{"id":"n185972824","loc":[-85.633438,42.027427]},"n185972826":{"id":"n185972826","loc":[-85.633342,42.022656]},"n185972830":{"id":"n185972830","loc":[-85.63327,42.020724]},"n185972832":{"id":"n185972832","loc":[-85.633198,42.019106]},"n185972834":{"id":"n185972834","loc":[-85.633249,42.018363]},"n185972835":{"id":"n185972835","loc":[-85.633139,42.012944]},"n185972836":{"id":"n185972836","loc":[-85.63309,42.008284]},"n185972839":{"id":"n185972839","loc":[-85.63298,42.00005]},"n185972845":{"id":"n185972845","loc":[-85.6325369,41.9764959]},"n185972847":{"id":"n185972847","loc":[-85.6327549,41.9750005]},"n185972849":{"id":"n185972849","loc":[-85.6329374,41.9742527]},"n185972851":{"id":"n185972851","loc":[-85.6331387,41.9736039]},"n185972862":{"id":"n185972862","loc":[-85.6383589,41.9585023]},"n185972868":{"id":"n185972868","loc":[-85.6393633,41.9551716]},"n185972878":{"id":"n185972878","loc":[-85.639377,41.95335]},"n185972882":{"id":"n185972882","loc":[-85.6389179,41.9516944]},"n185972885":{"id":"n185972885","loc":[-85.6387444,41.9512105]},"n185972891":{"id":"n185972891","loc":[-85.636421,41.946392]},"n185972895":{"id":"n185972895","loc":[-85.635965,41.945809]},"n185972897":{"id":"n185972897","loc":[-85.635683,41.945449]},"n185972899":{"id":"n185972899","loc":[-85.635281,41.9450252]},"n185972905":{"id":"n185972905","loc":[-85.6324428,41.9425743]},"n185985217":{"id":"n185985217","loc":[-85.638243,41.943674]},"n185985219":{"id":"n185985219","loc":[-85.638228,41.943747]},"n185985221":{"id":"n185985221","loc":[-85.638163,41.943797]},"n185985222":{"id":"n185985222","loc":[-85.638089,41.943832]},"n185985223":{"id":"n185985223","loc":[-85.637969,41.943841]},"n185985225":{"id":"n185985225","loc":[-85.637841,41.943833]},"n185985227":{"id":"n185985227","loc":[-85.637601,41.943789]},"n185985229":{"id":"n185985229","loc":[-85.637449,41.943754]},"n185985231":{"id":"n185985231","loc":[-85.637342,41.943734]},"n185985233":{"id":"n185985233","loc":[-85.637218,41.943703]},"n185985235":{"id":"n185985235","loc":[-85.637151,41.943663]},"n185985238":{"id":"n185985238","loc":[-85.637118,41.943615]},"n185985240":{"id":"n185985240","loc":[-85.637073,41.943494]},"n185990434":{"id":"n185990434","loc":[-85.6329028,41.9984292],"tags":{"railway":"level_crossing"}},"n1475284023":{"id":"n1475284023","loc":[-85.6336163,41.9435806],"tags":{"railway":"level_crossing"}},"n1475293222":{"id":"n1475293222","loc":[-85.6394045,41.953658],"tags":{"railway":"level_crossing"}},"n1475293226":{"id":"n1475293226","loc":[-85.6364975,41.9638663],"tags":{"railway":"level_crossing"}},"n1475293234":{"id":"n1475293234","loc":[-85.6390449,41.9565145]},"n1475293240":{"id":"n1475293240","loc":[-85.636943,41.9473114]},"n1475293252":{"id":"n1475293252","loc":[-85.6392115,41.9559003]},"n1475293254":{"id":"n1475293254","loc":[-85.6348931,41.9685127],"tags":{"railway":"level_crossing"}},"n1475293260":{"id":"n1475293260","loc":[-85.6375999,41.9485401]},"n1475293261":{"id":"n1475293261","loc":[-85.6391256,41.9523817],"tags":{"railway":"level_crossing"}},"n1475293264":{"id":"n1475293264","loc":[-85.6394155,41.9546493],"tags":{"railway":"level_crossing"}},"n1819805614":{"id":"n1819805614","loc":[-85.6345652,41.9363097]},"n1819805618":{"id":"n1819805618","loc":[-85.6295334,41.9426862]},"n1819805622":{"id":"n1819805622","loc":[-85.6308208,41.9430773]},"n1819805626":{"id":"n1819805626","loc":[-85.6274734,41.9406592]},"n1819805629":{"id":"n1819805629","loc":[-85.6296943,41.9430533]},"n1819805632":{"id":"n1819805632","loc":[-85.6340931,41.9354477]},"n1819805636":{"id":"n1819805636","loc":[-85.6304131,41.9436598]},"n1819805639":{"id":"n1819805639","loc":[-85.6304882,41.9426623]},"n1819805641":{"id":"n1819805641","loc":[-85.6336103,41.9367487]},"n1819805643":{"id":"n1819805643","loc":[-85.6300376,41.9418084]},"n1819805645":{"id":"n1819805645","loc":[-85.6365286,41.9336679]},"n1819805647":{"id":"n1819805647","loc":[-85.632016,41.9429221]},"n1819805666":{"id":"n1819805666","loc":[-85.6314753,41.9442663]},"n1819805669":{"id":"n1819805669","loc":[-85.6268619,41.9402203]},"n1819805673":{"id":"n1819805673","loc":[-85.6296728,41.9412099]},"n1819805676":{"id":"n1819805676","loc":[-85.6354557,41.932766]},"n1819805680":{"id":"n1819805680","loc":[-85.632752,41.9431012]},"n1819805683":{"id":"n1819805683","loc":[-85.631147,41.9432014]},"n1819805687":{"id":"n1819805687","loc":[-85.635284,41.9343942]},"n1819805690":{"id":"n1819805690","loc":[-85.6249736,41.9405794]},"n1819805694":{"id":"n1819805694","loc":[-85.6294153,41.9417925]},"n1819805698":{"id":"n1819805698","loc":[-85.6323486,41.9426986]},"n1819805702":{"id":"n1819805702","loc":[-85.6340287,41.9373871]},"n1819805707":{"id":"n1819805707","loc":[-85.6353698,41.9316326]},"n1819805711":{"id":"n1819805711","loc":[-85.6284176,41.940356]},"n1819805715":{"id":"n1819805715","loc":[-85.6291471,41.9412897]},"n1819805718":{"id":"n1819805718","loc":[-85.6311105,41.943979]},"n1819805722":{"id":"n1819805722","loc":[-85.6320868,41.9400128]},"n1819805724":{"id":"n1819805724","loc":[-85.635166,41.9324627]},"n1819805727":{"id":"n1819805727","loc":[-85.6344686,41.9350567]},"n1819805728":{"id":"n1819805728","loc":[-85.6357132,41.9332369]},"n1819805731":{"id":"n1819805731","loc":[-85.629984,41.9434444]},"n1819805760":{"id":"n1819805760","loc":[-85.6330996,41.9378784]},"n1819805766":{"id":"n1819805766","loc":[-85.625274,41.9411141]},"n1819805770":{"id":"n1819805770","loc":[-85.6326321,41.9412173]},"n1819805774":{"id":"n1819805774","loc":[-85.6347047,41.9312096]},"n1819805777":{"id":"n1819805777","loc":[-85.6363569,41.9339552]},"n1819805780":{"id":"n1819805780","loc":[-85.6327392,41.941926]},"n1819805783":{"id":"n1819805783","loc":[-85.6357239,41.9338435]},"n1819805786":{"id":"n1819805786","loc":[-85.6356595,41.9346576]},"n1819805789":{"id":"n1819805789","loc":[-85.6316469,41.9436598]},"n1819805792":{"id":"n1819805792","loc":[-85.6350587,41.9354557]},"n1819805795":{"id":"n1819805795","loc":[-85.6360028,41.9322791]},"n1819805798":{"id":"n1819805798","loc":[-85.63125,41.9443062]},"n1819805802":{"id":"n1819805802","loc":[-85.6263362,41.9408109]},"n1819805805":{"id":"n1819805805","loc":[-85.6315075,41.9438753]},"n1819805808":{"id":"n1819805808","loc":[-85.6340008,41.9316051]},"n1819805810":{"id":"n1819805810","loc":[-85.6345545,41.9320557]},"n1819805812":{"id":"n1819805812","loc":[-85.6250809,41.9408587]},"n1819805814":{"id":"n1819805814","loc":[-85.6257783,41.9400926]},"n1819805834":{"id":"n1819805834","loc":[-85.6326408,41.9424363]},"n1819805838":{"id":"n1819805838","loc":[-85.6365607,41.9334365]},"n1819805842":{"id":"n1819805842","loc":[-85.6288253,41.9410343]},"n1819805846":{"id":"n1819805846","loc":[-85.6279133,41.9402921]},"n1819805849":{"id":"n1819805849","loc":[-85.6289433,41.9405156]},"n1819805852":{"id":"n1819805852","loc":[-85.6313787,41.9439152]},"n1819805858":{"id":"n1819805858","loc":[-85.6300805,41.9420398]},"n1819805861":{"id":"n1819805861","loc":[-85.6321941,41.9396297]},"n1819805864":{"id":"n1819805864","loc":[-85.6329129,41.9393903]},"n1819805868":{"id":"n1819805868","loc":[-85.632001,41.9434922]},"n1819805870":{"id":"n1819805870","loc":[-85.6314903,41.9431535]},"n1819805873":{"id":"n1819805873","loc":[-85.6251667,41.9401166]},"n1819805876":{"id":"n1819805876","loc":[-85.63287,41.939941]},"n1819805878":{"id":"n1819805878","loc":[-85.6307886,41.9437317]},"n1819805880":{"id":"n1819805880","loc":[-85.6321727,41.940348]},"n1819805883":{"id":"n1819805883","loc":[-85.6265872,41.940113]},"n1819805885":{"id":"n1819805885","loc":[-85.6268404,41.9406672]},"n1819805887":{"id":"n1819805887","loc":[-85.6325267,41.9389035]},"n1819805889":{"id":"n1819805889","loc":[-85.6364964,41.933189]},"n1819805911":{"id":"n1819805911","loc":[-85.6248663,41.9401804]},"n1819805922":{"id":"n1819805922","loc":[-85.633267,41.9387199]},"n1819805925":{"id":"n1819805925","loc":[-85.6293402,41.9408428]},"n1819848849":{"id":"n1819848849","loc":[-85.6464957,41.9695178]},"n1819848850":{"id":"n1819848850","loc":[-85.6497642,41.9611355]},"n1819848851":{"id":"n1819848851","loc":[-85.6480943,41.9624818]},"n1819848854":{"id":"n1819848854","loc":[-85.6500362,41.9657367]},"n1819848855":{"id":"n1819848855","loc":[-85.6493673,41.9783496]},"n1819848856":{"id":"n1819848856","loc":[-85.6457409,41.9548007]},"n1819848857":{"id":"n1819848857","loc":[-85.651313,41.9760426]},"n1819848858":{"id":"n1819848858","loc":[-85.6495819,41.9784772]},"n1819848859":{"id":"n1819848859","loc":[-85.6495105,41.9833722]},"n1819848860":{"id":"n1819848860","loc":[-85.6405053,41.9492792]},"n1819848863":{"id":"n1819848863","loc":[-85.6502293,41.9786826]},"n1819848865":{"id":"n1819848865","loc":[-85.6406877,41.9495106]},"n1819848870":{"id":"n1819848870","loc":[-85.6493136,41.9704611]},"n1819848871":{"id":"n1819848871","loc":[-85.6372249,41.9441284]},"n1819848873":{"id":"n1819848873","loc":[-85.6512379,41.9659441]},"n1819848875":{"id":"n1819848875","loc":[-85.6508087,41.9650187]},"n1819848877":{"id":"n1819848877","loc":[-85.6487166,41.9605352]},"n1819848878":{"id":"n1819848878","loc":[-85.6506478,41.9760665]},"n1819848879":{"id":"n1819848879","loc":[-85.651431,41.9758512]},"n1819848886":{"id":"n1819848886","loc":[-85.6477617,41.9563945]},"n1819848889":{"id":"n1819848889","loc":[-85.6497895,41.9832286]},"n1819848892":{"id":"n1819848892","loc":[-85.6504868,41.9791931]},"n1819848893":{"id":"n1819848893","loc":[-85.6498002,41.9615085]},"n1819848894":{"id":"n1819848894","loc":[-85.6404302,41.9502846]},"n1819848901":{"id":"n1819848901","loc":[-85.6354412,41.9439886]},"n1819848903":{"id":"n1819848903","loc":[-85.6472145,41.9698528]},"n1819848904":{"id":"n1819848904","loc":[-85.6401979,41.9486233]},"n1819848905":{"id":"n1819848905","loc":[-85.6475042,41.963503]},"n1819848909":{"id":"n1819848909","loc":[-85.6343405,41.94358]},"n1819848914":{"id":"n1819848914","loc":[-85.6503474,41.9737773]},"n1819848915":{"id":"n1819848915","loc":[-85.6389533,41.9470992]},"n1819848916":{"id":"n1819848916","loc":[-85.6483625,41.9577907]},"n1819848917":{"id":"n1819848917","loc":[-85.6484768,41.9617419]},"n1819848918":{"id":"n1819848918","loc":[-85.644078,41.9545693]},"n1819848919":{"id":"n1819848919","loc":[-85.6437169,41.9543041]},"n1819848920":{"id":"n1819848920","loc":[-85.6478331,41.9627949]},"n1819848922":{"id":"n1819848922","loc":[-85.6499144,41.9785889]},"n1819848924":{"id":"n1819848924","loc":[-85.647633,41.9720066]},"n1819848926":{"id":"n1819848926","loc":[-85.6487987,41.978868]},"n1819848927":{"id":"n1819848927","loc":[-85.6495105,41.9730355]},"n1819848928":{"id":"n1819848928","loc":[-85.648223,41.9829654]},"n1819848929":{"id":"n1819848929","loc":[-85.6514846,41.9659122]},"n1819848931":{"id":"n1819848931","loc":[-85.6498753,41.9731871]},"n1819848932":{"id":"n1819848932","loc":[-85.640906,41.9508575]},"n1819848933":{"id":"n1819848933","loc":[-85.649775,41.9799767]},"n1819848934":{"id":"n1819848934","loc":[-85.6507014,41.9739927]},"n1819848937":{"id":"n1819848937","loc":[-85.6479763,41.9840899]},"n1819848938":{"id":"n1819848938","loc":[-85.6501113,41.9600884]},"n1819848939":{"id":"n1819848939","loc":[-85.6389962,41.9478253]},"n1819848941":{"id":"n1819848941","loc":[-85.637469,41.9445791]},"n1819848942":{"id":"n1819848942","loc":[-85.6494569,41.9601682]},"n1819848943":{"id":"n1819848943","loc":[-85.6368803,41.9439351]},"n1819848945":{"id":"n1819848945","loc":[-85.6474398,41.9724213]},"n1819848946":{"id":"n1819848946","loc":[-85.6382629,41.9463666]},"n1819848948":{"id":"n1819848948","loc":[-85.6489633,41.9830771]},"n1819848952":{"id":"n1819848952","loc":[-85.6488882,41.9600326]},"n1819848953":{"id":"n1819848953","loc":[-85.6488094,41.9774324]},"n1819848954":{"id":"n1819848954","loc":[-85.6491135,41.9600485]},"n1819848955":{"id":"n1819848955","loc":[-85.6501435,41.9734583]},"n1819848956":{"id":"n1819848956","loc":[-85.6495534,41.960958]},"n1819848958":{"id":"n1819848958","loc":[-85.6474683,41.9561491]},"n1819848959":{"id":"n1819848959","loc":[-85.6401083,41.9485451]},"n1819848960":{"id":"n1819848960","loc":[-85.6481764,41.9678686]},"n1819848961":{"id":"n1819848961","loc":[-85.6484017,41.967382]},"n1819848962":{"id":"n1819848962","loc":[-85.6501328,41.959897]},"n1819848964":{"id":"n1819848964","loc":[-85.6403695,41.9504586]},"n1819848966":{"id":"n1819848966","loc":[-85.6398975,41.9491499]},"n1819848967":{"id":"n1819848967","loc":[-85.6412455,41.9510187]},"n1819848968":{"id":"n1819848968","loc":[-85.6482622,41.9619493]},"n1819848969":{"id":"n1819848969","loc":[-85.6405841,41.9501474]},"n1819848970":{"id":"n1819848970","loc":[-85.6478583,41.9703394]},"n1819848971":{"id":"n1819848971","loc":[-85.6493388,41.9832845]},"n1819848972":{"id":"n1819848972","loc":[-85.6485664,41.9829415]},"n1819848974":{"id":"n1819848974","loc":[-85.6491457,41.9779887]},"n1819848975":{"id":"n1819848975","loc":[-85.6468889,41.9697033]},"n1819848976":{"id":"n1819848976","loc":[-85.6452726,41.9546072]},"n1819848977":{"id":"n1819848977","loc":[-85.6448435,41.9546072]},"n1819848979":{"id":"n1819848979","loc":[-85.6485342,41.9763138]},"n1819848980":{"id":"n1819848980","loc":[-85.6495282,41.9664087]},"n1819848986":{"id":"n1819848986","loc":[-85.6486307,41.9603278]},"n1819848987":{"id":"n1819848987","loc":[-85.6492278,41.9791871]},"n1819848990":{"id":"n1819848990","loc":[-85.6501934,41.9800724]},"n1819848992":{"id":"n1819848992","loc":[-85.6482445,41.9819685]},"n1819848993":{"id":"n1819848993","loc":[-85.6481871,41.9704451]},"n1819848994":{"id":"n1819848994","loc":[-85.6371364,41.9457602]},"n1819848996":{"id":"n1819848996","loc":[-85.6500362,41.9801023]},"n1819849000":{"id":"n1819849000","loc":[-85.639007,41.9485914]},"n1819849001":{"id":"n1819849001","loc":[-85.6488882,41.9669253]},"n1819849002":{"id":"n1819849002","loc":[-85.6484698,41.9565062]},"n1819849004":{"id":"n1819849004","loc":[-85.6510769,41.9761064]},"n1819849005":{"id":"n1819849005","loc":[-85.6503581,41.9799029]},"n1819849006":{"id":"n1819849006","loc":[-85.6489381,41.9703893]},"n1819849008":{"id":"n1819849008","loc":[-85.6497457,41.9833588]},"n1819849011":{"id":"n1819849011","loc":[-85.6497358,41.9717593]},"n1819849012":{"id":"n1819849012","loc":[-85.6494676,41.9796796]},"n1819849019":{"id":"n1819849019","loc":[-85.6486093,41.9771034]},"n1819849021":{"id":"n1819849021","loc":[-85.6504546,41.9796556]},"n1819849022":{"id":"n1819849022","loc":[-85.6371294,41.9454154]},"n1819849023":{"id":"n1819849023","loc":[-85.6503436,41.9759249]},"n1819849025":{"id":"n1819849025","loc":[-85.6462382,41.9693822]},"n1819849026":{"id":"n1819849026","loc":[-85.6497573,41.983093]},"n1819849028":{"id":"n1819849028","loc":[-85.6497465,41.9602799]},"n1819849029":{"id":"n1819849029","loc":[-85.6374728,41.9460698]},"n1819849030":{"id":"n1819849030","loc":[-85.6486592,41.9566039]},"n1819849031":{"id":"n1819849031","loc":[-85.6515989,41.9654993]},"n1819849032":{"id":"n1819849032","loc":[-85.6387028,41.9482658]},"n1819849033":{"id":"n1819849033","loc":[-85.6464742,41.9688398]},"n1819849034":{"id":"n1819849034","loc":[-85.6495212,41.9589236]},"n1819849035":{"id":"n1819849035","loc":[-85.6490599,41.9790096]},"n1819849036":{"id":"n1819849036","loc":[-85.6489918,41.9800724]},"n1819849038":{"id":"n1819849038","loc":[-85.6499182,41.9659042]},"n1819849040":{"id":"n1819849040","loc":[-85.639758,41.9490143]},"n1819849041":{"id":"n1819849041","loc":[-85.6514846,41.9755241]},"n1819849042":{"id":"n1819849042","loc":[-85.6436633,41.9540647]},"n1819849045":{"id":"n1819849045","loc":[-85.6475541,41.9726387]},"n1819849046":{"id":"n1819849046","loc":[-85.6488308,41.9718331]},"n1819849047":{"id":"n1819849047","loc":[-85.6377694,41.9460953]},"n1819849048":{"id":"n1819849048","loc":[-85.6490706,41.9804452]},"n1819849049":{"id":"n1819849049","loc":[-85.6485449,41.9766248]},"n1819849051":{"id":"n1819849051","loc":[-85.6483625,41.9790256]},"n1819849052":{"id":"n1819849052","loc":[-85.6490706,41.9585167]},"n1819849053":{"id":"n1819849053","loc":[-85.6425008,41.9522874]},"n1819849054":{"id":"n1819849054","loc":[-85.6475793,41.9632158]},"n1819849055":{"id":"n1819849055","loc":[-85.6408631,41.9499399]},"n1819849056":{"id":"n1819849056","loc":[-85.6483373,41.9814681]},"n1819849057":{"id":"n1819849057","loc":[-85.6313548,41.9442876]},"n1819849058":{"id":"n1819849058","loc":[-85.6432663,41.9529796]},"n1819849059":{"id":"n1819849059","loc":[-85.6487128,41.9582873]},"n1819849060":{"id":"n1819849060","loc":[-85.6482338,41.9817612]},"n1819849062":{"id":"n1819849062","loc":[-85.6485664,41.9788661]},"n1819849063":{"id":"n1819849063","loc":[-85.6373081,41.9448824]},"n1819849064":{"id":"n1819849064","loc":[-85.6472215,41.9557582]},"n1819849065":{"id":"n1819849065","loc":[-85.6348984,41.9440414]},"n1819849066":{"id":"n1819849066","loc":[-85.6501972,41.9647315]},"n1819849067":{"id":"n1819849067","loc":[-85.6489741,41.9808281]},"n1819849068":{"id":"n1819849068","loc":[-85.6420111,41.9515034]},"n1819849069":{"id":"n1819849069","loc":[-85.6397972,41.9488882]},"n1819849070":{"id":"n1819849070","loc":[-85.6499718,41.9593465]},"n1819849071":{"id":"n1819849071","loc":[-85.6486844,41.9811311]},"n1819849072":{"id":"n1819849072","loc":[-85.6390392,41.9474663]},"n1819849074":{"id":"n1819849074","loc":[-85.6495642,41.9616362]},"n1819849075":{"id":"n1819849075","loc":[-85.6483518,41.9791931]},"n1819849076":{"id":"n1819849076","loc":[-85.6478974,41.9833104]},"n1819849077":{"id":"n1819849077","loc":[-85.640155,41.948719]},"n1819849078":{"id":"n1819849078","loc":[-85.6399366,41.9487845]},"n1819849079":{"id":"n1819849079","loc":[-85.6492959,41.9825348]},"n1819849080":{"id":"n1819849080","loc":[-85.6505083,41.9648352]},"n1819849081":{"id":"n1819849081","loc":[-85.6492959,41.9645241]},"n1819849082":{"id":"n1819849082","loc":[-85.6402049,41.9491835]},"n1819849083":{"id":"n1819849083","loc":[-85.6495175,41.9826963]},"n1819849084":{"id":"n1819849084","loc":[-85.6480836,41.9728361]},"n1819849085":{"id":"n1819849085","loc":[-85.6374349,41.9443425]},"n1819849086":{"id":"n1819849086","loc":[-85.6478331,41.9681238]},"n1819849089":{"id":"n1819849089","loc":[-85.639368,41.9486169]},"n1819849092":{"id":"n1819849092","loc":[-85.6503581,41.9788022]},"n1819849093":{"id":"n1819849093","loc":[-85.64862,41.9568014]},"n1819849094":{"id":"n1819849094","loc":[-85.6496999,41.9828877]},"n1819849095":{"id":"n1819849095","loc":[-85.647472,41.972198]},"n1819849096":{"id":"n1819849096","loc":[-85.6485771,41.9644523]},"n1819849097":{"id":"n1819849097","loc":[-85.6388353,41.9480488]},"n1819849099":{"id":"n1819849099","loc":[-85.6472752,41.9683312]},"n1819849104":{"id":"n1819849104","loc":[-85.6479548,41.9836035]},"n1819849105":{"id":"n1819849105","loc":[-85.6462489,41.9691668]},"n1819849107":{"id":"n1819849107","loc":[-85.6511912,41.9746328]},"n1819849108":{"id":"n1819849108","loc":[-85.6498646,41.9714881]},"n1819849111":{"id":"n1819849111","loc":[-85.6488239,41.961684]},"n1819849112":{"id":"n1819849112","loc":[-85.6469356,41.9553812]},"n1819849114":{"id":"n1819849114","loc":[-85.6479548,41.9640853]},"n1819849119":{"id":"n1819849119","loc":[-85.6491565,41.961692]},"n1819849121":{"id":"n1819849121","loc":[-85.651667,41.9656728]},"n1819849124":{"id":"n1819849124","loc":[-85.6388423,41.9484414]},"n1819849126":{"id":"n1819849126","loc":[-85.6371686,41.9450978]},"n1819849127":{"id":"n1819849127","loc":[-85.6502615,41.9656728]},"n1819849129":{"id":"n1819849129","loc":[-85.6498501,41.9613031]},"n1819849131":{"id":"n1819849131","loc":[-85.6513881,41.9653298]},"n1819849133":{"id":"n1819849133","loc":[-85.639883,41.9485291]},"n1819849139":{"id":"n1819849139","loc":[-85.6508693,41.9658264]},"n1819849140":{"id":"n1819849140","loc":[-85.6486806,41.9761642]},"n1819849141":{"id":"n1819849141","loc":[-85.6483159,41.9717613]},"n1819849144":{"id":"n1819849144","loc":[-85.6443714,41.9546232]},"n1819849146":{"id":"n1819849146","loc":[-85.641775,41.9513359]},"n1819849147":{"id":"n1819849147","loc":[-85.6495604,41.9757335]},"n1819849148":{"id":"n1819849148","loc":[-85.6465671,41.9551678]},"n1819849150":{"id":"n1819849150","loc":[-85.6485127,41.9794084]},"n1819849151":{"id":"n1819849151","loc":[-85.6499144,41.9757096]},"n1819849152":{"id":"n1819849152","loc":[-85.6433736,41.9531072]},"n1819849154":{"id":"n1819849154","loc":[-85.6489741,41.9607426]},"n1819849155":{"id":"n1819849155","loc":[-85.640627,41.9507697]},"n1819849156":{"id":"n1819849156","loc":[-85.6509659,41.9743058]},"n1819849157":{"id":"n1819849157","loc":[-85.6486844,41.9704431]},"n1819849158":{"id":"n1819849158","loc":[-85.6498538,41.9711132]},"n1819849159":{"id":"n1819849159","loc":[-85.6358937,41.943719]},"n1819849160":{"id":"n1819849160","loc":[-85.6497358,41.9707702]},"n1819849161":{"id":"n1819849161","loc":[-85.6480476,41.9564842]},"n1819849162":{"id":"n1819849162","loc":[-85.6482982,41.9574556]},"n1819849163":{"id":"n1819849163","loc":[-85.6501757,41.9757794]},"n1819849164":{"id":"n1819849164","loc":[-85.6372973,41.9459916]},"n1819849165":{"id":"n1819849165","loc":[-85.6513773,41.9750775]},"n1819849166":{"id":"n1819849166","loc":[-85.6436418,41.9537455]},"n1819849167":{"id":"n1819849167","loc":[-85.6483625,41.9571524]},"n1819849169":{"id":"n1819849169","loc":[-85.647751,41.9727962]},"n1819849170":{"id":"n1819849170","loc":[-85.6504546,41.9656808]},"n1819849171":{"id":"n1819849171","loc":[-85.6479977,41.971839]},"n1819849172":{"id":"n1819849172","loc":[-85.6482767,41.9642449]},"n1819849174":{"id":"n1819849174","loc":[-85.6414317,41.9512086]},"n1819849176":{"id":"n1819849176","loc":[-85.6469034,41.9685287]},"n1819849179":{"id":"n1819849179","loc":[-85.6408631,41.9497564]},"n1819849182":{"id":"n1819849182","loc":[-85.6476721,41.96384]},"n1819849183":{"id":"n1819849183","loc":[-85.6479725,41.983111]},"n1819849184":{"id":"n1819849184","loc":[-85.640788,41.9500516]},"n1819849185":{"id":"n1819849185","loc":[-85.6427798,41.9528778]},"n1819849186":{"id":"n1819849186","loc":[-85.6435308,41.9534124]},"n1819849187":{"id":"n1819849187","loc":[-85.6483733,41.9821998]},"n1819849189":{"id":"n1819849189","loc":[-85.6351752,41.9440796]},"n1819849191":{"id":"n1819849191","loc":[-85.6487021,41.9601463]},"n1819849192":{"id":"n1819849192","loc":[-85.6363811,41.9437605]},"n1819849193":{"id":"n1819849193","loc":[-85.6490883,41.9759728]},"n1819849194":{"id":"n1819849194","loc":[-85.6423292,41.9520081]},"n1819849195":{"id":"n1819849195","loc":[-85.6500003,41.960242]},"n1819849196":{"id":"n1819849196","loc":[-85.6385778,41.9466443]},"n1819849197":{"id":"n1819849197","loc":[-85.6494032,41.9718789]},"n1819849198":{"id":"n1819849198","loc":[-85.6404339,41.9506501]},"n1819849199":{"id":"n1819849199","loc":[-85.6426226,41.9527083]},"n1819849200":{"id":"n1819849200","loc":[-85.6439101,41.9545035]},"n1819849201":{"id":"n1819849201","loc":[-85.6516563,41.9657845]},"n1819849202":{"id":"n1819849202","loc":[-85.6473395,41.9699585]},"n1819858501":{"id":"n1819858501","loc":[-85.6361263,41.9437126]},"n1819858503":{"id":"n1819858503","loc":[-85.6350068,41.944034]},"n1819858513":{"id":"n1819858513","loc":[-85.6371402,41.9453282]},"n1819858518":{"id":"n1819858518","loc":[-85.6348713,41.9432923]},"n1819858523":{"id":"n1819858523","loc":[-85.6357047,41.943799]},"n1819858526":{"id":"n1819858526","loc":[-85.6349947,41.9435756]},"n1819858531":{"id":"n1819858531","loc":[-85.6350376,41.943827]},"n1820937508":{"id":"n1820937508","loc":[-85.1026013,42.0881722]},"n1820937509":{"id":"n1820937509","loc":[-85.0558088,42.102493]},"n1820937511":{"id":"n1820937511","loc":[-85.3030116,41.9724451]},"n1820937513":{"id":"n1820937513","loc":[-85.0353221,42.1027398]},"n1820937514":{"id":"n1820937514","loc":[-85.0835468,42.1015469]},"n1820937515":{"id":"n1820937515","loc":[-85.2421298,42.0106305]},"n1820937517":{"id":"n1820937517","loc":[-85.0090632,42.0910452]},"n1820937518":{"id":"n1820937518","loc":[-85.086626,42.0948838]},"n1820937520":{"id":"n1820937520","loc":[-85.2552039,42.0015448]},"n1820937521":{"id":"n1820937521","loc":[-85.3739614,41.9969917]},"n1820937522":{"id":"n1820937522","loc":[-85.4831166,41.993898]},"n1820937523":{"id":"n1820937523","loc":[-85.0341084,42.0977657]},"n1820937524":{"id":"n1820937524","loc":[-85.3272802,41.9710333]},"n1820937525":{"id":"n1820937525","loc":[-85.2125568,42.0414521]},"n1820937526":{"id":"n1820937526","loc":[-85.3798022,41.9992458]},"n1820937527":{"id":"n1820937527","loc":[-85.2652021,41.999768]},"n1820937528":{"id":"n1820937528","loc":[-85.3852739,42.0004896]},"n1820937529":{"id":"n1820937529","loc":[-85.3911919,42.0030513]},"n1820937530":{"id":"n1820937530","loc":[-85.5440349,41.9717109]},"n1820937531":{"id":"n1820937531","loc":[-85.2790155,41.9911764]},"n1820937532":{"id":"n1820937532","loc":[-85.4723277,41.9950518]},"n1820937533":{"id":"n1820937533","loc":[-85.5690546,41.9653931]},"n1820937535":{"id":"n1820937535","loc":[-85.5674882,41.9649623]},"n1820937536":{"id":"n1820937536","loc":[-85.6362815,41.9189165]},"n1820937537":{"id":"n1820937537","loc":[-85.5659003,41.963638]},"n1820937539":{"id":"n1820937539","loc":[-85.6391353,41.9122262]},"n1820937540":{"id":"n1820937540","loc":[-85.4834385,41.9894803]},"n1820937541":{"id":"n1820937541","loc":[-85.6399078,41.9160744]},"n1820937542":{"id":"n1820937542","loc":[-85.632874,41.941031]},"n1820937543":{"id":"n1820937543","loc":[-85.1307591,42.0726961]},"n1820937544":{"id":"n1820937544","loc":[-85.6444397,41.9128378]},"n1820937545":{"id":"n1820937545","loc":[-85.6197204,41.9420365]},"n1820937546":{"id":"n1820937546","loc":[-85.1164857,42.0864631]},"n1820937547":{"id":"n1820937547","loc":[-85.6476111,41.9142222]},"n1820937548":{"id":"n1820937548","loc":[-85.2915747,41.9774223]},"n1820937549":{"id":"n1820937549","loc":[-85.6430192,41.9102461]},"n1820937550":{"id":"n1820937550","loc":[-85.1597495,42.0639017]},"n1820937551":{"id":"n1820937551","loc":[-85.5504079,41.9701793]},"n1820937553":{"id":"n1820937553","loc":[-85.2781317,41.9948951]},"n1820937555":{"id":"n1820937555","loc":[-85.3724594,41.997518]},"n1820937556":{"id":"n1820937556","loc":[-85.5629434,41.9665155]},"n1820937557":{"id":"n1820937557","loc":[-85.3791971,41.9990808]},"n1820937558":{"id":"n1820937558","loc":[-85.001891,42.0878843]},"n1820937560":{"id":"n1820937560","loc":[-85.3140838,41.9709056]},"n1820937561":{"id":"n1820937561","loc":[-85.2468032,42.0146987]},"n1820937563":{"id":"n1820937563","loc":[-85.0877378,42.097255]},"n1820937564":{"id":"n1820937564","loc":[-85.2442498,42.0150654]},"n1820937566":{"id":"n1820937566","loc":[-85.3108973,41.9701478]},"n1820937568":{"id":"n1820937568","loc":[-85.0344584,42.1016572]},"n1820937569":{"id":"n1820937569","loc":[-85.2331025,42.0297387]},"n1820937570":{"id":"n1820937570","loc":[-85.5058446,41.9746996]},"n1820937571":{"id":"n1820937571","loc":[-85.5622739,41.9676427]},"n1820937572":{"id":"n1820937572","loc":[-85.2792687,41.9890337]},"n1820937574":{"id":"n1820937574","loc":[-84.9909302,42.08695]},"n1820937575":{"id":"n1820937575","loc":[-85.6218233,41.9418609]},"n1820937576":{"id":"n1820937576","loc":[-85.3577437,41.9931062]},"n1820937577":{"id":"n1820937577","loc":[-85.639028,41.9165853]},"n1820937578":{"id":"n1820937578","loc":[-84.9956576,42.0865348]},"n1820937579":{"id":"n1820937579","loc":[-85.4828376,41.990198]},"n1820937580":{"id":"n1820937580","loc":[-85.3244478,41.9720543]},"n1820937582":{"id":"n1820937582","loc":[-85.0517479,42.1035159]},"n1820937583":{"id":"n1820937583","loc":[-85.225646,42.0338025]},"n1820937584":{"id":"n1820937584","loc":[-84.9941019,42.0862163]},"n1820937586":{"id":"n1820937586","loc":[-85.1051762,42.0879452]},"n1820937587":{"id":"n1820937587","loc":[-85.1245203,42.0753162]},"n1820937588":{"id":"n1820937588","loc":[-85.3250808,41.9719506]},"n1820937589":{"id":"n1820937589","loc":[-85.2720109,41.997933]},"n1820937590":{"id":"n1820937590","loc":[-85.2556653,42.0027248]},"n1820937591":{"id":"n1820937591","loc":[-85.0872483,42.0943544]},"n1820937592":{"id":"n1820937592","loc":[-85.2778353,41.9955023]},"n1820937593":{"id":"n1820937593","loc":[-85.2984733,41.9735538]},"n1820937594":{"id":"n1820937594","loc":[-85.101578,42.0889552]},"n1820937595":{"id":"n1820937595","loc":[-85.3888745,42.0016959]},"n1820937596":{"id":"n1820937596","loc":[-84.9903508,42.0870654]},"n1820937597":{"id":"n1820937597","loc":[-85.6405558,41.9146261]},"n1820937598":{"id":"n1820937598","loc":[-85.6460704,41.9141311]},"n1820937599":{"id":"n1820937599","loc":[-85.0377468,42.1037428]},"n1820937600":{"id":"n1820937600","loc":[-85.2298345,42.0312899]},"n1820937601":{"id":"n1820937601","loc":[-85.1080958,42.0861964]},"n1820937602":{"id":"n1820937602","loc":[-85.6325307,41.9402329]},"n1820937603":{"id":"n1820937603","loc":[-85.1165984,42.0832184]},"n1820937604":{"id":"n1820937604","loc":[-85.6354446,41.9190602]},"n1820937605":{"id":"n1820937605","loc":[-85.1114592,42.0862959]},"n1820937606":{"id":"n1820937606","loc":[-85.0858763,42.1001646]},"n1820937607":{"id":"n1820937607","loc":[-85.0472083,42.1015151]},"n1820937608":{"id":"n1820937608","loc":[-85.0802477,42.1027609]},"n1820937610":{"id":"n1820937610","loc":[-85.0924585,42.0928564]},"n1820937611":{"id":"n1820937611","loc":[-85.0329617,42.09827]},"n1820937612":{"id":"n1820937612","loc":[-85.2814617,41.993465]},"n1820937613":{"id":"n1820937613","loc":[-85.3097708,41.9700282]},"n1820937614":{"id":"n1820937614","loc":[-85.2809427,41.993695]},"n1820937615":{"id":"n1820937615","loc":[-85.0583233,42.1026494]},"n1820937617":{"id":"n1820937617","loc":[-85.2801592,41.9840021]},"n1820937619":{"id":"n1820937619","loc":[-85.1064154,42.0863449]},"n1820937620":{"id":"n1820937620","loc":[-85.0423173,42.1014662]},"n1820937621":{"id":"n1820937621","loc":[-85.2168913,42.0398107]},"n1820937622":{"id":"n1820937622","loc":[-85.2798481,41.9833401]},"n1820937623":{"id":"n1820937623","loc":[-85.0575468,42.1028672]},"n1820937625":{"id":"n1820937625","loc":[-85.0130369,42.0893067]},"n1820937626":{"id":"n1820937626","loc":[-85.0346985,42.1018256]},"n1820937627":{"id":"n1820937627","loc":[-85.2231569,42.0372768]},"n1820937628":{"id":"n1820937628","loc":[-85.2956195,41.9732268]},"n1820937629":{"id":"n1820937629","loc":[-85.1052312,42.086893]},"n1820937630":{"id":"n1820937630","loc":[-85.4813356,41.9958436]},"n1820937631":{"id":"n1820937631","loc":[-85.0961599,42.0914672]},"n1820937632":{"id":"n1820937632","loc":[-85.308419,41.9704749]},"n1820937633":{"id":"n1820937633","loc":[-85.295952,41.9715119]},"n1820937634":{"id":"n1820937634","loc":[-85.3310933,41.9703923]},"n1820937635":{"id":"n1820937635","loc":[-85.2940745,41.9739686]},"n1820937636":{"id":"n1820937636","loc":[-85.3803343,42.000484]},"n1820937637":{"id":"n1820937637","loc":[-85.1174231,42.0845533]},"n1820937638":{"id":"n1820937638","loc":[-85.0095836,42.089839]},"n1820937639":{"id":"n1820937639","loc":[-85.3179354,41.9705866]},"n1820937640":{"id":"n1820937640","loc":[-85.257708,42.0001189]},"n1820937641":{"id":"n1820937641","loc":[-85.2563522,42.0002771]},"n1820937642":{"id":"n1820937642","loc":[-85.3181929,41.970419]},"n1820937643":{"id":"n1820937643","loc":[-85.2911884,41.9757154]},"n1820937644":{"id":"n1820937644","loc":[-85.2714423,41.9975862]},"n1820937645":{"id":"n1820937645","loc":[-85.0193669,42.089888]},"n1820937646":{"id":"n1820937646","loc":[-85.3889818,42.0039921]},"n1820937647":{"id":"n1820937647","loc":[-85.3408093,41.9853965]},"n1820937648":{"id":"n1820937648","loc":[-85.1258091,42.0748332]},"n1820937649":{"id":"n1820937649","loc":[-85.5722561,41.962782]},"n1820937650":{"id":"n1820937650","loc":[-85.3266902,41.9721819]},"n1820937651":{"id":"n1820937651","loc":[-85.1473255,42.065192]},"n1820937652":{"id":"n1820937652","loc":[-85.1462526,42.0655106]},"n1820937653":{"id":"n1820937653","loc":[-85.4641051,42.0013929]},"n1820937654":{"id":"n1820937654","loc":[-85.5620379,41.9700677]},"n1820937655":{"id":"n1820937655","loc":[-85.3226025,41.971121]},"n1820937656":{"id":"n1820937656","loc":[-85.0200965,42.0899516]},"n1820937657":{"id":"n1820937657","loc":[-85.0624714,42.1044711]},"n1820937658":{"id":"n1820937658","loc":[-85.5649562,41.9637178]},"n1820937659":{"id":"n1820937659","loc":[-85.2360315,42.0253315]},"n1820937660":{"id":"n1820937660","loc":[-85.3881449,41.9994475]},"n1820937661":{"id":"n1820937661","loc":[-85.5032911,41.976263]},"n1820937662":{"id":"n1820937662","loc":[-85.481297,41.9871414]},"n1820937663":{"id":"n1820937663","loc":[-85.1167056,42.0841898]},"n1820937664":{"id":"n1820937664","loc":[-85.2891714,41.9787223]},"n1820937665":{"id":"n1820937665","loc":[-85.4393429,42.0058736]},"n1820937666":{"id":"n1820937666","loc":[-85.0077007,42.0895762]},"n1820937667":{"id":"n1820937667","loc":[-85.2736202,41.9979171]},"n1820937668":{"id":"n1820937668","loc":[-84.9935332,42.0859296]},"n1820937669":{"id":"n1820937669","loc":[-85.0622769,42.1046713]},"n1820937670":{"id":"n1820937670","loc":[-85.2309031,42.0311249]},"n1820937671":{"id":"n1820937671","loc":[-85.0343726,42.10069]},"n1820937672":{"id":"n1820937672","loc":[-85.0596551,42.1048612]},"n1820937673":{"id":"n1820937673","loc":[-85.1338597,42.0707449]},"n1820937674":{"id":"n1820937674","loc":[-85.3117663,41.9689194]},"n1820937675":{"id":"n1820937675","loc":[-85.0705649,42.1057499]},"n1820937676":{"id":"n1820937676","loc":[-85.2441425,42.0180944]},"n1820937677":{"id":"n1820937677","loc":[-85.1171174,42.0862692]},"n1820937678":{"id":"n1820937678","loc":[-85.0346824,42.1005519]},"n1820937680":{"id":"n1820937680","loc":[-85.2389927,42.0229245]},"n1820937681":{"id":"n1820937681","loc":[-85.0834892,42.1018642]},"n1820937682":{"id":"n1820937682","loc":[-85.0619443,42.1049459]},"n1820937683":{"id":"n1820937683","loc":[-85.2845366,41.9811868]},"n1820937684":{"id":"n1820937684","loc":[-85.210411,42.0394123]},"n1820937685":{"id":"n1820937685","loc":[-85.4377383,42.0055942]},"n1820937686":{"id":"n1820937686","loc":[-85.2882058,41.9789138]},"n1820937687":{"id":"n1820937687","loc":[-85.2741191,41.9955808]},"n1820937688":{"id":"n1820937688","loc":[-85.3442211,41.9903575]},"n1820937689":{"id":"n1820937689","loc":[-85.2641413,41.9995237]},"n1820937690":{"id":"n1820937690","loc":[-85.2804489,41.9829174]},"n1820937691":{"id":"n1820937691","loc":[-85.5593342,41.9729074]},"n1820937692":{"id":"n1820937692","loc":[-85.3590912,41.9932601]},"n1820937694":{"id":"n1820937694","loc":[-85.4826445,41.9957479]},"n1820937695":{"id":"n1820937695","loc":[-85.4539127,42.0063041]},"n1820937696":{"id":"n1820937696","loc":[-85.2456767,42.0153683]},"n1820937697":{"id":"n1820937697","loc":[-85.5794015,41.9489631]},"n1820937698":{"id":"n1820937698","loc":[-85.4108686,42.0078507]},"n1820937699":{"id":"n1820937699","loc":[-85.0616386,42.1051529]},"n1820937700":{"id":"n1820937700","loc":[-85.4977979,41.978241]},"n1820937701":{"id":"n1820937701","loc":[-85.2488417,42.0086319]},"n1820937702":{"id":"n1820937702","loc":[-85.5588836,41.9728116]},"n1820937703":{"id":"n1820937703","loc":[-85.4557366,42.0051241]},"n1820937705":{"id":"n1820937705","loc":[-85.0723151,42.1056094]},"n1820937706":{"id":"n1820937706","loc":[-85.0057909,42.0887323]},"n1820937707":{"id":"n1820937707","loc":[-85.0756786,42.105677]},"n1820937708":{"id":"n1820937708","loc":[-85.0901504,42.0940001]},"n1820937709":{"id":"n1820937709","loc":[-85.0979999,42.0910213]},"n1820937710":{"id":"n1820937710","loc":[-85.2376301,42.0239686]},"n1820937711":{"id":"n1820937711","loc":[-85.2780671,41.9902299]},"n1820937712":{"id":"n1820937712","loc":[-85.251481,42.0113188]},"n1820937713":{"id":"n1820937713","loc":[-85.3114767,41.9690311]},"n1820937714":{"id":"n1820937714","loc":[-85.2649621,41.9975662]},"n1820937715":{"id":"n1820937715","loc":[-85.283807,41.9813383]},"n1820937716":{"id":"n1820937716","loc":[-85.5515451,41.9703867]},"n1820937717":{"id":"n1820937717","loc":[-85.1176605,42.0850896]},"n1820937718":{"id":"n1820937718","loc":[-85.1069317,42.0862441]},"n1820937719":{"id":"n1820937719","loc":[-85.2739314,41.9976938]},"n1820937720":{"id":"n1820937720","loc":[-85.5550212,41.9702112]},"n1820937721":{"id":"n1820937721","loc":[-85.3076679,41.9719904]},"n1820937722":{"id":"n1820937722","loc":[-85.592319,41.9440316]},"n1820937723":{"id":"n1820937723","loc":[-85.3139979,41.9704031]},"n1820937724":{"id":"n1820937724","loc":[-85.0421134,42.1013149]},"n1820937725":{"id":"n1820937725","loc":[-85.2508373,42.0102741]},"n1820937726":{"id":"n1820937726","loc":[-85.0830922,42.1038821]},"n1820937727":{"id":"n1820937727","loc":[-85.6342473,41.9360031]},"n1820937730":{"id":"n1820937730","loc":[-85.0500192,42.1024942]},"n1820937731":{"id":"n1820937731","loc":[-85.3498644,41.9926221]},"n1820937732":{"id":"n1820937732","loc":[-85.0234117,42.0918903]},"n1820937733":{"id":"n1820937733","loc":[-85.0464425,42.1009408]},"n1820937734":{"id":"n1820937734","loc":[-85.033938,42.099886]},"n1820937736":{"id":"n1820937736","loc":[-85.0152752,42.0886009]},"n1820937737":{"id":"n1820937737","loc":[-85.0441894,42.1012671]},"n1820937738":{"id":"n1820937738","loc":[-85.4668731,41.9979804]},"n1820937739":{"id":"n1820937739","loc":[-85.4407377,42.006033]},"n1820937740":{"id":"n1820937740","loc":[-85.2262253,42.0344878]},"n1820937741":{"id":"n1820937741","loc":[-85.2550001,42.0033706]},"n1820937742":{"id":"n1820937742","loc":[-85.3071422,41.9722617]},"n1820937743":{"id":"n1820937743","loc":[-85.6147852,41.942228]},"n1820937744":{"id":"n1820937744","loc":[-85.0183853,42.0901825]},"n1820937745":{"id":"n1820937745","loc":[-85.6323161,41.9228489]},"n1820937746":{"id":"n1820937746","loc":[-85.0095568,42.0901376]},"n1820937747":{"id":"n1820937747","loc":[-85.2524037,42.0113826]},"n1820937748":{"id":"n1820937748","loc":[-85.3186864,41.9708578]},"n1820937749":{"id":"n1820937749","loc":[-85.2805669,41.9870883]},"n1820937750":{"id":"n1820937750","loc":[-85.0585768,42.1038144]},"n1820937751":{"id":"n1820937751","loc":[-85.2970786,41.9715358]},"n1820937752":{"id":"n1820937752","loc":[-85.1315758,42.0723445]},"n1820937753":{"id":"n1820937753","loc":[-85.2448291,42.0175444]},"n1820937754":{"id":"n1820937754","loc":[-85.2446468,42.0174248]},"n1820937755":{"id":"n1820937755","loc":[-85.229165,42.032129]},"n1820937756":{"id":"n1820937756","loc":[-85.5612654,41.9724926]},"n1820937757":{"id":"n1820937757","loc":[-85.2331776,42.030854]},"n1820937758":{"id":"n1820937758","loc":[-85.2271909,42.0334519]},"n1820937759":{"id":"n1820937759","loc":[-85.1032396,42.0879214]},"n1820937760":{"id":"n1820937760","loc":[-85.0638447,42.1044154]},"n1820937761":{"id":"n1820937761","loc":[-85.1260706,42.0745556]},"n1820937762":{"id":"n1820937762","loc":[-85.3454485,41.99132]},"n1820937763":{"id":"n1820937763","loc":[-85.2639321,41.9980088]},"n1820937764":{"id":"n1820937764","loc":[-85.0837681,42.1013746]},"n1820937765":{"id":"n1820937765","loc":[-85.2808137,41.9869368]},"n1820937766":{"id":"n1820937766","loc":[-85.6338997,41.9309373]},"n1820937767":{"id":"n1820937767","loc":[-85.2267403,42.0332766]},"n1820937768":{"id":"n1820937768","loc":[-85.0605831,42.1052074]},"n1820937769":{"id":"n1820937769","loc":[-85.0259021,42.0930037]},"n1820937770":{"id":"n1820937770","loc":[-85.232963,42.0313162]},"n1820937771":{"id":"n1820937771","loc":[-85.2404947,42.0125381]},"n1820937772":{"id":"n1820937772","loc":[-85.0910892,42.0935742]},"n1820937773":{"id":"n1820937773","loc":[-85.2554829,42.0019435]},"n1820937774":{"id":"n1820937774","loc":[-85.2799339,41.9867773]},"n1820937775":{"id":"n1820937775","loc":[-85.1075432,42.0852767]},"n1820937776":{"id":"n1820937776","loc":[-85.1176927,42.0854001]},"n1820937777":{"id":"n1820937777","loc":[-85.1067064,42.0863357]},"n1820937778":{"id":"n1820937778","loc":[-85.2517492,42.0106333]},"n1820937779":{"id":"n1820937779","loc":[-85.0987174,42.0909031]},"n1820937780":{"id":"n1820937780","loc":[-85.1160083,42.0863994]},"n1820937781":{"id":"n1820937781","loc":[-85.1268645,42.0739703]},"n1820937782":{"id":"n1820937782","loc":[-85.0454702,42.1002852]},"n1820937783":{"id":"n1820937783","loc":[-85.1334145,42.0705418]},"n1820937784":{"id":"n1820937784","loc":[-85.5866542,41.947431]},"n1820937786":{"id":"n1820937786","loc":[-85.2359886,42.0250366]},"n1820937787":{"id":"n1820937787","loc":[-85.3138048,41.9698527]},"n1820937788":{"id":"n1820937788","loc":[-85.1274291,42.0733081]},"n1820937790":{"id":"n1820937790","loc":[-85.6292905,41.9411267]},"n1820937791":{"id":"n1820937791","loc":[-85.5958809,41.9417333]},"n1820937792":{"id":"n1820937792","loc":[-85.1271019,42.0737581]},"n1820937793":{"id":"n1820937793","loc":[-85.2312679,42.0314437]},"n1820937794":{"id":"n1820937794","loc":[-85.1081387,42.0863516]},"n1820937795":{"id":"n1820937795","loc":[-85.2424473,42.0212109]},"n1820937796":{"id":"n1820937796","loc":[-85.2710654,41.9975236]},"n1820937797":{"id":"n1820937797","loc":[-85.4798408,41.9863223]},"n1820937798":{"id":"n1820937798","loc":[-85.035939,42.104296]},"n1820937799":{"id":"n1820937799","loc":[-85.2178139,42.0395398]},"n1820937800":{"id":"n1820937800","loc":[-85.0630709,42.1042614]},"n1820937801":{"id":"n1820937801","loc":[-85.0440124,42.1014861]},"n1820937802":{"id":"n1820937802","loc":[-85.1321874,42.0720458]},"n1820937804":{"id":"n1820937804","loc":[-85.079427,42.1029121]},"n1820937805":{"id":"n1820937805","loc":[-85.2962632,41.9738968]},"n1820937806":{"id":"n1820937806","loc":[-85.6334748,41.9274627]},"n1820937807":{"id":"n1820937807","loc":[-85.1057341,42.0872804]},"n1820937808":{"id":"n1820937808","loc":[-85.4960169,41.9778263]},"n1820937809":{"id":"n1820937809","loc":[-85.2821226,41.9910273]},"n1820937810":{"id":"n1820937810","loc":[-85.0013868,42.0885054]},"n1820937811":{"id":"n1820937811","loc":[-85.2952547,41.9729795]},"n1820937812":{"id":"n1820937812","loc":[-85.1298375,42.0667842]},"n1820937813":{"id":"n1820937813","loc":[-85.1339201,42.0710025]},"n1820937814":{"id":"n1820937814","loc":[-85.0374356,42.103691]},"n1820937815":{"id":"n1820937815","loc":[-85.0061115,42.0880607]},"n1820937817":{"id":"n1820937817","loc":[-85.2398402,42.0226934]},"n1820937818":{"id":"n1820937818","loc":[-85.123501,42.076236]},"n1820937819":{"id":"n1820937819","loc":[-85.1209489,42.0791294]},"n1820937820":{"id":"n1820937820","loc":[-85.0818624,42.1025778]},"n1820937821":{"id":"n1820937821","loc":[-85.4428835,42.0054749]},"n1820937822":{"id":"n1820937822","loc":[-85.4710359,41.9961147]},"n1820937823":{"id":"n1820937823","loc":[-85.4253354,42.006198]},"n1820937824":{"id":"n1820937824","loc":[-85.5486483,41.9709451]},"n1820937825":{"id":"n1820937825","loc":[-85.2303238,42.0310452]},"n1820937826":{"id":"n1820937826","loc":[-85.6450405,41.9136361]},"n1820937828":{"id":"n1820937828","loc":[-85.2606853,41.9964073]},"n1820937830":{"id":"n1820937830","loc":[-85.097383,42.0911447]},"n1820937831":{"id":"n1820937831","loc":[-85.0498207,42.102136]},"n1820937832":{"id":"n1820937832","loc":[-85.1232435,42.0763793]},"n1820937833":{"id":"n1820937833","loc":[-85.394093,42.0055921]},"n1820937834":{"id":"n1820937834","loc":[-85.3566665,41.9928295]},"n1820937835":{"id":"n1820937835","loc":[-85.3543276,41.9920002]},"n1820937837":{"id":"n1820937837","loc":[-85.084668,42.1034932]},"n1820937838":{"id":"n1820937838","loc":[-85.4400296,42.0060649]},"n1820937839":{"id":"n1820937839","loc":[-85.2362246,42.025714]},"n1820937840":{"id":"n1820937840","loc":[-85.0409225,42.1012791]},"n1820937841":{"id":"n1820937841","loc":[-85.2442283,42.019832]},"n1820937842":{"id":"n1820937842","loc":[-85.1123001,42.084824]},"n1820937843":{"id":"n1820937843","loc":[-85.1603074,42.0638061]},"n1820937844":{"id":"n1820937844","loc":[-85.1359744,42.0650646]},"n1820937845":{"id":"n1820937845","loc":[-85.1757569,42.053849]},"n1820937846":{"id":"n1820937846","loc":[-85.5200925,41.9716686]},"n1820937848":{"id":"n1820937848","loc":[-85.5525322,41.9701315]},"n1820937849":{"id":"n1820937849","loc":[-85.0406489,42.10149]},"n1820937850":{"id":"n1820937850","loc":[-85.0142547,42.088825]},"n1820937851":{"id":"n1820937851","loc":[-85.343749,41.9881884]},"n1820937852":{"id":"n1820937852","loc":[-85.074996,42.1060205]},"n1820937853":{"id":"n1820937853","loc":[-85.2436275,42.0136864]},"n1820937854":{"id":"n1820937854","loc":[-85.2641453,41.9980897]},"n1820937856":{"id":"n1820937856","loc":[-85.2802343,41.9870086]},"n1820937857":{"id":"n1820937857","loc":[-85.0099256,42.0909946]},"n1820937858":{"id":"n1820937858","loc":[-85.493957,41.9786079]},"n1820937859":{"id":"n1820937859","loc":[-85.0739405,42.1059795]},"n1820937860":{"id":"n1820937860","loc":[-85.2331605,42.0301423]},"n1820937862":{"id":"n1820937862","loc":[-85.2035231,42.0438425]},"n1820937863":{"id":"n1820937863","loc":[-85.0884928,42.0986971]},"n1820937864":{"id":"n1820937864","loc":[-85.131597,42.0690142]},"n1820937865":{"id":"n1820937865","loc":[-85.3937454,42.0052677]},"n1820937866":{"id":"n1820937866","loc":[-85.2212729,42.0378561]},"n1820937867":{"id":"n1820937867","loc":[-85.0886068,42.0982421]},"n1820937868":{"id":"n1820937868","loc":[-85.0875004,42.0968064]},"n1820937869":{"id":"n1820937869","loc":[-85.0771323,42.1042642]},"n1820937870":{"id":"n1820937870","loc":[-85.0164554,42.0894887]},"n1820937871":{"id":"n1820937871","loc":[-85.6069102,41.9415577]},"n1820937872":{"id":"n1820937872","loc":[-85.3273875,41.9704908]},"n1820937873":{"id":"n1820937873","loc":[-85.3890891,41.9997983]},"n1820937875":{"id":"n1820937875","loc":[-85.5091276,41.9723705]},"n1820937876":{"id":"n1820937876","loc":[-85.0770626,42.1047696]},"n1820937877":{"id":"n1820937877","loc":[-85.612575,41.9419567]},"n1820937878":{"id":"n1820937878","loc":[-85.3868146,42.0036094]},"n1820937879":{"id":"n1820937879","loc":[-85.2722738,41.9981204]},"n1820937880":{"id":"n1820937880","loc":[-85.3064878,41.9723733]},"n1820937882":{"id":"n1820937882","loc":[-85.1270845,42.0727678]},"n1820937884":{"id":"n1820937884","loc":[-85.3316512,41.97923]},"n1820937885":{"id":"n1820937885","loc":[-85.3932519,42.0042472]},"n1820937886":{"id":"n1820937886","loc":[-85.2457411,42.0175444]},"n1820937887":{"id":"n1820937887","loc":[-85.1397509,42.0648415]},"n1820937891":{"id":"n1820937891","loc":[-85.3196735,41.9719665]},"n1820937892":{"id":"n1820937892","loc":[-85.3372473,41.9845033]},"n1820937894":{"id":"n1820937894","loc":[-85.3254778,41.9719745]},"n1820937897":{"id":"n1820937897","loc":[-85.3185148,41.9691268]},"n1820937899":{"id":"n1820937899","loc":[-85.5419106,41.9714556]},"n1820937901":{"id":"n1820937901","loc":[-85.3293509,41.9748368]},"n1820937903":{"id":"n1820937903","loc":[-85.0798078,42.1028365]},"n1820937905":{"id":"n1820937905","loc":[-85.3954191,42.0056025]},"n1820937909":{"id":"n1820937909","loc":[-85.3417534,41.9857155]},"n1820937913":{"id":"n1820937913","loc":[-84.9927822,42.0857107]},"n1820937915":{"id":"n1820937915","loc":[-85.5444212,41.9712801]},"n1820937917":{"id":"n1820937917","loc":[-85.259088,41.9981682]},"n1820937921":{"id":"n1820937921","loc":[-85.2784576,41.9876358]},"n1820937922":{"id":"n1820937922","loc":[-84.9971918,42.087753]},"n1820937924":{"id":"n1820937924","loc":[-85.5310688,41.966899]},"n1820937928":{"id":"n1820937928","loc":[-85.3766436,41.9979326]},"n1820937930":{"id":"n1820937930","loc":[-85.5494852,41.9704346]},"n1820937933":{"id":"n1820937933","loc":[-85.5548281,41.9695412]},"n1820937935":{"id":"n1820937935","loc":[-85.0768588,42.105088]},"n1820937937":{"id":"n1820937937","loc":[-85.2646885,41.9978054]},"n1820937939":{"id":"n1820937939","loc":[-85.2441532,42.0176082]},"n1820937941":{"id":"n1820937941","loc":[-85.105553,42.0877928]},"n1820937943":{"id":"n1820937943","loc":[-85.0879457,42.0958909]},"n1820937944":{"id":"n1820937944","loc":[-85.3187015,41.9704402]},"n1820937945":{"id":"n1820937945","loc":[-85.5624456,41.970626]},"n1820937946":{"id":"n1820937946","loc":[-85.0580176,42.1028644]},"n1820937948":{"id":"n1820937948","loc":[-85.3016061,41.9726286]},"n1820937949":{"id":"n1820937949","loc":[-85.4310388,42.0069418]},"n1820937950":{"id":"n1820937950","loc":[-85.2945144,41.9740723]},"n1820937951":{"id":"n1820937951","loc":[-85.1170222,42.082657]},"n1820937952":{"id":"n1820937952","loc":[-85.0864503,42.0947632]},"n1820937953":{"id":"n1820937953","loc":[-85.4285926,42.0059533]},"n1820937970":{"id":"n1820937970","loc":[-85.3629965,41.9938023]},"n1820937972":{"id":"n1820937972","loc":[-85.2438099,42.0199755]},"n1820937974":{"id":"n1820937974","loc":[-85.1327654,42.0699285]},"n1820937977":{"id":"n1820937977","loc":[-85.1515956,42.0611935]},"n1820937978":{"id":"n1820937978","loc":[-85.0107369,42.0896638]},"n1820937979":{"id":"n1820937979","loc":[-85.1152626,42.0862083]},"n1820937980":{"id":"n1820937980","loc":[-85.4531831,42.0062881]},"n1820937981":{"id":"n1820937981","loc":[-85.0341473,42.0985924]},"n1820937982":{"id":"n1820937982","loc":[-85.0877485,42.0960171]},"n1820937983":{"id":"n1820937983","loc":[-85.2756373,41.9951742]},"n1820937984":{"id":"n1820937984","loc":[-85.2965421,41.9714401]},"n1820937985":{"id":"n1820937985","loc":[-85.2409775,42.0226934]},"n1820937986":{"id":"n1820937986","loc":[-85.0170723,42.0900579]},"n1820937987":{"id":"n1820937987","loc":[-85.1034663,42.0880555]},"n1820937988":{"id":"n1820937988","loc":[-85.0585071,42.1031577]},"n1820937990":{"id":"n1820937990","loc":[-85.0819174,42.1032373]},"n1820937992":{"id":"n1820937992","loc":[-85.0546608,42.1030542]},"n1820937993":{"id":"n1820937993","loc":[-85.0100811,42.0906125]},"n1820937995":{"id":"n1820937995","loc":[-85.6304278,41.9432655]},"n1820937997":{"id":"n1820937997","loc":[-85.0255628,42.092778]},"n1820938011":{"id":"n1820938011","loc":[-85.2316756,42.0317146]},"n1820938012":{"id":"n1820938012","loc":[-85.4067917,42.008042]},"n1820938013":{"id":"n1820938013","loc":[-85.390398,42.0028759]},"n1820938014":{"id":"n1820938014","loc":[-85.0161604,42.0886527]},"n1820938015":{"id":"n1820938015","loc":[-85.125337,42.0744589]},"n1820938016":{"id":"n1820938016","loc":[-85.2151317,42.0404801]},"n1820938017":{"id":"n1820938017","loc":[-85.3165085,41.9706025]},"n1820938018":{"id":"n1820938018","loc":[-85.5641193,41.9640688]},"n1820938019":{"id":"n1820938019","loc":[-85.147583,42.0642203]},"n1820938022":{"id":"n1820938022","loc":[-85.2803781,41.9947886]},"n1820938024":{"id":"n1820938024","loc":[-85.2692469,41.9982053]},"n1820938026":{"id":"n1820938026","loc":[-85.4321975,42.0067505]},"n1820938028":{"id":"n1820938028","loc":[-85.572535,41.9633405]},"n1820938030":{"id":"n1820938030","loc":[-85.3237505,41.9716475]},"n1820938032":{"id":"n1820938032","loc":[-85.6487698,41.9141583]},"n1820938033":{"id":"n1820938033","loc":[-85.0526371,42.1038315]},"n1820938034":{"id":"n1820938034","loc":[-85.088069,42.0978731]},"n1820938035":{"id":"n1820938035","loc":[-85.2516312,42.0102267]},"n1820938039":{"id":"n1820938039","loc":[-85.2731374,41.9982958]},"n1820938040":{"id":"n1820938040","loc":[-85.5453224,41.9713439]},"n1820938041":{"id":"n1820938041","loc":[-85.4480548,42.0049647]},"n1820938043":{"id":"n1820938043","loc":[-85.2504081,42.010322]},"n1820938045":{"id":"n1820938045","loc":[-85.2663447,41.99919]},"n1820938046":{"id":"n1820938046","loc":[-85.0507287,42.102907]},"n1820938047":{"id":"n1820938047","loc":[-85.0408246,42.1024743]},"n1820938048":{"id":"n1820938048","loc":[-85.2796335,41.9866099]},"n1820938050":{"id":"n1820938050","loc":[-85.452475,42.0061127]},"n1820938051":{"id":"n1820938051","loc":[-85.2410569,42.0128147]},"n1820938052":{"id":"n1820938052","loc":[-85.0413302,42.1011477]},"n1820938053":{"id":"n1820938053","loc":[-85.6327409,41.9197627]},"n1820938056":{"id":"n1820938056","loc":[-85.1072039,42.0857994]},"n1820938057":{"id":"n1820938057","loc":[-85.2001114,42.0448145]},"n1820938058":{"id":"n1820938058","loc":[-85.2655347,41.9978186]},"n1820938059":{"id":"n1820938059","loc":[-85.2330918,42.0304874]},"n1820938060":{"id":"n1820938060","loc":[-85.2601113,41.9966545]},"n1820938061":{"id":"n1820938061","loc":[-85.5397863,41.9708494]},"n1820938062":{"id":"n1820938062","loc":[-85.2702085,41.9977217]},"n1820938063":{"id":"n1820938063","loc":[-85.2219982,42.03699]},"n1820938064":{"id":"n1820938064","loc":[-85.0668957,42.105121]},"n1820938065":{"id":"n1820938065","loc":[-85.2328665,42.0270769]},"n1820938066":{"id":"n1820938066","loc":[-85.3189654,41.9694778]},"n1820938067":{"id":"n1820938067","loc":[-85.3814115,42.0022915]},"n1820938068":{"id":"n1820938068","loc":[-85.2759108,41.9956008]},"n1820938069":{"id":"n1820938069","loc":[-85.0391938,42.1034853]},"n1820938070":{"id":"n1820938070","loc":[-85.2850623,41.9810353]},"n1820938071":{"id":"n1820938071","loc":[-85.538074,41.970855]},"n1820938073":{"id":"n1820938073","loc":[-85.1319661,42.0670932]},"n1820938074":{"id":"n1820938074","loc":[-85.2816763,41.9913678]},"n1820938075":{"id":"n1820938075","loc":[-85.3182144,41.9700282]},"n1820938076":{"id":"n1820938076","loc":[-85.5909028,41.9458989]},"n1820938077":{"id":"n1820938077","loc":[-85.4057617,42.0074361]},"n1820938078":{"id":"n1820938078","loc":[-85.2620438,41.9967729]},"n1820938079":{"id":"n1820938079","loc":[-85.1122143,42.0851107]},"n1820938080":{"id":"n1820938080","loc":[-85.2443785,42.0174567]},"n1820938081":{"id":"n1820938081","loc":[-85.0319733,42.0953853]},"n1820938082":{"id":"n1820938082","loc":[-85.0878276,42.09443]},"n1820938083":{"id":"n1820938083","loc":[-85.0271789,42.0935809]},"n1820938084":{"id":"n1820938084","loc":[-85.0326399,42.0974222]},"n1820938085":{"id":"n1820938085","loc":[-85.3989167,42.0065592]},"n1820938086":{"id":"n1820938086","loc":[-85.3263361,41.9721261]},"n1820938087":{"id":"n1820938087","loc":[-85.2547855,42.0037134]},"n1820938088":{"id":"n1820938088","loc":[-85.4373259,42.005746]},"n1820938089":{"id":"n1820938089","loc":[-85.3094275,41.9699245]},"n1820938090":{"id":"n1820938090","loc":[-85.2783246,41.9872793]},"n1820938092":{"id":"n1820938092","loc":[-85.0815633,42.1025169]},"n1820938093":{"id":"n1820938093","loc":[-85.1788511,42.0522134]},"n1820938095":{"id":"n1820938095","loc":[-85.2830345,41.9816733]},"n1820938096":{"id":"n1820938096","loc":[-85.0744984,42.1059835]},"n1820938097":{"id":"n1820938097","loc":[-85.2788396,41.9879333]},"n1820938098":{"id":"n1820938098","loc":[-85.3640093,41.9946531]},"n1820938099":{"id":"n1820938099","loc":[-85.291167,41.9787463]},"n1820938100":{"id":"n1820938100","loc":[-85.0772436,42.1038156]},"n1820938101":{"id":"n1820938101","loc":[-85.00563,42.0887482]},"n1820938102":{"id":"n1820938102","loc":[-85.0326881,42.0961245]},"n1820938104":{"id":"n1820938104","loc":[-85.0530448,42.1038634]},"n1820938105":{"id":"n1820938105","loc":[-85.2625266,41.9970639]},"n1820938106":{"id":"n1820938106","loc":[-85.2827556,41.9823512]},"n1820938107":{"id":"n1820938107","loc":[-85.2784319,41.9910752]},"n1820938108":{"id":"n1820938108","loc":[-85.0882099,42.094393]},"n1820938109":{"id":"n1820938109","loc":[-85.5718484,41.9645371]},"n1820938110":{"id":"n1820938110","loc":[-85.2559764,42.0099317]},"n1820938111":{"id":"n1820938111","loc":[-85.2969284,41.973179]},"n1820938113":{"id":"n1820938113","loc":[-85.3875055,42.0019726]},"n1820938114":{"id":"n1820938114","loc":[-85.4250779,42.0068199]},"n1820938115":{"id":"n1820938115","loc":[-85.0645367,42.104889]},"n1820938116":{"id":"n1820938116","loc":[-85.1636762,42.0623724]},"n1820938117":{"id":"n1820938117","loc":[-85.0757322,42.1055935]},"n1820938118":{"id":"n1820938118","loc":[-85.3695197,41.9981559]},"n1820938120":{"id":"n1820938120","loc":[-85.1297516,42.0671027]},"n1820938121":{"id":"n1820938121","loc":[-85.1057448,42.0875551]},"n1820938122":{"id":"n1820938122","loc":[-85.2805175,41.9943182]},"n1820938123":{"id":"n1820938123","loc":[-85.2545173,42.0040722]},"n1820938124":{"id":"n1820938124","loc":[-84.9966607,42.0871319]},"n1820938125":{"id":"n1820938125","loc":[-85.0099899,42.0904612]},"n1820938126":{"id":"n1820938126","loc":[-85.2489919,42.0091102]},"n1820938127":{"id":"n1820938127","loc":[-85.0342706,42.0979476]},"n1820938128":{"id":"n1820938128","loc":[-85.1080891,42.0855884]},"n1820938129":{"id":"n1820938129","loc":[-85.0128183,42.0905356]},"n1820938130":{"id":"n1820938130","loc":[-85.631608,41.9434251]},"n1820938131":{"id":"n1820938131","loc":[-85.2551975,42.0008524]},"n1820938132":{"id":"n1820938132","loc":[-85.6421823,41.9096233]},"n1820938133":{"id":"n1820938133","loc":[-85.0125059,42.0906284]},"n1820938134":{"id":"n1820938134","loc":[-85.5499358,41.9701793]},"n1820938135":{"id":"n1820938135","loc":[-85.5472107,41.9712323]},"n1820938136":{"id":"n1820938136","loc":[-85.2760758,41.9958691]},"n1820938137":{"id":"n1820938137","loc":[-85.276678,41.9960433]},"n1820938138":{"id":"n1820938138","loc":[-85.0570319,42.1024731]},"n1820938140":{"id":"n1820938140","loc":[-85.2394325,42.0227492]},"n1820938142":{"id":"n1820938142","loc":[-85.5666341,41.9638829]},"n1820938144":{"id":"n1820938144","loc":[-85.258101,41.9996353]},"n1820938147":{"id":"n1820938147","loc":[-85.2129645,42.0413565]},"n1820938149":{"id":"n1820938149","loc":[-84.9962369,42.0868373]},"n1820938151":{"id":"n1820938151","loc":[-85.2570386,42.0084968]},"n1820938153":{"id":"n1820938153","loc":[-85.3971142,42.0050285]},"n1820938155":{"id":"n1820938155","loc":[-85.1072093,42.0855566]},"n1820938157":{"id":"n1820938157","loc":[-85.2840323,41.9920959]},"n1820938159":{"id":"n1820938159","loc":[-85.1187924,42.0816458]},"n1820938161":{"id":"n1820938161","loc":[-85.2681324,41.9985788]},"n1820938163":{"id":"n1820938163","loc":[-85.0887034,42.0984969]},"n1820938165":{"id":"n1820938165","loc":[-85.4133405,42.0073141]},"n1820938166":{"id":"n1820938166","loc":[-85.0097445,42.0902888]},"n1820938167":{"id":"n1820938167","loc":[-85.0828133,42.1037388]},"n1820938168":{"id":"n1820938168","loc":[-85.0549599,42.1030833]},"n1820938169":{"id":"n1820938169","loc":[-85.4571528,42.0010421]},"n1820938178":{"id":"n1820938178","loc":[-85.2706644,41.9975941]},"n1820938180":{"id":"n1820938180","loc":[-85.2258606,42.0335794]},"n1820938182":{"id":"n1820938182","loc":[-85.2832276,41.9814659]},"n1820938184":{"id":"n1820938184","loc":[-85.1082299,42.0860928]},"n1820938185":{"id":"n1820938185","loc":[-85.3839392,42.0022381]},"n1820938186":{"id":"n1820938186","loc":[-85.2772131,41.995905]},"n1820938187":{"id":"n1820938187","loc":[-85.1044895,42.0879214]},"n1820938188":{"id":"n1820938188","loc":[-85.2135267,42.0407087]},"n1820938189":{"id":"n1820938189","loc":[-85.2543993,42.0044628]},"n1820938190":{"id":"n1820938190","loc":[-85.1501793,42.0617351]},"n1820938191":{"id":"n1820938191","loc":[-85.3350587,41.9820469]},"n1820938192":{"id":"n1820938192","loc":[-85.1350731,42.0655735]},"n1820938193":{"id":"n1820938193","loc":[-85.0404008,42.1028843]},"n1820938194":{"id":"n1820938194","loc":[-85.6323161,41.943042]},"n1820938195":{"id":"n1820938195","loc":[-85.1259593,42.0742837]},"n1820938196":{"id":"n1820938196","loc":[-85.4562988,42.0033758]},"n1820938197":{"id":"n1820938197","loc":[-85.256824,42.0056826]},"n1820938198":{"id":"n1820938198","loc":[-85.2742103,41.9963862]},"n1820938199":{"id":"n1820938199","loc":[-85.0380888,42.1037877]},"n1820938200":{"id":"n1820938200","loc":[-85.47404,41.9944721]},"n1820938201":{"id":"n1820938201","loc":[-85.103021,42.087948]},"n1820938202":{"id":"n1820938202","loc":[-85.4030151,42.0065113]},"n1820938203":{"id":"n1820938203","loc":[-85.2113981,42.040735]},"n1820938204":{"id":"n1820938204","loc":[-85.2603433,41.9965137]},"n1820938206":{"id":"n1820938206","loc":[-85.1669378,42.0607634]},"n1820938207":{"id":"n1820938207","loc":[-85.0642027,42.1046076]},"n1820938208":{"id":"n1820938208","loc":[-85.2812428,41.9915696]},"n1820938209":{"id":"n1820938209","loc":[-85.0839559,42.1038343]},"n1820938210":{"id":"n1820938210","loc":[-85.1239946,42.0769368]},"n1820938211":{"id":"n1820938211","loc":[-85.2311177,42.0283042]},"n1820938212":{"id":"n1820938212","loc":[-85.2791614,41.9882682]},"n1820938213":{"id":"n1820938213","loc":[-85.2674941,41.9987582]},"n1820938214":{"id":"n1820938214","loc":[-85.352787,41.9919579]},"n1820938215":{"id":"n1820938215","loc":[-85.0874146,42.0952182]},"n1820938216":{"id":"n1820938216","loc":[-85.0069711,42.0877092]},"n1820938217":{"id":"n1820938217","loc":[-85.2059049,42.0404004]},"n1820938218":{"id":"n1820938218","loc":[-85.2403552,42.0227332]},"n1820938219":{"id":"n1820938219","loc":[-85.2492923,42.0098915]},"n1820938220":{"id":"n1820938220","loc":[-85.269778,41.9979541]},"n1820938221":{"id":"n1820938221","loc":[-85.2097673,42.0389024]},"n1820938222":{"id":"n1820938222","loc":[-85.0845942,42.1032015]},"n1820938223":{"id":"n1820938223","loc":[-84.993206,42.0858142]},"n1820938224":{"id":"n1820938224","loc":[-85.2108187,42.0402729]},"n1820938225":{"id":"n1820938225","loc":[-84.9893959,42.0873043]},"n1820938226":{"id":"n1820938226","loc":[-85.2952332,41.9719984]},"n1820938227":{"id":"n1820938227","loc":[-85.4100961,42.0081536]},"n1820938228":{"id":"n1820938228","loc":[-85.3299088,41.9785696]},"n1820938229":{"id":"n1820938229","loc":[-85.2258176,42.0340097]},"n1820938230":{"id":"n1820938230","loc":[-85.3146739,41.9711449]},"n1820938231":{"id":"n1820938231","loc":[-85.5447645,41.9712801]},"n1820938232":{"id":"n1820938232","loc":[-85.5510087,41.9705941]},"n1820938233":{"id":"n1820938233","loc":[-85.5122389,41.9703445]},"n1820938234":{"id":"n1820938234","loc":[-85.2792687,41.9865381]},"n1820938235":{"id":"n1820938235","loc":[-85.1475229,42.0630151]},"n1820938237":{"id":"n1820938237","loc":[-85.0332889,42.0996034]},"n1820938238":{"id":"n1820938238","loc":[-85.2588882,41.9986877]},"n1820938239":{"id":"n1820938239","loc":[-85.0656458,42.1050892]},"n1820938240":{"id":"n1820938240","loc":[-84.9913915,42.086098]},"n1820938241":{"id":"n1820938241","loc":[-85.4752416,41.9944402]},"n1820938242":{"id":"n1820938242","loc":[-85.1214304,42.0791147]},"n1820938243":{"id":"n1820938243","loc":[-85.0075183,42.0886925]},"n1820938244":{"id":"n1820938244","loc":[-85.1052888,42.0872087]},"n1820938245":{"id":"n1820938245","loc":[-85.3104252,41.9703393]},"n1820938246":{"id":"n1820938246","loc":[-85.232109,42.0318158]},"n1820938247":{"id":"n1820938247","loc":[-85.0756075,42.1059528]},"n1820938248":{"id":"n1820938248","loc":[-85.0075612,42.0890866]},"n1820938249":{"id":"n1820938249","loc":[-85.1013312,42.0897474]},"n1820938250":{"id":"n1820938250","loc":[-85.1168076,42.0828919]},"n1820938251":{"id":"n1820938251","loc":[-85.2951367,41.9723334]},"n1820938252":{"id":"n1820938252","loc":[-85.0879363,42.0976053]},"n1820938253":{"id":"n1820938253","loc":[-85.0354763,42.1021838]},"n1820938254":{"id":"n1820938254","loc":[-85.2379627,42.0236339]},"n1820938255":{"id":"n1820938255","loc":[-85.1308245,42.0685364]},"n1820938256":{"id":"n1820938256","loc":[-85.0914446,42.0934774]},"n1820938257":{"id":"n1820938257","loc":[-85.2436812,42.014069]},"n1820938258":{"id":"n1820938258","loc":[-85.0682529,42.1056106]},"n1820938259":{"id":"n1820938259","loc":[-85.290652,41.9766805]},"n1820938260":{"id":"n1820938260","loc":[-85.0133494,42.0897434]},"n1820938261":{"id":"n1820938261","loc":[-85.2753047,41.9949429]},"n1820938262":{"id":"n1820938262","loc":[-85.0314691,42.0950788]},"n1820938263":{"id":"n1820938263","loc":[-85.3444786,41.9908359]},"n1820938264":{"id":"n1820938264","loc":[-85.0443115,42.1009061]},"n1820938265":{"id":"n1820938265","loc":[-85.0634853,42.1043159]},"n1820938267":{"id":"n1820938267","loc":[-85.3978223,42.0053952]},"n1820938268":{"id":"n1820938268","loc":[-85.0228659,42.0911885]},"n1820938269":{"id":"n1820938269","loc":[-85.0220237,42.0906272]},"n1820938270":{"id":"n1820938270","loc":[-85.1061525,42.0863369]},"n1820938271":{"id":"n1820938271","loc":[-85.2382309,42.0233708]},"n1820938272":{"id":"n1820938272","loc":[-85.310672,41.9702755]},"n1820938273":{"id":"n1820938273","loc":[-85.1448192,42.0652613]},"n1820938274":{"id":"n1820938274","loc":[-85.6036057,41.9403766]},"n1820938275":{"id":"n1820938275","loc":[-85.0778941,42.1032413]},"n1820938276":{"id":"n1820938276","loc":[-85.1279374,42.0723974]},"n1820938277":{"id":"n1820938277","loc":[-85.2806635,41.9847836]},"n1820938278":{"id":"n1820938278","loc":[-85.2653201,41.9976352]},"n1820938279":{"id":"n1820938279","loc":[-85.0351665,42.1001805]},"n1820938280":{"id":"n1820938280","loc":[-85.0718269,42.1056253]},"n1820938281":{"id":"n1820938281","loc":[-85.2574248,42.0075322]},"n1820938282":{"id":"n1820938282","loc":[-85.126666,42.0740778]},"n1820938283":{"id":"n1820938283","loc":[-85.077705,42.1034733]},"n1820938284":{"id":"n1820938284","loc":[-85.3535552,41.9919045]},"n1820938286":{"id":"n1820938286","loc":[-85.2810711,41.9866657]},"n1820938287":{"id":"n1820938287","loc":[-85.4567494,42.0019885]},"n1820938288":{"id":"n1820938288","loc":[-85.2642419,41.9992936]},"n1820938289":{"id":"n1820938289","loc":[-85.2643344,41.9980925]},"n1820938290":{"id":"n1820938290","loc":[-85.3270335,41.9776125]},"n1820938291":{"id":"n1820938291","loc":[-85.1200584,42.0795077]},"n1820938292":{"id":"n1820938292","loc":[-85.2290792,42.0340256]},"n1820938293":{"id":"n1820938293","loc":[-85.6015887,41.9401372]},"n1820938294":{"id":"n1820938294","loc":[-85.5370869,41.970488]},"n1820938295":{"id":"n1820938295","loc":[-85.3108866,41.9698048]},"n1820938297":{"id":"n1820938297","loc":[-85.1556511,42.0628184]},"n1820938298":{"id":"n1820938298","loc":[-85.0027922,42.0875221]},"n1820938300":{"id":"n1820938300","loc":[-85.3873338,42.0040614]},"n1820938301":{"id":"n1820938301","loc":[-85.0350753,42.1004034]},"n1820938302":{"id":"n1820938302","loc":[-85.6239476,41.9411906]},"n1820938304":{"id":"n1820938304","loc":[-85.0118246,42.0897964]},"n1820938306":{"id":"n1820938306","loc":[-85.4796877,41.995275]},"n1820938307":{"id":"n1820938307","loc":[-85.5388636,41.9707856]},"n1820938309":{"id":"n1820938309","loc":[-85.2971902,41.9727773]},"n1820938310":{"id":"n1820938310","loc":[-85.5426831,41.9715513]},"n1820938311":{"id":"n1820938311","loc":[-85.2798373,41.9836671]},"n1820938312":{"id":"n1820938312","loc":[-85.2432198,42.0104017]},"n1820938313":{"id":"n1820938313","loc":[-85.2650412,41.9987554]},"n1820938317":{"id":"n1820938317","loc":[-85.0015423,42.0882386]},"n1820938318":{"id":"n1820938318","loc":[-85.1409783,42.064879]},"n1820938319":{"id":"n1820938319","loc":[-85.1691908,42.058995]},"n1820938320":{"id":"n1820938320","loc":[-85.1059165,42.0864882]},"n1820938321":{"id":"n1820938321","loc":[-85.3664941,41.9965771]},"n1820938323":{"id":"n1820938323","loc":[-85.3143198,41.9710971]},"n1820938324":{"id":"n1820938324","loc":[-85.0016067,42.0880675]},"n1820938325":{"id":"n1820938325","loc":[-85.0148139,42.0887164]},"n1820938326":{"id":"n1820938326","loc":[-85.0324682,42.0959056]},"n1820938327":{"id":"n1820938327","loc":[-85.0898661,42.0939921]},"n1820938328":{"id":"n1820938328","loc":[-85.2556427,42.0004936]},"n1820938329":{"id":"n1820938329","loc":[-85.6287112,41.9407437]},"n1820938330":{"id":"n1820938330","loc":[-84.9913392,42.0866701]},"n1820938331":{"id":"n1820938331","loc":[-85.2685777,41.9984632]},"n1820938332":{"id":"n1820938332","loc":[-85.0078884,42.0901614]},"n1820938333":{"id":"n1820938333","loc":[-84.999642,42.0878616]},"n1820938334":{"id":"n1820938334","loc":[-85.0188909,42.0899186]},"n1820938335":{"id":"n1820938335","loc":[-85.2830238,41.9819843]},"n1820938336":{"id":"n1820938336","loc":[-85.2491421,42.0096204]},"n1820938337":{"id":"n1820938337","loc":[-85.0585701,42.1034295]},"n1820938338":{"id":"n1820938338","loc":[-85.0651965,42.1051636]},"n1820938339":{"id":"n1820938339","loc":[-85.0583944,42.104292]},"n1820938340":{"id":"n1820938340","loc":[-85.119876,42.0801567]},"n1820938341":{"id":"n1820938341","loc":[-85.0943937,42.0931323]},"n1820938342":{"id":"n1820938342","loc":[-85.1504583,42.0613209]},"n1820938343":{"id":"n1820938343","loc":[-85.0425426,42.1019836]},"n1820938345":{"id":"n1820938345","loc":[-84.9991391,42.0878206]},"n1820938346":{"id":"n1820938346","loc":[-85.2563841,42.0094614]},"n1820938347":{"id":"n1820938347","loc":[-85.0515387,42.103297]},"n1820938348":{"id":"n1820938348","loc":[-85.0857261,42.1003636]},"n1820938349":{"id":"n1820938349","loc":[-85.078971,42.1029241]},"n1820938350":{"id":"n1820938350","loc":[-85.5699558,41.958931]},"n1820938351":{"id":"n1820938351","loc":[-85.3181285,41.9696533]},"n1820938352":{"id":"n1820938352","loc":[-85.5998506,41.9402329]},"n1820938353":{"id":"n1820938353","loc":[-85.2567277,42.000317]},"n1820938354":{"id":"n1820938354","loc":[-85.3082795,41.9708338]},"n1820938355":{"id":"n1820938355","loc":[-85.3127856,41.9692784]},"n1820938356":{"id":"n1820938356","loc":[-85.0340775,42.1010721]},"n1820938357":{"id":"n1820938357","loc":[-85.3158111,41.9706583]},"n1820938359":{"id":"n1820938359","loc":[-85.2312035,42.0280412]},"n1820938360":{"id":"n1820938360","loc":[-85.2448613,42.018477]},"n1820938361":{"id":"n1820938361","loc":[-85.29077,41.9759068]},"n1820938364":{"id":"n1820938364","loc":[-85.3677387,41.9976615]},"n1820938365":{"id":"n1820938365","loc":[-85.0785204,42.1030355]},"n1820938366":{"id":"n1820938366","loc":[-85.2262039,42.0333722]},"n1820938367":{"id":"n1820938367","loc":[-85.1226011,42.0780902]},"n1820938368":{"id":"n1820938368","loc":[-85.3229673,41.971129]},"n1820938369":{"id":"n1820938369","loc":[-85.385334,42.0000056]},"n1820938370":{"id":"n1820938370","loc":[-85.000098,42.0879094]},"n1820938372":{"id":"n1820938372","loc":[-85.3852481,42.0025091]},"n1820938373":{"id":"n1820938373","loc":[-85.3770513,41.9982515]},"n1820938374":{"id":"n1820938374","loc":[-85.6278314,41.9405362]},"n1820938375":{"id":"n1820938375","loc":[-85.6355133,41.9344068]},"n1820938376":{"id":"n1820938376","loc":[-85.635642,41.9324753]},"n1820938377":{"id":"n1820938377","loc":[-85.3154463,41.970778]},"n1820938378":{"id":"n1820938378","loc":[-85.0920334,42.093411]},"n1820938379":{"id":"n1820938379","loc":[-85.3269155,41.9722297]},"n1820938381":{"id":"n1820938381","loc":[-85.1134334,42.0849184]},"n1820938382":{"id":"n1820938382","loc":[-85.005968,42.088585]},"n1820938384":{"id":"n1820938384","loc":[-85.1245203,42.0757183]},"n1820938385":{"id":"n1820938385","loc":[-85.020704,42.0905396]},"n1820938386":{"id":"n1820938386","loc":[-85.119585,42.0808984]},"n1820938387":{"id":"n1820938387","loc":[-85.0072447,42.0880117]},"n1820938388":{"id":"n1820938388","loc":[-85.2742908,41.9960273]},"n1820938389":{"id":"n1820938389","loc":[-85.3275807,41.9696852]},"n1820938390":{"id":"n1820938390","loc":[-85.2385635,42.0231556]},"n1820938392":{"id":"n1820938392","loc":[-85.0202856,42.0900778]},"n1820938393":{"id":"n1820938393","loc":[-85.2067847,42.0395398]},"n1820938394":{"id":"n1820938394","loc":[-85.5183544,41.9713495]},"n1820938396":{"id":"n1820938396","loc":[-85.5073037,41.9736787]},"n1820938397":{"id":"n1820938397","loc":[-85.2519638,42.0114225]},"n1820938398":{"id":"n1820938398","loc":[-85.287487,41.9793285]},"n1820938399":{"id":"n1820938399","loc":[-85.2298088,42.0336431]},"n1820938400":{"id":"n1820938400","loc":[-85.229444,42.0339141]},"n1820938401":{"id":"n1820938401","loc":[-85.2421791,42.0220239]},"n1820938402":{"id":"n1820938402","loc":[-85.2976687,41.9737612]},"n1820938403":{"id":"n1820938403","loc":[-85.3622069,41.993473]},"n1820938404":{"id":"n1820938404","loc":[-85.2465458,42.014906]},"n1820938405":{"id":"n1820938405","loc":[-85.5724663,41.9639412]},"n1820938406":{"id":"n1820938406","loc":[-85.3708501,41.9982037]},"n1820938408":{"id":"n1820938408","loc":[-85.2564592,42.0055311]},"n1820938409":{"id":"n1820938409","loc":[-85.1192846,42.0810856]},"n1820938410":{"id":"n1820938410","loc":[-85.5623812,41.971663]},"n1820938411":{"id":"n1820938411","loc":[-85.3221948,41.9719665]},"n1820938412":{"id":"n1820938412","loc":[-85.5168738,41.9710305]},"n1820938413":{"id":"n1820938413","loc":[-85.4546852,42.0061127]},"n1820938414":{"id":"n1820938414","loc":[-85.5896153,41.9463617]},"n1820938415":{"id":"n1820938415","loc":[-85.2978189,41.9722138]},"n1820938416":{"id":"n1820938416","loc":[-85.1021681,42.0883581]},"n1820938417":{"id":"n1820938417","loc":[-85.2797193,41.9912984]},"n1820938419":{"id":"n1820938419","loc":[-85.2362461,42.0248533]},"n1820938420":{"id":"n1820938420","loc":[-85.4833639,41.9846252]},"n1820938422":{"id":"n1820938422","loc":[-85.3281064,41.9689433]},"n1820938424":{"id":"n1820938424","loc":[-85.2416963,42.0130088]},"n1820938425":{"id":"n1820938425","loc":[-85.5718655,41.9564577]},"n1820938426":{"id":"n1820938426","loc":[-85.0512812,42.1030701]},"n1820938427":{"id":"n1820938427","loc":[-85.1273527,42.0723616]},"n1820938428":{"id":"n1820938428","loc":[-85.0215033,42.0904083]},"n1820938429":{"id":"n1820938429","loc":[-85.6169953,41.942228]},"n1820938430":{"id":"n1820938430","loc":[-85.2829165,41.9907243]},"n1820938431":{"id":"n1820938431","loc":[-85.2240796,42.0374203]},"n1820938432":{"id":"n1820938432","loc":[-85.0167598,42.0898442]},"n1820938433":{"id":"n1820938433","loc":[-85.2132649,42.0411334]},"n1820938434":{"id":"n1820938434","loc":[-85.2293839,42.031513]},"n1820938435":{"id":"n1820938435","loc":[-85.1203374,42.0792608]},"n1820938436":{"id":"n1820938436","loc":[-85.109571,42.086268]},"n1820938437":{"id":"n1820938437","loc":[-85.1079026,42.0853842]},"n1820938438":{"id":"n1820938438","loc":[-85.109237,42.0862413]},"n1820938439":{"id":"n1820938439","loc":[-85.2259936,42.0350831]},"n1820938440":{"id":"n1820938440","loc":[-85.3669705,41.99679]},"n1820938441":{"id":"n1820938441","loc":[-85.2418143,42.0223507]},"n1820938442":{"id":"n1820938442","loc":[-85.3101248,41.9702515]},"n1820938443":{"id":"n1820938443","loc":[-85.069315,42.1059688]},"n1820938444":{"id":"n1820938444","loc":[-85.205862,42.0410378]},"n1820938445":{"id":"n1820938445","loc":[-85.0388076,42.1036604]},"n1820938446":{"id":"n1820938446","loc":[-85.2225389,42.0370115]},"n1820938447":{"id":"n1820938447","loc":[-85.3241474,41.9719346]},"n1820938448":{"id":"n1820938448","loc":[-85.3125496,41.9690789]},"n1820938449":{"id":"n1820938449","loc":[-85.1146497,42.0857039]},"n1820938450":{"id":"n1820938450","loc":[-85.1333944,42.0714963]},"n1820938451":{"id":"n1820938451","loc":[-85.5619306,41.9720937]},"n1820938452":{"id":"n1820938452","loc":[-85.2553651,42.0006479]},"n1820938453":{"id":"n1820938453","loc":[-85.3151137,41.9710093]},"n1820938454":{"id":"n1820938454","loc":[-85.2592315,41.9977947]},"n1820938455":{"id":"n1820938455","loc":[-85.2655723,41.9995966]},"n1820938456":{"id":"n1820938456","loc":[-85.4820652,41.9959233]},"n1820938459":{"id":"n1820938459","loc":[-85.450737,42.0055068]},"n1820938460":{"id":"n1820938460","loc":[-85.2428658,42.0205573]},"n1820938461":{"id":"n1820938461","loc":[-85.0835576,42.1021559]},"n1820938462":{"id":"n1820938462","loc":[-85.244636,42.0194733]},"n1820938463":{"id":"n1820938463","loc":[-85.5702562,41.9581332]},"n1820938465":{"id":"n1820938465","loc":[-85.5680031,41.9659515]},"n1820938467":{"id":"n1820938467","loc":[-85.2798752,41.9948353]},"n1820938468":{"id":"n1820938468","loc":[-85.0477407,42.1015537]},"n1820938469":{"id":"n1820938469","loc":[-85.6403842,41.913732]},"n1820938470":{"id":"n1820938470","loc":[-85.0396029,42.103289]},"n1820938471":{"id":"n1820938471","loc":[-85.2824702,41.9907777]},"n1820938472":{"id":"n1820938472","loc":[-85.2969284,41.9735538]},"n1820938474":{"id":"n1820938474","loc":[-85.401041,42.0070853]},"n1820938475":{"id":"n1820938475","loc":[-85.4116625,42.0073883]},"n1820938476":{"id":"n1820938476","loc":[-85.0437764,42.1016214]},"n1820938477":{"id":"n1820938477","loc":[-85.3643269,41.9958436]},"n1820938478":{"id":"n1820938478","loc":[-85.3895182,42.0009465]},"n1820938479":{"id":"n1820938479","loc":[-85.636157,41.9333373]},"n1820938480":{"id":"n1820938480","loc":[-85.2811355,41.9858044]},"n1820938481":{"id":"n1820938481","loc":[-85.0239052,42.092153]},"n1820938482":{"id":"n1820938482","loc":[-85.2558798,42.0053557]},"n1820938483":{"id":"n1820938483","loc":[-85.2544422,42.0047339]},"n1820938484":{"id":"n1820938484","loc":[-85.4864683,41.9843183]},"n1820938485":{"id":"n1820938485","loc":[-85.2554185,42.0031075]},"n1820938486":{"id":"n1820938486","loc":[-85.3082795,41.9712486]},"n1820938487":{"id":"n1820938487","loc":[-85.2433378,42.0133436]},"n1820938488":{"id":"n1820938488","loc":[-85.0216696,42.0904162]},"n1820938489":{"id":"n1820938489","loc":[-85.2546138,42.0050289]},"n1820938490":{"id":"n1820938490","loc":[-85.2717521,41.9977349]},"n1820938491":{"id":"n1820938491","loc":[-85.0100489,42.0908195]},"n1820938492":{"id":"n1820938492","loc":[-85.207879,42.0392211]},"n1820938493":{"id":"n1820938493","loc":[-85.0007363,42.0882836]},"n1820938494":{"id":"n1820938494","loc":[-85.5775303,41.9504097]},"n1820938495":{"id":"n1820938495","loc":[-85.1131584,42.0847683]},"n1820938496":{"id":"n1820938496","loc":[-85.0887825,42.0941633]},"n1820938497":{"id":"n1820938497","loc":[-85.1185926,42.0818938]},"n1820938498":{"id":"n1820938498","loc":[-85.2748487,41.9948712]},"n1820938499":{"id":"n1820938499","loc":[-85.2566952,42.0090788]},"n1820938500":{"id":"n1820938500","loc":[-85.0774757,42.1036234]},"n1820938501":{"id":"n1820938501","loc":[-85.4190869,42.008903]},"n1820938502":{"id":"n1820938502","loc":[-85.1140395,42.0850577]},"n1820938503":{"id":"n1820938503","loc":[-85.1136104,42.0848627]},"n1820938504":{"id":"n1820938504","loc":[-85.5828089,41.9480638]},"n1820938505":{"id":"n1820938505","loc":[-85.625514,41.9405202]},"n1820938506":{"id":"n1820938506","loc":[-85.2063384,42.0398322]},"n1820938507":{"id":"n1820938507","loc":[-85.3395476,41.9851636]},"n1820938508":{"id":"n1820938508","loc":[-85.0328853,42.0963606]},"n1820938510":{"id":"n1820938510","loc":[-85.1170369,42.0843702]},"n1820938511":{"id":"n1820938511","loc":[-85.2784748,41.9868487]},"n1820938512":{"id":"n1820938512","loc":[-85.6310501,41.9435528]},"n1820938514":{"id":"n1820938514","loc":[-85.0334284,42.0981028]},"n1820938515":{"id":"n1820938515","loc":[-84.9912091,42.0868226]},"n1820938516":{"id":"n1820938516","loc":[-85.2806141,41.9940351]},"n1820938517":{"id":"n1820938517","loc":[-85.1233025,42.0776734]},"n1820938518":{"id":"n1820938518","loc":[-85.2047891,42.0429023]},"n1820938519":{"id":"n1820938519","loc":[-85.1475443,42.0648312]},"n1820938520":{"id":"n1820938520","loc":[-85.2644685,41.9990891]},"n1820938521":{"id":"n1820938521","loc":[-85.1056281,42.0872553]},"n1820938522":{"id":"n1820938522","loc":[-85.4813184,41.9930105]},"n1820938523":{"id":"n1820938523","loc":[-85.321551,41.9722936]},"n1820938524":{"id":"n1820938524","loc":[-85.1564664,42.0631211]},"n1820938525":{"id":"n1820938525","loc":[-85.4149885,42.0079144]},"n1820938527":{"id":"n1820938527","loc":[-85.2861888,41.9803653]},"n1820938528":{"id":"n1820938528","loc":[-85.1301379,42.0682178]},"n1820938529":{"id":"n1820938529","loc":[-85.4156537,42.0084247]},"n1820938530":{"id":"n1820938530","loc":[-85.245151,42.0176082]},"n1820938531":{"id":"n1820938531","loc":[-85.457818,42.0001651]},"n1820938532":{"id":"n1820938532","loc":[-85.310951,41.9694538]},"n1820938533":{"id":"n1820938533","loc":[-85.1509089,42.0611298]},"n1820938534":{"id":"n1820938534","loc":[-85.1108249,42.086321]},"n1820938535":{"id":"n1820938535","loc":[-85.1260344,42.0740687]},"n1820938536":{"id":"n1820938536","loc":[-85.4561228,42.0042791]},"n1820938537":{"id":"n1820938537","loc":[-85.2805082,41.9945761]},"n1820938538":{"id":"n1820938538","loc":[-85.273352,41.9981921]},"n1820938539":{"id":"n1820938539","loc":[-85.1084216,42.0864364]},"n1820938540":{"id":"n1820938540","loc":[-85.5009737,41.9773637]},"n1820938541":{"id":"n1820938541","loc":[-85.3960843,42.0051879]},"n1820938542":{"id":"n1820938542","loc":[-85.3425088,41.9865034]},"n1820938545":{"id":"n1820938545","loc":[-84.9937907,42.0860849]},"n1820938546":{"id":"n1820938546","loc":[-85.1084176,42.086065]},"n1820938547":{"id":"n1820938547","loc":[-85.3492851,41.9924786]},"n1820938548":{"id":"n1820938548","loc":[-85.2512235,42.0101147]},"n1820938549":{"id":"n1820938549","loc":[-85.3717298,41.9979326]},"n1820938551":{"id":"n1820938551","loc":[-85.2573712,42.0064081]},"n1820938552":{"id":"n1820938552","loc":[-85.2514596,42.010139]},"n1820938553":{"id":"n1820938553","loc":[-85.416512,42.0088073]},"n1820938554":{"id":"n1820938554","loc":[-85.4365964,42.0061606]},"n1820938555":{"id":"n1820938555","loc":[-85.4552431,42.0057301]},"n1820938556":{"id":"n1820938556","loc":[-85.2916283,41.9778769]},"n1820938557":{"id":"n1820938557","loc":[-85.100709,42.0902968]},"n1820938558":{"id":"n1820938558","loc":[-85.4703064,41.9965771]},"n1820938559":{"id":"n1820938559","loc":[-85.3134722,41.9696134]},"n1820938560":{"id":"n1820938560","loc":[-85.4834213,41.9885768]},"n1820938561":{"id":"n1820938561","loc":[-85.2740641,41.9975236]},"n1820938562":{"id":"n1820938562","loc":[-85.148334,42.0623405]},"n1820938563":{"id":"n1820938563","loc":[-85.2358598,42.0263675]},"n1820938565":{"id":"n1820938565","loc":[-85.2902979,41.9790892]},"n1820938566":{"id":"n1820938566","loc":[-85.2528865,42.0112869]},"n1820938567":{"id":"n1820938567","loc":[-85.2595319,41.9973003]},"n1820938568":{"id":"n1820938568","loc":[-85.071151,42.105689]},"n1820938570":{"id":"n1820938570","loc":[-85.299278,41.9732188]},"n1820938571":{"id":"n1820938571","loc":[-85.0354669,42.1024771]},"n1820938583":{"id":"n1820938583","loc":[-85.3313937,41.972562]},"n1820938585":{"id":"n1820938585","loc":[-85.0756933,42.1058334]},"n1820938587":{"id":"n1820938587","loc":[-85.3130324,41.9694219]},"n1820938590":{"id":"n1820938590","loc":[-85.0934227,42.0931681]},"n1820938592":{"id":"n1820938592","loc":[-85.3517956,41.9922553]},"n1820938593":{"id":"n1820938593","loc":[-85.4023971,42.0065169]},"n1820938594":{"id":"n1820938594","loc":[-85.3506798,41.9925583]},"n1820938595":{"id":"n1820938595","loc":[-85.3673524,41.9971193]},"n1820938596":{"id":"n1820938596","loc":[-85.1073608,42.0853523]},"n1820938597":{"id":"n1820938597","loc":[-85.2976579,41.972477]},"n1820938598":{"id":"n1820938598","loc":[-85.5616517,41.9694295]},"n1820938599":{"id":"n1820938599","loc":[-85.3552074,41.9921915]},"n1820938600":{"id":"n1820938600","loc":[-85.4665126,41.9999953]},"n1820938601":{"id":"n1820938601","loc":[-85.2740695,41.9966226]},"n1820938602":{"id":"n1820938602","loc":[-85.279376,41.9886669]},"n1820938603":{"id":"n1820938603","loc":[-85.0771109,42.1040413]},"n1820938604":{"id":"n1820938604","loc":[-85.2636049,41.9977895]},"n1820938605":{"id":"n1820938605","loc":[-85.3762145,41.9976456]},"n1820938606":{"id":"n1820938606","loc":[-85.2321369,42.0289577]},"n1820938620":{"id":"n1820938620","loc":[-85.4947724,41.9776189]},"n1820938622":{"id":"n1820938622","loc":[-85.1547069,42.0622768]},"n1820938624":{"id":"n1820938624","loc":[-85.0005056,42.0880249]},"n1820938626":{"id":"n1820938626","loc":[-85.0735596,42.1059357]},"n1820938628":{"id":"n1820938628","loc":[-85.4665298,41.99932]},"n1820938629":{"id":"n1820938629","loc":[-85.434515,42.0065273]},"n1820938630":{"id":"n1820938630","loc":[-85.117462,42.0823823]},"n1820938631":{"id":"n1820938631","loc":[-85.0131777,42.0890707]},"n1820938632":{"id":"n1820938632","loc":[-85.0875326,42.0961934]},"n1820938634":{"id":"n1820938634","loc":[-85.6433839,41.9112042]},"n1820938635":{"id":"n1820938635","loc":[-85.1366181,42.064969]},"n1820938636":{"id":"n1820938636","loc":[-85.073109,42.1057925]},"n1820938638":{"id":"n1820938638","loc":[-85.161406,42.0632541]},"n1820938640":{"id":"n1820938640","loc":[-85.6343932,41.9188845]},"n1820938642":{"id":"n1820938642","loc":[-85.2500004,42.010306]},"n1820938644":{"id":"n1820938644","loc":[-85.291918,41.9753166]},"n1820938663":{"id":"n1820938663","loc":[-85.2841611,41.9916812]},"n1820938664":{"id":"n1820938664","loc":[-85.1052955,42.0868134]},"n1820938665":{"id":"n1820938665","loc":[-85.4606118,42.0005534]},"n1820938666":{"id":"n1820938666","loc":[-85.5672736,41.9642922]},"n1820938667":{"id":"n1820938667","loc":[-85.6348481,41.9316932]},"n1820938668":{"id":"n1820938668","loc":[-85.0224904,42.0909576]},"n1820938669":{"id":"n1820938669","loc":[-85.0133856,42.0899755]},"n1820938670":{"id":"n1820938670","loc":[-85.344779,41.991139]},"n1820938671":{"id":"n1820938671","loc":[-85.632874,41.9425313]},"n1820938673":{"id":"n1820938673","loc":[-85.4941501,41.9779698]},"n1820938675":{"id":"n1820938675","loc":[-85.0862559,42.0997519]},"n1820938676":{"id":"n1820938676","loc":[-85.0097874,42.0898032]},"n1820938678":{"id":"n1820938678","loc":[-84.9913553,42.0863675]},"n1820938680":{"id":"n1820938680","loc":[-85.0533666,42.1038315]},"n1820938682":{"id":"n1820938682","loc":[-85.2950294,41.9743914]},"n1820938684":{"id":"n1820938684","loc":[-85.2517385,42.0104499]},"n1820938686":{"id":"n1820938686","loc":[-85.0247971,42.0922514]},"n1820938688":{"id":"n1820938688","loc":[-85.0807037,42.1026017]},"n1820938690":{"id":"n1820938690","loc":[-85.52462,41.9722748]},"n1820938694":{"id":"n1820938694","loc":[-85.2586535,41.9988818]},"n1820938695":{"id":"n1820938695","loc":[-85.0931612,42.092948]},"n1820938697":{"id":"n1820938697","loc":[-85.2470822,42.016564]},"n1820938698":{"id":"n1820938698","loc":[-85.4143018,42.0075158]},"n1820938699":{"id":"n1820938699","loc":[-85.0771484,42.104487]},"n1820938700":{"id":"n1820938700","loc":[-85.0291208,42.0942775]},"n1820938701":{"id":"n1820938701","loc":[-85.6367964,41.9185971]},"n1820938702":{"id":"n1820938702","loc":[-85.085419,42.1010693]},"n1820938703":{"id":"n1820938703","loc":[-85.0583877,42.1040584]},"n1820938705":{"id":"n1820938705","loc":[-85.2573379,42.0003182]},"n1820938706":{"id":"n1820938706","loc":[-85.2655937,41.9981575]},"n1820938707":{"id":"n1820938707","loc":[-85.023181,42.0915758]},"n1820938708":{"id":"n1820938708","loc":[-85.2318687,42.0274674]},"n1820938709":{"id":"n1820938709","loc":[-85.1056389,42.0866184]},"n1820938710":{"id":"n1820938710","loc":[-85.5276265,41.9700978]},"n1820938711":{"id":"n1820938711","loc":[-85.0864128,42.0945761]},"n1820938712":{"id":"n1820938712","loc":[-84.9897071,42.0871888]},"n1820938714":{"id":"n1820938714","loc":[-85.1328845,42.0665611]},"n1820938715":{"id":"n1820938715","loc":[-85.0336537,42.0991377]},"n1820938716":{"id":"n1820938716","loc":[-85.087597,42.0986692]},"n1820938717":{"id":"n1820938717","loc":[-85.1241394,42.0761882]},"n1820938718":{"id":"n1820938718","loc":[-85.1176002,42.0847723]},"n1820938719":{"id":"n1820938719","loc":[-85.2423615,42.0216572]},"n1820938721":{"id":"n1820938721","loc":[-85.2196378,42.0387908]},"n1820938722":{"id":"n1820938722","loc":[-85.0164272,42.0890082]},"n1820938723":{"id":"n1820938723","loc":[-85.5917182,41.9451807]},"n1820938724":{"id":"n1820938724","loc":[-85.2458806,42.0086638]},"n1820938725":{"id":"n1820938725","loc":[-85.1264474,42.0740527]},"n1820938726":{"id":"n1820938726","loc":[-85.1961631,42.04738]},"n1820938727":{"id":"n1820938727","loc":[-85.2784643,41.9943648]},"n1820938728":{"id":"n1820938728","loc":[-85.2905554,41.9763216]},"n1820938729":{"id":"n1820938729","loc":[-85.2913386,41.9771511]},"n1820938730":{"id":"n1820938730","loc":[-85.0112519,42.0895683]},"n1820938732":{"id":"n1820938732","loc":[-85.4290261,42.0064531]},"n1820938733":{"id":"n1820938733","loc":[-85.3867073,42.0031629]},"n1820938734":{"id":"n1820938734","loc":[-85.4943647,41.9836005]},"n1820938735":{"id":"n1820938735","loc":[-85.4900303,41.9860728]},"n1820938736":{"id":"n1820938736","loc":[-85.0866153,42.0944539]},"n1820938737":{"id":"n1820938737","loc":[-85.0869532,42.0990911]},"n1820938738":{"id":"n1820938738","loc":[-85.6321659,41.9208851]},"n1820938739":{"id":"n1820938739","loc":[-85.5930485,41.9433453]},"n1820938740":{"id":"n1820938740","loc":[-85.0406851,42.102733]},"n1820938741":{"id":"n1820938741","loc":[-85.1051131,42.0869846]},"n1820938742":{"id":"n1820938742","loc":[-85.1377554,42.0648893]},"n1820938743":{"id":"n1820938743","loc":[-85.2795694,41.994604]},"n1820938745":{"id":"n1820938745","loc":[-85.4948153,41.9826594]},"n1820938746":{"id":"n1820938746","loc":[-85.4488916,42.0050923]},"n1820938747":{"id":"n1820938747","loc":[-85.1052526,42.0866144]},"n1820938748":{"id":"n1820938748","loc":[-85.1468749,42.0653991]},"n1820938749":{"id":"n1820938749","loc":[-85.0856886,42.1006104]},"n1820938750":{"id":"n1820938750","loc":[-85.2144022,42.0404004]},"n1820938751":{"id":"n1820938751","loc":[-85.277771,41.9907458]},"n1820938752":{"id":"n1820938752","loc":[-85.1474542,42.0636149]},"n1820938753":{"id":"n1820938753","loc":[-85.0820515,42.1028075]},"n1820938754":{"id":"n1820938754","loc":[-85.1122948,42.08525]},"n1820938756":{"id":"n1820938756","loc":[-85.0173352,42.0901933]},"n1820938757":{"id":"n1820938757","loc":[-85.2259721,42.0354018]},"n1820938758":{"id":"n1820938758","loc":[-85.0872389,42.0987795]},"n1820938759":{"id":"n1820938759","loc":[-85.2291436,42.031874]},"n1820938760":{"id":"n1820938760","loc":[-85.3802485,42.0016002]},"n1820938761":{"id":"n1820938761","loc":[-85.3945822,42.0057938]},"n1820938762":{"id":"n1820938762","loc":[-85.5273237,41.9713017]},"n1820938763":{"id":"n1820938763","loc":[-85.2868862,41.9798629]},"n1820938764":{"id":"n1820938764","loc":[-85.2516677,42.0107899]},"n1820938766":{"id":"n1820938766","loc":[-85.3183002,41.9693103]},"n1820938768":{"id":"n1820938768","loc":[-85.2159042,42.0401932]},"n1820938770":{"id":"n1820938770","loc":[-85.0094481,42.0911141]},"n1820938771":{"id":"n1820938771","loc":[-85.0244538,42.0922155]},"n1820938772":{"id":"n1820938772","loc":[-85.231697,42.028862]},"n1820938773":{"id":"n1820938773","loc":[-85.2102394,42.0390617]},"n1820938774":{"id":"n1820938774","loc":[-85.2463419,42.0151212]},"n1820938775":{"id":"n1820938775","loc":[-85.0726195,42.1056424]},"n1820938776":{"id":"n1820938776","loc":[-85.0060431,42.0883262]},"n1820938778":{"id":"n1820938778","loc":[-85.425889,42.0056982]},"n1820938779":{"id":"n1820938779","loc":[-85.1183042,42.0820638]},"n1820938780":{"id":"n1820938780","loc":[-85.441596,42.0058257]},"n1820938781":{"id":"n1820938781","loc":[-85.1124879,42.0847086]},"n1820938782":{"id":"n1820938782","loc":[-85.2452733,42.0153894]},"n1820938783":{"id":"n1820938783","loc":[-85.2741191,41.9969244]},"n1820938784":{"id":"n1820938784","loc":[-85.2829487,41.9822236]},"n1820938785":{"id":"n1820938785","loc":[-85.3202743,41.972142]},"n1820938786":{"id":"n1820938786","loc":[-85.2345402,42.0266465]},"n1820938787":{"id":"n1820938787","loc":[-85.3037626,41.9724611]},"n1820938789":{"id":"n1820938789","loc":[-85.2474792,42.0161973]},"n1820938790":{"id":"n1820938790","loc":[-85.2951045,41.9727323]},"n1820938791":{"id":"n1820938791","loc":[-85.322345,41.9712726]},"n1820938792":{"id":"n1820938792","loc":[-85.2402372,42.0110394]},"n1820938793":{"id":"n1820938793","loc":[-85.5135693,41.9698659]},"n1820938794":{"id":"n1820938794","loc":[-85.4695339,41.9967366]},"n1820938796":{"id":"n1820938796","loc":[-85.0418492,42.1011131]},"n1820938797":{"id":"n1820938797","loc":[-85.3334107,41.9806337]},"n1820938798":{"id":"n1820938798","loc":[-85.5625314,41.9711685]},"n1820938799":{"id":"n1820938799","loc":[-85.3755707,41.9973585]},"n1820938800":{"id":"n1820938800","loc":[-85.5227532,41.9722429]},"n1820938801":{"id":"n1820938801","loc":[-85.4267687,42.0052836]},"n1820938803":{"id":"n1820938803","loc":[-85.0284704,42.0940837]},"n1820938804":{"id":"n1820938804","loc":[-85.015585,42.0885305]},"n1820938805":{"id":"n1820938805","loc":[-85.0765905,42.1053865]},"n1820938806":{"id":"n1820938806","loc":[-85.2614953,41.9964551]},"n1820938808":{"id":"n1820938808","loc":[-85.0307355,42.0947313]},"n1820938810":{"id":"n1820938810","loc":[-85.3894753,42.0003565]},"n1820938812":{"id":"n1820938812","loc":[-85.0868848,42.095006]},"n1820938813":{"id":"n1820938813","loc":[-85.3854198,42.0009465]},"n1820938814":{"id":"n1820938814","loc":[-85.2659692,41.9993534]},"n1820938815":{"id":"n1820938815","loc":[-85.1234259,42.0765266]},"n1820938816":{"id":"n1820938816","loc":[-85.1426906,42.0648893]},"n1820938818":{"id":"n1820938818","loc":[-85.1014533,42.0893067]},"n1820938819":{"id":"n1820938819","loc":[-85.0883064,42.098067]},"n1820938820":{"id":"n1820938820","loc":[-85.0503156,42.102704]},"n1820938821":{"id":"n1820938821","loc":[-85.1179649,42.0821884]},"n1820938822":{"id":"n1820938822","loc":[-85.3484697,41.9921596]},"n1820938823":{"id":"n1820938823","loc":[-85.3732962,41.9970874]},"n1820938824":{"id":"n1820938824","loc":[-85.2784104,41.9898312]},"n1820938825":{"id":"n1820938825","loc":[-85.4441709,42.0052198]},"n1820938826":{"id":"n1820938826","loc":[-85.3925438,42.0038326]},"n1820938829":{"id":"n1820938829","loc":[-85.5717582,41.9621861]},"n1820938830":{"id":"n1820938830","loc":[-85.0866314,42.0995051]},"n1820938831":{"id":"n1820938831","loc":[-85.576672,41.9522769]},"n1820938832":{"id":"n1820938832","loc":[-85.1587238,42.0636205]},"n1820938833":{"id":"n1820938833","loc":[-85.3804245,41.9999155]},"n1820938834":{"id":"n1820938834","loc":[-85.280083,41.9948843]},"n1820938836":{"id":"n1820938836","loc":[-85.561892,41.9686693]},"n1820938837":{"id":"n1820938837","loc":[-85.0158975,42.0885253]},"n1820938838":{"id":"n1820938838","loc":[-85.4248204,42.007633]},"n1820938839":{"id":"n1820938839","loc":[-85.0352738,42.1039657]},"n1820938840":{"id":"n1820938840","loc":[-85.211956,42.0411812]},"n1820938841":{"id":"n1820938841","loc":[-85.4816575,41.9908997]},"n1820938842":{"id":"n1820938842","loc":[-85.3807635,42.0020308]},"n1820938843":{"id":"n1820938843","loc":[-85.0100865,42.0898521]},"n1820938844":{"id":"n1820938844","loc":[-85.0103936,42.0897434]},"n1820938848":{"id":"n1820938848","loc":[-85.2430052,42.0131363]},"n1820938849":{"id":"n1820938849","loc":[-85.112559,42.0853723]},"n1820938851":{"id":"n1820938851","loc":[-85.3641553,41.9952535]},"n1820938852":{"id":"n1820938852","loc":[-85.2087373,42.0390777]},"n1820938853":{"id":"n1820938853","loc":[-85.2473933,42.0148263]},"n1820938854":{"id":"n1820938854","loc":[-85.0213464,42.090509]},"n1820938855":{"id":"n1820938855","loc":[-85.0673208,42.1052353]},"n1820938856":{"id":"n1820938856","loc":[-85.1003053,42.0905528]},"n1820938857":{"id":"n1820938857","loc":[-85.2617367,41.9965389]},"n1820938858":{"id":"n1820938858","loc":[-85.280363,41.9916015]},"n1820938859":{"id":"n1820938859","loc":[-85.0038866,42.0873469]},"n1820938860":{"id":"n1820938860","loc":[-85.2476401,42.0151451]},"n1820938861":{"id":"n1820938861","loc":[-85.193717,42.0499294]},"n1820938862":{"id":"n1820938862","loc":[-85.3478689,41.9917609]},"n1820938863":{"id":"n1820938863","loc":[-85.5638017,41.9648881]},"n1820938864":{"id":"n1820938864","loc":[-85.4356308,42.0064476]},"n1820938865":{"id":"n1820938865","loc":[-85.0561722,42.1023509]},"n1820938867":{"id":"n1820938867","loc":[-85.2256031,42.0356034]},"n1820938868":{"id":"n1820938868","loc":[-85.6102576,41.9420844]},"n1820938869":{"id":"n1820938869","loc":[-85.2285213,42.0339938]},"n1820938870":{"id":"n1820938870","loc":[-85.0326238,42.0978003]},"n1820938871":{"id":"n1820938871","loc":[-85.0131389,42.0903736]},"n1820938872":{"id":"n1820938872","loc":[-85.2550859,42.0012259]},"n1820938873":{"id":"n1820938873","loc":[-85.1130029,42.0846966]},"n1820938874":{"id":"n1820938874","loc":[-85.1579041,42.06336]},"n1820938875":{"id":"n1820938875","loc":[-85.0430522,42.1020234]},"n1820938876":{"id":"n1820938876","loc":[-85.2786679,41.9865935]},"n1820938877":{"id":"n1820938877","loc":[-85.1221666,42.0788706]},"n1820938878":{"id":"n1820938878","loc":[-85.2554614,42.0103303]},"n1820938879":{"id":"n1820938879","loc":[-85.2349801,42.0265748]},"n1820938880":{"id":"n1820938880","loc":[-85.0997434,42.0907864]},"n1820938881":{"id":"n1820938881","loc":[-85.0045464,42.0878167]},"n1820938882":{"id":"n1820938882","loc":[-85.2728048,41.9982519]},"n1820938883":{"id":"n1820938883","loc":[-85.3111333,41.9691587]},"n1820938884":{"id":"n1820938884","loc":[-85.3219802,41.9721899]},"n1820938885":{"id":"n1820938885","loc":[-85.3091378,41.9699325]},"n1820938887":{"id":"n1820938887","loc":[-85.4242367,42.0085203]},"n1820938888":{"id":"n1820938888","loc":[-84.9968377,42.0874504]},"n1820938890":{"id":"n1820938890","loc":[-85.5443139,41.9714078]},"n1820938891":{"id":"n1820938891","loc":[-85.6404013,41.9154676]},"n1820938892":{"id":"n1820938892","loc":[-85.3644986,41.9962582]},"n1820938893":{"id":"n1820938893","loc":[-85.0496772,42.1018323]},"n1820938894":{"id":"n1820938894","loc":[-85.297261,41.9737373]},"n1820938895":{"id":"n1820938895","loc":[-85.0327096,42.098071]},"n1820938896":{"id":"n1820938896","loc":[-85.3856773,41.9996867]},"n1820938897":{"id":"n1820938897","loc":[-85.0493862,42.1015509]},"n1820938898":{"id":"n1820938898","loc":[-84.9969879,42.0876614]},"n1820938899":{"id":"n1820938899","loc":[-85.0848625,42.1013587]},"n1820938900":{"id":"n1820938900","loc":[-85.5853195,41.9479201]},"n1820938901":{"id":"n1820938901","loc":[-85.6329169,41.9387964]},"n1820938902":{"id":"n1820938902","loc":[-85.0843046,42.1029468]},"n1820938903":{"id":"n1820938903","loc":[-85.1228747,42.0778474]},"n1820938904":{"id":"n1820938904","loc":[-85.4855456,41.984095]},"n1820938905":{"id":"n1820938905","loc":[-85.0573269,42.1026801]},"n1820938906":{"id":"n1820938906","loc":[-85.2425868,42.0131523]},"n1820938907":{"id":"n1820938907","loc":[-85.1149622,42.0860053]},"n1820938908":{"id":"n1820938908","loc":[-85.4833097,41.9951578]},"n1820938909":{"id":"n1820938909","loc":[-85.075979,42.1056372]},"n1820938910":{"id":"n1820938910","loc":[-85.0338509,42.0977139]},"n1820938911":{"id":"n1820938911","loc":[-85.6384272,41.9115715]},"n1820938912":{"id":"n1820938912","loc":[-85.0458363,42.1004074]},"n1820938913":{"id":"n1820938913","loc":[-85.0592138,42.1048305]},"n1820938914":{"id":"n1820938914","loc":[-85.2807493,41.9916653]},"n1820938915":{"id":"n1820938915","loc":[-85.1103274,42.0864193]},"n1820938916":{"id":"n1820938916","loc":[-85.6267156,41.9404404]},"n1820938918":{"id":"n1820938918","loc":[-85.0331374,42.0982911]},"n1820938919":{"id":"n1820938919","loc":[-85.5637331,41.965409]},"n1820938920":{"id":"n1820938920","loc":[-85.5457515,41.9714237]},"n1820938922":{"id":"n1820938922","loc":[-85.082073,42.1030104]},"n1820938923":{"id":"n1820938923","loc":[-85.0780765,42.103102]},"n1820938924":{"id":"n1820938924","loc":[-85.4208035,42.0089508]},"n1820938925":{"id":"n1820938925","loc":[-85.3469934,41.9914795]},"n1820938926":{"id":"n1820938926","loc":[-85.0322,42.095619]},"n1820938927":{"id":"n1820938927","loc":[-85.4784431,41.9949401]},"n1820938928":{"id":"n1820938928","loc":[-85.1303095,42.0667523]},"n1820938929":{"id":"n1820938929","loc":[-85.2463784,42.0084781]},"n1820938930":{"id":"n1820938930","loc":[-85.6299986,41.9427707]},"n1820938931":{"id":"n1820938931","loc":[-85.6325907,41.9238499]},"n1820938932":{"id":"n1820938932","loc":[-85.4808464,41.9914476]},"n1820938934":{"id":"n1820938934","loc":[-85.2411599,42.0105292]},"n1820938935":{"id":"n1820938935","loc":[-85.0163213,42.0892379]},"n1820938936":{"id":"n1820938936","loc":[-85.3290934,41.9682322]},"n1820938937":{"id":"n1820938937","loc":[-85.4925623,41.9853231]},"n1820938938":{"id":"n1820938938","loc":[-85.0338294,42.09892]},"n1820938940":{"id":"n1820938940","loc":[-85.4174561,42.008903]},"n1820938941":{"id":"n1820938941","loc":[-85.1165595,42.0838845]},"n1820938942":{"id":"n1820938942","loc":[-85.2954585,41.9717192]},"n1820938943":{"id":"n1820938943","loc":[-85.6330199,41.9257338]},"n1820938944":{"id":"n1820938944","loc":[-85.2294654,42.0324478]},"n1820938945":{"id":"n1820938945","loc":[-85.5601282,41.9728914]},"n1820938946":{"id":"n1820938946","loc":[-85.1176324,42.08568]},"n1820938947":{"id":"n1820938947","loc":[-85.0210245,42.0906005]},"n1820938948":{"id":"n1820938948","loc":[-85.0251887,42.09253]},"n1820938949":{"id":"n1820938949","loc":[-85.0895832,42.0939551]},"n1820938950":{"id":"n1820938950","loc":[-84.9915109,42.085842]},"n1820938951":{"id":"n1820938951","loc":[-85.2187366,42.0393486]},"n1820938952":{"id":"n1820938952","loc":[-85.006605,42.087579]},"n1820938953":{"id":"n1820938953","loc":[-85.046641,42.1012393]},"n1820938954":{"id":"n1820938954","loc":[-85.052102,42.103695]},"n1820938955":{"id":"n1820938955","loc":[-85.283925,41.9912825]},"n1820938956":{"id":"n1820938956","loc":[-85.2326626,42.0316349]},"n1820938957":{"id":"n1820938957","loc":[-85.1174298,42.0859694]},"n1820938958":{"id":"n1820938958","loc":[-85.3802056,41.9994794]},"n1820938959":{"id":"n1820938959","loc":[-85.4586334,41.9999737]},"n1820938960":{"id":"n1820938960","loc":[-85.4302234,42.0069418]},"n1820938961":{"id":"n1820938961","loc":[-85.092201,42.0930674]},"n1820938962":{"id":"n1820938962","loc":[-85.3684511,41.9979382]},"n1820938963":{"id":"n1820938963","loc":[-85.4618735,42.0011856]},"n1820938964":{"id":"n1820938964","loc":[-85.4828205,41.9877793]},"n1820938965":{"id":"n1820938965","loc":[-85.0837789,42.1025726]},"n1820938966":{"id":"n1820938966","loc":[-85.0176195,42.090253]},"n1820938967":{"id":"n1820938967","loc":[-85.3801627,42.001074]},"n1820938968":{"id":"n1820938968","loc":[-85.4767007,41.994488]},"n1820938969":{"id":"n1820938969","loc":[-85.274268,41.9957495]},"n1820938970":{"id":"n1820938970","loc":[-85.2977438,41.9719506]},"n1820938971":{"id":"n1820938971","loc":[-85.2425546,42.0208682]},"n1820938972":{"id":"n1820938972","loc":[-85.2557082,42.002382]},"n1820938973":{"id":"n1820938973","loc":[-85.3187937,41.9691986]},"n1820938975":{"id":"n1820938975","loc":[-85.2448077,42.0153045]},"n1820938977":{"id":"n1820938977","loc":[-85.0343015,42.0997718]},"n1820938978":{"id":"n1820938978","loc":[-85.2449364,42.01874]},"n1820938979":{"id":"n1820938979","loc":[-85.2598391,41.9969602]},"n1820938980":{"id":"n1820938980","loc":[-85.4294724,42.0067665]},"n1820938981":{"id":"n1820938981","loc":[-85.428082,42.0055124]},"n1820938983":{"id":"n1820938983","loc":[-85.5436315,41.9717484]},"n1820938985":{"id":"n1820938985","loc":[-85.5978336,41.9407437]},"n1820938986":{"id":"n1820938986","loc":[-85.491661,41.9860249]},"n1820938987":{"id":"n1820938987","loc":[-85.4942789,41.9801392]},"n1820938988":{"id":"n1820938988","loc":[-85.0416306,42.1010841]},"n1820938989":{"id":"n1820938989","loc":[-85.2653644,41.9984433]},"n1820938990":{"id":"n1820938990","loc":[-85.1028266,42.0881124]},"n1820938991":{"id":"n1820938991","loc":[-85.0163146,42.0887932]},"n1820938992":{"id":"n1820938992","loc":[-85.5282209,41.9678112]},"n1820938993":{"id":"n1820938993","loc":[-85.5442752,41.9715888]},"n1820938994":{"id":"n1820938994","loc":[-85.5634327,41.9658558]},"n1820938995":{"id":"n1820938995","loc":[-85.0384227,42.1037627]},"n1820938996":{"id":"n1820938996","loc":[-85.1144258,42.0854439]},"n1820938997":{"id":"n1820938997","loc":[-85.1870651,42.0506305]},"n1820938998":{"id":"n1820938998","loc":[-85.1256159,42.0747376]},"n1820938999":{"id":"n1820938999","loc":[-85.3272695,41.9715836]},"n1820939000":{"id":"n1820939000","loc":[-85.0543067,42.103098]},"n1820939001":{"id":"n1820939001","loc":[-85.4678173,41.9973585]},"n1820939003":{"id":"n1820939003","loc":[-85.0266626,42.0933154]},"n1820939004":{"id":"n1820939004","loc":[-85.0353046,42.1019728]},"n1820939005":{"id":"n1820939005","loc":[-85.1237961,42.0762798]},"n1820939006":{"id":"n1820939006","loc":[-85.2812214,41.9826702]},"n1820939007":{"id":"n1820939007","loc":[-85.2927763,41.9747343]},"n1820939008":{"id":"n1820939008","loc":[-85.3270979,41.9720862]},"n1820939009":{"id":"n1820939009","loc":[-85.488657,41.9856581]},"n1820939010":{"id":"n1820939010","loc":[-85.3087301,41.9701399]},"n1820939011":{"id":"n1820939011","loc":[-85.0276939,42.093768]},"n1820939012":{"id":"n1820939012","loc":[-85.2956516,41.9748779]},"n1820939013":{"id":"n1820939013","loc":[-85.1298579,42.0726443]},"n1820939014":{"id":"n1820939014","loc":[-85.105144,42.0870893]},"n1820939015":{"id":"n1820939015","loc":[-85.0677486,42.1053917]},"n1820939016":{"id":"n1820939016","loc":[-85.0333681,42.0993459]},"n1820939017":{"id":"n1820939017","loc":[-85.6384272,41.910805]},"n1820939018":{"id":"n1820939018","loc":[-85.399496,42.006894]},"n1820939019":{"id":"n1820939019","loc":[-85.2648427,41.9998318]},"n1820939020":{"id":"n1820939020","loc":[-85.1237424,42.0766779]},"n1820939021":{"id":"n1820939021","loc":[-85.2515025,42.0109442]},"n1820939022":{"id":"n1820939022","loc":[-85.5566306,41.9718385]},"n1820939023":{"id":"n1820939023","loc":[-85.090644,42.0938369]},"n1820939024":{"id":"n1820939024","loc":[-85.1245525,42.074914]},"n1820939025":{"id":"n1820939025","loc":[-85.1099934,42.0863926]},"n1820939026":{"id":"n1820939026","loc":[-85.1251653,42.0744589]},"n1820939027":{"id":"n1820939027","loc":[-85.401792,42.0068143]},"n1820939028":{"id":"n1820939028","loc":[-85.0094763,42.0899584]},"n1820939029":{"id":"n1820939029","loc":[-85.1330779,42.0705605]},"n1820939030":{"id":"n1820939030","loc":[-85.4935064,41.984398]},"n1820939031":{"id":"n1820939031","loc":[-85.5713334,41.9613939]},"n1820939032":{"id":"n1820939032","loc":[-85.0873945,42.0964669]},"n1820939033":{"id":"n1820939033","loc":[-85.0886497,42.0986481]},"n1820939034":{"id":"n1820939034","loc":[-85.3276343,41.9758897]},"n1820939035":{"id":"n1820939035","loc":[-85.1304386,42.0727387]},"n1820939036":{"id":"n1820939036","loc":[-85.2551932,42.0052999]},"n1820939037":{"id":"n1820939037","loc":[-85.2206936,42.0384458]},"n1820939038":{"id":"n1820939038","loc":[-85.2313645,42.0286389]},"n1820939039":{"id":"n1820939039","loc":[-85.0754586,42.1059835]},"n1820939040":{"id":"n1820939040","loc":[-85.0663324,42.1050812]},"n1820939041":{"id":"n1820939041","loc":[-85.2406234,42.0106887]},"n1820939042":{"id":"n1820939042","loc":[-85.0685962,42.1058175]},"n1820939043":{"id":"n1820939043","loc":[-85.0689462,42.1059437]},"n1820939044":{"id":"n1820939044","loc":[-85.0586144,42.1046144]},"n1820939045":{"id":"n1820939045","loc":[-85.3650565,41.9965452]},"n1820939047":{"id":"n1820939047","loc":[-85.5752558,41.9536014]},"n1820939048":{"id":"n1820939048","loc":[-85.5110159,41.9710624]},"n1820939050":{"id":"n1820939050","loc":[-85.2832641,41.9926477]},"n1820939051":{"id":"n1820939051","loc":[-85.0078402,42.0898947]},"n1820939052":{"id":"n1820939052","loc":[-85.3882737,42.0017916]},"n1820939053":{"id":"n1820939053","loc":[-85.1718945,42.0564937]},"n1820939054":{"id":"n1820939054","loc":[-85.0947048,42.0929293]},"n1820939055":{"id":"n1820939055","loc":[-85.4456944,42.0051082]},"n1820939056":{"id":"n1820939056","loc":[-85.3139872,41.9706903]},"n1820939057":{"id":"n1820939057","loc":[-85.3893895,42.0034021]},"n1820939058":{"id":"n1820939058","loc":[-85.2425332,42.0106089]},"n1820939059":{"id":"n1820939059","loc":[-85.6085624,41.9420844]},"n1820939060":{"id":"n1820939060","loc":[-85.210411,42.0397789]},"n1820939061":{"id":"n1820939061","loc":[-85.2762542,41.9960473]},"n1820939062":{"id":"n1820939062","loc":[-85.4686584,41.9969973]},"n1820939063":{"id":"n1820939063","loc":[-85.3860421,42.0018394]},"n1820939064":{"id":"n1820939064","loc":[-85.5636944,41.9644414]},"n1820939065":{"id":"n1820939065","loc":[-85.3267331,41.9766554]},"n1820939066":{"id":"n1820939066","loc":[-85.0868996,42.0943822]},"n1820939067":{"id":"n1820939067","loc":[-85.104861,42.0880038]},"n1820939068":{"id":"n1820939068","loc":[-85.5537123,41.9695093]},"n1820939069":{"id":"n1820939069","loc":[-85.6325092,41.9396743]},"n1820939070":{"id":"n1820939070","loc":[-85.3869648,42.0024454]},"n1820939071":{"id":"n1820939071","loc":[-85.2775349,41.9957335]},"n1820939072":{"id":"n1820939072","loc":[-85.2055616,42.0421533]},"n1820939073":{"id":"n1820939073","loc":[-85.4731431,41.9946531]},"n1820939074":{"id":"n1820939074","loc":[-85.0399609,42.1030833]},"n1820939075":{"id":"n1820939075","loc":[-85.3055758,41.9725169]},"n1820939076":{"id":"n1820939076","loc":[-85.4834599,41.994488]},"n1820939077":{"id":"n1820939077","loc":[-85.3819866,42.0023018]},"n1820939078":{"id":"n1820939078","loc":[-85.1218756,42.0789992]},"n1820939079":{"id":"n1820939079","loc":[-85.2793159,41.9944458]},"n1820939080":{"id":"n1820939080","loc":[-85.2495498,42.0101466]},"n1820939081":{"id":"n1820939081","loc":[-85.0035969,42.0872434]},"n1820939082":{"id":"n1820939082","loc":[-85.1054243,42.0865626]},"n1820939083":{"id":"n1820939083","loc":[-85.0917665,42.0934774]},"n1820939084":{"id":"n1820939084","loc":[-85.3442211,41.988938]},"n1820939086":{"id":"n1820939086","loc":[-85.273989,41.9953588]},"n1820939087":{"id":"n1820939087","loc":[-85.1142541,42.0852488]},"n1820939089":{"id":"n1820939089","loc":[-85.1526684,42.0615758]},"n1820939090":{"id":"n1820939090","loc":[-85.2538843,42.0110159]},"n1820939091":{"id":"n1820939091","loc":[-85.28341,41.9909635]},"n1820939092":{"id":"n1820939092","loc":[-85.3963178,42.0050217]},"n1820939093":{"id":"n1820939093","loc":[-85.0851682,42.1012472]},"n1820939095":{"id":"n1820939095","loc":[-85.2811784,41.986243]},"n1820939096":{"id":"n1820939096","loc":[-85.4274125,42.0052995]},"n1820939097":{"id":"n1820939097","loc":[-85.0871262,42.0951652]},"n1820939099":{"id":"n1820939099","loc":[-85.1314253,42.0671665]},"n1820939100":{"id":"n1820939100","loc":[-85.2778997,41.991001]},"n1820939101":{"id":"n1820939101","loc":[-85.112107,42.0862812]},"n1820939102":{"id":"n1820939102","loc":[-85.299911,41.9729955]},"n1820939103":{"id":"n1820939103","loc":[-85.639822,41.9094796]},"n1820939104":{"id":"n1820939104","loc":[-85.122294,42.0785334]},"n1820939105":{"id":"n1820939105","loc":[-85.2476294,42.015719]},"n1820939106":{"id":"n1820939106","loc":[-85.4946007,41.9814631]},"n1820939107":{"id":"n1820939107","loc":[-85.0879524,42.0986919]},"n1820939108":{"id":"n1820939108","loc":[-85.0342814,42.098274]},"n1820939109":{"id":"n1820939109","loc":[-85.2450695,42.0095463]},"n1820939110":{"id":"n1820939110","loc":[-85.3847546,42.0024135]},"n1820939111":{"id":"n1820939111","loc":[-85.2961344,41.9742558]},"n1820939112":{"id":"n1820939112","loc":[-85.27899,41.994317]},"n1820939114":{"id":"n1820939114","loc":[-85.1017644,42.0886618]},"n1820939115":{"id":"n1820939115","loc":[-85.076215,42.1056333]},"n1820939116":{"id":"n1820939116","loc":[-85.1198009,42.0805349]},"n1820939117":{"id":"n1820939117","loc":[-85.11988,42.0798513]},"n1820939118":{"id":"n1820939118","loc":[-85.147819,42.0625476]},"n1820939119":{"id":"n1820939119","loc":[-85.0585969,42.1029042]},"n1820939120":{"id":"n1820939120","loc":[-85.1248596,42.0745744]},"n1820939121":{"id":"n1820939121","loc":[-85.3023786,41.9725249]},"n1820939123":{"id":"n1820939123","loc":[-85.0119332,42.0900699]},"n1820939124":{"id":"n1820939124","loc":[-85.2466852,42.0170343]},"n1820939125":{"id":"n1820939125","loc":[-85.0033019,42.0872792]},"n1820939126":{"id":"n1820939126","loc":[-85.0042084,42.0875778]},"n1820939128":{"id":"n1820939128","loc":[-85.0052961,42.0885424]},"n1820939130":{"id":"n1820939130","loc":[-85.0647942,42.10508]},"n1820939131":{"id":"n1820939131","loc":[-85.2824123,41.9825107]},"n1820939132":{"id":"n1820939132","loc":[-85.3210039,41.9723255]},"n1820939133":{"id":"n1820939133","loc":[-85.0491033,42.1014184]},"n1820939134":{"id":"n1820939134","loc":[-85.1127776,42.0855168]},"n1820939135":{"id":"n1820939135","loc":[-85.1243768,42.0759322]},"n1820939137":{"id":"n1820939137","loc":[-85.125974,42.0747547]},"n1820939138":{"id":"n1820939138","loc":[-85.1071248,42.0859973]},"n1820939139":{"id":"n1820939139","loc":[-85.5326175,41.9674833]},"n1820939140":{"id":"n1820939140","loc":[-85.1338715,42.0660833]},"n1820939142":{"id":"n1820939142","loc":[-85.649671,41.9135675]},"n1820939144":{"id":"n1820939144","loc":[-85.0236545,42.0920444]},"n1820939145":{"id":"n1820939145","loc":[-85.1084391,42.0859376]},"n1820939146":{"id":"n1820939146","loc":[-85.1539988,42.0618626]},"n1820939147":{"id":"n1820939147","loc":[-85.2354521,42.026511]},"n1820939148":{"id":"n1820939148","loc":[-85.2362246,42.0260408]},"n1820939149":{"id":"n1820939149","loc":[-85.2401342,42.0115233]},"n1820939150":{"id":"n1820939150","loc":[-85.295319,41.9747423]},"n1820939151":{"id":"n1820939151","loc":[-85.1164696,42.0835409]},"n1820939152":{"id":"n1820939152","loc":[-85.3232891,41.9712885]},"n1820939153":{"id":"n1820939153","loc":[-85.2574463,42.0068944]},"n1820939155":{"id":"n1820939155","loc":[-85.5704064,41.9598246]},"n1820939156":{"id":"n1820939156","loc":[-85.0349077,42.0998116]},"n1820939157":{"id":"n1820939157","loc":[-85.0949529,42.0925619]},"n1820939159":{"id":"n1820939159","loc":[-85.0179829,42.0902343]},"n1820939160":{"id":"n1820939160","loc":[-85.0405832,42.1016942]},"n1820939161":{"id":"n1820939161","loc":[-85.2534015,42.0111833]},"n1820939162":{"id":"n1820939162","loc":[-85.0839881,42.102708]},"n1820939163":{"id":"n1820939163","loc":[-85.0341996,42.1008385]},"n1820939164":{"id":"n1820939164","loc":[-85.1037761,42.0879731]},"n1820939173":{"id":"n1820939173","loc":[-85.0460616,42.1005786]},"n1820939177":{"id":"n1820939177","loc":[-85.0061651,42.0878059]},"n1820939181":{"id":"n1820939181","loc":[-85.1456775,42.0654684]},"n1820939183":{"id":"n1820939183","loc":[-85.1325508,42.0718439]},"n1820939185":{"id":"n1820939185","loc":[-85.2485842,42.008329]},"n1820939187":{"id":"n1820939187","loc":[-85.2744128,41.9949322]},"n1820939189":{"id":"n1820939189","loc":[-85.2579025,41.9999542]},"n1820939191":{"id":"n1820939191","loc":[-85.3358998,41.9828987]},"n1820939193":{"id":"n1820939193","loc":[-85.3192658,41.9716714]},"n1820939194":{"id":"n1820939194","loc":[-85.6400795,41.9130725]},"n1820939195":{"id":"n1820939195","loc":[-85.3278489,41.9780591]},"n1820939196":{"id":"n1820939196","loc":[-85.2800197,41.983061]},"n1820939197":{"id":"n1820939197","loc":[-85.3278167,41.9692943]},"n1820939198":{"id":"n1820939198","loc":[-85.3366894,41.9838653]},"n1820939199":{"id":"n1820939199","loc":[-85.0328383,42.0969923]},"n1820939201":{"id":"n1820939201","loc":[-85.3259284,41.9720383]},"n1820939217":{"id":"n1820939217","loc":[-85.1840181,42.0503277]},"n1820939220":{"id":"n1820939220","loc":[-85.422563,42.0089986]},"n1820939222":{"id":"n1820939222","loc":[-85.555386,41.9707856]},"n1820939224":{"id":"n1820939224","loc":[-85.3830809,42.002254]},"n1820939226":{"id":"n1820939226","loc":[-84.9917938,42.0857517]},"n1820939227":{"id":"n1820939227","loc":[-85.2936775,41.9740484]},"n1820939228":{"id":"n1820939228","loc":[-85.2632133,41.9975024]},"n1820939229":{"id":"n1820939229","loc":[-85.2809424,41.9853259]},"n1820939230":{"id":"n1820939230","loc":[-85.242104,42.0131204]},"n1820939232":{"id":"n1820939232","loc":[-85.2610246,41.9963901]},"n1820939233":{"id":"n1820939233","loc":[-85.2335531,42.0268378]},"n1820939234":{"id":"n1820939234","loc":[-85.3188839,41.9713575]},"n1820939235":{"id":"n1820939235","loc":[-85.2413637,42.0225658]},"n1820939237":{"id":"n1820939237","loc":[-85.0010796,42.0887215]},"n1820939239":{"id":"n1820939239","loc":[-85.2241697,42.0362624]},"n1820939243":{"id":"n1820939243","loc":[-85.0368456,42.1040134]},"n1820939244":{"id":"n1820939244","loc":[-85.1327986,42.069524]},"n1820939260":{"id":"n1820939260","loc":[-85.5408163,41.9711206]},"n1820939261":{"id":"n1820939261","loc":[-85.2959199,41.9746546]},"n1820939262":{"id":"n1820939262","loc":[-85.3298659,41.9683598]},"n1820939263":{"id":"n1820939263","loc":[-85.2240581,42.0358425]},"n1820939264":{"id":"n1820939264","loc":[-85.2438206,42.0101944]},"n1820939265":{"id":"n1820939265","loc":[-85.3984489,42.0059589]},"n1820939266":{"id":"n1820939266","loc":[-85.2330811,42.0294279]},"n1820939268":{"id":"n1820939268","loc":[-85.1126877,42.0857704]},"n1820939271":{"id":"n1820939271","loc":[-85.254925,42.0106253]},"n1820939273":{"id":"n1820939273","loc":[-85.4328046,42.0064662]},"n1820939277":{"id":"n1820939277","loc":[-85.289622,41.9789616]},"n1820939279":{"id":"n1820939279","loc":[-85.4574532,42.0004043]},"n1820939281":{"id":"n1820939281","loc":[-85.4803486,41.9867211]},"n1820939283":{"id":"n1820939283","loc":[-85.157475,42.0631848]},"n1820939285":{"id":"n1820939285","loc":[-85.2571458,42.0059935]},"n1820939287":{"id":"n1820939287","loc":[-85.2818544,41.9825984]},"n1820939289":{"id":"n1820939289","loc":[-85.2298302,42.0328781]},"n1820939291":{"id":"n1820939291","loc":[-85.4819523,41.984821]},"n1820939301":{"id":"n1820939301","loc":[-85.3139765,41.9701159]},"n1820939304":{"id":"n1820939304","loc":[-85.0424447,42.101742]},"n1820939306":{"id":"n1820939306","loc":[-85.6360283,41.9338482]},"n1820939310":{"id":"n1820939310","loc":[-85.3463025,41.9913622]},"n1820939312":{"id":"n1820939312","loc":[-85.4664869,41.9988097]},"n1820939314":{"id":"n1820939314","loc":[-85.149364,42.0622449]},"n1820939316":{"id":"n1820939316","loc":[-85.2460415,42.0153125]},"n1820939318":{"id":"n1820939318","loc":[-85.4806103,41.9924523]},"n1820939320":{"id":"n1820939320","loc":[-85.2449042,42.0190987]},"n1820939322":{"id":"n1820939322","loc":[-85.5280165,41.9689263]},"n1820939324":{"id":"n1820939324","loc":[-85.0051204,42.0882625]},"n1820939326":{"id":"n1820939326","loc":[-85.1240925,42.0771546]},"n1820939329":{"id":"n1820939329","loc":[-85.2261653,42.0342225]},"n1820939331":{"id":"n1820939331","loc":[-85.5259933,41.972211]},"n1820939333":{"id":"n1820939333","loc":[-85.0074754,42.0883183]},"n1820939335":{"id":"n1820939335","loc":[-85.0764014,42.1055549]},"n1820939336":{"id":"n1820939336","loc":[-85.2908773,41.9769597]},"n1820939337":{"id":"n1820939337","loc":[-85.4095382,42.0083449]},"n1820939346":{"id":"n1820939346","loc":[-85.2514166,42.0111753]},"n1820939348":{"id":"n1820939348","loc":[-85.0030377,42.0873799]},"n1820939350":{"id":"n1820939350","loc":[-85.3659362,41.9964974]},"n1820939352":{"id":"n1820939352","loc":[-85.226058,42.0348281]},"n1820939355":{"id":"n1820939355","loc":[-85.1902408,42.0507101]},"n1820939357":{"id":"n1820939357","loc":[-85.2781854,41.9946001]},"n1820939359":{"id":"n1820939359","loc":[-85.2139988,42.0405175]},"n1820939361":{"id":"n1820939361","loc":[-85.0086609,42.0908262]},"n1820939363":{"id":"n1820939363","loc":[-85.0627128,42.1043398]},"n1820939365":{"id":"n1820939365","loc":[-85.1311346,42.072501]},"n1820939369":{"id":"n1820939369","loc":[-85.248198,42.0082652]},"n1820939370":{"id":"n1820939370","loc":[-84.99792,42.087794]},"n1820939371":{"id":"n1820939371","loc":[-85.2786775,41.9942783]},"n1820939372":{"id":"n1820939372","loc":[-85.0342103,42.1013957]},"n1820939373":{"id":"n1820939373","loc":[-85.2022357,42.0444799]},"n1820939374":{"id":"n1820939374","loc":[-85.2279205,42.0337388]},"n1820939375":{"id":"n1820939375","loc":[-85.1337699,42.0712614]},"n1820939376":{"id":"n1820939376","loc":[-85.317517,41.9707062]},"n1820939377":{"id":"n1820939377","loc":[-85.1326326,42.070218]},"n1820939394":{"id":"n1820939394","loc":[-85.0197746,42.0899118]},"n1820939397":{"id":"n1820939397","loc":[-85.2590076,41.9984632]},"n1820939399":{"id":"n1820939399","loc":[-85.2469964,42.0083449]},"n1820939400":{"id":"n1820939400","loc":[-85.2470929,42.0146668]},"n1820939401":{"id":"n1820939401","loc":[-84.9984095,42.0878087]},"n1820939402":{"id":"n1820939402","loc":[-85.2372653,42.0243273]},"n1820939403":{"id":"n1820939403","loc":[-85.2454986,42.0091955]},"n1820939404":{"id":"n1820939404","loc":[-85.0539205,42.1035995]},"n1820939405":{"id":"n1820939405","loc":[-85.550601,41.9706101]},"n1820939406":{"id":"n1820939406","loc":[-85.0351343,42.0999656]},"n1820939407":{"id":"n1820939407","loc":[-85.0082908,42.0905755]},"n1820939408":{"id":"n1820939408","loc":[-85.0132904,42.0902251]},"n1820939410":{"id":"n1820939410","loc":[-85.0892546,42.094012]},"n1820939412":{"id":"n1820939412","loc":[-85.0350793,42.1030315]},"n1820939416":{"id":"n1820939416","loc":[-85.0012406,42.0886777]},"n1820939418":{"id":"n1820939418","loc":[-85.0577453,42.1029229]},"n1820939420":{"id":"n1820939420","loc":[-85.1230786,42.0776722]},"n1820939422":{"id":"n1820939422","loc":[-85.571136,41.9649304]},"n1820939436":{"id":"n1820939436","loc":[-85.1137968,42.0848997]},"n1820939437":{"id":"n1820939437","loc":[-85.3559584,41.9925105]},"n1820939438":{"id":"n1820939438","loc":[-85.0080172,42.0903565]},"n1820939439":{"id":"n1820939439","loc":[-85.0048897,42.0880913]},"n1820939441":{"id":"n1820939441","loc":[-85.0406959,42.1018574]},"n1820939443":{"id":"n1820939443","loc":[-85.3897328,42.0029078]},"n1820939445":{"id":"n1820939445","loc":[-85.122349,42.0782814]},"n1820939448":{"id":"n1820939448","loc":[-85.4872193,41.985036]},"n1820939450":{"id":"n1820939450","loc":[-85.0120459,42.0904919]},"n1820939452":{"id":"n1820939452","loc":[-85.6320543,41.921982]},"n1820939456":{"id":"n1820939456","loc":[-85.0844749,42.1036843]},"n1820939458":{"id":"n1820939458","loc":[-85.0968037,42.091296]},"n1820939463":{"id":"n1820939463","loc":[-85.5339747,41.9681841]},"n1820939465":{"id":"n1820939465","loc":[-85.4125423,42.0072129]},"n1820939467":{"id":"n1820939467","loc":[-85.6335563,41.9303626]},"n1820939469":{"id":"n1820939469","loc":[-85.2821014,41.9932126]},"n1820939471":{"id":"n1820939471","loc":[-85.374691,41.9969917]},"n1820939485":{"id":"n1820939485","loc":[-85.4471321,42.0049806]},"n1820939487":{"id":"n1820939487","loc":[-85.3752532,41.9972206]},"n1820939489":{"id":"n1820939489","loc":[-85.4517283,42.005927]},"n1820939492":{"id":"n1820939492","loc":[-85.4662552,42.0005693]},"n1820939494":{"id":"n1820939494","loc":[-85.0120083,42.0902928]},"n1820939496":{"id":"n1820939496","loc":[-85.044463,42.1004631]},"n1820939498":{"id":"n1820939498","loc":[-85.418293,42.0089667]},"n1820939500":{"id":"n1820939500","loc":[-85.0554762,42.1027358]},"n1820939504":{"id":"n1820939504","loc":[-85.1246289,42.0746858]},"n1820939507":{"id":"n1820939507","loc":[-85.0408139,42.1021838]},"n1820939508":{"id":"n1820939508","loc":[-85.1236204,42.0775169]},"n1820939509":{"id":"n1820939509","loc":[-85.0350109,42.1037428]},"n1820939510":{"id":"n1820939510","loc":[-85.0551583,42.1029878]},"n1820939511":{"id":"n1820939511","loc":[-85.0956771,42.0916662]},"n1820939512":{"id":"n1820939512","loc":[-85.2323408,42.0273638]},"n1820939513":{"id":"n1820939513","loc":[-85.1232771,42.0762388]},"n1820939531":{"id":"n1820939531","loc":[-85.264608,41.9997828]},"n1820939533":{"id":"n1820939533","loc":[-85.4198808,42.0087914]},"n1820939535":{"id":"n1820939535","loc":[-85.3080864,41.9715677]},"n1820939536":{"id":"n1820939536","loc":[-85.1189426,42.0812596]},"n1820939537":{"id":"n1820939537","loc":[-85.2642741,41.9996764]},"n1820939538":{"id":"n1820939538","loc":[-85.2572531,42.0079627]},"n1820939539":{"id":"n1820939539","loc":[-85.2907807,41.9790174]},"n1820939540":{"id":"n1820939540","loc":[-85.3171415,41.9707301]},"n1820939541":{"id":"n1820939541","loc":[-85.08777,42.0953841]},"n1820939542":{"id":"n1820939542","loc":[-85.1239262,42.0773218]},"n1820939543":{"id":"n1820939543","loc":[-84.9973956,42.0877968]},"n1820939544":{"id":"n1820939544","loc":[-85.011606,42.0896161]},"n1820939545":{"id":"n1820939545","loc":[-85.4077358,42.0082971]},"n1820939546":{"id":"n1820939546","loc":[-85.3614945,41.9933717]},"n1820939547":{"id":"n1820939547","loc":[-85.3189118,41.9697649]},"n1820939550":{"id":"n1820939550","loc":[-85.1262691,42.0740221]},"n1820939551":{"id":"n1820939551","loc":[-85.3863639,41.9994635]},"n1820939552":{"id":"n1820939552","loc":[-85.2836034,41.9923953]},"n1820939554":{"id":"n1820939554","loc":[-85.3222377,41.9715916]},"n1820939555":{"id":"n1820939555","loc":[-85.0122658,42.0906312]},"n1820939556":{"id":"n1820939556","loc":[-85.0022652,42.0877581]},"n1820939557":{"id":"n1820939557","loc":[-85.1011314,42.0899954]},"n1820939559":{"id":"n1820939559","loc":[-85.0008181,42.0885293]},"n1820939561":{"id":"n1820939561","loc":[-85.3637046,41.9942488]},"n1820939562":{"id":"n1820939562","loc":[-85.4500117,42.0052892]},"n1820939563":{"id":"n1820939563","loc":[-85.0537636,42.1036365]},"n1820939565":{"id":"n1820939565","loc":[-85.2367503,42.0246939]},"n1820939566":{"id":"n1820939566","loc":[-85.0448479,42.1002653]},"n1820939567":{"id":"n1820939567","loc":[-85.6337065,41.9295006]},"n1820939568":{"id":"n1820939568","loc":[-85.0879792,42.095623]},"n1820939569":{"id":"n1820939569","loc":[-85.6347623,41.9352369]},"n1820939570":{"id":"n1820939570","loc":[-85.1497931,42.0620378]},"n1820939571":{"id":"n1820939571","loc":[-85.5676169,41.9656324]},"n1820939572":{"id":"n1820939572","loc":[-85.638041,41.9166971]},"n1820939573":{"id":"n1820939573","loc":[-85.4993429,41.9781293]},"n1820939574":{"id":"n1820939574","loc":[-85.5352831,41.9692127]},"n1820939575":{"id":"n1820939575","loc":[-84.9924429,42.0857118]},"n1820939577":{"id":"n1820939577","loc":[-85.0581101,42.1026721]},"n1820939578":{"id":"n1820939578","loc":[-85.641088,41.9094477]},"n1820939579":{"id":"n1820939579","loc":[-85.2548821,42.0052282]},"n1820939580":{"id":"n1820939580","loc":[-85.1124463,42.0859734]},"n1820939581":{"id":"n1820939581","loc":[-85.1083479,42.0857624]},"n1820939583":{"id":"n1820939583","loc":[-85.1387424,42.0648893]},"n1820939584":{"id":"n1820939584","loc":[-85.5152645,41.9700892]},"n1820939585":{"id":"n1820939585","loc":[-85.5463738,41.9713439]},"n1820939586":{"id":"n1820939586","loc":[-85.360207,41.9933717]},"n1820939587":{"id":"n1820939587","loc":[-85.2402372,42.0120917]},"n1820939588":{"id":"n1820939588","loc":[-85.3936381,42.0047255]},"n1820939589":{"id":"n1820939589","loc":[-85.3310246,41.973784]},"n1820939590":{"id":"n1820939590","loc":[-85.0329403,42.096642]},"n1820939591":{"id":"n1820939591","loc":[-85.0097271,42.0910981]},"n1820939593":{"id":"n1820939593","loc":[-85.0446562,42.1003437]},"n1820939595":{"id":"n1820939595","loc":[-85.0856671,42.1008452]},"n1820939596":{"id":"n1820939596","loc":[-85.4087228,42.0083449]},"n1820939597":{"id":"n1820939597","loc":[-85.0609519,42.1052564]},"n1820939598":{"id":"n1820939598","loc":[-85.3432126,41.9874548]},"n1820939599":{"id":"n1820939599","loc":[-85.4041738,42.0067027]},"n1820939600":{"id":"n1820939600","loc":[-85.0825437,42.1035768]},"n1820939601":{"id":"n1820939601","loc":[-85.048422,42.101498]},"n1820939602":{"id":"n1820939602","loc":[-85.0336256,42.0999031]},"n1820939603":{"id":"n1820939603","loc":[-85.046818,42.1014104]},"n1820939605":{"id":"n1820939605","loc":[-85.2856524,41.98078]},"n1820939607":{"id":"n1820939607","loc":[-85.1118173,42.0864245]},"n1820939609":{"id":"n1820939609","loc":[-85.0443397,42.1006263]},"n1820939610":{"id":"n1820939610","loc":[-85.0336698,42.0978361]},"n1820939611":{"id":"n1820939611","loc":[-85.4630322,42.0014248]},"n1820939612":{"id":"n1820939612","loc":[-85.0613127,42.1052353]},"n1820939613":{"id":"n1820939613","loc":[-85.0137571,42.0887801]},"n1820939614":{"id":"n1820939614","loc":[-85.272487,41.9982013]},"n1820939616":{"id":"n1820939616","loc":[-85.4665727,41.9983791]},"n1820939617":{"id":"n1820939617","loc":[-85.1288078,42.0725476]},"n1820939618":{"id":"n1820939618","loc":[-85.4653282,42.00109]},"n1820939619":{"id":"n1820939619","loc":[-85.2314717,42.0276746]},"n1820939620":{"id":"n1820939620","loc":[-85.255982,42.0003569]},"n1820939621":{"id":"n1820939621","loc":[-85.2886779,41.9787223]},"n1820939622":{"id":"n1820939622","loc":[-85.22438,42.0367509]},"n1820939623":{"id":"n1820939623","loc":[-85.0334713,42.0998382]},"n1820939624":{"id":"n1820939624","loc":[-85.2236504,42.037484]},"n1820939625":{"id":"n1820939625","loc":[-85.636908,41.9175162]},"n1820939627":{"id":"n1820939627","loc":[-85.2669187,41.9989707]},"n1820939628":{"id":"n1820939628","loc":[-85.3247268,41.9720702]},"n1820939629":{"id":"n1820939629","loc":[-85.3785104,41.9987299]},"n1820939630":{"id":"n1820939630","loc":[-85.5267658,41.9720515]},"n1820939631":{"id":"n1820939631","loc":[-85.2445116,42.0098811]},"n1820939632":{"id":"n1820939632","loc":[-85.1271448,42.0725077]},"n1820939633":{"id":"n1820939633","loc":[-85.0345751,42.099724]},"n1820939634":{"id":"n1820939634","loc":[-85.4217476,42.0089986]},"n1820939635":{"id":"n1820939635","loc":[-85.3121848,41.9689433]},"n1820939636":{"id":"n1820939636","loc":[-85.2826419,41.9929985]},"n1820939637":{"id":"n1820939637","loc":[-85.3160257,41.9706344]},"n1820939638":{"id":"n1820939638","loc":[-85.5684967,41.9657919]},"n1820939640":{"id":"n1820939640","loc":[-85.225131,42.0356194]},"n1820939642":{"id":"n1820939642","loc":[-85.1324124,42.0693328]},"n1820939644":{"id":"n1820939644","loc":[-84.9994073,42.0878843]},"n1820939645":{"id":"n1820939645","loc":[-85.1087596,42.0863329]},"n1820939646":{"id":"n1820939646","loc":[-85.2915532,41.9782996]},"n1820939647":{"id":"n1820939647","loc":[-84.9988708,42.0877808]},"n1820939648":{"id":"n1820939648","loc":[-85.2243628,42.0356728]},"n1820939649":{"id":"n1820939649","loc":[-85.0427397,42.1020524]},"n1820939650":{"id":"n1820939650","loc":[-85.6388392,41.9100752]},"n1820939651":{"id":"n1820939651","loc":[-85.0133709,42.0888557]},"n1820939652":{"id":"n1820939652","loc":[-85.318798,41.9701211]},"n1820939653":{"id":"n1820939653","loc":[-85.6335778,41.9190602]},"n1820939654":{"id":"n1820939654","loc":[-85.6338396,41.9370247]},"n1820939655":{"id":"n1820939655","loc":[-85.0939069,42.0931988]},"n1820939656":{"id":"n1820939656","loc":[-85.5702347,41.9651378]},"n1820939657":{"id":"n1820939657","loc":[-85.4235286,42.0088392]},"n1820939658":{"id":"n1820939658","loc":[-85.2740856,41.9972206]},"n1820939659":{"id":"n1820939659","loc":[-85.4824299,41.9934195]},"n1820939660":{"id":"n1820939660","loc":[-85.3857846,42.0014408]},"n1820939661":{"id":"n1820939661","loc":[-85.0451658,42.10028]},"n1820939662":{"id":"n1820939662","loc":[-85.3893036,42.001377]},"n1820939664":{"id":"n1820939664","loc":[-85.2455845,42.0088607]},"n1820939665":{"id":"n1820939665","loc":[-85.2741071,41.9951116]},"n1820939666":{"id":"n1820939666","loc":[-85.1298375,42.0677718]},"n1820939667":{"id":"n1820939667","loc":[-85.5491848,41.9707377]},"n1820939669":{"id":"n1820939669","loc":[-85.2780298,41.995238]},"n1820939670":{"id":"n1820939670","loc":[-85.1330068,42.0716926]},"n1820939671":{"id":"n1820939671","loc":[-85.0811342,42.1025129]},"n1820939672":{"id":"n1820939672","loc":[-85.2325124,42.0290135]},"n1820939673":{"id":"n1820939673","loc":[-85.2975077,41.9716953]},"n1820939674":{"id":"n1820939674","loc":[-85.0951729,42.0922394]},"n1820939676":{"id":"n1820939676","loc":[-85.0363252,42.1043119]},"n1820939677":{"id":"n1820939677","loc":[-85.2960057,41.97349]},"n1820939678":{"id":"n1820939678","loc":[-85.3701849,41.9982515]},"n1820939679":{"id":"n1820939679","loc":[-85.3381486,41.9848861]},"n1820939680":{"id":"n1820939680","loc":[-85.2058448,42.0417286]},"n1820939682":{"id":"n1820939682","loc":[-85.0819335,42.1034443]},"n1820939683":{"id":"n1820939683","loc":[-85.3872223,41.9993359]},"n1820939684":{"id":"n1820939684","loc":[-85.095366,42.091909]},"n1820939685":{"id":"n1820939685","loc":[-85.2327914,42.0291888]},"n1820939686":{"id":"n1820939686","loc":[-85.0433459,42.1018773]},"n1820939687":{"id":"n1820939687","loc":[-85.0585339,42.1027318]},"n1820939688":{"id":"n1820939688","loc":[-85.0062885,42.0876347]},"n1820939689":{"id":"n1820939689","loc":[-85.246299,42.017377]},"n1820939690":{"id":"n1820939690","loc":[-85.2932376,41.9742877]},"n1820939691":{"id":"n1820939691","loc":[-85.2962846,41.9736815]},"n1820939692":{"id":"n1820939692","loc":[-85.6052365,41.9409193]},"n1820939693":{"id":"n1820939693","loc":[-85.2570536,42.0003341]},"n1820939694":{"id":"n1820939694","loc":[-85.0488458,42.1014064]},"n1820939695":{"id":"n1820939695","loc":[-85.4050321,42.0069578]},"n1820939696":{"id":"n1820939696","loc":[-85.4847517,41.9845894]},"n1820939697":{"id":"n1820939697","loc":[-85.0844655,42.1013826]},"n1820939698":{"id":"n1820939698","loc":[-85.1437206,42.0650008]},"n1820939699":{"id":"n1820939699","loc":[-85.1168183,42.0864034]},"n1820939700":{"id":"n1820939700","loc":[-85.5479831,41.9711366]},"n1820939701":{"id":"n1820939701","loc":[-85.0349948,42.1034124]},"n1820939702":{"id":"n1820939702","loc":[-85.0835589,42.1038821]},"n1820939703":{"id":"n1820939703","loc":[-85.0203875,42.0902649]},"n1820939704":{"id":"n1820939704","loc":[-85.0371191,42.1038184]},"n1820939705":{"id":"n1820939705","loc":[-85.1273312,42.0735681]},"n1820939707":{"id":"n1820939707","loc":[-85.1272239,42.0730226]},"n1820939710":{"id":"n1820939710","loc":[-85.0349881,42.1019012]},"n1820939712":{"id":"n1820939712","loc":[-85.2440459,42.0178313]},"n1820939713":{"id":"n1820939713","loc":[-85.2444751,42.0182618]},"n1820939714":{"id":"n1820939714","loc":[-85.0539996,42.1032863]},"n1820939715":{"id":"n1820939715","loc":[-85.2215905,42.0373246]},"n1820939716":{"id":"n1820939716","loc":[-85.0649712,42.1051994]},"n1820939717":{"id":"n1820939717","loc":[-85.0927146,42.0927581]},"n1820939718":{"id":"n1820939718","loc":[-85.3884668,42.0042312]},"n1820939719":{"id":"n1820939719","loc":[-85.0840672,42.1013241]},"n1820939720":{"id":"n1820939720","loc":[-85.304739,41.9725408]},"n1820939721":{"id":"n1820939721","loc":[-85.2243585,42.0371334]},"n1820939722":{"id":"n1820939722","loc":[-85.0599823,42.1049686]},"n1820939723":{"id":"n1820939723","loc":[-85.0298825,42.0944288]},"n1820939724":{"id":"n1820939724","loc":[-85.0366095,42.1042443]},"n1820939725":{"id":"n1820939725","loc":[-85.0698783,42.1058135]},"n1820939726":{"id":"n1820939726","loc":[-85.1054551,42.0873361]},"n1820939727":{"id":"n1820939727","loc":[-84.9952324,42.0864285]},"n1820939728":{"id":"n1820939728","loc":[-85.3442211,41.9897993]},"n1820939729":{"id":"n1820939729","loc":[-85.4386134,42.0056822]},"n1820939730":{"id":"n1820939730","loc":[-85.2438528,42.0146589]},"n1820939731":{"id":"n1820939731","loc":[-85.0355581,42.1041846]},"n1820939732":{"id":"n1820939732","loc":[-85.557682,41.9724447]},"n1820939734":{"id":"n1820939734","loc":[-85.2299418,42.033314]},"n1820939735":{"id":"n1820939735","loc":[-85.6297412,41.9419088]},"n1820939736":{"id":"n1820939736","loc":[-85.2645101,41.9980259]},"n1820939738":{"id":"n1820939738","loc":[-85.082195,42.1035649]},"n1820939739":{"id":"n1820939739","loc":[-85.234272,42.0267102]},"n1820939740":{"id":"n1820939740","loc":[-85.0130758,42.0895006]},"n1820939741":{"id":"n1820939741","loc":[-85.4594702,42.0000375]},"n1820939742":{"id":"n1820939742","loc":[-84.9946745,42.0863687]},"n1820939743":{"id":"n1820939743","loc":[-85.6438775,41.9120186]},"n1820939744":{"id":"n1820939744","loc":[-85.6372685,41.9168089]},"n1820939745":{"id":"n1820939745","loc":[-85.2789468,41.9893208]},"n1820939747":{"id":"n1820939747","loc":[-85.3775019,41.998427]},"n1820939749":{"id":"n1820939749","loc":[-85.0993571,42.0909178]},"n1820939750":{"id":"n1820939750","loc":[-85.1308503,42.0669339]},"n1820939751":{"id":"n1820939751","loc":[-85.4802566,41.9856659]},"n1820939752":{"id":"n1820939752","loc":[-85.2543563,42.0108804]},"n1820939753":{"id":"n1820939753","loc":[-85.1041033,42.0878815]},"n1820939755":{"id":"n1820939755","loc":[-85.4000969,42.0071651]},"n1820939757":{"id":"n1820939757","loc":[-85.3858275,42.0022381]},"n1820939758":{"id":"n1820939758","loc":[-85.3653998,41.996609]},"n1820939759":{"id":"n1820939759","loc":[-85.2432949,42.0202305]},"n1820939760":{"id":"n1820939760","loc":[-85.3878874,42.0042472]},"n1820939761":{"id":"n1820939761","loc":[-85.2516741,42.0114145]},"n1820939762":{"id":"n1820939762","loc":[-85.2788825,41.9865142]},"n1820939763":{"id":"n1820939763","loc":[-85.0009147,42.0886686]},"n1820939764":{"id":"n1820939764","loc":[-85.3918142,42.003434]},"n1820939765":{"id":"n1820939765","loc":[-85.5532832,41.9696848]},"n1820939766":{"id":"n1820939766","loc":[-85.5545063,41.969254]},"n1820939768":{"id":"n1820939768","loc":[-85.1327989,42.0704769]},"n1820939770":{"id":"n1820939770","loc":[-85.0588558,42.1047696]},"n1820939772":{"id":"n1820939772","loc":[-85.555798,41.9713017]},"n1820939773":{"id":"n1820939773","loc":[-85.0565853,42.1023589]},"n1820939774":{"id":"n1820939774","loc":[-85.2582941,41.9992765]},"n1820939775":{"id":"n1820939775","loc":[-85.3007264,41.9727642]},"n1820939776":{"id":"n1820939776","loc":[-85.2477045,42.0082652]},"n1820939777":{"id":"n1820939777","loc":[-85.2415247,42.0104973]},"n1821006698":{"id":"n1821006698","loc":[-85.6345227,41.9382009]},"n1821006700":{"id":"n1821006700","loc":[-85.6344894,41.938975]},"n1821006704":{"id":"n1821006704","loc":[-85.6351181,41.9370157]},"n1821006706":{"id":"n1821006706","loc":[-85.6357554,41.9361657]},"n1821006708":{"id":"n1821006708","loc":[-85.6351235,41.9368481]},"n1821006710":{"id":"n1821006710","loc":[-85.6352844,41.9364211]},"n1821006712":{"id":"n1821006712","loc":[-85.6351503,41.937307]},"n1821006716":{"id":"n1821006716","loc":[-85.6350366,41.9379774]},"n1821006725":{"id":"n1821006725","loc":[-85.6352147,41.9375903]},"n1821137607":{"id":"n1821137607","loc":[-85.5297057,41.9669915]},"n1821137608":{"id":"n1821137608","loc":[-85.5288598,41.9673094]},"n1821139530":{"id":"n1821139530","loc":[-85.4832228,41.9881686]},"n1821139531":{"id":"n1821139531","loc":[-85.4812101,41.9851258]},"n1821139532":{"id":"n1821139532","loc":[-85.4799127,41.9860244]},"n1821139533":{"id":"n1821139533","loc":[-85.4800313,41.9865555]},"n1841425201":{"id":"n1841425201","loc":[-85.4334577,42.0063713]},"n1841425222":{"id":"n1841425222","loc":[-85.4382449,42.0055785]},"n1914861007":{"id":"n1914861007","loc":[-85.394959,42.0057472]},"n1914861057":{"id":"n1914861057","loc":[-85.3967185,42.0049695]},"n1914861112":{"id":"n1914861112","loc":[-85.394179,42.0056906]},"n1914861306":{"id":"n1914861306","loc":[-85.3900226,42.0028488]},"n2114807565":{"id":"n2114807565","loc":[-85.6385979,41.9577824]},"n2114807568":{"id":"n2114807568","loc":[-85.6325097,41.9775713]},"n2114807572":{"id":"n2114807572","loc":[-85.6328996,41.9980965]},"n2114807578":{"id":"n2114807578","loc":[-85.6344818,41.9696956]},"n2114807583":{"id":"n2114807583","loc":[-85.6326289,41.9757853]},"n2114807593":{"id":"n2114807593","loc":[-85.6360828,41.9650674]},"n2130304159":{"id":"n2130304159","loc":[-85.6352537,41.9450015],"tags":{"railway":"level_crossing"}},"n2139795852":{"id":"n2139795852","loc":[-85.6374708,41.9311633]},"n2139858882":{"id":"n2139858882","loc":[-85.635178,41.9356158]},"n2139858883":{"id":"n2139858883","loc":[-85.63533,41.9355886]},"n2139858884":{"id":"n2139858884","loc":[-85.6353819,41.93556]},"n2139858885":{"id":"n2139858885","loc":[-85.6353665,41.9355157]},"n2139858886":{"id":"n2139858886","loc":[-85.6353165,41.9354971]},"n2139858887":{"id":"n2139858887","loc":[-85.6352454,41.9355328]},"n2139858888":{"id":"n2139858888","loc":[-85.6350184,41.9357846]},"n2139858889":{"id":"n2139858889","loc":[-85.634978,41.9359448]},"n2139858890":{"id":"n2139858890","loc":[-85.6347723,41.9361523]},"n2139858891":{"id":"n2139858891","loc":[-85.6347165,41.9362667]},"n2139858892":{"id":"n2139858892","loc":[-85.6346992,41.9364312]},"n2139858893":{"id":"n2139858893","loc":[-85.634603,41.9366329]},"n2139858894":{"id":"n2139858894","loc":[-85.6345973,41.9367488]},"n2139858895":{"id":"n2139858895","loc":[-85.6345127,41.9369734]},"n2139858896":{"id":"n2139858896","loc":[-85.634478,41.9371923]},"n2139858897":{"id":"n2139858897","loc":[-85.6344838,41.9373768]},"n2139858898":{"id":"n2139858898","loc":[-85.6346242,41.9375299]},"n2139858899":{"id":"n2139858899","loc":[-85.6347723,41.9376357]},"n2139858900":{"id":"n2139858900","loc":[-85.6347607,41.9377788]},"n2139858901":{"id":"n2139858901","loc":[-85.6346204,41.9379533]},"n2139858902":{"id":"n2139858902","loc":[-85.6344184,41.9380105]},"n2139858903":{"id":"n2139858903","loc":[-85.6341627,41.9380406]},"n2139858904":{"id":"n2139858904","loc":[-85.634005,41.9381679]},"n2139858905":{"id":"n2139858905","loc":[-85.63393,41.9383353]},"n2139858906":{"id":"n2139858906","loc":[-85.6338588,41.9384597]},"n2139858907":{"id":"n2139858907","loc":[-85.6336627,41.9387759]},"n2139858908":{"id":"n2139858908","loc":[-85.6335127,41.9389361]},"n2139858933":{"id":"n2139858933","loc":[-85.6353118,41.9432646]},"n2139858934":{"id":"n2139858934","loc":[-85.6353952,41.9433002]},"n2139858935":{"id":"n2139858935","loc":[-85.6356496,41.9433255]},"n2139858936":{"id":"n2139858936","loc":[-85.6363128,41.9433373]},"n2139858937":{"id":"n2139858937","loc":[-85.6365467,41.9433779]},"n2139858938":{"id":"n2139858938","loc":[-85.6368692,41.9435265]},"n2139858939":{"id":"n2139858939","loc":[-85.6370986,41.9437039]},"n2139858940":{"id":"n2139858940","loc":[-85.6372371,41.9437732]},"n2139858941":{"id":"n2139858941","loc":[-85.6374756,41.9438171]},"n2139858942":{"id":"n2139858942","loc":[-85.6376164,41.9439286]},"n2139858943":{"id":"n2139858943","loc":[-85.6377504,41.944138]},"n2139858944":{"id":"n2139858944","loc":[-85.6384204,41.9443137]},"n2139858945":{"id":"n2139858945","loc":[-85.6385726,41.9444506]},"n2139858946":{"id":"n2139858946","loc":[-85.638702,41.9445739]},"n2139858947":{"id":"n2139858947","loc":[-85.6387179,41.9446516]},"n2139858948":{"id":"n2139858948","loc":[-85.6387088,41.9447985]},"n2139858949":{"id":"n2139858949","loc":[-85.6387656,41.9449877]},"n2139858950":{"id":"n2139858950","loc":[-85.638777,41.9451448]},"n2139858951":{"id":"n2139858951","loc":[-85.6387088,41.9452631]},"n2139858964":{"id":"n2139858964","loc":[-85.6383346,41.9442912]},"n2139858966":{"id":"n2139858966","loc":[-85.6384724,41.9443605]},"n2139858967":{"id":"n2139858967","loc":[-85.6354078,41.9434285]},"n2139858968":{"id":"n2139858968","loc":[-85.635271,41.943654]},"n2139858969":{"id":"n2139858969","loc":[-85.6352657,41.9437437]},"n2139858970":{"id":"n2139858970","loc":[-85.635271,41.9438195]},"n2139858971":{"id":"n2139858971","loc":[-85.6351563,41.9438906]},"n2139858972":{"id":"n2139858972","loc":[-85.6351384,41.9438882]},"n2139858973":{"id":"n2139858973","loc":[-85.6351514,41.9438034]},"n2139858974":{"id":"n2139858974","loc":[-85.6351237,41.9436641]},"n2139858975":{"id":"n2139858975","loc":[-85.6351498,41.9436108]},"n2139858976":{"id":"n2139858976","loc":[-85.6351058,41.9435345]},"n2139858977":{"id":"n2139858977","loc":[-85.6349641,41.9432051]},"n2139858986":{"id":"n2139858986","loc":[-85.6341205,41.9380746]},"n2139858990":{"id":"n2139858990","loc":[-85.6345671,41.9381816]},"n2139858995":{"id":"n2139858995","loc":[-85.6339783,41.9382273]},"n2139859003":{"id":"n2139859003","loc":[-85.6340477,41.9373489]},"n2139859004":{"id":"n2139859004","loc":[-85.6339784,41.9374752]},"n2139870406":{"id":"n2139870406","loc":[-85.6342265,41.9432605]},"n2139877106":{"id":"n2139877106","loc":[-85.6346323,41.9438746]},"n2139982399":{"id":"n2139982399","loc":[-85.6324055,41.9408537]},"n2139982400":{"id":"n2139982400","loc":[-85.632488,41.941063],"tags":{"leisure":"slipway"}},"n2139982401":{"id":"n2139982401","loc":[-85.6327261,41.9415366]},"n2139982402":{"id":"n2139982402","loc":[-85.6326391,41.9413598]},"n2139982403":{"id":"n2139982403","loc":[-85.6327041,41.9414391]},"n2139982405":{"id":"n2139982405","loc":[-85.6322891,41.9406009]},"n2139982406":{"id":"n2139982406","loc":[-85.6325412,41.9425257]},"n2139989333":{"id":"n2139989333","loc":[-85.6340584,41.9431731]},"n2140006331":{"id":"n2140006331","loc":[-85.6361751,41.9459744]},"n2140006334":{"id":"n2140006334","loc":[-85.636528,41.9459751]},"n2140006336":{"id":"n2140006336","loc":[-85.6370918,41.9458926]},"n2140006338":{"id":"n2140006338","loc":[-85.6378806,41.9456474]},"n2140006340":{"id":"n2140006340","loc":[-85.6385831,41.9454343]},"n2140006342":{"id":"n2140006342","loc":[-85.639341,41.945157]},"n2140006344":{"id":"n2140006344","loc":[-85.6393497,41.9450232]},"n2140006346":{"id":"n2140006346","loc":[-85.6388245,41.9450145]},"n2140006348":{"id":"n2140006348","loc":[-85.6388167,41.9441739]},"n2140006351":{"id":"n2140006351","loc":[-85.6382915,41.9441797]},"n2140006353":{"id":"n2140006353","loc":[-85.63828,41.9438109]},"n2140006355":{"id":"n2140006355","loc":[-85.6381949,41.9436009]},"n2140006357":{"id":"n2140006357","loc":[-85.6371904,41.9435918]},"n2140006359":{"id":"n2140006359","loc":[-85.6366966,41.9432727]},"n2140006361":{"id":"n2140006361","loc":[-85.6353755,41.9432744]},"n2140006365":{"id":"n2140006365","loc":[-85.6350906,41.9435472]},"n2140006366":{"id":"n2140006366","loc":[-85.6343461,41.9441573]},"n2140006395":{"id":"n2140006395","loc":[-85.6351171,41.9437175]},"n2140006397":{"id":"n2140006397","loc":[-85.635352,41.9450206]},"n2140006399":{"id":"n2140006399","loc":[-85.6358194,41.9454937]},"n2140006401":{"id":"n2140006401","loc":[-85.6348693,41.9445739]},"n2140006431":{"id":"n2140006431","loc":[-85.6376737,41.9438023]},"n2140006437":{"id":"n2140006437","loc":[-85.6382631,41.9442724]},"n2189123379":{"id":"n2189123379","loc":[-85.6342671,41.9352665]},"w203974076":{"id":"w203974076","tags":{"highway":"footway"},"nodes":["n2139870442","n2139870457","n2139870458","n2139870459","n2139870460","n2139870452"]},"w170989131":{"id":"w170989131","tags":{"name":"St Joseph River","waterway":"river"},"nodes":["n1820938225","n1820938712","n1820937596","n1820937574","n1820938515","n1820938330","n1820938678","n1820938240","n1820938950","n1820939226","n1820939575","n1820937913","n1820938223","n1820937668","n1820938545","n1820937584","n1820939742","n1820939727","n1820937578","n1820938149","n1820938124","n1820938888","n1820938898","n1820937922","n1820939543","n1820939370","n1820939401","n1820939647","n1820938345","n1820939644","n1820938333","n1820938370","n1820938624","n1820938493","n1820939559","n1820939763","n1820939237","n1820939416","n1820937810","n1820938317","n1820938324","n1820937558","n1820939556","n1820938298","n1820939348","n1820939125","n1820939081","n1820938859","n1820939126","n1820938881","n1820939439","n1820939324","n1820939128","n1820938101","n1820937706","n1820938382","n1820938776","n1820937815","n1820939177","n1820939688","n1820938952","n1820938216","n1820938387","n1820939333","n1820938243","n1820938248","n1820937666","n1820939051","n1820938332","n1820939438","n1820939407","n1820939361","n1820937517","n1820938770","n1820939591","n1820937857","n1820938491","n1820937993","n1820938125","n1820938166","n1820937746","n1820939028","n1820937638","n1820938676","n1820938843","n1820938844","n1820937978","n1820938730","n1820939544","n1820938304","n1820939123","n1820939494","n1820939450","n1820939555","n1820938133","n1820938129","n1820938871","n1820939408","n1820938669","n1820938260","n1820939740","n1820937625","n1820938631","n1820939651","n1820939613","n1820937850","n1820938325","n1820937736","n1820938804","n1820938837","n1820938014","n1820938991","n1820938722","n1820938935","n1820937870","n1820938432","n1820937986","n1820938756","n1820938966","n1820939159","n1820937744","n1820938334","n1820937645","n1820939394","n1820937656","n1820938392","n1820939703","n1820938385","n1820938947","n1820938854","n1820938428","n1820938488","n1820938269","n1820938668","n1820938268","n1820938707","n1820937732","n1820939144","n1820938481","n1820938771","n1820938686","n1820938948","n1820937997","n1820937769","n1820939003","n1820938083","n1820939011","n1820938803","n1820938700","n1820939723","n1820938808","n1820938262","n1820938081","n1820938926","n1820938326","n1820938102","n1820938508","n1820939590","n1820939199","n1820938084","n1820938870","n1820938895","n1820937611","n1820938918","n1820938514","n1820939610","n1820938910","n1820937523","n1820938127","n1820939108","n1820937981","n1820938938","n1820938715","n1820939016","n1820938237","n1820939623","n1820939602","n1820937734","n1820938977","n1820939633","n1820939156","n1820939406","n1820938279","n1820938301","n1820937678","n1820937671","n1820939163","n1820938356","n1820939372","n1820937568","n1820937626","n1820939710","n1820939004","n1820938253","n1820938571","n1820937513","n1820939412","n1820939701","n1820939509","n1820938839","n1820939731","n1820937798","n1820939676","n1820939724","n1820939243","n1820939704","n1820937814","n1820937599","n1820938199","n1820938995","n1820938445","n1820938069","n1820938470","n1820939074","n1820938193","n1820938740","n1820938047","n1820939507","n1820939441","n1820939160","n1820937849","n1820937840","n1820938052","n1820938988","n1820938796","n1820937724","n1820937620","n1820939304","n1820938343","n1820939649","n1820938875","n1820939686","n1820938476","n1820937801","n1820937737","n1820938264","n1820939609","n1820939496","n1820939593","n1820939566","n1820939661","n1820937782","n1820938912","n1820939173","n1820937733","n1820938953","n1820939603","n1820937607","n1820938468","n1820939601","n1820939694","n1820939133","n1820938897","n1820938893","n1820937831","n1820937730","n1820938820","n1820938046","n1820938426","n1820938347","n1820937582","n1820938954","n1820938033","n1820938104","n1820938680","n1820939563","n1820939404","n1820939714","n1820939000","n1820937992","n1820938168","n1820939510","n1820939500","n1820937509","n1820938865","n1820939773","n1820938138","n1820938905","n1820937623","n1820939418","n1820937946","n1820939577","n1820937615","n1820939687","n1820939119","n1820937988","n1820938337","n1820937750","n1820938703","n1820938339","n1820939044","n1820939770","n1820938913","n1820937672","n1820939722","n1820937768","n1820939597","n1820939612","n1820937699","n1820937682","n1820937669","n1820937657","n1820939363","n1820937800","n1820938265","n1820937760","n1820938207","n1820938115","n1820939130","n1820939716","n1820938338","n1820938239","n1820939040","n1820938064","n1820938855","n1820939015","n1820938258","n1820939042","n1820939043","n1820938443","n1820939725","n1820937675","n1820938568","n1820938280","n1820937705","n1820938775","n1820938636","n1820938626","n1820937859","n1820938096","n1820937852","n1820939039","n1820938247","n1820938585","n1820937707","n1820938117","n1820938909","n1820939115","n1820939335","n1820938805","n1820937935","n1820937876","n1820938699","n1820937869","n1820938603","n1820938100","n1820938500","n1820938283","n1820938275","n1820938923","n1820938365","n1820938349","n1820937804","n1820937903","n1820937608","n1820938688","n1820939671","n1820938092","n1820937820","n1820938753","n1820938922","n1820937990","n1820939682","n1820939738","n1820939600","n1820938167","n1820937726","n1820939702","n1820938209","n1820939456","n1820937837","n1820938222","n1820938902","n1820939162","n1820938965","n1820938461","n1820937681","n1820937514","n1820937764","n1820939719","n1820939697","n1820938899","n1820939093","n1820938702","n1820939595","n1820938749","n1820938348","n1820937606","n1820938675","n1820938830","n1820938737","n1820938758","n1820938716","n1820939107","n1820937863","n1820939033","n1820938163","n1820937867","n1820938819","n1820938034","n1820938252","n1820937563","n1820937868","n1820939032","n1820938632","n1820937982","n1820937943","n1820939568","n1820939541","n1820938215","n1820939097","n1820938812","n1820937518","n1820937952","n1820938711","n1820938736","n1820939066","n1820937591","n1820938082","n1820938108","n1820938496","n1820939410","n1820938949","n1820938327","n1820937708","n1820939023","n1820937772","n1820938256","n1820939083","n1820938378","n1820938961","n1820937610","n1820939717","n1820938695","n1820938590","n1820939655","n1820938341","n1820939054","n1820939157","n1820939674","n1820939684","n1820939511","n1820937631","n1820939458","n1820937830","n1820937709","n1820937779","n1820939749","n1820938880","n1820938856","n1820938557","n1820939557","n1820938249","n1820938818","n1820937594","n1820939114","n1820938416","n1820937508","n1820938990","n1820938201","n1820937759","n1820937987","n1820939164","n1820939753","n1820938187","n1820939067","n1820937586","n1820937941","n1820938121","n1820937807","n1820938521","n1820939726","n1820938244","n1820939014","n1820938741","n1820937629","n1820938664","n1820938747","n1820939082","n1820938709","n1820938320","n1820938270","n1820937619","n1820937777","n1820937718","n1820939138","n1820938056","n1820938155","n1820938596","n1820937775","n1820938437","n1820938128","n1820939581","n1820939145","n1820938546","n1820938184","n1820937601","n1820937794","n1820938539","n1820939645","n1820938438","n1820938436","n1820939025","n1820938915","n1820938534","n1820937605","n1820939607","n1820939101","n1820939580","n1820939268","n1820939134","n1820938849","n1820938754","n1820938079","n1820937842","n1820938781","n1820938873","n1820938495","n1820938381","n1820938503","n1820939436","n1820938502","n1820939087","n1820938996","n1820938449","n1820938907","n1820937979","n1820937780","n1820937546","n1820939699","n1820937677","n1820938957","n1820938946","n1820937776","n1820937717","n1820938718","n1820937637","n1820938510","n1820937663","n1820938941","n1820939151","n1820937603","n1820938250","n1820937951","n1820938630","n1820938821","n1820938779","n1820938497","n1820938159","n1820939536","n1820938409","n1820938386","n1820939116","n1820938340","n1820939117","n1820938291","n1820938435","n1820937819","n1820938242","n1820939078","n1820938877","n1820939104","n1820939445","n1820938367","n1820938903","n1820939420","n1820938517","n1820939508","n1820939542","n1820939326","n1820938210","n1820939020","n1820938815","n1820937832","n1820939513","n1820937818","n1820939005","n1820938717","n1820939135","n1820938384","n1820937587","n1820939024","n1820939504","n1820939120","n1820939026","n1820938015","n1820938998","n1820937648","n1820939137","n1820937761","n1820938195","n1820938535","n1820939550","n1820938725","n1820938282","n1820937781","n1820937792","n1820939705","n1820937788","n1820939707","n1820937882","n1820939632","n1820938427","n1820938276","n1820939617","n1820939013","n1820939035","n1820937543","n1820939365","n1820937752","n1820937802","n1820939183","n1820939670","n1820938450","n1820939375","n1820937813","n1820937673","n1820937783","n1820939029","n1820939768","n1820939377","n1820937974","n1820939244","n1820939642","n1820937864","n1820938255","n1820938528","n1820939666","n1820938120","n1820937812","n1820938928","n1820939750","n1820939099","n1820938073","n1820938714","n1820939140","n1820938192","n1820937844","n1820938635","n1820938742","n1820939583","n1820937887","n1820938318","n1820938816","n1820939698","n1820938273","n1820939181","n1820937652","n1820938748","n1820937651","n1820938519","n1820938019","n1820938752","n1820938235","n1820939118","n1820938562","n1820939314","n1820939570","n1820938190","n1820938342","n1820938533","n1820937977","n1820939089","n1820939146","n1820938622","n1820938297","n1820938524","n1820939283","n1820938874","n1820938832","n1820937550","n1820937843","n1820938638","n1820938116","n1820938206","n1820938319","n1820939053","n1820937845","n1820938093","n1820939217","n1820938997","n1820939355","n1820938861","n1820938726","n1820938057","n1820939373","n1820937862","n1820938518","n1820939072","n1820939680","n1820938444","n1820938217","n1820938506","n1820938393","n1820938492","n1820938852","n1820938221","n1820938773","n1820937684","n1820939060","n1820938224","n1820938203","n1820938840","n1820937525","n1820938147","n1820938433","n1820938188","n1820939359","n1820938750","n1820938016","n1820938768","n1820937621","n1820937799","n1820938951","n1820938721","n1820939037","n1820937866","n1820939715","n1820938063","n1820938446","n1820937627","n1820939624","n1820938431","n1820939721","n1820939622","n1820939239","n1820939263","n1820939648","n1820939640","n1820938867","n1820938757","n1820938439","n1820939352","n1820937740","n1820939329","n1820938229","n1820937583","n1820938180","n1820938366","n1820937767","n1820937758","n1820939374","n1820938869","n1820938292","n1820938400","n1820938399","n1820939734","n1820939289","n1820938944","n1820937755","n1820938759","n1820938434","n1820937600","n1820937825","n1820937670","n1820937793","n1820938011","n1820938246","n1820938956","n1820937770","n1820937757","n1820938059","n1820937860","n1820937569","n1820939266","n1820939685","n1820939672","n1820938606","n1820938772","n1820939038","n1820938211","n1820938359","n1820939619","n1820938708","n1820939512","n1820938065","n1820939233","n1820939739","n1820938786","n1820938879","n1820939147","n1820938563","n1820939148","n1820937839","n1820937659","n1820937786","n1820938419","n1820939565","n1820939402","n1820937710","n1820938254","n1820938271","n1820938390","n1820937680","n1820938140","n1820937817","n1820938218","n1820937985","n1820939235","n1820938441","n1820938401","n1820938719","n1820937795","n1820938971","n1820938460","n1820939759","n1820937972","n1820937841","n1820938462","n1820939320","n1820938978","n1820938360","n1820939713","n1820937676","n1820939712","n1820937939","n1820938080","n1820937754","n1820937753","n1820938530","n1820937886","n1820939689","n1820939124","n1820938697","n1820938789","n1820939105","n1820938860","n1820938853","n1820939400","n1820937561","n1820938404","n1820938774","n1820939316","n1820937696","n1820938782","n1820938975","n1820937564","n1820939730","n1820938257","n1820937853","n1820938487","n1820938848","n1820938906","n1820939230","n1820938424","n1820938051","n1820937771","n1820939587","n1820939149","n1820938792","n1820939041","n1820938934","n1820939777","n1820937515","n1820939058","n1820938312","n1820939264","n1820939631","n1820939109","n1820939403","n1820939664","n1820938724","n1820938929","n1820939399","n1820939776","n1820939369","n1820939185","n1820937701","n1820938126","n1820938336","n1820938219","n1820939080","n1820938642","n1820938043","n1820937725","n1820938548","n1820938552","n1820938035","n1820938684","n1820937778","n1820938764","n1820939021","n1820939346","n1820937712","n1820939761","n1820938397","n1820937747","n1820938566","n1820939161","n1820939090","n1820939752","n1820939271","n1820938878","n1820938110","n1820938346","n1820938499","n1820938151","n1820939538","n1820938281","n1820939153","n1820938551","n1820939285","n1820938197","n1820938408","n1820938482","n1820939036","n1820939579","n1820938489","n1820938483","n1820938189","n1820938123","n1820938087","n1820937741","n1820938485","n1820937590","n1820938972","n1820937773","n1820937520","n1820938872","n1820938131","n1820938452","n1820938328","n1820939620","n1820937641","n1820938353","n1820939693","n1820938705","n1820937640","n1820939189","n1820938144","n1820939774","n1820938694","n1820938238","n1820939397","n1820937917","n1820938454","n1820938567","n1820938979","n1820938060","n1820938204","n1820937828","n1820939232","n1820938806","n1820938857","n1820938078","n1820938105","n1820939228","n1820938604","n1820937763","n1820937854","n1820938289","n1820939736","n1820937937","n1820937714","n1820938278","n1820938058","n1820938706","n1820938989","n1820938313","n1820938520","n1820938288","n1820937689","n1820939537","n1820939531","n1820939019","n1820937527","n1820938455","n1820938814","n1820938045","n1820939627","n1820938213","n1820938161","n1820938331","n1820938024","n1820938220","n1820938062","n1820938178","n1820937796","n1820937644","n1820938490","n1820937589","n1820937879","n1820939614","n1820938882","n1820938039","n1820938538","n1820937667","n1820937719","n1820938561","n1820939658","n1820938783","n1820938601","n1820938198","n1820938388","n1820938969","n1820937687","n1820939086","n1820939665","n1820939187","n1820938498","n1820938261","n1820937983","n1820938068","n1820938136","n1820939061","n1820938137","n1820938186","n1820939071","n1820937592","n1820939669","n1820937553","n1820939357","n1820938727","n1820939371","n1820939112","n1820939079","n1820938743","n1820938467","n1820938834","n1820938022","n1820938537","n1820938122","n1820938516","n1820937614","n1820937612","n1820939469","n1820939636","n1820939050","n1820939552","n1820938157","n1820938663","n1820938955","n1820939091","n1820938430","n1820938471","n1820937809","n1820938074","n1820938208","n1820938914","n1820938858","n1820938417","n1820937531","n1820938107","n1820939100","n1820938751","n1820937711","n1820938824","n1820939745","n1820937572","n1820938602","n1820938212","n1820938097","n1820937921","n1820938090","n1820938511","n1820938876","n1820939762","n1820938234","n1820938048","n1820937774","n1820937856","n1820937749","n1820937765","n1820938286","n1820939095","n1820938480","n1820939229","n1820938277","n1820937617","n1820938311","n1820937622","n1820939196","n1820937690","n1820939006","n1820939287","n1820939131","n1820938106","n1820938784","n1820938335","n1820938095","n1820938182","n1820937715","n1820937683","n1820938070","n1820939605","n1820938527","n1820938763","n1820938398","n1820937686","n1820939621","n1820937664","n1820939277","n1820938565","n1820939539","n1820938099","n1820939646","n1820938556","n1820937548","n1820938729","n1820939336","n1820938259","n1820938728","n1820938361","n1820937643","n1820938644","n1820939007","n1820939690","n1820939227","n1820937635","n1820937950","n1820938682","n1820939150","n1820939012","n1820939261","n1820939111","n1820937805","n1820939691","n1820939677","n1820937628","n1820937811","n1820938790","n1820938251","n1820938226","n1820938942","n1820937633","n1820937984","n1820937751","n1820939673","n1820938970","n1820938415","n1820938597","n1820938309","n1820938111","n1820938472","n1820938894","n1820938402","n1820937593","n1820938570","n1820939102","n1820939775","n1820937948","n1820939121","n1820937511","n1820938787","n1820939720","n1820939075","n1820937880","n1820937742","n1820937721","n1820939535","n1820938486","n1820938354","n1820937632","n1820939010","n1820938885","n1820938089","n1820937613","n1820938442","n1820938245","n1820938272","n1820937566","n1820938295","n1820938532","n1820938883","n1820937713","n1820937674","n1820939635","n1820938448","n1820938355","n1820938587","n1820938559","n1820937787","n1820939301","n1820937723","n1820939056","n1820937560","n1820938323","n1820938230","n1820938453","n1820938377","n1820938357","n1820939637","n1820938017","n1820939540","n1820939376","n1820937639","n1820937642","n1820938075","n1820938351","n1820938766","n1820937897","n1820938973","n1820938066","n1820939547","n1820939652","n1820937944","n1820937748","n1820939234","n1820939193","n1820937891","n1820938785","n1820939132","n1820938523","n1820938884","n1820938411","n1820939554","n1820938791","n1820937655","n1820938368","n1820939152","n1820938030","n1820938447","n1820937580","n1820939628","n1820937588","n1820937894","n1820939201","n1820938086","n1820937650","n1820938379","n1820939008","n1820938999","n1820937524","n1820937872","n1820938389","n1820939197","n1820938422","n1820938936","n1820939262","n1820937634","n1820938583","n1820939589","n1820937901","n1820939034","n1820939065","n1820938290","n1820939195","n1820938228","n1820937884","n1820938797","n1820938191","n1820939191","n1820939198","n1820937892","n1820939679","n1820938507","n1820937647","n1820937909","n1820938542","n1820939598","n1820937851","n1820939084","n1820939728","n1820937688","n1820938263","n1820938670","n1820937762","n1820939310","n1820938925","n1820938862","n1820938822","n1820938547","n1820937731","n1820938594","n1820938592","n1820938214","n1820938284","n1820937835","n1820938599","n1820939437","n1820937834","n1820937576","n1820937692","n1820939586","n1820939546","n1820938403","n1820937970","n1820939561","n1820938098","n1820938851","n1820938477","n1820938892","n1820939045","n1820939758","n1820939350","n1820938321","n1820938440","n1820938595","n1820938364","n1820938962","n1820938118","n1820939678","n1820938406","n1820938549","n1820937555","n1820938823","n1820937521","n1820939471","n1820939487","n1820938799","n1820938605","n1820937928","n1820938373","n1820939747","n1820939629","n1820937557","n1820937526","n1820938958","n1820938833","n1820937636","n1820938967","n1820938760","n1820938842","n1820938067","n1820939077","n1820939224","n1820938185","n1820939110","n1820938372","n1820939757","n1820939063","n1820939660","n1820938813","n1820937528","n1820938369","n1820938896","n1820939551","n1820939683","n1820937660","n1820937873","n1820938810","n1820938478","n1820939662","n1820937595","n1820939052","n1820938113","n1820939070","n1820938733","n1820937878","n1820938300","n1820939760","n1820939718","n1820937646","n1820939057","n1820939443","n1914861306","n1820938013","n1820937529","n1820939764","n1820938826","n1820937885","n1820939588","n1820937865","n1820937833","n1914861112","n1820938761","n1914861007","n1820937905","n1820938541","n1820939092","n1914861057","n1820938153","n1820938267","n1820939265","n1820938085","n1820939018","n1820939755","n1820938474","n1820939027","n1820938593","n1820938202","n1820939599","n1820939695","n1820938077","n1820938012","n1820939545","n1820939596","n1820939337","n1820938227","n1820937698","n1820938475","n1820939465","n1820938165","n1820938698","n1820938525","n1820938529","n1820938553","n1820938940","n1820939498","n1820938501","n1820939533","n1820938924","n1820939634","n1820939220","n1820939657","n1820938887","n1820938838","n1820938114","n1820937823","n1820938778","n1820938801","n1820939096","n1820938981","n1820937953","n1820938732","n1820938980","n1820938960","n1820937949","n1820938026","n1820939273","n1841425201","n1820938629","n1820938864","n1820938554","n1820938088","n1820937685","n1841425222","n1820939729","n1820937665","n1820937838","n1820937739","n1820938780","n1820937821","n1820938825","n1820939055","n1820939485","n1820938041","n1820938746","n1820939562","n1820938459","n1820939489","n1820938050","n1820937980","n1820937695","n1820938413","n1820938555","n1820937703","n1820938536","n1820938196","n1820938287","n1820938169","n1820939279","n1820938531","n1820938959","n1820939741","n1820938665","n1820938963","n1820939611","n1820937653","n1820939618","n1820939492","n1820938600","n1820938628","n1820939312","n1820939616","n1820937738","n1820939001","n1820939062","n1820938794","n1820938558","n1820937822","n1820937532","n1820939073","n1820938200","n1820938241","n1820938968","n1820938927","n1820938306","n1820937630","n1820938456","n1820937694","n1820938908","n1820939076","n1820937522","n1820939659","n1820938522","n1820939318","n1820938932","n1820938841","n1820937579","n1820937540","n1820938560","n1821139530","n1820938964","n1820937662","n1820939281","n1821139533","n1820937797","n1821139532","n1820939751","n1821139531","n1820939291","n1820938420","n1820939696","n1820938904","n1820938484","n1820939448","n1820939009","n1820938735","n1820938986","n1820938937","n1820939030","n1820938734","n1820938745","n1820939106","n1820938987","n1820937858","n1820938673","n1820938620","n1820937808","n1820937700","n1820939573","n1820938540","n1820937661","n1820937570","n1820938396","n1820937875","n1820939048","n1820938233","n1820938793","n1820939584","n1820938412","n1820938394","n1820937846","n1820938800","n1820938690","n1820939331","n1820939630","n1820938762","n1820938710","n1820939322","n1820938992","n1821137608","n1821137607","n1820937924","n1820939139","n1820939463","n1820939574","n1820938294","n1820938071","n1820938307","n1820938061","n1820939260","n1820937899","n1820938310","n1820938983","n1820937530","n1820938993","n1820938890","n1820937915","n1820938231","n1820938040","n1820938920","n1820939585","n1820938135","n1820939700","n1820937824","n1820939667","n1820937930","n1820938134","n1820937551","n1820939405","n1820938232","n1820937716","n1820937848","n1820939765","n1820939068","n1820939766","n1820937933","n1820937720","n1820939222","n1820939772","n1820939022","n1820939732","n1820937702","n1820937691","n1820938945","n1820937756","n1820938451","n1820938410","n1820938798","n1820937945","n1820937654","n1820938598","n1820938836","n1820937571","n1820937556","n1820938994","n1820938919","n1820938863","n1820939064","n1820938018","n1820937658","n1820937537","n1820938142","n1820938666","n1820937535","n1820939571","n1820938465","n1820939638","n1820937533","n1820939656","n1820939422","n1820938109","n1820938405","n1820938028","n1820937649","n1820938829","n1820939031","n1820939155","n1820938350","n1820938463","n1820938425","n1820939047","n1820938831","n1820938494","n1820937697","n1820938504","n1820938900","n1820937784","n1820938414","n1820938076","n1820938723","n1820937722","n1820938739","n1820937791","n1820938985","n1820938352","n1820938293","n1820938274","n1820939692","n1820937871","n1820939059","n1820938868","n1820937877","n1820937743","n1820938429","n1820937545","n1820937575","n1820938302","n1820938505","n1820938916","n1820938374","n1820938329","n1820937790","n1820939735","n1820938930","n1820937995","n1820938512","n1820938130","n1820938194","n1820938671","n1820938802","n1820937542","n1820937602","n1820939069","n1820938901","n1820939654","n1820937727","n1820939569","n1820938375","n1820939306","n1820938479","n1820938376","n1820938667","n1820937766","n1820939467","n1820939567","n1820937806","n1820938943","n1820938931","n1820937745","n1820939452","n1820938738","n1820938053","n1820939653","n1820938640","n1820937604","n1820937536","n1820938701","n1820939625","n1820939744","n1820939572","n1820937577","n1820937541","n1820938891","n1820937597","n1820938469","n1820939194","n1820937539","n1820938911","n1820939017","n1820939650","n1820939103","n1820939578","n1820938132","n1820937549","n1820938634","n1820939743","n1820937544","n1820937826","n1820937598","n1820937547","n1820938032","n1820939142"]},"w17963021":{"id":"w17963021","tags":{"highway":"residential"},"nodes":["n185948706","n185948708","n185948710"]},"w203974069":{"id":"w203974069","tags":{"amenity":"shelter","area":"yes","building":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139870431","n2139870432","n2139870433","n2139870434","n2139870431"]},"w209816575":{"id":"w209816575","tags":{"area":"yes","building":"yes"},"nodes":["n2199856288","n2199856289","n2199856290","n2199856291","n2199856292","n2199856293","n2199856294","n2199856295","n2199856296","n2199856297","n2199856298","n2199856299","n2199856300","n2199856301","n2199856302","n2199856303","n2199856288"]},"w203841838":{"id":"w203841838","tags":{"area":"yes","natural":"water"},"nodes":["n2138493826","n2138493827","n2138493828","n2138493829","n2138493830","n2138493831","n2138493833","n2138493832","n2138493826"]},"w203972937":{"id":"w203972937","tags":{"highway":"path","name":"Riverwalk Trail","surface":"asphalt","width":"3"},"nodes":["n2139858882","n2139858883","n2139858884","n2139858885","n2139858886","n2139858887","n2139858882","n2139858888","n2139858889","n2139858890","n2139858891","n2139858892","n2139858893","n2139858894","n2139858895","n2139858896","n2139858897","n2139858898","n2139858899","n2139858900","n2139858901","n2139858902","n2139858903","n2139858986","n2139858904","n2139858995","n2139858905","n2139858906","n2139858907","n2139858908","n2139858909","n2139858910","n2139858911","n2139858912","n2139858913","n2139858914","n2139858915","n2139858916","n2139858917","n2139858918","n2139858919","n2139858920","n2139858921","n2139858922","n2139858923","n2139858924","n2139858925","n2139858926","n2139858927","n2139858982","n2139858928","n2139858929","n2139858930","n2139858931","n2139858932","n2139858981","n2139858933","n2139858934","n2139858935","n2139858936","n2139858937","n2139858938","n2139858939","n2139858940","n2139858941","n2139858942","n2139858943","n2140006437","n2139858964","n2139858944","n2139858966","n2139858945","n2139858946","n2139858947","n2139858948","n2139858949","n2139858950","n2139858951"]},"w17964015":{"id":"w17964015","tags":{"highway":"residential"},"nodes":["n185954680","n185954683","n185954685","n185954687","n185954689","n185954690","n185954691","n2139870379","n2139870456","n185954692","n185954693","n185954695"]},"w17967315":{"id":"w17967315","tags":{"highway":"residential","name":"South Andrews Street"},"nodes":["n185981999","n185974477","n185964963"]},"w203974071":{"id":"w203974071","tags":{"highway":"footway"},"nodes":["n2139870439","n2139870440","n2139870441","n2139870442","n2139870443","n2139870444","n2139870445","n2139870446","n2139870447","n2139870448","n2139870449"]},"w170848824":{"id":"w170848824","tags":{"name":"Rocky River","waterway":"river"},"nodes":["n1819858503","n1819858531","n1819858526","n1819858518","n1819858505","n1819858508","n1819858512","n1819858514","n1819858528","n1819858509","n1819858511","n1819858507","n1819858521"]},"w203986458":{"id":"w203986458","tags":{"amenity":"shelter","area":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139989357","n2139989359","n2139989360","n2139989362","n2139989357"]},"w170844917":{"id":"w170844917","tags":{"waterway":"riverbank"},"nodes":["n1819805911","n1819805690","n1819805812","n1819805766","n1819805802","n1819805885","n1819805626","n1819805842","n1819805715","n1819805694","n1819805618","n1819805629","n1819805731","n1819805636","n1819805878","n1819805718","n1819805798","n1819849057","n1819805666","n1819805852","n1819805805","n1819805789","n1819805868","n1819805680","n1819805918","n1819848888","n1819805762","n2139989328","n1819805907","n2139989330","n1819805915","n1819858521","n1819805854","n1819805876","n1819805864","n1819805922","n2139859004","n1819805702","n2139859003","n1819805614","n1819805792","n1819805786","n1819805777","n1819805645","n1819805838","n1819805889","n1819805795","n1819805707","n1819805774","n1819805808","n1819805810","n1819805724","n1819805676","n1819805728","n1819805783","n1819805687","n1819805727","n2189123379","n1819805632","n1819805641","n1819805760","n1819805887","n1819805861","n1819805722","n1819805880","n2139982405","n2139982399","n2139982400","n1819805770","n2139982402","n2139982403","n2139982401","n1819805780","n1819805834","n2139982406","n1819805698","n1819805647","n1819805870","n1819805683","n1819805622","n1819805639","n1819805858","n1819805643","n1819805673","n1819805925","n1819805849","n1819805711","n1819805846","n1819805669","n1819805883","n1819805814","n1819805873","n1819805911"]},"w17967326":{"id":"w17967326","tags":{"highway":"residential","name":"North Constantine Street"},"nodes":["n185985217","n185985219","n185985221","n185985222","n185985223","n185985225","n2140006431","n185985227","n185985229","n185985231","n185985233","n185985235","n185985238","n185985240","n2140018998","n185964965"]},"w134150789":{"id":"w134150789","tags":{"highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964971","n2139870406","n185964972"]},"w17966400":{"id":"w17966400","tags":{"highway":"tertiary","name":"South Constantine Street"},"nodes":["n185958672","n185964965"]},"w203974066":{"id":"w203974066","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139870417","n2139870418","n2139870420","n2139870419"]},"w17965998":{"id":"w17965998","tags":{"name":"Conrail Railroad","railway":"rail"},"nodes":["n185972775","n185972777","n185972779","n185972781","n185972783","n185972785","n185972787","n185972788","n185972789","n185972790","n185972791","n185972793","n185972795","n185972797","n185972798","n185972800","n185972802","n185972805","n185972807","n185972809","n185972811","n185972813","n185972814","n185972815","n185972816","n185972817","n185972819","n185972821","n185972824","n185972826","n185972830","n185972832","n185972834","n185972835","n185972836","n185972839","n185990434","n2114807572","n2114807568","n185972845","n2114807583","n185972847","n185972849","n185972851","n2114807578","n1475293254","n2114807593","n1475293226","n185972862","n2114807565","n185951869","n1475293234","n1475293252","n185972868","n1475293264","n1475293222","n185972878","n1475293261","n185972882","n185972885","n1475293260","n1475293240","n185972891","n185972895","n185972897","n185972899","n2130304159","n1475284023","n185972903"]},"w134150795":{"id":"w134150795","tags":{"bridge":"yes","highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964970","n185964971"]},"w203974067":{"id":"w203974067","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139870420","n2139870421"]},"w170995908":{"id":"w170995908","tags":{"highway":"residential","name":"Thomas Street"},"nodes":["n1821006702","n1821006700","n1821006698","n2139858990","n1821006716","n1821006725","n1821006712","n1821006704","n1821006708","n1821006710","n1821006706"]},"w17965834":{"id":"w17965834","tags":{"highway":"residential","name":"Spring Street"},"nodes":["n185971361","n185971364","n185971366","n185971368","n185954695","n185964968"]},"w203974070":{"id":"w203974070","tags":{"amenity":"shelter","area":"yes","building":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139870435","n2139870436","n2139870437","n2139870438","n2139870435"]},"w203989879":{"id":"w203989879","tags":{"highway":"service"},"nodes":["n2140018998","n2140018999","n2140019000"]},"w203974062":{"id":"w203974062","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139870387","n2139870388","n2139870389","n2139870390","n2139870391","n2139870392","n2139870397","n2139870393","n2139870396","n2139870395","n2139870394","n2139870387"]},"w203974061":{"id":"w203974061","tags":{"bridge":"yes","highway":"footway"},"nodes":["n2139870382","n2139870383"]},"w203049587":{"id":"w203049587","tags":{"area":"yes","name":"Scidmore Park Petting Zoo","tourism":"zoo","zoo":"petting_zoo"},"nodes":["n2130304133","n2130304136","n2130304138","n2130304140","n2130304142","n2130304144","n2130304146","n2130304147","n2130304148","n2130304149","n2130304150","n2130304151","n2130304133"]},"w203972941":{"id":"w203972941","tags":{"highway":"path"},"nodes":["n2139858982","n2139858983","n2139858984","n2139858985","n2139858927"]},"w203974065":{"id":"w203974065","tags":{"highway":"service"},"nodes":["n2139870406","n2139870407","n2139870408","n2139870417","n2139870409","n2139870410","n2139870411","n2139870412","n2139870426","n2139870413","n2139870414","n2139870415","n2139870419","n2139870416","n2139870421","n2139870408"]},"w203972940":{"id":"w203972940","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139858934","n2139858967","n2139858968","n2139858969","n2139858970","n2139858971","n2139858972","n2139858973","n2139858974","n2139858975","n2139858976","n2139858977","n2139858978","n2139858979","n2139858980","n2139858981"]},"w203974072":{"id":"w203974072","tags":{"highway":"footway"},"nodes":["n2139858925","n2139870450","n2139870453","n2139870451","n2139870452","n2139870441"]},"w203974074":{"id":"w203974074","tags":{"highway":"footway"},"nodes":["n2139870454","n2139870456","n2139870429"]},"w203974060":{"id":"w203974060","tags":{"highway":"footway"},"nodes":["n2139870383","n2139870384","n2139870422","n2139870385","n2139870386","n2139870388"]},"w203841837":{"id":"w203841837","tags":{"area":"yes","natural":"water"},"nodes":["n2138493807","n2138493808","n2138493809","n2138493810","n2138493811","n2138493812","n2138493813","n2138493814","n2138493815","n2138493816","n2138493825","n2138493817","n2138493824","n2138493818","n2138493819","n2138493820","n2138493821","n2138493822","n2138493823","n2138493807"]},"w134150845":{"id":"w134150845","tags":{"bridge":"yes","name":"Conrail Railroad","railway":"rail"},"nodes":["n185972903","n185972905"]},"w203974059":{"id":"w203974059","tags":{"highway":"footway"},"nodes":["n2139870430","n2139870439","n2139870429","n2139870428","n2139870379","n2139870455","n2139870380","n2139870381","n2139858925","n2139870382"]},"w203986457":{"id":"w203986457","tags":{"area":"yes","leisure":"park","name":"Scidmore Park"},"nodes":["n2139989333","n2139989335","n2139989337","n2139989339","n1819805762","n2139989328","n1819805907","n2139989330","n1819805915","n2139989341","n2139989344","n2139989346","n2139989348","n2139989350","n2139989351","n2139989353","n2139989355","n2139989333"]},"w170848331":{"id":"w170848331","tags":{"name":"Rocky River","waterway":"river"},"nodes":["n1819848937","n1819849104","n1819849076","n1819849183","n1819848928","n1819848972","n1819848948","n1819848971","n1819848859","n1819849008","n1819848889","n1819849026","n1819849094","n1819849083","n1819849079","n1819849187","n1819848992","n1819849060","n1819849056","n1819849071","n1819849067","n1819849048","n1819849036","n1819849150","n1819849075","n1819849051","n1819849062","n1819848926","n1819849035","n1819848987","n1819849012","n1819848933","n1819848996","n1819848990","n1819849005","n1819849021","n1819848892","n1819849092","n1819848863","n1819848922","n1819848858","n1819848855","n1819848974","n1819848953","n1819849019","n1819849049","n1819848979","n1819849140","n1819849193","n1819849147","n1819849151","n1819849163","n1819849023","n1819848878","n1819849004","n1819848857","n1819848879","n1819849041","n1819849165","n1819849107","n1819849156","n1819848934","n1819848914","n1819848955","n1819848931","n1819848927","n1819849084","n1819849169","n1819849045","n1819848945","n1819849095","n1819848924","n1819849171","n1819849141","n1819849046","n1819849197","n1819849011","n1819849108","n1819849158","n1819849160","n1819848870","n1819849006","n1819849157","n1819848993","n1819848970","n1819849202","n1819848903","n1819848975","n1819848849","n1819849025","n1819849105","n1819849033","n1819849176","n1819849099","n1819849086","n1819848960","n1819848961","n1819849001","n1819848980","n1819849038","n1819848854","n1819849127","n1819849170","n1819849139","n1819848873","n1819848929","n1819849201","n1819849121","n1819849031","n1819849131","n1819848875","n1819849080","n1819849066","n1819849081","n1819849096","n1819849172","n1819849114","n1819849182","n1819848905","n1819849054","n1819848920","n1819848851","n1819848968","n1819848917","n1819849111","n1819849119","n1819849074","n1819848893","n1819849129","n1819848850","n1819848956","n1819849154","n1819848877","n1819848986","n1819849191","n1819848952","n1819848954","n1819848942","n1819849028","n1819849195","n1819848938","n1819848962","n1819849070","n1819849034","n1819849052","n1819849059","n1819848916","n1819849162","n1819849167","n1819849093","n1819849030","n1819849002","n1819849161","n1819848886","n1819848958","n1819849064","n1819849112","n1819849148","n1819848856","n1819848976","n1819848977","n1819849144","n1819848918","n1819849200","n1819848919","n1819849042","n1819849166","n1819849186","n1819849152","n1819849058","n1819849185","n1819849199","n1819849053","n1819849194","n1819849068","n1819849146","n1819849174","n1819848967","n1819848932","n1819849155","n1819849198","n1819848964","n1819848894","n1819848969","n1819849184","n1819849055","n1819849179","n1819848865","n1819848860","n1819849082","n1819848966","n1819849040","n1819849069","n1819849078","n1819849077","n1819848904","n1819848959","n1819849133","n1819849089","n1819849000","n1819849124","n1819849032","n1819849097","n1819848939","n1819849072","n1819848915","n1819849196","n1819848946","n1819849047","n1819849029","n1819849164","n1819848994","n1819849022","n1819858513","n1819849126","n1819849063","n1819848941","n1819849085","n1819848871","n1819848943","n1819849192","n1819858501","n1819849159","n1819858523","n1819848901","n1819849189","n1819858503","n1819849065","n2139877106","n1819848909","n1819848930","n1819848888"]},"w17967397":{"id":"w17967397","tags":{"highway":"residential","name":"North Andrews Street"},"nodes":["n185964963","n185985217"]},"w17964497":{"id":"w17964497","tags":{"highway":"tertiary","name":"Constantine St"},"nodes":["n185958643","n185958645","n2139795852","n185958647","n185958649","n185958651","n185958653","n185958656","n185958658","n185958660","n185958662","n185958664","n185958666","n185958668","n185958670","n185948710","n185958672"]},"w203974068":{"id":"w203974068","tags":{"highway":"footway"},"nodes":["n2139870422","n2139870423","n2139870424","n2139870425","n2139870426","n2139870427"]},"w203974063":{"id":"w203974063","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139870398","n2139870399","n2139870400","n2139870401","n2139870398"]},"w203986459":{"id":"w203986459","tags":{"amenity":"shelter","area":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139989364","n2139989366","n2139989368","n2139989370","n2139989364"]},"w203988286":{"id":"w203988286","tags":{"area":"yes","leisure":"park","name":"Memory Isle Park"},"nodes":["n2140006331","n2140006334","n2140006336","n2140006338","n2140006340","n2140006342","n2140006344","n2140006346","n2140006348","n2140006351","n2140006353","n2140006355","n2140006357","n2140006359","n2140006361","n2140006363","n2140006364","n2140006365","n2140006395","n2140006366","n2140006401","n2140006397","n2140006399","n2140006331"]},"w203974073":{"id":"w203974073","tags":{"highway":"footway"},"nodes":["n2139870453","n2139870454","n2139870455"]},"w203974064":{"id":"w203974064","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139870402","n2139870403","n2139870404","n2139870405","n2139870402"]},"n185966959":{"id":"n185966959","loc":[-85.642185,41.946411]},"n1475283980":{"id":"n1475283980","loc":[-85.6398249,41.9451425]},"n1475284013":{"id":"n1475284013","loc":[-85.6396448,41.9451666]},"n1475284042":{"id":"n1475284042","loc":[-85.6386382,41.9454789]},"n185975925":{"id":"n185975925","loc":[-85.6393332,41.9452388]},"n185975919":{"id":"n185975919","loc":[-85.6391279,41.9453044]},"n185975917":{"id":"n185975917","loc":[-85.6389034,41.9453872]},"n2140006369":{"id":"n2140006369","loc":[-85.6386163,41.9451631]},"n2140006370":{"id":"n2140006370","loc":[-85.6385144,41.9449357]},"n2140006417":{"id":"n2140006417","loc":[-85.6385785,41.9450299]},"n2140006419":{"id":"n2140006419","loc":[-85.6385781,41.9452152]},"n2189123361":{"id":"n2189123361","loc":[-85.6404948,41.947015]},"n2189123363":{"id":"n2189123363","loc":[-85.6395765,41.946495]},"n2189123365":{"id":"n2189123365","loc":[-85.6389347,41.9460875]},"n185966962":{"id":"n185966962","loc":[-85.644417,41.946364]},"n185975911":{"id":"n185975911","loc":[-85.637532,41.9458276]},"n185975913":{"id":"n185975913","loc":[-85.6376323,41.9457936]},"n185975915":{"id":"n185975915","loc":[-85.6383596,41.9455425]},"n185975932":{"id":"n185975932","loc":[-85.644403,41.945088]},"n185975934":{"id":"n185975934","loc":[-85.645486,41.945084]},"n185979974":{"id":"n185979974","loc":[-85.644381,41.943831]},"n2139795809":{"id":"n2139795809","loc":[-85.6464756,41.9450813]},"n2139795810":{"id":"n2139795810","loc":[-85.6466646,41.945174]},"n2139858952":{"id":"n2139858952","loc":[-85.6383567,41.9454039]},"n2139858953":{"id":"n2139858953","loc":[-85.6380506,41.9455301]},"n2139858954":{"id":"n2139858954","loc":[-85.6377321,41.9455546]},"n2139858955":{"id":"n2139858955","loc":[-85.6376571,41.9455245]},"n2139858956":{"id":"n2139858956","loc":[-85.6375859,41.9454544]},"n2139858957":{"id":"n2139858957","loc":[-85.6376686,41.9453185]},"n2139858958":{"id":"n2139858958","loc":[-85.6378936,41.9451712]},"n2139858959":{"id":"n2139858959","loc":[-85.6379225,41.9450825]},"n2139858960":{"id":"n2139858960","loc":[-85.6379302,41.9447564]},"n2139858961":{"id":"n2139858961","loc":[-85.6379763,41.9446963]},"n2139858962":{"id":"n2139858962","loc":[-85.6380436,41.9446706]},"n2139858963":{"id":"n2139858963","loc":[-85.6381286,41.9445969]},"n2139858965":{"id":"n2139858965","loc":[-85.6382523,41.9444134]},"n2140006367":{"id":"n2140006367","loc":[-85.6380923,41.9454418]},"n2140006368":{"id":"n2140006368","loc":[-85.6384089,41.9453146]},"n2140006372":{"id":"n2140006372","loc":[-85.6383252,41.9447706]},"n2140006374":{"id":"n2140006374","loc":[-85.6381033,41.9447436]},"n2140006376":{"id":"n2140006376","loc":[-85.6379759,41.9447815]},"n2140006378":{"id":"n2140006378","loc":[-85.6379832,41.9448654]},"n2140006380":{"id":"n2140006380","loc":[-85.6380632,41.9450738]},"n2140006382":{"id":"n2140006382","loc":[-85.6380414,41.9452064]},"n2140006389":{"id":"n2140006389","loc":[-85.6379068,41.9453092]},"n2140006391":{"id":"n2140006391","loc":[-85.637925,41.9453904]},"n2140006393":{"id":"n2140006393","loc":[-85.6379977,41.94545]},"n2189123275":{"id":"n2189123275","loc":[-85.6371346,41.9462544]},"n2189123278":{"id":"n2189123278","loc":[-85.6368371,41.9466153]},"n2189123280":{"id":"n2189123280","loc":[-85.6379537,41.9489088]},"n2189123282":{"id":"n2189123282","loc":[-85.6383816,41.9497858]},"n2189123285":{"id":"n2189123285","loc":[-85.6393673,41.9512417]},"n2189123287":{"id":"n2189123287","loc":[-85.640554,41.9517766]},"n2189123289":{"id":"n2189123289","loc":[-85.6411,41.9522344]},"n2189123291":{"id":"n2189123291","loc":[-85.6417418,41.9526574]},"n2189123293":{"id":"n2189123293","loc":[-85.642321,41.9529407]},"n2189123295":{"id":"n2189123295","loc":[-85.6427697,41.9532278]},"n2189123297":{"id":"n2189123297","loc":[-85.6433332,41.9538254]},"n2189123300":{"id":"n2189123300","loc":[-85.6435785,41.9543648]},"n2189123301":{"id":"n2189123301","loc":[-85.6444394,41.9541048]},"n2189123303":{"id":"n2189123303","loc":[-85.6450603,41.954]},"n2189123312":{"id":"n2189123312","loc":[-85.6454829,41.9539108]},"n2189123314":{"id":"n2189123314","loc":[-85.6460464,41.9538526]},"n2189123315":{"id":"n2189123315","loc":[-85.6463178,41.9537167]},"n2189123316":{"id":"n2189123316","loc":[-85.646276,41.9534141]},"n2189123317":{"id":"n2189123317","loc":[-85.6459995,41.9531541]},"n2189123318":{"id":"n2189123318","loc":[-85.645222,41.9531929]},"n2189123319":{"id":"n2189123319","loc":[-85.6447316,41.9531813]},"n2189123320":{"id":"n2189123320","loc":[-85.6440637,41.9532977]},"n2189123321":{"id":"n2189123321","loc":[-85.6438185,41.9531774]},"n2189123322":{"id":"n2189123322","loc":[-85.6440011,41.9528398]},"n2189123323":{"id":"n2189123323","loc":[-85.6442672,41.9525914]},"n2189123324":{"id":"n2189123324","loc":[-85.6442881,41.9523276]},"n2189123326":{"id":"n2189123326","loc":[-85.644262,41.952153]},"n2189123328":{"id":"n2189123328","loc":[-85.6441681,41.9520404]},"n2189123330":{"id":"n2189123330","loc":[-85.6442098,41.9517494]},"n2189123333":{"id":"n2189123333","loc":[-85.6438498,41.9515864]},"n2189123336":{"id":"n2189123336","loc":[-85.6435889,41.9513225]},"n2189123339":{"id":"n2189123339","loc":[-85.6425349,41.9510315]},"n2189123342":{"id":"n2189123342","loc":[-85.6422688,41.9508802]},"n2189123345":{"id":"n2189123345","loc":[-85.6418775,41.9508142]},"n2189123348":{"id":"n2189123348","loc":[-85.6415488,41.9508064]},"n2189123351":{"id":"n2189123351","loc":[-85.6411027,41.9505488]},"n2189123353":{"id":"n2189123353","loc":[-85.6410374,41.9498208]},"n2189123355":{"id":"n2189123355","loc":[-85.6410061,41.9494327]},"n2189123357":{"id":"n2189123357","loc":[-85.6411522,41.9482569]},"n2189123359":{"id":"n2189123359","loc":[-85.6410548,41.9473036]},"n2189123368":{"id":"n2189123368","loc":[-85.6380216,41.9458974]},"n2189123370":{"id":"n2189123370","loc":[-85.6386721,41.9507782]},"w17968193":{"id":"w17968193","tags":{"highway":"residential","name":"French St"},"nodes":["n185970906","n185982877","n185967774","n185985823","n185979974"]},"w203972939":{"id":"w203972939","tags":{"highway":"path"},"nodes":["n2139858965","n2139858966"]},"w203988289":{"id":"w203988289","tags":{"area":"yes","natural":"water"},"nodes":["n2140006367","n2140006368","n2140006419","n2140006369","n2140006417","n2140006370","n2140006372","n2140006374","n2140006376","n2140006378","n2140006380","n2140006382","n2140006389","n2140006391","n2140006393","n2140006367"]},"w208640157":{"id":"w208640157","tags":{"area":"yes","natural":"wetland"},"nodes":["n1819849029","n2189123275","n2189123278","n2189123280","n2189123282","n2189123370","n2189123285","n2189123287","n2189123289","n2189123291","n2189123293","n2189123295","n2189123297","n2189123300","n2189123301","n2189123303","n2189123312","n2189123314","n2189123315","n2189123316","n2189123317","n2189123318","n2189123319","n2189123320","n2189123321","n2189123322","n2189123323","n2189123324","n2189123326","n2189123328","n2189123330","n2189123333","n2189123336","n2189123339","n2189123342","n2189123345","n2189123348","n2189123351","n2189123353","n2189123355","n2189123357","n2189123359","n2189123361","n2189123363","n2189123365","n2189123368","n1819849029"]},"w17966281":{"id":"w17966281","tags":{"highway":"residential","name":"Pealer St"},"nodes":["n185975911","n185975913","n185975915","n1475284042","n185975917","n185975919","n185975925","n185970909","n1475284013","n1475283980","n185975928","n185967775","n185975930","n185975932","n185975934","n2139795809","n2139795810"]},"w17965353":{"id":"w17965353","tags":{"highway":"residential","name":"Yauney St"},"nodes":["n185966958","n185966959","n185966960","n185966962"]},"w203972938":{"id":"w203972938","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139858964","n2139858965","n2139858963","n2139858962","n2139858961","n2139858960","n2139858959","n2139858958","n2139858957","n2139858956","n2139858955","n2139858954","n2139858953","n2139858952","n2139858951"]},"n354002665":{"id":"n354002665","loc":[-85.6366599,41.9444923],"tags":{"name":"Memory Isle","place":"island"}},"n354031301":{"id":"n354031301","loc":[-85.635,41.9463889],"tags":{"amenity":"post_office","name":"Three Rivers Post Office"}},"n185963454":{"id":"n185963454","loc":[-85.633686,41.946072]},"n185963455":{"id":"n185963455","loc":[-85.633815,41.946131]},"n185963456":{"id":"n185963456","loc":[-85.633951,41.946174]},"n185978375":{"id":"n185978375","loc":[-85.634385,41.94559]},"n185978377":{"id":"n185978377","loc":[-85.634544,41.945725]},"n185978379":{"id":"n185978379","loc":[-85.634573,41.945764]},"n185978381":{"id":"n185978381","loc":[-85.634616,41.945849]},"n185978383":{"id":"n185978383","loc":[-85.634629,41.945893]},"n185984011":{"id":"n185984011","loc":[-85.636058,41.946201]},"n185984013":{"id":"n185984013","loc":[-85.636112,41.946366]},"n185984015":{"id":"n185984015","loc":[-85.636143,41.946551]},"n185988237":{"id":"n185988237","loc":[-85.6354162,41.946044]},"n185988969":{"id":"n185988969","loc":[-85.635374,41.945325]},"n185988971":{"id":"n185988971","loc":[-85.635643,41.945585]},"n185988972":{"id":"n185988972","loc":[-85.635853,41.94586]},"n1475283992":{"id":"n1475283992","loc":[-85.6372968,41.9459007]},"n1475284011":{"id":"n1475284011","loc":[-85.6359415,41.9459797]},"n1475284019":{"id":"n1475284019","loc":[-85.6364433,41.9460423]},"n185984009":{"id":"n185984009","loc":[-85.6360524,41.9460485]},"n185988239":{"id":"n185988239","loc":[-85.6358187,41.9460423]},"n185988243":{"id":"n185988243","loc":[-85.6366156,41.9460282]},"n185988244":{"id":"n185988244","loc":[-85.6368316,41.9460046]},"n185988245":{"id":"n185988245","loc":[-85.6370133,41.9459704]},"n185988241":{"id":"n185988241","loc":[-85.636291,41.9460461]},"n185964976":{"id":"n185964976","loc":[-85.633923,41.9434157]},"n185964980":{"id":"n185964980","loc":[-85.6333656,41.9437293]},"n185978388":{"id":"n185978388","loc":[-85.6346449,41.9460571]},"n1819858504":{"id":"n1819858504","loc":[-85.6365343,41.9447926]},"n1819858506":{"id":"n1819858506","loc":[-85.6370546,41.9451882]},"n1819858516":{"id":"n1819858516","loc":[-85.6358369,41.9444654]},"n1819858519":{"id":"n1819858519","loc":[-85.6361534,41.9446176]},"n1819858525":{"id":"n1819858525","loc":[-85.6368025,41.9449442]},"n1819858527":{"id":"n1819858527","loc":[-85.6334199,41.9457495]},"n185963452":{"id":"n185963452","loc":[-85.633564,41.9458519]},"n185963453":{"id":"n185963453","loc":[-85.6336152,41.9459804]},"n185963451":{"id":"n185963451","loc":[-85.6332888,41.9456871]},"n2130304152":{"id":"n2130304152","loc":[-85.6359466,41.9454599]},"n2130304153":{"id":"n2130304153","loc":[-85.6362773,41.9452683]},"n2130304154":{"id":"n2130304154","loc":[-85.6352028,41.9442868]},"n2130304155":{"id":"n2130304155","loc":[-85.6348756,41.9444769]},"n2130304156":{"id":"n2130304156","loc":[-85.6349723,41.9444207]},"n2130304157":{"id":"n2130304157","loc":[-85.6338698,41.9434443]},"n2130304158":{"id":"n2130304158","loc":[-85.635094,41.9451026]},"n2130304160":{"id":"n2130304160","loc":[-85.6353716,41.9449322]},"n2130304162":{"id":"n2130304162","loc":[-85.6365942,41.9459352]},"n2130304163":{"id":"n2130304163","loc":[-85.6369006,41.9457469]},"n2130304164":{"id":"n2130304164","loc":[-85.6363292,41.9452278]},"n2130304165":{"id":"n2130304165","loc":[-85.6360248,41.9454175]},"n2139824683":{"id":"n2139824683","loc":[-85.6339825,41.9446441]},"n2139824689":{"id":"n2139824689","loc":[-85.6340437,41.9446925]},"n2139824702":{"id":"n2139824702","loc":[-85.6340961,41.9447551]},"n2139824705":{"id":"n2139824705","loc":[-85.6337467,41.944809]},"n2139824707":{"id":"n2139824707","loc":[-85.6341598,41.9448129]},"n2139824710":{"id":"n2139824710","loc":[-85.6342771,41.9448223]},"n2139824712":{"id":"n2139824712","loc":[-85.6346058,41.944841]},"n2139824713":{"id":"n2139824713","loc":[-85.633808,41.9448574]},"n2139824714":{"id":"n2139824714","loc":[-85.6340889,41.9448589]},"n2139824716":{"id":"n2139824716","loc":[-85.6343335,41.944871]},"n2139824717":{"id":"n2139824717","loc":[-85.6343341,41.9448717]},"n2139824720":{"id":"n2139824720","loc":[-85.6338757,41.9449069]},"n2139824721":{"id":"n2139824721","loc":[-85.6341445,41.9449071]},"n2139824724":{"id":"n2139824724","loc":[-85.6334787,41.9449262]},"n2139824726":{"id":"n2139824726","loc":[-85.6347119,41.9449332]},"n2139824727":{"id":"n2139824727","loc":[-85.6347175,41.9449418]},"n2139824728":{"id":"n2139824728","loc":[-85.6344284,41.9449538]},"n2139824729":{"id":"n2139824729","loc":[-85.6339339,41.9449573]},"n2139824730":{"id":"n2139824730","loc":[-85.6339179,41.9449682]},"n2139824732":{"id":"n2139824732","loc":[-85.6335472,41.9449895]},"n2139824733":{"id":"n2139824733","loc":[-85.6339736,41.9450164]},"n2139824735":{"id":"n2139824735","loc":[-85.6336034,41.9450415]},"n2139824736":{"id":"n2139824736","loc":[-85.6348317,41.945043]},"n2139824737":{"id":"n2139824737","loc":[-85.63403,41.9450651]},"n2139824738":{"id":"n2139824738","loc":[-85.6336611,41.9450949]},"n2139824740":{"id":"n2139824740","loc":[-85.6336582,41.9450966]},"n2139824744":{"id":"n2139824744","loc":[-85.6331702,41.9451107]},"n2139824745":{"id":"n2139824745","loc":[-85.6333388,41.9451142]},"n2139824746":{"id":"n2139824746","loc":[-85.6337131,41.9451341]},"n2139824747":{"id":"n2139824747","loc":[-85.6337021,41.9451372]},"n2139824748":{"id":"n2139824748","loc":[-85.6341244,41.9451472]},"n2139824749":{"id":"n2139824749","loc":[-85.6333952,41.945166]},"n2139824750":{"id":"n2139824750","loc":[-85.633395,41.9451661]},"n2139824751":{"id":"n2139824751","loc":[-85.6346258,41.9451725]},"n2139824752":{"id":"n2139824752","loc":[-85.6332387,41.9451741]},"n2139824753":{"id":"n2139824753","loc":[-85.6346901,41.9451853]},"n2139824754":{"id":"n2139824754","loc":[-85.6346611,41.9452035]},"n2139824755":{"id":"n2139824755","loc":[-85.6346574,41.9452059]},"n2139824756":{"id":"n2139824756","loc":[-85.6345611,41.9452133]},"n2139824757":{"id":"n2139824757","loc":[-85.633453,41.9452194]},"n2139824758":{"id":"n2139824758","loc":[-85.6335508,41.9452283]},"n2139824759":{"id":"n2139824759","loc":[-85.6347424,41.9452312]},"n2139824760":{"id":"n2139824760","loc":[-85.6342305,41.9452395]},"n2139824761":{"id":"n2139824761","loc":[-85.6342319,41.9452449]},"n2139824762":{"id":"n2139824762","loc":[-85.6334969,41.94526]},"n2139824763":{"id":"n2139824763","loc":[-85.63468,41.9452706]},"n2139824764":{"id":"n2139824764","loc":[-85.6346772,41.9452724]},"n2139824765":{"id":"n2139824765","loc":[-85.6338611,41.9452763]},"n2139824766":{"id":"n2139824766","loc":[-85.6347811,41.9452939]},"n2139824767":{"id":"n2139824767","loc":[-85.6347375,41.9453211]},"n2139824768":{"id":"n2139824768","loc":[-85.6339171,41.9453301]},"n2139824769":{"id":"n2139824769","loc":[-85.6348307,41.9453377]},"n2139824770":{"id":"n2139824770","loc":[-85.6347067,41.9453405]},"n2139824771":{"id":"n2139824771","loc":[-85.6343461,41.9453461]},"n2139824772":{"id":"n2139824772","loc":[-85.6343481,41.9453475]},"n2139824773":{"id":"n2139824773","loc":[-85.634805,41.9453538]},"n2139824774":{"id":"n2139824774","loc":[-85.6336997,41.9453692]},"n2139824775":{"id":"n2139824775","loc":[-85.6339709,41.9453818]},"n2139824776":{"id":"n2139824776","loc":[-85.6336229,41.9454134]},"n2139824777":{"id":"n2139824777","loc":[-85.6349022,41.9454141]},"n2139824778":{"id":"n2139824778","loc":[-85.6348854,41.9454246]},"n2139824779":{"id":"n2139824779","loc":[-85.6340286,41.9454373]},"n2139824780":{"id":"n2139824780","loc":[-85.6336963,41.9454572]},"n2139824781":{"id":"n2139824781","loc":[-85.6336789,41.9454672]},"n2139824782":{"id":"n2139824782","loc":[-85.6344933,41.945475]},"n2139824783":{"id":"n2139824783","loc":[-85.6340854,41.9454918]},"n2139824784":{"id":"n2139824784","loc":[-85.6350036,41.9455034]},"n2139824785":{"id":"n2139824785","loc":[-85.6337501,41.9455089]},"n2139824786":{"id":"n2139824786","loc":[-85.6337497,41.9455091]},"n2139824787":{"id":"n2139824787","loc":[-85.6345425,41.9455186]},"n2139824788":{"id":"n2139824788","loc":[-85.6341459,41.9455372]},"n2139824789":{"id":"n2139824789","loc":[-85.6341376,41.945542]},"n2139824790":{"id":"n2139824790","loc":[-85.6338394,41.9455462]},"n2139824791":{"id":"n2139824791","loc":[-85.6349171,41.9455588]},"n2139824792":{"id":"n2139824792","loc":[-85.6338074,41.9455646]},"n2139824793":{"id":"n2139824793","loc":[-85.6346229,41.9455894]},"n2139824794":{"id":"n2139824794","loc":[-85.6338983,41.9455995]},"n2139824795":{"id":"n2139824795","loc":[-85.6338962,41.9456007]},"n2139824796":{"id":"n2139824796","loc":[-85.6342475,41.9456348]},"n2139824797":{"id":"n2139824797","loc":[-85.6339505,41.9456497]},"n2139824798":{"id":"n2139824798","loc":[-85.6347243,41.9456788]},"n2139824799":{"id":"n2139824799","loc":[-85.635057,41.9456831]},"n2139824800":{"id":"n2139824800","loc":[-85.635287,41.9457056]},"n2139824801":{"id":"n2139824801","loc":[-85.6350753,41.9457068]},"n2139824802":{"id":"n2139824802","loc":[-85.6347753,41.9457252]},"n2139824803":{"id":"n2139824803","loc":[-85.6340521,41.9457473]},"n2139824804":{"id":"n2139824804","loc":[-85.6352875,41.9457611]},"n2139824805":{"id":"n2139824805","loc":[-85.6352941,41.9457611]},"n2139824806":{"id":"n2139824806","loc":[-85.6350758,41.9457623]},"n2139824807":{"id":"n2139824807","loc":[-85.6348194,41.9457638]},"n2139824808":{"id":"n2139824808","loc":[-85.635296,41.9459428]},"n2139824809":{"id":"n2139824809","loc":[-85.6348212,41.9459455]},"n2139832635":{"id":"n2139832635","loc":[-85.6354612,41.9448791]},"n2139832636":{"id":"n2139832636","loc":[-85.6360241,41.9453844]},"n2139832637":{"id":"n2139832637","loc":[-85.6361452,41.9453121]},"n2139832639":{"id":"n2139832639","loc":[-85.6355997,41.944797]},"n2139832641":{"id":"n2139832641","loc":[-85.6351346,41.9443541]},"n2139832647":{"id":"n2139832647","loc":[-85.6329883,41.9453692]},"n2139832653":{"id":"n2139832653","loc":[-85.6333643,41.9456293]},"n2139832663":{"id":"n2139832663","loc":[-85.6335394,41.9455339]},"n2139832665":{"id":"n2139832665","loc":[-85.6332375,41.9452476]},"n2139832667":{"id":"n2139832667","loc":[-85.6331664,41.9452161]},"n2139832669":{"id":"n2139832669","loc":[-85.6331144,41.9451875]},"n2139832671":{"id":"n2139832671","loc":[-85.6330779,41.9451274]},"n2139832673":{"id":"n2139832673","loc":[-85.6330664,41.9450802]},"n2139832678":{"id":"n2139832678","loc":[-85.6332218,41.9453585]},"n2139832686":{"id":"n2139832686","loc":[-85.6334246,41.945541]},"n2139832691":{"id":"n2139832691","loc":[-85.6329898,41.9454997]},"n2139832693":{"id":"n2139832693","loc":[-85.6343554,41.9443274]},"n2139832694":{"id":"n2139832694","loc":[-85.6336339,41.9437089]},"n2139832696":{"id":"n2139832696","loc":[-85.633532,41.9437708]},"n2139832697":{"id":"n2139832697","loc":[-85.6338316,41.9440868]},"n2139832698":{"id":"n2139832698","loc":[-85.6342258,41.9444141]},"n2139832699":{"id":"n2139832699","loc":[-85.6339164,41.9442166]},"n2139832700":{"id":"n2139832700","loc":[-85.6341389,41.944384]},"n2139832701":{"id":"n2139832701","loc":[-85.634235,41.9443259]},"n2139832702":{"id":"n2139832702","loc":[-85.633613,41.9437875]},"n2139832703":{"id":"n2139832703","loc":[-85.633915,41.9436132]},"n2139832704":{"id":"n2139832704","loc":[-85.6340019,41.9435613]},"n2139832706":{"id":"n2139832706","loc":[-85.6343197,41.9438427]},"n2139832708":{"id":"n2139832708","loc":[-85.6342361,41.9438936]},"n2139832709":{"id":"n2139832709","loc":[-85.6353839,41.9460401]},"n2139832710":{"id":"n2139832710","loc":[-85.6354032,41.9456763]},"n2139832711":{"id":"n2139832711","loc":[-85.6356839,41.9459252]},"n2139832712":{"id":"n2139832712","loc":[-85.6356109,41.945735]},"n2139832713":{"id":"n2139832713","loc":[-85.6353997,41.9457421]},"n2139832714":{"id":"n2139832714","loc":[-85.6353895,41.9459347]},"n2139832715":{"id":"n2139832715","loc":[-85.6334777,41.9436628]},"n2139832716":{"id":"n2139832716","loc":[-85.6333137,41.9435382]},"n2139832717":{"id":"n2139832717","loc":[-85.6330938,41.9435406]},"n2139832721":{"id":"n2139832721","loc":[-85.6333023,41.9434922]},"n2139832722":{"id":"n2139832722","loc":[-85.6330466,41.943623]},"n2139832723":{"id":"n2139832723","loc":[-85.6332746,41.9435624]},"n2139832724":{"id":"n2139832724","loc":[-85.6333511,41.9435176]},"n2139832725":{"id":"n2139832725","loc":[-85.6332241,41.9434001]},"n2139832726":{"id":"n2139832726","loc":[-85.6332355,41.9433686]},"n2139870373":{"id":"n2139870373","loc":[-85.6351783,41.9439117]},"n2139870374":{"id":"n2139870374","loc":[-85.6351431,41.9439217]},"n2139870375":{"id":"n2139870375","loc":[-85.6348853,41.9439117]},"n2139870376":{"id":"n2139870376","loc":[-85.6348317,41.9439105]},"n2139870377":{"id":"n2139870377","loc":[-85.6346384,41.944007]},"n2139870378":{"id":"n2139870378","loc":[-85.6345563,41.9440523]},"n2140006403":{"id":"n2140006403","loc":[-85.6359942,41.9450097]},"n2140006405":{"id":"n2140006405","loc":[-85.6363884,41.9446079]},"n2140006407":{"id":"n2140006407","loc":[-85.6362148,41.9447874]},"n2140006409":{"id":"n2140006409","loc":[-85.6379476,41.9445869]},"n2140006411":{"id":"n2140006411","loc":[-85.6378485,41.9445674]},"n2140006413":{"id":"n2140006413","loc":[-85.6378952,41.9444547]},"n2140006415":{"id":"n2140006415","loc":[-85.6379962,41.944477]},"n2140006421":{"id":"n2140006421","loc":[-85.6355248,41.9433702]},"n2140006423":{"id":"n2140006423","loc":[-85.6378471,41.9439233]},"n2140006425":{"id":"n2140006425","loc":[-85.6378913,41.9441238]},"n2140006426":{"id":"n2140006426","loc":[-85.6381674,41.9442289]},"n2140006427":{"id":"n2140006427","loc":[-85.6382359,41.9440975]},"n2140006428":{"id":"n2140006428","loc":[-85.6382071,41.9440252]},"n2140006429":{"id":"n2140006429","loc":[-85.6381409,41.9439973]},"n2140006430":{"id":"n2140006430","loc":[-85.6380569,41.9440153]},"n2140006433":{"id":"n2140006433","loc":[-85.6379071,41.9442467]},"n2140006435":{"id":"n2140006435","loc":[-85.6381634,41.9443125]},"n2140006436":{"id":"n2140006436","loc":[-85.6382407,41.944301]},"n2140006438":{"id":"n2140006438","loc":[-85.6382761,41.9442188]},"n2140006439":{"id":"n2140006439","loc":[-85.6382429,41.9441761]},"n2140006440":{"id":"n2140006440","loc":[-85.6382016,41.9441632]},"n2140006441":{"id":"n2140006441","loc":[-85.6378185,41.9439835]},"n2166205688":{"id":"n2166205688","loc":[-85.6349963,41.9444392]},"n2168544780":{"id":"n2168544780","loc":[-85.633944,41.945807]},"n2168544781":{"id":"n2168544781","loc":[-85.6340783,41.9458621]},"n2168544782":{"id":"n2168544782","loc":[-85.6338184,41.9457548]},"n2168544783":{"id":"n2168544783","loc":[-85.6339925,41.9459777]},"n2168544784":{"id":"n2168544784","loc":[-85.6337317,41.9458698]},"n2168544785":{"id":"n2168544785","loc":[-85.6337297,41.9460042]},"n2168544786":{"id":"n2168544786","loc":[-85.633919,41.9460797]},"n2168544787":{"id":"n2168544787","loc":[-85.6338672,41.9459263]},"n2168544788":{"id":"n2168544788","loc":[-85.6338246,41.9459853]},"n2168544789":{"id":"n2168544789","loc":[-85.6337615,41.9459601]},"n2168544790":{"id":"n2168544790","loc":[-85.6342079,41.9460399]},"n2168544791":{"id":"n2168544791","loc":[-85.6343346,41.9458503]},"n2168544792":{"id":"n2168544792","loc":[-85.6343759,41.9458116]},"n2168544793":{"id":"n2168544793","loc":[-85.6344394,41.9458109]},"n2168544795":{"id":"n2168544795","loc":[-85.6344827,41.945851]},"n2168544797":{"id":"n2168544797","loc":[-85.6344807,41.945969]},"n2168544798":{"id":"n2168544798","loc":[-85.6344404,41.9459697]},"n2168544799":{"id":"n2168544799","loc":[-85.6344413,41.9460333]},"n2168544800":{"id":"n2168544800","loc":[-85.6342173,41.9460705]},"n2168544801":{"id":"n2168544801","loc":[-85.6342162,41.9460392]},"n2168544802":{"id":"n2168544802","loc":[-85.6344251,41.9460351]},"n2168544805":{"id":"n2168544805","loc":[-85.6344257,41.9460507]},"n2168544807":{"id":"n2168544807","loc":[-85.6344721,41.9460498]},"n2168544809":{"id":"n2168544809","loc":[-85.6344754,41.9461427]},"n2168544811":{"id":"n2168544811","loc":[-85.6344311,41.9461435]},"n2168544813":{"id":"n2168544813","loc":[-85.6344317,41.9461592]},"n2168544815":{"id":"n2168544815","loc":[-85.6343708,41.9461604]},"n2168544817":{"id":"n2168544817","loc":[-85.6343715,41.9461786]},"n2168544819":{"id":"n2168544819","loc":[-85.6343229,41.9461795]},"n2168544821":{"id":"n2168544821","loc":[-85.6343222,41.9461606]},"n2168544823":{"id":"n2168544823","loc":[-85.6342476,41.9461621]},"n2168544825":{"id":"n2168544825","loc":[-85.6342444,41.94607]},"n2168544827":{"id":"n2168544827","loc":[-85.634138,41.9461632]},"n2168544829":{"id":"n2168544829","loc":[-85.6342016,41.9460703]},"n2168544830":{"id":"n2168544830","loc":[-85.6332929,41.9463092]},"n2168544831":{"id":"n2168544831","loc":[-85.633122,41.946239]},"n2168544832":{"id":"n2168544832","loc":[-85.6332954,41.9460055]},"n2168544833":{"id":"n2168544833","loc":[-85.6333954,41.9460466]},"n2168544834":{"id":"n2168544834","loc":[-85.6334044,41.9460345]},"n2168544835":{"id":"n2168544835","loc":[-85.6334594,41.9460571]},"n2168544836":{"id":"n2168544836","loc":[-85.6333871,41.9461544]},"n2168544837":{"id":"n2168544837","loc":[-85.633403,41.9461609]},"n2168544838":{"id":"n2168544838","loc":[-85.6341683,41.9464167]},"n2168544839":{"id":"n2168544839","loc":[-85.6341711,41.9463411]},"n2168544840":{"id":"n2168544840","loc":[-85.6344471,41.9463469]},"n2168544841":{"id":"n2168544841","loc":[-85.6344441,41.9464243]},"n2168544842":{"id":"n2168544842","loc":[-85.6343622,41.9464226]},"n2168544843":{"id":"n2168544843","loc":[-85.6343593,41.9464989]},"n2168544844":{"id":"n2168544844","loc":[-85.6342812,41.9464973]},"n2168544845":{"id":"n2168544845","loc":[-85.634283,41.9464504]},"n2168544846":{"id":"n2168544846","loc":[-85.6342609,41.9464499]},"n2168544847":{"id":"n2168544847","loc":[-85.6342621,41.9464187]},"n2168544848":{"id":"n2168544848","loc":[-85.6348414,41.9463396]},"n2168544849":{"id":"n2168544849","loc":[-85.6348387,41.9461872]},"n2168544850":{"id":"n2168544850","loc":[-85.6351186,41.9461844]},"n2168544851":{"id":"n2168544851","loc":[-85.635119,41.9462112]},"n2168544852":{"id":"n2168544852","loc":[-85.6351918,41.9462104]},"n2168544853":{"id":"n2168544853","loc":[-85.6351944,41.9463515]},"n2168544854":{"id":"n2168544854","loc":[-85.6351049,41.9463524]},"n2168544855":{"id":"n2168544855","loc":[-85.6351046,41.946337]},"n2189153180":{"id":"n2189153180","loc":[-85.6340369,41.9469572]},"n2189153181":{"id":"n2189153181","loc":[-85.6342531,41.946953]},"n2189153183":{"id":"n2189153183","loc":[-85.6348115,41.9465468]},"n2189153184":{"id":"n2189153184","loc":[-85.6348105,41.9464569]},"n2189153185":{"id":"n2189153185","loc":[-85.6351431,41.9464549]},"n2189153186":{"id":"n2189153186","loc":[-85.6351441,41.9465448]},"n2189153187":{"id":"n2189153187","loc":[-85.6350077,41.9465456]},"n2189153188":{"id":"n2189153188","loc":[-85.635008,41.9465721]},"n2189153189":{"id":"n2189153189","loc":[-85.6348965,41.9465727]},"n2189153190":{"id":"n2189153190","loc":[-85.6348962,41.9465463]},"n2189153191":{"id":"n2189153191","loc":[-85.6348963,41.9471586]},"n2189153192":{"id":"n2189153192","loc":[-85.6348944,41.947032]},"n2189153193":{"id":"n2189153193","loc":[-85.6350241,41.947031]},"n2189153194":{"id":"n2189153194","loc":[-85.635026,41.9471575]},"n2189153195":{"id":"n2189153195","loc":[-85.6352328,41.9471053]},"n2189153196":{"id":"n2189153196","loc":[-85.6352359,41.9469906]},"n2189153197":{"id":"n2189153197","loc":[-85.6353694,41.9469925]},"n2189153198":{"id":"n2189153198","loc":[-85.6353664,41.9471072]},"n2189153199":{"id":"n2189153199","loc":[-85.6348241,41.9469287]},"n2189153200":{"id":"n2189153200","loc":[-85.6348248,41.9468185]},"n2189153201":{"id":"n2189153201","loc":[-85.6351199,41.9468195]},"n2189153202":{"id":"n2189153202","loc":[-85.6351192,41.9469298]},"n2189153203":{"id":"n2189153203","loc":[-85.6347965,41.9468057]},"n2189153204":{"id":"n2189153204","loc":[-85.634792,41.9466044]},"n2189153205":{"id":"n2189153205","loc":[-85.6349483,41.9466025]},"n2189153206":{"id":"n2189153206","loc":[-85.6349493,41.9466448]},"n2189153207":{"id":"n2189153207","loc":[-85.6349753,41.9466445]},"n2189153208":{"id":"n2189153208","loc":[-85.6349743,41.9465995]},"n2189153209":{"id":"n2189153209","loc":[-85.6351173,41.9465977]},"n2189153210":{"id":"n2189153210","loc":[-85.6351219,41.9468015]},"n2189153211":{"id":"n2189153211","loc":[-85.6349806,41.9468032]},"n2189153212":{"id":"n2189153212","loc":[-85.6349794,41.9467519]},"n2189153213":{"id":"n2189153213","loc":[-85.6349521,41.9467523]},"n2189153214":{"id":"n2189153214","loc":[-85.6349532,41.9468037]},"n2189153215":{"id":"n2189153215","loc":[-85.6346302,41.9468381]},"n2189153216":{"id":"n2189153216","loc":[-85.6343028,41.9468449]},"n2189153217":{"id":"n2189153217","loc":[-85.6342006,41.9468297]},"n2189153218":{"id":"n2189153218","loc":[-85.6336698,41.9465918]},"n2189153219":{"id":"n2189153219","loc":[-85.6344663,41.9466639]},"n2189153220":{"id":"n2189153220","loc":[-85.6344639,41.9466015]},"n2189153221":{"id":"n2189153221","loc":[-85.6342283,41.9466065]},"n2189153222":{"id":"n2189153222","loc":[-85.6342303,41.9466587]},"n2189153223":{"id":"n2189153223","loc":[-85.6342843,41.9466575]},"n2189153224":{"id":"n2189153224","loc":[-85.6342851,41.9466794]},"n2189153225":{"id":"n2189153225","loc":[-85.6343475,41.9466781]},"n2189153226":{"id":"n2189153226","loc":[-85.634347,41.9466664]},"n2189153227":{"id":"n2189153227","loc":[-85.6354428,41.9470148]},"n2189153228":{"id":"n2189153228","loc":[-85.6354432,41.9468005]},"n2189153229":{"id":"n2189153229","loc":[-85.6360277,41.9468011]},"n2189153230":{"id":"n2189153230","loc":[-85.6360273,41.9470154]},"n2189153231":{"id":"n2189153231","loc":[-85.6354565,41.9465823]},"n2189153232":{"id":"n2189153232","loc":[-85.6354496,41.946218]},"n2189153233":{"id":"n2189153233","loc":[-85.6356355,41.9465788]},"n2189153234":{"id":"n2189153234","loc":[-85.6357155,41.9468008]},"n2189153235":{"id":"n2189153235","loc":[-85.6359539,41.9467969]},"n2189153236":{"id":"n2189153236","loc":[-85.6359561,41.9463036]},"n2189153237":{"id":"n2189153237","loc":[-85.6360129,41.9464793]},"n2189153238":{"id":"n2189153238","loc":[-85.6360152,41.9463898]},"n2189153239":{"id":"n2189153239","loc":[-85.6359607,41.9464928]},"n2189153240":{"id":"n2189153240","loc":[-85.6356903,41.9462227]},"n2189153242":{"id":"n2189153242","loc":[-85.6354163,41.946142]},"n2189153243":{"id":"n2189153243","loc":[-85.6357546,41.9462214]},"n2189153244":{"id":"n2189153244","loc":[-85.6357937,41.9462542]},"n2189153245":{"id":"n2189153245","loc":[-85.6358723,41.9467048]},"n2189153246":{"id":"n2189153246","loc":[-85.6361494,41.946757]},"n2189153247":{"id":"n2189153247","loc":[-85.6354173,41.9469082]},"n2189153248":{"id":"n2189153248","loc":[-85.635443,41.9469079]},"n2189153249":{"id":"n2189153249","loc":[-85.6360275,41.9469093]},"n2189153250":{"id":"n2189153250","loc":[-85.6361542,41.946915]},"n2189153251":{"id":"n2189153251","loc":[-85.6358654,41.9464843]},"n2189153252":{"id":"n2189153252","loc":[-85.6359549,41.9467499]},"n2189153253":{"id":"n2189153253","loc":[-85.6357172,41.9466335]},"n2189153254":{"id":"n2189153254","loc":[-85.6355644,41.9461768]},"n2189153255":{"id":"n2189153255","loc":[-85.6355655,41.946528]},"n2189153256":{"id":"n2189153256","loc":[-85.6357055,41.9465971]},"n2189153257":{"id":"n2189153257","loc":[-85.635869,41.9465971]},"n2189153259":{"id":"n2189153259","loc":[-85.6354561,41.9470278]},"n2189153260":{"id":"n2189153260","loc":[-85.6357961,41.9470233]},"n2189153261":{"id":"n2189153261","loc":[-85.6357977,41.9470907]},"n2189153262":{"id":"n2189153262","loc":[-85.6357297,41.9470916]},"n2189153263":{"id":"n2189153263","loc":[-85.635733,41.947233]},"n2189153264":{"id":"n2189153264","loc":[-85.6362674,41.9468637]},"n2189153265":{"id":"n2189153265","loc":[-85.6362646,41.9467047]},"n2189153266":{"id":"n2189153266","loc":[-85.6363267,41.9467047]},"n2189153267":{"id":"n2189153267","loc":[-85.6362633,41.9465848]},"n2189153268":{"id":"n2189153268","loc":[-85.6363805,41.9465468]},"n2189153269":{"id":"n2189153269","loc":[-85.6364604,41.9466842]},"n2189153270":{"id":"n2189153270","loc":[-85.6364604,41.9468647]},"n2199109756":{"id":"n2199109756","loc":[-85.6337134,41.9471841]},"n2199109757":{"id":"n2199109757","loc":[-85.6336514,41.94716]},"n2199109758":{"id":"n2199109758","loc":[-85.6337043,41.9470847]},"n2199109759":{"id":"n2199109759","loc":[-85.6335997,41.9470441]},"n2199109760":{"id":"n2199109760","loc":[-85.6335064,41.9471771]},"n185960195":{"id":"n185960195","loc":[-85.6295992,41.9524346]},"n185960796":{"id":"n185960796","loc":[-85.634723,41.953681]},"n185961396":{"id":"n185961396","loc":[-85.634767,41.959009]},"n185962625":{"id":"n185962625","loc":[-85.635175,41.97201]},"n185964982":{"id":"n185964982","loc":[-85.632799,41.9440543]},"n185965289":{"id":"n185965289","loc":[-85.634621,41.947323]},"n185965291":{"id":"n185965291","loc":[-85.636166,41.947296]},"n185965399":{"id":"n185965399","loc":[-85.634776,41.959834]},"n185966937":{"id":"n185966937","loc":[-85.633183,41.947315]},"n185966948":{"id":"n185966948","loc":[-85.626406,41.957188]},"n185967422":{"id":"n185967422","loc":[-85.6320229,41.9490123]},"n185967917":{"id":"n185967917","loc":[-85.634763,41.958292]},"n185967918":{"id":"n185967918","loc":[-85.636271,41.958311]},"n185968100":{"id":"n185968100","loc":[-85.630835,41.950656]},"n185970515":{"id":"n185970515","loc":[-85.634832,41.963866]},"n185971578":{"id":"n185971578","loc":[-85.634641,41.948627]},"n185971580":{"id":"n185971580","loc":[-85.6361818,41.9486135]},"n185971631":{"id":"n185971631","loc":[-85.634729,41.954667]},"n185971632":{"id":"n185971632","loc":[-85.636236,41.954656]},"n185972155":{"id":"n185972155","loc":[-85.623333,41.961987]},"n185974583":{"id":"n185974583","loc":[-85.634686,41.951158]},"n185974585":{"id":"n185974585","loc":[-85.6362059,41.9511457]},"n185975064":{"id":"n185975064","loc":[-85.636218,41.953667]},"n185975735":{"id":"n185975735","loc":[-85.634923,41.969269]},"n185978390":{"id":"n185978390","loc":[-85.634668,41.949875]},"n185978392":{"id":"n185978392","loc":[-85.634686,41.952415]},"n185978394":{"id":"n185978394","loc":[-85.634726,41.955921]},"n185978399":{"id":"n185978399","loc":[-85.6347861,41.9606613]},"n185978402":{"id":"n185978402","loc":[-85.634806,41.961485]},"n185978406":{"id":"n185978406","loc":[-85.6348298,41.964783]},"n185978410":{"id":"n185978410","loc":[-85.6348766,41.9677088]},"n185978414":{"id":"n185978414","loc":[-85.634938,41.971566]},"n185978415":{"id":"n185978415","loc":[-85.634942,41.971611]},"n185978417":{"id":"n185978417","loc":[-85.634952,41.971655]},"n185978419":{"id":"n185978419","loc":[-85.634989,41.971741]},"n185978420":{"id":"n185978420","loc":[-85.635063,41.971864]},"n185978787":{"id":"n185978787","loc":[-85.627936,41.954693]},"n185978790":{"id":"n185978790","loc":[-85.626832,41.954677]},"n185978967":{"id":"n185978967","loc":[-85.632278,41.948613]},"n185980735":{"id":"n185980735","loc":[-85.628639,41.953725]},"n185982163":{"id":"n185982163","loc":[-85.636233,41.952398]},"n185982193":{"id":"n185982193","loc":[-85.6313855,41.9499125]},"n185982195":{"id":"n185982195","loc":[-85.6304857,41.9511945]},"n185982196":{"id":"n185982196","loc":[-85.626336,41.957291]},"n185982197":{"id":"n185982197","loc":[-85.625578,41.958664]},"n185982198":{"id":"n185982198","loc":[-85.624619,41.960145]},"n185982200":{"id":"n185982200","loc":[-85.624494,41.960338]},"n185984017":{"id":"n185984017","loc":[-85.636163,41.947382]},"n185984020":{"id":"n185984020","loc":[-85.636188,41.9498803]},"n185984022":{"id":"n185984022","loc":[-85.636276,41.955919]},"n185984024":{"id":"n185984024","loc":[-85.636279,41.956901]},"n185988036":{"id":"n185988036","loc":[-85.631422,41.948294]},"n185988867":{"id":"n185988867","loc":[-85.63102,41.948805]},"n185988869":{"id":"n185988869","loc":[-85.630773,41.949209]},"n185988871":{"id":"n185988871","loc":[-85.63005,41.95016]},"n185988872":{"id":"n185988872","loc":[-85.629423,41.951016]},"n185988873":{"id":"n185988873","loc":[-85.629252,41.951256]},"n185988875":{"id":"n185988875","loc":[-85.629126,41.951489]},"n185988877":{"id":"n185988877","loc":[-85.628991,41.951704]},"n185988878":{"id":"n185988878","loc":[-85.628689,41.952112]},"n185988879":{"id":"n185988879","loc":[-85.628313,41.952666]},"n185988880":{"id":"n185988880","loc":[-85.627687,41.953529]},"n185988882":{"id":"n185988882","loc":[-85.627394,41.953947]},"n185988884":{"id":"n185988884","loc":[-85.627287,41.954128]},"n1819858502":{"id":"n1819858502","loc":[-85.6328435,41.9455473]},"n1819858510":{"id":"n1819858510","loc":[-85.6324841,41.9453438]},"n1819858515":{"id":"n1819858515","loc":[-85.6318511,41.9446409]},"n1819858520":{"id":"n1819858520","loc":[-85.6326558,41.9454708]},"n1819858522":{"id":"n1819858522","loc":[-85.6319048,41.9447407]},"n1819858524":{"id":"n1819858524","loc":[-85.6317718,41.9443666]},"n1819858530":{"id":"n1819858530","loc":[-85.632055,41.9449128]},"n2139795768":{"id":"n2139795768","loc":[-85.6243023,41.9606102]},"n2139832645":{"id":"n2139832645","loc":[-85.6324455,41.9448607]},"n2139832649":{"id":"n2139832649","loc":[-85.6328043,41.9454773]},"n2139832651":{"id":"n2139832651","loc":[-85.6322547,41.9449621]},"n2139832675":{"id":"n2139832675","loc":[-85.6327356,41.944757]},"n2139832677":{"id":"n2139832677","loc":[-85.6325433,41.9448599]},"n2139832680":{"id":"n2139832680","loc":[-85.6328885,41.9455614]},"n2139832682":{"id":"n2139832682","loc":[-85.6320913,41.9449492]},"n2139832684":{"id":"n2139832684","loc":[-85.6325366,41.9447133]},"n2139832688":{"id":"n2139832688","loc":[-85.6322786,41.94485]},"n2139832718":{"id":"n2139832718","loc":[-85.6327486,41.9432475]},"n2139832719":{"id":"n2139832719","loc":[-85.6327926,41.9431773]},"n2139832720":{"id":"n2139832720","loc":[-85.6329033,41.943153]},"n2139832727":{"id":"n2139832727","loc":[-85.6328975,41.9430783]},"n2139844839":{"id":"n2139844839","loc":[-85.6326261,41.9432308]},"n2189015992":{"id":"n2189015992","loc":[-85.6347706,41.9593383]},"n2189153179":{"id":"n2189153179","loc":[-85.6340476,41.9472565]},"n2189153182":{"id":"n2189153182","loc":[-85.6342638,41.9472522]},"n2189153241":{"id":"n2189153241","loc":[-85.6354184,41.9473091]},"n2189153258":{"id":"n2189153258","loc":[-85.6354611,41.9472366]},"n2189153277":{"id":"n2189153277","loc":[-85.6328948,41.9462374]},"n2199109755":{"id":"n2199109755","loc":[-85.6336729,41.9472417]},"w203970139":{"id":"w203970139","tags":{"building":"yes"},"nodes":["n2139824793","n2139824787","n2139824773","n2139824778","n2139824793"]},"w203970098":{"id":"w203970098","tags":{"building":"yes"},"nodes":["n2139824748","n2139824712","n2139824726","n2139824760","n2139824748"]},"w208643132":{"id":"w208643132","tags":{"area":"yes","building":"yes"},"nodes":["n2189153195","n2189153196","n2189153197","n2189153198","n2189153195"]},"w203970094":{"id":"w203970094","tags":{"building":"yes"},"nodes":["n2139824755","n2139824753","n2139824759","n2139824764","n2139824763","n2139824767","n2139824770","n2139824782","n2139824772","n2139824756","n2139824751","n2139824754","n2139824755"]},"w208643138":{"id":"w208643138","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153231","n2189153232","n2189153240","n2189153244","n2189153236","n2189153238","n2189153237","n2189153239","n2189153252","n2189153235","n2189153234","n2189153253","n2189153233","n2189153231"]},"w203970125":{"id":"w203970125","tags":{"building":"yes"},"nodes":["n2139824735","n2139824738","n2139824757","n2139824749","n2139824735"]},"w170848823":{"id":"w170848823","tags":{"name":"Rocky River","waterway":"river"},"nodes":["n1819849189","n1819858516","n1819858519","n1819858504","n1819858525","n1819858506","n1819858513"]},"w203970898":{"id":"w203970898","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832645","n2139832647","n2139832649","n2139832651","n2139832645"]},"w203970134":{"id":"w203970134","tags":{"building":"yes"},"nodes":["n2139824796","n2139824803","n2139824797","n2139824788","n2139824796"]},"w203970104":{"id":"w203970104","tags":{"building":"yes"},"nodes":["n2139824733","n2139824730","n2139824714","n2139824721","n2139824733"]},"w206805245":{"id":"w206805245","tags":{"area":"yes","building":"yes"},"nodes":["n2168544780","n2168544781","n2139824796","n2139824803","n2168544780"]},"w206805252":{"id":"w206805252","tags":{"area":"yes","building":"yes"},"nodes":["n2168544838","n2168544839","n2168544840","n2168544841","n2168544842","n2168544843","n2168544844","n2168544845","n2168544846","n2168544847","n2168544838"]},"w203970099":{"id":"w203970099","tags":{"building":"yes"},"nodes":["n2139824783","n2139824795","n2139824790","n2139824779","n2139824783"]},"w17967730":{"id":"w17967730","tags":{"highway":"residential","name":"Water St"},"nodes":["n185963451","n2189153277","n185988036","n185988867","n185988869","n185988871","n185988872","n185988873","n185988875","n185988877","n185988878","n185988879","n185988880","n185988882","n185988884","n185978790"]},"w208643133":{"id":"w208643133","tags":{"area":"yes","building":"yes"},"nodes":["n2189153199","n2189153200","n2189153201","n2189153202","n2189153199"]},"w203970127":{"id":"w203970127","tags":{"building":"yes"},"nodes":["n2139824794","n2139824783","n2139824789","n2139824797","n2139824794"]},"w208643139":{"id":"w208643139","tags":{"highway":"service"},"nodes":["n185988237","n2189153242","n2189153247","n2189153241"]},"w203988297":{"id":"w203988297","tags":{"amenity":"parking","area":"yes"},"nodes":["n2140006423","n2140006441","n2140006425","n2140006426","n2140006440","n2140006427","n2140006428","n2140006429","n2140006430","n2140006423"]},"w206805250":{"id":"w206805250","tags":{"area":"yes","building":"yes"},"nodes":["n2168544827","n2168544823","n2168544825","n2168544800","n2168544829","n2168544827"]},"w208643140":{"id":"w208643140","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153242","n2189153254","n2189153243","n2189153244","n2189153251","n2189153257","n2189153245","n2189153252","n2189153246"]},"w203974055":{"id":"w203974055","tags":{"bridge":"yes","highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870376","n2139870377"]},"w206805247":{"id":"w206805247","tags":{"area":"yes","building":"yes"},"nodes":["n2168544785","n2168544786","n2168544783","n2168544787","n2168544788","n2168544789","n2168544785"]},"w17964996":{"id":"w17964996","tags":{"highway":"residential","name":"Foster St"},"nodes":["n1819858524","n1819858515","n1819858522","n1819858530","n2139832682","n1819858510","n1819858520","n1819858502","n2139832680","n185963451","n1819858527","n185963452","n185963453","n185963454","n185963455","n185963456"]},"w208643144":{"id":"w208643144","tags":{"area":"yes","building":"yes"},"nodes":["n2189153264","n2189153265","n2189153266","n2189153267","n2189153268","n2189153269","n2189153270","n2189153264"]},"w203970914":{"id":"w203970914","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832722","n2139832723","n2139832724","n2139832725","n2139832726","n2139832727","n2139844839","n2139832722"]},"w208643143":{"id":"w208643143","tags":{"area":"yes","building":"yes"},"nodes":["n2189153258","n2189153259","n2189153260","n2189153261","n2189153262","n2189153263","n2189153258"]},"w203049590":{"id":"w203049590","tags":{"amenity":"parking","area":"yes"},"nodes":["n2130304152","n2130304153","n2140006403","n2130304154","n2130304156","n2130304155","n2130304160","n2130304152"]},"w203974054":{"id":"w203974054","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139858971","n2139870373","n2139870374"]},"w203049595":{"id":"w203049595","tags":{"highway":"service"},"nodes":["n2130304158","n2130304159","n2130304160","n2139832635","n2139832639"]},"w203970913":{"id":"w203970913","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832715","n2139832716","n2139832717","n2139832718","n2139832719","n2139832720","n2139832721","n2139832716"]},"w208643134":{"id":"w208643134","tags":{"area":"yes","building":"yes"},"nodes":["n2189153203","n2189153204","n2189153205","n2189153206","n2189153207","n2189153208","n2189153209","n2189153210","n2189153211","n2189153212","n2189153213","n2189153214","n2189153203"]},"w134150808":{"id":"w134150808","tags":{"bridge":"yes","highway":"residential","name":"Moore St"},"nodes":["n185988239","n185984009","n185988241","n1475284019"]},"w203970115":{"id":"w203970115","tags":{"building":"yes"},"nodes":["n2139824761","n2139824727","n2139824736","n2139824771","n2139824761"]},"w208643130":{"id":"w208643130","tags":{"area":"yes","building":"yes"},"nodes":["n2189153183","n2189153184","n2189153185","n2189153186","n2189153187","n2189153188","n2189153189","n2189153190","n2189153183"]},"w206805246":{"id":"w206805246","tags":{"area":"yes","building":"yes"},"nodes":["n2168544782","n2168544780","n2168544781","n2168544783","n2168544787","n2168544784","n2168544782"]},"w203970138":{"id":"w203970138","tags":{"building":"yes"},"nodes":["n2139824729","n2139824720","n2139824702","n2139824707","n2139824729"]},"w203970133":{"id":"w203970133","tags":{"building":"yes"},"nodes":["n2139824748","n2139824737","n2139824717","n2139824728","n2139824748"]},"w203970907":{"id":"w203970907","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832700","n2139832701","n2139832702"]},"w203974056":{"id":"w203974056","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870377","n2139870378"]},"w203970897":{"id":"w203970897","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2130304156","n2166205688","n2139832635","n2139832636","n2139832637","n2139832639","n2139832641","n2166205688"]},"w203974057":{"id":"w203974057","tags":{"highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870375","n2139870376"]},"w203049594":{"id":"w203049594","tags":{"highway":"service"},"nodes":["n2130304156","n2139870378","n2139832706","n2139832704","n2130304157"]},"w203970122":{"id":"w203970122","tags":{"building":"yes"},"nodes":["n2139824757","n2139824740","n2139824747","n2139824762","n2139824757"]},"w208643136":{"id":"w208643136","tags":{"area":"yes","building":"yes"},"nodes":["n2189153219","n2189153220","n2189153221","n2189153222","n2189153223","n2189153224","n2189153225","n2189153226","n2189153219"]},"w203970128":{"id":"w203970128","tags":{"building":"yes"},"nodes":["n2139824732","n2139824752","n2139824744","n2139824724","n2139824732"]},"w203970097":{"id":"w203970097","tags":{"building":"yes"},"nodes":["n2139824737","n2139824733","n2139824710","n2139824716","n2139824737"]},"w203970137":{"id":"w203970137","tags":{"building":"yes"},"nodes":["n2139824765","n2139824774","n2139824758","n2139824746","n2139824765"]},"w134150840":{"id":"w134150840","tags":{"highway":"residential","name":"Moore St"},"nodes":["n1475284019","n185988243","n185988244","n185988245"]},"w17967628":{"id":"w17967628","tags":{"highway":"residential","name":"Moore St"},"nodes":["n185978388","n2139832709","n185988237","n185988239"]},"w203988292":{"id":"w203988292","tags":{"bridge":"yes","highway":"footway"},"nodes":["n2140006407","n2140006405"]},"w203970118":{"id":"w203970118","tags":{"building":"yes"},"nodes":["n2139824775","n2139824785","n2139824780","n2139824768","n2139824775"]},"w203970121":{"id":"w203970121","tags":{"building":"yes"},"nodes":["n2139824768","n2139824781","n2139824776","n2139824765","n2139824768"]},"w17967752":{"id":"w17967752","tags":{"highway":"residential","name":"Railroad Drive"},"nodes":["n185964980","n2139832699","n2139832700","n2130304158","n185988969","n185988971","n185988972","n1475284011"]},"w203970136":{"id":"w203970136","tags":{"building":"yes"},"nodes":["n2139824798","n2139824793","n2139824777","n2139824784","n2139824798"]},"w203970142":{"id":"w203970142","tags":{"building":"yes"},"nodes":["n2139824808","n2139824809","n2139824807","n2139824806","n2139824801","n2139824800","n2139824804","n2139824805","n2139824808"]},"w208643137":{"id":"w208643137","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153227","n2189153248","n2189153228","n2189153234","n2189153235","n2189153229","n2189153249","n2189153230","n2189153227"]},"w208643129":{"id":"w208643129","tags":{"area":"yes","building":"yes"},"nodes":["n2189153179","n2189153180","n2189153181","n2189153182","n2189153179"]},"w203970909":{"id":"w203970909","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832703","n2139832704","n2139832706","n2139832708","n2139832703"]},"w203970905":{"id":"w203970905","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832688","n2139832691"]},"w203988298":{"id":"w203988298","tags":{"highway":"service"},"nodes":["n2140006431","n2140006433","n2140006435","n2140006436","n2140006437","n2140006438","n2140006439","n2140006440"]},"w203970106":{"id":"w203970106","tags":{"building":"yes"},"nodes":["n2139824798","n2139824791","n2139824799","n2139824802","n2139824798"]},"w203970129":{"id":"w203970129","tags":{"building":"yes"},"nodes":["n2139824787","n2139824782","n2139824766","n2139824769","n2139824787"]},"w208643131":{"id":"w208643131","tags":{"area":"yes","building":"yes"},"nodes":["n2189153191","n2189153192","n2189153193","n2189153194","n2189153191"]},"w206805249":{"id":"w206805249","tags":{"area":"yes","building":"yes"},"nodes":["n2168544800","n2168544801","n2168544802","n2168544805","n2168544807","n2168544809","n2168544811","n2168544813","n2168544815","n2168544817","n2168544819","n2168544821","n2168544823","n2168544825","n2168544800"]},"w134150800":{"id":"w134150800","tags":{"bridge":"yes","highway":"primary","name":"W Michigan Ave","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964972","n185964976"]},"w17966984":{"id":"w17966984","tags":{"highway":"residential","name":"Portage Avenue"},"nodes":["n185978375","n185963456","n2189153218","n185966937","n185978967","n185967422","n185982193","n185968100","n185982195","n185960195","n185980735","n185978787","n185966948","n185982196","n185982197","n185982198","n185982200","n2139795768","n185972155"]},"w203988294":{"id":"w203988294","tags":{"amenity":"shelter","area":"yes","building":"yes","shelter_type":"picnic_shelter"},"nodes":["n2140006409","n2140006411","n2140006413","n2140006415","n2140006409"]},"w203970912":{"id":"w203970912","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832711","n2139832712","n2139832713","n2139832714","n2139832711"]},"w203970119":{"id":"w203970119","tags":{"building":"yes"},"nodes":["n2139824713","n2139824705","n2139824683","n2139824689","n2139824713"]},"w203970114":{"id":"w203970114","tags":{"building":"yes"},"nodes":["n2139824735","n2139824750","n2139824745","n2139824732","n2139824735"]},"w208643142":{"id":"w208643142","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153254","n2189153255","n2189153256","n2189153257"]},"w206805253":{"id":"w206805253","tags":{"area":"yes","building":"yes"},"nodes":["n2168544848","n2168544849","n2168544850","n2168544851","n2168544852","n2168544853","n2168544854","n2168544855","n2168544848"]},"w143497377":{"id":"w143497377","tags":{"highway":"primary","name":"North Main Street","old_ref":"US 131","ref":"US 131 Business"},"nodes":["n185962625","n185978420","n185978419","n185978417","n185978415","n185978414","n185975735","n1475293254","n185978410","n185978406","n185970515","n185978402","n185978399","n185965399","n2189015992","n185961396","n185967917","n185978394","n185971631","n185960796","n185978392","n185974583","n185978390","n185971578","n185965289","n2189153215","n185978388","n185978383","n185978381","n185978379","n185978377","n185978375","n185964982"]},"w134150811":{"id":"w134150811","tags":{"highway":"primary","name":"West Michigan Avenue","old_ref":"US 131","ref":"US 131 Business;M 60"},"nodes":["n185964976","n2130304157","n1475284023","n2139832715","n185964980","n185964982"]},"w208643135":{"id":"w208643135","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153215","n2189153216","n2189153217","n2189153218"]},"w17967183":{"id":"w17967183","tags":{"highway":"residential","name":"West Street"},"nodes":["n1475284011","n185984011","n185984013","n185984015","n2189153246","n2189153250","n185965291","n185984017","n185971580","n185984020","n185974585","n185982163","n185975064","n185971632","n185984022","n185984024","n185967918"]},"w134150778":{"id":"w134150778","tags":{"bridge":"yes","highway":"residential","name":"Moore St"},"nodes":["n185988245","n1475283992","n185975911"]},"w206805248":{"id":"w206805248","tags":{"area":"yes","building":"yes"},"nodes":["n2168544790","n2168544791","n2168544792","n2168544793","n2168544795","n2168544797","n2168544798","n2168544799","n2168544802","n2168544801","n2168544790"]},"w203974058":{"id":"w203974058","tags":{"bridge":"yes","highway":"path","name":"Riverwalk Trail"},"nodes":["n2139870374","n2139870375"]},"w203970902":{"id":"w203970902","tags":{"highway":"service"},"nodes":["n2139832678","n2139832691","n2139832680"]},"w203988296":{"id":"w203988296","tags":{"highway":"path"},"nodes":["n2139858967","n2140006421","n2139858935"]},"w206805251":{"id":"w206805251","tags":{"area":"yes","building":"yes"},"nodes":["n2168544830","n2168544831","n2168544832","n2168544833","n2168544834","n2168544835","n2168544836","n2168544837","n2168544830"]},"w203970906":{"id":"w203970906","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832693","n2139832694","n2139832696","n2139832697","n2139832698","n2139832693"]},"w203049598":{"id":"w203049598","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2130304162","n2130304163","n2130304164","n2130304165","n2130304162"]},"w203970911":{"id":"w203970911","tags":{"highway":"service"},"nodes":["n2139832709","n2139832714","n2139832713","n2139832710","n185988971"]},"w203970105":{"id":"w203970105","tags":{"building":"yes"},"nodes":["n2139824779","n2139824792","n2139824786","n2139824775","n2139824779"]},"w203988290":{"id":"w203988290","tags":{"highway":"footway"},"nodes":["n2140006403","n2140006407"]},"w203970900":{"id":"w203970900","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139832653","n2139832663","n2139832665","n2139832667","n2139832669","n2139832671","n2139832673","n2139832675","n2139832677","n2139832653"]},"w209717048":{"id":"w209717048","tags":{"area":"yes","building":"yes"},"nodes":["n2199109755","n2199109756","n2199109757","n2199109758","n2199109759","n2199109760","n2199109755"]},"w208643141":{"id":"w208643141","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153247","n2189153248","n2189153249","n2189153250"]},"w203970903":{"id":"w203970903","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2139832682","n2139832688","n2139832684","n2139832678","n2139832686"]},"n354002527":{"id":"n354002527","loc":[-85.6236039,41.9458813],"tags":{"amenity":"school","name":"Barrows School"}},"n185963396":{"id":"n185963396","loc":[-85.627401,41.943496]},"n185963397":{"id":"n185963397","loc":[-85.627403,41.943625]},"n185965101":{"id":"n185965101","loc":[-85.626409,41.943215]},"n185971474":{"id":"n185971474","loc":[-85.624884,41.943508]},"n185971475":{"id":"n185971475","loc":[-85.625191,41.943509]},"n185971482":{"id":"n185971482","loc":[-85.624882,41.94382]},"n185983135":{"id":"n185983135","loc":[-85.624893,41.945616]},"n185983137":{"id":"n185983137","loc":[-85.624912,41.946524]},"n185988027":{"id":"n185988027","loc":[-85.622721,41.946535]},"n185963398":{"id":"n185963398","loc":[-85.6273993,41.9446899]},"n185983238":{"id":"n185983238","loc":[-85.6227157,41.9456321]},"n185980374":{"id":"n185980374","loc":[-85.6248856,41.9447242]},"n185980373":{"id":"n185980373","loc":[-85.6226744,41.9447371]},"n2196831342":{"id":"n2196831342","loc":[-85.6250924,41.945063]},"n2196831343":{"id":"n2196831343","loc":[-85.6252335,41.9450636]},"n2196831344":{"id":"n2196831344","loc":[-85.6252286,41.9448707]},"n2196831345":{"id":"n2196831345","loc":[-85.6250661,41.9448707]},"n2196831346":{"id":"n2196831346","loc":[-85.6250243,41.9449012]},"n2196831347":{"id":"n2196831347","loc":[-85.6250251,41.9449244]},"n2196831348":{"id":"n2196831348","loc":[-85.6250867,41.9449257]},"n2196831349":{"id":"n2196831349","loc":[-85.625349,41.9445058]},"n2196831350":{"id":"n2196831350","loc":[-85.6253471,41.9443882]},"n2196831351":{"id":"n2196831351","loc":[-85.6251516,41.94439]},"n2196831352":{"id":"n2196831352","loc":[-85.6251522,41.9444308]},"n2196831353":{"id":"n2196831353","loc":[-85.6251344,41.9444309]},"n2196831354":{"id":"n2196831354","loc":[-85.6251356,41.9445077]},"n2196831355":{"id":"n2196831355","loc":[-85.6232357,41.9463406]},"n2196831356":{"id":"n2196831356","loc":[-85.6232409,41.9460668]},"n2196831357":{"id":"n2196831357","loc":[-85.6232072,41.9460665]},"n2196831358":{"id":"n2196831358","loc":[-85.6232117,41.9458272]},"n2196831359":{"id":"n2196831359","loc":[-85.6229808,41.9458248]},"n2196831360":{"id":"n2196831360","loc":[-85.6229763,41.9460627]},"n2196831361":{"id":"n2196831361","loc":[-85.623006,41.946063]},"n2196831362":{"id":"n2196831362","loc":[-85.6230023,41.9462557]},"n2196831363":{"id":"n2196831363","loc":[-85.6230755,41.9462565]},"n2196831364":{"id":"n2196831364","loc":[-85.6230739,41.9463389]},"n185947349":{"id":"n185947349","loc":[-85.618327,41.945607]},"n185947359":{"id":"n185947359","loc":[-85.615453,41.945597]},"n185947378":{"id":"n185947378","loc":[-85.617231,41.945603]},"n185947474":{"id":"n185947474","loc":[-85.616136,41.945602]},"n185948972":{"id":"n185948972","loc":[-85.615273,41.945637]},"n185955019":{"id":"n185955019","loc":[-85.620172,41.945627]},"n185960682":{"id":"n185960682","loc":[-85.622759,41.951845]},"n185961369":{"id":"n185961369","loc":[-85.622758,41.947444]},"n185961371":{"id":"n185961371","loc":[-85.624908,41.947416]},"n185963392":{"id":"n185963392","loc":[-85.6270462,41.9409953]},"n185963393":{"id":"n185963393","loc":[-85.627295,41.941304]},"n185963394":{"id":"n185963394","loc":[-85.627352,41.94148]},"n185963395":{"id":"n185963395","loc":[-85.62737,41.942261]},"n185965099":{"id":"n185965099","loc":[-85.6264,41.942263]},"n185965108":{"id":"n185965108","loc":[-85.622769,41.949224]},"n185965110":{"id":"n185965110","loc":[-85.624937,41.949237]},"n185966295":{"id":"n185966295","loc":[-85.6299942,41.9446689]},"n185966342":{"id":"n185966342","loc":[-85.624873,41.942022]},"n185970222":{"id":"n185970222","loc":[-85.622761,41.948357]},"n185970224":{"id":"n185970224","loc":[-85.624924,41.9483338]},"n185971477":{"id":"n185971477","loc":[-85.620051,41.94383]},"n185971478":{"id":"n185971478","loc":[-85.621219,41.943801]},"n185971481":{"id":"n185971481","loc":[-85.621812,41.943807]},"n185973866":{"id":"n185973866","loc":[-85.627629,41.946498]},"n185974699":{"id":"n185974699","loc":[-85.6227688,41.950119]},"n185978800":{"id":"n185978800","loc":[-85.623953,41.954684]},"n185980372":{"id":"n185980372","loc":[-85.621459,41.944756]},"n185980378":{"id":"n185980378","loc":[-85.6286375,41.9446764]},"n185980380":{"id":"n185980380","loc":[-85.630139,41.944661]},"n185980382":{"id":"n185980382","loc":[-85.630298,41.944635]},"n185980384":{"id":"n185980384","loc":[-85.630759,41.94454]},"n185980386":{"id":"n185980386","loc":[-85.6312369,41.9444548]},"n185983133":{"id":"n185983133","loc":[-85.6248672,41.9415903]},"n185983139":{"id":"n185983139","loc":[-85.624951,41.950239]},"n185983140":{"id":"n185983140","loc":[-85.624934,41.950681]},"n185983141":{"id":"n185983141","loc":[-85.624813,41.950983]},"n185983143":{"id":"n185983143","loc":[-85.6246225,41.951591]},"n185983144":{"id":"n185983144","loc":[-85.623908,41.9539165]},"n185983145":{"id":"n185983145","loc":[-85.6238903,41.9540956]},"n185983146":{"id":"n185983146","loc":[-85.623898,41.95431]},"n185983236":{"id":"n185983236","loc":[-85.628481,41.945611]},"n185985914":{"id":"n185985914","loc":[-85.620072,41.946538]},"n185986812":{"id":"n185986812","loc":[-85.6227785,41.9510005]},"n185988028":{"id":"n185988028","loc":[-85.6281401,41.9469632]},"n185988030":{"id":"n185988030","loc":[-85.6282451,41.9470314]},"n185988032":{"id":"n185988032","loc":[-85.6283312,41.9470656]},"w17964989":{"id":"w17964989","tags":{"highway":"residential","name":"Middle St"},"nodes":["n185963392","n185963393","n185963394","n185963395","n185963396","n185963397","n185963398"]},"w17965158":{"id":"w17965158","tags":{"access":"private","highway":"service","name":"Battle St"},"nodes":["n185965099","n185965101"]},"w41074896":{"id":"w41074896","tags":{"highway":"secondary","name":"East Michigan Avenue","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185980372","n185980373","n185980374","n185963398","n185980378","n185966295","n185980380","n185980382","n185980384","n185980386"]},"w17965846":{"id":"w17965846","tags":{"highway":"residential","name":"2nd Ave"},"nodes":["n185971477","n185971478","n185971481","n185971482"]},"w209470306":{"id":"w209470306","tags":{"area":"yes","building":"yes"},"nodes":["n2196831349","n2196831350","n2196831351","n2196831352","n2196831353","n2196831354","n2196831349"]},"w17965845":{"id":"w17965845","tags":{"highway":"residential","name":"2nd Ave"},"nodes":["n185971474","n185971475","n185963396"]},"w209470307":{"id":"w209470307","tags":{"area":"yes","building":"yes"},"nodes":["n2196831355","n2196831356","n2196831357","n2196831358","n2196831359","n2196831360","n2196831361","n2196831362","n2196831363","n2196831364","n2196831355"]},"w17968192":{"id":"w17968192","tags":{"highway":"residential","name":"Washington St"},"nodes":["n185980373","n185983238","n185988027","n185961369","n185970222","n185965108","n185974699","n185986812","n185960682"]},"w17967603":{"id":"w17967603","tags":{"highway":"residential","name":"5th Ave"},"nodes":["n185985914","n185988027","n185983137","n185973866","n185988028","n185988030","n185988032"]},"w209470305":{"id":"w209470305","tags":{"area":"yes","building":"yes"},"nodes":["n2196831342","n2196831343","n2196831344","n2196831345","n2196831346","n2196831347","n2196831348","n2196831342"]},"w17967092":{"id":"w17967092","tags":{"highway":"residential","name":"Wood St"},"nodes":["n185983133","n185966342","n185971474","n185971482","n185980374","n185983135","n185983137","n185961371","n185970224","n185965110","n185983139","n185983140","n185983141","n185983143","n185983144","n185983145","n185983146","n185978800"]},"w17967107":{"id":"w17967107","tags":{"highway":"residential","name":"4th Ave"},"nodes":["n185983236","n185983135","n185983238","n185955019","n185947349","n185947378","n185947474","n185947359","n185948972"]},"n354030330":{"id":"n354030330","loc":[-85.6297222,41.9444444],"tags":{"leisure":"park","name":"Scouter Park"}},"n185966296":{"id":"n185966296","loc":[-85.629998,41.944078]},"n185966298":{"id":"n185966298","loc":[-85.629972,41.943927]},"n185966300":{"id":"n185966300","loc":[-85.629948,41.943783]},"n185980391":{"id":"n185980391","loc":[-85.6322992,41.9442766]},"n185980393":{"id":"n185980393","loc":[-85.6324925,41.9442136]},"n185980389":{"id":"n185980389","loc":[-85.6320272,41.9443281]},"n185980388":{"id":"n185980388","loc":[-85.6315778,41.9443959]},"n354031320":{"id":"n354031320","loc":[-85.6280556,41.9447222],"tags":{"amenity":"place_of_worship","name":"Riverside Church","religion":"christian"}},"n185987309":{"id":"n185987309","loc":[-85.6286497,41.9453531]},"n185987311":{"id":"n185987311","loc":[-85.6285942,41.9454805]},"n185988034":{"id":"n185988034","loc":[-85.6285815,41.9471692]},"n185988896":{"id":"n185988896","loc":[-85.6318433,41.9437929]},"n185977764":{"id":"n185977764","loc":[-85.6322988,41.943472]},"n1819848852":{"id":"n1819848852","loc":[-85.6315188,41.9448808]},"n1819848912":{"id":"n1819848912","loc":[-85.6284289,41.9472189]},"n1819848925":{"id":"n1819848925","loc":[-85.6314501,41.9451617]},"n1819848949":{"id":"n1819848949","loc":[-85.6309394,41.9455192]},"n1819848951":{"id":"n1819848951","loc":[-85.6290297,41.9457187]},"n1819848963":{"id":"n1819848963","loc":[-85.630521,41.9455591]},"n1819848981":{"id":"n1819848981","loc":[-85.6292936,41.9455846]},"n1819848989":{"id":"n1819848989","loc":[-85.6298451,41.9455431]},"n1819848998":{"id":"n1819848998","loc":[-85.6314973,41.9446254]},"n1819849018":{"id":"n1819849018","loc":[-85.6302807,41.9455527]},"n1819849043":{"id":"n1819849043","loc":[-85.6285533,41.9469731]},"n1819849087":{"id":"n1819849087","loc":[-85.6314501,41.9453532]},"n1819849090":{"id":"n1819849090","loc":[-85.628843,41.9461033]},"n1819849109":{"id":"n1819849109","loc":[-85.6311926,41.9454729]},"n1819849116":{"id":"n1819849116","loc":[-85.6288967,41.9459437]},"n1819849177":{"id":"n1819849177","loc":[-85.6287894,41.9464544]},"n1819858529":{"id":"n1819858529","loc":[-85.6325485,41.9445625]},"n2189112797":{"id":"n2189112797","loc":[-85.6275271,41.944555]},"n2189112798":{"id":"n2189112798","loc":[-85.6275196,41.9437258]},"n2189112799":{"id":"n2189112799","loc":[-85.6278937,41.943723]},"n2189112800":{"id":"n2189112800","loc":[-85.6278969,41.9439191]},"n2189112801":{"id":"n2189112801","loc":[-85.6279907,41.9439345]},"n2189112802":{"id":"n2189112802","loc":[-85.6280817,41.9439663]},"n2189112803":{"id":"n2189112803","loc":[-85.6281768,41.9440145]},"n2189112804":{"id":"n2189112804","loc":[-85.6281933,41.9440483]},"n2189112805":{"id":"n2189112805","loc":[-85.6281671,41.9440535]},"n2189112806":{"id":"n2189112806","loc":[-85.6281933,41.9440935]},"n2189112807":{"id":"n2189112807","loc":[-85.6282126,41.9441437]},"n2189112808":{"id":"n2189112808","loc":[-85.628214,41.9441991]},"n2189112809":{"id":"n2189112809","loc":[-85.6283298,41.944196]},"n2189112810":{"id":"n2189112810","loc":[-85.6283285,41.9442616]},"n2189112811":{"id":"n2189112811","loc":[-85.6281727,41.9442616]},"n2189112812":{"id":"n2189112812","loc":[-85.6281713,41.9442934]},"n2189112813":{"id":"n2189112813","loc":[-85.6280386,41.9442963]},"n2189112814":{"id":"n2189112814","loc":[-85.6280405,41.9443292]},"n2189112815":{"id":"n2189112815","loc":[-85.627829,41.9443349]},"n2189112816":{"id":"n2189112816","loc":[-85.6278347,41.9445495]},"n2189153271":{"id":"n2189153271","loc":[-85.6321053,41.9460342]},"n2189153272":{"id":"n2189153272","loc":[-85.632278,41.9457841]},"n2189153273":{"id":"n2189153273","loc":[-85.632823,41.9459936]},"n2189153274":{"id":"n2189153274","loc":[-85.6326845,41.9461963]},"n2189153275":{"id":"n2189153275","loc":[-85.6325664,41.9461507]},"n2189153276":{"id":"n2189153276","loc":[-85.6325323,41.946198]},"n2189153278":{"id":"n2189153278","loc":[-85.6321916,41.9459733]},"n2189153279":{"id":"n2189153279","loc":[-85.6322598,41.9458703]},"n2189153280":{"id":"n2189153280","loc":[-85.6327208,41.9460358]},"n2189153281":{"id":"n2189153281","loc":[-85.6326413,41.9461422]},"n185959079":{"id":"n185959079","loc":[-85.6293702,41.9474668]},"n185966301":{"id":"n185966301","loc":[-85.629692,41.943136]},"n185966304":{"id":"n185966304","loc":[-85.629565,41.942916]},"n185966308":{"id":"n185966308","loc":[-85.629501,41.942751]},"n185966315":{"id":"n185966315","loc":[-85.629472,41.942578]},"n185966319":{"id":"n185966319","loc":[-85.629444,41.942414]},"n185966321":{"id":"n185966321","loc":[-85.629391,41.94205]},"n185966323":{"id":"n185966323","loc":[-85.629369,41.941858]},"n185966327":{"id":"n185966327","loc":[-85.629297,41.941604]},"n185966331":{"id":"n185966331","loc":[-85.629233,41.941549]},"n185966336":{"id":"n185966336","loc":[-85.628504,41.941364]},"n185966338":{"id":"n185966338","loc":[-85.628275,41.941303]},"n185966340":{"id":"n185966340","loc":[-85.6269038,41.9410983]},"n185973867":{"id":"n185973867","loc":[-85.626843,41.947333]},"n185977762":{"id":"n185977762","loc":[-85.6318441,41.9429453]},"n1819848853":{"id":"n1819848853","loc":[-85.625854,41.9492218]},"n1819848861":{"id":"n1819848861","loc":[-85.6251459,41.9552376]},"n1819848874":{"id":"n1819848874","loc":[-85.6267445,41.9482961]},"n1819848882":{"id":"n1819848882","loc":[-85.6257209,41.9552396]},"n1819848883":{"id":"n1819848883","loc":[-85.624706,41.9523173]},"n1819848907":{"id":"n1819848907","loc":[-85.62609,41.9561471]},"n1819848908":{"id":"n1819848908","loc":[-85.6244013,41.9549284]},"n1819848911":{"id":"n1819848911","loc":[-85.6265578,41.9553672]},"n1819848923":{"id":"n1819848923","loc":[-85.6246802,41.9550959]},"n1819848936":{"id":"n1819848936","loc":[-85.6241588,41.9539291]},"n1819848940":{"id":"n1819848940","loc":[-85.62506,41.9511129]},"n1819848944":{"id":"n1819848944","loc":[-85.624942,41.9515912]},"n1819848950":{"id":"n1819848950","loc":[-85.6273989,41.9475461]},"n1819848957":{"id":"n1819848957","loc":[-85.627695,41.947404]},"n1819849009":{"id":"n1819849009","loc":[-85.6259248,41.94896]},"n1819849037":{"id":"n1819849037","loc":[-85.6257252,41.9502112]},"n1819849061":{"id":"n1819849061","loc":[-85.6270084,41.9479626]},"n1819849073":{"id":"n1819849073","loc":[-85.6243734,41.9534583]},"n1819849091":{"id":"n1819849091","loc":[-85.6241373,41.9543918]},"n1819849130":{"id":"n1819849130","loc":[-85.6282572,41.9473067]},"n1819849143":{"id":"n1819849143","loc":[-85.625281,41.9506596]},"n1819849153":{"id":"n1819849153","loc":[-85.6258647,41.9498043]},"n1819849168":{"id":"n1819849168","loc":[-85.6265084,41.9559317]},"n1819849173":{"id":"n1819849173","loc":[-85.6263325,41.9552156]},"n1819849175":{"id":"n1819849175","loc":[-85.6266372,41.9556764]},"n1819849178":{"id":"n1819849178","loc":[-85.6242232,41.9545993]},"n1819849181":{"id":"n1819849181","loc":[-85.6262187,41.9486712]},"n1819849188":{"id":"n1819849188","loc":[-85.6245558,41.9530434]},"n1819849190":{"id":"n1819849190","loc":[-85.6255982,41.9563017]},"n2168544738":{"id":"n2168544738","loc":[-85.6245707,41.9529711]},"w208643145":{"id":"w208643145","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189153271","n2189153272","n2189153273","n2189153274","n2189153275","n2189153276","n2189153271"]},"w17967561":{"id":"w17967561","tags":{"highway":"residential","name":"Garden St"},"nodes":["n185980378","n185987309","n185987311","n185983236","n185973866"]},"w134150802":{"id":"w134150802","tags":{"bridge":"yes","highway":"secondary","name":"East Michigan Avenue","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185980386","n185980388"]},"w208639462":{"id":"w208639462","tags":{"area":"yes","building":"yes"},"nodes":["n2189112797","n2189112798","n2189112799","n2189112800","n2189112801","n2189112802","n2189112803","n2189112804","n2189112805","n2189112806","n2189112807","n2189112808","n2189112809","n2189112810","n2189112811","n2189112812","n2189112813","n2189112814","n2189112815","n2189112816","n2189112797"]},"w134150830":{"id":"w134150830","tags":{"bridge":"yes","highway":"secondary","name":"South Main Street","old_ref":"US 131","ref":"M 86"},"nodes":["n185977762","n185977764"]},"w134150801":{"id":"w134150801","tags":{"highway":"secondary","name":"South Main Street","old_ref":"US 131","ref":"M 86"},"nodes":["n185977764","n185964982"]},"w208643146":{"id":"w208643146","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2189153277","n2189153281","n2189153278","n2189153279","n2189153280","n2189153281"]},"w17966061":{"id":"w17966061","tags":{"highway":"residential","name":"John Glenn Ct"},"nodes":["n185973866","n185973867"]},"w134150772":{"id":"w134150772","tags":{"highway":"residential","name":"5th Ave"},"nodes":["n185988034","n185959079","n185988036","n185978967"]},"w134150836":{"id":"w134150836","tags":{"highway":"secondary","name":"East Michigan Avenue","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185980388","n1819858524","n185980389","n185980391","n185980393","n185964982"]},"w17967734":{"id":"w17967734","tags":{"highway":"residential","name":"Water Street"},"nodes":["n185988896","n185980391","n1819858529"]},"w17965305":{"id":"w17965305","tags":{"highway":"residential","name":"River Dr"},"nodes":["n185966295","n185966296","n185966298","n185966300","n185966301","n185966304","n185966308","n185966315","n185966319","n185966321","n185966323","n185966327","n185966331","n185966336","n185966338","n185963392","n185966340","n185966342"]},"w134150826":{"id":"w134150826","tags":{"bridge":"yes","highway":"residential","name":"5th Ave"},"nodes":["n185988032","n185988034"]},"w170848330":{"id":"w170848330","tags":{"name":"Portage River","waterway":"river"},"nodes":["n1819849190","n1819848907","n1819849168","n1819849175","n1819848911","n1819849173","n1819848882","n1819848861","n1819848923","n1819848908","n1819849178","n1819849091","n1819848936","n1819849073","n1819849188","n2168544738","n1819848883","n1819848944","n1819848940","n1819849143","n1819849037","n1819849153","n1819848853","n1819849009","n1819849181","n1819848874","n1819849061","n1819848950","n1819848957","n1819849130","n1819848912","n1819849043","n1819849177","n1819849090","n1819849116","n1819848951","n1819848981","n1819848989","n1819849018","n1819848963","n1819848949","n1819849109","n1819849087","n1819848925","n1819848852","n1819848998","n1819849057"]},"r270264":{"id":"r270264","tags":{"network":"US:MI","ref":"86","route":"road","state_id":"MI","type":"route","url":"http://en.wikipedia.org/wiki/M-86_%28Michigan_highway%29"},"members":[{"id":"w17737723","type":"way","role":""},{"id":"w17735949","type":"way","role":""},{"id":"w17740404","type":"way","role":""},{"id":"w17966273","type":"way","role":""},{"id":"w17964745","type":"way","role":""},{"id":"w151538068","type":"way","role":""},{"id":"w151538067","type":"way","role":""},{"id":"w17964960","type":"way","role":""},{"id":"w17966099","type":"way","role":""},{"id":"w17968009","type":"way","role":""},{"id":"w41259499","type":"way","role":""},{"id":"w151540401","type":"way","role":""},{"id":"w151540418","type":"way","role":""},{"id":"w17967997","type":"way","role":""},{"id":"w17966029","type":"way","role":""},{"id":"w17964801","type":"way","role":""},{"id":"w41259496","type":"way","role":""},{"id":"w151540399","type":"way","role":""},{"id":"w17968004","type":"way","role":""},{"id":"w17966462","type":"way","role":""},{"id":"w134150830","type":"way","role":""},{"id":"w134150801","type":"way","role":""},{"id":"w17732295","type":"way","role":""}]},"n185980093":{"id":"n185980093","loc":[-85.6271414,41.9407274]},"n185964330":{"id":"n185964330","loc":[-85.6235688,41.9399111]},"n185964328":{"id":"n185964328","loc":[-85.6235609,41.9391301]},"n185958034":{"id":"n185958034","loc":[-85.627102,41.939125]},"n185964331":{"id":"n185964331","loc":[-85.623571,41.940124]},"n185964329":{"id":"n185964329","loc":[-85.623562,41.9392411]},"n185972756":{"id":"n185972756","loc":[-85.623802,41.939102]},"n185972757":{"id":"n185972757","loc":[-85.623584,41.93913]},"n185975325":{"id":"n185975325","loc":[-85.624835,41.939318]},"n185975326":{"id":"n185975326","loc":[-85.624811,41.939435]},"n185975327":{"id":"n185975327","loc":[-85.624635,41.939703]},"n185975328":{"id":"n185975328","loc":[-85.624366,41.940055]},"n185975330":{"id":"n185975330","loc":[-85.624287,41.940113]},"n185975332":{"id":"n185975332","loc":[-85.624215,41.940134]},"n185980088":{"id":"n185980088","loc":[-85.627127,41.940086]},"n185988943":{"id":"n185988943","loc":[-85.622643,41.940128]},"n185988961":{"id":"n185988961","loc":[-85.627263,41.940082]},"n185990192":{"id":"n185990192","loc":[-85.622933,41.939224]},"n185990194":{"id":"n185990194","loc":[-85.621976,41.939203]},"n185991378":{"id":"n185991378","loc":[-85.622643,41.940635]},"n1475283999":{"id":"n1475283999","loc":[-85.6271165,41.9408429]},"n185980090":{"id":"n185980090","loc":[-85.6271315,41.9402001]},"n185958036":{"id":"n185958036","loc":[-85.6248366,41.9391615]},"n1819800188":{"id":"n1819800188","loc":[-85.6246947,41.9401644]},"n1819800199":{"id":"n1819800199","loc":[-85.6233686,41.9430896]},"n1819800204":{"id":"n1819800204","loc":[-85.6223236,41.9408587]},"n1819800213":{"id":"n1819800213","loc":[-85.6247526,41.9414138]},"n1819800216":{"id":"n1819800216","loc":[-85.6230961,41.9407151]},"n1819800218":{"id":"n1819800218","loc":[-85.621991,41.9429336]},"n1819800221":{"id":"n1819800221","loc":[-85.6246088,41.9424708]},"n1819800227":{"id":"n1819800227","loc":[-85.6241368,41.9403081]},"n1819800230":{"id":"n1819800230","loc":[-85.6226776,41.9431012]},"n1819800231":{"id":"n1819800231","loc":[-85.6243728,41.9401644]},"n1819800232":{"id":"n1819800232","loc":[-85.6249629,41.9408907]},"n1819800248":{"id":"n1819800248","loc":[-85.6238685,41.9405555]},"n1819800266":{"id":"n1819800266","loc":[-85.6246882,41.9418367]},"n1819800271":{"id":"n1819800271","loc":[-85.62492,41.9413695]},"n1819800294":{"id":"n1819800294","loc":[-85.6243556,41.9427465]},"n1819800304":{"id":"n1819800304","loc":[-85.6251453,41.94117]},"n1819800325":{"id":"n1819800325","loc":[-85.6248234,41.9405714]},"n1819800362":{"id":"n1819800362","loc":[-85.6239544,41.9429416]},"n1819800368":{"id":"n1819800368","loc":[-85.6243406,41.9402283]},"n1819800375":{"id":"n1819800375","loc":[-85.6226562,41.940755]},"n1819800377":{"id":"n1819800377","loc":[-85.6232033,41.9406512]},"n185945133":{"id":"n185945133","loc":[-85.623501,41.933232]},"n185945135":{"id":"n185945135","loc":[-85.624776,41.933205]},"n185945395":{"id":"n185945395","loc":[-85.624741,41.93019]},"n185952239":{"id":"n185952239","loc":[-85.615166,41.9382]},"n185954490":{"id":"n185954490","loc":[-85.624721,41.929278]},"n185957831":{"id":"n185957831","loc":[-85.625041,41.938662]},"n185958030":{"id":"n185958030","loc":[-85.629033,41.93913]},"n185958032":{"id":"n185958032","loc":[-85.628429,41.939143]},"n185958498":{"id":"n185958498","loc":[-85.621605,41.940143]},"n185961186":{"id":"n185961186","loc":[-85.624792,41.935214]},"n185963099":{"id":"n185963099","loc":[-85.6204461,41.9401485]},"n185963698":{"id":"n185963698","loc":[-85.6297342,41.9400783]},"n185964320":{"id":"n185964320","loc":[-85.623511,41.934216]},"n185964322":{"id":"n185964322","loc":[-85.6235312,41.9362084]},"n185964324":{"id":"n185964324","loc":[-85.6235488,41.9371726]},"n185964326":{"id":"n185964326","loc":[-85.6235512,41.9381718]},"n185967077":{"id":"n185967077","loc":[-85.617359,41.940161]},"n185967634":{"id":"n185967634","loc":[-85.6248039,41.9362012]},"n185970833":{"id":"n185970833","loc":[-85.6248019,41.9381684]},"n185972752":{"id":"n185972752","loc":[-85.624582,41.938848]},"n185972754":{"id":"n185972754","loc":[-85.6242,41.939008]},"n185973251":{"id":"n185973251","loc":[-85.602727,41.936012]},"n185974509":{"id":"n185974509","loc":[-85.62478,41.93217]},"n185975315":{"id":"n185975315","loc":[-85.624703,41.925597]},"n185975316":{"id":"n185975316","loc":[-85.624716,41.927359]},"n185975317":{"id":"n185975317","loc":[-85.62475,41.93119]},"n185975318":{"id":"n185975318","loc":[-85.624782,41.934218]},"n185975320":{"id":"n185975320","loc":[-85.6247949,41.9371708]},"n185977754":{"id":"n185977754","loc":[-85.6276,41.937412]},"n185980075":{"id":"n185980075","loc":[-85.627451,41.937549]},"n185980077":{"id":"n185980077","loc":[-85.627375,41.937618]},"n185980078":{"id":"n185980078","loc":[-85.627278,41.937728]},"n185980079":{"id":"n185980079","loc":[-85.627199,41.937842]},"n185980081":{"id":"n185980081","loc":[-85.627141,41.937981]},"n185980083":{"id":"n185980083","loc":[-85.627109,41.938153]},"n185980085":{"id":"n185980085","loc":[-85.627101,41.938699]},"n185981173":{"id":"n185981173","loc":[-85.61433,41.940167]},"n185987021":{"id":"n185987021","loc":[-85.628311,41.942261]},"n185988963":{"id":"n185988963","loc":[-85.628439,41.940086]},"n185990195":{"id":"n185990195","loc":[-85.621225,41.939143]},"n185990196":{"id":"n185990196","loc":[-85.620576,41.939033]},"n185990198":{"id":"n185990198","loc":[-85.619081,41.938804]},"n185990200":{"id":"n185990200","loc":[-85.617593,41.938552]},"n185990202":{"id":"n185990202","loc":[-85.617372,41.938535]},"n185990204":{"id":"n185990204","loc":[-85.616087,41.93832]},"n185990206":{"id":"n185990206","loc":[-85.615754,41.938289]},"n185990209":{"id":"n185990209","loc":[-85.615438,41.938251]},"n185990211":{"id":"n185990211","loc":[-85.613469,41.937867]},"n185990212":{"id":"n185990212","loc":[-85.610172,41.937298]},"n185990213":{"id":"n185990213","loc":[-85.605537,41.936497]},"n185990214":{"id":"n185990214","loc":[-85.604014,41.936234]},"n1819800180":{"id":"n1819800180","loc":[-85.588775,41.9455032]},"n1819800181":{"id":"n1819800181","loc":[-85.6074212,41.9408827]},"n1819800182":{"id":"n1819800182","loc":[-85.6131397,41.9427022]},"n1819800183":{"id":"n1819800183","loc":[-85.6171523,41.9416807]},"n1819800184":{"id":"n1819800184","loc":[-85.602465,41.9397415]},"n1819800185":{"id":"n1819800185","loc":[-85.6109296,41.9410583]},"n1819800186":{"id":"n1819800186","loc":[-85.6165729,41.9418004]},"n1819800189":{"id":"n1819800189","loc":[-85.5866293,41.9458224]},"n1819800191":{"id":"n1819800191","loc":[-85.5853311,41.9466603]},"n1819800201":{"id":"n1819800201","loc":[-85.6101142,41.9433406]},"n1819800202":{"id":"n1819800202","loc":[-85.600963,41.9428618]},"n1819800206":{"id":"n1819800206","loc":[-85.6154357,41.9427501]},"n1819800207":{"id":"n1819800207","loc":[-85.6040309,41.9414094]},"n1819800209":{"id":"n1819800209","loc":[-85.6113694,41.943189]},"n1819800211":{"id":"n1819800211","loc":[-85.618032,41.9416408]},"n1819800214":{"id":"n1819800214","loc":[-85.5959419,41.9402602]},"n1819800219":{"id":"n1819800219","loc":[-85.5972117,41.9420043]},"n1819800223":{"id":"n1819800223","loc":[-85.6117171,41.9430019]},"n1819800224":{"id":"n1819800224","loc":[-85.5977873,41.9395579]},"n1819800226":{"id":"n1819800226","loc":[-85.5917362,41.9432209]},"n1819800228":{"id":"n1819800228","loc":[-85.6055759,41.9419122]},"n1819800229":{"id":"n1819800229","loc":[-85.6203395,41.9425595]},"n1819800233":{"id":"n1819800233","loc":[-85.6107579,41.9433007]},"n1819800234":{"id":"n1819800234","loc":[-85.6039773,41.9412498]},"n1819800235":{"id":"n1819800235","loc":[-85.6000977,41.9412861]},"n1819800236":{"id":"n1819800236","loc":[-85.6026689,41.9407231]},"n1819800237":{"id":"n1819800237","loc":[-85.615161,41.9428662]},"n1819800238":{"id":"n1819800238","loc":[-85.5878953,41.9454314]},"n1819800239":{"id":"n1819800239","loc":[-85.6035267,41.941569]},"n1819800240":{"id":"n1819800240","loc":[-85.5929738,41.9450208]},"n1819800241":{"id":"n1819800241","loc":[-85.6186329,41.9416488]},"n1819800242":{"id":"n1819800242","loc":[-85.5881136,41.9483963]},"n1819800243":{"id":"n1819800243","loc":[-85.5909208,41.9466922]},"n1819800244":{"id":"n1819800244","loc":[-85.5997721,41.9394941]},"n1819800245":{"id":"n1819800245","loc":[-85.6202064,41.9425712]},"n1819800246":{"id":"n1819800246","loc":[-85.591071,41.9448808]},"n1819800247":{"id":"n1819800247","loc":[-85.5866078,41.9490622]},"n1819800250":{"id":"n1819800250","loc":[-85.602383,41.9420841]},"n1819800251":{"id":"n1819800251","loc":[-85.5957418,41.9426906]},"n1819800255":{"id":"n1819800255","loc":[-85.6157039,41.9416727]},"n1819800256":{"id":"n1819800256","loc":[-85.6080328,41.9410982]},"n1819800258":{"id":"n1819800258","loc":[-85.6192551,41.9414892]},"n1819800260":{"id":"n1819800260","loc":[-85.6104253,41.94117]},"n1819800261":{"id":"n1819800261","loc":[-85.6204503,41.9425709]},"n1819800263":{"id":"n1819800263","loc":[-85.5872194,41.9455431]},"n1819800264":{"id":"n1819800264","loc":[-85.616176,41.9418244]},"n1819800268":{"id":"n1819800268","loc":[-85.6120883,41.9426703]},"n1819800269":{"id":"n1819800269","loc":[-85.5894547,41.9474946]},"n1819800272":{"id":"n1819800272","loc":[-85.6209181,41.9425027]},"n1819800274":{"id":"n1819800274","loc":[-85.6122814,41.9412817]},"n1819800276":{"id":"n1819800276","loc":[-85.5895153,41.9452798]},"n1819800277":{"id":"n1819800277","loc":[-85.5884317,41.9455272]},"n1819800279":{"id":"n1819800279","loc":[-85.5884103,41.9480966]},"n1819800287":{"id":"n1819800287","loc":[-85.5904917,41.9453915]},"n1819800288":{"id":"n1819800288","loc":[-85.6212292,41.9412977]},"n1819800289":{"id":"n1819800289","loc":[-85.5954377,41.9406832]},"n1819800290":{"id":"n1819800290","loc":[-85.593721,41.9420957]},"n1819800291":{"id":"n1819800291","loc":[-85.6162832,41.9427102]},"n1819800292":{"id":"n1819800292","loc":[-85.605018,41.9401804]},"n1819800293":{"id":"n1819800293","loc":[-85.6086443,41.941146]},"n1819800296":{"id":"n1819800296","loc":[-85.6204675,41.9413775]},"n1819800297":{"id":"n1819800297","loc":[-85.612496,41.9424947]},"n1819800299":{"id":"n1819800299","loc":[-85.6065629,41.9423431]},"n1819800301":{"id":"n1819800301","loc":[-85.6036125,41.9398452]},"n1819800303":{"id":"n1819800303","loc":[-85.6114767,41.94117]},"n1819800306":{"id":"n1819800306","loc":[-85.592616,41.9428139]},"n1819800308":{"id":"n1819800308","loc":[-85.6023041,41.9419521]},"n1819800310":{"id":"n1819800310","loc":[-85.6218944,41.9411061]},"n1819800311":{"id":"n1819800311","loc":[-85.6097816,41.941162]},"n1819800312":{"id":"n1819800312","loc":[-85.5922549,41.9457869]},"n1819800313":{"id":"n1819800313","loc":[-85.5986027,41.9417206]},"n1819800314":{"id":"n1819800314","loc":[-85.5918687,41.946138]},"n1819800315":{"id":"n1819800315","loc":[-85.5872875,41.948883]},"n1819800316":{"id":"n1819800316","loc":[-85.594272,41.9436642]},"n1819800317":{"id":"n1819800317","loc":[-85.6176351,41.941577]},"n1819800318":{"id":"n1819800318","loc":[-85.6137834,41.9430853]},"n1819800319":{"id":"n1819800319","loc":[-85.6195383,41.942622],"tags":{"leisure":"slipway"}},"n1819800320":{"id":"n1819800320","loc":[-85.5971006,41.9398053]},"n1819800321":{"id":"n1819800321","loc":[-85.601714,41.9406752]},"n1819800322":{"id":"n1819800322","loc":[-85.5908028,41.9453117]},"n1819800323":{"id":"n1819800323","loc":[-85.6062732,41.9404597]},"n1819800324":{"id":"n1819800324","loc":[-85.62124,41.9425905]},"n1819800327":{"id":"n1819800327","loc":[-85.6008664,41.942766]},"n1819800328":{"id":"n1819800328","loc":[-85.6179355,41.9428538]},"n1819800330":{"id":"n1819800330","loc":[-85.6045566,41.9415131]},"n1819800331":{"id":"n1819800331","loc":[-85.5944935,41.9414653]},"n1819800333":{"id":"n1819800333","loc":[-85.6088911,41.943181]},"n1819800334":{"id":"n1819800334","loc":[-85.5946367,41.943369]},"n1819800336":{"id":"n1819800336","loc":[-85.6150494,41.9429656]},"n1819800343":{"id":"n1819800343","loc":[-85.6096099,41.9433326]},"n1819800345":{"id":"n1819800345","loc":[-85.5915216,41.9435401]},"n1819800347":{"id":"n1819800347","loc":[-85.607786,41.9428698]},"n1819800349":{"id":"n1819800349","loc":[-85.6187616,41.9426623]},"n1819800350":{"id":"n1819800350","loc":[-85.6012527,41.9426064]},"n1819800352":{"id":"n1819800352","loc":[-85.6214867,41.9428379]},"n1819800354":{"id":"n1819800354","loc":[-85.61338,41.94293]},"n1819800355":{"id":"n1819800355","loc":[-85.5923156,41.9428139]},"n1819800357":{"id":"n1819800357","loc":[-85.5901591,41.9453197]},"n1819800359":{"id":"n1819800359","loc":[-85.6033979,41.9408827]},"n1819800360":{"id":"n1819800360","loc":[-85.6186543,41.9414653]},"n1819800363":{"id":"n1819800363","loc":[-85.6128607,41.9425665]},"n1819800365":{"id":"n1819800365","loc":[-85.614234,41.9412977]},"n1819800367":{"id":"n1819800367","loc":[-85.6089662,41.9410902]},"n1819800369":{"id":"n1819800369","loc":[-85.6197379,41.9413695]},"n1819800370":{"id":"n1819800370","loc":[-85.6037348,41.941733]},"n1819800371":{"id":"n1819800371","loc":[-85.5993467,41.9415654]},"n1819800372":{"id":"n1819800372","loc":[-85.598077,41.94196]},"n1819800373":{"id":"n1819800373","loc":[-85.5984203,41.9394781]},"n1819800374":{"id":"n1819800374","loc":[-85.6013315,41.9427066]},"n1819800376":{"id":"n1819800376","loc":[-85.5934673,41.944167]},"n1819800378":{"id":"n1819800378","loc":[-85.6011062,41.9407753]},"n1819800379":{"id":"n1819800379","loc":[-85.6150602,41.9415131]},"n1819800380":{"id":"n1819800380","loc":[-85.6132148,41.9412338]},"n1819800381":{"id":"n1819800381","loc":[-85.5889038,41.9453835]},"n2139966621":{"id":"n2139966621","loc":[-85.6198719,41.9426184]},"n2139966622":{"id":"n2139966622","loc":[-85.6197551,41.9426123]},"n2139966623":{"id":"n2139966623","loc":[-85.6196467,41.9426279]},"n2139966624":{"id":"n2139966624","loc":[-85.6191519,41.9426221]},"n2139966625":{"id":"n2139966625","loc":[-85.6194153,41.9426256]},"n2139966626":{"id":"n2139966626","loc":[-85.6200497,41.9425812]},"n2139966629":{"id":"n2139966629","loc":[-85.6192123,41.9426229]},"n2203933101":{"id":"n2203933101","loc":[-85.6030009,41.9360592]},"w17967539":{"id":"w17967539","tags":{"highway":"residential","name":"1st Ave"},"nodes":["n185965099","n185963395","n185987021"]},"w17967751":{"id":"w17967751","tags":{"highway":"residential","name":"River St"},"nodes":["n185980088","n185988961","n185988963","n185963698"]},"w17965088":{"id":"w17965088","tags":{"highway":"residential","name":"9th St"},"nodes":["n185945133","n185964320","n185964322","n185964324","n185964326","n185964328","n185964329","n185964330","n185964331"]},"w17964467":{"id":"w17964467","tags":{"highway":"residential","name":"Mechanic St"},"nodes":["n185958030","n185958032","n185958034","n185958036"]},"w134150842":{"id":"w134150842","tags":{"bridge":"yes","highway":"residential","name":"6th St"},"nodes":["n185980090","n185980093"]},"w17966740":{"id":"w17966740","tags":{"highway":"residential","name":"6th St"},"nodes":["n185977754","n185980075","n185980077","n185980078","n185980079","n185980081","n185980083","n185980085","n185958034","n185980088","n185980090"]},"w170844765":{"id":"w170844765","tags":{"waterway":"dam"},"nodes":["n1819800304","n1819800232","n1819800325","n1819800188"]},"w17967745":{"id":"w17967745","tags":{"highway":"residential","name":"River St"},"nodes":["n185981173","n185967077","n185963099","n185958498","n185988943","n185964331","n185975332"]},"w17968113":{"id":"w17968113","tags":{"highway":"residential","name":"Green St"},"nodes":["n185988943","n185991378"]},"w134150833":{"id":"w134150833","tags":{"highway":"residential","name":"6th St"},"nodes":["n185980093","n1475283999","n185963392"]},"w17967935":{"id":"w17967935","tags":{"name":"Michigan Central Railroad","railway":"abandoned"},"nodes":["n185972757","n185990192","n185990194","n185990195","n185990196","n185990198","n185990200","n185990202","n185990204","n185990206","n185990209","n185952239","n185990211","n185990212","n185990213","n185990214","n2203933101","n185973251"]},"w17965993":{"id":"w17965993","tags":{"name":"Conrail Railroad","railway":"abandoned"},"nodes":["n185957831","n185972752","n185972754","n185972756","n185972757"]},"w17966211":{"id":"w17966211","tags":{"highway":"residential","name":"8th St"},"nodes":["n185975315","n185975316","n185954490","n185945395","n185975317","n185974509","n185945135","n185975318","n185961186","n185967634","n185975320","n185970833","n185958036","n185975325","n185975326","n185975327","n185975328","n185975330","n185975332"]},"w170844766":{"id":"w170844766","tags":{"waterway":"riverbank"},"nodes":["n1819800229","n1819800245","n2139966626","n2139966621","n2139966622","n2139966623","n1819800319","n2139966625","n2139966629","n2139966624","n1819800349","n1819800328","n1819800291","n1819800206","n1819800237","n1819800336","n1819800318","n1819800354","n1819800182","n1819800363","n1819800297","n1819800268","n1819800223","n1819800209","n1819800233","n1819800201","n1819800343","n1819800333","n1819800347","n1819800299","n1819800228","n1819800330","n1819800370","n1819800250","n1819800374","n1819800202","n1819800327","n1819800350","n1819800308","n1819800239","n1819800207","n1819800234","n1819800359","n1819800236","n1819800321","n1819800378","n1819800235","n1819800371","n1819800313","n1819800372","n1819800219","n1819800251","n1819800334","n1819800316","n1819800376","n1819800240","n1819800312","n1819800314","n1819800243","n1819800269","n1819800279","n1819800242","n1819800315","n1819800247","n1819800191","n1819800189","n1819800263","n1819800238","n1819800277","n1819800180","n1819800381","n1819800276","n1819800357","n1819800287","n1819800322","n1819800246","n1819800345","n1819800226","n1819800355","n1819800306","n1819800290","n1819800331","n1819800289","n1819800214","n1819800320","n1819800224","n1819800373","n1819800244","n1819800184","n1819800301","n1819800292","n1819800323","n1819800181","n1819800256","n1819800293","n1819800367","n1819800311","n1819800260","n1819800185","n1819800303","n1819800274","n1819800380","n1819800365","n1819800379","n1819800255","n1819800264","n1819800186","n1819800183","n1819800317","n1819800211","n1819800241","n1819800360","n1819800258","n1819800369","n1819800296","n1819800288","n1819800310","n1819800204","n1819800375","n1819800216","n1819800377","n1819800248","n1819800227","n1819800368","n1819800231","n1819800188","n1819800325","n1819800232","n1819800304","n1819800271","n1819800213","n1819800266","n1819800221","n1819800294","n1819800362","n1819800199","n1819800230","n1819800218","n1819800352","n1819800324","n1819800272","n1819800261","n1819800229"]},"n1875654132":{"id":"n1875654132","loc":[-85.6297439,41.939808]},"n1475293263":{"id":"n1475293263","loc":[-85.6296235,41.939922]},"n185947850":{"id":"n185947850","loc":[-85.631594,41.942613]},"n185952745":{"id":"n185952745","loc":[-85.630986,41.941786]},"n185972907":{"id":"n185972907","loc":[-85.631797,41.9420055]},"n185972911":{"id":"n185972911","loc":[-85.6309723,41.9411623]},"n185972915":{"id":"n185972915","loc":[-85.6295971,41.939267]},"n1475293223":{"id":"n1475293223","loc":[-85.6313962,41.9416114],"tags":{"railway":"level_crossing"}},"n1475293231":{"id":"n1475293231","loc":[-85.6318779,41.9415447]},"n1475293241":{"id":"n1475293241","loc":[-85.6304613,41.9405499]},"n1475293246":{"id":"n1475293246","loc":[-85.6297512,41.9395393],"tags":{"railway":"level_crossing"}},"n1475293251":{"id":"n1475293251","loc":[-85.6316633,41.9415128]},"n2139982404":{"id":"n2139982404","loc":[-85.6313283,41.9413748]},"n2139982407":{"id":"n2139982407","loc":[-85.6325545,41.9417787]},"n2139982408":{"id":"n2139982408","loc":[-85.6324499,41.9417693]},"n2139982409":{"id":"n2139982409","loc":[-85.6324753,41.9416444]},"n2139982410":{"id":"n2139982410","loc":[-85.6325814,41.9416538]},"n2139982411":{"id":"n2139982411","loc":[-85.6319572,41.9413515]},"n2139982412":{"id":"n2139982412","loc":[-85.6322925,41.941139]},"n2139982413":{"id":"n2139982413","loc":[-85.6323153,41.941153]},"n2139982414":{"id":"n2139982414","loc":[-85.6323019,41.9412617]},"n2139982415":{"id":"n2139982415","loc":[-85.6323703,41.9412667]},"n2139982416":{"id":"n2139982416","loc":[-85.6323555,41.941538]},"n2139982417":{"id":"n2139982417","loc":[-85.6321343,41.9416777]},"n2139982418":{"id":"n2139982418","loc":[-85.6319425,41.9416866]},"n2139982419":{"id":"n2139982419","loc":[-85.6320303,41.9416941]},"n2139982420":{"id":"n2139982420","loc":[-85.6321665,41.9415554]},"n2139982421":{"id":"n2139982421","loc":[-85.632412,41.9414164]},"n2139982422":{"id":"n2139982422","loc":[-85.6324801,41.9413421]},"n2139982423":{"id":"n2139982423","loc":[-85.6325023,41.9412585]},"n2139982424":{"id":"n2139982424","loc":[-85.6324532,41.9411607]},"n2139982425":{"id":"n2139982425","loc":[-85.6323502,41.941103]},"n2139982426":{"id":"n2139982426","loc":[-85.6322362,41.9411183]},"n2139982427":{"id":"n2139982427","loc":[-85.6318941,41.9413551]},"n2139982428":{"id":"n2139982428","loc":[-85.6318592,41.9414105]},"n2139982429":{"id":"n2139982429","loc":[-85.6320111,41.9415866]},"n2139982430":{"id":"n2139982430","loc":[-85.632446,41.9413792]},"n2139982431":{"id":"n2139982431","loc":[-85.6325112,41.941416]},"n2139982432":{"id":"n2139982432","loc":[-85.6325449,41.9416345]},"n2139982433":{"id":"n2139982433","loc":[-85.6326122,41.94164]},"n2139982434":{"id":"n2139982434","loc":[-85.6325954,41.9421966]},"n2139982435":{"id":"n2139982435","loc":[-85.6325655,41.9422411]},"n2139982436":{"id":"n2139982436","loc":[-85.632515,41.9422564]},"n2139982437":{"id":"n2139982437","loc":[-85.6324495,41.94223]},"n2139982438":{"id":"n2139982438","loc":[-85.6324009,41.9421743]},"n2139982439":{"id":"n2139982439","loc":[-85.6323915,41.9421145]},"n2139982440":{"id":"n2139982440","loc":[-85.6320287,41.9418585]},"n2139982441":{"id":"n2139982441","loc":[-85.6318285,41.9416387]},"n1475293258":{"id":"n1475293258","loc":[-85.6318289,41.9415077]},"n2168544754":{"id":"n2168544754","loc":[-85.6312814,41.9431198]},"n2168544755":{"id":"n2168544755","loc":[-85.6314212,41.9430646]},"n2168544756":{"id":"n2168544756","loc":[-85.6313387,41.942949]},"n2168544757":{"id":"n2168544757","loc":[-85.6311989,41.9430041]},"n2168544758":{"id":"n2168544758","loc":[-85.6311024,41.9429313]},"n2168544759":{"id":"n2168544759","loc":[-85.6310087,41.9428087]},"n2168544760":{"id":"n2168544760","loc":[-85.6313831,41.9426504]},"n2168544761":{"id":"n2168544761","loc":[-85.6314768,41.9427729]},"n2168544762":{"id":"n2168544762","loc":[-85.6306376,41.942809]},"n2168544763":{"id":"n2168544763","loc":[-85.6307378,41.9429427]},"n2168544764":{"id":"n2168544764","loc":[-85.630841,41.9428998]},"n2168544765":{"id":"n2168544765","loc":[-85.6307408,41.9427662]},"n2168544766":{"id":"n2168544766","loc":[-85.6305404,41.9426029]},"n2168544767":{"id":"n2168544767","loc":[-85.6304976,41.9426194]},"n2168544768":{"id":"n2168544768","loc":[-85.6305673,41.9427184]},"n2168544769":{"id":"n2168544769","loc":[-85.6306164,41.9426984]},"n2168544770":{"id":"n2168544770","loc":[-85.6306418,41.9427302]},"n2168544771":{"id":"n2168544771","loc":[-85.6306861,41.9427137]},"n2168544772":{"id":"n2168544772","loc":[-85.6307146,41.9427537]},"n2168544773":{"id":"n2168544773","loc":[-85.6308999,41.9426807]},"n2168544774":{"id":"n2168544774","loc":[-85.6308429,41.9426053]},"n2168544775":{"id":"n2168544775","loc":[-85.6308999,41.9425806]},"n2168544776":{"id":"n2168544776","loc":[-85.6308318,41.9424875]},"n2168544777":{"id":"n2168544777","loc":[-85.6307732,41.9425087]},"n2168544778":{"id":"n2168544778","loc":[-85.6307178,41.9424357]},"n2168544779":{"id":"n2168544779","loc":[-85.630485,41.942524]},"n2189099387":{"id":"n2189099387","loc":[-85.631203,41.9393371]},"n2189099404":{"id":"n2189099404","loc":[-85.6301963,41.9391363]},"n2189099405":{"id":"n2189099405","loc":[-85.6304447,41.9391352]},"n2189099406":{"id":"n2189099406","loc":[-85.6304463,41.9393391]},"n2189099407":{"id":"n2189099407","loc":[-85.6308435,41.9393373]},"n2189099408":{"id":"n2189099408","loc":[-85.6308418,41.9391251]},"n2189099409":{"id":"n2189099409","loc":[-85.6310929,41.939124]},"n2189099410":{"id":"n2189099410","loc":[-85.6310946,41.9393376]},"n2189112720":{"id":"n2189112720","loc":[-85.6314677,41.9412327]},"n2189112721":{"id":"n2189112721","loc":[-85.6313337,41.9411397]},"n2189112722":{"id":"n2189112722","loc":[-85.6320521,41.9405678]},"n2189112723":{"id":"n2189112723","loc":[-85.6321899,41.9406633]},"n2189112724":{"id":"n2189112724","loc":[-85.6313229,41.9408344]},"n2189112725":{"id":"n2189112725","loc":[-85.6311223,41.9410018]},"n2189112726":{"id":"n2189112726","loc":[-85.6313205,41.9411333]},"n2189112727":{"id":"n2189112727","loc":[-85.6315211,41.9409659]},"n2189112728":{"id":"n2189112728","loc":[-85.6311035,41.9402529]},"n2189112729":{"id":"n2189112729","loc":[-85.631226,41.9402107]},"n2189112730":{"id":"n2189112730","loc":[-85.6315966,41.9408051]},"n2189112731":{"id":"n2189112731","loc":[-85.6314741,41.9408473]},"n2189112732":{"id":"n2189112732","loc":[-85.6318114,41.940534]},"n2189112733":{"id":"n2189112733","loc":[-85.631588,41.94061]},"n2189112734":{"id":"n2189112734","loc":[-85.6314379,41.940366]},"n2189112735":{"id":"n2189112735","loc":[-85.6316613,41.94029]},"n2189112736":{"id":"n2189112736","loc":[-85.6306214,41.9400415]},"n2189112737":{"id":"n2189112737","loc":[-85.6304362,41.9397728]},"n2189112738":{"id":"n2189112738","loc":[-85.6305899,41.9397142]},"n2189112739":{"id":"n2189112739","loc":[-85.6307751,41.9399828]},"n2189112740":{"id":"n2189112740","loc":[-85.6304695,41.9401673]},"n2189112741":{"id":"n2189112741","loc":[-85.6301298,41.9396855]},"n2189112742":{"id":"n2189112742","loc":[-85.6303016,41.9396184]},"n2189112743":{"id":"n2189112743","loc":[-85.6306413,41.9401003]},"n2189112744":{"id":"n2189112744","loc":[-85.6309656,41.9406189]},"n2189112745":{"id":"n2189112745","loc":[-85.6308738,41.940493]},"n2189112746":{"id":"n2189112746","loc":[-85.6309333,41.940469]},"n2189112747":{"id":"n2189112747","loc":[-85.6307634,41.9402358]},"n2189112748":{"id":"n2189112748","loc":[-85.6308798,41.9401889]},"n2189112749":{"id":"n2189112749","loc":[-85.6311416,41.940548]},"n2189112750":{"id":"n2189112750","loc":[-85.6309577,41.9408708]},"n2189112751":{"id":"n2189112751","loc":[-85.630874,41.9407777]},"n2189112752":{"id":"n2189112752","loc":[-85.6310622,41.9406841]},"n2189112753":{"id":"n2189112753","loc":[-85.6311459,41.9407772]},"n2189112754":{"id":"n2189112754","loc":[-85.6320308,41.9405747]},"n2189112755":{"id":"n2189112755","loc":[-85.6317769,41.9401857]},"n2189112756":{"id":"n2189112756","loc":[-85.6313462,41.9401785]},"n2189112757":{"id":"n2189112757","loc":[-85.6313423,41.9401199]},"n2189112758":{"id":"n2189112758","loc":[-85.6318308,41.9401184]},"n2189112759":{"id":"n2189112759","loc":[-85.6321154,41.9405433]},"n2189112760":{"id":"n2189112760","loc":[-85.6310307,41.941683]},"n2189112761":{"id":"n2189112761","loc":[-85.6309808,41.9416078]},"n2189112762":{"id":"n2189112762","loc":[-85.6312094,41.9415156]},"n2189112763":{"id":"n2189112763","loc":[-85.6312636,41.9415865]},"n2189112764":{"id":"n2189112764","loc":[-85.6309384,41.94155]},"n2189112765":{"id":"n2189112765","loc":[-85.631156,41.9414619]},"n2189112766":{"id":"n2189112766","loc":[-85.6311968,41.94152]},"n2189112767":{"id":"n2189112767","loc":[-85.6308946,41.9414851]},"n2189112768":{"id":"n2189112768","loc":[-85.6308237,41.9413888]},"n2189112769":{"id":"n2189112769","loc":[-85.6309858,41.9413228]},"n2189112770":{"id":"n2189112770","loc":[-85.6310567,41.9414192]},"n2189112771":{"id":"n2189112771","loc":[-85.6307774,41.9413276]},"n2189112772":{"id":"n2189112772","loc":[-85.6309068,41.9412735]},"n2189112773":{"id":"n2189112773","loc":[-85.6309531,41.9413347]},"n2189112774":{"id":"n2189112774","loc":[-85.6307975,41.9412466]},"n2189112775":{"id":"n2189112775","loc":[-85.6307006,41.9411699]},"n2189112776":{"id":"n2189112776","loc":[-85.6308289,41.941113]},"n2189112777":{"id":"n2189112777","loc":[-85.6308997,41.9412012]},"n2189112778":{"id":"n2189112778","loc":[-85.630765,41.9412062]},"n2189112779":{"id":"n2189112779","loc":[-85.630739,41.9412177]},"n2189112780":{"id":"n2189112780","loc":[-85.6305822,41.9410391]},"n2189112781":{"id":"n2189112781","loc":[-85.6304117,41.9408177]},"n2189112782":{"id":"n2189112782","loc":[-85.6305086,41.9407769]},"n2189112783":{"id":"n2189112783","loc":[-85.6306779,41.9410044]},"n2189112784":{"id":"n2189112784","loc":[-85.6307734,41.9421663]},"n2189112785":{"id":"n2189112785","loc":[-85.630708,41.9420741]},"n2189112786":{"id":"n2189112786","loc":[-85.630863,41.9420133]},"n2189112787":{"id":"n2189112787","loc":[-85.6309285,41.9421055]},"n2189112788":{"id":"n2189112788","loc":[-85.6307014,41.9420263]},"n2189112789":{"id":"n2189112789","loc":[-85.6306648,41.941971]},"n2189112790":{"id":"n2189112790","loc":[-85.6307927,41.9419178]},"n2189112791":{"id":"n2189112791","loc":[-85.6308366,41.9419696]},"n2189112792":{"id":"n2189112792","loc":[-85.6307574,41.9418708]},"n2189112793":{"id":"n2189112793","loc":[-85.6306288,41.9419231]},"n2189112794":{"id":"n2189112794","loc":[-85.6306943,41.9417835]},"n2189112795":{"id":"n2189112795","loc":[-85.6305344,41.9418474]},"n2189112796":{"id":"n2189112796","loc":[-85.6305981,41.9419355]},"n2189123410":{"id":"n2189123410","loc":[-85.6315476,41.9393801]},"n2189123412":{"id":"n2189123412","loc":[-85.6315247,41.9399188]},"n2189123415":{"id":"n2189123415","loc":[-85.6316484,41.9400433]},"n185945138":{"id":"n185945138","loc":[-85.627073,41.93319]},"n185945142":{"id":"n185945142","loc":[-85.6296891,41.9331674]},"n185945401":{"id":"n185945401","loc":[-85.6269,41.930199]},"n185945405":{"id":"n185945405","loc":[-85.6296598,41.9301676]},"n185956891":{"id":"n185956891","loc":[-85.6251617,41.9255049]},"n185959979":{"id":"n185959979","loc":[-85.626333,41.928347]},"n185959983":{"id":"n185959983","loc":[-85.6296419,41.9283288]},"n185961192":{"id":"n185961192","loc":[-85.627053,41.9352031]},"n185961200":{"id":"n185961200","loc":[-85.6297088,41.9351902]},"n185963655":{"id":"n185963655","loc":[-85.6296112,41.9273948]},"n185963665":{"id":"n185963665","loc":[-85.626047,41.92737]},"n185963688":{"id":"n185963688","loc":[-85.6296503,41.9292199]},"n185963689":{"id":"n185963689","loc":[-85.6296694,41.931157]},"n185963690":{"id":"n185963690","loc":[-85.6296791,41.9321485]},"n185963691":{"id":"n185963691","loc":[-85.6296991,41.9341973]},"n185967638":{"id":"n185967638","loc":[-85.627089,41.9361884]},"n185972917":{"id":"n185972917","loc":[-85.6293759,41.9388605]},"n185972919":{"id":"n185972919","loc":[-85.6290337,41.9380234]},"n185972921":{"id":"n185972921","loc":[-85.628424,41.936212]},"n185972923":{"id":"n185972923","loc":[-85.628367,41.936029]},"n185974511":{"id":"n185974511","loc":[-85.627064,41.932169]},"n185977728":{"id":"n185977728","loc":[-85.625605,41.925842]},"n185977729":{"id":"n185977729","loc":[-85.625685,41.926163]},"n185977731":{"id":"n185977731","loc":[-85.6257845,41.9264872]},"n185977733":{"id":"n185977733","loc":[-85.62663,41.929251]},"n185977734":{"id":"n185977734","loc":[-85.627008,41.930642]},"n185977736":{"id":"n185977736","loc":[-85.627029,41.930775]},"n185977738":{"id":"n185977738","loc":[-85.627041,41.930946]},"n185977739":{"id":"n185977739","loc":[-85.6270379,41.9311746]},"n185977742":{"id":"n185977742","loc":[-85.627055,41.934206]},"n185977744":{"id":"n185977744","loc":[-85.627084,41.936804]},"n185977746":{"id":"n185977746","loc":[-85.627104,41.936914]},"n185977748":{"id":"n185977748","loc":[-85.627156,41.937026]},"n185977750":{"id":"n185977750","loc":[-85.6272406,41.9371672]},"n185977752":{"id":"n185977752","loc":[-85.627317,41.93723]},"n185977753":{"id":"n185977753","loc":[-85.627422,41.937312]},"n185977755":{"id":"n185977755","loc":[-85.627754,41.937504]},"n185977757":{"id":"n185977757","loc":[-85.627883,41.937623]},"n185977761":{"id":"n185977761","loc":[-85.627984,41.93773]},"n1475283996":{"id":"n1475283996","loc":[-85.6270514,41.9317122],"tags":{"railway":"level_crossing"}},"n1475284004":{"id":"n1475284004","loc":[-85.6278177,41.9342117],"tags":{"railway":"level_crossing"}},"n1475284014":{"id":"n1475284014","loc":[-85.6251877,41.9255913],"tags":{"railway":"level_crossing"}},"n1475284017":{"id":"n1475284017","loc":[-85.6274992,41.9331816],"tags":{"railway":"level_crossing"}},"n1475284021":{"id":"n1475284021","loc":[-85.6297108,41.9353939],"tags":{"railway":"level_crossing"}},"n1475284027":{"id":"n1475284027","loc":[-85.62811,41.935198],"tags":{"railway":"level_crossing"}},"n1475284035":{"id":"n1475284035","loc":[-85.626888,41.9311757],"tags":{"railway":"level_crossing"}},"n1475293245":{"id":"n1475293245","loc":[-85.6286047,41.9367881]},"n1875654302":{"id":"n1875654302","loc":[-85.6296367,41.927491]},"n2189099388":{"id":"n2189099388","loc":[-85.6312007,41.9389988]},"n2189099389":{"id":"n2189099389","loc":[-85.6311003,41.9389992]},"n2189099390":{"id":"n2189099390","loc":[-85.6310988,41.9387847]},"n2189099391":{"id":"n2189099391","loc":[-85.6312165,41.9387843]},"n2189099392":{"id":"n2189099392","loc":[-85.6312152,41.9385857]},"n2189099393":{"id":"n2189099393","loc":[-85.6310877,41.9385862]},"n2189099394":{"id":"n2189099394","loc":[-85.6310858,41.9383161]},"n2189099395":{"id":"n2189099395","loc":[-85.6302002,41.9383196]},"n2189099396":{"id":"n2189099396","loc":[-85.6302011,41.9384472]},"n2189099397":{"id":"n2189099397","loc":[-85.6301018,41.9384476]},"n2189099398":{"id":"n2189099398","loc":[-85.6301025,41.9385419]},"n2189099399":{"id":"n2189099399","loc":[-85.6299275,41.9385427]},"n2189099400":{"id":"n2189099400","loc":[-85.62993,41.9388653]},"n2189099401":{"id":"n2189099401","loc":[-85.630107,41.9388645]},"n2189099402":{"id":"n2189099402","loc":[-85.6301079,41.9389908]},"n2189099403":{"id":"n2189099403","loc":[-85.6301951,41.9389904]},"n2189123382":{"id":"n2189123382","loc":[-85.6336279,41.9354365]},"n2189123384":{"id":"n2189123384","loc":[-85.6328492,41.9355177]},"n2189123387":{"id":"n2189123387","loc":[-85.6323762,41.9357396]},"n2189123388":{"id":"n2189123388","loc":[-85.6315174,41.9358966]},"n2189123389":{"id":"n2189123389","loc":[-85.6304331,41.936124]},"n2189123390":{"id":"n2189123390","loc":[-85.6302075,41.9364271]},"n2189123391":{"id":"n2189123391","loc":[-85.6303458,41.9367953]},"n2189123392":{"id":"n2189123392","loc":[-85.6299601,41.9369739]},"n2189123393":{"id":"n2189123393","loc":[-85.6299164,41.9374882]},"n2189123394":{"id":"n2189123394","loc":[-85.6299455,41.9378022]},"n2189123395":{"id":"n2189123395","loc":[-85.6299771,41.9379053]},"n2189123396":{"id":"n2189123396","loc":[-85.6301597,41.9379091]},"n2189123397":{"id":"n2189123397","loc":[-85.6308042,41.9377913]},"n2189123398":{"id":"n2189123398","loc":[-85.6316885,41.9378082]},"n2189123399":{"id":"n2189123399","loc":[-85.6316848,41.9380079]},"n2189123400":{"id":"n2189123400","loc":[-85.6318449,41.9381161]},"n2189123401":{"id":"n2189123401","loc":[-85.6320705,41.9381811]},"n2189123402":{"id":"n2189123402","loc":[-85.6321433,41.9383706]},"n2189123404":{"id":"n2189123404","loc":[-85.632056,41.9384355]},"n2189123406":{"id":"n2189123406","loc":[-85.6317867,41.9384572]},"n2189123409":{"id":"n2189123409","loc":[-85.6316572,41.9387281]},"n2189123417":{"id":"n2189123417","loc":[-85.6315946,41.93775]},"n2189123419":{"id":"n2189123419","loc":[-85.6302641,41.9378393]},"w208640158":{"id":"w208640158","tags":{"area":"yes","natural":"wetland"},"nodes":["n2189123379","n2189123382","n2189123384","n2189123387","n2189123388","n2189123389","n2189123390","n2189123391","n2189123392","n2189123393","n2189123394","n2189123395","n2189123396","n2189123419","n2189123397","n2189123417","n2189123398","n2189123399","n2189123400","n2189123401","n2189123402","n2189123404","n2189123406","n2189123409","n2189123410","n2189123412","n2189123415","n1819805722","n1819805861","n1819805887","n1819805760","n1819805641","n1819805632","n2189123379"]},"w134150787":{"id":"w134150787","tags":{"name":"Conrail Railroad","railway":"rail"},"nodes":["n185972905","n185972907","n1475293223","n185972911","n1475293241","n1475293246","n185972915","n185972917","n185972919","n1475293245","n185972921","n185972923","n1475284027","n1475284004","n1475284017","n1475283996","n1475284035","n1475284014","n185956891"]},"w208639443":{"id":"w208639443","tags":{"area":"yes","building":"yes"},"nodes":["n2189112720","n2189112721","n2189112722","n2189112723","n2189112720"]},"w17966462":{"id":"w17966462","tags":{"highway":"secondary","name":"South Main Street","old_ref":"US 131","ref":"M 86"},"nodes":["n185977728","n185977729","n185977731","n185963665","n185959979","n185977733","n185945401","n185977734","n185977736","n185977738","n185977739","n1475283996","n185974511","n185945138","n185977742","n185961192","n185967638","n185977744","n185977746","n185977748","n185977750","n185977752","n185977753","n185977754","n185977755","n185977757","n185977761","n185958030","n1475293263","n185963698","n185952745","n185947850","n185977762"]},"w203985741":{"id":"w203985741","tags":{"area":"yes","leisure":"park","name":"Conservation Park"},"nodes":["n2139982404","n2139982405","n2139982399","n2139982400","n1819805770","n2139982402","n2139982403","n2139982401","n1819805780","n1819805834","n2139982406","n2139982404"]},"w17963676":{"id":"w17963676","tags":{"highway":"service"},"nodes":["n1475293258","n2139982428","n2139982427","n2139982426","n2139982425","n2139982424","n2139982423","n2139982422","n2139982430","n2139982421","n2139982420","n2139982429","n1475293231","n1475293258","n1475293251","n1475293223","n185952745"]},"w203985745":{"id":"w203985745","tags":{"highway":"footway"},"nodes":["n2139982430","n2139982431","n2139982432","n2139982433","n2139982434","n2139982435","n2139982436","n2139982437","n2139982438","n2139982439","n2139982440","n2139982441","n1475293231"]},"w208639451":{"id":"w208639451","tags":{"area":"yes","building":"yes"},"nodes":["n2189112754","n2189112755","n2189112756","n2189112757","n2189112758","n2189112759","n2189112754"]},"w208639452":{"id":"w208639452","tags":{"area":"yes","building":"yes"},"nodes":["n2189112760","n2189112761","n2189112766","n2189112762","n2189112763","n2189112760"]},"w206805244":{"id":"w206805244","tags":{"area":"yes","building":"yes"},"nodes":["n2168544766","n2168544767","n2168544768","n2168544769","n2168544770","n2168544771","n2168544772","n2168544773","n2168544774","n2168544775","n2168544776","n2168544777","n2168544778","n2168544779","n2168544766"]},"w208639444":{"id":"w208639444","tags":{"area":"yes","building":"yes"},"nodes":["n2189112724","n2189112725","n2189112726","n2189112727","n2189112724"]},"w208639450":{"id":"w208639450","tags":{"area":"yes","building":"yes"},"nodes":["n2189112750","n2189112751","n2189112752","n2189112753","n2189112750"]},"w208639448":{"id":"w208639448","tags":{"area":"yes","building":"yes"},"nodes":["n2189112740","n2189112741","n2189112742","n2189112743","n2189112740"]},"w208637859":{"id":"w208637859","tags":{"area":"yes","building":"yes"},"nodes":["n2189099387","n2189099388","n2189099389","n2189099390","n2189099391","n2189099392","n2189099393","n2189099394","n2189099395","n2189099396","n2189099397","n2189099398","n2189099399","n2189099400","n2189099401","n2189099402","n2189099403","n2189099404","n2189099405","n2189099406","n2189099407","n2189099408","n2189099409","n2189099410","n2189099387"]},"w208639453":{"id":"w208639453","tags":{"area":"yes","building":"yes"},"nodes":["n2189112764","n2189112765","n2189112766","n2189112761","n2189112764"]},"w208639456":{"id":"w208639456","tags":{"area":"yes","building":"yes"},"nodes":["n2189112774","n2189112778","n2189112779","n2189112775","n2189112776","n2189112777","n2189112774"]},"w208639445":{"id":"w208639445","tags":{"area":"yes","building":"yes"},"nodes":["n2189112728","n2189112729","n2189112730","n2189112731","n2189112728"]},"w17967776":{"id":"w17967776","tags":{"highway":"residential","name":"5th St"},"nodes":["n185958032","n185988963"]},"w208639461":{"id":"w208639461","tags":{"area":"yes","building":"yes"},"nodes":["n2189112792","n2189112794","n2189112795","n2189112796","n2189112793","n2189112792"]},"w206805241":{"id":"w206805241","tags":{"area":"yes","building":"yes"},"nodes":["n2168544754","n2168544755","n2168544756","n2168544757","n2168544754"]},"w208639449":{"id":"w208639449","tags":{"area":"yes","building":"yes"},"nodes":["n2189112744","n2189112745","n2189112746","n2189112747","n2189112748","n2189112749","n2189112744"]},"w208639455":{"id":"w208639455","tags":{"area":"yes","building":"yes"},"nodes":["n2189112771","n2189112772","n2189112773","n2189112768","n2189112771"]},"w208639457":{"id":"w208639457","tags":{"area":"yes","building":"yes"},"nodes":["n2189112780","n2189112781","n2189112782","n2189112783","n2189112780"]},"w208639446":{"id":"w208639446","tags":{"area":"yes","building":"yes"},"nodes":["n2189112732","n2189112733","n2189112734","n2189112735","n2189112732"]},"w208639454":{"id":"w208639454","tags":{"area":"yes","building":"yes"},"nodes":["n2189112767","n2189112768","n2189112773","n2189112769","n2189112770","n2189112767"]},"w203985743":{"id":"w203985743","tags":{"amenity":"parking","area":"yes"},"nodes":["n2139982411","n2139982412","n2139982413","n2139982414","n2139982415","n2139982416","n2139982417","n2139982419","n2139982418","n2139982411"]},"w17965023":{"id":"w17965023","tags":{"highway":"residential","name":"4th St"},"nodes":["n185963655","n1875654302","n185959983","n185963688","n185945405","n185963689","n185963690","n185945142","n185963691","n185961200","n1475284021","n1475293246","n1875654132","n1475293263"]},"w206805242":{"id":"w206805242","tags":{"area":"yes","building":"yes"},"nodes":["n2168544758","n2168544759","n2168544760","n2168544761","n2168544758"]},"w208639460":{"id":"w208639460","tags":{"area":"yes","building":"yes"},"nodes":["n2189112792","n2189112793","n2189112789","n2189112790","n2189112792"]},"w208639447":{"id":"w208639447","tags":{"area":"yes","building":"yes"},"nodes":["n2189112736","n2189112737","n2189112738","n2189112739","n2189112736"]},"w208639458":{"id":"w208639458","tags":{"area":"yes","building":"yes"},"nodes":["n2189112784","n2189112785","n2189112786","n2189112787","n2189112784"]},"w203985744":{"id":"w203985744","tags":{"highway":"service"},"nodes":["n2139982425","n2139982400"]},"w208639459":{"id":"w208639459","tags":{"area":"yes","building":"yes"},"nodes":["n2189112788","n2189112789","n2189112790","n2189112791","n2189112788"]},"w203985742":{"id":"w203985742","tags":{"amenity":"shelter","area":"yes","shelter_type":"picnic_shelter"},"nodes":["n2139982407","n2139982408","n2139982409","n2139982410","n2139982407"]},"w206805243":{"id":"w206805243","tags":{"area":"yes","building":"yes"},"nodes":["n2168544762","n2168544763","n2168544764","n2168544765","n2168544762"]},"n185959081":{"id":"n185959081","loc":[-85.628469,41.948674]},"n185967427":{"id":"n185967427","loc":[-85.632054,41.951174]},"n185967424":{"id":"n185967424","loc":[-85.6320391,41.9499109]},"n185968101":{"id":"n185968101","loc":[-85.6308395,41.9511969]},"n185960792":{"id":"n185960792","loc":[-85.632074,41.953707]},"n185961389":{"id":"n185961389","loc":[-85.630935,41.959037]},"n185961391":{"id":"n185961391","loc":[-85.632169,41.959025]},"n185965395":{"id":"n185965395","loc":[-85.63216,41.959859]},"n185966953":{"id":"n185966953","loc":[-85.630894,41.957428]},"n185966955":{"id":"n185966955","loc":[-85.632122,41.957427]},"n185967430":{"id":"n185967430","loc":[-85.632077,41.952453]},"n185967432":{"id":"n185967432","loc":[-85.632095,41.954685]},"n185967434":{"id":"n185967434","loc":[-85.632121,41.955914]},"n185967436":{"id":"n185967436","loc":[-85.632128,41.9583]},"n185967438":{"id":"n185967438","loc":[-85.632187,41.960681]},"n185967440":{"id":"n185967440","loc":[-85.632182,41.961493]},"n185968102":{"id":"n185968102","loc":[-85.630855,41.952452]},"n185968104":{"id":"n185968104","loc":[-85.630887,41.953714]},"n185968106":{"id":"n185968106","loc":[-85.630883,41.954692]},"n185968108":{"id":"n185968108","loc":[-85.630904,41.955913]},"n185968110":{"id":"n185968110","loc":[-85.630904,41.958058]},"n185968112":{"id":"n185968112","loc":[-85.630952,41.960667]},"n185968114":{"id":"n185968114","loc":[-85.630972,41.961495]},"n185968116":{"id":"n185968116","loc":[-85.630962,41.961967]},"n185978969":{"id":"n185978969","loc":[-85.633214,41.948618]},"n185985812":{"id":"n185985812","loc":[-85.633274,41.951159]},"n185986155":{"id":"n185986155","loc":[-85.633258,41.949893]},"n2208608826":{"id":"n2208608826","loc":[-85.6339222,41.9486225]},"w17964531":{"id":"w17964531","tags":{"highway":"residential","name":"Willow Dr"},"nodes":["n185959079","n185959081"]},"w17967386":{"id":"w17967386","tags":{"highway":"residential","name":"East Armitage Street"},"nodes":["n185982195","n185968101","n185967427","n185985812","n185974583"]},"w17965502":{"id":"w17965502","tags":{"highway":"residential","name":"Elm Street"},"nodes":["n185968100","n185968101","n185968102","n185968104","n185968106","n185968108","n185966953","n185968110","n185961389","n185968112","n185968114","n185968116"]},"w17967844":{"id":"w17967844","tags":{"highway":"residential","name":"East Bennett Street"},"nodes":["n185982193","n185967424","n185986155","n185978390"]},"w17966581":{"id":"w17966581","tags":{"highway":"residential","name":"E Kelsey St"},"nodes":["n185978967","n185978969","n2208608826","n185971578"]},"w17965402":{"id":"w17965402","tags":{"highway":"residential","name":"Walnut Street"},"nodes":["n185967422","n185967424","n185967427","n185967430","n185960792","n185967432","n185967434","n185966955","n185967436","n185961391","n185965395","n185967438","n185967440"]},"n2199093506":{"id":"n2199093506","loc":[-85.6251879,41.9478322]},"n2199093505":{"id":"n2199093505","loc":[-85.6252076,41.9477749]},"n2199093504":{"id":"n2199093504","loc":[-85.6252289,41.9477602]},"n2199093503":{"id":"n2199093503","loc":[-85.625201,41.9477492]},"n2199093502":{"id":"n2199093502","loc":[-85.6251682,41.9477066]},"n2199093501":{"id":"n2199093501","loc":[-85.6251715,41.947609]},"n2199093500":{"id":"n2199093500","loc":[-85.6252125,41.9475639]},"n2199093499":{"id":"n2199093499","loc":[-85.6252896,41.9475602]},"n2199093498":{"id":"n2199093498","loc":[-85.6253027,41.9475334]},"n2199093497":{"id":"n2199093497","loc":[-85.6253437,41.9474822]},"n2199093496":{"id":"n2199093496","loc":[-85.6254421,41.9474675]},"n2199093495":{"id":"n2199093495","loc":[-85.6256503,41.9474944]},"n2199093494":{"id":"n2199093494","loc":[-85.6257257,41.9476127]},"n2199093493":{"id":"n2199093493","loc":[-85.6257028,41.9477285]},"n2199093492":{"id":"n2199093492","loc":[-85.6255339,41.9478102]},"n2199093491":{"id":"n2199093491","loc":[-85.6253912,41.9478224]},"n2199093490":{"id":"n2199093490","loc":[-85.6253043,41.947859]},"n2199093489":{"id":"n2199093489","loc":[-85.6252027,41.9478846]},"n2199093458":{"id":"n2199093458","loc":[-85.6246876,41.9486617]},"n2199093457":{"id":"n2199093457","loc":[-85.6243127,41.9486583]},"n2199093456":{"id":"n2199093456","loc":[-85.624306,41.9490569]},"n2199093455":{"id":"n2199093455","loc":[-85.624681,41.9490603]},"n2199093514":{"id":"n2199093514","loc":[-85.6236228,41.9496059]},"n2199093513":{"id":"n2199093513","loc":[-85.6236231,41.9496997]},"n2199093512":{"id":"n2199093512","loc":[-85.623357,41.9497002]},"n2199093511":{"id":"n2199093511","loc":[-85.6233567,41.9496136]},"n2199093508":{"id":"n2199093508","loc":[-85.6239735,41.9494287]},"n2199093507":{"id":"n2199093507","loc":[-85.6239741,41.9496052]},"n2199093488":{"id":"n2199093488","loc":[-85.624497,41.9512286]},"n2199093487":{"id":"n2199093487","loc":[-85.6244966,41.9511259]},"n2199093486":{"id":"n2199093486","loc":[-85.6243151,41.9511263]},"n2199093485":{"id":"n2199093485","loc":[-85.6243154,41.951229]},"n2199093484":{"id":"n2199093484","loc":[-85.6241205,41.9508665]},"n2199093483":{"id":"n2199093483","loc":[-85.624115,41.9505249]},"n2199093482":{"id":"n2199093482","loc":[-85.6243149,41.9505231]},"n2199093481":{"id":"n2199093481","loc":[-85.6243203,41.9508648]},"n2199093480":{"id":"n2199093480","loc":[-85.624393,41.9508668]},"n2199093479":{"id":"n2199093479","loc":[-85.6243904,41.9505956]},"n2199093478":{"id":"n2199093478","loc":[-85.6246727,41.950594]},"n2199093477":{"id":"n2199093477","loc":[-85.624675,41.9508203]},"n2199093476":{"id":"n2199093476","loc":[-85.6245097,41.9508212]},"n2199093475":{"id":"n2199093475","loc":[-85.6245101,41.9508662]},"n2199093474":{"id":"n2199093474","loc":[-85.6241008,41.9493459]},"n2199093473":{"id":"n2199093473","loc":[-85.6242442,41.9493459]},"n2199093472":{"id":"n2199093472","loc":[-85.6242442,41.9493681]},"n2199093471":{"id":"n2199093471","loc":[-85.6243397,41.9493681]},"n2199093470":{"id":"n2199093470","loc":[-85.6243417,41.9493511]},"n2199093469":{"id":"n2199093469","loc":[-85.6247251,41.9493485]},"n2199093468":{"id":"n2199093468","loc":[-85.6247548,41.9504949]},"n2199093467":{"id":"n2199093467","loc":[-85.6241214,41.9505017]},"n2199093466":{"id":"n2199093466","loc":[-85.6254398,41.950174]},"n2199093465":{"id":"n2199093465","loc":[-85.6254412,41.9499872]},"n2199093464":{"id":"n2199093464","loc":[-85.6255363,41.9499876]},"n2199093463":{"id":"n2199093463","loc":[-85.6255374,41.9498439]},"n2199093462":{"id":"n2199093462","loc":[-85.6255638,41.949844]},"n2199093461":{"id":"n2199093461","loc":[-85.6255652,41.9496672]},"n2199093460":{"id":"n2199093460","loc":[-85.6251823,41.9496656]},"n2199093459":{"id":"n2199093459","loc":[-85.6251785,41.9501729]},"n2199093510":{"id":"n2199093510","loc":[-85.6229922,41.9496143]},"n2199093509":{"id":"n2199093509","loc":[-85.6229915,41.9494306]},"n185948903":{"id":"n185948903","loc":[-85.616514,41.947449]},"n185955120":{"id":"n185955120","loc":[-85.620103,41.951]},"n185955143":{"id":"n185955143","loc":[-85.619784,41.94746]},"n185960124":{"id":"n185960124","loc":[-85.615238,41.947468]},"n185961362":{"id":"n185961362","loc":[-85.617437,41.947451]},"n185961364":{"id":"n185961364","loc":[-85.61861,41.947456]},"n185961367":{"id":"n185961367","loc":[-85.620088,41.947458]},"n185965105":{"id":"n185965105","loc":[-85.620087,41.94924]},"n185970220":{"id":"n185970220","loc":[-85.62156,41.948333]},"n185974697":{"id":"n185974697","loc":[-85.6201059,41.950132]},"n2138420778":{"id":"n2138420778","loc":[-85.616948,41.9474499]},"w17967535":{"id":"w17967535","tags":{"highway":"residential","name":"10th Ave"},"nodes":["n185955120","n185986812","n185983141"]},"w209716130":{"id":"w209716130","tags":{"area":"yes","building":"yes"},"nodes":["n2199093485","n2199093486","n2199093487","n2199093488","n2199093485"]},"w17964788":{"id":"w17964788","tags":{"highway":"residential","name":"6th Ave"},"nodes":["n185960124","n185948903","n2138420778","n185961362","n185961364","n185955143","n185961367","n185961369","n185961371"]},"w17965159":{"id":"w17965159","tags":{"highway":"residential","name":"8th Ave"},"nodes":["n185965105","n185965108","n185965110"]},"w209716125":{"id":"w209716125","tags":{"area":"yes","building":"yes"},"nodes":["n2199093459","n2199093460","n2199093461","n2199093462","n2199093463","n2199093464","n2199093465","n2199093466","n2199093459"]},"w17965699":{"id":"w17965699","tags":{"highway":"residential","name":"7th Ave"},"nodes":["n185970220","n185970222","n185970224"]},"w209716132":{"id":"w209716132","tags":{"area":"yes","building":"yes"},"nodes":["n2199093507","n2199093508","n2199093509","n2199093510","n2199093511","n2199093512","n2199093513","n2199093514","n2199093507"]},"w17966129":{"id":"w17966129","tags":{"highway":"residential","name":"9th Ave"},"nodes":["n185974697","n185974699"]},"w209716127":{"id":"w209716127","tags":{"area":"yes","building":"yes"},"nodes":["n2199093475","n2199093476","n2199093477","n2199093478","n2199093479","n2199093480","n2199093475"]},"w209716131":{"id":"w209716131","tags":{"area":"yes","natural":"water","water":"pond"},"nodes":["n2199093489","n2199093490","n2199093491","n2199093492","n2199093493","n2199093494","n2199093495","n2199093496","n2199093497","n2199093498","n2199093499","n2199093500","n2199093501","n2199093502","n2199093503","n2199093504","n2199093505","n2199093506","n2199093489"]},"w209716126":{"id":"w209716126","tags":{"area":"yes","building":"yes"},"nodes":["n2199093467","n2199093468","n2199093469","n2199093470","n2199093471","n2199093472","n2199093473","n2199093474","n2199093467"]},"w209716124":{"id":"w209716124","tags":{"area":"yes","building":"yes"},"nodes":["n2199093455","n2199093456","n2199093457","n2199093458","n2199093455"]},"w209716128":{"id":"w209716128","tags":{"area":"yes","building":"yes"},"nodes":["n2199093481","n2199093482","n2199093483","n2199093484","n2199093481"]},"n185949872":{"id":"n185949872","loc":[-85.643009,41.949264]},"n185949875":{"id":"n185949875","loc":[-85.642598,41.94929]},"n185949877":{"id":"n185949877","loc":[-85.642127,41.949382]},"n185949881":{"id":"n185949881","loc":[-85.64169,41.949936]},"n185988165":{"id":"n185988165","loc":[-85.642167,41.947657]},"n185988167":{"id":"n185988167","loc":[-85.642347,41.947662]},"n185988169":{"id":"n185988169","loc":[-85.642621,41.947659]},"n185965019":{"id":"n185965019","loc":[-85.6385084,41.951127]},"n1475293248":{"id":"n1475293248","loc":[-85.6386095,41.9512214]},"n185962639":{"id":"n185962639","loc":[-85.649669,41.949161]},"n185962810":{"id":"n185962810","loc":[-85.649907,41.949157]},"n185964355":{"id":"n185964355","loc":[-85.637412,41.9511359]},"n185965021":{"id":"n185965021","loc":[-85.638661,41.952386]},"n185965023":{"id":"n185965023","loc":[-85.638654,41.953665]},"n185965025":{"id":"n185965025","loc":[-85.638694,41.954649]},"n185965027":{"id":"n185965027","loc":[-85.638724,41.955913]},"n185971415":{"id":"n185971415","loc":[-85.644466,41.949246]},"n185971417":{"id":"n185971417","loc":[-85.647021,41.949193]},"n185971420":{"id":"n185971420","loc":[-85.648476,41.949169]},"n185979975":{"id":"n185979975","loc":[-85.644429,41.947633]},"n185988171":{"id":"n185988171","loc":[-85.645377,41.947622]},"w17963211":{"id":"w17963211","tags":{"highway":"residential"},"nodes":["n185949870","n185949872","n185949875","n185949877","n185949881"]},"w17965839":{"id":"w17965839","tags":{"highway":"residential","name":"Arnold St"},"nodes":["n185949870","n185971415","n185971417","n185971420","n185962639","n185962810"]},"w17967618":{"id":"w17967618","tags":{"highway":"residential","name":"Pierson St"},"nodes":["n185967777","n185988165","n185988167","n185988169","n185985824","n185979975","n185988171"]},"w17965149":{"id":"w17965149","tags":{"highway":"residential","name":"Oak St"},"nodes":["n185965019","n1475293248","n185965021","n185965023","n185965025","n185965027"]},"w17966118":{"id":"w17966118","tags":{"highway":"residential","name":"West Armitage Street"},"nodes":["n185974583","n185974585","n185964355","n185965019"]},"n2208608800":{"id":"n2208608800","loc":[-85.6354294,41.9486201]},"n2199109806":{"id":"n2199109806","loc":[-85.6350474,41.9477884]},"n2199109804":{"id":"n2199109804","loc":[-85.6350476,41.9477962]},"n2199109802":{"id":"n2199109802","loc":[-85.635002,41.9477969]},"n2199109799":{"id":"n2199109799","loc":[-85.6350018,41.9477883]},"n2199109797":{"id":"n2199109797","loc":[-85.6349141,41.9477897]},"n2199109795":{"id":"n2199109795","loc":[-85.6349131,41.9477535]},"n2199109793":{"id":"n2199109793","loc":[-85.6349395,41.9477531]},"n2199109791":{"id":"n2199109791","loc":[-85.6349382,41.9477077]},"n2199109789":{"id":"n2199109789","loc":[-85.6351236,41.9477049]},"n2199109787":{"id":"n2199109787","loc":[-85.6351259,41.9477872]},"n2199109785":{"id":"n2199109785","loc":[-85.634972,41.9475992]},"n2199109783":{"id":"n2199109783","loc":[-85.6349206,41.9475997]},"n2199109770":{"id":"n2199109770","loc":[-85.6348499,41.9475461]},"n2199109768":{"id":"n2199109768","loc":[-85.6348499,41.9475084]},"n2199109765":{"id":"n2199109765","loc":[-85.6349241,41.9474569]},"n2199109763":{"id":"n2199109763","loc":[-85.634967,41.9474564]},"n2199109762":{"id":"n2199109762","loc":[-85.6350405,41.9475121]},"n2199109761":{"id":"n2199109761","loc":[-85.6350405,41.9475419]},"n2199109753":{"id":"n2199109753","loc":[-85.6342443,41.9478391]},"n2199109751":{"id":"n2199109751","loc":[-85.6342427,41.9477927]},"n2199109745":{"id":"n2199109745","loc":[-85.6342439,41.9476859]},"n2199109743":{"id":"n2199109743","loc":[-85.6342429,41.9476575]},"n2199109741":{"id":"n2199109741","loc":[-85.6344615,41.9476533]},"n2199109739":{"id":"n2199109739","loc":[-85.6344678,41.9478348]},"n2199109737":{"id":"n2199109737","loc":[-85.634416,41.9480059]},"n2199109735":{"id":"n2199109735","loc":[-85.6344145,41.9478983]},"n2199109733":{"id":"n2199109733","loc":[-85.6342749,41.9478993]},"n2199109731":{"id":"n2199109731","loc":[-85.6342753,41.9479272]},"n2199109729":{"id":"n2199109729","loc":[-85.6342498,41.9479274]},"n2199109727":{"id":"n2199109727","loc":[-85.6342505,41.9479762]},"n2199109725":{"id":"n2199109725","loc":[-85.6342743,41.947976]},"n2199109723":{"id":"n2199109723","loc":[-85.6342747,41.948007]},"n2199109721":{"id":"n2199109721","loc":[-85.6343415,41.9476355]},"n2199109719":{"id":"n2199109719","loc":[-85.6343391,41.9474973]},"n2199109717":{"id":"n2199109717","loc":[-85.6343133,41.9474798]},"n2199109715":{"id":"n2199109715","loc":[-85.6342874,41.9474737]},"n2199109709":{"id":"n2199109709","loc":[-85.6349804,41.94815]},"n2199109707":{"id":"n2199109707","loc":[-85.6348915,41.9481505]},"n2199109705":{"id":"n2199109705","loc":[-85.6348917,41.9481692]},"n2199109702":{"id":"n2199109702","loc":[-85.6348522,41.9481694]},"n2199109700":{"id":"n2199109700","loc":[-85.6348532,41.9482679]},"n2199109698":{"id":"n2199109698","loc":[-85.6348315,41.948268]},"n2199109696":{"id":"n2199109696","loc":[-85.6348318,41.9482955]},"n2199109694":{"id":"n2199109694","loc":[-85.6349653,41.9482946]},"n2199109692":{"id":"n2199109692","loc":[-85.6349656,41.9483211]},"n2199109690":{"id":"n2199109690","loc":[-85.634999,41.9483209]},"n2199109688":{"id":"n2199109688","loc":[-85.6349987,41.9482947]},"n2199109686":{"id":"n2199109686","loc":[-85.6351753,41.9482935]},"n2199109684":{"id":"n2199109684","loc":[-85.6351749,41.9482617]},"n2199109682":{"id":"n2199109682","loc":[-85.6351588,41.9482618]},"n2199109680":{"id":"n2199109680","loc":[-85.6351575,41.9481518]},"n2199109678":{"id":"n2199109678","loc":[-85.6350671,41.9481524]},"n2199109676":{"id":"n2199109676","loc":[-85.6350649,41.9479659]},"n2199109674":{"id":"n2199109674","loc":[-85.6349785,41.9479665]},"n2199109671":{"id":"n2199109671","loc":[-85.6343069,41.9483263]},"n2199109669":{"id":"n2199109669","loc":[-85.6343052,41.9482981]},"n2199109658":{"id":"n2199109658","loc":[-85.6343314,41.9480549]},"n2199109656":{"id":"n2199109656","loc":[-85.6343305,41.9480461]},"n2199109654":{"id":"n2199109654","loc":[-85.634435,41.9480468]},"n2199109652":{"id":"n2199109652","loc":[-85.6344342,41.9483746]},"n2199109650":{"id":"n2199109650","loc":[-85.6344629,41.9483727]},"n2199109648":{"id":"n2199109648","loc":[-85.6344637,41.9484561]},"n2199109645":{"id":"n2199109645","loc":[-85.63443,41.9484567]},"n2199109642":{"id":"n2199109642","loc":[-85.6344317,41.948505]},"n185964352":{"id":"n185964352","loc":[-85.6373958,41.9489943]},"n185964351":{"id":"n185964351","loc":[-85.637113,41.9486]},"n2208608825":{"id":"n2208608825","loc":[-85.6354483,41.9494241]},"n2208608823":{"id":"n2208608823","loc":[-85.6360418,41.949416]},"n2208608821":{"id":"n2208608821","loc":[-85.6360458,41.9495802]},"n2208608811":{"id":"n2208608811","loc":[-85.6357458,41.9495843]},"n2208608808":{"id":"n2208608808","loc":[-85.6357508,41.9497835]},"n2208608806":{"id":"n2208608806","loc":[-85.6354573,41.9497875]},"n2208608795":{"id":"n2208608795","loc":[-85.6354595,41.9498778]},"n2199109638":{"id":"n2199109638","loc":[-85.6349605,41.949749]},"n2199109636":{"id":"n2199109636","loc":[-85.6349605,41.9497639]},"n2199109634":{"id":"n2199109634","loc":[-85.6349061,41.94971]},"n2199109632":{"id":"n2199109632","loc":[-85.6349048,41.9496569]},"n2199109630":{"id":"n2199109630","loc":[-85.6348835,41.9496571]},"n2199109628":{"id":"n2199109628","loc":[-85.6348829,41.9497103]},"n2199109626":{"id":"n2199109626","loc":[-85.635227,41.9497738]},"n2199109624":{"id":"n2199109624","loc":[-85.6352184,41.9497787]},"n2199109622":{"id":"n2199109622","loc":[-85.6351181,41.9497806]},"n2199109620":{"id":"n2199109620","loc":[-85.6351181,41.9497456]},"n2199109618":{"id":"n2199109618","loc":[-85.6348842,41.9497651]},"n2199109616":{"id":"n2199109616","loc":[-85.6348827,41.9496238]},"n2199109615":{"id":"n2199109615","loc":[-85.6351268,41.9496206]},"n2199109614":{"id":"n2199109614","loc":[-85.6351261,41.9495891]},"n2199109613":{"id":"n2199109613","loc":[-85.6351957,41.9495881]},"n2199109612":{"id":"n2199109612","loc":[-85.6351924,41.9494515]},"n2199109611":{"id":"n2199109611","loc":[-85.6353997,41.9494488]},"n2199109610":{"id":"n2199109610","loc":[-85.6354074,41.9497715]},"n2189015681":{"id":"n2189015681","loc":[-85.6344229,41.9509639]},"n2189015677":{"id":"n2189015677","loc":[-85.634424,41.9507396]},"n2138493843":{"id":"n2138493843","loc":[-85.6343935,41.9502836]},"n2138493840":{"id":"n2138493840","loc":[-85.634398,41.9506264]},"n354002838":{"id":"n354002838","loc":[-85.6345197,41.9510631]},"n2114807590":{"id":"n2114807590","loc":[-85.634511,41.9499767]},"n185964353":{"id":"n185964353","loc":[-85.6374092,41.9498755]},"n1819849180":{"id":"n1819849180","loc":[-85.6348236,41.94996]},"n1819849115":{"id":"n1819849115","loc":[-85.6354372,41.9499538]},"n1819848921":{"id":"n1819848921","loc":[-85.6348439,41.951064]},"n1819848885":{"id":"n1819848885","loc":[-85.6354575,41.9510578]},"n185984281":{"id":"n185984281","loc":[-85.638075,41.949872]},"n2208608827":{"id":"n2208608827","loc":[-85.6339169,41.9473191]},"n2199109749":{"id":"n2199109749","loc":[-85.6342082,41.9477934]},"n2199109747":{"id":"n2199109747","loc":[-85.6342045,41.9476867]},"n2199109713":{"id":"n2199109713","loc":[-85.6342404,41.9474746]},"n2199109711":{"id":"n2199109711","loc":[-85.6342404,41.9476355]},"n2199109673":{"id":"n2199109673","loc":[-85.6340886,41.9483282]},"n2199109667":{"id":"n2199109667","loc":[-85.6342403,41.9482988]},"n2199109665":{"id":"n2199109665","loc":[-85.6342386,41.9482116]},"n2199109662":{"id":"n2199109662","loc":[-85.6340861,41.9482135]},"n2199109660":{"id":"n2199109660","loc":[-85.6340802,41.9480562]},"n2199109640":{"id":"n2199109640","loc":[-85.6340928,41.9485063]},"n354031366":{"id":"n354031366","loc":[-85.6341667,41.9477778],"tags":{"amenity":"place_of_worship","name":"Faith Tabernacle Church","religion":"christian"}},"n2189015686":{"id":"n2189015686","loc":[-85.6337798,41.95099]},"n2189015684":{"id":"n2189015684","loc":[-85.6337794,41.9509674]},"n2189015673":{"id":"n2189015673","loc":[-85.6337501,41.9507457]},"n2189015669":{"id":"n2189015669","loc":[-85.6337501,41.9506974]},"n2189015665":{"id":"n2189015665","loc":[-85.6339034,41.9506959]},"n2189015662":{"id":"n2189015662","loc":[-85.6339015,41.950436]},"n2189015658":{"id":"n2189015658","loc":[-85.6334916,41.9504376]},"n2189015655":{"id":"n2189015655","loc":[-85.6334939,41.9507558]},"n2189015650":{"id":"n2189015650","loc":[-85.6334543,41.950756]},"n2189015649":{"id":"n2189015649","loc":[-85.633456,41.9509915]},"n2138493842":{"id":"n2138493842","loc":[-85.6339937,41.9502836]},"n2138493841":{"id":"n2138493841","loc":[-85.6339983,41.9506281]},"n2114807579":{"id":"n2114807579","loc":[-85.6333644,41.9510682]},"n2114807573":{"id":"n2114807573","loc":[-85.6333557,41.9499819]},"n354031330":{"id":"n354031330","loc":[-85.6341667,41.9497222],"tags":{"amenity":"place_of_worship","name":"Trinity Episcopal Church","religion":"christian"}},"n185960794":{"id":"n185960794","loc":[-85.633307,41.9537]},"n185964357":{"id":"n185964357","loc":[-85.637432,41.952399]},"n185964358":{"id":"n185964358","loc":[-85.637452,41.953665]},"n185964359":{"id":"n185964359","loc":[-85.63746,41.954658]},"n185964360":{"id":"n185964360","loc":[-85.637473,41.95592]},"n185964361":{"id":"n185964361","loc":[-85.637468,41.956906]},"n185964362":{"id":"n185964362","loc":[-85.637483,41.958313]},"n185966957":{"id":"n185966957","loc":[-85.633361,41.957422]},"n185975351":{"id":"n185975351","loc":[-85.63334,41.9559]},"n185978784":{"id":"n185978784","loc":[-85.633311,41.954679]},"n185986157":{"id":"n185986157","loc":[-85.633287,41.952426]},"n185986158":{"id":"n185986158","loc":[-85.6333607,41.9582301],"tags":{"highway":"turning_circle"}},"w17965182":{"id":"w17965182","tags":{"highway":"residential","name":"W Prutzman St"},"nodes":["n185965289","n2189153241","n185965291"]},"w208627205":{"id":"w208627205","tags":{"area":"yes","building":"yes"},"nodes":["n2189015649","n2189015650","n2189015655","n2189015658","n2189015662","n2189015665","n2189015669","n2189015673","n2189015677","n2189015681","n2189015684","n2189015686","n2189015649"]},"w209717042":{"id":"w209717042","tags":{"amenity":"place_of_worship","area":"yes","building":"yes","denomination":"presbyterian","name":"First Presbyterian Church","religion":"christian"},"nodes":["n2199109610","n2199109611","n2199109612","n2199109613","n2199109614","n2199109615","n2199109616","n2199109630","n2199109632","n2199109634","n2199109628","n2199109618","n2199109636","n2199109638","n2199109620","n2199109622","n2199109624","n2199109626","n2199109610"]},"w209717045":{"id":"w209717045","tags":{"area":"yes","building":"yes"},"nodes":["n2199109711","n2199109713","n2199109715","n2199109717","n2199109719","n2199109721","n2199109711"]},"w209717047":{"id":"w209717047","tags":{"area":"yes","building":"yes"},"nodes":["n2199109739","n2199109741","n2199109743","n2199109745","n2199109747","n2199109749","n2199109751","n2199109753","n2199109739"]},"w209717044":{"id":"w209717044","tags":{"area":"yes","building":"yes"},"nodes":["n2199109674","n2199109676","n2199109678","n2199109680","n2199109682","n2199109684","n2199109686","n2199109688","n2199109690","n2199109692","n2199109694","n2199109696","n2199109698","n2199109700","n2199109702","n2199109705","n2199109707","n2199109709","n2199109674"]},"w210822776":{"id":"w210822776","tags":{"highway":"service","service":"alley","surface":"unpaved"},"nodes":["n2208608795","n2208608806","n2208608825","n2208608800","n2189153241"]},"w210822778":{"id":"w210822778","tags":{"highway":"service","service":"alley"},"nodes":["n2208608826","n2208608827"]},"w209717050":{"id":"w209717050","tags":{"area":"yes","building":"yes"},"nodes":["n2199109787","n2199109789","n2199109791","n2199109793","n2199109795","n2199109797","n2199109799","n2199109802","n2199109804","n2199109806","n2199109787"]},"w17965097":{"id":"w17965097","tags":{"highway":"residential","name":"Maple Street"},"nodes":["n185964351","n185964352","n185964353","n185964355","n185964357","n185964358","n185964359","n185964360","n185964361","n185964362"]},"w17965856":{"id":"w17965856","tags":{"highway":"residential","name":"W Kelsey St"},"nodes":["n185971578","n2208608800","n185971580","n185964351"]},"w17967444":{"id":"w17967444","tags":{"highway":"residential","name":"East Street"},"nodes":["n185966937","n185978969","n185986155","n185985812","n185986157","n185960794","n185978784","n185975351","n185966957","n185986158"]},"w17967764":{"id":"w17967764","tags":{"highway":"residential","name":"Rock River Ave"},"nodes":["n185984017","n185964351"]},"w170848329":{"id":"w170848329","tags":{"leisure":"park","name":"LaFayette Park"},"nodes":["n1819849180","n1819849115","n1819848885","n1819848921","n1819849180"]},"w17967208":{"id":"w17967208","tags":{"highway":"residential","name":"West Bennett Street"},"nodes":["n185978390","n2208608795","n185984020","n185964353","n185984281"]},"w17965349":{"id":"w17965349","tags":{"highway":"residential","name":"E Prutzman St"},"nodes":["n185966937","n2208608827","n185965289"]},"w209717049":{"id":"w209717049","tags":{"area":"yes","building":"yes"},"nodes":["n2199109761","n2199109762","n2199109763","n2199109765","n2199109768","n2199109770","n2199109783","n2199109785","n2199109761"]},"w203841840":{"id":"w203841840","tags":{"area":"yes","leisure":"playground"},"nodes":["n2138493840","n2138493841","n2138493842","n2138493843","n2138493840"]},"w209717043":{"id":"w209717043","tags":{"amenity":"place_of_worship","area":"yes","building":"church","denomination":"methodist","name":"First United Methodist Church","religion":"christian"},"nodes":["n2199109640","n2199109642","n2199109645","n2199109648","n2199109650","n2199109652","n2199109654","n2199109656","n2199109658","n2199109660","n2199109662","n2199109665","n2199109667","n2199109669","n2199109671","n2199109673","n2199109640"]},"w201484341":{"id":"w201484341","tags":{"amenity":"school","name":"Hoppin School"},"nodes":["n354002838","n2114807579","n2114807573","n2114807590","n354002838"]},"w209717046":{"id":"w209717046","tags":{"area":"yes","building":"yes"},"nodes":["n2199109723","n2199109725","n2199109727","n2199109729","n2199109731","n2199109733","n2199109735","n2199109737","n2199109723"]},"w210822777":{"id":"w210822777","tags":{"amenity":"parking","area":"yes"},"nodes":["n2208608806","n2208608808","n2208608811","n2208608821","n2208608823","n2208608825","n2208608806"]},"n185954965":{"id":"n185954965","loc":[-85.6191189,41.9441922]},"n185954968":{"id":"n185954968","loc":[-85.6194384,41.9442405]},"n185954970":{"id":"n185954970","loc":[-85.6196543,41.9443252]},"n185954972":{"id":"n185954972","loc":[-85.6197862,41.9444539]},"n354002931":{"id":"n354002931","loc":[-85.6198991,41.9455269]},"n354030853":{"id":"n354030853","loc":[-85.6219444,41.9455556],"tags":{"amenity":"place_of_worship","name":"Grant Chapel","religion":"christian"}},"n367815963":{"id":"n367815963","loc":[-85.6202778,41.9461111],"tags":{"building":"yes","name":"George Washington Carver Community Center"}},"n185947331":{"id":"n185947331","loc":[-85.618779,41.943269]},"n185947333":{"id":"n185947333","loc":[-85.618795,41.943511]},"n185947336":{"id":"n185947336","loc":[-85.618711,41.94413]},"n185947338":{"id":"n185947338","loc":[-85.618704,41.944189]},"n185947339":{"id":"n185947339","loc":[-85.618597,41.944337]},"n185947340":{"id":"n185947340","loc":[-85.618485,41.944528]},"n185947343":{"id":"n185947343","loc":[-85.618442,41.944716]},"n185947345":{"id":"n185947345","loc":[-85.618457,41.945107]},"n185947347":{"id":"n185947347","loc":[-85.618296,41.945338]},"n185947374":{"id":"n185947374","loc":[-85.616748,41.944453]},"n185947375":{"id":"n185947375","loc":[-85.616813,41.944646]},"n185947376":{"id":"n185947376","loc":[-85.616859,41.945196]},"n185947377":{"id":"n185947377","loc":[-85.616941,41.945352]},"n185947406":{"id":"n185947406","loc":[-85.618184,41.944227]},"n185947409":{"id":"n185947409","loc":[-85.617911,41.943875]},"n185947410":{"id":"n185947410","loc":[-85.617579,41.943682]},"n185947411":{"id":"n185947411","loc":[-85.61713,41.943589]},"n185947412":{"id":"n185947412","loc":[-85.616549,41.943559]},"n185947414":{"id":"n185947414","loc":[-85.616482,41.943556]},"n185947464":{"id":"n185947464","loc":[-85.616526,41.943788]},"n185947466":{"id":"n185947466","loc":[-85.616504,41.944002]},"n185948863":{"id":"n185948863","loc":[-85.619017,41.943391]},"n185948865":{"id":"n185948865","loc":[-85.619059,41.943368]},"n185955022":{"id":"n185955022","loc":[-85.620088,41.945571]},"n185955025":{"id":"n185955025","loc":[-85.620051,41.945505]},"n185955028":{"id":"n185955028","loc":[-85.62001,41.94541]},"n185980371":{"id":"n185980371","loc":[-85.620982,41.944742]},"n185980398":{"id":"n185980398","loc":[-85.621305,41.944782]},"n185980401":{"id":"n185980401","loc":[-85.621174,41.944819]},"n185980403":{"id":"n185980403","loc":[-85.621029,41.944871]},"n185980405":{"id":"n185980405","loc":[-85.620741,41.945011]},"n185980407":{"id":"n185980407","loc":[-85.620616,41.945085]},"n185980409":{"id":"n185980409","loc":[-85.620506,41.945172]},"n185980411":{"id":"n185980411","loc":[-85.620394,41.945273]},"n185980413":{"id":"n185980413","loc":[-85.620316,41.94536]},"n185980415":{"id":"n185980415","loc":[-85.620257,41.945452]},"n185980417":{"id":"n185980417","loc":[-85.620212,41.945535]},"n185985910":{"id":"n185985910","loc":[-85.620101,41.945811]},"n185985912":{"id":"n185985912","loc":[-85.620081,41.945937]},"n1475283972":{"id":"n1475283972","loc":[-85.6198991,41.9437179]},"n1475283982":{"id":"n1475283982","loc":[-85.6195022,41.9433463]},"n1475284007":{"id":"n1475284007","loc":[-85.6193037,41.9433383]},"n1475284040":{"id":"n1475284040","loc":[-85.6197329,41.9434121]},"n1475284044":{"id":"n1475284044","loc":[-85.6198756,41.9435363]},"n1475284050":{"id":"n1475284050","loc":[-85.6199689,41.9432106]},"n1475284053":{"id":"n1475284053","loc":[-85.6198943,41.9432921]},"n185954974":{"id":"n185954974","loc":[-85.6198296,41.94473]},"n185954977":{"id":"n185954977","loc":[-85.6200474,41.9447384]},"n2196831365":{"id":"n2196831365","loc":[-85.6202259,41.9460883]},"n2196831366":{"id":"n2196831366","loc":[-85.6202245,41.9458642]},"n2196831367":{"id":"n2196831367","loc":[-85.6205184,41.9458631]},"n2196831368":{"id":"n2196831368","loc":[-85.6205189,41.9459437]},"n2196831369":{"id":"n2196831369","loc":[-85.6203879,41.9459441]},"n2196831370":{"id":"n2196831370","loc":[-85.6203888,41.9460878]},"n2196831371":{"id":"n2196831371","loc":[-85.6184046,41.9465663]},"n2196831372":{"id":"n2196831372","loc":[-85.6191563,41.9465618]},"n2196831373":{"id":"n2196831373","loc":[-85.6191536,41.946319]},"n2196831374":{"id":"n2196831374","loc":[-85.6187356,41.9463216]},"n2196831375":{"id":"n2196831375","loc":[-85.6187334,41.9461197]},"n2196831376":{"id":"n2196831376","loc":[-85.6193167,41.9461162]},"n2196831377":{"id":"n2196831377","loc":[-85.6193156,41.9460229]},"n2196831378":{"id":"n2196831378","loc":[-85.619622,41.946021]},"n2196831379":{"id":"n2196831379","loc":[-85.6196237,41.9461712]},"n2196831380":{"id":"n2196831380","loc":[-85.6197702,41.9461703]},"n2196831381":{"id":"n2196831381","loc":[-85.6197685,41.9460202]},"n2196831382":{"id":"n2196831382","loc":[-85.6197323,41.9460204]},"n2196831383":{"id":"n2196831383","loc":[-85.6197305,41.9458563]},"n2196831384":{"id":"n2196831384","loc":[-85.6196165,41.945857]},"n2196831385":{"id":"n2196831385","loc":[-85.6196156,41.9457764]},"n2196831386":{"id":"n2196831386","loc":[-85.6194472,41.9457775]},"n2196831387":{"id":"n2196831387","loc":[-85.6194151,41.9457777]},"n2196831388":{"id":"n2196831388","loc":[-85.6183779,41.9457883]},"n2196831389":{"id":"n2196831389","loc":[-85.6183842,41.9461317]},"n2196831390":{"id":"n2196831390","loc":[-85.6185026,41.9461304]},"n2196831391":{"id":"n2196831391","loc":[-85.6185061,41.9463194]},"n2196831392":{"id":"n2196831392","loc":[-85.6184001,41.9463205]},"n2196831393":{"id":"n2196831393","loc":[-85.6182482,41.9464163]},"n2196831394":{"id":"n2196831394","loc":[-85.6182467,41.9463193]},"n2196831395":{"id":"n2196831395","loc":[-85.6180389,41.946321]},"n2196831397":{"id":"n2196831397","loc":[-85.6180404,41.946418]},"n185947303":{"id":"n185947303","loc":[-85.611074,41.943389]},"n185947304":{"id":"n185947304","loc":[-85.611332,41.943267]},"n185947305":{"id":"n185947305","loc":[-85.611635,41.943218]},"n185947306":{"id":"n185947306","loc":[-85.612762,41.943311]},"n185947308":{"id":"n185947308","loc":[-85.613027,41.943327]},"n185947310":{"id":"n185947310","loc":[-85.615377,41.942996]},"n185947312":{"id":"n185947312","loc":[-85.615701,41.943007]},"n185947314":{"id":"n185947314","loc":[-85.61604,41.943067]},"n185947315":{"id":"n185947315","loc":[-85.61626,41.943083]},"n185947316":{"id":"n185947316","loc":[-85.616507,41.943048]},"n185947319":{"id":"n185947319","loc":[-85.616702,41.94299]},"n185947321":{"id":"n185947321","loc":[-85.617078,41.942918]},"n185947322":{"id":"n185947322","loc":[-85.617366,41.942973]},"n185947323":{"id":"n185947323","loc":[-85.617601,41.943033]},"n185947325":{"id":"n185947325","loc":[-85.617799,41.943027]},"n185947327":{"id":"n185947327","loc":[-85.618264,41.942961]},"n185947328":{"id":"n185947328","loc":[-85.618508,41.942972]},"n185947329":{"id":"n185947329","loc":[-85.618707,41.943076]},"n185947361":{"id":"n185947361","loc":[-85.615356,41.944922]},"n185947363":{"id":"n185947363","loc":[-85.61536,41.944893]},"n185947365":{"id":"n185947365","loc":[-85.615406,41.944547]},"n185947367":{"id":"n185947367","loc":[-85.61548,41.944351]},"n185947369":{"id":"n185947369","loc":[-85.615805,41.94419]},"n185947371":{"id":"n185947371","loc":[-85.616166,41.944156]},"n185947373":{"id":"n185947373","loc":[-85.616411,41.944197]},"n185947416":{"id":"n185947416","loc":[-85.616335,41.94343]},"n185947417":{"id":"n185947417","loc":[-85.616069,41.943293]},"n185947419":{"id":"n185947419","loc":[-85.615803,41.943249]},"n185947420":{"id":"n185947420","loc":[-85.615524,41.943342]},"n185947421":{"id":"n185947421","loc":[-85.615311,41.94353]},"n185947422":{"id":"n185947422","loc":[-85.614338,41.943558]},"n185947423":{"id":"n185947423","loc":[-85.61422,41.94369]},"n185947425":{"id":"n185947425","loc":[-85.614221,41.944224]},"n185947427":{"id":"n185947427","loc":[-85.614198,41.944888]},"n185947429":{"id":"n185947429","loc":[-85.614221,41.945439]},"n185947468":{"id":"n185947468","loc":[-85.615908,41.944756]},"n185947470":{"id":"n185947470","loc":[-85.615871,41.944888]},"n185947472":{"id":"n185947472","loc":[-85.615878,41.94507]},"n185955153":{"id":"n185955153","loc":[-85.620087,41.947701]},"n185960690":{"id":"n185960690","loc":[-85.620141,41.951901]},"n185978817":{"id":"n185978817","loc":[-85.617193,41.954706]},"n185985916":{"id":"n185985916","loc":[-85.620088,41.94758]},"n185985918":{"id":"n185985918","loc":[-85.620133,41.951538]},"n185985919":{"id":"n185985919","loc":[-85.62013,41.952104]},"n185985920":{"id":"n185985920","loc":[-85.620104,41.952305]},"n185985921":{"id":"n185985921","loc":[-85.620062,41.952499]},"n185985922":{"id":"n185985922","loc":[-85.619993,41.952702]},"n185985925":{"id":"n185985925","loc":[-85.619879,41.952986]},"n185985927":{"id":"n185985927","loc":[-85.619689,41.95329]},"n185985928":{"id":"n185985928","loc":[-85.619508,41.953521]},"n185985929":{"id":"n185985929","loc":[-85.619286,41.953728]},"n185985930":{"id":"n185985930","loc":[-85.618925,41.954007]},"n185985931":{"id":"n185985931","loc":[-85.618638,41.954189]},"n185985932":{"id":"n185985932","loc":[-85.61831,41.954358]},"n185985934":{"id":"n185985934","loc":[-85.618015,41.954485]},"n185985936":{"id":"n185985936","loc":[-85.617606,41.954611]},"n1475283975":{"id":"n1475283975","loc":[-85.6150935,41.9434118]},"n1475283979":{"id":"n1475283979","loc":[-85.6193367,41.9430252]},"n1475283989":{"id":"n1475283989","loc":[-85.6104771,41.9455269]},"n1475283990":{"id":"n1475283990","loc":[-85.6104771,41.9437179]},"n1475283994":{"id":"n1475283994","loc":[-85.6198042,41.9429763]},"n1475283998":{"id":"n1475283998","loc":[-85.6192101,41.9426716]},"n1475284000":{"id":"n1475284000","loc":[-85.6198622,41.942836]},"n1475284002":{"id":"n1475284002","loc":[-85.6163262,41.9427688]},"n1475284006":{"id":"n1475284006","loc":[-85.6179527,41.9429168]},"n1475284029":{"id":"n1475284029","loc":[-85.6197195,41.9427278]},"n1475284038":{"id":"n1475284038","loc":[-85.6194405,41.9427837]},"n1475284052":{"id":"n1475284052","loc":[-85.6153225,41.942841]},"n1475284055":{"id":"n1475284055","loc":[-85.6129233,41.9437179]},"n2139966627":{"id":"n2139966627","loc":[-85.61958,41.9427558]},"w17966773":{"id":"w17966773","tags":{"highway":"secondary","name":"E Michigan Ave","ref":"M 60"},"nodes":["n185980372","n185980398","n185980401","n185980403","n185980405","n185980407","n185980409","n185980411","n185980413","n185980415","n185980417","n185955019"]},"w17964043":{"id":"w17964043","tags":{"highway":"residential"},"nodes":["n185955019","n185955022","n185955025","n185955028","n185954977","n185971477","n1475284050","n1475284000","n1475284029","n2139966627","n1475284038"]},"w17962834":{"id":"w17962834","tags":{"highway":"service"},"nodes":["n185947316","n185947414","n185947464","n185947466","n185947373","n185947468","n185947470","n185947472","n185947474"]},"w209470310":{"id":"w209470310","tags":{"area":"yes","building":"yes"},"nodes":["n2196831393","n2196831394","n2196831395","n2196831397","n2196831393"]},"w17963058":{"id":"w17963058","tags":{"highway":"service"},"nodes":["n185947333","n185948863","n185948865","n1475284007","n1475283982","n1475284040","n1475284044"]},"w17962823":{"id":"w17962823","tags":{"highway":"service"},"nodes":["n185947359","n185947361","n185947363","n185947365","n185947367","n185947369","n185947371","n185947373","n185947374","n185947375","n185947376","n185947377","n185947378"]},"w17962821":{"id":"w17962821","tags":{"highway":"service"},"nodes":["n185947303","n185947304","n185947305","n185947306","n185947308","n185947310","n185947312","n185947314","n185947315","n185947316","n185947319","n185947321","n185947322","n185947323","n185947325","n185947327","n185947328","n185947329","n185947331","n185947333","n185947336","n185947338","n185947339","n185947340","n185947343","n185947345","n185947347","n185947349"]},"w134150798":{"id":"w134150798","tags":{"amenity":"grave_yard","name":"Riverside Cemetery"},"nodes":["n354002931","n1475283972","n1475284053","n1475283994","n1475283979","n1475283998","n1475284006","n1475284002","n1475284052","n1475283975","n1475284055","n1475283990","n1475283989","n354002931"]},"w17964040":{"id":"w17964040","tags":{"highway":"service"},"nodes":["n185947336","n185954965","n185954968","n185954970","n185954972","n185954974","n185954977"]},"w209470308":{"id":"w209470308","tags":{"area":"yes","building":"yes"},"nodes":["n2196831365","n2196831366","n2196831367","n2196831368","n2196831369","n2196831370","n2196831365"]},"w17962828":{"id":"w17962828","tags":{"highway":"service"},"nodes":["n185947340","n185947406","n185947409","n185947410","n185947411","n185947412","n185947414","n185947416","n185947417","n185947419","n185947420","n185947421","n185947422","n185947423","n185947425","n185947427","n185947429"]},"w209470309":{"id":"w209470309","tags":{"area":"yes","building":"yes"},"nodes":["n2196831371","n2196831372","n2196831373","n2196831374","n2196831375","n2196831376","n2196831377","n2196831378","n2196831379","n2196831380","n2196831381","n2196831382","n2196831383","n2196831384","n2196831385","n2196831386","n2196831387","n2196831388","n2196831389","n2196831390","n2196831391","n2196831392","n2196831371"]},"w17967415":{"id":"w17967415","tags":{"highway":"secondary","name":"Jefferson St","name_1":"State Highway 60","ref":"M 60"},"nodes":["n185955019","n185985910","n185985912","n185985914","n185961367","n185985916","n185955153","n185965105","n185974697","n185955120","n185985918","n185960690","n185985919","n185985920","n185985921","n185985922","n185985925","n185985927","n185985928","n185985929","n185985930","n185985931","n185985932","n185985934","n185985936","n185978817"]},"w17966772":{"id":"w17966772","tags":{"highway":"unclassified","name":"E Michigan Ave","name_1":"State Highway 60"},"nodes":["n185954977","n185980371","n185980372"]},"n185958500":{"id":"n185958500","loc":[-85.621591,41.941075]},"n185963110":{"id":"n185963110","loc":[-85.6204416,41.9408882]},"n2139966628":{"id":"n2139966628","loc":[-85.6196431,41.9426467],"tags":{"leisure":"fishing"}},"n2139966630":{"id":"n2139966630","loc":[-85.6199354,41.9429616]},"n2199127051":{"id":"n2199127051","loc":[-85.6170556,41.939696]},"n2199127052":{"id":"n2199127052","loc":[-85.6170536,41.9392909]},"n2199127053":{"id":"n2199127053","loc":[-85.6172067,41.9392905]},"n2199127054":{"id":"n2199127054","loc":[-85.6172061,41.9391853]},"n2199127055":{"id":"n2199127055","loc":[-85.6171481,41.9391854]},"n2199127060":{"id":"n2199127060","loc":[-85.6167389,41.9392896]},"n2199127061":{"id":"n2199127061","loc":[-85.6168728,41.9392892]},"n2199127062":{"id":"n2199127062","loc":[-85.6168747,41.9396965]},"n2199127071":{"id":"n2199127071","loc":[-85.620196,41.9399446]},"n2199127072":{"id":"n2199127072","loc":[-85.620193,41.9397316]},"n2199127073":{"id":"n2199127073","loc":[-85.6200381,41.9397328]},"n2199127074":{"id":"n2199127074","loc":[-85.6200412,41.9399458]},"n2199127075":{"id":"n2199127075","loc":[-85.6203606,41.9399939]},"n2199127076":{"id":"n2199127076","loc":[-85.6205527,41.9399922]},"n2199127077":{"id":"n2199127077","loc":[-85.6205482,41.9397115]},"n2199127078":{"id":"n2199127078","loc":[-85.6204132,41.9397124]},"n2199127079":{"id":"n2199127079","loc":[-85.6204144,41.9396341]},"n2199127080":{"id":"n2199127080","loc":[-85.6205699,41.9396324]},"n2199127081":{"id":"n2199127081","loc":[-85.6205722,41.939498]},"n2199127082":{"id":"n2199127082","loc":[-85.6204064,41.9394997]},"n2199127083":{"id":"n2199127083","loc":[-85.6204087,41.939561]},"n2199127084":{"id":"n2199127084","loc":[-85.6203103,41.9395618]},"n2199127085":{"id":"n2199127085","loc":[-85.620308,41.9396069]},"n2199127086":{"id":"n2199127086","loc":[-85.6200347,41.9396086]},"n2199127087":{"id":"n2199127087","loc":[-85.6200382,41.9397141]},"n2199127088":{"id":"n2199127088","loc":[-85.6202257,41.9397149]},"n2199127089":{"id":"n2199127089","loc":[-85.6202269,41.9399182]},"n2199127090":{"id":"n2199127090","loc":[-85.6203595,41.9399199]},"n2199127091":{"id":"n2199127091","loc":[-85.6212335,41.939688]},"n2199127092":{"id":"n2199127092","loc":[-85.6212328,41.939595]},"n2199127093":{"id":"n2199127093","loc":[-85.6208807,41.9395966]},"n2199127094":{"id":"n2199127094","loc":[-85.6208815,41.9396896]},"n2199127095":{"id":"n2199127095","loc":[-85.6208676,41.9396872]},"n2199127096":{"id":"n2199127096","loc":[-85.6208583,41.9393539]},"n2199127097":{"id":"n2199127097","loc":[-85.6207006,41.9393563]},"n2199127098":{"id":"n2199127098","loc":[-85.6207099,41.9396896]},"n185967054":{"id":"n185967054","loc":[-85.6173384,41.9356126]},"n185967063":{"id":"n185967063","loc":[-85.617371,41.936243]},"n185967065":{"id":"n185967065","loc":[-85.617337,41.936299]},"n185967068":{"id":"n185967068","loc":[-85.617321,41.936373]},"n185967070":{"id":"n185967070","loc":[-85.6173562,41.9366969]},"n185967074":{"id":"n185967074","loc":[-85.6173635,41.9377414]},"n185967075":{"id":"n185967075","loc":[-85.6173696,41.9381886]},"n185967076":{"id":"n185967076","loc":[-85.617372,41.938535]},"n2199127056":{"id":"n2199127056","loc":[-85.617147,41.9389616]},"n2199127057":{"id":"n2199127057","loc":[-85.6172136,41.9389614]},"n2199127058":{"id":"n2199127058","loc":[-85.6172123,41.9386909]},"n2199127059":{"id":"n2199127059","loc":[-85.616736,41.9386922]},"n2203921041":{"id":"n2203921041","loc":[-85.6173018,41.9346369]},"w203983952":{"id":"w203983952","tags":{"highway":"service"},"nodes":["n2139966627","n1819800319"]},"w209718301":{"id":"w209718301","tags":{"area":"yes","building":"yes"},"nodes":["n2199127051","n2199127052","n2199127053","n2199127054","n2199127055","n2199127056","n2199127057","n2199127058","n2199127059","n2199127060","n2199127061","n2199127062","n2199127051"]},"w209718304":{"id":"w209718304","tags":{"area":"yes","building":"yes"},"nodes":["n2199127071","n2199127072","n2199127073","n2199127074","n2199127071"]},"w17964961":{"id":"w17964961","tags":{"highway":"residential","name":"Whipple St"},"nodes":["n185963099","n185963110"]},"w17964489":{"id":"w17964489","tags":{"highway":"residential","name":"Jackson St"},"nodes":["n185958498","n185958500"]},"w203983953":{"id":"w203983953","tags":{"area":"yes","leisure":"park","name":"Marina Park"},"nodes":["n1475283994","n1475283979","n1475283998","n2139966629","n2139966625","n1819800319","n2139966623","n2139966622","n2139966621","n2139966630","n1475283994"]},"w17965366":{"id":"w17965366","tags":{"highway":"residential","name":"14th St"},"nodes":["n2203921041","n185967054","n185967063","n185967065","n185967068","n185967070","n185967074","n185967075","n185967076","n185967077"]},"w209718306":{"id":"w209718306","tags":{"area":"yes","building":"yes"},"nodes":["n2199127091","n2199127092","n2199127093","n2199127094","n2199127091"]},"w209718307":{"id":"w209718307","tags":{"area":"yes","building":"yes"},"nodes":["n2199127095","n2199127096","n2199127097","n2199127098","n2199127095"]},"w209718305":{"id":"w209718305","tags":{"area":"yes","building":"yes"},"nodes":["n2199127075","n2199127076","n2199127077","n2199127078","n2199127079","n2199127080","n2199127081","n2199127082","n2199127083","n2199127084","n2199127085","n2199127086","n2199127087","n2199127088","n2199127089","n2199127090","n2199127075"]},"n185960199":{"id":"n185960199","loc":[-85.62965,41.95469]},"n185980737":{"id":"n185980737","loc":[-85.629083,41.953725]},"n2114807561":{"id":"n2114807561","loc":[-85.6297681,41.9524688]},"n2114807597":{"id":"n2114807597","loc":[-85.6296517,41.952563]},"n185960197":{"id":"n185960197","loc":[-85.629676,41.9537314]},"n185978791":{"id":"n185978791","loc":[-85.6244542,41.9547066]},"w17967573":{"id":"w17967573","tags":{"highway":"residential","name":"E Wheeler St"},"nodes":["n185960195","n2114807561","n185968102","n185967430","n185986157","n185978392"]},"w17966553":{"id":"w17966553","tags":{"highway":"residential","name":"East Hoffman Street"},"nodes":["n185971631","n185978784","n185967432","n185968106","n185960199","n185978787","n185978790","n185978791"]},"w17966787":{"id":"w17966787","tags":{"highway":"residential","name":"East Cushman Street"},"nodes":["n185980735","n185980737","n185960197","n185968104","n185960792"]},"w17964723":{"id":"w17964723","tags":{"highway":"residential","name":"Cushman Street"},"nodes":["n185960792","n185960794","n185960796"]},"w17964654":{"id":"w17964654","tags":{"highway":"residential","name":"Pine Street"},"nodes":["n185960195","n2114807597","n185960197","n185960199"]},"n1819848862":{"id":"n1819848862","loc":[-85.6346087,41.9545845]},"n1819848935":{"id":"n1819848935","loc":[-85.6345948,41.9537717]},"n1819848973":{"id":"n1819848973","loc":[-85.6334247,41.9537827]},"n1819848997":{"id":"n1819848997","loc":[-85.6334386,41.9545956]},"n2189015861":{"id":"n2189015861","loc":[-85.6375906,41.954836]},"n2189015865":{"id":"n2189015865","loc":[-85.6383307,41.9548291]},"n2189015867":{"id":"n2189015867","loc":[-85.6383337,41.9550072]},"n2189015868":{"id":"n2189015868","loc":[-85.6380986,41.9550094]},"n2189015869":{"id":"n2189015869","loc":[-85.6381005,41.9551226]},"n2199109808":{"id":"n2199109808","loc":[-85.6372702,41.9522894]},"n2199109810":{"id":"n2199109810","loc":[-85.6372677,41.9521583]},"n2199109812":{"id":"n2199109812","loc":[-85.6369505,41.9521617]},"n2199109814":{"id":"n2199109814","loc":[-85.636953,41.9522927]},"n185952156":{"id":"n185952156","loc":[-85.640983,41.9546557]},"n185953423":{"id":"n185953423","loc":[-85.641871,41.954652]},"n185971637":{"id":"n185971637","loc":[-85.641583,41.95465]},"n185971639":{"id":"n185971639","loc":[-85.6421344,41.9546444]},"n185971642":{"id":"n185971642","loc":[-85.6428264,41.9545612]},"n185971648":{"id":"n185971648","loc":[-85.6436023,41.9544262]},"n185975066":{"id":"n185975066","loc":[-85.640532,41.953638]},"n185975067":{"id":"n185975067","loc":[-85.64079,41.953638]},"n185982166":{"id":"n185982166","loc":[-85.6399012,41.9523817]},"n2189015858":{"id":"n2189015858","loc":[-85.6376104,41.9560138]},"n2189015870":{"id":"n2189015870","loc":[-85.6386794,41.9551172]},"n2189015871":{"id":"n2189015871","loc":[-85.6386817,41.955256]},"n2189015873":{"id":"n2189015873","loc":[-85.6385437,41.9552573]},"n2189015876":{"id":"n2189015876","loc":[-85.638555,41.9559278]},"n2189015879":{"id":"n2189015879","loc":[-85.6384954,41.9559283]},"n2189015882":{"id":"n2189015882","loc":[-85.6384965,41.9559935]},"n2189015885":{"id":"n2189015885","loc":[-85.6383533,41.9559949]},"n2189015888":{"id":"n2189015888","loc":[-85.638351,41.9558607]},"n2189015891":{"id":"n2189015891","loc":[-85.6382178,41.9558619]},"n2189015894":{"id":"n2189015894","loc":[-85.6382203,41.956008]},"w208627223":{"id":"w208627223","tags":{"area":"yes","building":"yes"},"nodes":["n2189015858","n2189015861","n2189015865","n2189015867","n2189015868","n2189015869","n2189015870","n2189015871","n2189015873","n2189015876","n2189015879","n2189015882","n2189015885","n2189015888","n2189015891","n2189015894","n2189015858"]},"w170848328":{"id":"w170848328","tags":{"leisure":"park","name":"Bowman Park"},"nodes":["n1819848935","n1819848973","n1819848997","n1819848862","n1819848935"]},"w17965866":{"id":"w17965866","tags":{"highway":"residential","name":"West Hoffman Street"},"nodes":["n185971631","n185971632","n185964359","n185965025","n1475293264","n185952156","n185971637","n185953423","n185971639","n185971642","n185971648"]},"w209717051":{"id":"w209717051","tags":{"amenity":"place_of_worship","area":"yes","building":"yes","denomination":"baptist","name":"Calvary Missionary Baptist Church","religion":"christian"},"nodes":["n2199109808","n2199109810","n2199109812","n2199109814","n2199109808"]},"w17966172":{"id":"w17966172","tags":{"highway":"residential","name":"West Cushman Street"},"nodes":["n185960796","n185975064","n185964358","n185965023","n1475293222","n185975066","n185975067"]},"w17966975":{"id":"w17966975","tags":{"highway":"residential","name":"W Wheeler St"},"nodes":["n185978392","n185982163","n185964357","n185965021","n1475293261","n185982166"]},"n185960684":{"id":"n185960684","loc":[-85.622687,41.951885]},"n185960686":{"id":"n185960686","loc":[-85.622492,41.951901]},"n185978795":{"id":"n185978795","loc":[-85.6240991,41.954708]},"n185978803":{"id":"n185978803","loc":[-85.623348,41.954547]},"n185978806":{"id":"n185978806","loc":[-85.623123,41.954502]},"n185978808":{"id":"n185978808","loc":[-85.622923,41.954469]},"n185978810":{"id":"n185978810","loc":[-85.622787,41.954457]},"n185978811":{"id":"n185978811","loc":[-85.622612,41.954458]},"n185978813":{"id":"n185978813","loc":[-85.622368,41.954472]},"n1819790545":{"id":"n1819790545","loc":[-85.6240295,41.9548949]},"n1819790621":{"id":"n1819790621","loc":[-85.6235789,41.954855]},"n1819790664":{"id":"n1819790664","loc":[-85.6238363,41.9549507]},"n1819790683":{"id":"n1819790683","loc":[-85.6224727,41.9545921]},"n1819790730":{"id":"n1819790730","loc":[-85.6227527,41.9545795]},"n1819790740":{"id":"n1819790740","loc":[-85.6240402,41.9550784]},"n1819790831":{"id":"n1819790831","loc":[-85.624126,41.9549986]},"n1819790861":{"id":"n1819790861","loc":[-85.6231712,41.9546872]},"n1819790887":{"id":"n1819790887","loc":[-85.6242762,41.955206]},"n2168544739":{"id":"n2168544739","loc":[-85.6249102,41.952801]},"n2168544740":{"id":"n2168544740","loc":[-85.6251859,41.9527564]},"n2168544741":{"id":"n2168544741","loc":[-85.6255515,41.9527921]},"n2168544742":{"id":"n2168544742","loc":[-85.626001,41.9529481]},"n2168544743":{"id":"n2168544743","loc":[-85.6265284,41.9529838]},"n2168544744":{"id":"n2168544744","loc":[-85.626942,41.9528857]},"n2168544745":{"id":"n2168544745","loc":[-85.6270918,41.9526851]},"n2168544746":{"id":"n2168544746","loc":[-85.6272117,41.95244]},"n2168544747":{"id":"n2168544747","loc":[-85.6271578,41.952226]},"n2168544748":{"id":"n2168544748","loc":[-85.6270019,41.9519719]},"n2168544749":{"id":"n2168544749","loc":[-85.6268221,41.9518382]},"n2168544750":{"id":"n2168544750","loc":[-85.6265284,41.951807]},"n2168544751":{"id":"n2168544751","loc":[-85.6256534,41.9518516]},"n2168544752":{"id":"n2168544752","loc":[-85.6253477,41.9518338]},"n2168544753":{"id":"n2168544753","loc":[-85.6251139,41.9517669]},"n185955747":{"id":"n185955747","loc":[-85.620674,41.954709]},"n185960688":{"id":"n185960688","loc":[-85.621032,41.951913]},"n185972054":{"id":"n185972054","loc":[-85.6186728,41.9547335]},"n185978814":{"id":"n185978814","loc":[-85.6201708,41.9547403]},"n1819790532":{"id":"n1819790532","loc":[-85.6244908,41.9555731]},"n1819790536":{"id":"n1819790536","loc":[-85.6217925,41.9583135]},"n1819790538":{"id":"n1819790538","loc":[-85.6233954,41.9600014]},"n1819790539":{"id":"n1819790539","loc":[-85.6204611,41.9562117]},"n1819790546":{"id":"n1819790546","loc":[-85.6210898,41.9567657]},"n1819790548":{"id":"n1819790548","loc":[-85.6202465,41.9562237]},"n1819790550":{"id":"n1819790550","loc":[-85.6250165,41.9560677]},"n1819790551":{"id":"n1819790551","loc":[-85.6227946,41.9597023]},"n1819790553":{"id":"n1819790553","loc":[-85.6215726,41.9584571]},"n1819790556":{"id":"n1819790556","loc":[-85.6196306,41.9573002]},"n1819790557":{"id":"n1819790557","loc":[-85.6209503,41.9563109]},"n1819790558":{"id":"n1819790558","loc":[-85.6196939,41.9574085]},"n1819790561":{"id":"n1819790561","loc":[-85.621079,41.957751]},"n1819790562":{"id":"n1819790562","loc":[-85.6224255,41.9611417]},"n1819790565":{"id":"n1819790565","loc":[-85.6232506,41.9604841]},"n1819790566":{"id":"n1819790566","loc":[-85.6190835,41.9562909]},"n1819790567":{"id":"n1819790567","loc":[-85.622227,41.9593028]},"n1819790569":{"id":"n1819790569","loc":[-85.620976,41.9591039]},"n1819790571":{"id":"n1819790571","loc":[-85.6212078,41.9565303]},"n1819790572":{"id":"n1819790572","loc":[-85.6235306,41.9595102]},"n1819790581":{"id":"n1819790581","loc":[-85.6235563,41.9579351]},"n1819790584":{"id":"n1819790584","loc":[-85.6230371,41.9574598]},"n1819790586":{"id":"n1819790586","loc":[-85.6211748,41.9564272]},"n1819790588":{"id":"n1819790588","loc":[-85.6226508,41.9601086]},"n1819790591":{"id":"n1819790591","loc":[-85.6218032,41.9607468]},"n1819790593":{"id":"n1819790593","loc":[-85.6207915,41.9618735]},"n1819790596":{"id":"n1819790596","loc":[-85.6252955,41.9567858]},"n1819790598":{"id":"n1819790598","loc":[-85.6196618,41.9568939]},"n1819790600":{"id":"n1819790600","loc":[-85.6224416,41.9587084]},"n1819790602":{"id":"n1819790602","loc":[-85.6217442,41.9558641]},"n1819790603":{"id":"n1819790603","loc":[-85.6213355,41.9592116]},"n1819790604":{"id":"n1819790604","loc":[-85.622801,41.9573042]},"n1819790608":{"id":"n1819790608","loc":[-85.6199729,41.9574325]},"n1819790610":{"id":"n1819790610","loc":[-85.6195555,41.9557165]},"n1819790611":{"id":"n1819790611","loc":[-85.622978,41.9586007]},"n1819790613":{"id":"n1819790613","loc":[-85.6253963,41.9562636]},"n1819790614":{"id":"n1819790614","loc":[-85.6235252,41.9580342]},"n1819790616":{"id":"n1819790616","loc":[-85.6232988,41.9596305]},"n1819790617":{"id":"n1819790617","loc":[-85.6226776,41.9598732]},"n1819790619":{"id":"n1819790619","loc":[-85.625553,41.9561794]},"n1819790620":{"id":"n1819790620","loc":[-85.6235574,41.959231]},"n1819790624":{"id":"n1819790624","loc":[-85.6228429,41.9573726]},"n1819790626":{"id":"n1819790626","loc":[-85.6193785,41.9556766]},"n1819790628":{"id":"n1819790628","loc":[-85.620092,41.9554253]},"n1819790630":{"id":"n1819790630","loc":[-85.6226658,41.9604402]},"n1819790638":{"id":"n1819790638","loc":[-85.6219964,41.9602561]},"n1819790640":{"id":"n1819790640","loc":[-85.6232731,41.9599969]},"n1819790643":{"id":"n1819790643","loc":[-85.6247698,41.9568895]},"n1819790650":{"id":"n1819790650","loc":[-85.6216412,41.9550149]},"n1819790652":{"id":"n1819790652","loc":[-85.6224952,41.9603918]},"n1819790656":{"id":"n1819790656","loc":[-85.61918,41.9555649]},"n1819790661":{"id":"n1819790661","loc":[-85.6200169,41.955505]},"n1819790662":{"id":"n1819790662","loc":[-85.6217389,41.9563149]},"n1819790666":{"id":"n1819790666","loc":[-85.6229566,41.9598373]},"n1819790667":{"id":"n1819790667","loc":[-85.6209117,41.9609189]},"n1819790669":{"id":"n1819790669","loc":[-85.6252311,41.9562353]},"n1819790670":{"id":"n1819790670","loc":[-85.6209758,41.961868]},"n1819790672":{"id":"n1819790672","loc":[-85.6209557,41.9589078]},"n1819790673":{"id":"n1819790673","loc":[-85.6190352,41.9561393]},"n1819790675":{"id":"n1819790675","loc":[-85.6236432,41.9586685]},"n1819790676":{"id":"n1819790676","loc":[-85.6194901,41.9565389]},"n1819790678":{"id":"n1819790678","loc":[-85.6219266,41.9582417]},"n1819790680":{"id":"n1819790680","loc":[-85.6208258,41.9557211]},"n1819790681":{"id":"n1819790681","loc":[-85.6212024,41.9613212]},"n1819790682":{"id":"n1819790682","loc":[-85.624877,41.9559401]},"n1819790684":{"id":"n1819790684","loc":[-85.6206499,41.9583693]},"n1819790699":{"id":"n1819790699","loc":[-85.6215243,41.956279]},"n1819790701":{"id":"n1819790701","loc":[-85.6246625,41.9559321]},"n1819790703":{"id":"n1819790703","loc":[-85.6230478,41.9585089]},"n1819790708":{"id":"n1819790708","loc":[-85.6211102,41.9575402]},"n1819790710":{"id":"n1819790710","loc":[-85.6215082,41.9548468]},"n1819790711":{"id":"n1819790711","loc":[-85.6206552,41.9586007]},"n1819790713":{"id":"n1819790713","loc":[-85.6215404,41.9549705]},"n1819790715":{"id":"n1819790715","loc":[-85.6216906,41.955521]},"n1819790717":{"id":"n1819790717","loc":[-85.6215404,41.9547391]},"n1819790722":{"id":"n1819790722","loc":[-85.6219964,41.9599131]},"n1819790723":{"id":"n1819790723","loc":[-85.622286,41.9606989]},"n1819790725":{"id":"n1819790725","loc":[-85.6228439,41.9572005]},"n1819790727":{"id":"n1819790727","loc":[-85.6202518,41.9554458]},"n1819790728":{"id":"n1819790728","loc":[-85.623434,41.9575276]},"n1819790729":{"id":"n1819790729","loc":[-85.6234287,41.9568576]},"n1819790732":{"id":"n1819790732","loc":[-85.6229566,41.9571369]},"n1819790733":{"id":"n1819790733","loc":[-85.6225543,41.9590275]},"n1819790734":{"id":"n1819790734","loc":[-85.6232892,41.9583135]},"n1819790736":{"id":"n1819790736","loc":[-85.622977,41.9608551]},"n1819790737":{"id":"n1819790737","loc":[-85.624008,41.9569533]},"n1819790741":{"id":"n1819790741","loc":[-85.6212775,41.9608545]},"n1819790742":{"id":"n1819790742","loc":[-85.6231282,41.9569932]},"n1819790743":{"id":"n1819790743","loc":[-85.6224523,41.9591831]},"n1819790744":{"id":"n1819790744","loc":[-85.6210951,41.9610819]},"n1819790745":{"id":"n1819790745","loc":[-85.6220114,41.960544]},"n1819790755":{"id":"n1819790755","loc":[-85.6216369,41.9553854]},"n1819790757":{"id":"n1819790757","loc":[-85.6209986,41.9592709]},"n1819790758":{"id":"n1819790758","loc":[-85.6200437,41.9563468]},"n1819790764":{"id":"n1819790764","loc":[-85.6219363,41.9596823]},"n1819790765":{"id":"n1819790765","loc":[-85.6237612,41.9568496]},"n1819790769":{"id":"n1819790769","loc":[-85.6212389,41.9593433]},"n1819790771":{"id":"n1819790771","loc":[-85.6210726,41.9560123]},"n1819790772":{"id":"n1819790772","loc":[-85.6212711,41.9561838]},"n1819790776":{"id":"n1819790776","loc":[-85.6234437,41.9577795]},"n1819790777":{"id":"n1819790777","loc":[-85.6212502,41.9618599]},"n1819790783":{"id":"n1819790783","loc":[-85.6216895,41.9610585]},"n1819790784":{"id":"n1819790784","loc":[-85.6200115,41.9556367]},"n1819790785":{"id":"n1819790785","loc":[-85.6210576,41.9573002]},"n1819790786":{"id":"n1819790786","loc":[-85.621138,41.9576632]},"n1819790788":{"id":"n1819790788","loc":[-85.6207733,41.9578946]},"n1819790789":{"id":"n1819790789","loc":[-85.6200705,41.9571566]},"n1819790790":{"id":"n1819790790","loc":[-85.6245337,41.9558443]},"n1819790792":{"id":"n1819790792","loc":[-85.621932,41.9608066]},"n1819790793":{"id":"n1819790793","loc":[-85.6233578,41.9581385]},"n1819790794":{"id":"n1819790794","loc":[-85.6204557,41.9555136]},"n1819790797":{"id":"n1819790797","loc":[-85.6235038,41.9576074]},"n1819790800":{"id":"n1819790800","loc":[-85.6214438,41.9607508]},"n1819790801":{"id":"n1819790801","loc":[-85.623492,41.9602129]},"n1819790802":{"id":"n1819790802","loc":[-85.6216691,41.9546553]},"n1819790803":{"id":"n1819790803","loc":[-85.6231057,41.9586851]},"n1819790804":{"id":"n1819790804","loc":[-85.6209224,41.9578673]},"n1819790813":{"id":"n1819790813","loc":[-85.620092,41.9572962]},"n1819790814":{"id":"n1819790814","loc":[-85.6216691,41.9552218]},"n1819790816":{"id":"n1819790816","loc":[-85.6216144,41.9609668]},"n1819790818":{"id":"n1819790818","loc":[-85.6216906,41.9557324]},"n1819790820":{"id":"n1819790820","loc":[-85.6192069,41.9564186]},"n1819790823":{"id":"n1819790823","loc":[-85.6211155,41.9566027]},"n1819790825":{"id":"n1819790825","loc":[-85.6233106,41.9569294]},"n1819790839":{"id":"n1819790839","loc":[-85.625671,41.9564986]},"n1819790842":{"id":"n1819790842","loc":[-85.6235252,41.9567379]},"n1819790844":{"id":"n1819790844","loc":[-85.6253813,41.9566342]},"n1819790847":{"id":"n1819790847","loc":[-85.6200963,41.9567702]},"n1819790849":{"id":"n1819790849","loc":[-85.6238031,41.9587449]},"n1819790851":{"id":"n1819790851","loc":[-85.6234984,41.9584571]},"n1819790856":{"id":"n1819790856","loc":[-85.6242226,41.9570092]},"n1819790865":{"id":"n1819790865","loc":[-85.6200265,41.9569458]},"n1819790869":{"id":"n1819790869","loc":[-85.6230049,41.9601245]},"n1819790871":{"id":"n1819790871","loc":[-85.6190727,41.9558322]},"n1819790873":{"id":"n1819790873","loc":[-85.6217442,41.9550104]},"n1819790875":{"id":"n1819790875","loc":[-85.6208044,41.9587808]},"n1819790879":{"id":"n1819790879","loc":[-85.6198444,41.9574484]},"n1819790883":{"id":"n1819790883","loc":[-85.623713,41.9588719]},"n1819790885":{"id":"n1819790885","loc":[-85.6223289,41.9605075]},"n1819790889":{"id":"n1819790889","loc":[-85.6208044,41.9562437]},"n1819790893":{"id":"n1819790893","loc":[-85.6218183,41.9559684]},"n1819790906":{"id":"n1819790906","loc":[-85.6214052,41.958697]},"n1819790913":{"id":"n1819790913","loc":[-85.6209981,41.9609957]},"n1819790917":{"id":"n1819790917","loc":[-85.6216208,41.9604436]},"n1819790919":{"id":"n1819790919","loc":[-85.6209406,41.9616373]},"n1819790920":{"id":"n1819790920","loc":[-85.6221948,41.9583334]},"n1819790922":{"id":"n1819790922","loc":[-85.6216681,41.9615292]},"n1819790924":{"id":"n1819790924","loc":[-85.6210147,41.9570489]},"n1819790929":{"id":"n1819790929","loc":[-85.6193678,41.955521]},"w17964707":{"id":"w17964707","tags":{"highway":"residential","name":"11th Ave"},"nodes":["n185960682","n185960684","n185960686","n185960688","n185960690"]},"w201484345":{"id":"w201484345","tags":{"bridge":"yes","highway":"residential","name":"E Hoffman St"},"nodes":["n185978791","n185978795"]},"w201484348":{"id":"w201484348","tags":{"highway":"residential","name":"E Hoffman St"},"nodes":["n185978795","n185978800","n185978803","n185978806","n185978808","n185978810","n185978811","n185978813","n185955747","n185978814","n185972054","n185978817"]},"w170843845":{"id":"w170843845","tags":{"landuse":"reservoir","name":"Hoffman Pond","natural":"water"},"nodes":["n1819790732","n1819790742","n1819790825","n1819790729","n1819790842","n1819790765","n1819790737","n1819790856","n1819790643","n1819790596","n1819790844","n1819790839","n1819849190","n1819790619","n1819790613","n1819790669","n1819790550","n1819790682","n1819790701","n1819790790","n1819790532","n1819790887","n1819790740","n1819790831","n1819790545","n1819790664","n1819790621","n1819790861","n1819790730","n1819790683","n1819790802","n1819790717","n1819790710","n1819790713","n1819790650","n1819790873","n1819790814","n1819790755","n1819790715","n1819790818","n1819790602","n1819790893","n1819790662","n1819790699","n1819790772","n1819790771","n1819790680","n1819790794","n1819790727","n1819790628","n1819790661","n1819790784","n1819790610","n1819790626","n1819790929","n1819790656","n1819790871","n1819790673","n1819790566","n1819790820","n1819790676","n1819790598","n1819790556","n1819790558","n1819790879","n1819790608","n1819790813","n1819790789","n1819790865","n1819790847","n1819790758","n1819790548","n1819790539","n1819790889","n1819790557","n1819790586","n1819790571","n1819790823","n1819790546","n1819790924","n1819790785","n1819790708","n1819790786","n1819790561","n1819790804","n1819790788","n1819790684","n1819790711","n1819790875","n1819790672","n1819790569","n1819790757","n1819790769","n1819790603","n1819790906","n1819790553","n1819790536","n1819790678","n1819790920","n1819790600","n1819790733","n1819790743","n1819790567","n1819790764","n1819790722","n1819790638","n1819790917","n1819790800","n1819790741","n1819790667","n1819790913","n1819790744","n1819790816","n1819790591","n1819790745","n1819790885","n1819790652","n1819790588","n1819790617","n1819790551","n1819790666","n1819790869","n1819790630","n1819790723","n1819790792","n1819790783","n1819790681","n1819790919","n1819790593","n1819790670","n1819790777","n1819790922","n1819790562","n1819790736","n1819790565","n1819790801","n1819790538","n1819790640","n1819790616","n1819790572","n1819790620","n1819790883","n1819790849","n1819790675","n1819790851","n1819790803","n1819790611","n1819790703","n1819790734","n1819790793","n1819790614","n1819790581","n1819790776","n1819790797","n1819790728","n1819790584","n1819790624","n1819790604","n1819790725","n1819790732"]},"w206805240":{"id":"w206805240","tags":{"waterway":"river"},"nodes":["n2168544738","n2168544739","n2168544740","n2168544741","n2168544742","n2168544743","n2168544744","n2168544745","n2168544746","n2168544747","n2168544748","n2168544749","n2168544750","n2168544751","n2168544752","n2168544753","n1819848944"]},"n394490429":{"id":"n394490429","loc":[-85.643883,41.954365]},"n185953421":{"id":"n185953421","loc":[-85.641876,41.954946]},"n185953417":{"id":"n185953417","loc":[-85.6418306,41.9551597]},"n185977233":{"id":"n185977233","loc":[-85.642987,41.95486]},"n185977232":{"id":"n185977232","loc":[-85.642894,41.9547842]},"n1475293244":{"id":"n1475293244","loc":[-85.63974,41.9521543]},"n1819848890":{"id":"n1819848890","loc":[-85.6410004,41.9552822]},"n1819848965":{"id":"n1819848965","loc":[-85.6409795,41.9553892]},"n2189015846":{"id":"n2189015846","loc":[-85.6420457,41.9549528]},"n2189015849":{"id":"n2189015849","loc":[-85.6425867,41.9551392]},"n2189015852":{"id":"n2189015852","loc":[-85.6426877,41.9549771]},"n2199109816":{"id":"n2199109816","loc":[-85.6399215,41.9540925]},"n2199109818":{"id":"n2199109818","loc":[-85.6399182,41.9538236]},"n2199109820":{"id":"n2199109820","loc":[-85.6402201,41.9538216]},"n2199109822":{"id":"n2199109822","loc":[-85.640222,41.9539771]},"n2199109825":{"id":"n2199109825","loc":[-85.6402904,41.9539766]},"n2199109827":{"id":"n2199109827","loc":[-85.6402918,41.95409]},"n2199109829":{"id":"n2199109829","loc":[-85.6395845,41.9544626]},"n2199109831":{"id":"n2199109831","loc":[-85.6395792,41.9540671]},"n2199109833":{"id":"n2199109833","loc":[-85.6397173,41.9540661]},"n2199109835":{"id":"n2199109835","loc":[-85.6397226,41.9544616]},"n2199109837":{"id":"n2199109837","loc":[-85.6399641,41.9545058]},"n2199109839":{"id":"n2199109839","loc":[-85.6399637,41.9541859]},"n2199109841":{"id":"n2199109841","loc":[-85.6401098,41.9541858]},"n2199109843":{"id":"n2199109843","loc":[-85.64011,41.9543272]},"n2199109845":{"id":"n2199109845","loc":[-85.6400783,41.9543273]},"n2199109847":{"id":"n2199109847","loc":[-85.6400785,41.9545058]},"n2199109853":{"id":"n2199109853","loc":[-85.6396184,41.9554049]},"n2199109855":{"id":"n2199109855","loc":[-85.6396825,41.9553713]},"n185949745":{"id":"n185949745","loc":[-85.6442727,41.9553112]},"n185949748":{"id":"n185949748","loc":[-85.6448804,41.9555238]},"n185949755":{"id":"n185949755","loc":[-85.6420011,41.9603536]},"n185949763":{"id":"n185949763","loc":[-85.6408843,41.9555822]},"n185949765":{"id":"n185949765","loc":[-85.6414548,41.9557751]},"n185952158":{"id":"n185952158","loc":[-85.640066,41.956854]},"n185952160":{"id":"n185952160","loc":[-85.639848,41.957229]},"n185952161":{"id":"n185952161","loc":[-85.6396089,41.9576192]},"n185952163":{"id":"n185952163","loc":[-85.63892,41.957957]},"n185953413":{"id":"n185953413","loc":[-85.64162,41.955475]},"n185971651":{"id":"n185971651","loc":[-85.6440766,41.9543462]},"n185977234":{"id":"n185977234","loc":[-85.645044,41.955581]},"n394490395":{"id":"n394490395","loc":[-85.657336,41.936762]},"n394490396":{"id":"n394490396","loc":[-85.653896,41.936978]},"n394490397":{"id":"n394490397","loc":[-85.653732,41.937386]},"n394490398":{"id":"n394490398","loc":[-85.65182,41.937378]},"n394490399":{"id":"n394490399","loc":[-85.651843,41.938445]},"n394490400":{"id":"n394490400","loc":[-85.652536,41.938447]},"n394490401":{"id":"n394490401","loc":[-85.652533,41.938901]},"n394490402":{"id":"n394490402","loc":[-85.652084,41.9389]},"n394490403":{"id":"n394490403","loc":[-85.6521,41.939627]},"n394490404":{"id":"n394490404","loc":[-85.652301,41.939628]},"n394490405":{"id":"n394490405","loc":[-85.652302,41.939755]},"n394490406":{"id":"n394490406","loc":[-85.652783,41.939747]},"n394490407":{"id":"n394490407","loc":[-85.652835,41.94112]},"n394490408":{"id":"n394490408","loc":[-85.651968,41.941123]},"n394490409":{"id":"n394490409","loc":[-85.651983,41.941969]},"n394490410":{"id":"n394490410","loc":[-85.652908,41.941961]},"n394490411":{"id":"n394490411","loc":[-85.65292,41.94278]},"n394490412":{"id":"n394490412","loc":[-85.651698,41.942816]},"n394490413":{"id":"n394490413","loc":[-85.651509,41.942823]},"n394490414":{"id":"n394490414","loc":[-85.651272,41.942837]},"n394490415":{"id":"n394490415","loc":[-85.651272,41.943325]},"n394490416":{"id":"n394490416","loc":[-85.65122,41.944053]},"n394490417":{"id":"n394490417","loc":[-85.651193,41.944449]},"n394490418":{"id":"n394490418","loc":[-85.651088,41.944969]},"n394490419":{"id":"n394490419","loc":[-85.650949,41.945554]},"n394490420":{"id":"n394490420","loc":[-85.650907,41.945719]},"n394490421":{"id":"n394490421","loc":[-85.650808,41.946016]},"n394490422":{"id":"n394490422","loc":[-85.650712,41.946516]},"n394490423":{"id":"n394490423","loc":[-85.650493,41.947166]},"n394490424":{"id":"n394490424","loc":[-85.650626,41.947213]},"n394490425":{"id":"n394490425","loc":[-85.650201,41.948109]},"n394490426":{"id":"n394490426","loc":[-85.649868,41.948797]},"n394490427":{"id":"n394490427","loc":[-85.649669,41.949161]},"n394490428":{"id":"n394490428","loc":[-85.64659,41.954067]},"n394490430":{"id":"n394490430","loc":[-85.644034,41.95444]},"n394490431":{"id":"n394490431","loc":[-85.644248,41.954507]},"n394490432":{"id":"n394490432","loc":[-85.64491,41.954481]},"n394490433":{"id":"n394490433","loc":[-85.645213,41.954433]},"n394490434":{"id":"n394490434","loc":[-85.645426,41.954477]},"n394490435":{"id":"n394490435","loc":[-85.6458,41.954704]},"n394490436":{"id":"n394490436","loc":[-85.64605,41.954804]},"n394490437":{"id":"n394490437","loc":[-85.646125,41.954817]},"n394490438":{"id":"n394490438","loc":[-85.646002,41.954997]},"n394490439":{"id":"n394490439","loc":[-85.645764,41.955366]},"n394490440":{"id":"n394490440","loc":[-85.645525,41.955734]},"n394490441":{"id":"n394490441","loc":[-85.64443,41.957424]},"n394490442":{"id":"n394490442","loc":[-85.641712,41.961723]},"n394490443":{"id":"n394490443","loc":[-85.640747,41.963246]},"n394490444":{"id":"n394490444","loc":[-85.637803,41.967894]},"n394490445":{"id":"n394490445","loc":[-85.637673,41.967861]},"n394490446":{"id":"n394490446","loc":[-85.636637,41.969275]},"n394490447":{"id":"n394490447","loc":[-85.634923,41.969269]},"n394490448":{"id":"n394490448","loc":[-85.634893,41.968537]},"n394490449":{"id":"n394490449","loc":[-85.634544,41.96927]},"n394490450":{"id":"n394490450","loc":[-85.630835,41.969274]},"n394490451":{"id":"n394490451","loc":[-85.630834,41.968348]},"n394490452":{"id":"n394490452","loc":[-85.630857,41.968179]},"n394490453":{"id":"n394490453","loc":[-85.630924,41.968044]},"n394490454":{"id":"n394490454","loc":[-85.631004,41.967925]},"n394490455":{"id":"n394490455","loc":[-85.631143,41.967811]},"n394490456":{"id":"n394490456","loc":[-85.631311,41.967736]},"n394490457":{"id":"n394490457","loc":[-85.631595,41.967693]},"n394490458":{"id":"n394490458","loc":[-85.63325,41.967702]},"n394490459":{"id":"n394490459","loc":[-85.633247,41.967021]},"n394490460":{"id":"n394490460","loc":[-85.634858,41.967021]},"n394490461":{"id":"n394490461","loc":[-85.634865,41.967711]},"n394490462":{"id":"n394490462","loc":[-85.634884,41.968231]},"n394490463":{"id":"n394490463","loc":[-85.636559,41.963867]},"n394490464":{"id":"n394490464","loc":[-85.634832,41.963866]},"n394490465":{"id":"n394490465","loc":[-85.63481,41.961899]},"n394490466":{"id":"n394490466","loc":[-85.637219,41.961842]},"n394490467":{"id":"n394490467","loc":[-85.637837,41.960019]},"n394490468":{"id":"n394490468","loc":[-85.637459,41.960022]},"n394490469":{"id":"n394490469","loc":[-85.635295,41.959987]},"n394490470":{"id":"n394490470","loc":[-85.634783,41.959979]},"n394490471":{"id":"n394490471","loc":[-85.634776,41.959834]},"n394490472":{"id":"n394490472","loc":[-85.634767,41.959009]},"n394490473":{"id":"n394490473","loc":[-85.634763,41.958292]},"n394490474":{"id":"n394490474","loc":[-85.633346,41.958287]},"n394490475":{"id":"n394490475","loc":[-85.632128,41.9583]},"n394490476":{"id":"n394490476","loc":[-85.631414,41.958318]},"n394490477":{"id":"n394490477","loc":[-85.63137,41.959033]},"n394490478":{"id":"n394490478","loc":[-85.631325,41.959753]},"n394490479":{"id":"n394490479","loc":[-85.631494,41.95977]},"n394490480":{"id":"n394490480","loc":[-85.631456,41.960673]},"n394490481":{"id":"n394490481","loc":[-85.631421,41.961494]},"n394490482":{"id":"n394490482","loc":[-85.631404,41.961887]},"n394490483":{"id":"n394490483","loc":[-85.631401,41.961968]},"n394490484":{"id":"n394490484","loc":[-85.630962,41.961967]},"n394490485":{"id":"n394490485","loc":[-85.6299,41.961973]},"n394490486":{"id":"n394490486","loc":[-85.624929,41.962002]},"n394490487":{"id":"n394490487","loc":[-85.623333,41.961987]},"n394490488":{"id":"n394490488","loc":[-85.621894,41.963956]},"n394490489":{"id":"n394490489","loc":[-85.62131,41.963727]},"n394490490":{"id":"n394490490","loc":[-85.621216,41.963868]},"n394490491":{"id":"n394490491","loc":[-85.620356,41.965119]},"n394490492":{"id":"n394490492","loc":[-85.620848,41.965341]},"n394490493":{"id":"n394490493","loc":[-85.620684,41.965558]},"n394490494":{"id":"n394490494","loc":[-85.620621,41.965658]},"n394490495":{"id":"n394490495","loc":[-85.618165,41.965759]},"n394490496":{"id":"n394490496","loc":[-85.618071,41.965759]},"n394490497":{"id":"n394490497","loc":[-85.617986,41.965759]},"n394490498":{"id":"n394490498","loc":[-85.605673,41.965764]},"n394490499":{"id":"n394490499","loc":[-85.605668,41.963548]},"n394490500":{"id":"n394490500","loc":[-85.605664,41.962094]},"n394490501":{"id":"n394490501","loc":[-85.595828,41.962159]},"n394490502":{"id":"n394490502","loc":[-85.587869,41.962169]},"n394490503":{"id":"n394490503","loc":[-85.586289,41.962179]},"n394490504":{"id":"n394490504","loc":[-85.583774,41.962178]},"n394490505":{"id":"n394490505","loc":[-85.583774,41.961789]},"n394490506":{"id":"n394490506","loc":[-85.581303,41.961783]},"n394490507":{"id":"n394490507","loc":[-85.581304,41.961616]},"n394490508":{"id":"n394490508","loc":[-85.581292,41.961616]},"n394490509":{"id":"n394490509","loc":[-85.581247,41.959244]},"n394490510":{"id":"n394490510","loc":[-85.581245,41.958394]},"n394490511":{"id":"n394490511","loc":[-85.581276,41.958372]},"n394490512":{"id":"n394490512","loc":[-85.581302,41.958353]},"n394490513":{"id":"n394490513","loc":[-85.581376,41.9583]},"n394490514":{"id":"n394490514","loc":[-85.582256,41.957663]},"n394490515":{"id":"n394490515","loc":[-85.585299,41.955483]},"n394490516":{"id":"n394490516","loc":[-85.585588,41.955331]},"n394490517":{"id":"n394490517","loc":[-85.586053,41.955163]},"n394490518":{"id":"n394490518","loc":[-85.58632,41.955076]},"n394490519":{"id":"n394490519","loc":[-85.586478,41.955025]},"n394490520":{"id":"n394490520","loc":[-85.58692,41.954947]},"n394490521":{"id":"n394490521","loc":[-85.587327,41.954914]},"n394490522":{"id":"n394490522","loc":[-85.587345,41.954913]},"n394490523":{"id":"n394490523","loc":[-85.587358,41.954913]},"n394490524":{"id":"n394490524","loc":[-85.58963,41.954877]},"n394490525":{"id":"n394490525","loc":[-85.591077,41.954865]},"n394490526":{"id":"n394490526","loc":[-85.594824,41.954843]},"n394490527":{"id":"n394490527","loc":[-85.594804,41.95331]},"n394490528":{"id":"n394490528","loc":[-85.599336,41.95331]},"n394490529":{"id":"n394490529","loc":[-85.599336,41.954825]},"n394490530":{"id":"n394490530","loc":[-85.597828,41.954839]},"n394490531":{"id":"n394490531","loc":[-85.597833,41.95614]},"n394490532":{"id":"n394490532","loc":[-85.596586,41.956151]},"n394490533":{"id":"n394490533","loc":[-85.596586,41.956394]},"n394490534":{"id":"n394490534","loc":[-85.595933,41.956394]},"n394490535":{"id":"n394490535","loc":[-85.595933,41.958176]},"n394490536":{"id":"n394490536","loc":[-85.597635,41.958179]},"n394490537":{"id":"n394490537","loc":[-85.597717,41.958177]},"n394490538":{"id":"n394490538","loc":[-85.601671,41.958194]},"n394490539":{"id":"n394490539","loc":[-85.605619,41.958194]},"n394490540":{"id":"n394490540","loc":[-85.608054,41.958187]},"n394490542":{"id":"n394490542","loc":[-85.6080762,41.9547864]},"n394490545":{"id":"n394490545","loc":[-85.6104354,41.9548263]},"n394490546":{"id":"n394490546","loc":[-85.610274,41.951106]},"n394490547":{"id":"n394490547","loc":[-85.610278,41.950829]},"n394490548":{"id":"n394490548","loc":[-85.610309,41.948377]},"n394490549":{"id":"n394490549","loc":[-85.610314,41.947986]},"n394490550":{"id":"n394490550","loc":[-85.610464,41.947985]},"n394490551":{"id":"n394490551","loc":[-85.610447,41.947468]},"n394490552":{"id":"n394490552","loc":[-85.612469,41.947471]},"n394490553":{"id":"n394490553","loc":[-85.612494,41.945576]},"n394490554":{"id":"n394490554","loc":[-85.610292,41.94558]},"n394490555":{"id":"n394490555","loc":[-85.608412,41.945625]},"n394490556":{"id":"n394490556","loc":[-85.608412,41.943036]},"n394490557":{"id":"n394490557","loc":[-85.608702,41.943087]},"n394490558":{"id":"n394490558","loc":[-85.609196,41.943224]},"n394490559":{"id":"n394490559","loc":[-85.609571,41.943263]},"n394490560":{"id":"n394490560","loc":[-85.610116,41.943295]},"n394490561":{"id":"n394490561","loc":[-85.610273,41.943275]},"n394490562":{"id":"n394490562","loc":[-85.611339,41.943075]},"n394490563":{"id":"n394490563","loc":[-85.611575,41.942997]},"n394490564":{"id":"n394490564","loc":[-85.611847,41.942849]},"n394490565":{"id":"n394490565","loc":[-85.612164,41.942568]},"n394490566":{"id":"n394490566","loc":[-85.612341,41.942529]},"n394490567":{"id":"n394490567","loc":[-85.612562,41.942524]},"n394490568":{"id":"n394490568","loc":[-85.612768,41.942546]},"n394490569":{"id":"n394490569","loc":[-85.612938,41.942633]},"n394490570":{"id":"n394490570","loc":[-85.6131,41.942782]},"n394490571":{"id":"n394490571","loc":[-85.613299,41.942919]},"n394490572":{"id":"n394490572","loc":[-85.613498,41.942996]},"n394490573":{"id":"n394490573","loc":[-85.614698,41.942842]},"n394490574":{"id":"n394490574","loc":[-85.615288,41.942698]},"n394490575":{"id":"n394490575","loc":[-85.616054,41.942693]},"n394490576":{"id":"n394490576","loc":[-85.61603,41.942175]},"n394490577":{"id":"n394490577","loc":[-85.616004,41.941741]},"n394490578":{"id":"n394490578","loc":[-85.615994,41.940156]},"n394490579":{"id":"n394490579","loc":[-85.615144,41.940159]},"n394490580":{"id":"n394490580","loc":[-85.614915,41.940161]},"n394490582":{"id":"n394490582","loc":[-85.614875,41.938532]},"n394490583":{"id":"n394490583","loc":[-85.616167,41.938787]},"n394490585":{"id":"n394490585","loc":[-85.616176,41.938589]},"n394490586":{"id":"n394490586","loc":[-85.614537,41.938282]},"n394490588":{"id":"n394490588","loc":[-85.610141,41.937459]},"n394490589":{"id":"n394490589","loc":[-85.610172,41.937298]},"n394490590":{"id":"n394490590","loc":[-85.609918,41.935495]},"n394490592":{"id":"n394490592","loc":[-85.610092,41.935451]},"n394490594":{"id":"n394490594","loc":[-85.610681,41.935247]},"n394490595":{"id":"n394490595","loc":[-85.611446,41.934955]},"n394490596":{"id":"n394490596","loc":[-85.612057,41.934696]},"n394490598":{"id":"n394490598","loc":[-85.613256,41.934084]},"n394490599":{"id":"n394490599","loc":[-85.613948,41.933682]},"n394490601":{"id":"n394490601","loc":[-85.61436,41.933417]},"n394490602":{"id":"n394490602","loc":[-85.614638,41.933212]},"n394490604":{"id":"n394490604","loc":[-85.615249,41.9332]},"n394490605":{"id":"n394490605","loc":[-85.618218,41.933223]},"n394490607":{"id":"n394490607","loc":[-85.618241,41.933479]},"n394490608":{"id":"n394490608","loc":[-85.618257,41.93365]},"n394490609":{"id":"n394490609","loc":[-85.618298,41.935067]},"n394490611":{"id":"n394490611","loc":[-85.619791,41.935067]},"n394490612":{"id":"n394490612","loc":[-85.619794,41.933301]},"n394490613":{"id":"n394490613","loc":[-85.619795,41.932692]},"n394490614":{"id":"n394490614","loc":[-85.619729,41.929517]},"n394490615":{"id":"n394490615","loc":[-85.619801,41.929305]},"n394490616":{"id":"n394490616","loc":[-85.619809,41.927391]},"n394490617":{"id":"n394490617","loc":[-85.620883,41.927378]},"n394490618":{"id":"n394490618","loc":[-85.620988,41.927368]},"n394490619":{"id":"n394490619","loc":[-85.621076,41.927368]},"n394490620":{"id":"n394490620","loc":[-85.621156,41.927376]},"n394490621":{"id":"n394490621","loc":[-85.621685,41.92737]},"n394490622":{"id":"n394490622","loc":[-85.624716,41.927359]},"n394490623":{"id":"n394490623","loc":[-85.625308,41.92737]},"n394490624":{"id":"n394490624","loc":[-85.625655,41.927377]},"n394490625":{"id":"n394490625","loc":[-85.625093,41.925591]},"n394490626":{"id":"n394490626","loc":[-85.625174,41.92559]},"n394490627":{"id":"n394490627","loc":[-85.625249,41.925597]},"n394490628":{"id":"n394490628","loc":[-85.625532,41.925604]},"n394490629":{"id":"n394490629","loc":[-85.625761,41.925597]},"n394490630":{"id":"n394490630","loc":[-85.625955,41.926153]},"n394490631":{"id":"n394490631","loc":[-85.626209,41.926155]},"n394490632":{"id":"n394490632","loc":[-85.627757,41.926151]},"n394490633":{"id":"n394490633","loc":[-85.627825,41.926298]},"n394490634":{"id":"n394490634","loc":[-85.627994,41.926315]},"n394490635":{"id":"n394490635","loc":[-85.628049,41.927196]},"n394490636":{"id":"n394490636","loc":[-85.62949,41.927221]},"n394490637":{"id":"n394490637","loc":[-85.629602,41.927277]},"n394490638":{"id":"n394490638","loc":[-85.6297102,41.9273279]},"n394490639":{"id":"n394490639","loc":[-85.630958,41.927398]},"n394490699":{"id":"n394490699","loc":[-85.632741,41.927388]},"n394490700":{"id":"n394490700","loc":[-85.632997,41.927391]},"n394490701":{"id":"n394490701","loc":[-85.633149,41.927393]},"n394490702":{"id":"n394490702","loc":[-85.633334,41.927393]},"n394490703":{"id":"n394490703","loc":[-85.633468,41.927561]},"n394490704":{"id":"n394490704","loc":[-85.633563,41.927755]},"n394490705":{"id":"n394490705","loc":[-85.633662,41.928192]},"n394490706":{"id":"n394490706","loc":[-85.633679,41.928807]},"n394490707":{"id":"n394490707","loc":[-85.633687,41.929107]},"n394490708":{"id":"n394490708","loc":[-85.633927,41.929109]},"n394490709":{"id":"n394490709","loc":[-85.634126,41.929111]},"n394490710":{"id":"n394490710","loc":[-85.634207,41.92911]},"n394490711":{"id":"n394490711","loc":[-85.634323,41.929111]},"n394490712":{"id":"n394490712","loc":[-85.636712,41.929128]},"n394490713":{"id":"n394490713","loc":[-85.63808,41.9291]},"n394490714":{"id":"n394490714","loc":[-85.639213,41.929088]},"n394490715":{"id":"n394490715","loc":[-85.639189,41.92852]},"n394490716":{"id":"n394490716","loc":[-85.639204,41.925488]},"n394490717":{"id":"n394490717","loc":[-85.644204,41.925452]},"n394490718":{"id":"n394490718","loc":[-85.651425,41.925406]},"n394490719":{"id":"n394490719","loc":[-85.651449,41.926321]},"n394490720":{"id":"n394490720","loc":[-85.651451,41.926969]},"n394490721":{"id":"n394490721","loc":[-85.651458,41.928052]},"n394490722":{"id":"n394490722","loc":[-85.651446,41.928892]},"n394490723":{"id":"n394490723","loc":[-85.651456,41.929447]},"n394490724":{"id":"n394490724","loc":[-85.651707,41.929454]},"n394490725":{"id":"n394490725","loc":[-85.652369,41.929473]},"n394490726":{"id":"n394490726","loc":[-85.6525,41.929452]},"n394490727":{"id":"n394490727","loc":[-85.654066,41.92946]},"n394490728":{"id":"n394490728","loc":[-85.654816,41.92946]},"n394490729":{"id":"n394490729","loc":[-85.654816,41.930337]},"n394490730":{"id":"n394490730","loc":[-85.654587,41.930337]},"n394490731":{"id":"n394490731","loc":[-85.654548,41.931072]},"n394490732":{"id":"n394490732","loc":[-85.654538,41.931701]},"n394490733":{"id":"n394490733","loc":[-85.654898,41.931689]},"n394490734":{"id":"n394490734","loc":[-85.654898,41.932505]},"n394490735":{"id":"n394490735","loc":[-85.654854,41.932514]},"n394490736":{"id":"n394490736","loc":[-85.655497,41.932499]},"n394490737":{"id":"n394490737","loc":[-85.656405,41.932493]},"n394490738":{"id":"n394490738","loc":[-85.656422,41.933416]},"n394490739":{"id":"n394490739","loc":[-85.657322,41.933438]},"n1475293233":{"id":"n1475293233","loc":[-85.6385522,41.9585167]},"n1475293242":{"id":"n1475293242","loc":[-85.64609,41.9540815]},"n1475293249":{"id":"n1475293249","loc":[-85.6358079,41.9692721]},"n1475293256":{"id":"n1475293256","loc":[-85.6387369,41.9581583]},"n1475293259":{"id":"n1475293259","loc":[-85.6455882,41.9541138]},"n1475293266":{"id":"n1475293266","loc":[-85.6451008,41.9541821]},"n1819800253":{"id":"n1819800253","loc":[-85.6134286,41.9429692]},"n2114807558":{"id":"n2114807558","loc":[-85.6365609,41.963866],"tags":{"railway":"level_crossing"}},"n2189015728":{"id":"n2189015728","loc":[-85.6383956,41.9590576]},"n2189015838":{"id":"n2189015838","loc":[-85.6435144,41.9563705]},"n2189015842":{"id":"n2189015842","loc":[-85.6415782,41.9557035]},"n2189015855":{"id":"n2189015855","loc":[-85.6440829,41.9554577]},"n2199109849":{"id":"n2199109849","loc":[-85.6393434,41.9565591]},"n2199109851":{"id":"n2199109851","loc":[-85.6393208,41.9565002]},"n2199109857":{"id":"n2199109857","loc":[-85.6401986,41.955545]},"n2199109859":{"id":"n2199109859","loc":[-85.6402362,41.955587]},"n2199109861":{"id":"n2199109861","loc":[-85.6395958,41.9565675]},"n2199109863":{"id":"n2199109863","loc":[-85.639528,41.9566011]},"w209717053":{"id":"w209717053","tags":{"area":"yes","building":"yes"},"nodes":["n2199109829","n2199109831","n2199109833","n2199109835","n2199109829"]},"w17966415":{"id":"w17966415","tags":{"access":"private","highway":"service","name":"Manufacturing Way"},"nodes":["n185971642","n185977232","n185977233","n185949745","n185949748","n185977234"]},"w209717054":{"id":"w209717054","tags":{"area":"yes","building":"yes"},"nodes":["n2199109837","n2199109839","n2199109841","n2199109843","n2199109845","n2199109847","n2199109837"]},"w208627214":{"id":"w208627214","tags":{"highway":"service"},"nodes":["n185949755","n2189015728","n1475293233","n1475293256","n185952163","n185952161","n185952160","n185952158","n185949763","n1819848965","n1819848890","n185952156"]},"w17963817":{"id":"w17963817","tags":{"access":"private","highway":"service"},"nodes":["n185949765","n185953413","n185953417","n185953421","n185953423"]},"w34369809":{"id":"w34369809","tags":{"admin_level":"8","boundary":"administrative","landuse":"residential"},"nodes":["n394490395","n394490396","n394490397","n394490398","n394490399","n394490400","n394490401","n394490402","n394490403","n394490404","n394490405","n394490406","n394490407","n394490408","n394490409","n394490410","n394490411","n394490412","n394490413","n394490414","n394490415","n394490416","n394490417","n394490418","n394490419","n394490420","n394490421","n394490422","n394490423","n394490424","n394490425","n394490426","n394490427","n394490428","n1475293242","n1475293259","n1475293266","n394490429","n394490430","n394490431","n394490432","n394490433","n394490434","n394490435","n394490436","n394490437","n394490438","n394490439","n394490440","n394490441","n394490442","n394490443","n394490444","n394490445","n394490446","n1475293249","n394490447","n394490448","n394490449","n394490450","n394490451","n394490452","n394490453","n394490454","n394490455","n394490456","n394490457","n394490458","n394490459","n394490460","n394490461","n394490462","n2114807558","n394490463","n1475293226","n394490464","n394490465","n394490466","n394490467","n394490468","n394490469","n394490470","n394490471","n394490472","n394490473","n394490474","n394490475","n394490476","n394490477","n394490478","n394490479","n394490480","n394490481","n394490482","n394490483","n394490484","n394490485","n394490486","n394490487","n394490488","n394490489","n394490490","n394490491","n394490492","n394490493","n394490494","n394490495","n394490496","n394490497","n394490498","n394490499","n394490500","n394490501","n394490502","n394490503","n394490504","n394490505","n394490506","n394490507","n394490508","n394490509","n394490510","n394490511","n394490512","n394490513","n394490514","n394490515","n394490516","n394490517","n394490518","n394490519","n394490520","n394490521","n394490522","n394490523","n394490524","n394490525","n394490526","n394490527","n394490528","n394490529","n394490530","n394490531","n394490532","n394490533","n394490534","n394490535","n394490536","n394490537","n394490538","n394490539","n394490540","n394490542","n394490545","n394490546","n394490547","n394490548","n394490549","n394490550","n394490551","n394490552","n394490553","n394490554","n394490555","n394490556","n394490557","n394490558","n394490559","n394490560","n394490561","n394490562","n394490563","n394490564","n394490565","n394490566","n394490567","n394490568","n394490569","n394490570","n394490571","n1819800253","n394490572","n394490573","n394490574","n394490575","n394490576","n394490577","n394490578","n394490579","n394490580","n394490582","n394490583","n394490585","n394490586","n394490588","n394490589","n394490590","n394490592","n394490594","n394490595","n394490596","n394490598","n394490599","n394490601","n394490602","n394490604","n394490605","n394490607","n394490608","n394490609","n394490611","n394490612","n394490613","n394490614","n394490615","n394490616","n394490617","n394490618","n394490619","n394490620","n394490621","n394490622","n394490623","n394490624","n394490625","n394490626","n394490627","n394490628","n394490629","n394490630","n394490631","n394490632","n394490633","n394490634","n394490635","n394490636","n394490637","n394490638","n394490639","n394490699","n394490700","n394490701","n394490702","n394490703","n394490704","n394490705","n394490706","n394490707","n394490708","n394490709","n394490710","n394490711","n394490712","n394490713","n394490714","n394490715","n394490716","n394490717","n394490718","n394490719","n394490720","n394490721","n394490722","n394490723","n394490724","n394490725","n394490726","n394490727","n394490728","n394490729","n394490730","n394490731","n394490732","n394490733","n394490734","n394490735","n394490736","n394490737","n394490738","n394490739","n394490395"]},"w208627221":{"id":"w208627221","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189015838","n2189015842","n2189015846","n2189015849","n2189015852","n2189015855","n2189015838"]},"w209717052":{"id":"w209717052","tags":{"area":"yes","building":"yes"},"nodes":["n2199109816","n2199109818","n2199109820","n2199109822","n2199109825","n2199109827","n2199109816"]},"w134151784":{"id":"w134151784","tags":{"bridge":"yes","highway":"residential","name":"W Hoffman St"},"nodes":["n185971648","n185971651"]},"w209717055":{"id":"w209717055","tags":{"area":"yes","landuse":"basin"},"nodes":["n2199109849","n2199109851","n2199109853","n2199109855","n2199109857","n2199109859","n2199109861","n2199109863","n2199109849"]},"w17967763":{"id":"w17967763","tags":{"highway":"residential","name":"Rock River Ave"},"nodes":["n1475293244","n185982166","n185975067","n185971637"]},"r134949":{"id":"r134949","tags":{"admin_level":"8","border_type":"city","boundary":"administrative","name":"Three Rivers","place":"city","type":"boundary"},"members":[{"id":"w34369809","type":"way","role":"outer"},{"id":"w34369821","type":"way","role":"outer"},{"id":"w34369822","type":"way","role":"outer"},{"id":"w34369823","type":"way","role":"outer"},{"id":"w34369824","type":"way","role":"outer"},{"id":"w34369825","type":"way","role":"outer"},{"id":"w34369826","type":"way","role":"outer"},{"id":"w34369810","type":"way","role":"inner"},{"id":"w34369811","type":"way","role":"inner"},{"id":"w34369812","type":"way","role":"inner"},{"id":"w34367079","type":"way","role":"inner"},{"id":"w34369814","type":"way","role":"inner"},{"id":"w34367080","type":"way","role":"inner"},{"id":"w34369815","type":"way","role":"inner"},{"id":"w34369820","type":"way","role":"inner"}]},"n1819848881":{"id":"n1819848881","loc":[-85.638562,41.9569965]},"n1819848947":{"id":"n1819848947","loc":[-85.6384348,41.9576565]},"n1819849044":{"id":"n1819849044","loc":[-85.6385749,41.9573345]},"n2114807547":{"id":"n2114807547","loc":[-85.6384626,41.9583756]},"n2114807564":{"id":"n2114807564","loc":[-85.638535,41.9581283]},"n2189015691":{"id":"n2189015691","loc":[-85.6435584,41.9565243]},"n2189015696":{"id":"n2189015696","loc":[-85.6435805,41.9566049]},"n2189015722":{"id":"n2189015722","loc":[-85.6435035,41.9567438]},"n2189015744":{"id":"n2189015744","loc":[-85.6437991,41.9569582]},"n2189015747":{"id":"n2189015747","loc":[-85.6433042,41.9567742]},"n2189015750":{"id":"n2189015750","loc":[-85.6433827,41.9566844]},"n2189015753":{"id":"n2189015753","loc":[-85.6430447,41.9565588]},"n2189015756":{"id":"n2189015756","loc":[-85.6431111,41.956451]},"n2189015759":{"id":"n2189015759","loc":[-85.6420247,41.956083]},"n2189015760":{"id":"n2189015760","loc":[-85.6419945,41.9561369]},"n2189015764":{"id":"n2189015764","loc":[-85.6413729,41.9558945]},"n2189015766":{"id":"n2189015766","loc":[-85.6412884,41.9560606]},"n2189015770":{"id":"n2189015770","loc":[-85.6411798,41.9560112]},"n2189015771":{"id":"n2189015771","loc":[-85.6410651,41.9562132]},"n2189015774":{"id":"n2189015774","loc":[-85.6409504,41.9561728]},"n2189015778":{"id":"n2189015778","loc":[-85.6407996,41.9564241]},"n2189015781":{"id":"n2189015781","loc":[-85.6406889,41.9563892]},"n2189015785":{"id":"n2189015785","loc":[-85.6404857,41.9567024]},"n2189015789":{"id":"n2189015789","loc":[-85.6406909,41.9567877]},"n2189015793":{"id":"n2189015793","loc":[-85.6405642,41.9570165]},"n2189015796":{"id":"n2189015796","loc":[-85.6415359,41.9573711]},"n2189015800":{"id":"n2189015800","loc":[-85.6411738,41.9579501]},"n2189015804":{"id":"n2189015804","loc":[-85.6411119,41.957921]},"n2189015808":{"id":"n2189015808","loc":[-85.6403186,41.9591751]},"n2189015909":{"id":"n2189015909","loc":[-85.6389293,41.9564636]},"n2189015926":{"id":"n2189015926","loc":[-85.6385431,41.9564617]},"n2189015929":{"id":"n2189015929","loc":[-85.6385457,41.9561823]},"n2189015932":{"id":"n2189015932","loc":[-85.6389319,41.9561843]},"n2199109865":{"id":"n2199109865","loc":[-85.6400768,41.956776]},"n2199109867":{"id":"n2199109867","loc":[-85.639902,41.9567153]},"n2199109869":{"id":"n2199109869","loc":[-85.640004,41.956553]},"n2199109871":{"id":"n2199109871","loc":[-85.6401788,41.9566137]},"n2199109873":{"id":"n2199109873","loc":[-85.6399316,41.9564506],"tags":{"man_made":"water_tower"}},"n2199109876":{"id":"n2199109876","loc":[-85.6397689,41.9572354]},"n2199109878":{"id":"n2199109878","loc":[-85.6399229,41.9569826]},"n2199109880":{"id":"n2199109880","loc":[-85.639706,41.9569095]},"n2199109882":{"id":"n2199109882","loc":[-85.639552,41.9571623]},"n2199109884":{"id":"n2199109884","loc":[-85.6391028,41.9569517]},"n2199109886":{"id":"n2199109886","loc":[-85.6392876,41.956646]},"n2199109888":{"id":"n2199109888","loc":[-85.639484,41.9567117]},"n2199109889":{"id":"n2199109889","loc":[-85.6394322,41.9567973]},"n2199109890":{"id":"n2199109890","loc":[-85.6393718,41.9567771]},"n2199109891":{"id":"n2199109891","loc":[-85.6392387,41.9569972]},"n1819848900":{"id":"n1819848900","loc":[-85.638281,41.9576578]},"n1819848978":{"id":"n1819848978","loc":[-85.6377186,41.9580867]},"n1819849039":{"id":"n1819849039","loc":[-85.6384217,41.9573405]},"n1819849050":{"id":"n1819849050","loc":[-85.6377011,41.9570042]},"n1819849088":{"id":"n1819849088","loc":[-85.6382879,41.9580817]},"n2114807549":{"id":"n2114807549","loc":[-85.6362551,41.96473]},"n2114807587":{"id":"n2114807587","loc":[-85.6368694,41.9629829]},"n2189015725":{"id":"n2189015725","loc":[-85.644156,41.9569753]},"n2189015741":{"id":"n2189015741","loc":[-85.6419825,41.9597632]},"w208627217":{"id":"w208627217","tags":{"area":"yes","building":"yes"},"nodes":["n2189015741","n2189015744","n2189015747","n2189015750","n2189015753","n2189015756","n2189015759","n2189015760","n2189015764","n2189015766","n2189015770","n2189015771","n2189015774","n2189015778","n2189015781","n2189015785","n2189015789","n2189015793","n2189015796","n2189015800","n2189015804","n2189015808","n2189015741"]},"w208627212":{"id":"w208627212","tags":{"highway":"service"},"nodes":["n2189015691","n2189015696","n2189015722","n2189015725"]},"w209717057":{"id":"w209717057","tags":{"area":"yes","building":"yes"},"nodes":["n2199109876","n2199109878","n2199109880","n2199109882","n2199109876"]},"w209717056":{"id":"w209717056","tags":{"area":"yes","building":"yes"},"nodes":["n2199109865","n2199109867","n2199109869","n2199109871","n2199109865"]},"w208627231":{"id":"w208627231","tags":{"area":"yes","building":"yes"},"nodes":["n2189015909","n2189015926","n2189015929","n2189015932","n2189015909"]},"w170848326":{"id":"w170848326","tags":{"building":"yes"},"nodes":["n1819848881","n1819849050","n1819848978","n1819849088","n1819848900","n1819848947","n1819849039","n1819849044","n1819848881"]},"w17963182":{"id":"w17963182","tags":{"highway":"service"},"nodes":["n185949763","n185949765","n2189015691","n185949745"]},"w201484340":{"id":"w201484340","tags":{"railway":"rail","service":"siding"},"nodes":["n2114807565","n2114807564","n2114807547","n2114807587","n2114807558","n2114807549","n2114807593"]},"w209717058":{"id":"w209717058","tags":{"area":"yes","building":"yes"},"nodes":["n2199109884","n2199109886","n2199109888","n2199109889","n2199109890","n2199109891","n2199109884"]},"n185954650":{"id":"n185954650","loc":[-85.627331,41.957439]},"n185966949":{"id":"n185966949","loc":[-85.626868,41.957314]},"n185989335":{"id":"n185989335","loc":[-85.62529,41.958568]},"n185989337":{"id":"n185989337","loc":[-85.624962,41.958453]},"n185989339":{"id":"n185989339","loc":[-85.624832,41.958399]},"n185989340":{"id":"n185989340","loc":[-85.624707,41.958325]},"n185989342":{"id":"n185989342","loc":[-85.624636,41.958251]},"n185989345":{"id":"n185989345","loc":[-85.624578,41.95818]},"n185989347":{"id":"n185989347","loc":[-85.624533,41.958099]},"n185989349":{"id":"n185989349","loc":[-85.624507,41.957985]},"n185989351":{"id":"n185989351","loc":[-85.624495,41.957807]},"n185989353":{"id":"n185989353","loc":[-85.624514,41.957663]},"n185989354":{"id":"n185989354","loc":[-85.624577,41.957593]},"n185989356":{"id":"n185989356","loc":[-85.624685,41.95754]},"n185989357":{"id":"n185989357","loc":[-85.624802,41.957523]},"n185989359":{"id":"n185989359","loc":[-85.624996,41.957524]},"n185989361":{"id":"n185989361","loc":[-85.625409,41.957515]},"n185989364":{"id":"n185989364","loc":[-85.625634,41.957496]},"n185989367":{"id":"n185989367","loc":[-85.625832,41.957453]},"n185989368":{"id":"n185989368","loc":[-85.626044,41.957394]},"n354031352":{"id":"n354031352","loc":[-85.6252778,41.9586111],"tags":{"amenity":"place_of_worship","denomination":"baptist","name":"First Baptist Church","religion":"christian"}},"n2199109892":{"id":"n2199109892","loc":[-85.6261578,41.9589963]},"n2199109893":{"id":"n2199109893","loc":[-85.6263191,41.9586865]},"n2199109894":{"id":"n2199109894","loc":[-85.6261186,41.9586288]},"n2199109895":{"id":"n2199109895","loc":[-85.6260644,41.9587329]},"n2199109896":{"id":"n2199109896","loc":[-85.6261547,41.9587589]},"n2199109898":{"id":"n2199109898","loc":[-85.6260476,41.9589646]},"n185966951":{"id":"n185966951","loc":[-85.628404,41.957438]},"w17965351":{"id":"w17965351","tags":{"highway":"residential","name":"Flower Street"},"nodes":["n185966948","n185966949","n185954650","n185966951","n185966953","n185966955","n185966957"]},"w17967809":{"id":"w17967809","tags":{"highway":"residential","name":"Azaleamum Drive"},"nodes":["n185982197","n185989335","n185989337","n185989339","n185989340","n185989342","n185989345","n185989347","n185989349","n185989351","n185989353","n185989354","n185989356","n185989357","n185989359","n185989361","n185989364","n185989367","n185989368","n185982196"]},"w209717059":{"id":"w209717059","tags":{"area":"yes","building":"yes"},"nodes":["n2199109892","n2199109893","n2199109894","n2199109895","n2199109896","n2199109898","n2199109892"]},"n185961390":{"id":"n185961390","loc":[-85.63137,41.959033]},"n185961393":{"id":"n185961393","loc":[-85.634315,41.959017]},"w17966214":{"id":"w17966214","tags":{"highway":"residential","name":"East Adams Street"},"nodes":["n185975351","n185967434","n185968108"]},"w17964793":{"id":"w17964793","tags":{"highway":"residential","name":"Morris Ave"},"nodes":["n185961389","n185961390","n185961391","n185961393","n185961396"]},"n185952166":{"id":"n185952166","loc":[-85.638174,41.95831]},"n2114807552":{"id":"n2114807552","loc":[-85.6383526,41.9593788]},"n2114807591":{"id":"n2114807591","loc":[-85.6383741,41.9593968]},"n2189015731":{"id":"n2189015731","loc":[-85.6368404,41.9592785]},"n2189015734":{"id":"n2189015734","loc":[-85.6368404,41.9585918]},"n2189015737":{"id":"n2189015737","loc":[-85.6376009,41.9585918]},"n2189015738":{"id":"n2189015738","loc":[-85.6376009,41.9592785]},"n2189015897":{"id":"n2189015897","loc":[-85.6376839,41.9566137]},"n2189015900":{"id":"n2189015900","loc":[-85.6376831,41.9564865]},"n2189015903":{"id":"n2189015903","loc":[-85.6381161,41.9564851]},"n2189015906":{"id":"n2189015906","loc":[-85.6381168,41.9566122]},"n2189015937":{"id":"n2189015937","loc":[-85.6364789,41.9590634]},"n2189015940":{"id":"n2189015940","loc":[-85.6361137,41.9590672]},"n2189015943":{"id":"n2189015943","loc":[-85.6361169,41.9594033]},"n2189015945":{"id":"n2189015945","loc":[-85.6363456,41.9594021]},"n2189015952":{"id":"n2189015952","loc":[-85.636112,41.958892]},"n2189015955":{"id":"n2189015955","loc":[-85.6364757,41.9588894]},"n2189015957":{"id":"n2189015957","loc":[-85.6364729,41.9586747]},"n2189015958":{"id":"n2189015958","loc":[-85.6361103,41.9586765]},"n2189015959":{"id":"n2189015959","loc":[-85.6364719,41.9585562]},"n2189015960":{"id":"n2189015960","loc":[-85.6361093,41.958558]},"n2189015961":{"id":"n2189015961","loc":[-85.6355494,41.9586403]},"n2189015962":{"id":"n2189015962","loc":[-85.635549,41.9584711]},"n2189015963":{"id":"n2189015963","loc":[-85.6351831,41.9584715]},"n2189015964":{"id":"n2189015964","loc":[-85.6351834,41.9586408]},"n2189015966":{"id":"n2189015966","loc":[-85.6359579,41.9586359]},"n2189015968":{"id":"n2189015968","loc":[-85.6359561,41.9585465]},"n2189015971":{"id":"n2189015971","loc":[-85.6355476,41.9585509]},"n2189015974":{"id":"n2189015974","loc":[-85.6359516,41.9592934]},"n2189015977":{"id":"n2189015977","loc":[-85.635949,41.9586697]},"n2189015980":{"id":"n2189015980","loc":[-85.6351329,41.9586716]},"n2189015983":{"id":"n2189015983","loc":[-85.6351318,41.9583949]},"n2189015986":{"id":"n2189015986","loc":[-85.6349148,41.9583954]},"n2189015989":{"id":"n2189015989","loc":[-85.6349186,41.9592958]},"n2189015995":{"id":"n2189015995","loc":[-85.6360173,41.9593286]},"n2189015998":{"id":"n2189015998","loc":[-85.6360278,41.9583079]},"n2114807550":{"id":"n2114807550","loc":[-85.6383392,41.9595404]},"n2114807551":{"id":"n2114807551","loc":[-85.6375855,41.9616107]},"n2114807559":{"id":"n2114807559","loc":[-85.6373978,41.9621273]},"n2114807562":{"id":"n2114807562","loc":[-85.6373361,41.9622609]},"n2114807563":{"id":"n2114807563","loc":[-85.6376472,41.9613953]},"n2114807574":{"id":"n2114807574","loc":[-85.636974,41.9627695]},"n2114807589":{"id":"n2114807589","loc":[-85.6383017,41.9595005]},"n2114807592":{"id":"n2114807592","loc":[-85.6377169,41.9613494]},"n2114807595":{"id":"n2114807595","loc":[-85.6371081,41.962574]},"n2189015934":{"id":"n2189015934","loc":[-85.6364855,41.9595098]},"n2189015949":{"id":"n2189015949","loc":[-85.6363466,41.9595105]},"w208627244":{"id":"w208627244","tags":{"highway":"service"},"nodes":["n2189015992","n2189015995","n2189015998"]},"w208627240":{"id":"w208627240","tags":{"area":"yes","building":"yes"},"nodes":["n2189015961","n2189015971","n2189015962","n2189015963","n2189015964","n2189015961"]},"w17967437":{"id":"w17967437","tags":{"highway":"residential","name":"Lyman St"},"nodes":["n185964361","n185984024"]},"w208627237":{"id":"w208627237","tags":{"area":"yes","building":"yes"},"nodes":["n2189015955","n2189015957","n2189015958","n2189015952","n2189015955"]},"w17967465":{"id":"w17967465","tags":{"highway":"residential","name":"W Adams St"},"nodes":["n185978394","n185984022","n185964360"]},"w208627228":{"id":"w208627228","tags":{"area":"yes","building":"yes"},"nodes":["n2189015897","n2189015900","n2189015903","n2189015906","n2189015897"]},"w201484351":{"id":"w201484351","tags":{"railway":"rail","service":"siding"},"nodes":["n2114807587","n2114807574","n2114807595","n2114807562","n2114807559","n2114807551","n2114807563","n2114807589","n2114807552"]},"w208627239":{"id":"w208627239","tags":{"area":"yes","building":"yes"},"nodes":["n2189015957","n2189015959","n2189015960","n2189015958","n2189015957"]},"w208627233":{"id":"w208627233","tags":{"area":"yes","building":"yes"},"nodes":["n2189015934","n2189015937","n2189015940","n2189015943","n2189015945","n2189015949","n2189015934"]},"w208627241":{"id":"w208627241","tags":{"area":"yes","building":"yes"},"nodes":["n2189015961","n2189015966","n2189015968","n2189015971","n2189015961"]},"w17967970":{"id":"w17967970","tags":{"highway":"residential","name":"Adams St"},"nodes":["n185975351","n185978394"]},"w208627235":{"id":"w208627235","tags":{"area":"yes","building":"yes"},"nodes":["n2189015940","n2189015952","n2189015955","n2189015937","n2189015940"]},"w17965468":{"id":"w17965468","tags":{"highway":"residential","name":"Armstrong Blvd"},"nodes":["n185967917","n2189015998","n185967918","n185964362","n185952166"]},"w201484346":{"id":"w201484346","tags":{"railway":"rail","service":"siding"},"nodes":["n2114807551","n2114807592","n2114807550","n2114807591"]},"w208627242":{"id":"w208627242","tags":{"amenity":"parking","area":"yes"},"nodes":["n2189015974","n2189015977","n2189015980","n2189015983","n2189015986","n2189015989","n2189015974"]},"w208627216":{"id":"w208627216","tags":{"area":"yes","building":"yes"},"nodes":["n2189015731","n2189015734","n2189015737","n2189015738","n2189015731"]},"n185984309":{"id":"n185984309","loc":[-85.631421,41.961494]},"n185987987":{"id":"n185987987","loc":[-85.631456,41.960673]},"n185965397":{"id":"n185965397","loc":[-85.634603,41.959838]},"w17965196":{"id":"w17965196","tags":{"highway":"residential","name":"Burke Ave"},"nodes":["n185965395","n185965397","n185965399"]},"w17967215":{"id":"w17967215","tags":{"highway":"residential","name":"Kellogg Ave"},"nodes":["n185968114","n185984309","n185967440","n185978402"]},"w17967597":{"id":"w17967597","tags":{"highway":"residential","name":"Barnard Ave"},"nodes":["n185968112","n185987987","n185967438","n185978399"]},"n394490857":{"id":"n394490857","loc":[-85.633952,41.960664]},"n394490858":{"id":"n394490858","loc":[-85.633938,41.960227]},"n394490859":{"id":"n394490859","loc":[-85.634794,41.960212]},"n394490860":{"id":"n394490860","loc":[-85.634815,41.960662]},"n394490861":{"id":"n394490861","loc":[-85.634103,41.961268]},"n394490862":{"id":"n394490862","loc":[-85.634103,41.961001]},"n394490863":{"id":"n394490863","loc":[-85.634504,41.961003]},"n394490864":{"id":"n394490864","loc":[-85.634561,41.961269]},"n1057629869":{"id":"n1057629869","loc":[-85.6382599,41.9612134]},"n1057629937":{"id":"n1057629937","loc":[-85.6380035,41.9616137]},"n2189016014":{"id":"n2189016014","loc":[-85.6360365,41.9626496]},"n2189016017":{"id":"n2189016017","loc":[-85.6360374,41.9623228]},"n2189016020":{"id":"n2189016020","loc":[-85.6367557,41.9623239]},"n2189016022":{"id":"n2189016022","loc":[-85.6367566,41.9619919]},"n2189016025":{"id":"n2189016025","loc":[-85.6351794,41.9619893]},"n2189016028":{"id":"n2189016028","loc":[-85.6351788,41.9622011]},"n2189016031":{"id":"n2189016031","loc":[-85.6350855,41.9622009]},"n2189016034":{"id":"n2189016034","loc":[-85.6350845,41.962527]},"n2189016037":{"id":"n2189016037","loc":[-85.6352732,41.9625273]},"n2189016039":{"id":"n2189016039","loc":[-85.6352738,41.9623178]},"n2189016042":{"id":"n2189016042","loc":[-85.6357712,41.9623186]},"n2189016044":{"id":"n2189016044","loc":[-85.6357702,41.9626492]},"n1057629880":{"id":"n1057629880","loc":[-85.638817,41.9619017]},"n1057629923":{"id":"n1057629923","loc":[-85.6390733,41.9615014]},"w91092312":{"id":"w91092312","tags":{"power":"station"},"nodes":["n1057629923","n1057629869","n1057629937","n1057629880","n1057629923"]},"w34369826":{"id":"w34369826","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490861","n394490862","n394490863","n394490864","n394490861"]},"w34369825":{"id":"w34369825","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490857","n394490858","n394490859","n394490860","n394490857"]},"w208627248":{"id":"w208627248","tags":{"area":"yes","building":"yes"},"nodes":["n2189016014","n2189016017","n2189016020","n2189016022","n2189016025","n2189016028","n2189016031","n2189016034","n2189016037","n2189016039","n2189016042","n2189016044","n2189016014"]},"n394490766":{"id":"n394490766","loc":[-85.616777,41.955642]},"n394490768":{"id":"n394490768","loc":[-85.617239,41.955644]},"n394490792":{"id":"n394490792","loc":[-85.619034,41.95543]},"n185972055":{"id":"n185972055","loc":[-85.6185905,41.9568211]},"n185972057":{"id":"n185972057","loc":[-85.6186688,41.9570086]},"n185972059":{"id":"n185972059","loc":[-85.6186924,41.9581453]},"n185972060":{"id":"n185972060","loc":[-85.6187082,41.9588211],"tags":{"highway":"turning_circle"}},"n1819790724":{"id":"n1819790724","loc":[-85.6182155,41.9555703]},"n1819790735":{"id":"n1819790735","loc":[-85.6184059,41.9566188]},"n1819790799":{"id":"n1819790799","loc":[-85.6182372,41.9563771]},"n1819790896":{"id":"n1819790896","loc":[-85.6181431,41.9557227]},"n185971405":{"id":"n185971405","loc":[-85.6186766,41.9577468]},"n185971565":{"id":"n185971565","loc":[-85.6181613,41.9560879]},"n185967985":{"id":"n185967985","loc":[-85.6186798,41.9585791]},"n185955753":{"id":"n185955753","loc":[-85.620773,41.9555854]},"n185955755":{"id":"n185955755","loc":[-85.6212652,41.9559891]},"n185955748":{"id":"n185955748","loc":[-85.620722,41.954858]},"n185955751":{"id":"n185955751","loc":[-85.6206912,41.955367]},"n185967987":{"id":"n185967987","loc":[-85.6159351,41.9585809]},"n185971407":{"id":"n185971407","loc":[-85.6159142,41.9577578]},"n185971570":{"id":"n185971570","loc":[-85.6162248,41.95603]},"n185971572":{"id":"n185971572","loc":[-85.6160402,41.9560749]},"n185971574":{"id":"n185971574","loc":[-85.61593,41.956201]},"n185981301":{"id":"n185981301","loc":[-85.6158973,41.9581601]},"n394490762":{"id":"n394490762","loc":[-85.617193,41.954706]},"n394490764":{"id":"n394490764","loc":[-85.616773,41.954737]},"n394490787":{"id":"n394490787","loc":[-85.618972,41.954737]},"n394490790":{"id":"n394490790","loc":[-85.619046,41.954929]},"n394490794":{"id":"n394490794","loc":[-85.619922,41.955296]},"n394490796":{"id":"n394490796","loc":[-85.61991,41.95501]},"n394490798":{"id":"n394490798","loc":[-85.619974,41.954751]},"n1819790677":{"id":"n1819790677","loc":[-85.6187031,41.9550522]},"n1819790787":{"id":"n1819790787","loc":[-85.6186436,41.9552022]},"n1819790828":{"id":"n1819790828","loc":[-85.6185127,41.9553393]},"w17966857":{"id":"w17966857","tags":{"access":"private","highway":"service","name":"Sable River Rd"},"nodes":["n185972059","n185981301"]},"w34369814":{"id":"w34369814","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490787","n394490790","n394490792","n394490794","n394490796","n394490798","n394490787"]},"w17964176":{"id":"w17964176","tags":{"highway":"residential"},"nodes":["n185955747","n185955748","n185955751","n185955753","n185955755"]},"w17965838":{"id":"w17965838","tags":{"access":"private","highway":"service","name":"Pine River Rd"},"nodes":["n185971405","n185971407"]},"w17965476":{"id":"w17965476","tags":{"access":"private","highway":"service","name":"Raisin River Rd"},"nodes":["n185967985","n185967987"]},"w17965913":{"id":"w17965913","tags":{"access":"private","highway":"service","name":"Shiawassee River Rd"},"nodes":["n185972054","n1819790677","n1819790787","n1819790828","n1819790724","n1819790896","n185971565","n1819790799","n1819790735","n185972055","n185972057","n185971405","n185972059","n185967985","n185972060"]},"w34369811":{"id":"w34369811","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490762","n394490764","n394490766","n394490768","n394490762"]},"w17965854":{"id":"w17965854","tags":{"access":"private","highway":"service","name":"Sturgeon River Rd"},"nodes":["n185971565","n185971570","n185971572","n185971574"]},"n2139795769":{"id":"n2139795769","loc":[-85.6250804,41.9608796]},"n2139795770":{"id":"n2139795770","loc":[-85.6250315,41.9613684]},"n2139795771":{"id":"n2139795771","loc":[-85.6249671,41.9614362]},"n2139795772":{"id":"n2139795772","loc":[-85.6249698,41.961522]},"n2139795773":{"id":"n2139795773","loc":[-85.6250798,41.9615838]},"n2139795774":{"id":"n2139795774","loc":[-85.6252273,41.9615639]},"n2139795775":{"id":"n2139795775","loc":[-85.6252863,41.9614622]},"n2139795776":{"id":"n2139795776","loc":[-85.6252273,41.9613764]},"n2139795777":{"id":"n2139795777","loc":[-85.6251227,41.9613525]},"n2139795778":{"id":"n2139795778","loc":[-85.6249564,41.9612527]},"n2139795779":{"id":"n2139795779","loc":[-85.6249846,41.9610254]},"n2139795780":{"id":"n2139795780","loc":[-85.6266725,41.9599647]},"n2139795781":{"id":"n2139795781","loc":[-85.6259162,41.9599711]},"n2139795782":{"id":"n2139795782","loc":[-85.6257185,41.960019]},"n2139795783":{"id":"n2139795783","loc":[-85.6255509,41.9601213]},"n185963539":{"id":"n185963539","loc":[-85.615718,41.983893]},"n185964418":{"id":"n185964418","loc":[-85.616626,42.049512]},"n185966614":{"id":"n185966614","loc":[-85.615514,41.976603]},"n185966635":{"id":"n185966635","loc":[-85.616118,42.013017]},"n185969040":{"id":"n185969040","loc":[-85.615632,41.972357]},"n185969070":{"id":"n185969070","loc":[-85.619145,41.967648]},"n185972156":{"id":"n185972156","loc":[-85.621894,41.963956]},"n185972157":{"id":"n185972157","loc":[-85.621806,41.964077]},"n185972158":{"id":"n185972158","loc":[-85.620848,41.965341]},"n185972159":{"id":"n185972159","loc":[-85.620684,41.965558]},"n185972160":{"id":"n185972160","loc":[-85.620621,41.965658]},"n185972161":{"id":"n185972161","loc":[-85.617844,41.969359]},"n185972162":{"id":"n185972162","loc":[-85.616843,41.97068]},"n185972164":{"id":"n185972164","loc":[-85.616714,41.970839]},"n185972166":{"id":"n185972166","loc":[-85.615879,41.971969]},"n185972168":{"id":"n185972168","loc":[-85.615748,41.972159]},"n185972170":{"id":"n185972170","loc":[-85.615589,41.972502]},"n185972172":{"id":"n185972172","loc":[-85.615542,41.972733]},"n185972175":{"id":"n185972175","loc":[-85.615524,41.972947]},"n185972177":{"id":"n185972177","loc":[-85.615512,41.973715]},"n185972179":{"id":"n185972179","loc":[-85.615513,41.976496]},"n185972180":{"id":"n185972180","loc":[-85.615538,41.977246]},"n185972181":{"id":"n185972181","loc":[-85.61558,41.982139]},"n185972184":{"id":"n185972184","loc":[-85.61557,41.983317]},"n185972186":{"id":"n185972186","loc":[-85.615591,41.983463]},"n185972188":{"id":"n185972188","loc":[-85.615763,41.984146]},"n185972190":{"id":"n185972190","loc":[-85.615814,41.98435]},"n185972192":{"id":"n185972192","loc":[-85.615965,41.998453]},"n185972194":{"id":"n185972194","loc":[-85.615982,42.001237]},"n185972195":{"id":"n185972195","loc":[-85.616055,42.00555]},"n185972197":{"id":"n185972197","loc":[-85.616134,42.014887]},"n185972199":{"id":"n185972199","loc":[-85.616177,42.018465]},"n185972201":{"id":"n185972201","loc":[-85.616298,42.027627]},"n185972203":{"id":"n185972203","loc":[-85.616513,42.042212]},"w203968015":{"id":"w203968015","tags":{"highway":"residential"},"nodes":["n2139795768","n2139795769"]},"w17965932":{"id":"w17965932","tags":{"highway":"residential","name":"Buckhorn Road","name_1":"County Highway 122"},"nodes":["n185972155","n185972156","n185972157","n185972158","n185972159","n185972160","n185969070","n185972161","n185972162","n185972164","n185972166","n185972168","n185969040","n185972170","n185972172","n185972175","n185972177","n185972179","n185966614","n185972180","n185972181","n185972184","n185972186","n185963539","n185972188","n185972190","n185972192","n185972194","n185972195","n185966635","n185972197","n185972199","n185972201","n185972203","n185964418"]},"w203968016":{"id":"w203968016","tags":{"highway":"residential","name":"New Jersey Court"},"nodes":["n2139795770","n2139795771","n2139795772","n2139795773","n2139795774","n2139795775","n2139795776","n2139795777","n2139795770","n2139795778","n2139795779","n2139795769"]},"w203968017":{"id":"w203968017","tags":{"highway":"residential","name":"Oklahoma Drive"},"nodes":["n2139795780","n2139795781","n2139795782","n2139795783","n2139795769"]},"n1819790528":{"id":"n1819790528","loc":[-85.6184827,41.960025]},"n1819790530":{"id":"n1819790530","loc":[-85.6168626,41.9605834]},"n1819790534":{"id":"n1819790534","loc":[-85.6197379,41.9617163]},"n1819790541":{"id":"n1819790541","loc":[-85.6198881,41.9620833]},"n1819790543":{"id":"n1819790543","loc":[-85.619695,41.9619397]},"n1819790547":{"id":"n1819790547","loc":[-85.6190298,41.9609504]},"n1819790555":{"id":"n1819790555","loc":[-85.6180471,41.9609788]},"n1819790559":{"id":"n1819790559","loc":[-85.6203817,41.9605436]},"n1819790583":{"id":"n1819790583","loc":[-85.6201564,41.9603282]},"n1819790590":{"id":"n1819790590","loc":[-85.617045,41.9598894]},"n1819790609":{"id":"n1819790609","loc":[-85.6177638,41.9598495]},"n1819790618":{"id":"n1819790618","loc":[-85.6195234,41.9610143]},"n1819790642":{"id":"n1819790642","loc":[-85.6181179,41.9627933]},"n1819790659":{"id":"n1819790659","loc":[-85.6174634,41.962897]},"n1819790665":{"id":"n1819790665","loc":[-85.6170343,41.9630885]},"n1819790674":{"id":"n1819790674","loc":[-85.6194697,41.9601925]},"n1819790685":{"id":"n1819790685","loc":[-85.6207722,41.9610665]},"n1819790687":{"id":"n1819790687","loc":[-85.6202315,41.9622109]},"n1819790697":{"id":"n1819790697","loc":[-85.6184505,41.9624662]},"n1819790726":{"id":"n1819790726","loc":[-85.6178926,41.9628492]},"n1819790738":{"id":"n1819790738","loc":[-85.6173347,41.9598016]},"n1819790762":{"id":"n1819790762","loc":[-85.6186221,41.9609105]},"n1819790774":{"id":"n1819790774","loc":[-85.6175922,41.9608308]},"n1819790781":{"id":"n1819790781","loc":[-85.6167768,41.9633198]},"n1819790796":{"id":"n1819790796","loc":[-85.619856,41.961461]},"n1819790811":{"id":"n1819790811","loc":[-85.6208215,41.9620195]},"n1819790833":{"id":"n1819790833","loc":[-85.618311,41.9612536]},"n1819790854":{"id":"n1819790854","loc":[-85.6183646,41.9626417]},"n1819790863":{"id":"n1819790863","loc":[-85.6204997,41.9608547]},"n1819790867":{"id":"n1819790867","loc":[-85.6184934,41.9621391]},"n1819790877":{"id":"n1819790877","loc":[-85.6206928,41.9621152]},"n1819790881":{"id":"n1819790881","loc":[-85.6170879,41.960735]},"n1819790891":{"id":"n1819790891","loc":[-85.6168304,41.9601207]},"n1819790898":{"id":"n1819790898","loc":[-85.619813,41.9612297]},"n1819790909":{"id":"n1819790909","loc":[-85.6167982,41.960376]},"n1819790912":{"id":"n1819790912","loc":[-85.6205855,41.9610462]},"n1819790544":{"id":"n1819790544","loc":[-85.612968,41.9707781]},"n1819790549":{"id":"n1819790549","loc":[-85.614395,41.9697172]},"n1819790552":{"id":"n1819790552","loc":[-85.6180535,41.9655536]},"n1819790554":{"id":"n1819790554","loc":[-85.6111227,41.9703713]},"n1819790560":{"id":"n1819790560","loc":[-85.6112729,41.9701958]},"n1819790563":{"id":"n1819790563","loc":[-85.6137512,41.9689917]},"n1819790564":{"id":"n1819790564","loc":[-85.6181072,41.9659205]},"n1819790595":{"id":"n1819790595","loc":[-85.6170021,41.9666863]},"n1819790605":{"id":"n1819790605","loc":[-85.6168948,41.9644527]},"n1819790606":{"id":"n1819790606","loc":[-85.6128071,41.9701081]},"n1819790607":{"id":"n1819790607","loc":[-85.6129251,41.9704032]},"n1819790612":{"id":"n1819790612","loc":[-85.6177638,41.9663912]},"n1819790615":{"id":"n1819790615","loc":[-85.6152533,41.9670373]},"n1819790622":{"id":"n1819790622","loc":[-85.6146739,41.9673804]},"n1819790623":{"id":"n1819790623","loc":[-85.6180428,41.9661838]},"n1819790625":{"id":"n1819790625","loc":[-85.6172918,41.9646202]},"n1819790645":{"id":"n1819790645","loc":[-85.6178067,41.965043]},"n1819790647":{"id":"n1819790647","loc":[-85.6143306,41.9712488]},"n1819790649":{"id":"n1819790649","loc":[-85.6147383,41.9707702]},"n1819790654":{"id":"n1819790654","loc":[-85.6157361,41.9668459]},"n1819790657":{"id":"n1819790657","loc":[-85.6145666,41.9710733]},"n1819790668":{"id":"n1819790668","loc":[-85.6166909,41.9642692]},"n1819790671":{"id":"n1819790671","loc":[-85.6141482,41.9696538]},"n1819790679":{"id":"n1819790679","loc":[-85.6148349,41.9705388]},"n1819790686":{"id":"n1819790686","loc":[-85.6139551,41.9695501]},"n1819790696":{"id":"n1819790696","loc":[-85.6119703,41.9699087]},"n1819790704":{"id":"n1819790704","loc":[-85.6140731,41.9684174]},"n1819790706":{"id":"n1819790706","loc":[-85.6124745,41.9699246]},"n1819790718":{"id":"n1819790718","loc":[-85.6165407,41.9636868]},"n1819790720":{"id":"n1819790720","loc":[-85.61388,41.9687365]},"n1819790731":{"id":"n1819790731","loc":[-85.6165193,41.9639421]},"n1819790739":{"id":"n1819790739","loc":[-85.6146739,41.9699964]},"n1819790753":{"id":"n1819790753","loc":[-85.6173883,41.9665747]},"n1819790760":{"id":"n1819790760","loc":[-85.6133221,41.9712089]},"n1819790767":{"id":"n1819790767","loc":[-85.6116698,41.9699246]},"n1819790779":{"id":"n1819790779","loc":[-85.6130753,41.9710573]},"n1819790791":{"id":"n1819790791","loc":[-85.6137083,41.9692869]},"n1819790795":{"id":"n1819790795","loc":[-85.6141482,41.9679627]},"n1819790798":{"id":"n1819790798","loc":[-85.6137727,41.9694305]},"n1819790836":{"id":"n1819790836","loc":[-85.6143842,41.9676037]},"n1819790915":{"id":"n1819790915","loc":[-85.6148456,41.9702756]},"n1819790926":{"id":"n1819790926","loc":[-85.6138371,41.9713525]},"n1819790927":{"id":"n1819790927","loc":[-85.6141053,41.9713525]},"n1819790931":{"id":"n1819790931","loc":[-85.6162832,41.966814]},"n1821014625":{"id":"n1821014625","loc":[-85.5960611,41.9808498]},"n1821014627":{"id":"n1821014627","loc":[-85.5565843,42.010982]},"n1821014629":{"id":"n1821014629","loc":[-85.5971541,41.9805808]},"n1821014632":{"id":"n1821014632","loc":[-85.6061837,41.9725907]},"n1821014633":{"id":"n1821014633","loc":[-85.5247773,42.025766]},"n1821014635":{"id":"n1821014635","loc":[-85.5908938,41.9902384]},"n1821014636":{"id":"n1821014636","loc":[-85.5917682,41.9860637]},"n1821014637":{"id":"n1821014637","loc":[-85.5456556,42.0166797]},"n1821014638":{"id":"n1821014638","loc":[-85.5795749,42.0032352]},"n1821014639":{"id":"n1821014639","loc":[-85.6103988,41.9723456]},"n1821014642":{"id":"n1821014642","loc":[-85.5818816,42.0022466]},"n1821014643":{"id":"n1821014643","loc":[-85.5570604,42.0091586]},"n1821014644":{"id":"n1821014644","loc":[-85.5952886,41.9803792]},"n1821014645":{"id":"n1821014645","loc":[-85.5780366,42.0040343]},"n1821014646":{"id":"n1821014646","loc":[-85.6050505,41.9751971]},"n1821014647":{"id":"n1821014647","loc":[-85.5854435,41.9946162]},"n1821014648":{"id":"n1821014648","loc":[-85.5452278,42.0168768]},"n1821014649":{"id":"n1821014649","loc":[-85.6023254,41.9780166]},"n1821014651":{"id":"n1821014651","loc":[-85.5761899,42.0046783]},"n1821014653":{"id":"n1821014653","loc":[-85.5897351,41.9876707]},"n1821014657":{"id":"n1821014657","loc":[-85.5963601,41.9808998]},"n1821014658":{"id":"n1821014658","loc":[-85.5892952,41.9951983]},"n1821014660":{"id":"n1821014660","loc":[-85.5778328,42.0037194]},"n1821014661":{"id":"n1821014661","loc":[-85.5541475,42.0125705]},"n1821014663":{"id":"n1821014663","loc":[-85.5914047,41.9856469]},"n1821014664":{"id":"n1821014664","loc":[-85.6101681,41.9727723]},"n1821014665":{"id":"n1821014665","loc":[-85.5910172,41.9854696]},"n1821014666":{"id":"n1821014666","loc":[-85.5398688,42.0187699]},"n1821014667":{"id":"n1821014667","loc":[-85.5218752,42.0282884]},"n1821014668":{"id":"n1821014668","loc":[-85.5159582,42.0329384]},"n1821014669":{"id":"n1821014669","loc":[-85.5898102,41.9847319]},"n1821014670":{"id":"n1821014670","loc":[-85.5734809,42.0066235]},"n1821014671":{"id":"n1821014671","loc":[-85.5922939,41.980852]},"n1821014672":{"id":"n1821014672","loc":[-85.6023629,41.9781163]},"n1821014674":{"id":"n1821014674","loc":[-85.5409953,42.0191724]},"n1821014676":{"id":"n1821014676","loc":[-85.584435,41.9949909]},"n1821014677":{"id":"n1821014677","loc":[-85.5972399,41.9783835]},"n1821014678":{"id":"n1821014678","loc":[-85.5616738,42.0071337]},"n1821014681":{"id":"n1821014681","loc":[-85.5202994,42.0310755]},"n1821014682":{"id":"n1821014682","loc":[-85.5915912,41.9857767]},"n1821014684":{"id":"n1821014684","loc":[-85.6022288,41.977897]},"n1821014687":{"id":"n1821014687","loc":[-85.5933024,41.9846362]},"n1821014688":{"id":"n1821014688","loc":[-85.5846871,41.9956169]},"n1821014689":{"id":"n1821014689","loc":[-85.5898209,41.99037]},"n1821014691":{"id":"n1821014691","loc":[-85.5448939,42.0149261]},"n1821014692":{"id":"n1821014692","loc":[-85.5977763,41.9786348]},"n1821014694":{"id":"n1821014694","loc":[-85.5767706,42.0034523]},"n1821014695":{"id":"n1821014695","loc":[-85.6103559,41.9726766]},"n1821014697":{"id":"n1821014697","loc":[-85.5922134,41.9809876]},"n1821014698":{"id":"n1821014698","loc":[-85.5935277,41.9831728]},"n1821014700":{"id":"n1821014700","loc":[-85.5674674,42.0078273]},"n1821014703":{"id":"n1821014703","loc":[-85.6021,41.9778053]},"n1821014704":{"id":"n1821014704","loc":[-85.5756763,42.0053737]},"n1821014705":{"id":"n1821014705","loc":[-85.5887695,41.9895207]},"n1821014707":{"id":"n1821014707","loc":[-85.6061073,41.9746866]},"n1821014708":{"id":"n1821014708","loc":[-85.6033446,41.9751692]},"n1821014710":{"id":"n1821014710","loc":[-85.5180986,42.0322332]},"n1821014711":{"id":"n1821014711","loc":[-85.543365,42.0163569]},"n1821014712":{"id":"n1821014712","loc":[-85.6030656,41.9753646]},"n1821014713":{"id":"n1821014713","loc":[-85.6104417,41.9704792]},"n1821014714":{"id":"n1821014714","loc":[-85.5205716,42.030998]},"n1821014716":{"id":"n1821014716","loc":[-85.516382,42.032536]},"n1821014717":{"id":"n1821014717","loc":[-85.5932863,41.9820882]},"n1821014718":{"id":"n1821014718","loc":[-85.5361928,42.0194974]},"n1821014720":{"id":"n1821014720","loc":[-85.6011613,41.9773586]},"n1821014721":{"id":"n1821014721","loc":[-85.554287,42.0109124]},"n1821014722":{"id":"n1821014722","loc":[-85.5577524,42.0103425]},"n1821014725":{"id":"n1821014725","loc":[-85.5867256,41.9921004]},"n1821014726":{"id":"n1821014726","loc":[-85.5856045,41.9968807]},"n1821014727":{"id":"n1821014727","loc":[-85.5545445,42.0106454]},"n1821014728":{"id":"n1821014728","loc":[-85.5923797,41.9842534]},"n1821014729":{"id":"n1821014729","loc":[-85.5696346,42.0081462]},"n1821014730":{"id":"n1821014730","loc":[-85.5998322,41.9786884]},"n1821014735":{"id":"n1821014735","loc":[-85.5337426,42.0218266]},"n1821014736":{"id":"n1821014736","loc":[-85.5847944,41.994672]},"n1821014740":{"id":"n1821014740","loc":[-85.5315271,42.0238669]},"n1821014741":{"id":"n1821014741","loc":[-85.5248846,42.027085]},"n1821014742":{"id":"n1821014742","loc":[-85.5853376,41.997018]},"n1821014743":{"id":"n1821014743","loc":[-85.5894883,41.988811]},"n1821014745":{"id":"n1821014745","loc":[-85.6095311,41.9726226]},"n1821014746":{"id":"n1821014746","loc":[-85.5531511,42.0133416]},"n1821014747":{"id":"n1821014747","loc":[-85.5735882,42.007058]},"n1821014749":{"id":"n1821014749","loc":[-85.5428554,42.0164366]},"n1821014751":{"id":"n1821014751","loc":[-85.5395255,42.0186304]},"n1821014752":{"id":"n1821014752","loc":[-85.571378,42.0083176]},"n1821014754":{"id":"n1821014754","loc":[-85.5541918,42.0113925]},"n1821014755":{"id":"n1821014755","loc":[-85.5278029,42.0250806]},"n1821014756":{"id":"n1821014756","loc":[-85.5936725,41.9827102]},"n1821014757":{"id":"n1821014757","loc":[-85.5176266,42.0346677]},"n1821014758":{"id":"n1821014758","loc":[-85.6096692,41.9714245]},"n1821014759":{"id":"n1821014759","loc":[-85.5770321,42.0034266]},"n1821014761":{"id":"n1821014761","loc":[-85.5988921,41.9779369]},"n1821014762":{"id":"n1821014762","loc":[-85.5811788,42.0024499]},"n1821014763":{"id":"n1821014763","loc":[-85.5154003,42.0381101]},"n1821014764":{"id":"n1821014764","loc":[-85.5155827,42.0374089]},"n1821014765":{"id":"n1821014765","loc":[-85.5891249,41.9884978]},"n1821014766":{"id":"n1821014766","loc":[-85.5313863,42.0238293]},"n1821014768":{"id":"n1821014768","loc":[-85.593297,41.9833363]},"n1821014769":{"id":"n1821014769","loc":[-85.5849446,41.9957245]},"n1821014770":{"id":"n1821014770","loc":[-85.5537774,42.0130847]},"n1821014771":{"id":"n1821014771","loc":[-85.6111766,41.9706069]},"n1821014772":{"id":"n1821014772","loc":[-85.5585477,42.008989]},"n1821014774":{"id":"n1821014774","loc":[-85.5928142,41.9852623]},"n1821014777":{"id":"n1821014777","loc":[-85.5891933,41.9882608]},"n1821014778":{"id":"n1821014778","loc":[-85.5926909,41.9817532]},"n1821014779":{"id":"n1821014779","loc":[-85.5260272,42.0252201]},"n1821014781":{"id":"n1821014781","loc":[-85.5894615,41.9950468]},"n1821014782":{"id":"n1821014782","loc":[-85.5461063,42.0143242]},"n1821014783":{"id":"n1821014783","loc":[-85.5711527,42.0085886]},"n1821014784":{"id":"n1821014784","loc":[-85.5329379,42.0218624]},"n1821014786":{"id":"n1821014786","loc":[-85.583047,42.0020252]},"n1821014787":{"id":"n1821014787","loc":[-85.5758962,42.0054095]},"n1821014788":{"id":"n1821014788","loc":[-85.5626354,42.0077733]},"n1821014789":{"id":"n1821014789","loc":[-85.6029852,41.9755999]},"n1821014790":{"id":"n1821014790","loc":[-85.5892362,41.9886755]},"n1821014791":{"id":"n1821014791","loc":[-85.5157597,42.0372017]},"n1821014793":{"id":"n1821014793","loc":[-85.6054582,41.9751094]},"n1821014794":{"id":"n1821014794","loc":[-85.5986936,41.9778412]},"n1821014795":{"id":"n1821014795","loc":[-85.5880775,41.98976]},"n1821014796":{"id":"n1821014796","loc":[-85.5858727,41.9963624]},"n1821014798":{"id":"n1821014798","loc":[-85.5792543,42.0035958]},"n1821014799":{"id":"n1821014799","loc":[-85.5921665,41.9838326]},"n1821014801":{"id":"n1821014801","loc":[-85.599214,41.9782599]},"n1821014802":{"id":"n1821014802","loc":[-85.5571905,42.0090967]},"n1821014803":{"id":"n1821014803","loc":[-85.5426891,42.0173612]},"n1821014804":{"id":"n1821014804","loc":[-85.5889626,41.9896404]},"n1821014805":{"id":"n1821014805","loc":[-85.5491264,42.0141648]},"n1821014806":{"id":"n1821014806","loc":[-85.5618897,42.0072631]},"n1821014808":{"id":"n1821014808","loc":[-85.5573501,42.0109802]},"n1821014809":{"id":"n1821014809","loc":[-85.5983463,41.9778031]},"n1821014810":{"id":"n1821014810","loc":[-85.5885173,41.9895128]},"n1821014811":{"id":"n1821014811","loc":[-85.6084998,41.9721143]},"n1821014812":{"id":"n1821014812","loc":[-85.5737598,42.0056389]},"n1821014814":{"id":"n1821014814","loc":[-85.5542173,42.0118132]},"n1821014816":{"id":"n1821014816","loc":[-85.5277868,42.024451]},"n1821014817":{"id":"n1821014817","loc":[-85.5403999,42.0191724]},"n1821014819":{"id":"n1821014819","loc":[-85.5983879,41.9791452]},"n1821014820":{"id":"n1821014820","loc":[-85.5891302,41.9897578]},"n1821014822":{"id":"n1821014822","loc":[-85.5930731,41.9805108]},"n1821014824":{"id":"n1821014824","loc":[-85.515395,42.0378471]},"n1821014825":{"id":"n1821014825","loc":[-85.5352755,42.0205136]},"n1821014826":{"id":"n1821014826","loc":[-85.5502744,42.0133398]},"n1821014828":{"id":"n1821014828","loc":[-85.5701295,42.0088256]},"n1821014830":{"id":"n1821014830","loc":[-85.5888929,41.9953099]},"n1821014832":{"id":"n1821014832","loc":[-85.5880077,41.9901547]},"n1821014833":{"id":"n1821014833","loc":[-85.5451192,42.0157072]},"n1821014834":{"id":"n1821014834","loc":[-85.6096478,41.9711932]},"n1821014835":{"id":"n1821014835","loc":[-85.5806424,42.0026532]},"n1821014836":{"id":"n1821014836","loc":[-85.5911674,41.9868732]},"n1821014838":{"id":"n1821014838","loc":[-85.5930302,41.9836571]},"n1821014839":{"id":"n1821014839","loc":[-85.588925,41.9938148]},"n1821014840":{"id":"n1821014840","loc":[-85.6111874,41.9705311]},"n1821014841":{"id":"n1821014841","loc":[-85.5680843,42.0075842]},"n1821014842":{"id":"n1821014842","loc":[-85.6012793,41.9775062]},"n1821014843":{"id":"n1821014843","loc":[-85.5855562,41.9989777]},"n1821014844":{"id":"n1821014844","loc":[-85.5506137,42.0131662]},"n1821014845":{"id":"n1821014845","loc":[-85.5270049,42.025457]},"n1821014846":{"id":"n1821014846","loc":[-85.5257054,42.025244]},"n1821014847":{"id":"n1821014847","loc":[-85.6011184,41.9771832]},"n1821014848":{"id":"n1821014848","loc":[-85.515534,42.0389234]},"n1821014850":{"id":"n1821014850","loc":[-85.5847032,42.0010347]},"n1821014853":{"id":"n1821014853","loc":[-85.5361499,42.019063]},"n1821014854":{"id":"n1821014854","loc":[-85.5439176,42.0165721]},"n1821014855":{"id":"n1821014855","loc":[-85.5838825,42.0017284]},"n1821014857":{"id":"n1821014857","loc":[-85.5542173,42.0122317]},"n1821014859":{"id":"n1821014859","loc":[-85.5708201,42.0089195]},"n1821014860":{"id":"n1821014860","loc":[-85.5844833,41.9954415]},"n1821014862":{"id":"n1821014862","loc":[-85.5223204,42.0295396]},"n1821014863":{"id":"n1821014863","loc":[-85.5777898,42.0035918]},"n1821014864":{"id":"n1821014864","loc":[-85.591044,41.9898078]},"n1821014865":{"id":"n1821014865","loc":[-85.5973204,41.980182]},"n1821014866":{"id":"n1821014866","loc":[-85.5699578,42.0085825]},"n1821014867":{"id":"n1821014867","loc":[-85.5210598,42.0305278]},"n1821014868":{"id":"n1821014868","loc":[-85.5929108,41.9819008]},"n1821014869":{"id":"n1821014869","loc":[-85.5279799,42.0242995]},"n1821014870":{"id":"n1821014870","loc":[-85.5196114,42.0320539]},"n1821014871":{"id":"n1821014871","loc":[-85.5785449,42.0040883]},"n1821014872":{"id":"n1821014872","loc":[-85.588292,41.9895766]},"n1821014873":{"id":"n1821014873","loc":[-85.5160172,42.0331775]},"n1821014874":{"id":"n1821014874","loc":[-85.5688849,42.0077016]},"n1821014876":{"id":"n1821014876","loc":[-85.5857976,41.9996036]},"n1821014879":{"id":"n1821014879","loc":[-85.5990906,41.9780765]},"n1821014881":{"id":"n1821014881","loc":[-85.5483647,42.0144279]},"n1821014883":{"id":"n1821014883","loc":[-85.5691209,42.0077972]},"n1821014885":{"id":"n1821014885","loc":[-85.6076844,41.9721103]},"n1821014886":{"id":"n1821014886","loc":[-85.6015489,41.9766147]},"n1821014887":{"id":"n1821014887","loc":[-85.574822,42.0052802]},"n1821014888":{"id":"n1821014888","loc":[-85.5880024,41.9899593]},"n1821014890":{"id":"n1821014890","loc":[-85.5909421,41.9893772]},"n1821014892":{"id":"n1821014892","loc":[-85.5497326,42.0138141]},"n1821014893":{"id":"n1821014893","loc":[-85.5167106,42.0357811]},"n1821014895":{"id":"n1821014895","loc":[-85.5844404,41.9952501]},"n1821014896":{"id":"n1821014896","loc":[-85.5362465,42.0192662]},"n1821014898":{"id":"n1821014898","loc":[-85.5906095,41.9889147]},"n1821014899":{"id":"n1821014899","loc":[-85.5590667,42.0089354]},"n1821014900":{"id":"n1821014900","loc":[-85.5921598,41.9844209]},"n1821014902":{"id":"n1821014902","loc":[-85.5778971,42.0039266]},"n1821014903":{"id":"n1821014903","loc":[-85.603012,41.9761981]},"n1821014904":{"id":"n1821014904","loc":[-85.6108977,41.9706787]},"n1821014905":{"id":"n1821014905","loc":[-85.5685738,42.0076139]},"n1821014906":{"id":"n1821014906","loc":[-85.5392787,42.0186304]},"n1821014907":{"id":"n1821014907","loc":[-85.5227885,42.0274972]},"n1821014908":{"id":"n1821014908","loc":[-85.5857547,41.9961431]},"n1821014910":{"id":"n1821014910","loc":[-85.5610354,42.0072812]},"n1821014911":{"id":"n1821014911","loc":[-85.5209632,42.0308705]},"n1821014912":{"id":"n1821014912","loc":[-85.5709757,42.0087959]},"n1821014913":{"id":"n1821014913","loc":[-85.59231,41.9839344]},"n1821014914":{"id":"n1821014914","loc":[-85.5375245,42.0185865]},"n1821014916":{"id":"n1821014916","loc":[-85.5901548,41.9839841]},"n1821014917":{"id":"n1821014917","loc":[-85.5611213,42.0086405]},"n1821014918":{"id":"n1821014918","loc":[-85.5360426,42.0198122]},"n1821014919":{"id":"n1821014919","loc":[-85.5862817,41.9948691]},"n1821014921":{"id":"n1821014921","loc":[-85.5469807,42.0144438]},"n1821014922":{"id":"n1821014922","loc":[-85.5761309,42.0053838]},"n1821014924":{"id":"n1821014924","loc":[-85.516264,42.0332971]},"n1821014925":{"id":"n1821014925","loc":[-85.5277224,42.0246661]},"n1821014926":{"id":"n1821014926","loc":[-85.5980016,41.9798231]},"n1821014928":{"id":"n1821014928","loc":[-85.5924548,41.9806965]},"n1821014930":{"id":"n1821014930","loc":[-85.5899121,41.985023]},"n1821014931":{"id":"n1821014931","loc":[-85.5706015,42.0089492]},"n1821014932":{"id":"n1821014932","loc":[-85.515926,42.033046]},"n1821014933":{"id":"n1821014933","loc":[-85.5982377,41.9796796]},"n1821014936":{"id":"n1821014936","loc":[-85.5475721,42.0145253]},"n1821014938":{"id":"n1821014938","loc":[-85.5895701,41.9902323]},"n1821014939":{"id":"n1821014939","loc":[-85.6030495,41.9759947]},"n1821014942":{"id":"n1821014942","loc":[-85.6094721,41.9724989]},"n1821014944":{"id":"n1821014944","loc":[-85.5921973,41.9811112]},"n1821014945":{"id":"n1821014945","loc":[-85.5223526,42.0291332]},"n1821014946":{"id":"n1821014946","loc":[-85.5965103,41.9808998]},"n1821014948":{"id":"n1821014948","loc":[-85.517766,42.0349227]},"n1821014950":{"id":"n1821014950","loc":[-85.5889894,41.990996]},"n1821014951":{"id":"n1821014951","loc":[-85.5601932,42.0092902]},"n1821014954":{"id":"n1821014954","loc":[-85.6028135,41.9764055]},"n1821014955":{"id":"n1821014955","loc":[-85.5520621,42.0130666]},"n1821014956":{"id":"n1821014956","loc":[-85.593002,41.9839344]},"n1821014957":{"id":"n1821014957","loc":[-85.515926,42.0369666]},"n1821014960":{"id":"n1821014960","loc":[-85.5761255,42.003877]},"n1821014961":{"id":"n1821014961","loc":[-85.5716355,42.007911]},"n1821014962":{"id":"n1821014962","loc":[-85.5575378,42.0109045]},"n1821014963":{"id":"n1821014963","loc":[-85.5735667,42.0068188]},"n1821014964":{"id":"n1821014964","loc":[-85.5915214,41.9865861]},"n1821014965":{"id":"n1821014965","loc":[-85.5866344,41.9923157]},"n1821014967":{"id":"n1821014967","loc":[-85.5283138,42.0242256]},"n1821014968":{"id":"n1821014968","loc":[-85.5177875,42.0355801]},"n1821014969":{"id":"n1821014969","loc":[-85.548071,42.0144934]},"n1821014972":{"id":"n1821014972","loc":[-85.5611159,42.0088557]},"n1821014973":{"id":"n1821014973","loc":[-85.541686,42.0188757]},"n1821014974":{"id":"n1821014974","loc":[-85.5917628,41.9862631]},"n1821014975":{"id":"n1821014975","loc":[-85.5854864,41.9959478]},"n1821014977":{"id":"n1821014977","loc":[-85.609102,41.9722317]},"n1821014980":{"id":"n1821014980","loc":[-85.5761202,42.0042438]},"n1821014982":{"id":"n1821014982","loc":[-85.5465944,42.0143601]},"n1821014983":{"id":"n1821014983","loc":[-85.5173261,42.0342732]},"n1821014984":{"id":"n1821014984","loc":[-85.5897297,41.9888509]},"n1821014985":{"id":"n1821014985","loc":[-85.5856688,41.999181]},"n1821014986":{"id":"n1821014986","loc":[-85.5344011,42.0217251]},"n1821014987":{"id":"n1821014987","loc":[-85.601467,41.9768203]},"n1821014988":{"id":"n1821014988","loc":[-85.5457254,42.0165123]},"n1821014989":{"id":"n1821014989","loc":[-85.6023482,41.9784332]},"n1821014991":{"id":"n1821014991","loc":[-85.5361606,42.01823]},"n1821014992":{"id":"n1821014992","loc":[-85.5178465,42.0351139]},"n1821014995":{"id":"n1821014995","loc":[-85.5634293,42.0078092]},"n1821014996":{"id":"n1821014996","loc":[-85.573497,42.0072015]},"n1821014997":{"id":"n1821014997","loc":[-85.5976328,41.9799725]},"n1821014998":{"id":"n1821014998","loc":[-85.5210651,42.0303166]},"n1821015003":{"id":"n1821015003","loc":[-85.5222131,42.0288064]},"n1821015004":{"id":"n1821015004","loc":[-85.5897941,41.984405]},"n1821015005":{"id":"n1821015005","loc":[-85.5975725,41.9776099]},"n1821015006":{"id":"n1821015006","loc":[-85.5765708,42.0034903]},"n1821015007":{"id":"n1821015007","loc":[-85.5250187,42.026559]},"n1821015009":{"id":"n1821015009","loc":[-85.5426998,42.0166279]},"n1821015010":{"id":"n1821015010","loc":[-85.5957606,41.9806584]},"n1821015011":{"id":"n1821015011","loc":[-85.5262753,42.0252497]},"n1821015012":{"id":"n1821015012","loc":[-85.5266455,42.0253374]},"n1821015014":{"id":"n1821015014","loc":[-85.5515632,42.0130187]},"n1821015015":{"id":"n1821015015","loc":[-85.6024058,41.9765212]},"n1821015017":{"id":"n1821015017","loc":[-85.5175032,42.0357156]},"n1821015018":{"id":"n1821015018","loc":[-85.5302718,42.0236039]},"n1821015019":{"id":"n1821015019","loc":[-85.6024005,41.9782759]},"n1821015020":{"id":"n1821015020","loc":[-85.5907758,41.9890821]},"n1821015021":{"id":"n1821015021","loc":[-85.6019445,41.9777215]},"n1821015022":{"id":"n1821015022","loc":[-85.5942854,41.9800881]},"n1821015024":{"id":"n1821015024","loc":[-85.5325826,42.0222711]},"n1821015029":{"id":"n1821015029","loc":[-85.555093,42.0105316]},"n1821015033":{"id":"n1821015033","loc":[-85.5249704,42.0270372]},"n1821015034":{"id":"n1821015034","loc":[-85.5243965,42.0272205]},"n1821015038":{"id":"n1821015038","loc":[-85.5413426,42.0190749]},"n1821015039":{"id":"n1821015039","loc":[-85.5920431,41.9848175]},"n1821015041":{"id":"n1821015041","loc":[-85.5577685,42.0106015]},"n1821015042":{"id":"n1821015042","loc":[-85.5453606,42.0158866]},"n1821015045":{"id":"n1821015045","loc":[-85.5333228,42.0217889]},"n1821015046":{"id":"n1821015046","loc":[-85.5426891,42.0175924]},"n1821015048":{"id":"n1821015048","loc":[-85.5886836,41.9936474]},"n1821015050":{"id":"n1821015050","loc":[-85.6001152,41.9786467]},"n1821015051":{"id":"n1821015051","loc":[-85.6094064,41.9723655]},"n1821015053":{"id":"n1821015053","loc":[-85.605721,41.9749738]},"n1821015055":{"id":"n1821015055","loc":[-85.6106791,41.9705048]},"n1821015057":{"id":"n1821015057","loc":[-85.5210437,42.0307071]},"n1821015059":{"id":"n1821015059","loc":[-85.5995694,41.9786725]},"n1821015060":{"id":"n1821015060","loc":[-85.5371638,42.0182938]},"n1821015062":{"id":"n1821015062","loc":[-85.6111766,41.9704593]},"n1821015065":{"id":"n1821015065","loc":[-85.577704,42.0034921]},"n1821015067":{"id":"n1821015067","loc":[-85.5570067,42.0093699]},"n1821015068":{"id":"n1821015068","loc":[-85.5920364,41.9845525]},"n1821015069":{"id":"n1821015069","loc":[-85.5252065,42.0253954]},"n1821015072":{"id":"n1821015072","loc":[-85.5664159,42.0088517]},"n1821015073":{"id":"n1821015073","loc":[-85.5880399,41.991905]},"n1821015075":{"id":"n1821015075","loc":[-85.6099871,41.9727861]},"n1821015076":{"id":"n1821015076","loc":[-85.5319603,42.0231478]},"n1821015078":{"id":"n1821015078","loc":[-85.6036088,41.9751112]},"n1821015080":{"id":"n1821015080","loc":[-85.5983128,41.9789179]},"n1821015082":{"id":"n1821015082","loc":[-85.5614069,42.0071395]},"n1821015083":{"id":"n1821015083","loc":[-85.60968,41.9709738]},"n1821015086":{"id":"n1821015086","loc":[-85.5914195,41.9837351]},"n1821015087":{"id":"n1821015087","loc":[-85.5895473,41.9948036]},"n1821015090":{"id":"n1821015090","loc":[-85.5929913,41.9851905]},"n1821015093":{"id":"n1821015093","loc":[-85.5907396,41.9838485]},"n1821015095":{"id":"n1821015095","loc":[-85.5893864,41.9880176]},"n1821015096":{"id":"n1821015096","loc":[-85.5788024,42.0039807]},"n1821015097":{"id":"n1821015097","loc":[-85.5630592,42.0078411]},"n1821015098":{"id":"n1821015098","loc":[-85.5350609,42.0211274]},"n1821015099":{"id":"n1821015099","loc":[-85.5967195,41.9808679]},"n1821015100":{"id":"n1821015100","loc":[-85.5666734,42.0088119]},"n1821015101":{"id":"n1821015101","loc":[-85.564694,42.0077675]},"n1821015103":{"id":"n1821015103","loc":[-85.6066544,41.9726527]},"n1821015104":{"id":"n1821015104","loc":[-85.6011827,41.9769838]},"n1821015105":{"id":"n1821015105","loc":[-85.5972131,41.9776697]},"n1821015106":{"id":"n1821015106","loc":[-85.5880828,41.9903341]},"n1821015107":{"id":"n1821015107","loc":[-85.5510268,42.0130626]},"n1821015108":{"id":"n1821015108","loc":[-85.6102164,41.970543]},"n1821015109":{"id":"n1821015109","loc":[-85.5905344,41.9853899]},"n1821015111":{"id":"n1821015111","loc":[-85.5888821,41.9913429]},"n1821015112":{"id":"n1821015112","loc":[-85.606295,41.9741921]},"n1821015114":{"id":"n1821015114","loc":[-85.5969556,41.9807443]},"n1821015115":{"id":"n1821015115","loc":[-85.5882223,41.9934081]},"n1821015116":{"id":"n1821015116","loc":[-85.6104471,41.9724971]},"n1821015118":{"id":"n1821015118","loc":[-85.5406091,42.0192162]},"n1821015120":{"id":"n1821015120","loc":[-85.589955,41.9888429]},"n1821015121":{"id":"n1821015121","loc":[-85.5598821,42.0092304]},"n1821015122":{"id":"n1821015122","loc":[-85.545598,42.0144097]},"n1821015123":{"id":"n1821015123","loc":[-85.5649528,42.0079965]},"n1821015125":{"id":"n1821015125","loc":[-85.5883993,41.9917814]},"n1821015126":{"id":"n1821015126","loc":[-85.5295785,42.0239967]},"n1821015129":{"id":"n1821015129","loc":[-85.5648723,42.0078809]},"n1821015132":{"id":"n1821015132","loc":[-85.564989,42.0081103]},"n1821015133":{"id":"n1821015133","loc":[-85.5946127,41.9800841]},"n1821015134":{"id":"n1821015134","loc":[-85.583448,42.0019078]},"n1821015135":{"id":"n1821015135","loc":[-85.5905934,41.9871842]},"n1821015137":{"id":"n1821015137","loc":[-85.610608,41.9704752]},"n1821015138":{"id":"n1821015138","loc":[-85.5752257,42.0052939]},"n1821015139":{"id":"n1821015139","loc":[-85.5893864,41.9943491]},"n1821015140":{"id":"n1821015140","loc":[-85.5426247,42.0169866]},"n1821015141":{"id":"n1821015141","loc":[-85.562001,42.0074526]},"n1821015142":{"id":"n1821015142","loc":[-85.5212046,42.0301094]},"n1821015143":{"id":"n1821015143","loc":[-85.602214,41.9784531]},"n1821015144":{"id":"n1821015144","loc":[-85.5858687,41.9948293]},"n1821015145":{"id":"n1821015145","loc":[-85.5608477,42.0074805]},"n1821015146":{"id":"n1821015146","loc":[-85.5651607,42.0083614]},"n1821015147":{"id":"n1821015147","loc":[-85.5288288,42.0242495]},"n1821015149":{"id":"n1821015149","loc":[-85.5450334,42.0146989]},"n1821015151":{"id":"n1821015151","loc":[-85.5578275,42.0092304]},"n1821015154":{"id":"n1821015154","loc":[-85.6056634,41.9724511]},"n1821015155":{"id":"n1821015155","loc":[-85.5902179,41.9852742]},"n1821015156":{"id":"n1821015156","loc":[-85.5156256,42.0387157]},"n1821015157":{"id":"n1821015157","loc":[-85.5734433,42.0059459]},"n1821015158":{"id":"n1821015158","loc":[-85.6050773,41.9731273]},"n1821015160":{"id":"n1821015160","loc":[-85.5223419,42.0275233]},"n1821015163":{"id":"n1821015163","loc":[-85.6053562,41.972525]},"n1821015164":{"id":"n1821015164","loc":[-85.5850412,41.9946082]},"n1821015165":{"id":"n1821015165","loc":[-85.5359031,42.0186326]},"n1821015166":{"id":"n1821015166","loc":[-85.5608745,42.0077635]},"n1821015169":{"id":"n1821015169","loc":[-85.572876,42.0073189]},"n1821015171":{"id":"n1821015171","loc":[-85.5875424,41.9919188]},"n1821015172":{"id":"n1821015172","loc":[-85.5240116,42.0272581]},"n1821015173":{"id":"n1821015173","loc":[-85.5318369,42.0236818]},"n1821015174":{"id":"n1821015174","loc":[-85.566888,42.0086923]},"n1821015175":{"id":"n1821015175","loc":[-85.5931522,41.9850669]},"n1821015176":{"id":"n1821015176","loc":[-85.5604842,42.0093199]},"n1821015177":{"id":"n1821015177","loc":[-85.5868168,41.9927543]},"n1821015178":{"id":"n1821015178","loc":[-85.6052275,41.9732549]},"n1821015179":{"id":"n1821015179","loc":[-85.5910118,41.9900431]},"n1821015182":{"id":"n1821015182","loc":[-85.5610032,42.0082897]},"n1821015183":{"id":"n1821015183","loc":[-85.5425443,42.0179431]},"n1821015184":{"id":"n1821015184","loc":[-85.5843277,42.0014055]},"n1821015186":{"id":"n1821015186","loc":[-85.5733307,42.0063564]},"n1821015188":{"id":"n1821015188","loc":[-85.5277385,42.0248694]},"n1821015189":{"id":"n1821015189","loc":[-85.5558427,42.0108168]},"n1821015190":{"id":"n1821015190","loc":[-85.5650587,42.0082618]},"n1821015191":{"id":"n1821015191","loc":[-85.5660351,42.0088278]},"n1821015192":{"id":"n1821015192","loc":[-85.5849768,41.9980049]},"n1821015194":{"id":"n1821015194","loc":[-85.5359139,42.0188199]},"n1821015195":{"id":"n1821015195","loc":[-85.593238,41.9849194]},"n1821015197":{"id":"n1821015197","loc":[-85.5850841,41.9983239]},"n1821015199":{"id":"n1821015199","loc":[-85.5983396,41.9794283]},"n1821015204":{"id":"n1821015204","loc":[-85.5452801,42.0145355]},"n1821015205":{"id":"n1821015205","loc":[-85.5340685,42.0218407]},"n1821015207":{"id":"n1821015207","loc":[-85.5773272,42.0034186]},"n1821015209":{"id":"n1821015209","loc":[-85.5535212,42.0132419]},"n1821015211":{"id":"n1821015211","loc":[-85.6107703,41.9706045]},"n1821015212":{"id":"n1821015212","loc":[-85.6030066,41.9758193]},"n1821015213":{"id":"n1821015213","loc":[-85.5359943,42.0184213]},"n1821015214":{"id":"n1821015214","loc":[-85.5922993,41.9813305]},"n1821015215":{"id":"n1821015215","loc":[-85.5672689,42.0080465]},"n1821015217":{"id":"n1821015217","loc":[-85.5160494,42.0365682]},"n1821015218":{"id":"n1821015218","loc":[-85.5401142,42.0190351]},"n1821015219":{"id":"n1821015219","loc":[-85.5607632,42.0092282]},"n1821015220":{"id":"n1821015220","loc":[-85.5866197,41.9947894]},"n1821015221":{"id":"n1821015221","loc":[-85.6017889,41.9765132]},"n1821015222":{"id":"n1821015222","loc":[-85.5595978,42.009059]},"n1821015226":{"id":"n1821015226","loc":[-85.5871494,41.9929018]},"n1821015227":{"id":"n1821015227","loc":[-85.5857708,41.9998866]},"n1821015228":{"id":"n1821015228","loc":[-85.5317135,42.0238094]},"n1821015231":{"id":"n1821015231","loc":[-85.5733521,42.0061372]},"n1821015233":{"id":"n1821015233","loc":[-85.5855991,42.0001936]},"n1821015234":{"id":"n1821015234","loc":[-85.5213924,42.029962]},"n1821015235":{"id":"n1821015235","loc":[-85.6052221,41.9726567]},"n1821015236":{"id":"n1821015236","loc":[-85.5763723,42.0035422]},"n1821015237":{"id":"n1821015237","loc":[-85.5858512,41.9966215]},"n1821015238":{"id":"n1821015238","loc":[-85.567061,42.008439]},"n1821015239":{"id":"n1821015239","loc":[-85.5250563,42.0269057]},"n1821015240":{"id":"n1821015240","loc":[-85.5347551,42.0214263]},"n1821015241":{"id":"n1821015241","loc":[-85.6098463,41.9707066]},"n1821015242":{"id":"n1821015242","loc":[-85.5676927,42.0076519]},"n1821015243":{"id":"n1821015243","loc":[-85.516775,42.0322669]},"n1821015244":{"id":"n1821015244","loc":[-85.5762275,42.0036538]},"n1821015245":{"id":"n1821015245","loc":[-85.5583639,42.0090949]},"n1821015246":{"id":"n1821015246","loc":[-85.5554041,42.0106432]},"n1821015247":{"id":"n1821015247","loc":[-85.5973364,41.9776099]},"n1821015248":{"id":"n1821015248","loc":[-85.6098945,41.9717513]},"n1821015249":{"id":"n1821015249","loc":[-85.6045315,41.9751511]},"n1821015250":{"id":"n1821015250","loc":[-85.5579938,42.0092264]},"n1821015253":{"id":"n1821015253","loc":[-85.6058873,41.9724652]},"n1821015254":{"id":"n1821015254","loc":[-85.5869456,41.9947517]},"n1821015255":{"id":"n1821015255","loc":[-85.5936565,41.9823713]},"n1821015256":{"id":"n1821015256","loc":[-85.5218269,42.0278102]},"n1821015258":{"id":"n1821015258","loc":[-85.5887802,41.9905534]},"n1821015259":{"id":"n1821015259","loc":[-85.5901924,41.9904515]},"n1821015263":{"id":"n1821015263","loc":[-85.5249222,42.0255787]},"n1821015265":{"id":"n1821015265","loc":[-85.5175206,42.0321672]},"n1821015266":{"id":"n1821015266","loc":[-85.5275722,42.0254034]},"n1821015267":{"id":"n1821015267","loc":[-85.6016226,41.9765451]},"n1821015269":{"id":"n1821015269","loc":[-85.5569316,42.011032]},"n1821015271":{"id":"n1821015271","loc":[-85.6010714,41.9785209]},"n1821015272":{"id":"n1821015272","loc":[-85.6050666,41.9729917]},"n1821015273":{"id":"n1821015273","loc":[-85.5891235,41.99529]},"n1821015274":{"id":"n1821015274","loc":[-85.515454,42.0376439]},"n1821015276":{"id":"n1821015276","loc":[-85.5776021,42.0034443]},"n1821015277":{"id":"n1821015277","loc":[-85.6041707,41.9751453]},"n1821015278":{"id":"n1821015278","loc":[-85.5444701,42.0167435]},"n1821015280":{"id":"n1821015280","loc":[-85.5923274,41.9852202]},"n1821015283":{"id":"n1821015283","loc":[-85.5893649,41.9900271]},"n1821015284":{"id":"n1821015284","loc":[-85.5933453,41.9804412]},"n1821015285":{"id":"n1821015285","loc":[-85.5247237,42.026017]},"n1821015286":{"id":"n1821015286","loc":[-85.5286182,42.0242477]},"n1821015287":{"id":"n1821015287","loc":[-85.5904003,41.9888549]},"n1821015288":{"id":"n1821015288","loc":[-85.6062146,41.9739369]},"n1821015290":{"id":"n1821015290","loc":[-85.5762596,42.0052602]},"n1821015292":{"id":"n1821015292","loc":[-85.5849715,41.9975465]},"n1821015293":{"id":"n1821015293","loc":[-85.585229,42.0006241]},"n1821015294":{"id":"n1821015294","loc":[-85.5926922,41.9805946]},"n1821015295":{"id":"n1821015295","loc":[-85.5703387,42.0089133]},"n1821015299":{"id":"n1821015299","loc":[-85.5789955,42.0038611]},"n1821015301":{"id":"n1821015301","loc":[-85.6072888,41.9721918]},"n1821015302":{"id":"n1821015302","loc":[-85.5356349,42.0200992]},"n1821015304":{"id":"n1821015304","loc":[-85.5891772,41.994066]},"n1821015306":{"id":"n1821015306","loc":[-85.606295,41.9744952]},"n1821015307":{"id":"n1821015307","loc":[-85.538871,42.0186583]},"n1821015308":{"id":"n1821015308","loc":[-85.587997,41.994971]},"n1821015311":{"id":"n1821015311","loc":[-85.606869,41.9725809]},"n1821015312":{"id":"n1821015312","loc":[-85.5171974,42.0339943]},"n1821015314":{"id":"n1821015314","loc":[-85.5327435,42.0220479]},"n1821015315":{"id":"n1821015315","loc":[-85.5383439,42.0187282]},"n1821015316":{"id":"n1821015316","loc":[-85.5248095,42.0263119]},"n1821015318":{"id":"n1821015318","loc":[-85.5732502,42.0073051]},"n1821015319":{"id":"n1821015319","loc":[-85.5924226,41.9852663]},"n1821015321":{"id":"n1821015321","loc":[-85.5179001,42.0353052]},"n1821015322":{"id":"n1821015322","loc":[-85.5456771,42.0162413]},"n1821015323":{"id":"n1821015323","loc":[-85.5936618,41.9829096]},"n1821015325":{"id":"n1821015325","loc":[-85.5656931,42.0086582]},"n1821015326":{"id":"n1821015326","loc":[-85.5448456,42.0150975]},"n1821015327":{"id":"n1821015327","loc":[-85.5220039,42.027615]},"n1821015329":{"id":"n1821015329","loc":[-85.517884,42.0354885]},"n1821015330":{"id":"n1821015330","loc":[-85.5576666,42.0101671]},"n1821015332":{"id":"n1821015332","loc":[-85.5368754,42.0181402]},"n1821015333":{"id":"n1821015333","loc":[-85.5367078,42.0181145]},"n1821015334":{"id":"n1821015334","loc":[-85.5903909,41.9904316]},"n1821015335":{"id":"n1821015335","loc":[-85.5430767,42.0163587]},"n1821015336":{"id":"n1821015336","loc":[-85.5277492,42.0252878]},"n1821015337":{"id":"n1821015337","loc":[-85.5312146,42.0236898]},"n1821015338":{"id":"n1821015338","loc":[-85.5886568,41.991614]},"n1821015339":{"id":"n1821015339","loc":[-85.5782498,42.0040883]},"n1821015341":{"id":"n1821015341","loc":[-85.562233,42.0076457]},"n1821015342":{"id":"n1821015342","loc":[-85.588626,41.9952479]},"n1821015343":{"id":"n1821015343","loc":[-85.5762865,42.005033]},"n1821015344":{"id":"n1821015344","loc":[-85.5850841,41.9971478]},"n1821015346":{"id":"n1821015346","loc":[-85.5643144,42.0076936]},"n1821015347":{"id":"n1821015347","loc":[-85.5164893,42.0359467]},"n1821015348":{"id":"n1821015348","loc":[-85.5906846,41.9903541]},"n1821015349":{"id":"n1821015349","loc":[-85.557688,42.0107769]},"n1821015350":{"id":"n1821015350","loc":[-85.5363698,42.0181424]},"n1821015351":{"id":"n1821015351","loc":[-85.5939636,41.9801918]},"n1821015352":{"id":"n1821015352","loc":[-85.5524041,42.0131644]},"n1821015354":{"id":"n1821015354","loc":[-85.5308606,42.0236221]},"n1821015355":{"id":"n1821015355","loc":[-85.5877449,41.9932367]},"n1821015356":{"id":"n1821015356","loc":[-85.519885,42.0318586]},"n1821015357":{"id":"n1821015357","loc":[-85.5454035,42.0168431]},"n1821015358":{"id":"n1821015358","loc":[-85.5970629,41.9781881]},"n1821015359":{"id":"n1821015359","loc":[-85.5932541,41.9844767]},"n1821015360":{"id":"n1821015360","loc":[-85.5970736,41.9778252]},"n1821015361":{"id":"n1821015361","loc":[-85.537031,42.0181601]},"n1821015362":{"id":"n1821015362","loc":[-85.5548355,42.0105156]},"n1821015363":{"id":"n1821015363","loc":[-85.5168648,42.0336158]},"n1821015365":{"id":"n1821015365","loc":[-85.5870435,41.9919507]},"n1821015366":{"id":"n1821015366","loc":[-85.5719681,42.0075443]},"n1821015367":{"id":"n1821015367","loc":[-85.5969985,41.9780446]},"n1821015368":{"id":"n1821015368","loc":[-85.5926761,41.98528]},"n1821015369":{"id":"n1821015369","loc":[-85.5224009,42.0293444]},"n1821015371":{"id":"n1821015371","loc":[-85.518737,42.0322651]},"n1821015372":{"id":"n1821015372","loc":[-85.6064573,41.9726465]},"n1821015373":{"id":"n1821015373","loc":[-85.5201103,42.0313088]},"n1821015375":{"id":"n1821015375","loc":[-85.5378182,42.0186844]},"n1821015376":{"id":"n1821015376","loc":[-85.6109741,41.9706882]},"n1821015377":{"id":"n1821015377","loc":[-85.5993333,41.9785488]},"n1821015378":{"id":"n1821015378","loc":[-85.5889787,41.9907368]},"n1821015380":{"id":"n1821015380","loc":[-85.6060161,41.9737375]},"n1821015381":{"id":"n1821015381","loc":[-85.5743016,42.0053679]},"n1821015382":{"id":"n1821015382","loc":[-85.6014724,41.9776099]},"n1821015383":{"id":"n1821015383","loc":[-85.5574426,42.0091644]},"n1821015385":{"id":"n1821015385","loc":[-85.5208613,42.0309302]},"n1821015386":{"id":"n1821015386","loc":[-85.5919023,41.9837789]},"n1821015387":{"id":"n1821015387","loc":[-85.5455484,42.0160221]},"n1821015392":{"id":"n1821015392","loc":[-85.5801757,42.0028964]},"n1821015395":{"id":"n1821015395","loc":[-85.5493785,42.0139974]},"n1821015396":{"id":"n1821015396","loc":[-85.5449475,42.015488]},"n1821015398":{"id":"n1821015398","loc":[-85.611123,41.9706627]},"n1821015400":{"id":"n1821015400","loc":[-85.5935706,41.9822477]},"n1821015401":{"id":"n1821015401","loc":[-85.5724254,42.0073508]},"n1821015403":{"id":"n1821015403","loc":[-85.5486812,42.0143442]},"n1821015404":{"id":"n1821015404","loc":[-85.5161835,42.0327711]},"n1821015406":{"id":"n1821015406","loc":[-85.5921705,41.9851107]},"n1821015407":{"id":"n1821015407","loc":[-85.531912,42.0234069]},"n1821015410":{"id":"n1821015410","loc":[-85.5292566,42.024176]},"n1821015411":{"id":"n1821015411","loc":[-85.5845316,41.9948315]},"n1821015413":{"id":"n1821015413","loc":[-85.5217947,42.0280413]},"n1821015414":{"id":"n1821015414","loc":[-85.5527367,42.013272]},"n1821015415":{"id":"n1821015415","loc":[-85.5191179,42.0321973]},"n1821015416":{"id":"n1821015416","loc":[-85.5540241,42.0128655]},"n1821015418":{"id":"n1821015418","loc":[-85.5272892,42.0254849]},"n1821015419":{"id":"n1821015419","loc":[-85.5449744,42.016867]},"n1821015420":{"id":"n1821015420","loc":[-85.5852665,41.9986787]},"n1821015421":{"id":"n1821015421","loc":[-85.6102701,41.972186]},"n1821015423":{"id":"n1821015423","loc":[-85.6026365,41.9764972]},"n1821015427":{"id":"n1821015427","loc":[-85.5898692,41.9841498]},"n1821015429":{"id":"n1821015429","loc":[-85.5422546,42.0183855]},"n1821015430":{"id":"n1821015430","loc":[-85.5866505,41.9925549]},"n1821015431":{"id":"n1821015431","loc":[-85.5234376,42.0273577]},"n1821015432":{"id":"n1821015432","loc":[-85.6096746,41.9727284]},"n1821015433":{"id":"n1821015433","loc":[-85.5824891,42.0021567]},"n1821015434":{"id":"n1821015434","loc":[-85.5923905,41.9841139]},"n1821015435":{"id":"n1821015435","loc":[-85.5874565,41.9948014]},"n1821015437":{"id":"n1821015437","loc":[-85.6055279,41.9734423]},"n1821015438":{"id":"n1821015438","loc":[-85.5299379,42.0237376]},"n1821015439":{"id":"n1821015439","loc":[-85.5155022,42.0383651]},"n1821015442":{"id":"n1821015442","loc":[-85.527422,42.0254711]},"n1821015443":{"id":"n1821015443","loc":[-85.5920699,41.9849291]},"n1821015444":{"id":"n1821015444","loc":[-85.5639711,42.0077494]},"n1821015445":{"id":"n1821015445","loc":[-85.5162586,42.0361777]},"n1821015446":{"id":"n1821015446","loc":[-85.5220039,42.029695]},"n1821015448":{"id":"n1821015448","loc":[-85.5176641,42.0356956]},"n1821015449":{"id":"n1821015449","loc":[-85.5930556,41.9841577]},"n1821015451":{"id":"n1821015451","loc":[-85.5320783,42.0228848]},"n1821015452":{"id":"n1821015452","loc":[-85.5170096,42.0357235]},"n1821015453":{"id":"n1821015453","loc":[-85.5571355,42.009613]},"n1821015454":{"id":"n1821015454","loc":[-85.5609979,42.009059]},"n1821015455":{"id":"n1821015455","loc":[-85.6097336,41.9708342]},"n1821015456":{"id":"n1821015456","loc":[-85.5884476,41.9904218]},"w170843846":{"id":"w170843846","tags":{"waterway":"river"},"nodes":["n1819790555","n1819790762","n1819790547","n1819790618","n1819790898","n1819790796","n1819790534","n1819790543","n1819790541","n1819790687","n1819790877","n1819790811","n1819790670"]},"w209083541":{"id":"w209083541","tags":{"name":"Portage River","waterway":"river"},"nodes":["n1821014848","n1821015156","n1821015439","n1821014763","n1821014824","n1821015274","n1821014764","n1821014791","n1821014957","n1821015217","n1821015445","n1821015347","n1821014893","n1821015452","n1821015017","n1821015448","n1821014968","n1821015329","n1821015321","n1821014992","n1821014948","n1821014757","n1821014983","n1821015312","n1821015363","n1821014924","n1821014873","n1821014932","n1821014668","n1821015404","n1821014716","n1821015243","n1821015265","n1821014710","n1821015371","n1821015415","n1821014870","n1821015356","n1821015373","n1821014681","n1821014714","n1821015385","n1821014911","n1821015057","n1821014867","n1821014998","n1821015142","n1821015234","n1821015446","n1821014862","n1821015369","n1821014945","n1821015003","n1821014667","n1821015413","n1821015256","n1821015327","n1821015160","n1821014907","n1821015431","n1821015172","n1821015034","n1821014741","n1821015033","n1821015239","n1821015007","n1821015316","n1821015285","n1821014633","n1821015263","n1821015069","n1821014846","n1821014779","n1821015011","n1821015012","n1821014845","n1821015418","n1821015442","n1821015266","n1821015336","n1821014755","n1821015188","n1821014925","n1821014816","n1821014869","n1821014967","n1821015286","n1821015147","n1821015410","n1821015126","n1821015438","n1821015018","n1821015354","n1821015337","n1821014766","n1821014740","n1821015228","n1821015173","n1821015407","n1821015076","n1821015451","n1821015024","n1821015314","n1821014784","n1821015045","n1821014735","n1821015205","n1821014986","n1821015240","n1821015098","n1821014825","n1821015302","n1821014918","n1821014718","n1821014896","n1821014853","n1821015194","n1821015165","n1821015213","n1821014991","n1821015350","n1821015333","n1821015332","n1821015361","n1821015060","n1821014914","n1821015375","n1821015315","n1821015307","n1821014906","n1821014751","n1821014666","n1821015218","n1821014817","n1821015118","n1821014674","n1821015038","n1821014973","n1821015429","n1821015183","n1821015046","n1821014803","n1821015140","n1821015009","n1821014749","n1821015335","n1821014711","n1821014854","n1821015278","n1821015419","n1821014648","n1821015357","n1821014637","n1821014988","n1821015322","n1821015387","n1821015042","n1821014833","n1821015396","n1821015326","n1821014691","n1821015149","n1821015204","n1821015122","n1821014782","n1821014982","n1821014921","n1821014936","n1821014969","n1821014881","n1821015403","n1821014805","n1821015395","n1821014892","n1821014826","n1821014844","n1821015107","n1821015014","n1821014955","n1821015352","n1821015414","n1821014746","n1821015209","n1821014770","n1821015416","n1821014661","n1821014857","n1821014814","n1821014754","n1821014721","n1821014727","n1821015362","n1821015029","n1821015246","n1821015189","n1821014627","n1821015269","n1821014808","n1821014962","n1821015349","n1821015041","n1821014722","n1821015330","n1821015453","n1821015067","n1821014643","n1821014802","n1821015383","n1821015151","n1821015250","n1821015245","n1821014772","n1821014899","n1821015222","n1821015121","n1821014951","n1821015176","n1821015219","n1821015454","n1821014972","n1821014917","n1821015182","n1821015166","n1821015145","n1821014910","n1821015082","n1821014678","n1821014806","n1821015141","n1821015341","n1821014788","n1821015097","n1821014995","n1821015444","n1821015346","n1821015101","n1821015129","n1821015123","n1821015132","n1821015190","n1821015146","n1821015325","n1821015191","n1821015072","n1821015100","n1821015174","n1821015238","n1821015215","n1821014700","n1821015242","n1821014841","n1821014905","n1821014874","n1821014883","n1821014729","n1821014866","n1821014828","n1821015295","n1821014931","n1821014859","n1821014912","n1821014783","n1821014752","n1821014961","n1821015366","n1821015401","n1821015169","n1821015318","n1821014996","n1821014747","n1821014963","n1821014670","n1821015186","n1821015231","n1821015157","n1821014812","n1821015381","n1821014887","n1821015138","n1821014704","n1821014787","n1821014922","n1821015290","n1821015343","n1821014651","n1821014980","n1821014960","n1821015244","n1821015236","n1821015006","n1821014694","n1821014759","n1821015207","n1821015276","n1821015065","n1821014863","n1821014660","n1821014902","n1821014645","n1821015339","n1821014871","n1821015096","n1821015299","n1821014798","n1821014638","n1821015392","n1821014835","n1821014762","n1821014642","n1821015433","n1821014786","n1821015134","n1821014855","n1821015184","n1821014850","n1821015293","n1821015233","n1821015227","n1821014876","n1821014985","n1821014843","n1821015420","n1821015197","n1821015192","n1821015292","n1821015344","n1821014742","n1821014726","n1821015237","n1821014796","n1821014908","n1821014975","n1821014769","n1821014688","n1821014860","n1821014895","n1821014676","n1821015411","n1821014736","n1821015164","n1821014647","n1821015144","n1821014919","n1821015220","n1821015254","n1821015435","n1821015308","n1821015342","n1821014830","n1821015273","n1821014658","n1821014781","n1821015087","n1821015139","n1821015304","n1821014839","n1821015048","n1821015115","n1821015355","n1821015226","n1821015177","n1821015430","n1821014965","n1821014725","n1821015365","n1821015171","n1821015073","n1821015125","n1821015338","n1821015111","n1821014950","n1821015378","n1821015258","n1821015456","n1821015106","n1821014832","n1821014888","n1821014795","n1821014872","n1821014810","n1821014705","n1821014804","n1821014820","n1821015283","n1821014938","n1821014689","n1821015259","n1821015334","n1821015348","n1821014635","n1821015179","n1821014864","n1821014890","n1821015020","n1821014898","n1821015287","n1821015120","n1821014984","n1821014743","n1821014790","n1821014765","n1821014777","n1821015095","n1821014653","n1821015135","n1821014836","n1821014964","n1821014974","n1821014636","n1821014682","n1821014663","n1821014665","n1821015109","n1821015155","n1821014930","n1821014669","n1821015004","n1821015427","n1821014916","n1821015093","n1821015086","n1821015386","n1821014799","n1821014913","n1821015434","n1821014728","n1821014900","n1821015068","n1821015039","n1821015443","n1821015406","n1821015280","n1821015319","n1821015368","n1821014774","n1821015090","n1821015175","n1821015195","n1821014687","n1821015359","n1821015449","n1821014956","n1821014838","n1821014768","n1821014698","n1821015323","n1821014756","n1821015255","n1821015400","n1821014717","n1821014868","n1821014778","n1821015214","n1821014944","n1821014697","n1821014671","n1821014928","n1821015294","n1821014822","n1821015284","n1821015351","n1821015022","n1821015133","n1821014644","n1821015010","n1821014625","n1821014657","n1821014946","n1821015099","n1821015114","n1821014629","n1821014865","n1821014997","n1821014926","n1821014933","n1821015199","n1821014819","n1821015080","n1821014692","n1821014677","n1821015358","n1821015367","n1821015360","n1821015105","n1821015247","n1821015005","n1821014809","n1821014794","n1821014761","n1821014879","n1821014801","n1821015377","n1821015059","n1821014730","n1821015050","n1821015271","n1821015143","n1821014989","n1821015019","n1821014672","n1821014649","n1821014684","n1821014703","n1821015021","n1821015382","n1821014842","n1821014720","n1821014847","n1821015104","n1821014987","n1821014886","n1821015267","n1821015221","n1821015015","n1821015423","n1821014954","n1821014903","n1821014939","n1821015212","n1821014789","n1821014712","n1821014708","n1821015078","n1821015277","n1821015249","n1821014646","n1821014793","n1821015053","n1821014707","n1821015306","n1821015112","n1821015288","n1821015380","n1821015437","n1821015178","n1821015158","n1821015272","n1821015235","n1821015163","n1821015154","n1821015253","n1821014632","n1821015372","n1821015103","n1821015311","n1821015301","n1821014885","n1821014811","n1821014977","n1821015051","n1821014942","n1821014745","n1821015432","n1821015075","n1821014664","n1821014695","n1821015116","n1821014639","n1821015421","n1821015248","n1821014758","n1821014834","n1821015083","n1821015455","n1821015241","n1821015108","n1821014713","n1821015137","n1821015055","n1821015211","n1821014904","n1821015376","n1821015398","n1821014771","n1821014840","n1821015062","n1819790554","n1819790560","n1819790767","n1819790696","n1819790706","n1819790606","n1819790607","n1819790544","n1819790779","n1819790760","n1819790926","n1819790927","n1819790647","n1819790657","n1819790649","n1819790679","n1819790915","n1819790739","n1819790549","n1819790671","n1819790686","n1819790798","n1819790791","n1819790563","n1819790720","n1819790704","n1819790795","n1819790836","n1819790622","n1819790615","n1819790654","n1819790931","n1819790595","n1819790753","n1819790612","n1819790623","n1819790564","n1819790552","n1819790645","n1819790625","n1819790605","n1819790668","n1819790731","n1819790718","n1819790781","n1819790665","n1819790659","n1819790726","n1819790642","n1819790854","n1819790697","n1819790867","n1819790833","n1819790555","n1819790774","n1819790881","n1819790530","n1819790909","n1819790891","n1819790590","n1819790738","n1819790609","n1819790528","n1819790674","n1819790583","n1819790559","n1819790863","n1819790912","n1819790685","n1819790913"]},"n185955128":{"id":"n185955128","loc":[-85.6189367,41.9519432]},"n185948818":{"id":"n185948818","loc":[-85.616755,41.952231]},"n185978819":{"id":"n185978819","loc":[-85.616773,41.954737]},"n185978821":{"id":"n185978821","loc":[-85.616699,41.954742]},"n2138420714":{"id":"n2138420714","loc":[-85.6176304,41.9515154]},"n2138420715":{"id":"n2138420715","loc":[-85.6177355,41.9515717]},"n2138420716":{"id":"n2138420716","loc":[-85.6192901,41.951573]},"n2138420718":{"id":"n2138420718","loc":[-85.6171481,41.9513579]},"n2138420719":{"id":"n2138420719","loc":[-85.6165981,41.9519199]},"n2138420720":{"id":"n2138420720","loc":[-85.6165719,41.9519922]},"n2138420721":{"id":"n2138420721","loc":[-85.6165832,41.9520757]},"n2138420722":{"id":"n2138420722","loc":[-85.6166355,41.9521453]},"n2138420723":{"id":"n2138420723","loc":[-85.6169161,41.9522788]},"n2138420724":{"id":"n2138420724","loc":[-85.6170882,41.9522538]},"n2138420725":{"id":"n2138420725","loc":[-85.6189204,41.9514674]},"n2138420726":{"id":"n2138420726","loc":[-85.6180346,41.9514735]},"n2138420727":{"id":"n2138420727","loc":[-85.6180362,41.9515719]},"n2138420728":{"id":"n2138420728","loc":[-85.6189204,41.9515727]},"n2138420744":{"id":"n2138420744","loc":[-85.618919,41.9519571]},"n2138420745":{"id":"n2138420745","loc":[-85.6194575,41.9522374]},"n2138420746":{"id":"n2138420746","loc":[-85.6181777,41.9536179]},"n2138420747":{"id":"n2138420747","loc":[-85.6176582,41.9533658]},"n2138420748":{"id":"n2138420748","loc":[-85.6179871,41.9530242]},"n2138420749":{"id":"n2138420749","loc":[-85.618429,41.9532476]},"n2138420750":{"id":"n2138420750","loc":[-85.6185538,41.9531194]},"n2138420751":{"id":"n2138420751","loc":[-85.6180765,41.9528677]},"n2138420752":{"id":"n2138420752","loc":[-85.6180394,41.9528855]},"n2138420753":{"id":"n2138420753","loc":[-85.6193752,41.9521695]},"n2138420754":{"id":"n2138420754","loc":[-85.6181374,41.9535376]},"n2138420755":{"id":"n2138420755","loc":[-85.6179898,41.9535545]},"n2138420756":{"id":"n2138420756","loc":[-85.6177286,41.9534228]},"n2138420757":{"id":"n2138420757","loc":[-85.6181011,41.9530292]},"n2138420759":{"id":"n2138420759","loc":[-85.6185158,41.9531194]},"n2138420760":{"id":"n2138420760","loc":[-85.6191318,41.9520425]},"n2138420761":{"id":"n2138420761","loc":[-85.6182348,41.9529815]},"n2138420762":{"id":"n2138420762","loc":[-85.6184853,41.9524248]},"n2138420763":{"id":"n2138420763","loc":[-85.6186764,41.9525193]},"n2138420764":{"id":"n2138420764","loc":[-85.6189421,41.9526483]},"n2138420765":{"id":"n2138420765","loc":[-85.6182875,41.9531222]},"n2138420766":{"id":"n2138420766","loc":[-85.6179141,41.9535163]},"n2138420767":{"id":"n2138420767","loc":[-85.6178363,41.9535735]},"n185948824":{"id":"n185948824","loc":[-85.6165667,41.9529715]},"n2138420758":{"id":"n2138420758","loc":[-85.6184408,41.953201]},"n2138422349":{"id":"n2138422349","loc":[-85.6175136,41.9533346]},"n2138422350":{"id":"n2138422350","loc":[-85.6171867,41.9531679]},"n2138422351":{"id":"n2138422351","loc":[-85.61722,41.9531305]},"n2138422352":{"id":"n2138422352","loc":[-85.6171889,41.9531158]},"n2138422353":{"id":"n2138422353","loc":[-85.6171733,41.9531284]},"n2138422354":{"id":"n2138422354","loc":[-85.616765,41.9529207]},"n2138422355":{"id":"n2138422355","loc":[-85.6167565,41.9529355]},"n2138422356":{"id":"n2138422356","loc":[-85.6164772,41.9527911]},"n2138422357":{"id":"n2138422357","loc":[-85.6168227,41.9524261]},"n2138422358":{"id":"n2138422358","loc":[-85.6171913,41.9526158]},"n2138422359":{"id":"n2138422359","loc":[-85.6172403,41.9525589]},"n2138422360":{"id":"n2138422360","loc":[-85.6172097,41.952542]},"n2138422361":{"id":"n2138422361","loc":[-85.6173948,41.9523512]},"n2138422362":{"id":"n2138422362","loc":[-85.6174256,41.9523678]},"n2138422363":{"id":"n2138422363","loc":[-85.6174831,41.9523086]},"n2138422364":{"id":"n2138422364","loc":[-85.6173316,41.9522289]},"n2138422365":{"id":"n2138422365","loc":[-85.6174507,41.9521024]},"n2138422366":{"id":"n2138422366","loc":[-85.6174773,41.9521155]},"n2138422367":{"id":"n2138422367","loc":[-85.6176577,41.9519232]},"n2138422368":{"id":"n2138422368","loc":[-85.6176336,41.9519105]},"n2138422369":{"id":"n2138422369","loc":[-85.617747,41.9517861]},"n2138422370":{"id":"n2138422370","loc":[-85.6182675,41.9520559]},"n2138422371":{"id":"n2138422371","loc":[-85.6182105,41.9521219]},"n2138422372":{"id":"n2138422372","loc":[-85.6183863,41.9522203]},"n2138422373":{"id":"n2138422373","loc":[-85.6180984,41.9525266]},"n2138422374":{"id":"n2138422374","loc":[-85.6179159,41.9524295]},"n2138422375":{"id":"n2138422375","loc":[-85.617854,41.9524979]},"n2138422376":{"id":"n2138422376","loc":[-85.6177686,41.9524531]},"n2138422377":{"id":"n2138422377","loc":[-85.6174716,41.9527765]},"n2138422378":{"id":"n2138422378","loc":[-85.6178545,41.9529756]},"n2138425424":{"id":"n2138425424","loc":[-85.6171736,41.9536385]},"n2138425425":{"id":"n2138425425","loc":[-85.6180159,41.9535782]},"n2138425426":{"id":"n2138425426","loc":[-85.6181068,41.9536282]},"n2138425427":{"id":"n2138425427","loc":[-85.6180673,41.9542678]},"n2138425428":{"id":"n2138425428","loc":[-85.6178636,41.9542634]},"n2138425429":{"id":"n2138425429","loc":[-85.6176204,41.9542046]},"n2138425430":{"id":"n2138425430","loc":[-85.6174366,41.9541031]},"n2138425431":{"id":"n2138425431","loc":[-85.6172942,41.9539781]},"n2138425432":{"id":"n2138425432","loc":[-85.6172171,41.9538399]},"n2138425433":{"id":"n2138425433","loc":[-85.6168138,41.9543266]},"n2138425434":{"id":"n2138425434","loc":[-85.6167779,41.9538098]},"n2138425435":{"id":"n2138425435","loc":[-85.6165849,41.9537073]},"n2138425441":{"id":"n2138425441","loc":[-85.616458,41.9543184]},"n2138425442":{"id":"n2138425442","loc":[-85.6166428,41.954345]},"n2138425445":{"id":"n2138425445","loc":[-85.6181332,41.9514117]},"n2138425446":{"id":"n2138425446","loc":[-85.6183263,41.9514111]},"n2138425447":{"id":"n2138425447","loc":[-85.6185033,41.9514102]},"n2138425449":{"id":"n2138425449","loc":[-85.6186809,41.9514093]},"n2138425451":{"id":"n2138425451","loc":[-85.6188681,41.9514082]},"n2138436008":{"id":"n2138436008","loc":[-85.6170474,41.9513604]},"n2138436009":{"id":"n2138436009","loc":[-85.6164937,41.9519586]},"n2138436010":{"id":"n2138436010","loc":[-85.616497,41.9520725]},"n2138436011":{"id":"n2138436011","loc":[-85.6165654,41.9521645]},"n2138436012":{"id":"n2138436012","loc":[-85.6166631,41.9522178]},"n2138436013":{"id":"n2138436013","loc":[-85.6167327,41.9522554]},"n2138436014":{"id":"n2138436014","loc":[-85.6172383,41.9525125]},"n2138439319":{"id":"n2138439319","loc":[-85.6170432,41.9524057]},"n2138439320":{"id":"n2138439320","loc":[-85.617691,41.9517107]},"n2138439321":{"id":"n2138439321","loc":[-85.6177727,41.9516794]},"n2138439322":{"id":"n2138439322","loc":[-85.619085,41.9516811]},"n2138439323":{"id":"n2138439323","loc":[-85.6179432,41.952895]},"n2138439324":{"id":"n2138439324","loc":[-85.6180389,41.9529384]},"n2138439325":{"id":"n2138439325","loc":[-85.6176303,41.9533604]},"n2138439326":{"id":"n2138439326","loc":[-85.6175538,41.9534396]},"n2138439327":{"id":"n2138439327","loc":[-85.6173806,41.9523658]},"n2138439328":{"id":"n2138439328","loc":[-85.6171841,41.9522542]},"n2138439329":{"id":"n2138439329","loc":[-85.6172077,41.9524958]},"n2138439330":{"id":"n2138439330","loc":[-85.6171235,41.9525809]},"n2138439331":{"id":"n2138439331","loc":[-85.6180938,41.9527349]},"n2138439332":{"id":"n2138439332","loc":[-85.6177023,41.9525253]},"n2138439333":{"id":"n2138439333","loc":[-85.6175543,41.9526865]},"n2138439334":{"id":"n2138439334","loc":[-85.6179589,41.9528783]},"n185948820":{"id":"n185948820","loc":[-85.6163249,41.952701]},"n185948822":{"id":"n185948822","loc":[-85.6163757,41.952855]},"n185955123":{"id":"n185955123","loc":[-85.6198103,41.9510408]},"n185958839":{"id":"n185958839","loc":[-85.611651,41.954761]},"n185965033":{"id":"n185965033","loc":[-85.614195,41.954754]},"n185976502":{"id":"n185976502","loc":[-85.617375,41.947559]},"n185976504":{"id":"n185976504","loc":[-85.6174164,41.9510804]},"n185978828":{"id":"n185978828","loc":[-85.613542,41.954756]},"n185978830":{"id":"n185978830","loc":[-85.610373,41.954774]},"n2138420713":{"id":"n2138420713","loc":[-85.6174641,41.9506942]},"n2138420717":{"id":"n2138420717","loc":[-85.6173027,41.9512895]},"n2138420768":{"id":"n2138420768","loc":[-85.61745,41.9501974]},"n2138420773":{"id":"n2138420773","loc":[-85.6174135,41.9489136]},"n2138425436":{"id":"n2138425436","loc":[-85.6159148,41.9538036]},"n2138425437":{"id":"n2138425437","loc":[-85.6159534,41.9539677]},"n2138425438":{"id":"n2138425438","loc":[-85.6160306,41.9540846]},"n2138425439":{"id":"n2138425439","loc":[-85.6161354,41.954181]},"n2138425440":{"id":"n2138425440","loc":[-85.6162733,41.954263]},"n2138425443":{"id":"n2138425443","loc":[-85.6183273,41.9510826]},"n2138425444":{"id":"n2138425444","loc":[-85.6181354,41.9510835]},"n2138425448":{"id":"n2138425448","loc":[-85.6185033,41.9510816]},"n2138425450":{"id":"n2138425450","loc":[-85.6186816,41.9510808]},"n2138425452":{"id":"n2138425452","loc":[-85.6188641,41.9510818]},"n2138435984":{"id":"n2138435984","loc":[-85.6167607,41.9501009]},"n2138436000":{"id":"n2138436000","loc":[-85.6173169,41.947558]},"n2138436001":{"id":"n2138436001","loc":[-85.6173362,41.948883]},"n2138436002":{"id":"n2138436002","loc":[-85.6167791,41.9492952]},"n2138436003":{"id":"n2138436003","loc":[-85.6167543,41.949349]},"n2138436004":{"id":"n2138436004","loc":[-85.6167648,41.9509125]},"n2138436005":{"id":"n2138436005","loc":[-85.6168832,41.9510412]},"n2138436006":{"id":"n2138436006","loc":[-85.6170045,41.9511417]},"n2138436007":{"id":"n2138436007","loc":[-85.6170624,41.9512483]},"n2138436017":{"id":"n2138436017","loc":[-85.6168094,41.9492729]},"n2138436021":{"id":"n2138436021","loc":[-85.6167553,41.9494886]},"n2138436023":{"id":"n2138436023","loc":[-85.6167585,41.9499707]},"n2138436025":{"id":"n2138436025","loc":[-85.6167567,41.9497018]},"w203838284":{"id":"w203838284","tags":{"area":"yes","leisure":"pitch","sport":"baseball"},"nodes":["n2138425424","n2138425425","n2138425426","n2138425427","n2138425428","n2138425429","n2138425430","n2138425431","n2138425432","n2138425424"]},"w203837928":{"id":"w203837928","tags":{"highway":"service"},"nodes":["n2138420717","n2138420718","n2138420719","n2138420720","n2138420721","n2138420722","n185948818","n2138420723","n2138420724","n2138420715"]},"w203839364":{"id":"w203839364","tags":{"highway":"footway"},"nodes":["n2138439331","n2138439332"]},"w203837932":{"id":"w203837932","tags":{"amenity":"parking","area":"yes"},"nodes":["n2138420744","n2138420745","n2138420746","n2138420747","n2138420748","n2138420749","n2138420750","n2138420751","n2138420744"]},"w203839362":{"id":"w203839362","tags":{"highway":"footway"},"nodes":["n2138439327","n2138439328"]},"w203839363":{"id":"w203839363","tags":{"highway":"footway"},"nodes":["n2138439329","n2138439330"]},"w203837933":{"id":"w203837933","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n185955128","n2138420760","n2138420753","n2138420764","n2138420759","n2138420758","n2138420754","n2138420755","n2138420766","n2138420756"]},"w203837936":{"id":"w203837936","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420765","n2138420766"]},"w17966364":{"id":"w17966364","tags":{"access":"private","highway":"service","name":"Collins Dr"},"nodes":["n185961362","n185976502","n2138420773","n2138420768","n2138420713","n185976504","n2138420717","n2138420714","n2138420715","n2138420727","n2138420728","n2138420716"]},"w203838040":{"id":"w203838040","tags":{"amenity":"school","area":"yes","building":"yes","name":"Three Rivers Middle School"},"nodes":["n2138422349","n2138422350","n2138422351","n2138422352","n2138422353","n2138422354","n2138422355","n2138422356","n2138422357","n2138439330","n2138422358","n2138422359","n2138422360","n2138436014","n2138439327","n2138422361","n2138422362","n2138422363","n2138422364","n2138422365","n2138422366","n2138422367","n2138422368","n2138422369","n2138422370","n2138422371","n2138422372","n2138422373","n2138422374","n2138422375","n2138422376","n2138439332","n2138439333","n2138422377","n2138422378","n2138422349"]},"w17964049":{"id":"w17964049","tags":{"highway":"service"},"nodes":["n185955120","n185955123","n2138420716","n185955128","n2138420762","n2138420752","n2138420761","n2138420759"]},"w41074899":{"id":"w41074899","tags":{"highway":"secondary","name":"E Hoffman St","ref":"M 60"},"nodes":["n185978817","n185978819","n185978821","n185965033","n185978828","n185958839","n185978830"]},"w203839365":{"id":"w203839365","tags":{"highway":"footway"},"nodes":["n2138439333","n2138439334"]},"w203837935":{"id":"w203837935","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420762","n2138420763","n2138420764"]},"w203838287":{"id":"w203838287","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425446","n2138425447","n2138425448","n2138425443","n2138425446"]},"w203837934":{"id":"w203837934","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420760","n2138420763","n2138420761"]},"w203838289":{"id":"w203838289","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425449","n2138425451","n2138425452","n2138425450","n2138425449"]},"w17963047":{"id":"w17963047","tags":{"highway":"service"},"nodes":["n185948818","n2138436013","n185948820","n185948822","n185948824","n2138439326","n2138420767","n2138420766"]},"w203839091":{"id":"w203839091","tags":{"highway":"footway"},"nodes":["n185976502","n2138436000","n2138436001","n2138436017","n2138436002","n2138436003","n2138436021","n2138436025","n2138436023","n2138435984","n2138436004","n2138436005","n2138436006","n2138436007","n2138436008","n2138436009","n2138436010","n2138436011","n2138436012","n2138436013","n2138439319","n2138439329","n2138436014"]},"w204830797":{"id":"w204830797","tags":{"highway":"service","service":"parking_aisle"},"nodes":["n2138420756","n2138420757","n2138420765","n2138420758"]},"w203838288":{"id":"w203838288","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425447","n2138425449","n2138425450","n2138425448","n2138425447"]},"w203838285":{"id":"w203838285","tags":{"area":"yes","leisure":"pitch","sport":"baseball"},"nodes":["n2138425433","n2138425434","n2138425435","n2138425436","n2138425437","n2138425438","n2138425439","n2138425440","n2138425441","n2138425442","n2138425433"]},"w203838286":{"id":"w203838286","tags":{"area":"yes","leisure":"pitch","sport":"tennis"},"nodes":["n2138425443","n2138425444","n2138425445","n2138425446","n2138425443"]},"w203837929":{"id":"w203837929","tags":{"amenity":"parking","area":"yes"},"nodes":["n2138420725","n2138420726","n2138420727","n2138420728","n2138420725"]},"w203839361":{"id":"w203839361","tags":{"highway":"footway"},"nodes":["n2138439319","n2138439328","n2138439320","n2138439321","n2138439322","n2138439331","n2138439334","n2138439323","n2138439324","n2138439325","n2138439326"]},"n394381698":{"id":"n394381698","loc":[-85.614471,41.954755]},"n394381699":{"id":"n394381699","loc":[-85.6152,41.954744]},"n394381700":{"id":"n394381700","loc":[-85.615201,41.954081]},"n394381701":{"id":"n394381701","loc":[-85.614426,41.954042]},"n394381702":{"id":"n394381702","loc":[-85.616319,41.954749]},"n394381704":{"id":"n394381704","loc":[-85.616152,41.954752]},"n394381706":{"id":"n394381706","loc":[-85.615201,41.95483]},"n394490775":{"id":"n394490775","loc":[-85.613971,41.954839]},"n394490782":{"id":"n394490782","loc":[-85.614372,41.954841]},"n185958835":{"id":"n185958835","loc":[-85.611615,41.953704]},"n185958837":{"id":"n185958837","loc":[-85.611636,41.953938]},"n185958842":{"id":"n185958842","loc":[-85.611187,41.951686]},"n185958844":{"id":"n185958844","loc":[-85.611087,41.951741]},"n185958845":{"id":"n185958845","loc":[-85.611034,41.951852]},"n185958847":{"id":"n185958847","loc":[-85.611016,41.95196]},"n185958849":{"id":"n185958849","loc":[-85.610989,41.95328]},"n185958851":{"id":"n185958851","loc":[-85.611021,41.953484]},"n185958852":{"id":"n185958852","loc":[-85.611091,41.953603]},"n185958853":{"id":"n185958853","loc":[-85.6112,41.953661]},"n185958855":{"id":"n185958855","loc":[-85.611364,41.953686]},"n185965031":{"id":"n185965031","loc":[-85.614204,41.953696]},"n185965032":{"id":"n185965032","loc":[-85.6142,41.953978]},"n185965062":{"id":"n185965062","loc":[-85.614617,41.951639]},"n185965064":{"id":"n185965064","loc":[-85.61463,41.951852]},"n185965066":{"id":"n185965066","loc":[-85.614642,41.953436]},"n185965068":{"id":"n185965068","loc":[-85.6146,41.953551]},"n185965071":{"id":"n185965071","loc":[-85.614487,41.95363]},"n185965073":{"id":"n185965073","loc":[-85.614354,41.953672]},"n185966288":{"id":"n185966288","loc":[-85.61179,41.953695]},"n185966290":{"id":"n185966290","loc":[-85.612232,41.953685]},"n185966293":{"id":"n185966293","loc":[-85.613438,41.953677]},"n185966349":{"id":"n185966349","loc":[-85.611323,41.951653]},"n185966351":{"id":"n185966351","loc":[-85.611892,41.951642]},"n185966352":{"id":"n185966352","loc":[-85.612216,41.951641]},"n185966353":{"id":"n185966353","loc":[-85.613111,41.951639]},"n185966354":{"id":"n185966354","loc":[-85.613396,41.95164]},"n185966355":{"id":"n185966355","loc":[-85.614221,41.95164]},"n185973839":{"id":"n185973839","loc":[-85.61341,41.951919]},"n185973840":{"id":"n185973840","loc":[-85.613438,41.953308]},"n185980222":{"id":"n185980222","loc":[-85.613781,41.955164]},"n185980223":{"id":"n185980223","loc":[-85.613815,41.955237]},"n185980225":{"id":"n185980225","loc":[-85.613837,41.955316]},"n185990345":{"id":"n185990345","loc":[-85.612211,41.951977]},"n185955743":{"id":"n185955743","loc":[-85.613873,41.95635]},"n185980227":{"id":"n185980227","loc":[-85.613851,41.955415]},"n185980229":{"id":"n185980229","loc":[-85.613918,41.957134]},"n394381703":{"id":"n394381703","loc":[-85.616287,41.955674]},"n394381705":{"id":"n394381705","loc":[-85.615164,41.955676]},"n394490777":{"id":"n394490777","loc":[-85.613973,41.955979]},"n394490780":{"id":"n394490780","loc":[-85.614364,41.955987]},"w17965307":{"id":"w17965307","tags":{"highway":"residential","name":"Bates Ave"},"nodes":["n185958842","n185966349","n185966351","n185966352","n185966353","n185966354","n185966355","n185965062"]},"w17967957":{"id":"w17967957","tags":{"highway":"residential","name":"Krum Ave"},"nodes":["n185966352","n185990345","n185966290"]},"w17964508":{"id":"w17964508","tags":{"highway":"residential","name":"Blossom Dr"},"nodes":["n185958842","n185958844","n185958845","n185958847","n185958849","n185958851","n185958852","n185958853","n185958855","n185958835"]},"w17964507":{"id":"w17964507","tags":{"highway":"residential","name":"Blossom Dr"},"nodes":["n185958835","n185958837","n185958839"]},"w34367080":{"id":"w34367080","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394381699","n394381706","n394381705","n394381703","n394381702","n394381704","n394381699"]},"w17965302":{"id":"w17965302","tags":{"highway":"residential","name":"Clausen Ave"},"nodes":["n185958835","n185966288","n185966290","n185966293","n185965031"]},"w17965156":{"id":"w17965156","tags":{"highway":"residential","name":"Orchard Dr"},"nodes":["n185965062","n185965064","n185965066","n185965068","n185965071","n185965073","n185965031"]},"w34369812":{"id":"w34369812","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394490775","n394490777","n394490780","n394490782","n394490775"]},"w17965151":{"id":"w17965151","tags":{"highway":"residential","name":"Orchard Dr"},"nodes":["n185965031","n185965032","n185965033"]},"w17966756":{"id":"w17966756","tags":{"access":"private","highway":"service","name":"Lockport Dr"},"nodes":["n185978828","n185980222","n185980223","n185980225","n185980227","n185955743","n185980229"]},"w17966056":{"id":"w17966056","tags":{"highway":"residential","name":"Angell Ave"},"nodes":["n185966354","n185973839","n185973840","n185966293"]},"w34367079":{"id":"w34367079","tags":{"admin_level":"8","boundary":"administrative"},"nodes":["n394381700","n394381701","n394381698","n394381699","n394381700"]},"n185955744":{"id":"n185955744","loc":[-85.611753,41.956208]},"n185988932":{"id":"n185988932","loc":[-85.6159,41.956336]},"n185988934":{"id":"n185988934","loc":[-85.6159158,41.9590646]},"n185988935":{"id":"n185988935","loc":[-85.6157358,41.959364],"tags":{"highway":"turning_circle"}},"n2138447007":{"id":"n2138447007","loc":[-85.6130784,41.9590689]},"n2138447008":{"id":"n2138447008","loc":[-85.6133328,41.9593805]},"n2138447003":{"id":"n2138447003","loc":[-85.610238,41.9547745]},"n2138447004":{"id":"n2138447004","loc":[-85.6102652,41.9566041]},"n2138447005":{"id":"n2138447005","loc":[-85.610325,41.9568823]},"n2138447006":{"id":"n2138447006","loc":[-85.6105644,41.9571383]},"n2138447009":{"id":"n2138447009","loc":[-85.6135946,41.959948]},"n2138447010":{"id":"n2138447010","loc":[-85.6136071,41.9629372]},"n2138447011":{"id":"n2138447011","loc":[-85.6134392,41.9633182]},"n2138447012":{"id":"n2138447012","loc":[-85.6130151,41.9636073]},"n2138447013":{"id":"n2138447013","loc":[-85.6122729,41.9637125]},"n2138447014":{"id":"n2138447014","loc":[-85.6056682,41.963752]},"w17964174":{"id":"w17964174","tags":{"access":"private","highway":"service"},"nodes":["n185955743","n185955744"]},"w17967743":{"id":"w17967743","tags":{"access":"private","highway":"service","name":"Manistee River Rd"},"nodes":["n185971574","n185988932","n185971407","n185981301","n185967987","n185988934","n185988935"]},"w203839666":{"id":"w203839666","tags":{"highway":"residential","name":"Hov Aire Drive"},"nodes":["n2138447003","n2138447004","n2138447005","n2138447006","n2138447007","n2138447008","n2138447009","n2138447010","n2138447011","n2138447012","n2138447013","n2138447014"]}}';iD.data = {"deprecated":[{"old":{"amenity":"firepit"},"replace":{"leisure":"firepit"}},{"old":{"barrier":"wire_fence"},"replace":{"barrier":"fence","fence_type":"chain"}},{"old":{"barrier":"wood_fence"},"replace":{"barrier":"fence","fence_type":"wood"}},{"old":{"highway":"ford"},"replace":{"ford":"yes"}},{"old":{"highway":"stile"},"replace":{"barrier":"stile"}},{"old":{"highway":"incline"},"replace":{"highway":"road","incline":"up"}},{"old":{"highway":"incline_steep"},"replace":{"highway":"road","incline":"up"}},{"old":{"highway":"unsurfaced"},"replace":{"highway":"road","incline":"unpaved"}},{"old":{"landuse":"wood"},"replace":{"landuse":"forest","natural":"wood"}},{"old":{"natural":"marsh"},"replace":{"natural":"wetland","wetland":"marsh"}},{"old":{"power_source":"*"},"replace":{"generator:source":"$1"}},{"old":{"power_rating":"*"},"replace":{"generator:output":"$1"}},{"old":{"shop":"organic"},"replace":{"shop":"supermarket","organic":"only"}}],"discarded":["created_by","odbl","odbl:note","tiger:upload_uuid","tiger:tlid","tiger:source","tiger:separated","geobase:datasetName","geobase:uuid","sub_sea:type","KSJ2:ADS","KSJ2:ARE","KSJ2:AdminArea","KSJ2:COP_label","KSJ2:DFD","KSJ2:INT","KSJ2:INT_label","KSJ2:LOC","KSJ2:LPN","KSJ2:OPC","KSJ2:PubFacAdmin","KSJ2:RAC","KSJ2:RAC_label","KSJ2:RIC","KSJ2:RIN","KSJ2:WSC","KSJ2:coordinate","KSJ2:curve_id","KSJ2:curve_type","KSJ2:filename","KSJ2:lake_id","KSJ2:lat","KSJ2:long","KSJ2:river_id","yh:LINE_NAME","yh:LINE_NUM","yh:STRUCTURE","yh:TOTYUMONO","yh:TYPE","yh:WIDTH","yh:WIDTH_RANK","SK53_bulk:load"],"wikipedia":[["Abkhazian","Аҧсшәа","ab"],["Achinese","Acèh","ace"],["Adyghe","адыгабзэ","ady"],["Afrikaans","Afrikaans","af"],["Akan","Akan","ak"],["Alemannisch","Alemannisch","als"],["Amharic","አማርኛ","am"],["Aragonese","aragonés","an"],["Old English","Ænglisc","ang"],["Arabic","العربية","ar"],["Aramaic","ܐܪܡܝܐ","arc"],["Egyptian Arabic","مصرى","arz"],["Assamese","অসমীয়া","as"],["Asturian","asturianu","ast"],["Avaric","авар","av"],["Aymara","Aymar aru","ay"],["Azerbaijani","azərbaycanca","az"],["تۆرکجه","تۆرکجه","azb"],["Bashkir","башҡортса","ba"],["Bavarian","Boarisch","bar"],["Samogitian","žemaitėška","bat-smg"],["Bikol Central","Bikol Central","bcl"],["Belarusian","беларуская","be"],["беларуская (тарашкевіца)","беларуская (тарашкевіца)","be-x-old"],["Bulgarian","български","bg"],["भोजपुरी","भोजपुरी","bh"],["Bislama","Bislama","bi"],["Banjar","Bahasa Banjar","bjn"],["Bambara","bamanankan","bm"],["Bengali","বাংলা","bn"],["Tibetan","བོད་ཡིག","bo"],["Bishnupriya","বিষ্ণুপ্রিয়া মণিপুরী","bpy"],["Breton","brezhoneg","br"],["Bosnian","bosanski","bs"],["Buginese","ᨅᨔ ᨕᨘᨁᨗ","bug"],["буряад","буряад","bxr"],["Catalan","català","ca"],["Chavacano de Zamboanga","Chavacano de Zamboanga","cbk-zam"],["Min Dong Chinese","Mìng-dĕ̤ng-ngṳ̄","cdo"],["Chechen","нохчийн","ce"],["Cebuano","Cebuano","ceb"],["Chamorro","Chamoru","ch"],["Cherokee","ᏣᎳᎩ","chr"],["Cheyenne","Tsetsêhestâhese","chy"],["Central Kurdish","کوردیی ناوەندی","ckb"],["Corsican","corsu","co"],["Cree","Nēhiyawēwin / ᓀᐦᐃᔭᐍᐏᐣ","cr"],["Crimean Turkish","qırımtatarca","crh"],["Czech","čeština","cs"],["Kashubian","kaszëbsczi","csb"],["Church Slavic","словѣньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ","cu"],["Chuvash","Чӑвашла","cv"],["Welsh","Cymraeg","cy"],["Danish","dansk","da"],["German","Deutsch","de"],["Zazaki","Zazaki","diq"],["Lower Sorbian","dolnoserbski","dsb"],["Divehi","ދިވެހިބަސް","dv"],["Dzongkha","ཇོང་ཁ","dz"],["Ewe","eʋegbe","ee"],["Greek","Ελληνικά","el"],["Emiliano-Romagnolo","emiliàn e rumagnòl","eml"],["English","English","en"],["Esperanto","Esperanto","eo"],["Spanish","español","es"],["Estonian","eesti","et"],["Basque","euskara","eu"],["Extremaduran","estremeñu","ext"],["Persian","فارسی","fa"],["Fulah","Fulfulde","ff"],["Finnish","suomi","fi"],["Võro","Võro","fiu-vro"],["Fijian","Na Vosa Vakaviti","fj"],["Faroese","føroyskt","fo"],["French","français","fr"],["Arpitan","arpetan","frp"],["Northern Frisian","Nordfriisk","frr"],["Friulian","furlan","fur"],["Western Frisian","Frysk","fy"],["Irish","Gaeilge","ga"],["Gagauz","Gagauz","gag"],["Gan Chinese","贛語","gan"],["Scottish Gaelic","Gàidhlig","gd"],["Galician","galego","gl"],["Gilaki","گیلکی","glk"],["Guarani","Avañe'ẽ","gn"],["Goan Konkani","गोंयची कोंकणी / Gõychi Konknni","gom"],["Gothic","𐌲𐌿𐍄𐌹𐍃𐌺","got"],["Gujarati","ગુજરાતી","gu"],["Manx","Gaelg","gv"],["Hausa","Hausa","ha"],["Hakka Chinese","客家語/Hak-kâ-ngî","hak"],["Hawaiian","Hawaiʻi","haw"],["Hebrew","עברית","he"],["Hindi","हिन्दी","hi"],["Fiji Hindi","Fiji Hindi","hif"],["Croatian","hrvatski","hr"],["Upper Sorbian","hornjoserbsce","hsb"],["Haitian Creole","Kreyòl ayisyen","ht"],["Hungarian","magyar","hu"],["Armenian","Հայերեն","hy"],["Interlingua","interlingua","ia"],["Indonesian","Bahasa Indonesia","id"],["Interlingue","Interlingue","ie"],["Igbo","Igbo","ig"],["Inupiaq","Iñupiak","ik"],["Iloko","Ilokano","ilo"],["Ido","Ido","io"],["Icelandic","íslenska","is"],["Italian","italiano","it"],["Inuktitut","ᐃᓄᒃᑎᑐᑦ/inuktitut","iu"],["Japanese","日本語","ja"],["Jamaican Creole English","Patois","jam"],["Lojban","la .lojban.","jbo"],["Javanese","Basa Jawa","jv"],["Georgian","ქართული","ka"],["Kara-Kalpak","Qaraqalpaqsha","kaa"],["Kabyle","Taqbaylit","kab"],["Kabardian","Адыгэбзэ","kbd"],["Kongo","Kongo","kg"],["Kikuyu","Gĩkũyũ","ki"],["Kazakh","қазақша","kk"],["Kalaallisut","kalaallisut","kl"],["Khmer","ភាសាខ្មែរ","km"],["Kannada","ಕನ್ನಡ","kn"],["Korean","한국어","ko"],["Komi-Permyak","Перем Коми","koi"],["Karachay-Balkar","къарачай-малкъар","krc"],["Kashmiri","कॉशुर / کٲشُر","ks"],["Colognian","Ripoarisch","ksh"],["Kurdish","Kurdî","ku"],["Komi","коми","kv"],["Cornish","kernowek","kw"],["Kyrgyz","Кыргызча","ky"],["Latin","Latina","la"],["Ladino","Ladino","lad"],["Luxembourgish","Lëtzebuergesch","lb"],["лакку","лакку","lbe"],["Lezghian","лезги","lez"],["Ganda","Luganda","lg"],["Limburgish","Limburgs","li"],["Ligurian","Ligure","lij"],["Lombard","lumbaart","lmo"],["Lingala","lingála","ln"],["Lao","ລາວ","lo"],["Northern Luri","لۊری شومالی","lrc"],["Lithuanian","lietuvių","lt"],["Latgalian","latgaļu","ltg"],["Latvian","latviešu","lv"],["Maithili","मैथिली","mai"],["Basa Banyumasan","Basa Banyumasan","map-bms"],["Moksha","мокшень","mdf"],["Malagasy","Malagasy","mg"],["Eastern Mari","олык марий","mhr"],["Maori","Māori","mi"],["Minangkabau","Baso Minangkabau","min"],["Macedonian","македонски","mk"],["Malayalam","മലയാളം","ml"],["Mongolian","монгол","mn"],["Marathi","मराठी","mr"],["Western Mari","кырык мары","mrj"],["Malay","Bahasa Melayu","ms"],["Maltese","Malti","mt"],["Mirandese","Mirandés","mwl"],["Burmese","မြန်မာဘာသာ","my"],["Erzya","эрзянь","myv"],["Mazanderani","مازِرونی","mzn"],["Nauru","Dorerin Naoero","na"],["Nāhuatl","Nāhuatl","nah"],["Neapolitan","Napulitano","nap"],["Low German","Plattdüütsch","nds"],["Low Saxon","Nedersaksies","nds-nl"],["Nepali","नेपाली","ne"],["Newari","नेपाल भाषा","new"],["Dutch","Nederlands","nl"],["Norwegian Nynorsk","norsk nynorsk","nn"],["Norwegian","norsk bokmål","no"],["Novial","Novial","nov"],["Nouormand","Nouormand","nrm"],["Northern Sotho","Sesotho sa Leboa","nso"],["Navajo","Diné bizaad","nv"],["Nyanja","Chi-Chewa","ny"],["Occitan","occitan","oc"],["Oromo","Oromoo","om"],["Oriya","ଓଡ଼ିଆ","or"],["Ossetic","Ирон","os"],["Punjabi","ਪੰਜਾਬੀ","pa"],["Pangasinan","Pangasinan","pag"],["Pampanga","Kapampangan","pam"],["Papiamento","Papiamentu","pap"],["Picard","Picard","pcd"],["Pennsylvania German","Deitsch","pdc"],["Palatine German","Pälzisch","pfl"],["Pali","पालि","pi"],["Norfuk / Pitkern","Norfuk / Pitkern","pih"],["Polish","polski","pl"],["Piedmontese","Piemontèis","pms"],["Western Punjabi","پنجابی","pnb"],["Pontic","Ποντιακά","pnt"],["Pashto","پښتو","ps"],["Portuguese","português","pt"],["Quechua","Runa Simi","qu"],["Romansh","rumantsch","rm"],["Romani","Romani","rmy"],["Rundi","Kirundi","rn"],["Romanian","română","ro"],["Aromanian","armãneashti","roa-rup"],["tarandíne","tarandíne","roa-tara"],["Russian","русский","ru"],["Rusyn","русиньскый","rue"],["Kinyarwanda","Kinyarwanda","rw"],["Sanskrit","संस्कृतम्","sa"],["Sakha","саха тыла","sah"],["Sardinian","sardu","sc"],["Sicilian","sicilianu","scn"],["Scots","Scots","sco"],["Sindhi","سنڌي","sd"],["Northern Sami","sámegiella","se"],["Sango","Sängö","sg"],["Serbo-Croatian","srpskohrvatski / српскохрватски","sh"],["Sinhala","සිංහල","si"],["Simple English","Simple English","simple"],["Slovak","slovenčina","sk"],["Slovenian","slovenščina","sl"],["Samoan","Gagana Samoa","sm"],["Shona","chiShona","sn"],["Somali","Soomaaliga","so"],["Albanian","shqip","sq"],["Serbian","српски / srpski","sr"],["Sranan Tongo","Sranantongo","srn"],["Swati","SiSwati","ss"],["Southern Sotho","Sesotho","st"],["Saterland Frisian","Seeltersk","stq"],["Sundanese","Basa Sunda","su"],["Swedish","svenska","sv"],["Swahili","Kiswahili","sw"],["Silesian","ślůnski","szl"],["Tamil","தமிழ்","ta"],["Telugu","తెలుగు","te"],["Tetum","tetun","tet"],["Tajik","тоҷикӣ","tg"],["Thai","ไทย","th"],["Tigrinya","ትግርኛ","ti"],["Turkmen","Türkmençe","tk"],["Tagalog","Tagalog","tl"],["Tswana","Setswana","tn"],["Tongan","lea faka-Tonga","to"],["Tok Pisin","Tok Pisin","tpi"],["Turkish","Türkçe","tr"],["Tsonga","Xitsonga","ts"],["Tatar","татарча/tatarça","tt"],["Tumbuka","chiTumbuka","tum"],["Twi","Twi","tw"],["Tahitian","reo tahiti","ty"],["Tuvinian","тыва дыл","tyv"],["Udmurt","удмурт","udm"],["Uyghur","ئۇيغۇرچە / Uyghurche","ug"],["Ukrainian","українська","uk"],["Urdu","اردو","ur"],["Uzbek","oʻzbekcha/ўзбекча","uz"],["Venda","Tshivenda","ve"],["Venetian","vèneto","vec"],["Veps","vepsän kel’","vep"],["Vietnamese","Tiếng Việt","vi"],["West Flemish","West-Vlams","vls"],["Volapük","Volapük","vo"],["Walloon","walon","wa"],["Waray","Winaray","war"],["Wolof","Wolof","wo"],["Wu Chinese","吴语","wuu"],["Kalmyk","хальмг","xal"],["Xhosa","isiXhosa","xh"],["Mingrelian","მარგალური","xmf"],["Yiddish","ייִדיש","yi"],["Yoruba","Yorùbá","yo"],["Zhuang","Vahcuengh","za"],["Zeelandic","Zeêuws","zea"],["Chinese","中文","zh"],["Classical Chinese","文言","zh-classical"],["Chinese (Min Nan)","Bân-lâm-gú","zh-min-nan"],["Cantonese","粵語","zh-yue"],["Zulu","isiZulu","zu"]],"imperial":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[1.97754,51.13111],[1.8457,63.45051],[-10.45898,57.01681],[-6.82251,55.26503],[-7.25583,55.06525],[-7.26546,55.0665],[-7.26992,55.06419],[-7.2725,55.06346],[-7.27818,55.05362],[-7.2893,55.04735],[-7.29939,55.0561],[-7.31835,55.04475],[-7.3447,55.05079],[-7.38831,55.02389],[-7.40547,55.00292],[-7.39157,54.99507],[-7.40075,54.98892],[-7.40706,54.98291],[-7.40363,54.97963],[-7.40633,54.97813],[-7.39835,54.97013],[-7.40745,54.96357],[-7.40178,54.95961],[-7.40727,54.95515],[-7.3944,54.94376],[-7.44444,54.93858],[-7.45216,54.89793],[-7.44204,54.87532],[-7.4713,54.83431],[-7.48092,54.83093],[-7.49216,54.82185],[-7.55121,54.79054],[-7.5443,54.78609],[-7.54958,54.75653],[-7.5349,54.74917],[-7.54881,54.74068],[-7.55941,54.74556],[-7.57894,54.74221],[-7.57507,54.7494],[-7.58606,54.75039],[-7.58872,54.74377],[-7.60031,54.74603],[-7.60632,54.74405],[-7.61662,54.74459],[-7.63593,54.75108],[-7.68854,54.72968],[-7.72064,54.72155],[-7.75094,54.70469],[-7.79094,54.71942],[-7.8051,54.71932],[-7.83497,54.73632],[-7.85419,54.72745],[-7.91496,54.67582],[-7.90174,54.66182],[-7.83832,54.63401],[-7.7433,54.6188],[-7.70863,54.63485],[-7.70682,54.6189],[-7.69386,54.6188],[-7.69631,54.61125],[-7.75845,54.59509],[-7.78708,54.58],[-7.79446,54.58141],[-7.79969,54.57704],[-7.79673,54.56915],[-7.8184,54.56315],[-7.83334,54.55227],[-7.82737,54.54299],[-7.85007,54.53363],[-7.90741,54.53722],[-7.93213,54.53388],[-8.00487,54.54568],[-8.03727,54.51162],[-8.04285,54.48759],[-8.08027,54.48829],[-8.09988,54.48395],[-8.09126,54.4765],[-8.111,54.47807],[-8.11512,54.46904],[-8.16542,54.46914],[-8.1776,54.46485],[-8.14293,54.45003],[-8.16284,54.4413],[-8.08731,54.4002],[-8.06062,54.37051],[-8.03289,54.35711],[-8.00054,54.34835],[-7.93333,54.30561],[-7.85849,54.29151],[-7.87067,54.28794],[-7.87265,54.26648],[-7.86123,54.25931],[-7.85917,54.21256],[-7.71043,54.20307],[-7.70193,54.20776],[-7.68828,54.202],[-7.67644,54.18906],[-7.66082,54.1871],[-7.62554,54.16545],[-7.62541,54.15319],[-7.61026,54.14353],[-7.57421,54.14142],[-7.57181,54.13287],[-7.56228,54.12704],[-7.51379,54.12998],[-7.47944,54.122],[-7.47169,54.12665],[-7.47075,54.13318],[-7.44684,54.15168],[-7.40792,54.156],[-7.42579,54.14092],[-7.41903,54.13629],[-7.3744,54.14172],[-7.37234,54.13881],[-7.39509,54.12624],[-7.39182,54.12017],[-7.36341,54.13157],[-7.34518,54.11577],[-7.32471,54.12123],[-7.32003,54.11379],[-7.3078,54.11718],[-7.30548,54.12347],[-7.31591,54.12697],[-7.31213,54.13162],[-7.3187,54.13411],[-7.31857,54.13745],[-7.32222,54.13836],[-7.32737,54.13544],[-7.3399,54.14585],[-7.30827,54.16716],[-7.30024,54.16625],[-7.29029,54.1715],[-7.28158,54.16839],[-7.2863,54.14919],[-7.29874,54.14904],[-7.30162,54.14411],[-7.28411,54.13971],[-7.29192,54.13071],[-7.29737,54.133],[-7.30883,54.13242],[-7.30333,54.12251],[-7.29218,54.11929],[-7.27844,54.12282],[-7.27707,54.12986],[-7.26613,54.13624],[-7.2566,54.16354],[-7.24015,54.17125],[-7.2575,54.17678],[-7.2581,54.19257],[-7.25179,54.19403],[-7.23608,54.1935],[-7.23338,54.19792],[-7.24317,54.20076],[-7.24892,54.1977],[-7.25183,54.20201],[-7.24119,54.20623],[-7.23094,54.20578],[-7.23269,54.20912],[-7.22188,54.21607],[-7.20643,54.2117],[-7.18506,54.22485],[-7.17055,54.21742],[-7.14721,54.22488],[-7.14633,54.23008],[-7.15051,54.23165],[-7.14613,54.23983],[-7.15802,54.24434],[-7.13985,54.25298],[-7.15255,54.26235],[-7.16064,54.27405],[-7.17991,54.27144],[-7.17201,54.28627],[-7.21252,54.2985],[-7.19888,54.31117],[-7.17918,54.30946],[-7.1812,54.3397],[-7.15339,54.33514],[-7.10253,54.35811],[-7.10811,54.36677],[-7.06927,54.3899],[-7.05593,54.41056],[-7.02898,54.42135],[-7.00198,54.40832],[-6.98683,54.40829],[-6.97562,54.40014],[-6.96774,54.40145],[-6.90682,54.36966],[-6.89772,54.35075],[-6.87527,54.33853],[-6.86512,54.32568],[-6.85163,54.29137],[-6.87452,54.28677],[-6.87791,54.27918],[-6.86673,54.27522],[-6.85177,54.26489],[-6.83693,54.26658],[-6.82165,54.24346],[-6.81633,54.22299],[-6.80045,54.22108],[-6.80122,54.21338],[-6.77599,54.19965],[-6.75573,54.1987],[-6.74316,54.18258],[-6.73406,54.18566],[-6.72445,54.18127],[-6.70295,54.20036],[-6.69166,54.20018],[-6.68673,54.19398],[-6.669,54.19584],[-6.65248,54.18102],[-6.6433,54.17801],[-6.63467,54.16449],[-6.63179,54.14766],[-6.64081,54.14238],[-6.63935,54.13599],[-6.66149,54.1205],[-6.6481,54.10153],[-6.66119,54.0934],[-6.66458,54.06629],[-6.64681,54.05873],[-6.62501,54.03737],[-6.59291,54.04755],[-6.58905,54.05808],[-6.5597,54.0481],[-6.52897,54.05888],[-6.50442,54.05566],[-6.47824,54.07004],[-6.47919,54.07762],[-6.43601,54.05959],[-6.36314,54.07057],[-6.36589,54.09338],[-6.36293,54.09758],[-6.37104,54.11497],[-6.3522,54.11084],[-6.34242,54.1114],[-6.33589,54.10833],[-6.33636,54.09469],[-6.31808,54.09096],[-6.30903,54.10463],[-6.29165,54.11235],[-6.28246,54.11145],[-6.26272,54.09786],[-5.35583,53.72597],[-7.0752,49.23912],[-1.83472,49.02346],[-2.12036,49.94415],[1.97754,51.13111]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-65.2,18.7],[-65,16.3],[-63.7,19.2],[-65.2,18.7]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-63,-50.5],[-55,-51],[-60,-54],[-63,-50.5]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-139.19952,60.08402],[-141,60.30621],[-141,76],[-169,68.63655],[-169,65.20147],[-180,61],[-180,-4],[-154,9],[-133.76404,54.54021],[-130.73868,54.71986],[-129.96277,55.29163],[-130.15228,55.7758],[-130.01787,55.90688],[-130.00362,56.00798],[-130.10284,56.12336],[-130.24498,56.09656],[-130.42625,56.14249],[-131.87439,56.79787],[-135.02884,59.56285],[-135.11759,59.62306],[-135.15827,59.6261],[-135.47928,59.79822],[-136.28677,59.57955],[-136.30531,59.46462],[-136.36836,59.44898],[-136.47697,59.46558],[-137.19727,59.01935],[-139.19952,60.08402]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-111.96064,48.99841],[-121.22623,49.00049],[-122.26513,49.00246],[-122.7565,49.00208],[-123.32218,49.00218],[-122.97821,48.76524],[-123.2666,48.69821],[-123.21991,48.21186],[-125.80444,48.60749],[-124.32129,31.54109],[-117.125,32.53429],[-116.82417,32.55996],[-115.88036,32.63735],[-115.49738,32.66486],[-114.71984,32.71877],[-114.7649,32.64602],[-114.80885,32.60959],[-114.81481,32.49451],[-112.81743,31.88004],[-111.07481,31.33224],[-109.56051,31.33402],[-108.20847,31.33384],[-108.20838,31.78363],[-106.52847,31.78391],[-106.52781,31.78086],[-106.52249,31.77501],[-106.51249,31.76933],[-106.50988,31.7612],[-106.50709,31.76123],[-106.48896,31.74806],[-106.48473,31.74769],[-106.4719,31.75101],[-106.46816,31.75897],[-106.45434,31.76466],[-106.45035,31.76426],[-106.43516,31.75492],[-106.41484,31.75101],[-106.37864,31.73021],[-106.37225,31.71174],[-106.34924,31.69633],[-106.33289,31.66178],[-106.3068,31.62459],[-106.28079,31.56179],[-106.24775,31.54226],[-106.2329,31.49982],[-106.2105,31.46857],[-106.08201,31.39863],[-106.00554,31.39233],[-105.76401,31.17051],[-105.58548,31.06117],[-105.56419,30.98526],[-104.99153,30.6639],[-104.97162,30.60896],[-104.90639,30.57822],[-104.83772,30.38117],[-104.70177,30.20567],[-104.68048,29.92399],[-104.57611,29.77838],[-104.51157,29.63674],[-104.39758,29.57047],[-104.39278,29.55293],[-104.05769,29.32173],[-103.79883,29.2581],[-103.78196,29.26555],[-103.76759,29.22799],[-103.14102,28.93666],[-102.86087,29.2217],[-102.65076,29.79418],[-101.41068,29.73457],[-101.26511,29.51372],[-101.05997,29.452],[-101.04083,29.38038],[-100.96303,29.34735],[-100.94406,29.34369],[-100.94071,29.33351],[-100.92775,29.32663],[-100.89814,29.30957],[-100.87818,29.28086],[-100.80076,29.2238],[-100.76437,29.15981],[-100.67047,29.08663],[-100.6412,28.91299],[-100.63236,28.90255],[-100.61296,28.89939],[-100.534,28.75622],[-100.51495,28.74531],[-100.50705,28.7143],[-100.51203,28.70666],[-100.51014,28.69127],[-100.50048,28.66186],[-100.45547,28.6381],[-100.44697,28.60743],[-100.35599,28.45239],[-100.34946,28.39653],[-100.29488,28.31315],[-100.29591,28.27324],[-100.17197,28.17493],[-99.93645,27.9568],[-99.87722,27.80173],[-99.79671,27.73338],[-99.772,27.72532],[-99.74556,27.69979],[-99.71947,27.65981],[-99.5957,27.59974],[-99.54094,27.60537],[-99.53055,27.57973],[-99.52034,27.55782],[-99.52802,27.49773],[-99.50141,27.49986],[-99.48755,27.49518],[-99.47897,27.48421],[-99.48661,27.46453],[-99.49534,27.44861],[-99.48927,27.40941],[-99.53957,27.31565],[-99.43588,27.19678],[-99.46404,27.01968],[-99.16698,26.56039],[-99.17474,26.53939],[-99.12698,26.51958],[-99.1135,26.42954],[-99.08355,26.39625],[-99.06007,26.39737],[-99.03634,26.41255],[-99.02042,26.40598],[-99.01291,26.39364],[-98.95686,26.38641],[-98.9566,26.37365],[-98.94523,26.36949],[-98.90013,26.36419],[-98.89905,26.35454],[-98.80305,26.36626],[-98.78254,26.30511],[-98.66667,26.23457],[-98.58496,26.24647],[-98.57951,26.23434],[-98.56519,26.23987],[-98.56294,26.22464],[-98.50599,26.20858],[-98.44806,26.21236],[-98.38617,26.15721],[-98.34176,26.15278],[-98.33579,26.1388],[-98.30626,26.10003],[-98.28841,26.10512],[-98.26524,26.0914],[-98.19898,26.06411],[-98.09577,26.05698],[-98.07568,26.06667],[-98.08302,26.03396],[-97.9771,26.04136],[-97.9532,26.06179],[-97.81643,26.04475],[-97.77017,26.02439],[-97.73884,26.02902],[-97.5289,25.90648],[-97.52151,25.88625],[-97.50615,25.89031],[-97.49851,25.89903],[-97.49637,25.89641],[-97.49748,25.88008],[-97.49422,25.87981],[-97.48847,25.88564],[-97.46409,25.88174],[-97.42607,25.842],[-97.36856,25.8396],[-97.26231,25.94724],[-80.81543,24.00633],[-66.87378,44.77794],[-67.16148,45.16715],[-67.2286,45.16739],[-67.26246,45.18797],[-67.28311,45.19175],[-67.28959,45.18784],[-67.29332,45.17568],[-67.29049,45.17317],[-67.3001,45.16776],[-67.3025,45.16122],[-67.29761,45.14766],[-67.33975,45.1255],[-67.40524,45.16122],[-67.40387,45.17139],[-67.4818,45.27682],[-67.42172,45.38543],[-67.45262,45.41008],[-67.50498,45.4889],[-67.41623,45.50105],[-67.42219,45.55661],[-67.42902,45.56833],[-67.42331,45.57154],[-67.42498,45.57836],[-67.45193,45.60323],[-67.77981,45.6738],[-67.79019,47.06776],[-67.88006,47.1067],[-67.91319,47.14793],[-67.92598,47.15418],[-67.95181,47.1875],[-68.02374,47.23915],[-68.13017,47.29309],[-68.17669,47.32893],[-68.24046,47.35354],[-68.32809,47.36005],[-68.36363,47.35476],[-68.38054,47.34167],[-68.38509,47.30321],[-68.37367,47.28796],[-68.4377,47.28232],[-68.47916,47.29623],[-68.51074,47.29885],[-68.54593,47.28441],[-68.58408,47.28482],[-68.59777,47.27134],[-68.59271,47.25762],[-68.61889,47.24148],[-68.68936,47.24125],[-68.71768,47.23676],[-68.80128,47.21423],[-68.89629,47.17676],[-69.05354,47.24847],[-69.04924,47.41798],[-69.22425,47.45961],[-69.99729,46.69558],[-70.0569,46.4149],[-70.25551,46.10871],[-70.29001,46.09431],[-70.39919,45.80667],[-70.83229,45.40062],[-70.80794,45.37878],[-70.82663,45.2367],[-70.87538,45.23453],[-70.92138,45.28099],[-70.90645,45.30918],[-71.0109,45.34798],[-71.08429,45.30556],[-71.1454,45.24226],[-71.20525,45.25278],[-71.28925,45.30097],[-71.41405,45.23513],[-71.43044,45.12381],[-71.49692,45.06991],[-71.50623,45.04878],[-71.49284,45.03629],[-71.50027,45.01372],[-71.79359,45.01075],[-72.08774,45.00581],[-72.14155,45.00568],[-72.15282,45.00609],[-72.17142,45.00584],[-72.25847,45.00436],[-72.38795,45.00626],[-72.4496,45.00863],[-72.5356,45.00936],[-72.66257,45.01523],[-72.82537,45.01642],[-73.08466,45.01561],[-73.45219,45.00875],[-74.14699,44.99145],[-74.33753,44.9923],[-74.50786,44.99798],[-74.66158,44.99949],[-74.71244,44.99734],[-74.75887,44.98708],[-74.76368,45.00632],[-74.78977,45.00365],[-74.82376,45.01773],[-74.94186,44.98229],[-75.30098,44.83883],[-75.30304,44.82836],[-75.59418,44.6457],[-75.97269,44.33502],[-75.97295,44.34595],[-76.00059,44.34797],[-76.17645,44.2865],[-76.18744,44.22158],[-76.88782,43.82759],[-79.16851,43.32168],[-79.05487,43.25371],[-79.05092,43.169],[-79.04603,43.16093],[-79.04208,43.13942],[-79.07002,43.12038],[-79.06015,43.114],[-79.0568,43.10474],[-79.0774,43.07861],[-78.9996,43.05484],[-79.02311,43.02071],[-79.02552,42.99473],[-78.96235,42.9573],[-78.91188,42.9426],[-78.90398,42.89181],[-82.42767,41.47978],[-83.14316,42.03807],[-83.12805,42.23843],[-83.09715,42.29052],[-83.07252,42.31515],[-82.94575,42.34332],[-82.59676,42.5479],[-82.51368,42.61785],[-82.5108,42.66464],[-82.4675,42.76415],[-82.48055,42.80573],[-82.45497,42.9284],[-82.41334,42.97099],[-82.42596,42.99536],[-82.15851,43.39507],[-83.53729,46.098],[-83.96301,46.05036],[-84.11021,46.23851],[-84.09794,46.25656],[-84.11613,46.26878],[-84.11905,46.31516],[-84.10721,46.3218],[-84.14394,46.41076],[-84.11682,46.51576],[-84.13536,46.53218],[-84.16162,46.5284],[-84.21621,46.53891],[-84.26994,46.49189],[-84.36092,46.50997],[-84.55284,46.4407],[-84.95178,46.77185],[-89.59179,48.00307],[-89.67547,48.00371],[-90.87204,48.25943],[-91.41312,48.06753],[-92.99377,48.62474],[-93.34877,48.62604],[-93.35529,48.61124],[-93.37074,48.60584],[-93.39812,48.60369],[-93.40542,48.61089],[-93.43846,48.59478],[-93.46859,48.59205],[-93.45735,48.56667],[-93.46533,48.54593],[-93.64763,48.51751],[-93.80625,48.51888],[-93.80642,48.58047],[-93.83328,48.62582],[-93.84865,48.63064],[-93.93388,48.6326],[-94.01327,48.64471],[-94.16176,48.64697],[-94.25025,48.65463],[-94.24931,48.67827],[-94.26046,48.69816],[-94.30578,48.71073],[-94.32758,48.70433],[-94.36123,48.70478],[-94.38406,48.71135],[-94.41629,48.71067],[-94.44294,48.69266],[-94.53615,48.7024],[-94.55031,48.71419],[-94.58894,48.71928],[-94.69425,48.77938],[-94.70129,48.83376],[-94.68996,48.83953],[-94.68395,48.99914],[-111.96064,48.99841]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[180,55],[170,53],[180,49],[180,55]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[143,22],[147,22],[147,12],[143,12],[143,22]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-171.5,-10],[-171,-15],[-167,-15],[-171.5,-10]]]}}]},"featureIcons":{"circle-stroked-24":{"x":0,"y":0,"width":24,"height":24},"circle-stroked-18":{"x":24,"y":0,"width":18,"height":18},"circle-stroked-12":{"x":42,"y":0,"width":12,"height":12},"circle-24":{"x":54,"y":0,"width":24,"height":24},"circle-18":{"x":78,"y":0,"width":18,"height":18},"circle-12":{"x":96,"y":0,"width":12,"height":12},"square-stroked-24":{"x":108,"y":0,"width":24,"height":24},"square-stroked-18":{"x":132,"y":0,"width":18,"height":18},"square-stroked-12":{"x":150,"y":0,"width":12,"height":12},"square-24":{"x":162,"y":0,"width":24,"height":24},"square-18":{"x":186,"y":0,"width":18,"height":18},"square-12":{"x":204,"y":0,"width":12,"height":12},"triangle-stroked-24":{"x":216,"y":0,"width":24,"height":24},"triangle-stroked-18":{"x":240,"y":0,"width":18,"height":18},"triangle-stroked-12":{"x":258,"y":0,"width":12,"height":12},"triangle-24":{"x":0,"y":24,"width":24,"height":24},"triangle-18":{"x":24,"y":24,"width":18,"height":18},"triangle-12":{"x":42,"y":24,"width":12,"height":12},"star-stroked-24":{"x":54,"y":24,"width":24,"height":24},"star-stroked-18":{"x":78,"y":24,"width":18,"height":18},"star-stroked-12":{"x":96,"y":24,"width":12,"height":12},"star-24":{"x":108,"y":24,"width":24,"height":24},"star-18":{"x":132,"y":24,"width":18,"height":18},"star-12":{"x":150,"y":24,"width":12,"height":12},"cross-24":{"x":162,"y":24,"width":24,"height":24},"cross-18":{"x":186,"y":24,"width":18,"height":18},"cross-12":{"x":204,"y":24,"width":12,"height":12},"marker-stroked-24":{"x":216,"y":24,"width":24,"height":24},"marker-stroked-18":{"x":240,"y":24,"width":18,"height":18},"marker-stroked-12":{"x":258,"y":24,"width":12,"height":12},"marker-24":{"x":0,"y":48,"width":24,"height":24},"marker-18":{"x":24,"y":48,"width":18,"height":18},"marker-12":{"x":42,"y":48,"width":12,"height":12},"religious-jewish-24":{"x":54,"y":48,"width":24,"height":24},"religious-jewish-18":{"x":78,"y":48,"width":18,"height":18},"religious-jewish-12":{"x":96,"y":48,"width":12,"height":12},"religious-christian-24":{"x":108,"y":48,"width":24,"height":24},"religious-christian-18":{"x":132,"y":48,"width":18,"height":18},"religious-christian-12":{"x":150,"y":48,"width":12,"height":12},"religious-muslim-24":{"x":162,"y":48,"width":24,"height":24},"religious-muslim-18":{"x":186,"y":48,"width":18,"height":18},"religious-muslim-12":{"x":204,"y":48,"width":12,"height":12},"cemetery-24":{"x":216,"y":48,"width":24,"height":24},"cemetery-18":{"x":240,"y":48,"width":18,"height":18},"cemetery-12":{"x":258,"y":48,"width":12,"height":12},"rocket-24":{"x":0,"y":72,"width":24,"height":24},"rocket-18":{"x":24,"y":72,"width":18,"height":18},"rocket-12":{"x":42,"y":72,"width":12,"height":12},"airport-24":{"x":54,"y":72,"width":24,"height":24},"airport-18":{"x":78,"y":72,"width":18,"height":18},"airport-12":{"x":96,"y":72,"width":12,"height":12},"heliport-24":{"x":108,"y":72,"width":24,"height":24},"heliport-18":{"x":132,"y":72,"width":18,"height":18},"heliport-12":{"x":150,"y":72,"width":12,"height":12},"rail-24":{"x":162,"y":72,"width":24,"height":24},"rail-18":{"x":186,"y":72,"width":18,"height":18},"rail-12":{"x":204,"y":72,"width":12,"height":12},"rail-metro-24":{"x":216,"y":72,"width":24,"height":24},"rail-metro-18":{"x":240,"y":72,"width":18,"height":18},"rail-metro-12":{"x":258,"y":72,"width":12,"height":12},"rail-light-24":{"x":0,"y":96,"width":24,"height":24},"rail-light-18":{"x":24,"y":96,"width":18,"height":18},"rail-light-12":{"x":42,"y":96,"width":12,"height":12},"bus-24":{"x":54,"y":96,"width":24,"height":24},"bus-18":{"x":78,"y":96,"width":18,"height":18},"bus-12":{"x":96,"y":96,"width":12,"height":12},"fuel-24":{"x":108,"y":96,"width":24,"height":24},"fuel-18":{"x":132,"y":96,"width":18,"height":18},"fuel-12":{"x":150,"y":96,"width":12,"height":12},"parking-24":{"x":162,"y":96,"width":24,"height":24},"parking-18":{"x":186,"y":96,"width":18,"height":18},"parking-12":{"x":204,"y":96,"width":12,"height":12},"parking-garage-24":{"x":216,"y":96,"width":24,"height":24},"parking-garage-18":{"x":240,"y":96,"width":18,"height":18},"parking-garage-12":{"x":258,"y":96,"width":12,"height":12},"airfield-24":{"x":0,"y":120,"width":24,"height":24},"airfield-18":{"x":24,"y":120,"width":18,"height":18},"airfield-12":{"x":42,"y":120,"width":12,"height":12},"roadblock-24":{"x":54,"y":120,"width":24,"height":24},"roadblock-18":{"x":78,"y":120,"width":18,"height":18},"roadblock-12":{"x":96,"y":120,"width":12,"height":12},"ferry-24":{"x":108,"y":120,"width":24,"height":24},"ferry-18":{"x":132,"y":120,"width":18,"height":18},"ferry-12":{"x":150,"y":120,"width":12,"height":12},"harbor-24":{"x":162,"y":120,"width":24,"height":24},"harbor-18":{"x":186,"y":120,"width":18,"height":18},"harbor-12":{"x":204,"y":120,"width":12,"height":12},"bicycle-24":{"x":216,"y":120,"width":24,"height":24},"bicycle-18":{"x":240,"y":120,"width":18,"height":18},"bicycle-12":{"x":258,"y":120,"width":12,"height":12},"park-24":{"x":0,"y":144,"width":24,"height":24},"park-18":{"x":24,"y":144,"width":18,"height":18},"park-12":{"x":42,"y":144,"width":12,"height":12},"park2-24":{"x":54,"y":144,"width":24,"height":24},"park2-18":{"x":78,"y":144,"width":18,"height":18},"park2-12":{"x":96,"y":144,"width":12,"height":12},"museum-24":{"x":108,"y":144,"width":24,"height":24},"museum-18":{"x":132,"y":144,"width":18,"height":18},"museum-12":{"x":150,"y":144,"width":12,"height":12},"lodging-24":{"x":162,"y":144,"width":24,"height":24},"lodging-18":{"x":186,"y":144,"width":18,"height":18},"lodging-12":{"x":204,"y":144,"width":12,"height":12},"monument-24":{"x":216,"y":144,"width":24,"height":24},"monument-18":{"x":240,"y":144,"width":18,"height":18},"monument-12":{"x":258,"y":144,"width":12,"height":12},"zoo-24":{"x":0,"y":168,"width":24,"height":24},"zoo-18":{"x":24,"y":168,"width":18,"height":18},"zoo-12":{"x":42,"y":168,"width":12,"height":12},"garden-24":{"x":54,"y":168,"width":24,"height":24},"garden-18":{"x":78,"y":168,"width":18,"height":18},"garden-12":{"x":96,"y":168,"width":12,"height":12},"campsite-24":{"x":108,"y":168,"width":24,"height":24},"campsite-18":{"x":132,"y":168,"width":18,"height":18},"campsite-12":{"x":150,"y":168,"width":12,"height":12},"theatre-24":{"x":162,"y":168,"width":24,"height":24},"theatre-18":{"x":186,"y":168,"width":18,"height":18},"theatre-12":{"x":204,"y":168,"width":12,"height":12},"art-gallery-24":{"x":216,"y":168,"width":24,"height":24},"art-gallery-18":{"x":240,"y":168,"width":18,"height":18},"art-gallery-12":{"x":258,"y":168,"width":12,"height":12},"pitch-24":{"x":0,"y":192,"width":24,"height":24},"pitch-18":{"x":24,"y":192,"width":18,"height":18},"pitch-12":{"x":42,"y":192,"width":12,"height":12},"soccer-24":{"x":54,"y":192,"width":24,"height":24},"soccer-18":{"x":78,"y":192,"width":18,"height":18},"soccer-12":{"x":96,"y":192,"width":12,"height":12},"america-football-24":{"x":108,"y":192,"width":24,"height":24},"america-football-18":{"x":132,"y":192,"width":18,"height":18},"america-football-12":{"x":150,"y":192,"width":12,"height":12},"tennis-24":{"x":162,"y":192,"width":24,"height":24},"tennis-18":{"x":186,"y":192,"width":18,"height":18},"tennis-12":{"x":204,"y":192,"width":12,"height":12},"basketball-24":{"x":216,"y":192,"width":24,"height":24},"basketball-18":{"x":240,"y":192,"width":18,"height":18},"basketball-12":{"x":258,"y":192,"width":12,"height":12},"baseball-24":{"x":0,"y":216,"width":24,"height":24},"baseball-18":{"x":24,"y":216,"width":18,"height":18},"baseball-12":{"x":42,"y":216,"width":12,"height":12},"golf-24":{"x":54,"y":216,"width":24,"height":24},"golf-18":{"x":78,"y":216,"width":18,"height":18},"golf-12":{"x":96,"y":216,"width":12,"height":12},"swimming-24":{"x":108,"y":216,"width":24,"height":24},"swimming-18":{"x":132,"y":216,"width":18,"height":18},"swimming-12":{"x":150,"y":216,"width":12,"height":12},"cricket-24":{"x":162,"y":216,"width":24,"height":24},"cricket-18":{"x":186,"y":216,"width":18,"height":18},"cricket-12":{"x":204,"y":216,"width":12,"height":12},"skiing-24":{"x":216,"y":216,"width":24,"height":24},"skiing-18":{"x":240,"y":216,"width":18,"height":18},"skiing-12":{"x":258,"y":216,"width":12,"height":12},"school-24":{"x":0,"y":240,"width":24,"height":24},"school-18":{"x":24,"y":240,"width":18,"height":18},"school-12":{"x":42,"y":240,"width":12,"height":12},"college-24":{"x":54,"y":240,"width":24,"height":24},"college-18":{"x":78,"y":240,"width":18,"height":18},"college-12":{"x":96,"y":240,"width":12,"height":12},"library-24":{"x":108,"y":240,"width":24,"height":24},"library-18":{"x":132,"y":240,"width":18,"height":18},"library-12":{"x":150,"y":240,"width":12,"height":12},"post-24":{"x":162,"y":240,"width":24,"height":24},"post-18":{"x":186,"y":240,"width":18,"height":18},"post-12":{"x":204,"y":240,"width":12,"height":12},"fire-station-24":{"x":216,"y":240,"width":24,"height":24},"fire-station-18":{"x":240,"y":240,"width":18,"height":18},"fire-station-12":{"x":258,"y":240,"width":12,"height":12},"town-hall-24":{"x":0,"y":264,"width":24,"height":24},"town-hall-18":{"x":24,"y":264,"width":18,"height":18},"town-hall-12":{"x":42,"y":264,"width":12,"height":12},"police-24":{"x":54,"y":264,"width":24,"height":24},"police-18":{"x":78,"y":264,"width":18,"height":18},"police-12":{"x":96,"y":264,"width":12,"height":12},"prison-24":{"x":108,"y":264,"width":24,"height":24},"prison-18":{"x":132,"y":264,"width":18,"height":18},"prison-12":{"x":150,"y":264,"width":12,"height":12},"embassy-24":{"x":162,"y":264,"width":24,"height":24},"embassy-18":{"x":186,"y":264,"width":18,"height":18},"embassy-12":{"x":204,"y":264,"width":12,"height":12},"beer-24":{"x":216,"y":264,"width":24,"height":24},"beer-18":{"x":240,"y":264,"width":18,"height":18},"beer-12":{"x":258,"y":264,"width":12,"height":12},"restaurant-24":{"x":0,"y":288,"width":24,"height":24},"restaurant-18":{"x":24,"y":288,"width":18,"height":18},"restaurant-12":{"x":42,"y":288,"width":12,"height":12},"cafe-24":{"x":54,"y":288,"width":24,"height":24},"cafe-18":{"x":78,"y":288,"width":18,"height":18},"cafe-12":{"x":96,"y":288,"width":12,"height":12},"shop-24":{"x":108,"y":288,"width":24,"height":24},"shop-18":{"x":132,"y":288,"width":18,"height":18},"shop-12":{"x":150,"y":288,"width":12,"height":12},"fast-food-24":{"x":162,"y":288,"width":24,"height":24},"fast-food-18":{"x":186,"y":288,"width":18,"height":18},"fast-food-12":{"x":204,"y":288,"width":12,"height":12},"bar-24":{"x":216,"y":288,"width":24,"height":24},"bar-18":{"x":240,"y":288,"width":18,"height":18},"bar-12":{"x":258,"y":288,"width":12,"height":12},"bank-24":{"x":0,"y":312,"width":24,"height":24},"bank-18":{"x":24,"y":312,"width":18,"height":18},"bank-12":{"x":42,"y":312,"width":12,"height":12},"grocery-24":{"x":54,"y":312,"width":24,"height":24},"grocery-18":{"x":78,"y":312,"width":18,"height":18},"grocery-12":{"x":96,"y":312,"width":12,"height":12},"cinema-24":{"x":108,"y":312,"width":24,"height":24},"cinema-18":{"x":132,"y":312,"width":18,"height":18},"cinema-12":{"x":150,"y":312,"width":12,"height":12},"pharmacy-24":{"x":162,"y":312,"width":24,"height":24},"pharmacy-18":{"x":186,"y":312,"width":18,"height":18},"pharmacy-12":{"x":204,"y":312,"width":12,"height":12},"hospital-24":{"x":216,"y":312,"width":24,"height":24},"hospital-18":{"x":240,"y":312,"width":18,"height":18},"hospital-12":{"x":258,"y":312,"width":12,"height":12},"danger-24":{"x":0,"y":336,"width":24,"height":24},"danger-18":{"x":24,"y":336,"width":18,"height":18},"danger-12":{"x":42,"y":336,"width":12,"height":12},"industrial-24":{"x":54,"y":336,"width":24,"height":24},"industrial-18":{"x":78,"y":336,"width":18,"height":18},"industrial-12":{"x":96,"y":336,"width":12,"height":12},"warehouse-24":{"x":108,"y":336,"width":24,"height":24},"warehouse-18":{"x":132,"y":336,"width":18,"height":18},"warehouse-12":{"x":150,"y":336,"width":12,"height":12},"commercial-24":{"x":162,"y":336,"width":24,"height":24},"commercial-18":{"x":186,"y":336,"width":18,"height":18},"commercial-12":{"x":204,"y":336,"width":12,"height":12},"building-24":{"x":216,"y":336,"width":24,"height":24},"building-18":{"x":240,"y":336,"width":18,"height":18},"building-12":{"x":258,"y":336,"width":12,"height":12},"place-of-worship-24":{"x":0,"y":360,"width":24,"height":24},"place-of-worship-18":{"x":24,"y":360,"width":18,"height":18},"place-of-worship-12":{"x":42,"y":360,"width":12,"height":12},"alcohol-shop-24":{"x":54,"y":360,"width":24,"height":24},"alcohol-shop-18":{"x":78,"y":360,"width":18,"height":18},"alcohol-shop-12":{"x":96,"y":360,"width":12,"height":12},"logging-24":{"x":108,"y":360,"width":24,"height":24},"logging-18":{"x":132,"y":360,"width":18,"height":18},"logging-12":{"x":150,"y":360,"width":12,"height":12},"oil-well-24":{"x":162,"y":360,"width":24,"height":24},"oil-well-18":{"x":186,"y":360,"width":18,"height":18},"oil-well-12":{"x":204,"y":360,"width":12,"height":12},"slaughterhouse-24":{"x":216,"y":360,"width":24,"height":24},"slaughterhouse-18":{"x":240,"y":360,"width":18,"height":18},"slaughterhouse-12":{"x":258,"y":360,"width":12,"height":12},"dam-24":{"x":0,"y":384,"width":24,"height":24},"dam-18":{"x":24,"y":384,"width":18,"height":18},"dam-12":{"x":42,"y":384,"width":12,"height":12},"water-24":{"x":54,"y":384,"width":24,"height":24},"water-18":{"x":78,"y":384,"width":18,"height":18},"water-12":{"x":96,"y":384,"width":12,"height":12},"wetland-24":{"x":108,"y":384,"width":24,"height":24},"wetland-18":{"x":132,"y":384,"width":18,"height":18},"wetland-12":{"x":150,"y":384,"width":12,"height":12},"disability-24":{"x":162,"y":384,"width":24,"height":24},"disability-18":{"x":186,"y":384,"width":18,"height":18},"disability-12":{"x":204,"y":384,"width":12,"height":12},"telephone-24":{"x":216,"y":384,"width":24,"height":24},"telephone-18":{"x":240,"y":384,"width":18,"height":18},"telephone-12":{"x":258,"y":384,"width":12,"height":12},"emergency-telephone-24":{"x":0,"y":408,"width":24,"height":24},"emergency-telephone-18":{"x":24,"y":408,"width":18,"height":18},"emergency-telephone-12":{"x":42,"y":408,"width":12,"height":12},"toilets-24":{"x":54,"y":408,"width":24,"height":24},"toilets-18":{"x":78,"y":408,"width":18,"height":18},"toilets-12":{"x":96,"y":408,"width":12,"height":12},"waste-basket-24":{"x":108,"y":408,"width":24,"height":24},"waste-basket-18":{"x":132,"y":408,"width":18,"height":18},"waste-basket-12":{"x":150,"y":408,"width":12,"height":12},"music-24":{"x":162,"y":408,"width":24,"height":24},"music-18":{"x":186,"y":408,"width":18,"height":18},"music-12":{"x":204,"y":408,"width":12,"height":12},"land-use-24":{"x":216,"y":408,"width":24,"height":24},"land-use-18":{"x":240,"y":408,"width":18,"height":18},"land-use-12":{"x":258,"y":408,"width":12,"height":12},"city-24":{"x":0,"y":432,"width":24,"height":24},"city-18":{"x":24,"y":432,"width":18,"height":18},"city-12":{"x":42,"y":432,"width":12,"height":12},"town-24":{"x":54,"y":432,"width":24,"height":24},"town-18":{"x":78,"y":432,"width":18,"height":18},"town-12":{"x":96,"y":432,"width":12,"height":12},"village-24":{"x":108,"y":432,"width":24,"height":24},"village-18":{"x":132,"y":432,"width":18,"height":18},"village-12":{"x":150,"y":432,"width":12,"height":12},"farm-24":{"x":162,"y":432,"width":24,"height":24},"farm-18":{"x":186,"y":432,"width":18,"height":18},"farm-12":{"x":204,"y":432,"width":12,"height":12},"bakery-24":{"x":216,"y":432,"width":24,"height":24},"bakery-18":{"x":240,"y":432,"width":18,"height":18},"bakery-12":{"x":258,"y":432,"width":12,"height":12},"dog-park-24":{"x":0,"y":456,"width":24,"height":24},"dog-park-18":{"x":24,"y":456,"width":18,"height":18},"dog-park-12":{"x":42,"y":456,"width":12,"height":12},"lighthouse-24":{"x":54,"y":456,"width":24,"height":24},"lighthouse-18":{"x":78,"y":456,"width":18,"height":18},"lighthouse-12":{"x":96,"y":456,"width":12,"height":12},"clothing-store-24":{"x":108,"y":456,"width":24,"height":24},"clothing-store-18":{"x":132,"y":456,"width":18,"height":18},"clothing-store-12":{"x":150,"y":456,"width":12,"height":12},"polling-place-24":{"x":162,"y":456,"width":24,"height":24},"polling-place-18":{"x":186,"y":456,"width":18,"height":18},"polling-place-12":{"x":204,"y":456,"width":12,"height":12},"playground-24":{"x":216,"y":456,"width":24,"height":24},"playground-18":{"x":240,"y":456,"width":18,"height":18},"playground-12":{"x":258,"y":456,"width":12,"height":12},"entrance-24":{"x":0,"y":480,"width":24,"height":24},"entrance-18":{"x":24,"y":480,"width":18,"height":18},"entrance-12":{"x":42,"y":480,"width":12,"height":12},"heart-24":{"x":54,"y":480,"width":24,"height":24},"heart-18":{"x":78,"y":480,"width":18,"height":18},"heart-12":{"x":96,"y":480,"width":12,"height":12},"london-underground-24":{"x":108,"y":480,"width":24,"height":24},"london-underground-18":{"x":132,"y":480,"width":18,"height":18},"london-underground-12":{"x":150,"y":480,"width":12,"height":12},"minefield-24":{"x":162,"y":480,"width":24,"height":24},"minefield-18":{"x":186,"y":480,"width":18,"height":18},"minefield-12":{"x":204,"y":480,"width":12,"height":12},"rail-underground-24":{"x":216,"y":480,"width":24,"height":24},"rail-underground-18":{"x":240,"y":480,"width":18,"height":18},"rail-underground-12":{"x":258,"y":480,"width":12,"height":12},"rail-above-24":{"x":0,"y":504,"width":24,"height":24},"rail-above-18":{"x":24,"y":504,"width":18,"height":18},"rail-above-12":{"x":42,"y":504,"width":12,"height":12},"camera-24":{"x":54,"y":504,"width":24,"height":24},"camera-18":{"x":78,"y":504,"width":18,"height":18},"camera-12":{"x":96,"y":504,"width":12,"height":12},"laundry-24":{"x":108,"y":504,"width":24,"height":24},"laundry-18":{"x":132,"y":504,"width":18,"height":18},"laundry-12":{"x":150,"y":504,"width":12,"height":12},"car-24":{"x":162,"y":504,"width":24,"height":24},"car-18":{"x":186,"y":504,"width":18,"height":18},"car-12":{"x":204,"y":504,"width":12,"height":12},"suitcase-24":{"x":216,"y":504,"width":24,"height":24},"suitcase-18":{"x":240,"y":504,"width":18,"height":18},"suitcase-12":{"x":258,"y":504,"width":12,"height":12},"hairdresser-24":{"x":0,"y":528,"width":24,"height":24},"hairdresser-18":{"x":24,"y":528,"width":18,"height":18},"hairdresser-12":{"x":42,"y":528,"width":12,"height":12},"chemist-24":{"x":54,"y":528,"width":24,"height":24},"chemist-18":{"x":78,"y":528,"width":18,"height":18},"chemist-12":{"x":96,"y":528,"width":12,"height":12},"mobilephone-24":{"x":108,"y":528,"width":24,"height":24},"mobilephone-18":{"x":132,"y":528,"width":18,"height":18},"mobilephone-12":{"x":150,"y":528,"width":12,"height":12},"scooter-24":{"x":162,"y":528,"width":24,"height":24},"scooter-18":{"x":186,"y":528,"width":18,"height":18},"scooter-12":{"x":204,"y":528,"width":12,"height":12},"gift-24":{"x":216,"y":528,"width":24,"height":24},"gift-18":{"x":240,"y":528,"width":18,"height":18},"gift-12":{"x":258,"y":528,"width":12,"height":12},"ice-cream-24":{"x":0,"y":552,"width":24,"height":24},"ice-cream-18":{"x":24,"y":552,"width":18,"height":18},"ice-cream-12":{"x":42,"y":552,"width":12,"height":12}},"locales":["af","sq","ar","ar-AA","hy","ast","bn","bs","bg-BG","ca","zh","zh-CN","zh-HK","zh-TW","yue","hr","cs","da","nl","en-GB","eo","et","fi","fr","gl","de","el","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 (required)","message_label":"Changeset comment","upload_explanation":"The changes you upload will be visible on all maps that use OpenStreetMap data.","upload_explanation_with_user":"The changes you upload as {user} will be visible on all maps that use OpenStreetMap data.","save":"Save","cancel":"Cancel","changes":"{count} Changes","warnings":"Warnings","modified":"Modified","deleted":"Deleted","created":"Created","about_changeset_comments":"About changeset comments","about_changeset_comments_link":"//wiki.openstreetmap.org/wiki/Good_changeset_comments","google_warning":"You mentioned Google in this comment: remember that copying from Google Maps is strictly forbidden.","google_warning_link":"http://www.openstreetmap.org/copyright"},"contributors":{"list":"Edits by {users}","truncated_list":"Edits by {users} and {count} others"},"infobox":{"selected":"{n} selected","geometry":"Geometry","closed":"closed","center":"Center","perimeter":"Perimeter","length":"Length","area":"Area","centroid":"Centroid","location":"Location","metric":"Metric","imperial":"Imperial"},"geometry":{"point":"point","vertex":"vertex","line":"line","area":"area","relation":"relation"},"geocoder":{"search":"Search worldwide...","no_results_visible":"No results in visible map area","no_results_worldwide":"No results found"},"geolocate":{"title":"Show My Location","locating":"Locating, please wait..."},"inspector":{"no_documentation_combination":"There is no documentation available for this tag combination","no_documentation_key":"There is no documentation available for this key","show_more":"Show More","view_on_osm":"View on openstreetmap.org","all_fields":"All fields","all_tags":"All tags","all_members":"All members","all_relations":"All relations","new_relation":"New relation...","role":"Role","choose":"Select feature type","results":"{n} results for {search}","reference":"View on OpenStreetMap Wiki","back_tooltip":"Change feature","remove":"Remove","search":"Search","multiselect":"Selected items","unknown":"Unknown","incomplete":"<not downloaded>","feature_list":"Search features","edit":"Edit feature","check":{"yes":"Yes","no":"No"},"add":"Add","none":"None","node":"Node","way":"Way","relation":"Relation","location":"Location","add_fields":"Add field:"},"background":{"title":"Background","description":"Background settings","percent_brightness":"{opacity}% brightness","none":"None","best_imagery":"Best known imagery source for this location","switch":"Switch back to this background","custom":"Custom","custom_button":"Edit custom background","custom_prompt":"Enter a tile URL template. Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.","fix_misalignment":"Adjust imagery offset","imagery_source_faq":"Where does this imagery come from?","reset":"reset","offset":"Drag anywhere in the gray area below to adjust the imagery offset, or enter the offset values in meters.","minimap":{"description":"Minimap","tooltip":"Show a zoomed out map to help locate the area currently displayed."}},"map_data":{"title":"Map Data","description":"Map Data","data_layers":"Data Layers","fill_area":"Fill Areas","map_features":"Map Features","autohidden":"These features have been automatically hidden because too many would be shown on the screen. You can zoom in to edit them."},"feature":{"points":{"description":"Points","tooltip":"Points of Interest"},"traffic_roads":{"description":"Traffic Roads","tooltip":"Highways, Streets, etc."},"service_roads":{"description":"Service Roads","tooltip":"Service Roads, Parking Aisles, Tracks, etc."},"paths":{"description":"Paths","tooltip":"Sidewalks, Foot Paths, Cycle Paths, etc."},"buildings":{"description":"Buildings","tooltip":"Buildings, Shelters, Garages, etc."},"landuse":{"description":"Landuse Features","tooltip":"Forests, Farmland, Parks, Residential, Commercial, etc."},"boundaries":{"description":"Boundaries","tooltip":"Administrative Boundaries"},"water":{"description":"Water Features","tooltip":"Rivers, Lakes, Ponds, Basins, etc."},"rail":{"description":"Rail Features","tooltip":"Railways"},"power":{"description":"Power Features","tooltip":"Power Lines, Power Plants, Substations, etc."},"past_future":{"description":"Past/Future","tooltip":"Proposed, Construction, Abandoned, Demolished, etc."},"others":{"description":"Others","tooltip":"Everything Else"}},"area_fill":{"wireframe":{"description":"No Fill (Wireframe)","tooltip":"Enabling wireframe mode makes it easy to see the background imagery."},"partial":{"description":"Partial Fill","tooltip":"Areas are drawn with fill only around their inner edges. (Recommended for beginner mappers)"},"full":{"description":"Full Fill","tooltip":"Areas are drawn fully filled."}},"restore":{"heading":"You have unsaved changes","description":"Do you wish to restore unsaved changes from a previous editing session?","restore":"Restore","reset":"Reset"},"save":{"title":"Save","help":"Save changes to OpenStreetMap, making them visible to other users.","no_changes":"No changes to save.","error":"Errors occurred while trying to save","status_code":"Server returned status code {code}","unknown_error_details":"Please ensure you are connected to the internet.","uploading":"Uploading changes to OpenStreetMap.","unsaved_changes":"You have unsaved changes","conflict":{"header":"Resolve conflicting edits","count":"Conflict {num} of {total}","previous":"< Previous","next":"Next >","keep_local":"Keep mine","keep_remote":"Use theirs","restore":"Restore","delete":"Leave Deleted","download_changes":"Or download your changes.","done":"All conflicts resolved!","help":"Another user changed some of the same map features you changed.\nClick on each item below for more details about the conflict, and choose whether to keep\nyour changes or the other user's changes.\n"}},"merge_remote_changes":{"conflict":{"deleted":"This object has been deleted by {user}.","location":"This object was moved by both you and {user}.","nodelist":"Nodes were changed by both you and {user}.","memberlist":"Relation members were changed by both you and {user}.","tags":"You changed the <b>{tag}</b> tag to \"{local}\" and {user} changed it to \"{remote}\"."}},"success":{"edited_osm":"Edited OSM!","just_edited":"You just edited OpenStreetMap!","view_on_osm":"View on OSM","facebook":"Share on Facebook","twitter":"Share on Twitter","google":"Share on Google+","help_html":"Your changes should appear in the \"Standard\" layer in a few minutes. Other layers, and certain features, may take longer.","help_link_text":"Details","help_link_url":"https://wiki.openstreetmap.org/wiki/FAQ#I_have_just_made_some_changes_to_the_map._How_do_I_get_to_see_my_changes.3F"},"confirm":{"okay":"Okay","cancel":"Cancel"},"splash":{"welcome":"Welcome to the iD OpenStreetMap editor","text":"iD is a friendly but powerful tool for contributing to the world's best free world map. This is version {version}. For more information see {website} and report bugs at {github}.","walkthrough":"Start the Walkthrough","start":"Edit Now"},"source_switch":{"live":"live","lose_changes":"You have unsaved changes. Switching the map server will discard them. Are you sure you want to switch servers?","dev":"dev"},"tag_reference":{"description":"Description","on_wiki":"{tag} on wiki.osm.org","used_with":"used with {type}"},"validations":{"untagged_point":"Untagged point","untagged_line":"Untagged line","untagged_area":"Untagged area","many_deletions":"You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.","tag_suggests_area":"The tag {tag} suggests line should be area, but it is not an area","untagged_point_tooltip":"Select a feature type that describes what this point is.","untagged_line_tooltip":"Select a feature type that describes what this line is.","untagged_area_tooltip":"Select a feature type that describes what this area is.","deprecated_tags":"Deprecated tags: {tags}"},"zoom":{"in":"Zoom In","out":"Zoom Out"},"cannot_zoom":"Cannot zoom out further in current mode.","full_screen":"Toggle Full Screen","gpx":{"local_layer":"Local GPX file","drag_drop":"Drag and drop a .gpx file on the page, or click the button to the right to browse","zoom":"Zoom to GPX track","browse":"Browse for a .gpx file"},"mapillary_images":{"tooltip":"Street-level photos from Mapillary","title":"Photo Overlay (Mapillary)"},"mapillary_signs":{"tooltip":"Traffic signs from Mapillary (must enable Photo Overlay)","title":"Traffic Sign Overlay (Mapillary)"},"mapillary":{"view_on_mapillary":"View this image on Mapillary"},"help":{"title":"Help","help":"# Help\n\nThis is an editor for [OpenStreetMap](http://www.openstreetmap.org/), the\nfree and editable map of the world. You can use it to add and update\ndata in your area, making an open-source and open-data map of the world\nbetter for everyone.\n\nEdits that you make on this map will be visible to everyone who uses\nOpenStreetMap. In order to make an edit, you'll need to\n[log in](https://www.openstreetmap.org/login).\n\nThe [iD editor](http://ideditor.com/) is a collaborative project with [source\ncode available on GitHub](https://github.com/openstreetmap/iD).\n","editing_saving":"# Editing & Saving\n\nThis editor is designed to work primarily online, and you're accessing\nit through a website right now.\n\n### Selecting Features\n\nTo select a map feature, like a road or point of interest, click\non it on the map. This will highlight the selected feature, open a panel with\ndetails about it, and show a menu of things you can do with the feature.\n\nTo select multiple features, hold down the 'Shift' key. Then either click\non the features you want to select, or drag on the map to draw a rectangle.\nThis will draw a box and select all the points within it.\n\n### Saving Edits\n\nWhen you make changes like editing roads, buildings, and places, these are\nstored locally until you save them to the server. Don't worry if you make\na mistake - you can undo changes by clicking the undo button, and redo\nchanges by clicking the redo button.\n\nClick 'Save' to finish a group of edits - for instance, if you've completed\nan area of town and would like to start on a new area. You'll have a chance\nto review what you've done, and the editor supplies helpful suggestions\nand warnings if something doesn't seem right about the changes.\n\nIf everything looks good, you can enter a short comment explaining the change\nyou made, and click 'Save' again to post the changes\nto [OpenStreetMap.org](http://www.openstreetmap.org/), where they are visible\nto all other users and available for others to build and improve upon.\n\nIf you can't finish your edits in one sitting, you can leave the editor\nwindow and come back (on the same browser and computer), and the\neditor application will offer to restore your work.\n\n### Using the editor\n\nA list of available keyboard shortcuts can be found [here](http://wiki.openstreetmap.org/wiki/ID/Shortcuts).\n","roads":"# Roads\n\nYou can create, fix, and delete roads with this editor. Roads can be all\nkinds: paths, highways, trails, cycleways, and more - any often-crossed\nsegment should be mappable.\n\n### Selecting\n\nClick on a road to select it. An outline should become visible, along\nwith a small tools menu on the map and a sidebar showing more information\nabout the road.\n\n### Modifying\n\nOften you'll see roads that aren't aligned to the imagery behind them\nor to a GPS track. You can adjust these roads so they are in the correct\nplace.\n\nFirst click on the road you want to change. This will highlight it and show\ncontrol points along it that you can drag to better locations. If\nyou want to add new control points for more detail, double-click a part\nof the road without a node, and one will be added.\n\nIf the road connects to another road, but doesn't properly connect on\nthe map, you can drag one of its control points onto the other road in\norder to join them. Having roads connect is important for the map\nand essential for providing driving directions.\n\nYou can also click the 'Move' tool or press the `M` shortcut key to move the entire road at\none time, and then click again to save that movement.\n\n### Deleting\n\nIf a road is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the road could simply be newly built.\n\nYou can delete a road by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n\n### Creating\n\nFound somewhere there should be a road but there isn't? Click the 'Line'\nicon in the top-left of the editor or press the shortcut key `2` to start drawing\na line.\n\nClick on the start of the road on the map to start drawing. If the road\nbranches off from an existing road, start by clicking on the place where they connect.\n\nThen click on points along the road so that it follows the right path, according\nto satellite imagery or GPS. If the road you are drawing crosses another road, connect\nit by clicking on the intersection point. When you're done drawing, double-click\nor press 'Return' or 'Enter' on your keyboard.\n","gps":"# GPS\n\nCollected GPS traces are one valuable source of data for OpenStreetMap. This editor\nsupports local traces - `.gpx` files on your local computer. You can collect\nthis kind of GPS trace with a number of smartphone applications as well as\npersonal GPS hardware.\n\nFor information on how to perform a GPS survey, read\n[Mapping with a smartphone, GPS, or paper](http://learnosm.org/en/mobile-mapping/).\n\nTo use a GPX track for mapping, drag and drop the GPX file onto the map\neditor. If it's recognized, it will be added to the map as a bright purple\nline. Click on the 'Map Data' menu on the right side to enable,\ndisable, or zoom to this new GPX-powered layer.\n\nThe GPX track isn't directly uploaded to OpenStreetMap - the best way to\nuse it is to draw on the map, using it as a guide for the new features that\nyou add, and also to [upload it to OpenStreetMap](http://www.openstreetmap.org/trace/create)\nfor other users to use.\n","imagery":"# Imagery\n\nAerial imagery is an important resource for mapping. A combination of\nairplane flyovers, satellite views, and freely-compiled sources are available\nin the editor under the 'Background Settings' menu on the right.\n\nBy default a [Bing Maps](http://www.bing.com/maps/) satellite layer is\npresented in the editor, but as you pan and zoom the map to new geographical\nareas, new sources will become available. Some countries, like the United\nStates, France, and Denmark have very high-quality imagery available for some areas.\n\nImagery is sometimes offset from the map data because of a mistake on the\nimagery provider's side. If you see a lot of roads shifted from the background,\ndon't immediately move them all to match the background. Instead you can adjust\nthe imagery so that it matches the existing data by clicking 'Fix alignment' at\nthe bottom of the Background Settings UI.\n","addresses":"# Addresses\n\nAddresses are some of the most useful information for the map.\n\nAlthough addresses are often represented as parts of streets, in OpenStreetMap\nthey're recorded as attributes of buildings and places along streets.\n\nYou can add address information to places mapped as building outlines\nas well as those mapped as single points. The optimal source of address\ndata is from an on-the-ground survey or personal knowledge - as with any\nother feature, copying from commercial sources like Google Maps is strictly\nforbidden.\n","inspector":"# Using the Inspector\n\nThe inspector is the section on the left side of the page that allows you to\nedit the details of the selected feature.\n\n### Selecting a Feature Type\n\nAfter you add a point, line, or area, you can choose what type of feature it\nis, like whether it's a highway or residential road, supermarket or cafe.\nThe inspector will display buttons for common feature types, and you can\nfind others by typing what you're looking for in the search box.\n\nClick the 'i' in the bottom-right-hand corner of a feature type button to\nlearn more about it. Click a button to choose that type.\n\n### Using Forms and Editing Tags\n\nAfter you choose a feature type, or when you select a feature that already\nhas a type assigned, the inspector will display fields with details about\nthe feature like its name and address.\n\nBelow the fields you see, you can click the 'Add field' dropdown to add\nother details, like a Wikipedia link, wheelchair access, and more.\n\nAt the bottom of the inspector, click 'Additional tags' to add arbitrary\nother tags to the element. [Taginfo](http://taginfo.openstreetmap.org/) is a\ngreat resource for learn more about popular tag combinations.\n\nChanges you make in the inspector are automatically applied to the map.\nYou can undo them at any time by clicking the 'Undo' button.\n","buildings":"# Buildings\n\nOpenStreetMap is the world's largest database of buildings. You can create\nand improve this database.\n\n### Selecting\n\nYou can select a building by clicking on its border. This will highlight the\nbuilding and open a small tools menu and a sidebar showing more information\nabout the building.\n\n### Modifying\n\nSometimes buildings are incorrectly placed or have incorrect tags.\n\nTo move an entire building, select it, then click the 'Move' tool. Move your\nmouse to shift the building, and click when it's correctly placed.\n\nTo fix the specific shape of a building, click and drag the nodes that form\nits border into better places.\n\n### Creating\n\nOne of the main questions around adding buildings to the map is that\nOpenStreetMap records buildings both as shapes and points. The rule of thumb\nis to _map a building as a shape whenever possible_, and map companies, homes,\namenities, and other things that operate out of buildings as points placed\nwithin the building shape.\n\nStart drawing a building as a shape by clicking the 'Area' button in the top\nleft of the interface, and end it either by pressing 'Return' on your keyboard\nor clicking on the first node drawn to close the shape.\n\n### Deleting\n\nIf a building is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the building could simply be newly built.\n\nYou can delete a building by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n","relations":"# Relations\n\nA relation is a special type of feature in OpenStreetMap that groups together\nother features. For example, two common types of relations are *route relations*,\nwhich group together sections of road that belong to a specific freeway or\nhighway, and *multipolygons*, which group together several lines that define\na complex area (one with several pieces or holes in it like a donut).\n\nThe group of features in a relation are called *members*. In the sidebar, you can\nsee which relations a feature is a member of, and click on a relation there\nto select the it. When the relation is selected, you can see all of its\nmembers listed in the sidebar and highlighted on the map.\n\nFor the most part, iD will take care of maintaining relations automatically\nwhile you edit. The main thing you should be aware of is that if you delete a\nsection of road to redraw it more accurately, you should make sure that the\nnew section is a member of the same relations as the original.\n\n## Editing Relations\n\nIf you want to edit relations, here are the basics.\n\nTo add a feature to a relation, select the feature, click the \"+\" button in the\n\"All relations\" section of the sidebar, and select or type the name of the relation.\n\nTo create a new relation, select the first feature that should be a member,\nclick the \"+\" button in the \"All relations\" section, and select \"New relation...\".\n\nTo remove a feature from a relation, select the feature and click the trash\nbutton next to the relation you want to remove it from.\n\nYou can create multipolygons with holes using the \"Merge\" tool. Draw two areas (inner\nand outer), hold the Shift key and click on each of them to select them both, and then\nclick the \"Merge\" (+) button.\n"},"intro":{"graph":{"city_hall":"Three Rivers City Hall","fire_department":"Three Rivers Fire Department","memory_isle_park":"Memory Isle Park","riverwalk_trail":"Riverwalk Trail","w_michigan_ave":"West Michigan Avenue","e_michigan_ave":"East Michigan Avenue","spring_st":"Spring Street","scidmore_park":"Scidmore Park","petting_zoo":"Scidmore Park Petting Zoo","n_andrews_st":"North Andrews Street","s_andrews_st":"South Andrews Street","n_constantine_st":"North Constantine Street","s_constantine_st":"South Constantine Street","rocky_river":"Rocky River","railroad_dr":"Railroad Drive","conrail_rr":"Conrail Railroad","st_joseph_river":"Saint Joseph River","n_main_st":"North Main Street","s_main_st":"South Main Street","water_st":"Water Street","foster_st":"Foster Street","portage_river":"Portage River","flower_st":"Flower Street","elm_st":"Elm Street","walnut_st":"Walnut Street","morris_ave":"Morris Avenue","east_st":"East Street","portage_ave":"Portage Avenue"},"navigation":{"title":"Navigation","drag":"The main map area shows OpenStreetMap data on top of a background. You can navigate by dragging and scrolling, just like any web map. **Drag the map!**","select":"Map features are represented three ways: using points, lines or areas. All features can be selected by clicking on them. **Click on the point to select it.**","pane":"When a feature is selected, the feature editor is displayed. The header shows us the feature type and the main pane shows the feature's attributes, such as its name and address. **Close the feature editor by pressing the {button} button in the top right.**","search":"You can also search for features in the current view, or worldwide. **Search for '{name}'**","choose":"**Choose {name} from the list to select it.**","chosen":"Great! {name} is now selected. **Close the feature editor by pressing the {button} button.**"},"points":{"title":"Points","add":"Points can be used to represent features such as shops, restaurants, and monuments. They mark a specific location, and describe what's there. **Click the {button} Point button to add a new point.**","place":"The point can be placed by clicking on the map. **Click the map to place the new point on top of the building.**","search":"There are many different features that can be represented by points. The point you just added is a Cafe. **Search for '{name}'**","choose":"**Choose Cafe from the list.**","describe":"The point is now marked as a cafe. Using the feature editor, we can add more information about the feature. **Add a name**","close":"The feature editor will remember all of your changes automatically. When you change a feature, the close button will change to a checkmark. **Click the {button} button to close the feature editor**","reselect":"Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Click to select the point you just created.**","fixname":"**Change the name, then click the {button} button to close the feature editor.**","reselect_delete":"All features on the map can be deleted. **Click to select the point you created.**","delete":"The menu around the point contains operations that can be performed on it, including delete. **Click on the {button} button to delete the point.**"},"areas":{"title":"Areas","add":"Areas are used to show the boundaries of features like lakes, buildings, and residential areas. They can be also be used for more detailed mapping of many features you might normally map as points. **Click the {button} Area button to add a new area.**","corner":"Areas are drawn by placing nodes that mark the boundary of the area. **Click to place a starting node on one of the corners of the playground.**","place":"Draw the area by placing more nodes. Finish the area by clicking on the starting node. **Draw an area for the playground.**","search":"**Search for '{name}'.**","choose":"**Choose Playground from the list.**","describe":"**Add a name, then click the {button} button to close the feature editor**"},"lines":{"title":"Lines","add":"Lines are used to represent features such as roads, railroads, and rivers. **Click the {button} Line button to add a new line.**","start":"**Start the line by clicking on the end of the road.**","intersect":"Click to add more nodes to the line. You can drag the map while drawing if necessary. Roads, and many other types of lines, are part of a larger network. It is important for these lines to be connected properly in order for routing applications to work. **Click on {name} to create an intersection connecting the two lines.**","finish":"Lines can be finished by clicking on the last node again. **Finish drawing the road.**","road":"**Select Road from the list**","residential":"There are different types of roads, the most common of which is Residential. **Choose the Residential road type**","describe":"**Name the road, then click the {button} button to close the feature editor.**","restart":"The road needs to intersect {name}.","wrong_preset":"You didn't select the Residential road type. **Click here to choose again**"},"startediting":{"title":"Start Editing","help":"You can replay this walkthrough or view more documentation by clicking the {button} Help button.","save":"Don't forget to regularly save your changes!","start":"Start mapping!"}},"presets":{"categories":{"category-barrier":{"name":"Barrier Features"},"category-building":{"name":"Building Features"},"category-golf":{"name":"Golf Features"},"category-landuse":{"name":"Land Use Features"},"category-path":{"name":"Path Features"},"category-rail":{"name":"Rail Features"},"category-restriction":{"name":"Restriction Features"},"category-road":{"name":"Road Features"},"category-route":{"name":"Route Features"},"category-water-area":{"name":"Water Features"},"category-water-line":{"name":"Water Features"}},"fields":{"access":{"label":"Allowed Access","placeholder":"Not Specified","types":{"access":"All","foot":"Foot","motor_vehicle":"Motor Vehicles","bicycle":"Bicycles","horse":"Horses"},"options":{"yes":{"title":"Allowed","description":"Access permitted by law; a right of way"},"no":{"title":"Prohibited","description":"Access not permitted to the general public"},"permissive":{"title":"Permissive","description":"Access permitted until such time as the owner revokes the permission"},"private":{"title":"Private","description":"Access permitted only with permission of the owner on an individual basis"},"designated":{"title":"Designated","description":"Access permitted according to signs or specific local laws"},"destination":{"title":"Destination","description":"Access permitted only to reach a destination"},"dismount":{"title":"Dismount","description":"Access permitted but rider must dismount"}}},"access_simple":{"label":"Allowed Access","placeholder":"yes"},"access_toilets":{"label":"Access"},"address":{"label":"Address","placeholders":{"housename":"Housename","housenumber":"123","conscriptionnumber":"123","street":"Street","city":"City","postcode":"Postcode","place":"Place","hamlet":"Hamlet","suburb":"Suburb","subdistrict":"Subdistrict","district":"District","province":"Province","state":"State","country":"Country"}},"admin_level":{"label":"Admin Level"},"aerialway":{"label":"Type"},"aerialway/access":{"label":"Access","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aerialway/bubble":{"label":"Bubble"},"aerialway/capacity":{"label":"Capacity (per hour)","placeholder":"500, 2500, 5000..."},"aerialway/duration":{"label":"Duration (minutes)","placeholder":"1, 2, 3..."},"aerialway/heating":{"label":"Heated"},"aerialway/occupancy":{"label":"Occupancy","placeholder":"2, 4, 8..."},"aerialway/summer/access":{"label":"Access (summer)","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aeroway":{"label":"Type"},"amenity":{"label":"Type"},"area/highway":{"label":"Type"},"artist":{"label":"Artist"},"artwork_type":{"label":"Type"},"atm":{"label":"ATM"},"backrest":{"label":"Backrest"},"barrier":{"label":"Type"},"bench":{"label":"Bench"},"bicycle_parking":{"label":"Type"},"bin":{"label":"Waste Bin"},"boundary":{"label":"Type"},"brand":{"label":"Brand"},"building":{"label":"Building"},"building_area":{"label":"Building"},"capacity":{"label":"Capacity","placeholder":"50, 100, 200..."},"cardinal_direction":{"label":"Direction","options":{"N":"North","E":"East","S":"South","W":"West","NE":"Northeast","SE":"Southeast","SW":"Southwest","NW":"Northwest","NNE":"North-northeast","ENE":"East-northeast","ESE":"East-southeast","SSE":"South-southeast","SSW":"South-southwest","WSW":"West-southwest","WNW":"West-northwest","NNW":"North-northwest"}},"clock_direction":{"label":"Direction","options":{"clockwise":"Clockwise","anticlockwise":"Counterclockwise"}},"collection_times":{"label":"Collection Times"},"construction":{"label":"Type"},"content":{"label":"Contents"},"country":{"label":"Country"},"covered":{"label":"Covered"},"craft":{"label":"Type"},"crop":{"label":"Crop"},"crossing":{"label":"Type"},"cuisine":{"label":"Cuisine"},"currency_multi":{"label":"Currency Types"},"cycleway":{"label":"Bike Lanes","placeholder":"none","types":{"cycleway:left":"Left side","cycleway:right":"Right side"},"options":{"none":{"title":"None","description":"No bike lane"},"lane":{"title":"Standard bike lane","description":"A bike lane separated from auto traffic by a painted line"},"shared_lane":{"title":"Shared bike lane","description":"A bike lane with no separation from auto traffic"},"track":{"title":"Bike track","description":"A bike lane separated from traffic by a physical barrier"},"share_busway":{"title":"Bike lane shared with bus","description":"A bike lane shared with a bus lane"},"opposite_lane":{"title":"Opposite bike lane","description":"A bike lane that travels in the opposite direction of traffic"},"opposite":{"title":"Contraflow bike lane","description":"A bike lane that travels in both directions on a one-way street"}}},"delivery":{"label":"Delivery"},"denomination":{"label":"Denomination"},"denotation":{"label":"Denotation"},"description":{"label":"Description"},"diaper":{"label":"Diaper Changing Available"},"dock":{"label":"Type"},"drive_through":{"label":"Drive-Through"},"electrified":{"label":"Electrification","placeholder":"Contact Line, Electrified Rail...","options":{"contact_line":"Contact Line","rail":"Electrified Rail","yes":"Yes (unspecified)","no":"No"}},"elevation":{"label":"Elevation"},"emergency":{"label":"Emergency"},"entrance":{"label":"Type"},"except":{"label":"Exceptions"},"fax":{"label":"Fax","placeholder":"+31 42 123 4567"},"fee":{"label":"Fee"},"fire_hydrant/type":{"label":"Type","options":{"pillar":"Pillar/Aboveground","underground":"Underground","wall":"Wall","pond":"Pond"}},"fixme":{"label":"Fix Me"},"fuel":{"label":"Fuel"},"fuel_multi":{"label":"Fuel Types"},"gauge":{"label":"Gauge"},"gender":{"label":"Gender","placeholder":"Unknown","options":{"male":"Male","female":"Female","unisex":"Unisex"}},"generator/method":{"label":"Method"},"generator/source":{"label":"Source"},"generator/type":{"label":"Type"},"golf_hole":{"label":"Reference","placeholder":"Hole number (1-18)"},"handicap":{"label":"Handicap","placeholder":"1-18"},"handrail":{"label":"Handrail"},"highway":{"label":"Type"},"historic":{"label":"Type"},"hoops":{"label":"Hoops","placeholder":"1, 2, 4..."},"iata":{"label":"IATA"},"icao":{"label":"ICAO"},"incline":{"label":"Incline"},"incline_steps":{"label":"Incline","options":{"up":"Up","down":"Down"}},"information":{"label":"Type"},"internet_access":{"label":"Internet Access","options":{"yes":"Yes","no":"No","wlan":"Wifi","wired":"Wired","terminal":"Terminal"}},"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"}},"payment_multi":{"label":"Payment Types"},"phone":{"label":"Phone","placeholder":"+31 42 123 4567"},"piste/difficulty":{"label":"Difficulty","placeholder":"Easy, Intermediate, Advanced...","options":{"novice":"Novice (instructional)","easy":"Easy (green circle)","intermediate":"Intermediate (blue square)","advanced":"Advanced (black diamond)","expert":"Expert (double black diamond)","freeride":"Freeride (off-piste)","extreme":"Extreme (climbing equipment required)"}},"piste/grooming":{"label":"Grooming","options":{"classic":"Classic","mogul":"Mogul","backcountry":"Backcountry","classic+skating":"Classic and Skating","scooter":"Scooter/Snowmobile","skating":"Skating"}},"piste/type":{"label":"Type","options":{"downhill":"Downhill","nordic":"Nordic","skitour":"Skitour","sled":"Sled","hike":"Hike","sleigh":"Sleigh","ice_skate":"Ice Skate","snow_park":"Snow Park","playground":"Playground"}},"place":{"label":"Type"},"population":{"label":"Population"},"power":{"label":"Type"},"power_supply":{"label":"Power Supply"},"railway":{"label":"Type"},"recycling_accepts":{"label":"Accepts"},"ref":{"label":"Reference"},"relation":{"label":"Type"},"religion":{"label":"Religion"},"restriction":{"label":"Type"},"restrictions":{"label":"Turn Restrictions"},"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,grill"},"amenity/bench":{"name":"Bench","terms":"seat"},"amenity/bicycle_parking":{"name":"Bicycle Parking","terms":"bike"},"amenity/bicycle_rental":{"name":"Bicycle Rental","terms":"bike"},"amenity/bicycle_repair_station":{"name":"Bicycle Repair Tool Stand","terms":"bike,repair,chain,pump"},"amenity/biergarten":{"name":"Beer Garden","terms":"beer,bier,booze"},"amenity/boat_rental":{"name":"Boat Rental","terms":""},"amenity/bureau_de_change":{"name":"Currency Exchange","terms":"bureau de change,money changer"},"amenity/bus_station":{"name":"Bus Station","terms":""},"amenity/cafe":{"name":"Cafe","terms":"bistro,coffee,tea"},"amenity/car_rental":{"name":"Car Rental","terms":""},"amenity/car_sharing":{"name":"Car Sharing","terms":""},"amenity/car_wash":{"name":"Car Wash","terms":""},"amenity/casino":{"name":"Casino","terms":"gambling,roulette,craps,poker,blackjack"},"amenity/charging_station":{"name":"Charging Station","terms":"EV,Electric Vehicle,Supercharger"},"amenity/childcare":{"name":"Nursery/Childcare","terms":"daycare,orphanage,playgroup"},"amenity/cinema":{"name":"Cinema","terms":"drive-in,film,flick,movie,theater,picture,show,screen"},"amenity/clinic":{"name":"Clinic","terms":"medical,urgentcare"},"amenity/clock":{"name":"Clock","terms":""},"amenity/college":{"name":"College Grounds","terms":"university"},"amenity/community_centre":{"name":"Community Center","terms":"event,hall"},"amenity/compressed_air":{"name":"Compressed Air","terms":""},"amenity/courthouse":{"name":"Courthouse","terms":""},"amenity/dentist":{"name":"Dentist","terms":"tooth,teeth"},"amenity/doctors":{"name":"Doctor","terms":"medic*"},"amenity/dojo":{"name":"Dojo / Martial Arts Academy","terms":"martial arts,dojang"},"amenity/drinking_water":{"name":"Drinking Water","terms":"fountain,potable"},"amenity/embassy":{"name":"Embassy","terms":""},"amenity/fast_food":{"name":"Fast Food","terms":"restaurant"},"amenity/ferry_terminal":{"name":"Ferry Terminal","terms":""},"amenity/fire_station":{"name":"Fire Station","terms":""},"amenity/fountain":{"name":"Fountain","terms":""},"amenity/fuel":{"name":"Gas Station","terms":"petrol,fuel,gasoline,propane,diesel,lng,cng,biodiesel"},"amenity/grave_yard":{"name":"Graveyard","terms":""},"amenity/grit_bin":{"name":"Grit Bin","terms":"salt,sand"},"amenity/hospital":{"name":"Hospital Grounds","terms":"clinic,doctor,emergency room,health service,hospice,infirmary,institution,nursing home,sanatorium,sanitarium,sick,surgery,ward"},"amenity/hunting_stand":{"name":"Hunting Stand","terms":""},"amenity/kindergarten":{"name":"Preschool/Kindergarten Grounds","terms":"kindergarden,pre-school"},"amenity/library":{"name":"Library","terms":"book"},"amenity/marketplace":{"name":"Marketplace","terms":""},"amenity/motorcycle_parking":{"name":"Motorcycle Parking","terms":""},"amenity/nightclub":{"name":"Nightclub","terms":"disco*,night club,dancing,dance club"},"amenity/parking":{"name":"Car Parking","terms":""},"amenity/parking_entrance":{"name":"Parking Garage Entrance/Exit","terms":""},"amenity/parking_space":{"name":"Parking Space","terms":""},"amenity/pharmacy":{"name":"Pharmacy","terms":"drug,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":"Trench","terms":""},"barrier/entrance":{"name":"Entrance","terms":""},"barrier/fence":{"name":"Fence","terms":""},"barrier/gate":{"name":"Gate","terms":""},"barrier/hedge":{"name":"Hedge","terms":""},"barrier/kissing_gate":{"name":"Kissing Gate","terms":""},"barrier/lift_gate":{"name":"Lift Gate","terms":""},"barrier/retaining_wall":{"name":"Retaining Wall","terms":""},"barrier/stile":{"name":"Stile","terms":""},"barrier/toll_booth":{"name":"Toll Booth","terms":""},"barrier/wall":{"name":"Wall","terms":""},"boundary/administrative":{"name":"Administrative Boundary","terms":""},"building":{"name":"Building","terms":""},"building/apartments":{"name":"Apartments","terms":""},"building/barn":{"name":"Barn","terms":""},"building/bunker":{"name":"Bunker","terms":""},"building/cabin":{"name":"Cabin","terms":""},"building/cathedral":{"name":"Cathedral Building","terms":""},"building/chapel":{"name":"Chapel Building","terms":""},"building/church":{"name":"Church Building","terms":""},"building/college":{"name":"College Building","terms":"university"},"building/commercial":{"name":"Commercial Building","terms":""},"building/construction":{"name":"Building Under Construction","terms":""},"building/detached":{"name":"Detached House","terms":"home,single,family,residence,dwelling"},"building/dormitory":{"name":"Dormitory","terms":""},"building/entrance":{"name":"Entrance/Exit","terms":""},"building/garage":{"name":"Garage","terms":""},"building/garages":{"name":"Garages","terms":""},"building/greenhouse":{"name":"Greenhouse","terms":""},"building/hospital":{"name":"Hospital Building","terms":""},"building/hotel":{"name":"Hotel Building","terms":""},"building/house":{"name":"House","terms":"home,family,residence,dwelling"},"building/hut":{"name":"Hut","terms":""},"building/industrial":{"name":"Industrial Building","terms":""},"building/kindergarten":{"name":"Preschool/Kindergarten Building","terms":"kindergarden,pre-school"},"building/public":{"name":"Public Building","terms":""},"building/residential":{"name":"Residential Building","terms":""},"building/retail":{"name":"Retail Building","terms":""},"building/roof":{"name":"Roof","terms":""},"building/school":{"name":"School Building","terms":"academy,elementary school,middle school,high school"},"building/semidetached_house":{"name":"Semi-Detached House","terms":"home,double,duplex,twin,family,residence,dwelling"},"building/shed":{"name":"Shed","terms":""},"building/stable":{"name":"Stable","terms":""},"building/static_caravan":{"name":"Static Mobile Home","terms":""},"building/terrace":{"name":"Row Houses","terms":"home,terrace,brownstone,family,residence,dwelling"},"building/train_station":{"name":"Train Station","terms":""},"building/university":{"name":"University Building","terms":"college"},"building/warehouse":{"name":"Warehouse","terms":""},"craft":{"name":"Craft","terms":""},"craft/basket_maker":{"name":"Basket Maker","terms":""},"craft/beekeeper":{"name":"Beekeeper","terms":""},"craft/blacksmith":{"name":"Blacksmith","terms":""},"craft/boatbuilder":{"name":"Boat Builder","terms":""},"craft/bookbinder":{"name":"Bookbinder","terms":"book repair"},"craft/brewery":{"name":"Brewery","terms":"beer,bier"},"craft/carpenter":{"name":"Carpenter","terms":"woodworker"},"craft/carpet_layer":{"name":"Carpet Layer","terms":""},"craft/caterer":{"name":"Caterer","terms":""},"craft/clockmaker":{"name":"Clockmaker","terms":""},"craft/confectionery":{"name":"Confectionery","terms":"sweets,candy"},"craft/dressmaker":{"name":"Dressmaker","terms":"seamstress"},"craft/electrician":{"name":"Electrician","terms":"power,wire"},"craft/gardener":{"name":"Gardener","terms":"landscaper,grounds keeper"},"craft/glaziery":{"name":"Glaziery","terms":"glass,stained-glass,window"},"craft/handicraft":{"name":"Handicraft","terms":""},"craft/hvac":{"name":"HVAC","terms":"heat*,vent*,air conditioning"},"craft/insulator":{"name":"Insulator","terms":""},"craft/jeweler":{"name":"Jeweler","terms":""},"craft/key_cutter":{"name":"Key Cutter","terms":""},"craft/locksmith":{"name":"Locksmith","terms":""},"craft/metal_construction":{"name":"Metal Construction","terms":""},"craft/optician":{"name":"Optician","terms":""},"craft/painter":{"name":"Painter","terms":""},"craft/photographer":{"name":"Photographer","terms":""},"craft/photographic_laboratory":{"name":"Photographic Laboratory","terms":"film"},"craft/plasterer":{"name":"Plasterer","terms":""},"craft/plumber":{"name":"Plumber","terms":"pipe"},"craft/pottery":{"name":"Pottery","terms":"ceramic"},"craft/rigger":{"name":"Rigger","terms":""},"craft/roofer":{"name":"Roofer","terms":""},"craft/saddler":{"name":"Saddler","terms":""},"craft/sailmaker":{"name":"Sailmaker","terms":""},"craft/sawmill":{"name":"Sawmill","terms":"lumber"},"craft/scaffolder":{"name":"Scaffolder","terms":""},"craft/sculpter":{"name":"Sculpter","terms":""},"craft/shoemaker":{"name":"Shoemaker","terms":"cobbler"},"craft/stonemason":{"name":"Stonemason","terms":"masonry"},"craft/sweep":{"name":"Chimney Sweep","terms":""},"craft/tailor":{"name":"Tailor","terms":"clothes,suit"},"craft/tiler":{"name":"Tiler","terms":""},"craft/tinsmith":{"name":"Tinsmith","terms":""},"craft/upholsterer":{"name":"Upholsterer","terms":""},"craft/watchmaker":{"name":"Watchmaker","terms":""},"craft/window_construction":{"name":"Window Construction","terms":"glass"},"craft/winery":{"name":"Winery","terms":""},"embankment":{"name":"Embankment","terms":""},"emergency/ambulance_station":{"name":"Ambulance Station","terms":"EMS,EMT,rescue"},"emergency/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/horse":{"name":"Riding Route","terms":""},"type/route/pipeline":{"name":"Pipeline Route","terms":""},"type/route/power":{"name":"Power Route","terms":""},"type/route/road":{"name":"Road Route","terms":""},"type/route/train":{"name":"Train Route","terms":""},"type/route/tram":{"name":"Tram Route","terms":""},"type/route_master":{"name":"Route Master","terms":""},"type/site":{"name":"Site","terms":""},"vertex":{"name":"Other","terms":""},"waterway":{"name":"Waterway","terms":""},"waterway/boatyard":{"name":"Boatyard","terms":""},"waterway/canal":{"name":"Canal","terms":""},"waterway/dam":{"name":"Dam","terms":""},"waterway/ditch":{"name":"Ditch","terms":""},"waterway/dock":{"name":"Wet Dock / Dry Dock","terms":"boat,ship,vessel,marine"},"waterway/drain":{"name":"Drain","terms":""},"waterway/fuel":{"name":"Marine Fuel Station","terms":"petrol,gas,diesel,boat"},"waterway/river":{"name":"River","terms":"beck,branch,brook,course,creek,estuary,rill,rivulet,run,runnel,stream,tributary,watercourse"},"waterway/riverbank":{"name":"Riverbank","terms":""},"waterway/sanitary_dump_station":{"name":"Marine Toilet Disposal","terms":"Boat,Watercraft,Sanitary,Dump Station,Pumpout,Pump out,Elsan,CDP,CTDP,Chemical Toilet"},"waterway/stream":{"name":"Stream","terms":"beck,branch,brook,burn,course,creek,current,drift,flood,flow,freshet,race,rill,rindle,rivulet,run,runnel,rush,spate,spritz,surge,tide,torrent,tributary,watercourse"},"waterway/water_point":{"name":"Marine Drinking Water","terms":""},"waterway/weir":{"name":"Weir","terms":""}}}},"suggestions":{"amenity":{"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"]]}],"phoneFormats":{"us":"+1-202-555-1234","ca":"+1-226-555-1234","bs":"+1-242-555-1234","bb":"+1-246-555-1234","ai":"+1-264-555-1234","ag":"+1-268-555-1234","vg":"+1-284-555-1234","vi":"+1-340-555-1234","ky":"+1-345-555-1234","bm":"+1-441-555-1234","gd":"+1-473-555-1234","tc":"+1-649-555-1234","ms":"+1-664-555-1234","mp":"+1-670-555-1234","gu":"+1-671-555-1234","as":"+1-684-555-1234","sx":"+1-721-555-1234","lc":"+1-758-555-1234","dm":"+1-767-555-1234","vc":"+1-784-555-1234","pr":"+1-787-555-1234","do":"+1-809-555-1234","tt":"+1-868-555-1234","kn":"+1-869-555-1234","jm":"+1-876-555-1234","za":"+27 11 907 1111","nl":"+31 42 123 4567","fr":"+33 1 23 45 67 89","es":"+34 989 12 34 56","pt":"+351 211 123456","fi":"+358 40 123 4567","hu":"+36 1 123 45 67","hr":"+385 01 123 4567","si":"+386 31 123 4567","it":"+39 01 123 456","va":"+39 01 123 456","gb":"+44 207 123456","gg":"+44 207 123456","im":"+44 207 123456","je":"+44 207 123456","se":"+46 31 123 4567","no":"+47 22 12 34 56","sj":"+47 22 12 34 56","pl":"+48 42 123 4567","de":"+49 89 1234567","br":"+55 11 0982 1098","ru":"+7 495 1234567","kz":"+7 495 1234567","vn":"+84 1 234 5678","hk":"+852 12345678"},"driveLeft":{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-75.38818,18.62542],[-80.09033,20.32402],[-82.24365,19.26967],[-77.36572,16.42555],[-75.38818,18.62542]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-64.33594,32.86113],[-79.39819,27.21067],[-80.63965,23.71998],[-73.39966,20.40642],[-65.1709,19.20743],[-65.09399,16.23577],[-59.13391,16.80454],[-62.64404,15.16228],[-59.43054,14.85985],[-62.83081,13.64599],[-61.80359,10.73752],[-62.08649,10.04729],[-61.06201,9.85522],[-59.81369,8.31274],[-59.8027,8.27469],[-59.83498,8.22712],[-59.94141,8.21149],[-59.99771,8.15576],[-59.97986,8.13265],[-59.99771,8.12041],[-60.00183,8.07147],[-60.05127,8.02524],[-60.09933,8.03747],[-60.12268,8.02388],[-60.14053,7.98988],[-60.36163,7.83345],[-60.53467,7.81713],[-60.5896,7.6375],[-60.72144,7.54493],[-60.5896,7.31888],[-60.63904,7.24532],[-60.54703,7.12542],[-60.46875,7.20309],[-60.37262,7.18401],[-60.29984,7.1445],[-60.2916,7.06819],[-60.39871,6.95097],[-60.66513,6.83235],[-60.71869,6.75053],[-60.91232,6.81735],[-60.94254,6.72053],[-61.14441,6.72326],[-61.23093,6.5773],[-61.1554,6.45314],[-61.14441,6.20199],[-61.39709,5.95619],[-60.71045,5.20036],[-60.21606,5.23319],[-59.99634,5.06906],[-60.13916,4.51071],[-59.69971,4.40118],[-59.5459,3.93002],[-59.87549,3.56825],[-59.7876,3.37086],[-60.01831,2.83332],[-59.90845,2.38335],[-59.69971,2.2626],[-59.77661,1.87833],[-59.65302,1.85087],[-59.69147,1.75754],[-59.61456,1.71361],[-59.55139,1.73283],[-59.36188,1.49123],[-59.26575,1.39238],[-58.92242,1.30726],[-58.83728,1.17271],[-58.71918,1.23037],[-58.71094,1.29902],[-58.49121,1.26058],[-58.461,1.37591],[-58.50494,1.38689],[-58.51044,1.46102],[-58.38135,1.4775],[-58.32642,1.57359],[-58.00507,1.49946],[-57.99133,1.65321],[-57.79907,1.69165],[-57.70844,1.71087],[-57.54364,1.68341],[-57.41455,1.94421],[-57.10693,1.97715],[-56.8103,1.85636],[-56.48071,1.92225],[-55.90942,1.81244],[-55.90942,2.04302],[-56.14014,2.26534],[-55.94788,2.53701],[-55.70892,2.39981],[-55.37933,2.43274],[-55.19257,2.53976],[-54.98108,2.57268],[-54.88495,2.43548],[-54.71191,2.46293],[-54.69543,2.34767],[-54.58832,2.32846],[-54.43451,2.43548],[-54.20654,2.76748],[-54.17358,3.12955],[-53.96484,3.57921],[-54.33838,4.00674],[-54.44412,4.52577],[-54.46884,4.91036],[-54.36653,5.13061],[-54.27727,5.26191],[-54.19968,5.3084],[-54.01222,5.54457],[-54.0239,5.64605],[-53.86322,5.94936],[-64.33594,32.86113]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-14.5459,-5.92204],[11.79657,-17.27197],[12.03415,-17.14866],[12.38159,-17.22213],[12.58484,-17.22476],[13.01193,-16.97405],[13.24951,-17.00098],[13.38135,-16.98522],[13.93341,-17.38734],[18.42476,-17.38996],[18.47763,-17.46857],[18.62663,-17.64599],[18.79211,-17.76177],[18.92944,-17.82061],[19.33044,-17.84806],[19.66278,-17.8644],[19.74792,-17.90557],[19.85161,-17.87486],[20.10361,-17.90296],[20.18394,-17.88401],[20.34737,-17.88466],[20.44693,-17.91733],[20.51697,-17.96698],[20.83008,-18.03032],[20.95711,-17.97285],[21.16997,-17.93497],[21.42677,-18.0264],[23.45032,-17.63879],[22.00012,-16.38866],[21.99944,-13.00523],[24.03809,-12.99118],[24.03809,-10.91962],[24.43359,-11.09217],[24.45557,-11.48002],[25.37842,-11.19996],[25.42236,-11.60919],[26.96045,-11.97484],[27.18018,-11.60919],[28.125,-12.42048],[29.11377,-13.36824],[29.1687,-13.43771],[29.55872,-13.19716],[29.68506,-13.2239],[29.62463,-13.41099],[29.80591,-13.44305],[29.81415,-12.14809],[29.31152,-12.55456],[28.41064,-11.78133],[28.63037,-10.70379],[28.65234,-9.73071],[28.37219,-9.24309],[28.89748,-8.47916],[30.78644,-8.26857],[29.39941,-6.05316],[29.4873,-4.45595],[29.75922,-4.46759],[29.81415,-4.36421],[29.88007,-4.36832],[30.04074,-4.26699],[30.07919,-4.1629],[30.18356,-4.08311],[30.1918,-4.05126],[30.21566,-4.04595],[30.22923,-4.01136],[30.21326,-3.99612],[30.25978,-3.88755],[30.29274,-3.86288],[30.34424,-3.77245],[30.39848,-3.79095],[30.40878,-3.76765],[30.39548,-3.7304],[30.39054,-3.72821],[30.3896,-3.71918],[30.39093,-3.7101],[30.39514,-3.70444],[30.42028,-3.64963],[30.46886,-3.53501],[30.67108,-3.41335],[30.63297,-3.34892],[30.84206,-3.25535],[30.84549,-3.16108],[30.83485,-3.09698],[30.7933,-3.06235],[30.82111,-3.02258],[30.84515,-2.9739],[30.74764,-2.99618],[30.7037,-2.97013],[30.66422,-2.98967],[30.57632,-2.90738],[30.49393,-2.94441],[30.41016,-2.87172],[30.52002,-2.39432],[30.77545,-2.38883],[30.8606,-2.31199],[30.84961,-2.19398],[30.89081,-2.07322],[30.81116,-1.96068],[30.83862,-1.6587],[30.73425,-1.4418],[30.56259,-1.33884],[30.4541,-1.05737],[30.35797,-1.06287],[30.34149,-1.13152],[30.16571,-1.34296],[29.91852,-1.48024],[29.83887,-1.31824],[29.58344,-1.39238],[29.729,0.05493],[29.96796,0.5136],[29.9707,0.8569],[30.22339,0.92281],[30.24536,1.15349],[30.47745,1.20772],[31.30966,2.15693],[31.20255,2.22211],[31.20255,2.29278],[31.16409,2.27906],[31.13937,2.28318],[31.13113,2.26534],[31.07826,2.30033],[31.0714,2.34767],[31.00479,2.4005],[30.97183,2.40461],[30.94711,2.38746],[30.94849,2.36276],[30.9375,2.33532],[30.88531,2.34012],[30.83038,2.42176],[30.74112,2.43274],[30.76035,2.5864],[30.90179,2.88132],[30.76447,3.04178],[30.93613,3.40239],[30.94059,3.50588],[30.85236,3.48601],[30.90866,3.5936],[30.95055,3.63918],[30.94677,3.65391],[30.9866,3.70187],[31.00582,3.70701],[31.02058,3.69708],[31.16547,3.7954],[31.28838,3.79643],[31.52699,3.66282],[31.7038,3.72449],[31.82671,3.82794],[31.96198,3.65596],[31.95854,3.57099],[32.04987,3.59155],[32.07733,3.57099],[32.0842,3.53672],[32.20093,3.50657],[32.21672,3.56448],[32.19578,3.59977],[32.41516,3.74504],[32.72055,3.76782],[32.89307,3.81219],[33.02782,3.89371],[33.18146,3.7793],[33.51173,3.75258],[33.98758,4.23309],[34.05762,4.28342],[34.38721,4.61065],[35.94452,4.62023],[35.95688,4.53467],[36.04134,4.44568],[36.89621,4.4491],[38.14728,3.62992],[38.55927,3.62033],[38.92181,3.51068],[39.56039,3.43392],[39.87076,3.87522],[40.76752,4.28753],[41.16371,3.94372],[41.89774,3.97797],[41.31271,3.14463],[40.98896,2.82869],[40.99548,-0.84042],[41.72607,-1.81244],[41.57227,-48.80686],[-27.11426,-60.23981],[-65.78613,-52.5897],[-14.5459,-5.92204]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[31.33301,35.47856],[33.0249,33.75175],[35.44189,36.02245],[31.33301,35.47856]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[13.86475,36.46105],[15.271,35.8935],[14.17786,35.40248],[13.86475,36.46105]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[0.13184,61.89758],[2.41699,51.26191],[-2.03247,49.91763],[-1.90338,48.93333],[-20.12695,53.33087],[0.13184,61.89758]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[180,-35.35322],[161.41113,-19.68397],[167.00317,-12.26486],[180,-21.7697],[180,4.62023],[170.85938,3.77656],[127.08435,5.74171],[118.21289,2.76748],[119.52026,5.30977],[117.26807,7.51498],[102.6123,8.47781],[102.9158,11.74099],[102.76268,12.07357],[102.70226,12.17158],[102.74139,12.46474],[102.53128,12.68857],[102.49557,12.9256],[102.49763,13.0064],[102.4597,13.08199],[102.43412,13.09026],[102.39155,13.16407],[102.35481,13.29341],[102.35893,13.30945],[102.34503,13.34837],[102.35928,13.39797],[102.3567,13.48095],[102.36168,13.50582],[102.33559,13.53787],[102.33971,13.56023],[102.35498,13.5649],[102.36511,13.5785],[102.40047,13.5679],[102.42537,13.56891],[102.44614,13.56123],[102.48047,13.57091],[102.53849,13.56757],[102.5699,13.58526],[102.57806,13.60486],[102.62501,13.60845],[102.62132,13.61295],[102.60767,13.61562],[102.57231,13.63331],[102.56922,13.64082],[102.54879,13.658],[102.56252,13.68552],[102.5972,13.70803],[102.67084,13.74472],[102.68818,13.75172],[102.7014,13.7684],[102.73161,13.77082],[102.76543,13.85541],[102.78397,13.93207],[102.80388,13.94406],[102.81607,13.96639],[102.90705,14.02119],[102.89726,14.0535],[102.90095,14.0838],[102.92421,14.10744],[102.92378,14.12838],[102.94147,14.15035],[102.92953,14.17952],[103.17535,14.33774],[103.19939,14.32992],[103.68553,14.44],[103.94508,14.34157],[104.05756,14.34589],[104.06636,14.3419],[104.26025,14.37749],[104.50058,14.36984],[104.57817,14.36019],[104.6422,14.42387],[104.66632,14.40234],[104.68357,14.39877],[104.71138,14.43169],[104.72305,14.42188],[104.71687,14.40043],[104.75344,14.40459],[104.80408,14.43867],[104.83429,14.41573],[104.99239,14.3838],[105.05402,14.19783],[105.47905,14.49186],[105.60883,15.0005],[105.46703,15.13005],[105.48866,15.20237],[105.59269,15.2716],[105.58617,15.32823],[105.50308,15.31912],[105.46703,15.33948],[105.49175,15.37921],[105.59372,15.42869],[105.59372,15.50927],[105.60986,15.54871],[105.62616,15.56492],[105.62702,15.59129],[105.63518,15.62742],[105.63612,15.66056],[105.5975,15.72088],[105.49965,15.76681],[105.46291,15.74517],[105.43819,15.75459],[105.40489,15.79424],[105.34241,15.92039],[105.37811,15.98344],[105.39167,15.99136],[105.41931,15.98608],[105.42652,15.99764],[105.41468,16.01661],[105.21263,16.05076],[105.04955,16.10552],[105.01316,16.24401],[104.88235,16.37812],[104.8391,16.45782],[104.77936,16.49041],[104.73919,16.53287],[104.74228,16.62205],[104.76391,16.70953],[104.73953,16.80323],[104.76425,16.85088],[104.73782,16.90968],[104.744,17.0128],[104.81266,17.21853],[104.79841,17.39274],[104.70348,17.52833],[104.46384,17.65515],[104.34368,17.83564],[104.27776,17.8559],[104.22661,17.98069],[104.1116,18.10735],[104.06525,18.21174],[103.97392,18.33823],[103.9286,18.33237],[103.88809,18.29456],[103.85582,18.28673],[103.83659,18.32715],[103.79128,18.3467],[103.70201,18.34214],[103.60931,18.40405],[103.57292,18.40437],[103.51593,18.42978],[103.45963,18.42587],[103.41568,18.44802],[103.30479,18.43206],[103.24265,18.37082],[103.24333,18.34133],[103.29123,18.32357],[103.28899,18.29521],[103.23595,18.28299],[103.16608,18.25511],[103.02429,17.98135],[102.6535,17.83237],[102.40631,17.99963],[102.10968,18.22413],[101.548,17.81538],[101.30493,17.64991],[101.14563,17.46595],[100.95886,17.61654],[101.01757,17.88858],[101.18752,18.05121],[101.16863,18.10409],[101.18134,18.33595],[101.08727,18.38287],[101.05499,18.43988],[101.23215,18.73015],[101.35265,19.04524],[101.25927,19.12733],[101.2373,19.32637],[101.25824,19.58438],[101.11954,19.56836],[101.08898,19.58777],[101.08624,19.59715],[101.03165,19.6185],[100.89844,19.62125],[100.77827,19.49249],[100.63751,19.56432],[100.58258,19.49313],[100.47478,19.5944],[100.42929,19.67152],[100.43341,19.7024],[100.4147,19.7255],[100.40525,19.7646],[100.43907,19.80345],[100.45555,19.84843],[100.50636,19.87264],[100.51709,19.93027],[100.58653,20.1599],[100.56576,20.1757],[100.54945,20.17473],[100.52731,20.14379],[100.51065,20.14895],[100.48697,20.17956],[100.46774,20.196],[100.45246,20.20147],[100.45521,20.22129],[100.44783,20.23546],[100.41607,20.25286],[100.40594,20.28184],[100.38397,20.31082],[100.37556,20.35187],[100.36165,20.35638],[100.35736,20.37408],[100.33195,20.39902],[100.27805,20.40224],[100.25917,20.39677],[100.2475,20.37263],[100.22535,20.35509],[100.22346,20.31839],[100.16579,20.29988],[100.17162,20.24545],[100.10845,20.25221],[100.09266,20.2696],[100.09798,20.31485],[100.07961,20.3678],[99.9567,20.46417],[99.91636,20.44925],[99.90765,20.44977],[99.89121,20.44511],[99.87276,20.44406],[99.86212,20.44326],[99.80186,20.33948],[99.46472,20.3884],[99.56085,20.20035],[99.43691,20.08882],[99.27727,20.11623],[99.06921,20.1101],[98.97789,19.74538],[98.24387,19.68656],[97.85934,19.57014],[97.76733,18.57336],[97.39655,18.47179],[97.62451,18.30238],[97.73849,17.97743],[97.66502,17.87943],[97.90947,17.56745],[98.52951,16.82557],[98.51303,16.69276],[98.69293,16.26873],[98.87421,16.43609],[98.93394,16.3353],[98.84743,16.13356],[98.74512,16.12037],[98.58307,16.07287],[98.5762,15.79754],[98.54736,15.37557],[98.17383,15.15167],[98.3606,14.63674],[99.08295,13.89208],[99.16534,13.72204],[99.18182,13.00723],[99.39331,12.56797],[99.64153,11.78973],[99.32156,11.30266],[98.77859,10.67849],[98.80597,10.47642],[98.76657,10.40459],[98.74924,10.34194],[96.85547,6.40265],[92.42523,20.54794],[92.2728,20.96272],[92.18353,21.16072],[92.21718,21.23434],[92.19727,21.32968],[92.26318,21.36485],[92.27142,21.43326],[92.32635,21.41919],[92.34695,21.47032],[92.37717,21.48246],[92.42592,21.43453],[92.43073,21.3706],[92.50763,21.35654],[92.51793,21.38979],[92.55913,21.37892],[92.60376,21.24074],[92.68135,21.29129],[92.62642,21.43262],[92.60925,21.99908],[93.21899,22.2586],[93.1366,23.05446],[93.34534,23.05952],[93.43323,23.68729],[93.33572,24.07154],[93.4964,23.94359],[93.62549,24.00758],[94.15524,23.84675],[94.17068,23.92821],[94.25171,24.07405],[94.27952,24.17307],[94.28844,24.23037],[94.30175,24.2371],[94.32561,24.2731],[94.32587,24.32457],[94.58199,24.72282],[94.73648,25.13783],[94.78455,25.47799],[94.88823,25.58054],[95.14709,26.07035],[95.1004,26.51482],[96.3446,27.28393],[97.36359,27.91919],[96.14136,29.38218],[95.41626,29.08498],[94.79004,29.20971],[92.40051,27.81964],[91.6452,27.76376],[91.40625,28.0138],[89.57977,28.18824],[88.90961,27.3242],[88.77228,27.54602],[88.90961,27.884],[88.70361,28.1059],[88.12134,27.87793],[85.92957,27.94103],[81.62292,30.44157],[81.19995,30.03343],[78.75,31.50363],[78.77197,31.96148],[78.39844,32.50513],[78.95325,32.37068],[79.3158,32.49586],[79.16199,33.0363],[79.01367,34.33436],[78.26111,34.6558],[78.01392,35.46067],[76.16821,35.79108],[76.00342,36.5626],[75.16846,37.01133],[74.53674,36.99817],[72.52075,36.84006],[71.19141,36.08906],[71.65283,35.44725],[71.50452,34.9805],[70.98541,34.54955],[71.17905,34.36271],[71.09253,34.11522],[70.8783,33.97298],[70.51849,33.94336],[69.90807,34.04697],[69.86893,33.96614],[69.97055,33.75746],[70.13123,33.72662],[70.33997,33.342],[70.02136,33.13985],[69.5723,33.09614],[69.23859,32.46227],[69.31274,31.9172],[68.11798,31.75153],[66.39313,30.93875],[66.26404,29.80252],[62.49023,29.41089],[60.87524,29.86447],[61.5303,29.01174],[61.65802,28.77609],[61.96632,28.5405],[62.43256,28.42341],[62.6049,28.2548],[62.7951,28.28141],[62.86789,27.23448],[63.25996,27.2473],[63.32726,27.1334],[63.25241,27.09092],[63.25241,26.83755],[63.18787,26.83816],[63.18993,26.65237],[62.30896,26.51974],[62.21558,26.27371],[61.85303,26.22937],[61.83105,25.75042],[61.68274,25.67124],[56.55762,-21.18697],[180,-65],[180,-35.35322]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[138.75732,46.69467],[145.5249,44.48475],[145.27771,43.68376],[145.86548,43.39307],[142.84424,18.22935],[122.09106,24.37712],[138.75732,46.69467]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-180,7],[-148,7],[-151,-12],[-171.5,-10.75],[-171,-16],[-152,-19],[-180,-55],[-180,7]]]}}]}};